143611afbSLars Povlsen // SPDX-License-Identifier: GPL-2.0-or-later
243611afbSLars Povlsen /*
343611afbSLars Povlsen * drivers/mmc/host/sdhci-of-sparx5.c
443611afbSLars Povlsen *
543611afbSLars Povlsen * MCHP Sparx5 SoC Secure Digital Host Controller Interface.
643611afbSLars Povlsen *
743611afbSLars Povlsen * Copyright (c) 2019 Microchip Inc.
843611afbSLars Povlsen *
943611afbSLars Povlsen * Author: Lars Povlsen <lars.povlsen@microchip.com>
1043611afbSLars Povlsen */
1143611afbSLars Povlsen
1243611afbSLars Povlsen #include <linux/sizes.h>
1343611afbSLars Povlsen #include <linux/delay.h>
1443611afbSLars Povlsen #include <linux/module.h>
1543611afbSLars Povlsen #include <linux/regmap.h>
1643611afbSLars Povlsen #include <linux/mfd/syscon.h>
1743611afbSLars Povlsen #include <linux/dma-mapping.h>
18c62da8a8SRob Herring #include <linux/of.h>
1943611afbSLars Povlsen
2043611afbSLars Povlsen #include "sdhci-pltfm.h"
2143611afbSLars Povlsen
2243611afbSLars Povlsen #define CPU_REGS_GENERAL_CTRL (0x22 * 4)
2343611afbSLars Povlsen #define MSHC_DLY_CC_MASK GENMASK(16, 13)
2443611afbSLars Povlsen #define MSHC_DLY_CC_SHIFT 13
2543611afbSLars Povlsen #define MSHC_DLY_CC_MAX 15
2643611afbSLars Povlsen
2743611afbSLars Povlsen #define CPU_REGS_PROC_CTRL (0x2C * 4)
2843611afbSLars Povlsen #define ACP_CACHE_FORCE_ENA BIT(4)
2943611afbSLars Povlsen #define ACP_AWCACHE BIT(3)
3043611afbSLars Povlsen #define ACP_ARCACHE BIT(2)
3143611afbSLars Povlsen #define ACP_CACHE_MASK (ACP_CACHE_FORCE_ENA|ACP_AWCACHE|ACP_ARCACHE)
3243611afbSLars Povlsen
3343611afbSLars Povlsen #define MSHC2_VERSION 0x500 /* Off 0x140, reg 0x0 */
3443611afbSLars Povlsen #define MSHC2_TYPE 0x504 /* Off 0x140, reg 0x1 */
3543611afbSLars Povlsen #define MSHC2_EMMC_CTRL 0x52c /* Off 0x140, reg 0xB */
3643611afbSLars Povlsen #define MSHC2_EMMC_CTRL_EMMC_RST_N BIT(2)
3743611afbSLars Povlsen #define MSHC2_EMMC_CTRL_IS_EMMC BIT(0)
3843611afbSLars Povlsen
3943611afbSLars Povlsen struct sdhci_sparx5_data {
4043611afbSLars Povlsen struct sdhci_host *host;
4143611afbSLars Povlsen struct regmap *cpu_ctrl;
4243611afbSLars Povlsen int delay_clock;
4343611afbSLars Povlsen };
4443611afbSLars Povlsen
4543611afbSLars Povlsen #define BOUNDARY_OK(addr, len) \
4643611afbSLars Povlsen ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
4743611afbSLars Povlsen
4843611afbSLars Povlsen /*
4943611afbSLars Povlsen * If DMA addr spans 128MB boundary, we split the DMA transfer into two
5043611afbSLars Povlsen * so that each DMA transfer doesn't exceed the boundary.
5143611afbSLars Povlsen */
sdhci_sparx5_adma_write_desc(struct sdhci_host * host,void ** desc,dma_addr_t addr,int len,unsigned int cmd)5243611afbSLars Povlsen static void sdhci_sparx5_adma_write_desc(struct sdhci_host *host, void **desc,
5343611afbSLars Povlsen dma_addr_t addr, int len,
5443611afbSLars Povlsen unsigned int cmd)
5543611afbSLars Povlsen {
5643611afbSLars Povlsen int tmplen, offset;
5743611afbSLars Povlsen
5843611afbSLars Povlsen if (likely(!len || BOUNDARY_OK(addr, len))) {
5943611afbSLars Povlsen sdhci_adma_write_desc(host, desc, addr, len, cmd);
6043611afbSLars Povlsen return;
6143611afbSLars Povlsen }
6243611afbSLars Povlsen
63b5f9a2c6SKrzysztof Kozlowski pr_debug("%s: write_desc: splitting dma len %d, offset %pad\n",
64b5f9a2c6SKrzysztof Kozlowski mmc_hostname(host->mmc), len, &addr);
6543611afbSLars Povlsen
6643611afbSLars Povlsen offset = addr & (SZ_128M - 1);
6743611afbSLars Povlsen tmplen = SZ_128M - offset;
6843611afbSLars Povlsen sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
6943611afbSLars Povlsen
7043611afbSLars Povlsen addr += tmplen;
7143611afbSLars Povlsen len -= tmplen;
7243611afbSLars Povlsen sdhci_adma_write_desc(host, desc, addr, len, cmd);
7343611afbSLars Povlsen }
7443611afbSLars Povlsen
sparx5_set_cacheable(struct sdhci_host * host,u32 value)7543611afbSLars Povlsen static void sparx5_set_cacheable(struct sdhci_host *host, u32 value)
7643611afbSLars Povlsen {
7743611afbSLars Povlsen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
7843611afbSLars Povlsen struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
7943611afbSLars Povlsen
8043611afbSLars Povlsen pr_debug("%s: Set Cacheable = 0x%x\n", mmc_hostname(host->mmc), value);
8143611afbSLars Povlsen
8243611afbSLars Povlsen /* Update ACP caching attributes in HW */
8343611afbSLars Povlsen regmap_update_bits(sdhci_sparx5->cpu_ctrl,
8443611afbSLars Povlsen CPU_REGS_PROC_CTRL, ACP_CACHE_MASK, value);
8543611afbSLars Povlsen }
8643611afbSLars Povlsen
sparx5_set_delay(struct sdhci_host * host,u8 value)8743611afbSLars Povlsen static void sparx5_set_delay(struct sdhci_host *host, u8 value)
8843611afbSLars Povlsen {
8943611afbSLars Povlsen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
9043611afbSLars Povlsen struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
9143611afbSLars Povlsen
9243611afbSLars Povlsen pr_debug("%s: Set DLY_CC = %u\n", mmc_hostname(host->mmc), value);
9343611afbSLars Povlsen
9443611afbSLars Povlsen /* Update DLY_CC in HW */
9543611afbSLars Povlsen regmap_update_bits(sdhci_sparx5->cpu_ctrl,
9643611afbSLars Povlsen CPU_REGS_GENERAL_CTRL,
9743611afbSLars Povlsen MSHC_DLY_CC_MASK,
9843611afbSLars Povlsen (value << MSHC_DLY_CC_SHIFT));
9943611afbSLars Povlsen }
10043611afbSLars Povlsen
sdhci_sparx5_set_emmc(struct sdhci_host * host)10143611afbSLars Povlsen static void sdhci_sparx5_set_emmc(struct sdhci_host *host)
10243611afbSLars Povlsen {
10343611afbSLars Povlsen if (!mmc_card_is_removable(host->mmc)) {
10443611afbSLars Povlsen u8 value;
10543611afbSLars Povlsen
10643611afbSLars Povlsen value = sdhci_readb(host, MSHC2_EMMC_CTRL);
10743611afbSLars Povlsen if (!(value & MSHC2_EMMC_CTRL_IS_EMMC)) {
10843611afbSLars Povlsen value |= MSHC2_EMMC_CTRL_IS_EMMC;
10943611afbSLars Povlsen pr_debug("%s: Set EMMC_CTRL: 0x%08x\n",
11043611afbSLars Povlsen mmc_hostname(host->mmc), value);
11143611afbSLars Povlsen sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
11243611afbSLars Povlsen }
11343611afbSLars Povlsen }
11443611afbSLars Povlsen }
11543611afbSLars Povlsen
sdhci_sparx5_reset_emmc(struct sdhci_host * host)11643611afbSLars Povlsen static void sdhci_sparx5_reset_emmc(struct sdhci_host *host)
11743611afbSLars Povlsen {
11843611afbSLars Povlsen u8 value;
11943611afbSLars Povlsen
12043611afbSLars Povlsen pr_debug("%s: Toggle EMMC_CTRL.EMMC_RST_N\n", mmc_hostname(host->mmc));
12143611afbSLars Povlsen value = sdhci_readb(host, MSHC2_EMMC_CTRL) &
12243611afbSLars Povlsen ~MSHC2_EMMC_CTRL_EMMC_RST_N;
12343611afbSLars Povlsen sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
12443611afbSLars Povlsen /* For eMMC, minimum is 1us but give it 10us for good measure */
12543611afbSLars Povlsen usleep_range(10, 20);
12643611afbSLars Povlsen sdhci_writeb(host, value | MSHC2_EMMC_CTRL_EMMC_RST_N,
12743611afbSLars Povlsen MSHC2_EMMC_CTRL);
12843611afbSLars Povlsen /* For eMMC, minimum is 200us but give it 300us for good measure */
12943611afbSLars Povlsen usleep_range(300, 400);
13043611afbSLars Povlsen }
13143611afbSLars Povlsen
sdhci_sparx5_reset(struct sdhci_host * host,u8 mask)13243611afbSLars Povlsen static void sdhci_sparx5_reset(struct sdhci_host *host, u8 mask)
13343611afbSLars Povlsen {
13443611afbSLars Povlsen pr_debug("%s: *** RESET: mask %d\n", mmc_hostname(host->mmc), mask);
13543611afbSLars Povlsen
13643611afbSLars Povlsen sdhci_reset(host, mask);
13743611afbSLars Povlsen
13843611afbSLars Povlsen /* Be sure CARD_IS_EMMC stays set */
13943611afbSLars Povlsen sdhci_sparx5_set_emmc(host);
14043611afbSLars Povlsen }
14143611afbSLars Povlsen
14243611afbSLars Povlsen static const struct sdhci_ops sdhci_sparx5_ops = {
14343611afbSLars Povlsen .set_clock = sdhci_set_clock,
14443611afbSLars Povlsen .set_bus_width = sdhci_set_bus_width,
14543611afbSLars Povlsen .set_uhs_signaling = sdhci_set_uhs_signaling,
14643611afbSLars Povlsen .get_max_clock = sdhci_pltfm_clk_get_max_clock,
14743611afbSLars Povlsen .reset = sdhci_sparx5_reset,
14843611afbSLars Povlsen .adma_write_desc = sdhci_sparx5_adma_write_desc,
14943611afbSLars Povlsen };
15043611afbSLars Povlsen
15143611afbSLars Povlsen static const struct sdhci_pltfm_data sdhci_sparx5_pdata = {
15243611afbSLars Povlsen .quirks = 0,
15343611afbSLars Povlsen .quirks2 = SDHCI_QUIRK2_HOST_NO_CMD23 | /* Controller issue */
15443611afbSLars Povlsen SDHCI_QUIRK2_NO_1_8_V, /* No sdr104, ddr50, etc */
15543611afbSLars Povlsen .ops = &sdhci_sparx5_ops,
15643611afbSLars Povlsen };
15743611afbSLars Povlsen
sdhci_sparx5_probe(struct platform_device * pdev)15843611afbSLars Povlsen static int sdhci_sparx5_probe(struct platform_device *pdev)
15943611afbSLars Povlsen {
16043611afbSLars Povlsen int ret;
16143611afbSLars Povlsen const char *syscon = "microchip,sparx5-cpu-syscon";
16243611afbSLars Povlsen struct sdhci_host *host;
16343611afbSLars Povlsen struct sdhci_pltfm_host *pltfm_host;
16443611afbSLars Povlsen struct sdhci_sparx5_data *sdhci_sparx5;
16543611afbSLars Povlsen struct device_node *np = pdev->dev.of_node;
16643611afbSLars Povlsen u32 value;
16743611afbSLars Povlsen u32 extra;
16843611afbSLars Povlsen
16943611afbSLars Povlsen host = sdhci_pltfm_init(pdev, &sdhci_sparx5_pdata,
17043611afbSLars Povlsen sizeof(*sdhci_sparx5));
17143611afbSLars Povlsen
17243611afbSLars Povlsen if (IS_ERR(host))
17343611afbSLars Povlsen return PTR_ERR(host);
17443611afbSLars Povlsen
17543611afbSLars Povlsen /*
17643611afbSLars Povlsen * extra adma table cnt for cross 128M boundary handling.
17743611afbSLars Povlsen */
17843611afbSLars Povlsen extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
17943611afbSLars Povlsen if (extra > SDHCI_MAX_SEGS)
18043611afbSLars Povlsen extra = SDHCI_MAX_SEGS;
18143611afbSLars Povlsen host->adma_table_cnt += extra;
18243611afbSLars Povlsen
18343611afbSLars Povlsen pltfm_host = sdhci_priv(host);
18443611afbSLars Povlsen sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);
18543611afbSLars Povlsen sdhci_sparx5->host = host;
18643611afbSLars Povlsen
187*18ba91acSAdrian Hunter pltfm_host->clk = devm_clk_get_enabled(&pdev->dev, "core");
18843611afbSLars Povlsen if (IS_ERR(pltfm_host->clk)) {
18943611afbSLars Povlsen ret = PTR_ERR(pltfm_host->clk);
190*18ba91acSAdrian Hunter dev_err(&pdev->dev, "failed to get and enable core clk: %d\n", ret);
19143611afbSLars Povlsen goto free_pltfm;
19243611afbSLars Povlsen }
19343611afbSLars Povlsen
19443611afbSLars Povlsen if (!of_property_read_u32(np, "microchip,clock-delay", &value) &&
19543611afbSLars Povlsen (value > 0 && value <= MSHC_DLY_CC_MAX))
19643611afbSLars Povlsen sdhci_sparx5->delay_clock = value;
19743611afbSLars Povlsen
19843611afbSLars Povlsen sdhci_get_of_property(pdev);
19943611afbSLars Povlsen
20043611afbSLars Povlsen ret = mmc_of_parse(host->mmc);
20143611afbSLars Povlsen if (ret)
202*18ba91acSAdrian Hunter goto free_pltfm;
20343611afbSLars Povlsen
20443611afbSLars Povlsen sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon);
20543611afbSLars Povlsen if (IS_ERR(sdhci_sparx5->cpu_ctrl)) {
20643611afbSLars Povlsen dev_err(&pdev->dev, "No CPU syscon regmap !\n");
20743611afbSLars Povlsen ret = PTR_ERR(sdhci_sparx5->cpu_ctrl);
208*18ba91acSAdrian Hunter goto free_pltfm;
20943611afbSLars Povlsen }
21043611afbSLars Povlsen
21143611afbSLars Povlsen if (sdhci_sparx5->delay_clock >= 0)
21243611afbSLars Povlsen sparx5_set_delay(host, sdhci_sparx5->delay_clock);
21343611afbSLars Povlsen
21443611afbSLars Povlsen if (!mmc_card_is_removable(host->mmc)) {
21543611afbSLars Povlsen /* Do a HW reset of eMMC card */
21643611afbSLars Povlsen sdhci_sparx5_reset_emmc(host);
21743611afbSLars Povlsen /* Update EMMC_CTRL */
21843611afbSLars Povlsen sdhci_sparx5_set_emmc(host);
21943611afbSLars Povlsen /* If eMMC, disable SD and SDIO */
22043611afbSLars Povlsen host->mmc->caps2 |= (MMC_CAP2_NO_SDIO|MMC_CAP2_NO_SD);
22143611afbSLars Povlsen }
22243611afbSLars Povlsen
22343611afbSLars Povlsen ret = sdhci_add_host(host);
22443611afbSLars Povlsen if (ret)
225*18ba91acSAdrian Hunter goto free_pltfm;
22643611afbSLars Povlsen
22743611afbSLars Povlsen /* Set AXI bus master to use un-cached access (for DMA) */
22843611afbSLars Povlsen if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) &&
22943611afbSLars Povlsen IS_ENABLED(CONFIG_DMA_DECLARE_COHERENT))
23043611afbSLars Povlsen sparx5_set_cacheable(host, ACP_CACHE_FORCE_ENA);
23143611afbSLars Povlsen
23243611afbSLars Povlsen pr_debug("%s: SDHC version: 0x%08x\n",
23343611afbSLars Povlsen mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_VERSION));
23443611afbSLars Povlsen pr_debug("%s: SDHC type: 0x%08x\n",
23543611afbSLars Povlsen mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_TYPE));
23643611afbSLars Povlsen
23743611afbSLars Povlsen return ret;
23843611afbSLars Povlsen
23943611afbSLars Povlsen free_pltfm:
24043611afbSLars Povlsen sdhci_pltfm_free(pdev);
24143611afbSLars Povlsen return ret;
24243611afbSLars Povlsen }
24343611afbSLars Povlsen
24443611afbSLars Povlsen static const struct of_device_id sdhci_sparx5_of_match[] = {
24543611afbSLars Povlsen { .compatible = "microchip,dw-sparx5-sdhci" },
24643611afbSLars Povlsen { }
24743611afbSLars Povlsen };
24843611afbSLars Povlsen MODULE_DEVICE_TABLE(of, sdhci_sparx5_of_match);
24943611afbSLars Povlsen
25043611afbSLars Povlsen static struct platform_driver sdhci_sparx5_driver = {
25143611afbSLars Povlsen .driver = {
25243611afbSLars Povlsen .name = "sdhci-sparx5",
25331ae4035SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS,
25443611afbSLars Povlsen .of_match_table = sdhci_sparx5_of_match,
25543611afbSLars Povlsen .pm = &sdhci_pltfm_pmops,
25643611afbSLars Povlsen },
25743611afbSLars Povlsen .probe = sdhci_sparx5_probe,
258*18ba91acSAdrian Hunter .remove_new = sdhci_pltfm_remove,
25943611afbSLars Povlsen };
26043611afbSLars Povlsen
26143611afbSLars Povlsen module_platform_driver(sdhci_sparx5_driver);
26243611afbSLars Povlsen
26343611afbSLars Povlsen MODULE_DESCRIPTION("Sparx5 SDHCI OF driver");
26443611afbSLars Povlsen MODULE_AUTHOR("Lars Povlsen <lars.povlsen@microchip.com>");
26543611afbSLars Povlsen MODULE_LICENSE("GPL v2");
266