blob: 831dd32eb79692f9ea1a559f8f12a3a2e989cce1 [file] [log] [blame]
Arun Parameswaran36645f42019-09-12 11:06:08 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Broadcom.
4 *
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
10#include <malloc.h>
11#include <sdhci.h>
12
13DECLARE_GLOBAL_DATA_PTR;
14
15struct sdhci_iproc_host {
16 struct sdhci_host host;
17 u32 shadow_cmd;
18 u32 shadow_blk;
19};
20
21#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
22
23static inline struct sdhci_iproc_host *to_iproc(struct sdhci_host *host)
24{
25 return (struct sdhci_iproc_host *)host;
26}
27
28#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
29static u32 sdhci_iproc_readl(struct sdhci_host *host, int reg)
30{
31 u32 val = readl(host->ioaddr + reg);
32#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS_TRACE
33 printf("%s %d: readl [0x%02x] 0x%08x\n",
34 host->name, host->index, reg, val);
35#endif
36 return val;
37}
38
39static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg)
40{
41 u32 val = sdhci_iproc_readl(host, (reg & ~3));
42 u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
43 return word;
44}
45
46static u8 sdhci_iproc_readb(struct sdhci_host *host, int reg)
47{
48 u32 val = sdhci_iproc_readl(host, (reg & ~3));
49 u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff;
50 return byte;
51}
52
53static void sdhci_iproc_writel(struct sdhci_host *host, u32 val, int reg)
54{
55 u32 clock = 0;
56#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS_TRACE
57 printf("%s %d: writel [0x%02x] 0x%08x\n",
58 host->name, host->index, reg, val);
59#endif
60 writel(val, host->ioaddr + reg);
61
62 if (host->mmc)
63 clock = host->mmc->clock;
64 if (clock <= 400000) {
65 /* Round up to micro-second four SD clock delay */
66 if (clock)
67 udelay((4 * 1000000 + clock - 1) / clock);
68 else
69 udelay(10);
70 }
71}
72
73/*
74 * The Arasan has a bugette whereby it may lose the content of successive
75 * writes to the same register that are within two SD-card clock cycles of
76 * each other (a clock domain crossing problem). The data
77 * register does not have this problem, which is just as well - otherwise we'd
78 * have to nobble the DMA engine too.
79 *
80 * This wouldn't be a problem with the code except that we can only write the
81 * controller with 32-bit writes. So two different 16-bit registers are
82 * written back to back creates the problem.
83 *
84 * In reality, this only happens when SDHCI_BLOCK_SIZE and SDHCI_BLOCK_COUNT
85 * are written followed by SDHCI_TRANSFER_MODE and SDHCI_COMMAND.
86 * The BLOCK_SIZE and BLOCK_COUNT are meaningless until a command issued so
87 * the work around can be further optimized. We can keep shadow values of
88 * BLOCK_SIZE, BLOCK_COUNT, and TRANSFER_MODE until a COMMAND is issued.
89 * Then, write the BLOCK_SIZE+BLOCK_COUNT in a single 32-bit write followed
90 * by the TRANSFER+COMMAND in another 32-bit write.
91 */
92static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg)
93{
94 struct sdhci_iproc_host *iproc_host = to_iproc(host);
95 u32 word_shift = REG_OFFSET_IN_BITS(reg);
96 u32 mask = 0xffff << word_shift;
97 u32 oldval, newval;
98
99 if (reg == SDHCI_COMMAND) {
100 /* Write the block now as we are issuing a command */
101 if (iproc_host->shadow_blk != 0) {
102 sdhci_iproc_writel(host, iproc_host->shadow_blk,
103 SDHCI_BLOCK_SIZE);
104 iproc_host->shadow_blk = 0;
105 }
106 oldval = iproc_host->shadow_cmd;
107 } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
108 /* Block size and count are stored in shadow reg */
109 oldval = iproc_host->shadow_blk;
110 } else {
111 /* Read reg, all other registers are not shadowed */
112 oldval = sdhci_iproc_readl(host, (reg & ~3));
113 }
114 newval = (oldval & ~mask) | (val << word_shift);
115
116 if (reg == SDHCI_TRANSFER_MODE) {
117 /* Save the transfer mode until the command is issued */
118 iproc_host->shadow_cmd = newval;
119 } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
120 /* Save the block info until the command is issued */
121 iproc_host->shadow_blk = newval;
122 } else {
123 /* Command or other regular 32-bit write */
124 sdhci_iproc_writel(host, newval, reg & ~3);
125 }
126}
127
128static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg)
129{
130 u32 oldval = sdhci_iproc_readl(host, (reg & ~3));
131 u32 byte_shift = REG_OFFSET_IN_BITS(reg);
132 u32 mask = 0xff << byte_shift;
133 u32 newval = (oldval & ~mask) | (val << byte_shift);
134
135 sdhci_iproc_writel(host, newval, reg & ~3);
136}
137#endif
138
139static void sdhci_iproc_set_ios_post(struct sdhci_host *host)
140{
141 u32 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
142
143 /* Reset UHS mode bits */
144 ctrl &= ~SDHCI_CTRL_UHS_MASK;
145
146 if (host->mmc->ddr_mode)
147 ctrl |= UHS_DDR50_BUS_SPEED;
148
149 sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
150}
151
152static struct sdhci_ops sdhci_platform_ops = {
153#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
154 .read_l = sdhci_iproc_readl,
155 .read_w = sdhci_iproc_readw,
156 .read_b = sdhci_iproc_readb,
157 .write_l = sdhci_iproc_writel,
158 .write_w = sdhci_iproc_writew,
159 .write_b = sdhci_iproc_writeb,
160#endif
161 .set_ios_post = sdhci_iproc_set_ios_post,
162};
163
164struct iproc_sdhci_plat {
165 struct mmc_config cfg;
166 struct mmc mmc;
167};
168
169static int iproc_sdhci_probe(struct udevice *dev)
170{
171 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
172 struct iproc_sdhci_plat *plat = dev_get_platdata(dev);
173 struct sdhci_host *host = dev_get_priv(dev);
174 struct sdhci_iproc_host *iproc_host;
175 int node = dev_of_offset(dev);
176 u32 f_min_max[2];
177 int ret;
178
179 iproc_host = (struct sdhci_iproc_host *)
180 malloc(sizeof(struct sdhci_iproc_host));
181 if (!iproc_host) {
182 printf("%s: sdhci host malloc fail!\n", __func__);
183 return -ENOMEM;
184 }
185 iproc_host->shadow_cmd = 0;
186 iproc_host->shadow_blk = 0;
187
188 host->name = dev->name;
189 host->ioaddr = (void *)devfdt_get_addr(dev);
190 host->voltages = MMC_VDD_165_195 |
191 MMC_VDD_32_33 | MMC_VDD_33_34;
192 host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE;
193 host->host_caps = MMC_MODE_DDR_52MHz;
194 host->index = fdtdec_get_uint(gd->fdt_blob, node, "index", 0);
195 host->ops = &sdhci_platform_ops;
196 host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
197 ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
198 "clock-freq-min-max", f_min_max, 2);
199 if (ret) {
200 printf("sdhci: clock-freq-min-max not found\n");
201 return ret;
202 }
203 host->max_clk = f_min_max[1];
204 host->bus_width = fdtdec_get_int(gd->fdt_blob,
205 dev_of_offset(dev), "bus-width", 4);
206
207 /* Update host_caps for 8 bit bus width */
208 if (host->bus_width == 8)
209 host->host_caps |= MMC_MODE_8BIT;
210
211 memcpy(&iproc_host->host, host, sizeof(struct sdhci_host));
212
213 ret = sdhci_setup_cfg(&plat->cfg, &iproc_host->host,
214 f_min_max[1], f_min_max[0]);
215 if (ret)
216 return ret;
217
218 iproc_host->host.mmc = &plat->mmc;
219 iproc_host->host.mmc->dev = dev;
220 iproc_host->host.mmc->priv = &iproc_host->host;
221 upriv->mmc = iproc_host->host.mmc;
222
223 return sdhci_probe(dev);
224}
225
226static int iproc_sdhci_bind(struct udevice *dev)
227{
228 struct iproc_sdhci_plat *plat = dev_get_platdata(dev);
229
230 return sdhci_bind(dev, &plat->mmc, &plat->cfg);
231}
232
233static const struct udevice_id iproc_sdhci_ids[] = {
234 { .compatible = "brcm,iproc-sdhci" },
235 { }
236};
237
238U_BOOT_DRIVER(iproc_sdhci_drv) = {
239 .name = "iproc_sdhci",
240 .id = UCLASS_MMC,
241 .of_match = iproc_sdhci_ids,
242 .ops = &sdhci_ops,
243 .bind = iproc_sdhci_bind,
244 .probe = iproc_sdhci_probe,
245 .priv_auto_alloc_size = sizeof(struct sdhci_host),
246 .platdata_auto_alloc_size = sizeof(struct iproc_sdhci_plat),
247};