1f52d9c4fSPeter Griffin /* 2f52d9c4fSPeter Griffin * Support for SDHCI on STMicroelectronics SoCs 3f52d9c4fSPeter Griffin * 4f52d9c4fSPeter Griffin * Copyright (C) 2014 STMicroelectronics Ltd 5f52d9c4fSPeter Griffin * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 6f52d9c4fSPeter Griffin * Contributors: Peter Griffin <peter.griffin@linaro.org> 7f52d9c4fSPeter Griffin * 8f52d9c4fSPeter Griffin * Based on sdhci-cns3xxx.c 9f52d9c4fSPeter Griffin * 10f52d9c4fSPeter Griffin * This program is free software; you can redistribute it and/or modify 11f52d9c4fSPeter Griffin * it under the terms of the GNU General Public License version 2 as 12f52d9c4fSPeter Griffin * published by the Free Software Foundation. 13f52d9c4fSPeter Griffin * 14f52d9c4fSPeter Griffin * This program is distributed in the hope that it will be useful, 15f52d9c4fSPeter Griffin * but WITHOUT ANY WARRANTY; without even the implied warranty of 16f52d9c4fSPeter Griffin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17f52d9c4fSPeter Griffin * GNU General Public License for more details. 18f52d9c4fSPeter Griffin * 19f52d9c4fSPeter Griffin */ 20f52d9c4fSPeter Griffin 21f52d9c4fSPeter Griffin #include <linux/io.h> 22f52d9c4fSPeter Griffin #include <linux/of.h> 23f52d9c4fSPeter Griffin #include <linux/module.h> 24f52d9c4fSPeter Griffin #include <linux/err.h> 25f52d9c4fSPeter Griffin #include <linux/mmc/host.h> 26f52d9c4fSPeter Griffin 27f52d9c4fSPeter Griffin #include "sdhci-pltfm.h" 28f52d9c4fSPeter Griffin 298bef7178SPeter Griffin /* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */ 308bef7178SPeter Griffin 318bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_1 0x400 328bef7178SPeter Griffin #define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT BIT(24) 338bef7178SPeter Griffin #define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ BIT(12) 348bef7178SPeter Griffin #define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT BIT(8) 358bef7178SPeter Griffin #define ST_MMC_CCONFIG_ASYNC_WAKEUP BIT(0) 368bef7178SPeter Griffin #define ST_MMC_CCONFIG_1_DEFAULT \ 378bef7178SPeter Griffin ((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \ 388bef7178SPeter Griffin (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \ 398bef7178SPeter Griffin (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT)) 408bef7178SPeter Griffin 418bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_2 0x404 428bef7178SPeter Griffin #define ST_MMC_CCONFIG_HIGH_SPEED BIT(28) 438bef7178SPeter Griffin #define ST_MMC_CCONFIG_ADMA2 BIT(24) 448bef7178SPeter Griffin #define ST_MMC_CCONFIG_8BIT BIT(20) 458bef7178SPeter Griffin #define ST_MMC_CCONFIG_MAX_BLK_LEN 16 468bef7178SPeter Griffin #define MAX_BLK_LEN_1024 1 478bef7178SPeter Griffin #define MAX_BLK_LEN_2048 2 488bef7178SPeter Griffin #define BASE_CLK_FREQ_200 0xc8 498bef7178SPeter Griffin #define BASE_CLK_FREQ_100 0x64 508bef7178SPeter Griffin #define BASE_CLK_FREQ_50 0x32 518bef7178SPeter Griffin #define ST_MMC_CCONFIG_2_DEFAULT \ 528bef7178SPeter Griffin (ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \ 538bef7178SPeter Griffin ST_MMC_CCONFIG_8BIT | \ 548bef7178SPeter Griffin (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN)) 558bef7178SPeter Griffin 568bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_3 0x408 578bef7178SPeter Griffin #define ST_MMC_CCONFIG_EMMC_SLOT_TYPE BIT(28) 588bef7178SPeter Griffin #define ST_MMC_CCONFIG_64BIT BIT(24) 598bef7178SPeter Griffin #define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT BIT(20) 608bef7178SPeter Griffin #define ST_MMC_CCONFIG_1P8_VOLT BIT(16) 618bef7178SPeter Griffin #define ST_MMC_CCONFIG_3P0_VOLT BIT(12) 628bef7178SPeter Griffin #define ST_MMC_CCONFIG_3P3_VOLT BIT(8) 638bef7178SPeter Griffin #define ST_MMC_CCONFIG_SUSP_RES_SUPPORT BIT(4) 648bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDMA BIT(0) 658bef7178SPeter Griffin #define ST_MMC_CCONFIG_3_DEFAULT \ 668bef7178SPeter Griffin (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT | \ 678bef7178SPeter Griffin ST_MMC_CCONFIG_3P3_VOLT | \ 688bef7178SPeter Griffin ST_MMC_CCONFIG_SUSP_RES_SUPPORT | \ 698bef7178SPeter Griffin ST_MMC_CCONFIG_SDMA) 708bef7178SPeter Griffin 718bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_4 0x40c 728bef7178SPeter Griffin #define ST_MMC_CCONFIG_D_DRIVER BIT(20) 738bef7178SPeter Griffin #define ST_MMC_CCONFIG_C_DRIVER BIT(16) 748bef7178SPeter Griffin #define ST_MMC_CCONFIG_A_DRIVER BIT(12) 758bef7178SPeter Griffin #define ST_MMC_CCONFIG_DDR50 BIT(8) 768bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDR104 BIT(4) 778bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDR50 BIT(0) 788bef7178SPeter Griffin #define ST_MMC_CCONFIG_4_DEFAULT 0 798bef7178SPeter Griffin 808bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_5 0x410 818bef7178SPeter Griffin #define ST_MMC_CCONFIG_TUNING_FOR_SDR50 BIT(8) 828bef7178SPeter Griffin #define RETUNING_TIMER_CNT_MAX 0xf 838bef7178SPeter Griffin #define ST_MMC_CCONFIG_5_DEFAULT 0 848bef7178SPeter Griffin 858bef7178SPeter Griffin /* I/O configuration for Arasan IP */ 868bef7178SPeter Griffin #define ST_MMC_GP_OUTPUT 0x450 878bef7178SPeter Griffin #define ST_MMC_GP_OUTPUT_CD BIT(12) 888bef7178SPeter Griffin 898bef7178SPeter Griffin #define ST_MMC_STATUS_R 0x460 908bef7178SPeter Griffin 918bef7178SPeter Griffin #define ST_TOP_MMC_DLY_FIX_OFF(x) (x - 0x8) 928bef7178SPeter Griffin 938bef7178SPeter Griffin /* TOP config registers to manage static and dynamic delay */ 948bef7178SPeter Griffin #define ST_TOP_MMC_TX_CLK_DLY ST_TOP_MMC_DLY_FIX_OFF(0x8) 958bef7178SPeter Griffin #define ST_TOP_MMC_RX_CLK_DLY ST_TOP_MMC_DLY_FIX_OFF(0xc) 968bef7178SPeter Griffin /* MMC delay control register */ 978bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL ST_TOP_MMC_DLY_FIX_OFF(0x18) 988bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD BIT(0) 998bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL BIT(1) 1008bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE BIT(8) 1018bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE BIT(9) 1028bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY BIT(10) 1038bef7178SPeter Griffin #define ST_TOP_MMC_START_DLL_LOCK BIT(11) 1048bef7178SPeter Griffin 1058bef7178SPeter Griffin /* register to provide the phase-shift value for DLL */ 1068bef7178SPeter Griffin #define ST_TOP_MMC_TX_DLL_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x1c) 1078bef7178SPeter Griffin #define ST_TOP_MMC_RX_DLL_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x20) 1088bef7178SPeter Griffin #define ST_TOP_MMC_RX_CMD_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x24) 1098bef7178SPeter Griffin 1108bef7178SPeter Griffin /* phase shift delay on the tx clk 2.188ns */ 1118bef7178SPeter Griffin #define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID 0x6 1128bef7178SPeter Griffin 1138bef7178SPeter Griffin #define ST_TOP_MMC_DLY_MAX 0xf 1148bef7178SPeter Griffin 1158bef7178SPeter Griffin #define ST_TOP_MMC_DYN_DLY_CONF \ 1168bef7178SPeter Griffin (ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \ 1178bef7178SPeter Griffin ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \ 1188bef7178SPeter Griffin ST_TOP_MMC_START_DLL_LOCK) 1198bef7178SPeter Griffin 120f52d9c4fSPeter Griffin static u32 sdhci_st_readl(struct sdhci_host *host, int reg) 121f52d9c4fSPeter Griffin { 122f52d9c4fSPeter Griffin u32 ret; 123f52d9c4fSPeter Griffin 124f52d9c4fSPeter Griffin switch (reg) { 125f52d9c4fSPeter Griffin case SDHCI_CAPABILITIES: 126f52d9c4fSPeter Griffin ret = readl_relaxed(host->ioaddr + reg); 127f52d9c4fSPeter Griffin /* Support 3.3V and 1.8V */ 128f52d9c4fSPeter Griffin ret &= ~SDHCI_CAN_VDD_300; 129f52d9c4fSPeter Griffin break; 130f52d9c4fSPeter Griffin default: 131f52d9c4fSPeter Griffin ret = readl_relaxed(host->ioaddr + reg); 132f52d9c4fSPeter Griffin } 133f52d9c4fSPeter Griffin return ret; 134f52d9c4fSPeter Griffin } 135f52d9c4fSPeter Griffin 136f52d9c4fSPeter Griffin static const struct sdhci_ops sdhci_st_ops = { 137f52d9c4fSPeter Griffin .get_max_clock = sdhci_pltfm_clk_get_max_clock, 138f52d9c4fSPeter Griffin .set_clock = sdhci_set_clock, 139f52d9c4fSPeter Griffin .set_bus_width = sdhci_set_bus_width, 140f52d9c4fSPeter Griffin .read_l = sdhci_st_readl, 141f52d9c4fSPeter Griffin .reset = sdhci_reset, 142f52d9c4fSPeter Griffin }; 143f52d9c4fSPeter Griffin 144f52d9c4fSPeter Griffin static const struct sdhci_pltfm_data sdhci_st_pdata = { 145f52d9c4fSPeter Griffin .ops = &sdhci_st_ops, 146f52d9c4fSPeter Griffin .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 147f52d9c4fSPeter Griffin SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 148f52d9c4fSPeter Griffin }; 149f52d9c4fSPeter Griffin 150f52d9c4fSPeter Griffin 151f52d9c4fSPeter Griffin static int sdhci_st_probe(struct platform_device *pdev) 152f52d9c4fSPeter Griffin { 153f52d9c4fSPeter Griffin struct sdhci_host *host; 154f52d9c4fSPeter Griffin struct sdhci_pltfm_host *pltfm_host; 155f52d9c4fSPeter Griffin struct clk *clk; 156f52d9c4fSPeter Griffin int ret = 0; 157f52d9c4fSPeter Griffin u16 host_version; 158f52d9c4fSPeter Griffin 159f52d9c4fSPeter Griffin clk = devm_clk_get(&pdev->dev, "mmc"); 160f52d9c4fSPeter Griffin if (IS_ERR(clk)) { 161f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Peripheral clk not found\n"); 162f52d9c4fSPeter Griffin return PTR_ERR(clk); 163f52d9c4fSPeter Griffin } 164f52d9c4fSPeter Griffin 165f52d9c4fSPeter Griffin host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0); 166f52d9c4fSPeter Griffin if (IS_ERR(host)) { 167f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n"); 168f52d9c4fSPeter Griffin return PTR_ERR(host); 169f52d9c4fSPeter Griffin } 170f52d9c4fSPeter Griffin 171f52d9c4fSPeter Griffin ret = mmc_of_parse(host->mmc); 172f52d9c4fSPeter Griffin if (ret) { 173f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Failed mmc_of_parse\n"); 174fc702cb3SUlf Hansson goto err_of; 175f52d9c4fSPeter Griffin } 176f52d9c4fSPeter Griffin 177f52d9c4fSPeter Griffin clk_prepare_enable(clk); 178f52d9c4fSPeter Griffin 179f52d9c4fSPeter Griffin pltfm_host = sdhci_priv(host); 180f52d9c4fSPeter Griffin pltfm_host->clk = clk; 181f52d9c4fSPeter Griffin 182f52d9c4fSPeter Griffin ret = sdhci_add_host(host); 183f52d9c4fSPeter Griffin if (ret) { 184f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Failed sdhci_add_host\n"); 185f52d9c4fSPeter Griffin goto err_out; 186f52d9c4fSPeter Griffin } 187f52d9c4fSPeter Griffin 188f52d9c4fSPeter Griffin platform_set_drvdata(pdev, host); 189f52d9c4fSPeter Griffin 190f52d9c4fSPeter Griffin host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); 191f52d9c4fSPeter Griffin 192f52d9c4fSPeter Griffin dev_info(&pdev->dev, "SDHCI ST Initialised: Host Version: 0x%x Vendor Version 0x%x\n", 193f52d9c4fSPeter Griffin ((host_version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT), 194f52d9c4fSPeter Griffin ((host_version & SDHCI_VENDOR_VER_MASK) >> 195f52d9c4fSPeter Griffin SDHCI_VENDOR_VER_SHIFT)); 196f52d9c4fSPeter Griffin 197f52d9c4fSPeter Griffin return 0; 198f52d9c4fSPeter Griffin 199f52d9c4fSPeter Griffin err_out: 200f52d9c4fSPeter Griffin clk_disable_unprepare(clk); 201fc702cb3SUlf Hansson err_of: 202f52d9c4fSPeter Griffin sdhci_pltfm_free(pdev); 203f52d9c4fSPeter Griffin 204f52d9c4fSPeter Griffin return ret; 205f52d9c4fSPeter Griffin } 206f52d9c4fSPeter Griffin 207f52d9c4fSPeter Griffin #ifdef CONFIG_PM_SLEEP 208f52d9c4fSPeter Griffin static int sdhci_st_suspend(struct device *dev) 209f52d9c4fSPeter Griffin { 210f52d9c4fSPeter Griffin struct sdhci_host *host = dev_get_drvdata(dev); 211f52d9c4fSPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 212f52d9c4fSPeter Griffin int ret = sdhci_suspend_host(host); 213f52d9c4fSPeter Griffin 214f52d9c4fSPeter Griffin if (ret) 215f52d9c4fSPeter Griffin goto out; 216f52d9c4fSPeter Griffin 217f52d9c4fSPeter Griffin clk_disable_unprepare(pltfm_host->clk); 218f52d9c4fSPeter Griffin out: 219f52d9c4fSPeter Griffin return ret; 220f52d9c4fSPeter Griffin } 221f52d9c4fSPeter Griffin 222f52d9c4fSPeter Griffin static int sdhci_st_resume(struct device *dev) 223f52d9c4fSPeter Griffin { 224f52d9c4fSPeter Griffin struct sdhci_host *host = dev_get_drvdata(dev); 225f52d9c4fSPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 226f52d9c4fSPeter Griffin 227f52d9c4fSPeter Griffin clk_prepare_enable(pltfm_host->clk); 228f52d9c4fSPeter Griffin 229f52d9c4fSPeter Griffin return sdhci_resume_host(host); 230f52d9c4fSPeter Griffin } 231f52d9c4fSPeter Griffin #endif 232f52d9c4fSPeter Griffin 233f52d9c4fSPeter Griffin static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume); 234f52d9c4fSPeter Griffin 235f52d9c4fSPeter Griffin static const struct of_device_id st_sdhci_match[] = { 236f52d9c4fSPeter Griffin { .compatible = "st,sdhci" }, 237f52d9c4fSPeter Griffin {}, 238f52d9c4fSPeter Griffin }; 239f52d9c4fSPeter Griffin 240f52d9c4fSPeter Griffin MODULE_DEVICE_TABLE(of, st_sdhci_match); 241f52d9c4fSPeter Griffin 242f52d9c4fSPeter Griffin static struct platform_driver sdhci_st_driver = { 243f52d9c4fSPeter Griffin .probe = sdhci_st_probe, 244caebcae9SKevin Hao .remove = sdhci_pltfm_unregister, 245f52d9c4fSPeter Griffin .driver = { 246f52d9c4fSPeter Griffin .name = "sdhci-st", 247f52d9c4fSPeter Griffin .pm = &sdhci_st_pmops, 248f52d9c4fSPeter Griffin .of_match_table = of_match_ptr(st_sdhci_match), 249f52d9c4fSPeter Griffin }, 250f52d9c4fSPeter Griffin }; 251f52d9c4fSPeter Griffin 252f52d9c4fSPeter Griffin module_platform_driver(sdhci_st_driver); 253f52d9c4fSPeter Griffin 254f52d9c4fSPeter Griffin MODULE_DESCRIPTION("SDHCI driver for STMicroelectronics SoCs"); 255f52d9c4fSPeter Griffin MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>"); 256f52d9c4fSPeter Griffin MODULE_LICENSE("GPL v2"); 257f52d9c4fSPeter Griffin MODULE_ALIAS("platform:st-sdhci"); 258