183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2e94cad93SMarek Vasut /* 3e94cad93SMarek Vasut * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com> 4e94cad93SMarek Vasut */ 5e94cad93SMarek Vasut 6e94cad93SMarek Vasut #include <common.h> 7e94cad93SMarek Vasut #include <clk.h> 8e94cad93SMarek Vasut #include <fdtdec.h> 9e94cad93SMarek Vasut #include <mmc.h> 10e94cad93SMarek Vasut #include <dm.h> 11e94cad93SMarek Vasut #include <linux/compat.h> 12e94cad93SMarek Vasut #include <linux/dma-direction.h> 13e94cad93SMarek Vasut #include <linux/io.h> 14e94cad93SMarek Vasut #include <linux/sizes.h> 15e94cad93SMarek Vasut #include <power/regulator.h> 16e94cad93SMarek Vasut #include <asm/unaligned.h> 17e94cad93SMarek Vasut 18cb0b6b03SMarek Vasut #include "tmio-common.h" 19e94cad93SMarek Vasut 20f63968baSMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 21f63968baSMarek Vasut 22f63968baSMarek Vasut /* SCC registers */ 23f63968baSMarek Vasut #define RENESAS_SDHI_SCC_DTCNTL 0x800 24f63968baSMarek Vasut #define RENESAS_SDHI_SCC_DTCNTL_TAPEN BIT(0) 25f63968baSMarek Vasut #define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 26f63968baSMarek Vasut #define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff 27f63968baSMarek Vasut #define RENESAS_SDHI_SCC_TAPSET 0x804 28f63968baSMarek Vasut #define RENESAS_SDHI_SCC_DT2FF 0x808 29f63968baSMarek Vasut #define RENESAS_SDHI_SCC_CKSEL 0x80c 30f63968baSMarek Vasut #define RENESAS_SDHI_SCC_CKSEL_DTSEL BIT(0) 31f63968baSMarek Vasut #define RENESAS_SDHI_SCC_RVSCNTL 0x810 32f63968baSMarek Vasut #define RENESAS_SDHI_SCC_RVSCNTL_RVSEN BIT(0) 33f63968baSMarek Vasut #define RENESAS_SDHI_SCC_RVSREQ 0x814 34f63968baSMarek Vasut #define RENESAS_SDHI_SCC_RVSREQ_RVSERR BIT(2) 35f63968baSMarek Vasut #define RENESAS_SDHI_SCC_SMPCMP 0x818 36f63968baSMarek Vasut #define RENESAS_SDHI_SCC_TMPPORT2 0x81c 37*dc1488f1SMarek Vasut #define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31) 38*dc1488f1SMarek Vasut #define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4) 39f63968baSMarek Vasut 40f63968baSMarek Vasut #define RENESAS_SDHI_MAX_TAP 3 41f63968baSMarek Vasut 42cb0b6b03SMarek Vasut static unsigned int renesas_sdhi_init_tuning(struct tmio_sd_priv *priv) 43f63968baSMarek Vasut { 44f63968baSMarek Vasut u32 reg; 45f63968baSMarek Vasut 46f63968baSMarek Vasut /* Initialize SCC */ 47cb0b6b03SMarek Vasut tmio_sd_writel(priv, 0, TMIO_SD_INFO1); 48f63968baSMarek Vasut 49cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL); 50cb0b6b03SMarek Vasut reg &= ~TMIO_SD_CLKCTL_SCLKEN; 51cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL); 52f63968baSMarek Vasut 53f63968baSMarek Vasut /* Set sampling clock selection range */ 54cb0b6b03SMarek Vasut tmio_sd_writel(priv, 0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT, 55f63968baSMarek Vasut RENESAS_SDHI_SCC_DTCNTL); 56f63968baSMarek Vasut 57cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL); 58f63968baSMarek Vasut reg |= RENESAS_SDHI_SCC_DTCNTL_TAPEN; 59cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_DTCNTL); 60f63968baSMarek Vasut 61cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); 62f63968baSMarek Vasut reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL; 63cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); 64f63968baSMarek Vasut 65cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); 66f63968baSMarek Vasut reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; 67cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); 68f63968baSMarek Vasut 69cb0b6b03SMarek Vasut tmio_sd_writel(priv, 0x300 /* scc_tappos */, 70f63968baSMarek Vasut RENESAS_SDHI_SCC_DT2FF); 71f63968baSMarek Vasut 72cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL); 73cb0b6b03SMarek Vasut reg |= TMIO_SD_CLKCTL_SCLKEN; 74cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL); 75f63968baSMarek Vasut 76f63968baSMarek Vasut /* Read TAPNUM */ 77cb0b6b03SMarek Vasut return (tmio_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL) >> 78f63968baSMarek Vasut RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & 79f63968baSMarek Vasut RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK; 80f63968baSMarek Vasut } 81f63968baSMarek Vasut 82cb0b6b03SMarek Vasut static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv) 83f63968baSMarek Vasut { 84f63968baSMarek Vasut u32 reg; 85f63968baSMarek Vasut 86f63968baSMarek Vasut /* Reset SCC */ 87cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL); 88cb0b6b03SMarek Vasut reg &= ~TMIO_SD_CLKCTL_SCLKEN; 89cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL); 90f63968baSMarek Vasut 91cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); 92f63968baSMarek Vasut reg &= ~RENESAS_SDHI_SCC_CKSEL_DTSEL; 93cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); 94f63968baSMarek Vasut 95*dc1488f1SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2); 96*dc1488f1SMarek Vasut reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN | 97*dc1488f1SMarek Vasut RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL); 98*dc1488f1SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2); 99*dc1488f1SMarek Vasut 100cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL); 101cb0b6b03SMarek Vasut reg |= TMIO_SD_CLKCTL_SCLKEN; 102cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL); 103f63968baSMarek Vasut 104cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); 105f63968baSMarek Vasut reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; 106cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); 107f63968baSMarek Vasut 108cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); 109f63968baSMarek Vasut reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; 110cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); 111f63968baSMarek Vasut } 112f63968baSMarek Vasut 113cb0b6b03SMarek Vasut static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv, 114f63968baSMarek Vasut unsigned long tap) 115f63968baSMarek Vasut { 116f63968baSMarek Vasut /* Set sampling clock position */ 117cb0b6b03SMarek Vasut tmio_sd_writel(priv, tap, RENESAS_SDHI_SCC_TAPSET); 118f63968baSMarek Vasut } 119f63968baSMarek Vasut 120cb0b6b03SMarek Vasut static unsigned int renesas_sdhi_compare_scc_data(struct tmio_sd_priv *priv) 121f63968baSMarek Vasut { 122f63968baSMarek Vasut /* Get comparison of sampling data */ 123cb0b6b03SMarek Vasut return tmio_sd_readl(priv, RENESAS_SDHI_SCC_SMPCMP); 124f63968baSMarek Vasut } 125f63968baSMarek Vasut 126cb0b6b03SMarek Vasut static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, 127f63968baSMarek Vasut unsigned int tap_num, unsigned int taps, 128f63968baSMarek Vasut unsigned int smpcmp) 129f63968baSMarek Vasut { 130f63968baSMarek Vasut unsigned long tap_cnt; /* counter of tuning success */ 131f63968baSMarek Vasut unsigned long tap_set; /* tap position */ 132f63968baSMarek Vasut unsigned long tap_start;/* start position of tuning success */ 133f63968baSMarek Vasut unsigned long tap_end; /* end position of tuning success */ 134f63968baSMarek Vasut unsigned long ntap; /* temporary counter of tuning success */ 135f63968baSMarek Vasut unsigned long match_cnt;/* counter of matching data */ 136f63968baSMarek Vasut unsigned long i; 137f63968baSMarek Vasut bool select = false; 138f63968baSMarek Vasut u32 reg; 139f63968baSMarek Vasut 140f63968baSMarek Vasut /* Clear SCC_RVSREQ */ 141cb0b6b03SMarek Vasut tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ); 142f63968baSMarek Vasut 143f63968baSMarek Vasut /* Merge the results */ 144f63968baSMarek Vasut for (i = 0; i < tap_num * 2; i++) { 145f63968baSMarek Vasut if (!(taps & BIT(i))) { 146f63968baSMarek Vasut taps &= ~BIT(i % tap_num); 147f63968baSMarek Vasut taps &= ~BIT((i % tap_num) + tap_num); 148f63968baSMarek Vasut } 149f63968baSMarek Vasut if (!(smpcmp & BIT(i))) { 150f63968baSMarek Vasut smpcmp &= ~BIT(i % tap_num); 151f63968baSMarek Vasut smpcmp &= ~BIT((i % tap_num) + tap_num); 152f63968baSMarek Vasut } 153f63968baSMarek Vasut } 154f63968baSMarek Vasut 155f63968baSMarek Vasut /* 156f63968baSMarek Vasut * Find the longest consecutive run of successful probes. If that 157f63968baSMarek Vasut * is more than RENESAS_SDHI_MAX_TAP probes long then use the 158f63968baSMarek Vasut * center index as the tap. 159f63968baSMarek Vasut */ 160f63968baSMarek Vasut tap_cnt = 0; 161f63968baSMarek Vasut ntap = 0; 162f63968baSMarek Vasut tap_start = 0; 163f63968baSMarek Vasut tap_end = 0; 164f63968baSMarek Vasut for (i = 0; i < tap_num * 2; i++) { 165f63968baSMarek Vasut if (taps & BIT(i)) 166f63968baSMarek Vasut ntap++; 167f63968baSMarek Vasut else { 168f63968baSMarek Vasut if (ntap > tap_cnt) { 169f63968baSMarek Vasut tap_start = i - ntap; 170f63968baSMarek Vasut tap_end = i - 1; 171f63968baSMarek Vasut tap_cnt = ntap; 172f63968baSMarek Vasut } 173f63968baSMarek Vasut ntap = 0; 174f63968baSMarek Vasut } 175f63968baSMarek Vasut } 176f63968baSMarek Vasut 177f63968baSMarek Vasut if (ntap > tap_cnt) { 178f63968baSMarek Vasut tap_start = i - ntap; 179f63968baSMarek Vasut tap_end = i - 1; 180f63968baSMarek Vasut tap_cnt = ntap; 181f63968baSMarek Vasut } 182f63968baSMarek Vasut 183f63968baSMarek Vasut /* 184f63968baSMarek Vasut * If all of the TAP is OK, the sampling clock position is selected by 185f63968baSMarek Vasut * identifying the change point of data. 186f63968baSMarek Vasut */ 187f63968baSMarek Vasut if (tap_cnt == tap_num * 2) { 188f63968baSMarek Vasut match_cnt = 0; 189f63968baSMarek Vasut ntap = 0; 190f63968baSMarek Vasut tap_start = 0; 191f63968baSMarek Vasut tap_end = 0; 192f63968baSMarek Vasut for (i = 0; i < tap_num * 2; i++) { 193f63968baSMarek Vasut if (smpcmp & BIT(i)) 194f63968baSMarek Vasut ntap++; 195f63968baSMarek Vasut else { 196f63968baSMarek Vasut if (ntap > match_cnt) { 197f63968baSMarek Vasut tap_start = i - ntap; 198f63968baSMarek Vasut tap_end = i - 1; 199f63968baSMarek Vasut match_cnt = ntap; 200f63968baSMarek Vasut } 201f63968baSMarek Vasut ntap = 0; 202f63968baSMarek Vasut } 203f63968baSMarek Vasut } 204f63968baSMarek Vasut if (ntap > match_cnt) { 205f63968baSMarek Vasut tap_start = i - ntap; 206f63968baSMarek Vasut tap_end = i - 1; 207f63968baSMarek Vasut match_cnt = ntap; 208f63968baSMarek Vasut } 209f63968baSMarek Vasut if (match_cnt) 210f63968baSMarek Vasut select = true; 211f63968baSMarek Vasut } else if (tap_cnt >= RENESAS_SDHI_MAX_TAP) 212f63968baSMarek Vasut select = true; 213f63968baSMarek Vasut 214f63968baSMarek Vasut if (select) 215f63968baSMarek Vasut tap_set = ((tap_start + tap_end) / 2) % tap_num; 216f63968baSMarek Vasut else 217f63968baSMarek Vasut return -EIO; 218f63968baSMarek Vasut 219f63968baSMarek Vasut /* Set SCC */ 220cb0b6b03SMarek Vasut tmio_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET); 221f63968baSMarek Vasut 222f63968baSMarek Vasut /* Enable auto re-tuning */ 223cb0b6b03SMarek Vasut reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); 224f63968baSMarek Vasut reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN; 225cb0b6b03SMarek Vasut tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); 226f63968baSMarek Vasut 227f63968baSMarek Vasut return 0; 228f63968baSMarek Vasut } 229f63968baSMarek Vasut 230f63968baSMarek Vasut int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) 231f63968baSMarek Vasut { 232cb0b6b03SMarek Vasut struct tmio_sd_priv *priv = dev_get_priv(dev); 233f63968baSMarek Vasut struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 234f63968baSMarek Vasut struct mmc *mmc = upriv->mmc; 235f63968baSMarek Vasut unsigned int tap_num; 236f63968baSMarek Vasut unsigned int taps = 0, smpcmp = 0; 237f63968baSMarek Vasut int i, ret = 0; 238f63968baSMarek Vasut u32 caps; 239f63968baSMarek Vasut 240f63968baSMarek Vasut /* Only supported on Renesas RCar */ 241cb0b6b03SMarek Vasut if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS)) 242f63968baSMarek Vasut return -EINVAL; 243f63968baSMarek Vasut 244f63968baSMarek Vasut /* clock tuning is not needed for upto 52MHz */ 245f63968baSMarek Vasut if (!((mmc->selected_mode == MMC_HS_200) || 246f63968baSMarek Vasut (mmc->selected_mode == UHS_SDR104) || 247f63968baSMarek Vasut (mmc->selected_mode == UHS_SDR50))) 248f63968baSMarek Vasut return 0; 249f63968baSMarek Vasut 250f63968baSMarek Vasut tap_num = renesas_sdhi_init_tuning(priv); 251f63968baSMarek Vasut if (!tap_num) 252f63968baSMarek Vasut /* Tuning is not supported */ 253f63968baSMarek Vasut goto out; 254f63968baSMarek Vasut 255f63968baSMarek Vasut if (tap_num * 2 >= sizeof(taps) * 8) { 256f63968baSMarek Vasut dev_err(dev, 257f63968baSMarek Vasut "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n"); 258f63968baSMarek Vasut goto out; 259f63968baSMarek Vasut } 260f63968baSMarek Vasut 261f63968baSMarek Vasut /* Issue CMD19 twice for each tap */ 262f63968baSMarek Vasut for (i = 0; i < 2 * tap_num; i++) { 263f63968baSMarek Vasut renesas_sdhi_prepare_tuning(priv, i % tap_num); 264f63968baSMarek Vasut 265f63968baSMarek Vasut /* Force PIO for the tuning */ 266f63968baSMarek Vasut caps = priv->caps; 267cb0b6b03SMarek Vasut priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL; 268f63968baSMarek Vasut 269f63968baSMarek Vasut ret = mmc_send_tuning(mmc, opcode, NULL); 270f63968baSMarek Vasut 271f63968baSMarek Vasut priv->caps = caps; 272f63968baSMarek Vasut 273f63968baSMarek Vasut if (ret == 0) 274f63968baSMarek Vasut taps |= BIT(i); 275f63968baSMarek Vasut 276f63968baSMarek Vasut ret = renesas_sdhi_compare_scc_data(priv); 277f63968baSMarek Vasut if (ret == 0) 278f63968baSMarek Vasut smpcmp |= BIT(i); 279f63968baSMarek Vasut 280f63968baSMarek Vasut mdelay(1); 281f63968baSMarek Vasut } 282f63968baSMarek Vasut 283f63968baSMarek Vasut ret = renesas_sdhi_select_tuning(priv, tap_num, taps, smpcmp); 284f63968baSMarek Vasut 285f63968baSMarek Vasut out: 286f63968baSMarek Vasut if (ret < 0) { 287f63968baSMarek Vasut dev_warn(dev, "Tuning procedure failed\n"); 288f63968baSMarek Vasut renesas_sdhi_reset_tuning(priv); 289f63968baSMarek Vasut } 290f63968baSMarek Vasut 291f63968baSMarek Vasut return ret; 292f63968baSMarek Vasut } 293f63968baSMarek Vasut #endif 294f63968baSMarek Vasut 295f63968baSMarek Vasut static int renesas_sdhi_set_ios(struct udevice *dev) 296f63968baSMarek Vasut { 297cb0b6b03SMarek Vasut int ret = tmio_sd_set_ios(dev); 298cf39f3f3SMarek Vasut 299cf39f3f3SMarek Vasut mdelay(10); 300cf39f3f3SMarek Vasut 301f63968baSMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 302cb0b6b03SMarek Vasut struct tmio_sd_priv *priv = dev_get_priv(dev); 303f63968baSMarek Vasut 30452e17968SMarek Vasut if (priv->caps & TMIO_SD_CAP_RCAR_UHS) 305f63968baSMarek Vasut renesas_sdhi_reset_tuning(priv); 306f63968baSMarek Vasut #endif 307f63968baSMarek Vasut 308f63968baSMarek Vasut return ret; 309f63968baSMarek Vasut } 310f63968baSMarek Vasut 311e94cad93SMarek Vasut static const struct dm_mmc_ops renesas_sdhi_ops = { 312cb0b6b03SMarek Vasut .send_cmd = tmio_sd_send_cmd, 313f63968baSMarek Vasut .set_ios = renesas_sdhi_set_ios, 314cb0b6b03SMarek Vasut .get_cd = tmio_sd_get_cd, 315f63968baSMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 316f63968baSMarek Vasut .execute_tuning = renesas_sdhi_execute_tuning, 317f63968baSMarek Vasut #endif 318e94cad93SMarek Vasut }; 319e94cad93SMarek Vasut 320cb0b6b03SMarek Vasut #define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2 321f98833dbSMarek Vasut #define RENESAS_GEN3_QUIRKS \ 322cb0b6b03SMarek Vasut TMIO_SD_CAP_64BIT | TMIO_SD_CAP_RCAR_GEN3 | TMIO_SD_CAP_RCAR_UHS 323f98833dbSMarek Vasut 324e94cad93SMarek Vasut static const struct udevice_id renesas_sdhi_match[] = { 325f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7790", .data = RENESAS_GEN2_QUIRKS }, 326f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7791", .data = RENESAS_GEN2_QUIRKS }, 327f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7792", .data = RENESAS_GEN2_QUIRKS }, 328f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7793", .data = RENESAS_GEN2_QUIRKS }, 329f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS }, 330f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS }, 331f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS }, 332f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS }, 333f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS }, 334d629152aSMarek Vasut { .compatible = "renesas,sdhi-r8a77990", .data = RENESAS_GEN3_QUIRKS }, 335f98833dbSMarek Vasut { .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_GEN3_QUIRKS }, 336e94cad93SMarek Vasut { /* sentinel */ } 337e94cad93SMarek Vasut }; 338e94cad93SMarek Vasut 339c769e609SMarek Vasut static int renesas_sdhi_probe(struct udevice *dev) 340c769e609SMarek Vasut { 34130b5d9aaSMasahiro Yamada struct tmio_sd_priv *priv = dev_get_priv(dev); 342c769e609SMarek Vasut u32 quirks = dev_get_driver_data(dev); 3437cf7ef81SMarek Vasut struct fdt_resource reg_res; 34430b5d9aaSMasahiro Yamada struct clk clk; 3457cf7ef81SMarek Vasut DECLARE_GLOBAL_DATA_PTR; 3467cf7ef81SMarek Vasut int ret; 3477cf7ef81SMarek Vasut 348f98833dbSMarek Vasut if (quirks == RENESAS_GEN2_QUIRKS) { 349f98833dbSMarek Vasut ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), 350f98833dbSMarek Vasut "reg", 0, ®_res); 3517cf7ef81SMarek Vasut if (ret < 0) { 352f98833dbSMarek Vasut dev_err(dev, "\"reg\" resource not found, ret=%i\n", 353f98833dbSMarek Vasut ret); 3547cf7ef81SMarek Vasut return ret; 3557cf7ef81SMarek Vasut } 3567cf7ef81SMarek Vasut 357f98833dbSMarek Vasut if (fdt_resource_size(®_res) == 0x100) 358cb0b6b03SMarek Vasut quirks |= TMIO_SD_CAP_16BIT; 359f98833dbSMarek Vasut } 360c769e609SMarek Vasut 36130b5d9aaSMasahiro Yamada ret = clk_get_by_index(dev, 0, &clk); 36230b5d9aaSMasahiro Yamada if (ret < 0) { 36330b5d9aaSMasahiro Yamada dev_err(dev, "failed to get host clock\n"); 36430b5d9aaSMasahiro Yamada return ret; 36530b5d9aaSMasahiro Yamada } 36630b5d9aaSMasahiro Yamada 36730b5d9aaSMasahiro Yamada /* set to max rate */ 36830b5d9aaSMasahiro Yamada priv->mclk = clk_set_rate(&clk, ULONG_MAX); 36930b5d9aaSMasahiro Yamada if (IS_ERR_VALUE(priv->mclk)) { 37030b5d9aaSMasahiro Yamada dev_err(dev, "failed to set rate for host clock\n"); 37130b5d9aaSMasahiro Yamada clk_free(&clk); 37230b5d9aaSMasahiro Yamada return priv->mclk; 37330b5d9aaSMasahiro Yamada } 37430b5d9aaSMasahiro Yamada 37530b5d9aaSMasahiro Yamada ret = clk_enable(&clk); 37630b5d9aaSMasahiro Yamada clk_free(&clk); 37730b5d9aaSMasahiro Yamada if (ret) { 37830b5d9aaSMasahiro Yamada dev_err(dev, "failed to enable host clock\n"); 37930b5d9aaSMasahiro Yamada return ret; 38030b5d9aaSMasahiro Yamada } 38130b5d9aaSMasahiro Yamada 382cb0b6b03SMarek Vasut ret = tmio_sd_probe(dev, quirks); 383f63968baSMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 38452e17968SMarek Vasut if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) 38565186977SMarek Vasut renesas_sdhi_reset_tuning(priv); 386f63968baSMarek Vasut #endif 387f63968baSMarek Vasut return ret; 388c769e609SMarek Vasut } 389c769e609SMarek Vasut 390e94cad93SMarek Vasut U_BOOT_DRIVER(renesas_sdhi) = { 391e94cad93SMarek Vasut .name = "renesas-sdhi", 392e94cad93SMarek Vasut .id = UCLASS_MMC, 393e94cad93SMarek Vasut .of_match = renesas_sdhi_match, 394cb0b6b03SMarek Vasut .bind = tmio_sd_bind, 395c769e609SMarek Vasut .probe = renesas_sdhi_probe, 396cb0b6b03SMarek Vasut .priv_auto_alloc_size = sizeof(struct tmio_sd_priv), 397cb0b6b03SMarek Vasut .platdata_auto_alloc_size = sizeof(struct tmio_sd_plat), 398e94cad93SMarek Vasut .ops = &renesas_sdhi_ops, 399e94cad93SMarek Vasut }; 400