1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * drivers/mmc/host/sdhci-of-sparx5.c 4 * 5 * MCHP Sparx5 SoC Secure Digital Host Controller Interface. 6 * 7 * Copyright (c) 2019 Microchip Inc. 8 * 9 * Author: Lars Povlsen <lars.povlsen@microchip.com> 10 */ 11 12 #include <linux/sizes.h> 13 #include <linux/delay.h> 14 #include <linux/module.h> 15 #include <linux/regmap.h> 16 #include <linux/of_device.h> 17 #include <linux/mfd/syscon.h> 18 #include <linux/dma-mapping.h> 19 20 #include "sdhci-pltfm.h" 21 22 #define CPU_REGS_GENERAL_CTRL (0x22 * 4) 23 #define MSHC_DLY_CC_MASK GENMASK(16, 13) 24 #define MSHC_DLY_CC_SHIFT 13 25 #define MSHC_DLY_CC_MAX 15 26 27 #define CPU_REGS_PROC_CTRL (0x2C * 4) 28 #define ACP_CACHE_FORCE_ENA BIT(4) 29 #define ACP_AWCACHE BIT(3) 30 #define ACP_ARCACHE BIT(2) 31 #define ACP_CACHE_MASK (ACP_CACHE_FORCE_ENA|ACP_AWCACHE|ACP_ARCACHE) 32 33 #define MSHC2_VERSION 0x500 /* Off 0x140, reg 0x0 */ 34 #define MSHC2_TYPE 0x504 /* Off 0x140, reg 0x1 */ 35 #define MSHC2_EMMC_CTRL 0x52c /* Off 0x140, reg 0xB */ 36 #define MSHC2_EMMC_CTRL_EMMC_RST_N BIT(2) 37 #define MSHC2_EMMC_CTRL_IS_EMMC BIT(0) 38 39 struct sdhci_sparx5_data { 40 struct sdhci_host *host; 41 struct regmap *cpu_ctrl; 42 int delay_clock; 43 }; 44 45 #define BOUNDARY_OK(addr, len) \ 46 ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) 47 48 /* 49 * If DMA addr spans 128MB boundary, we split the DMA transfer into two 50 * so that each DMA transfer doesn't exceed the boundary. 51 */ 52 static void sdhci_sparx5_adma_write_desc(struct sdhci_host *host, void **desc, 53 dma_addr_t addr, int len, 54 unsigned int cmd) 55 { 56 int tmplen, offset; 57 58 if (likely(!len || BOUNDARY_OK(addr, len))) { 59 sdhci_adma_write_desc(host, desc, addr, len, cmd); 60 return; 61 } 62 63 pr_debug("%s: write_desc: splitting dma len %d, offset %pad\n", 64 mmc_hostname(host->mmc), len, &addr); 65 66 offset = addr & (SZ_128M - 1); 67 tmplen = SZ_128M - offset; 68 sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); 69 70 addr += tmplen; 71 len -= tmplen; 72 sdhci_adma_write_desc(host, desc, addr, len, cmd); 73 } 74 75 static void sparx5_set_cacheable(struct sdhci_host *host, u32 value) 76 { 77 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 78 struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host); 79 80 pr_debug("%s: Set Cacheable = 0x%x\n", mmc_hostname(host->mmc), value); 81 82 /* Update ACP caching attributes in HW */ 83 regmap_update_bits(sdhci_sparx5->cpu_ctrl, 84 CPU_REGS_PROC_CTRL, ACP_CACHE_MASK, value); 85 } 86 87 static void sparx5_set_delay(struct sdhci_host *host, u8 value) 88 { 89 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 90 struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host); 91 92 pr_debug("%s: Set DLY_CC = %u\n", mmc_hostname(host->mmc), value); 93 94 /* Update DLY_CC in HW */ 95 regmap_update_bits(sdhci_sparx5->cpu_ctrl, 96 CPU_REGS_GENERAL_CTRL, 97 MSHC_DLY_CC_MASK, 98 (value << MSHC_DLY_CC_SHIFT)); 99 } 100 101 static void sdhci_sparx5_set_emmc(struct sdhci_host *host) 102 { 103 if (!mmc_card_is_removable(host->mmc)) { 104 u8 value; 105 106 value = sdhci_readb(host, MSHC2_EMMC_CTRL); 107 if (!(value & MSHC2_EMMC_CTRL_IS_EMMC)) { 108 value |= MSHC2_EMMC_CTRL_IS_EMMC; 109 pr_debug("%s: Set EMMC_CTRL: 0x%08x\n", 110 mmc_hostname(host->mmc), value); 111 sdhci_writeb(host, value, MSHC2_EMMC_CTRL); 112 } 113 } 114 } 115 116 static void sdhci_sparx5_reset_emmc(struct sdhci_host *host) 117 { 118 u8 value; 119 120 pr_debug("%s: Toggle EMMC_CTRL.EMMC_RST_N\n", mmc_hostname(host->mmc)); 121 value = sdhci_readb(host, MSHC2_EMMC_CTRL) & 122 ~MSHC2_EMMC_CTRL_EMMC_RST_N; 123 sdhci_writeb(host, value, MSHC2_EMMC_CTRL); 124 /* For eMMC, minimum is 1us but give it 10us for good measure */ 125 usleep_range(10, 20); 126 sdhci_writeb(host, value | MSHC2_EMMC_CTRL_EMMC_RST_N, 127 MSHC2_EMMC_CTRL); 128 /* For eMMC, minimum is 200us but give it 300us for good measure */ 129 usleep_range(300, 400); 130 } 131 132 static void sdhci_sparx5_reset(struct sdhci_host *host, u8 mask) 133 { 134 pr_debug("%s: *** RESET: mask %d\n", mmc_hostname(host->mmc), mask); 135 136 sdhci_reset(host, mask); 137 138 /* Be sure CARD_IS_EMMC stays set */ 139 sdhci_sparx5_set_emmc(host); 140 } 141 142 static const struct sdhci_ops sdhci_sparx5_ops = { 143 .set_clock = sdhci_set_clock, 144 .set_bus_width = sdhci_set_bus_width, 145 .set_uhs_signaling = sdhci_set_uhs_signaling, 146 .get_max_clock = sdhci_pltfm_clk_get_max_clock, 147 .reset = sdhci_sparx5_reset, 148 .adma_write_desc = sdhci_sparx5_adma_write_desc, 149 }; 150 151 static const struct sdhci_pltfm_data sdhci_sparx5_pdata = { 152 .quirks = 0, 153 .quirks2 = SDHCI_QUIRK2_HOST_NO_CMD23 | /* Controller issue */ 154 SDHCI_QUIRK2_NO_1_8_V, /* No sdr104, ddr50, etc */ 155 .ops = &sdhci_sparx5_ops, 156 }; 157 158 static int sdhci_sparx5_probe(struct platform_device *pdev) 159 { 160 int ret; 161 const char *syscon = "microchip,sparx5-cpu-syscon"; 162 struct sdhci_host *host; 163 struct sdhci_pltfm_host *pltfm_host; 164 struct sdhci_sparx5_data *sdhci_sparx5; 165 struct device_node *np = pdev->dev.of_node; 166 u32 value; 167 u32 extra; 168 169 host = sdhci_pltfm_init(pdev, &sdhci_sparx5_pdata, 170 sizeof(*sdhci_sparx5)); 171 172 if (IS_ERR(host)) 173 return PTR_ERR(host); 174 175 /* 176 * extra adma table cnt for cross 128M boundary handling. 177 */ 178 extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); 179 if (extra > SDHCI_MAX_SEGS) 180 extra = SDHCI_MAX_SEGS; 181 host->adma_table_cnt += extra; 182 183 pltfm_host = sdhci_priv(host); 184 sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host); 185 sdhci_sparx5->host = host; 186 187 pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); 188 if (IS_ERR(pltfm_host->clk)) { 189 ret = PTR_ERR(pltfm_host->clk); 190 dev_err(&pdev->dev, "failed to get core clk: %d\n", ret); 191 goto free_pltfm; 192 } 193 ret = clk_prepare_enable(pltfm_host->clk); 194 if (ret) 195 goto free_pltfm; 196 197 if (!of_property_read_u32(np, "microchip,clock-delay", &value) && 198 (value > 0 && value <= MSHC_DLY_CC_MAX)) 199 sdhci_sparx5->delay_clock = value; 200 201 sdhci_get_of_property(pdev); 202 203 ret = mmc_of_parse(host->mmc); 204 if (ret) 205 goto err_clk; 206 207 sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon); 208 if (IS_ERR(sdhci_sparx5->cpu_ctrl)) { 209 dev_err(&pdev->dev, "No CPU syscon regmap !\n"); 210 ret = PTR_ERR(sdhci_sparx5->cpu_ctrl); 211 goto err_clk; 212 } 213 214 if (sdhci_sparx5->delay_clock >= 0) 215 sparx5_set_delay(host, sdhci_sparx5->delay_clock); 216 217 if (!mmc_card_is_removable(host->mmc)) { 218 /* Do a HW reset of eMMC card */ 219 sdhci_sparx5_reset_emmc(host); 220 /* Update EMMC_CTRL */ 221 sdhci_sparx5_set_emmc(host); 222 /* If eMMC, disable SD and SDIO */ 223 host->mmc->caps2 |= (MMC_CAP2_NO_SDIO|MMC_CAP2_NO_SD); 224 } 225 226 ret = sdhci_add_host(host); 227 if (ret) 228 goto err_clk; 229 230 /* Set AXI bus master to use un-cached access (for DMA) */ 231 if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) && 232 IS_ENABLED(CONFIG_DMA_DECLARE_COHERENT)) 233 sparx5_set_cacheable(host, ACP_CACHE_FORCE_ENA); 234 235 pr_debug("%s: SDHC version: 0x%08x\n", 236 mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_VERSION)); 237 pr_debug("%s: SDHC type: 0x%08x\n", 238 mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_TYPE)); 239 240 return ret; 241 242 err_clk: 243 clk_disable_unprepare(pltfm_host->clk); 244 free_pltfm: 245 sdhci_pltfm_free(pdev); 246 return ret; 247 } 248 249 static const struct of_device_id sdhci_sparx5_of_match[] = { 250 { .compatible = "microchip,dw-sparx5-sdhci" }, 251 { } 252 }; 253 MODULE_DEVICE_TABLE(of, sdhci_sparx5_of_match); 254 255 static struct platform_driver sdhci_sparx5_driver = { 256 .driver = { 257 .name = "sdhci-sparx5", 258 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 259 .of_match_table = sdhci_sparx5_of_match, 260 .pm = &sdhci_pltfm_pmops, 261 }, 262 .probe = sdhci_sparx5_probe, 263 .remove = sdhci_pltfm_unregister, 264 }; 265 266 module_platform_driver(sdhci_sparx5_driver); 267 268 MODULE_DESCRIPTION("Sparx5 SDHCI OF driver"); 269 MODULE_AUTHOR("Lars Povlsen <lars.povlsen@microchip.com>"); 270 MODULE_LICENSE("GPL v2"); 271