blob: 65a22cefb715ac343804b06d7783972f8e6d89ce [file] [log] [blame]
Nathan Barrett-Morrison5fd870e2025-02-26 12:30:34 -05001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * (C) Copyright 2022 - Analog Devices, Inc.
4 *
5 * Written and/or maintained by Timesys Corporation
6 *
7 * Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
8 * Contact: Greg Malysa <greg.malysa@timesys.com>
9 *
10 * Based on Rockchip's sdhci.c file
11 */
12
13#include <clk.h>
14#include <dm.h>
15#include <malloc.h>
16#include <sdhci.h>
17#include <asm/cache.h>
18
19/* 400KHz is max freq for card ID etc. Use that as min */
20#define EMMC_MIN_FREQ 400000
21
22/* Check if an operation crossed a boundary of size ADMA_BOUNDARY_ALIGN */
23#define ADMA_BOUNDARY_ALGN SZ_128M
24#define BOUNDARY_OK(addr, len) \
25 (((addr) | (ADMA_BOUNDARY_ALGN - 1)) == (((addr) + (len) - 1) | \
26 (ADMA_BOUNDARY_ALGN - 1)))
27
28/* We split a descriptor for every crossing of the ADMA alignment boundary,
29 * so we need an additional descriptor for every expected crossing.
30 * As I understand it, the max expected transaction size is:
31 * CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN
32 *
33 * With the way the SDHCI-ADMA driver is implemented, if ADMA_MAX_LEN was a
34 * clean power of two, we'd only ever need +1 descriptor as the first
35 * descriptor that got split would then bring the remaining DMA
36 * destination addresses into alignment. Unfortunately, it's currently
37 * hardcoded to a non-power-of-two value.
38 *
39 * If that ever becomes parameterized, ADMA max length can be set to
40 * 0x10000, and set this to 1.
41 */
42#define ADMA_POTENTIAL_CROSSINGS \
43 DIV_ROUND_UP((CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN), \
44 ADMA_BOUNDARY_ALGN)
45/* +1 descriptor for each crossing.
46 */
47#define ADMA_TABLE_EXTRA_SZ (ADMA_POTENTIAL_CROSSINGS * ADMA_DESC_LEN)
48
49struct adi_sdhc_plat {
50 struct mmc_config cfg;
51 struct mmc mmc;
52};
53
54void adi_dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
55 dma_addr_t addr, int len, bool end)
56{
57 int tmplen, offset;
58
59 if (likely(!len || BOUNDARY_OK(addr, len))) {
60 sdhci_adma_write_desc(host, desc, addr, len, end);
61 return;
62 }
63
64 offset = addr & (ADMA_BOUNDARY_ALGN - 1);
65 tmplen = ADMA_BOUNDARY_ALGN - offset;
66 sdhci_adma_write_desc(host, desc, addr, tmplen, false);
67
68 addr += tmplen;
69 len -= tmplen;
70 sdhci_adma_write_desc(host, desc, addr, len, end);
71}
72
73struct sdhci_ops adi_dwcmshc_sdhci_ops = {
74 .adma_write_desc = adi_dwcmshc_adma_write_desc,
75};
76
77static int adi_dwcmshc_sdhci_probe(struct udevice *dev)
78{
79 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
80 struct adi_sdhc_plat *plat = dev_get_plat(dev);
81 struct sdhci_host *host = dev_get_priv(dev);
82 int max_frequency, ret;
83 struct clk clk;
84
85 max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
86 ret = clk_get_by_index(dev, 0, &clk);
87
88 host->quirks = 0;
89 host->max_clk = max_frequency;
90 /*
91 * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
92 * doesn't allow us to clear MMC_MODE_4BIT. Consequently, we don't
93 * check for other bus-width values.
94 */
95 if (host->bus_width == 8)
96 host->host_caps |= MMC_MODE_8BIT;
97
98 host->mmc = &plat->mmc;
99 host->mmc->priv = host;
100 host->mmc->dev = dev;
101 upriv->mmc = host->mmc;
102
103 host->ops = &adi_dwcmshc_sdhci_ops;
104 host->adma_desc_table = memalign(ARCH_DMA_MINALIGN,
105 ADMA_TABLE_SZ + ADMA_TABLE_EXTRA_SZ);
106 host->adma_addr = virt_to_phys(host->adma_desc_table);
107
108 ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
109 if (ret)
110 return ret;
111
112 return sdhci_probe(dev);
113}
114
115static int adi_dwcmshc_sdhci_of_to_plat(struct udevice *dev)
116{
117 struct sdhci_host *host = dev_get_priv(dev);
118
119 host->name = dev->name;
120 host->ioaddr = dev_read_addr_ptr(dev);
121 host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
122
123 return 0;
124}
125
126static int adi_sdhci_bind(struct udevice *dev)
127{
128 struct adi_sdhc_plat *plat = dev_get_plat(dev);
129
130 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
131}
132
133static const struct udevice_id adi_dwcmshc_sdhci_ids[] = {
134 { .compatible = "adi,dwc-sdhci" },
135 { }
136};
137
138U_BOOT_DRIVER(adi_dwcmshc_sdhci_drv) = {
139 .name = "adi_sdhci",
140 .id = UCLASS_MMC,
141 .of_match = adi_dwcmshc_sdhci_ids,
142 .of_to_plat = adi_dwcmshc_sdhci_of_to_plat,
143 .ops = &sdhci_ops,
144 .bind = adi_sdhci_bind,
145 .probe = adi_dwcmshc_sdhci_probe,
146 .priv_auto = sizeof(struct sdhci_host),
147 .plat_auto = sizeof(struct adi_sdhc_plat),
148};