blob: 95390a5be7e59f17bb1641251784902f41e7e932 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasutde0a6bf2011-11-08 23:18:09 +00002/*
3 * Freescale i.MX28 SSP MMC driver
4 *
Lukasz Majewskiaa92b862019-09-05 09:54:59 +02005 * Copyright (C) 2019 DENX Software Engineering
6 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
7 *
Marek Vasutde0a6bf2011-11-08 23:18:09 +00008 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
9 * on behalf of DENX Software Engineering GmbH
10 *
11 * Based on code from LTIB:
12 * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
13 * Terry Lv
14 *
15 * Copyright 2007, Freescale Semiconductor, Inc
16 * Andy Fleming
17 *
18 * Based vaguely on the pxa mmc code:
19 * (C) Copyright 2003
20 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
Marek Vasutde0a6bf2011-11-08 23:18:09 +000021 */
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020022
Simon Glass0f2af882020-05-10 11:40:05 -060023#include <log.h>
Marek Vasutde0a6bf2011-11-08 23:18:09 +000024#include <malloc.h>
25#include <mmc.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060026#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060027#include <linux/delay.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090028#include <linux/errno.h>
Marek Vasutde0a6bf2011-11-08 23:18:09 +000029#include <asm/io.h>
30#include <asm/arch/clock.h>
31#include <asm/arch/imx-regs.h>
32#include <asm/arch/sys_proto.h>
Stefano Babic33731bc2017-06-29 10:16:06 +020033#include <asm/mach-imx/dma.h>
Marek Vasutacc8d6b2012-08-26 15:19:07 +000034#include <bouncebuf.h>
Marek Vasutde0a6bf2011-11-08 23:18:09 +000035
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020036#define MXSMMC_MAX_TIMEOUT 10000
37#define MXSMMC_SMALL_TRANSFER 512
38
39#if !CONFIG_IS_ENABLED(DM_MMC)
Marek Vasutde0a6bf2011-11-08 23:18:09 +000040struct mxsmmc_priv {
41 int id;
Marek Vasutde0a6bf2011-11-08 23:18:09 +000042 int (*mmc_is_wp)(int);
Marek Vasut722181e2013-01-22 15:01:03 +000043 int (*mmc_cd)(int);
Pantelis Antoniou2c850462014-03-11 19:34:20 +020044 struct mmc_config cfg; /* mmc configuration */
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020045 struct mxs_dma_desc *desc;
46 uint32_t buswidth;
47 struct mxs_ssp_regs *regs;
Marek Vasutde0a6bf2011-11-08 23:18:09 +000048};
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020049#else /* CONFIG_IS_ENABLED(DM_MMC) */
50#include <dm/device.h>
51#include <dm/read.h>
52#include <dt-structs.h>
Marek Vasutde0a6bf2011-11-08 23:18:09 +000053
Simon Glassb75b15b2020-12-03 16:55:23 -070054struct mxsmmc_plat {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020055#if CONFIG_IS_ENABLED(OF_PLATDATA)
Walter Lozano69358932020-07-23 00:22:04 -030056 struct dtd_fsl_imx23_mmc dtplat;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020057#endif
58 struct mmc_config cfg;
59 struct mmc mmc;
60 fdt_addr_t base;
61 int non_removable;
62 int buswidth;
63 int dma_id;
64 int clk_id;
65};
66
67struct mxsmmc_priv {
68 int clkid;
69 struct mxs_dma_desc *desc;
70 u32 buswidth;
71 struct mxs_ssp_regs *regs;
72 unsigned int dma_channel;
73};
74#endif
75
76#if !CONFIG_IS_ENABLED(DM_MMC)
77static int mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
78 struct mmc_data *data);
Marek Vasutde0a6bf2011-11-08 23:18:09 +000079
Marek Vasut722181e2013-01-22 15:01:03 +000080static int mxsmmc_cd(struct mxsmmc_priv *priv)
81{
82 struct mxs_ssp_regs *ssp_regs = priv->regs;
83
84 if (priv->mmc_cd)
85 return priv->mmc_cd(priv->id);
86
87 return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT);
88}
89
Lukasz Majewskiaa92b862019-09-05 09:54:59 +020090static int mxsmmc_set_ios(struct mmc *mmc)
91{
92 struct mxsmmc_priv *priv = mmc->priv;
93 struct mxs_ssp_regs *ssp_regs = priv->regs;
94
95 /* Set the clock speed */
96 if (mmc->clock)
97 mxs_set_ssp_busclock(priv->id, mmc->clock / 1000);
98
99 switch (mmc->bus_width) {
100 case 1:
101 priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT;
102 break;
103 case 4:
104 priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT;
105 break;
106 case 8:
107 priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT;
108 break;
109 }
110
111 /* Set the bus width */
112 clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
113 SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth);
114
115 debug("MMC%d: Set %d bits bus width\n",
116 mmc->block_dev.devnum, mmc->bus_width);
117
118 return 0;
119}
120
121static int mxsmmc_init(struct mmc *mmc)
122{
123 struct mxsmmc_priv *priv = mmc->priv;
124 struct mxs_ssp_regs *ssp_regs = priv->regs;
125
126 /* Reset SSP */
127 mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
128
129 /* Reconfigure the SSP block for MMC operation */
130 writel(SSP_CTRL1_SSP_MODE_SD_MMC |
131 SSP_CTRL1_WORD_LENGTH_EIGHT_BITS |
132 SSP_CTRL1_DMA_ENABLE |
133 SSP_CTRL1_POLARITY |
134 SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
135 SSP_CTRL1_DATA_CRC_IRQ_EN |
136 SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
137 SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
138 SSP_CTRL1_RESP_ERR_IRQ_EN,
139 &ssp_regs->hw_ssp_ctrl1_set);
140
141 /* Set initial bit clock 400 KHz */
142 mxs_set_ssp_busclock(priv->id, 400);
143
144 /* Send initial 74 clock cycles (185 us @ 400 KHz)*/
145 writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set);
146 udelay(200);
147 writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr);
148
149 return 0;
150}
151
152static const struct mmc_ops mxsmmc_ops = {
153 .send_cmd = mxsmmc_send_cmd,
154 .set_ios = mxsmmc_set_ios,
155 .init = mxsmmc_init,
156};
157
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900158int mxsmmc_initialize(struct bd_info *bis, int id, int (*wp)(int),
159 int (*cd)(int))
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200160{
161 struct mmc *mmc = NULL;
162 struct mxsmmc_priv *priv = NULL;
163 int ret;
164 const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id);
165
166 if (!mxs_ssp_bus_id_valid(id))
167 return -ENODEV;
168
169 priv = malloc(sizeof(struct mxsmmc_priv));
170 if (!priv)
171 return -ENOMEM;
172
173 priv->desc = mxs_dma_desc_alloc();
174 if (!priv->desc) {
175 free(priv);
176 return -ENOMEM;
177 }
178
179 ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id);
180 if (ret)
181 return ret;
182
183 priv->mmc_is_wp = wp;
184 priv->mmc_cd = cd;
185 priv->id = id;
186 priv->regs = mxs_ssp_regs_by_bus(id);
187
188 priv->cfg.name = "MXS MMC";
189 priv->cfg.ops = &mxsmmc_ops;
190
191 priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
192
193 priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
194 MMC_MODE_HS_52MHz | MMC_MODE_HS;
195
196 /*
197 * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
198 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
199 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
200 * CLOCK_RATE could be any integer from 0 to 255.
201 */
202 priv->cfg.f_min = 400000;
203 priv->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id)
204 * 1000 / 2;
205 priv->cfg.b_max = 0x20;
206
207 mmc = mmc_create(&priv->cfg, priv);
208 if (!mmc) {
209 mxs_dma_desc_free(priv->desc);
210 free(priv);
211 return -ENOMEM;
212 }
213 return 0;
214}
215#endif /* CONFIG_IS_ENABLED(DM_MMC) */
216
Marek Vasut92af6152012-07-06 21:25:55 +0000217static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data)
218{
219 struct mxs_ssp_regs *ssp_regs = priv->regs;
220 uint32_t *data_ptr;
221 int timeout = MXSMMC_MAX_TIMEOUT;
222 uint32_t reg;
223 uint32_t data_count = data->blocksize * data->blocks;
224
225 if (data->flags & MMC_DATA_READ) {
226 data_ptr = (uint32_t *)data->dest;
227 while (data_count && --timeout) {
228 reg = readl(&ssp_regs->hw_ssp_status);
229 if (!(reg & SSP_STATUS_FIFO_EMPTY)) {
230 *data_ptr++ = readl(&ssp_regs->hw_ssp_data);
231 data_count -= 4;
232 timeout = MXSMMC_MAX_TIMEOUT;
233 } else
234 udelay(1000);
235 }
236 } else {
237 data_ptr = (uint32_t *)data->src;
238 timeout *= 100;
239 while (data_count && --timeout) {
240 reg = readl(&ssp_regs->hw_ssp_status);
241 if (!(reg & SSP_STATUS_FIFO_FULL)) {
242 writel(*data_ptr++, &ssp_regs->hw_ssp_data);
243 data_count -= 4;
244 timeout = MXSMMC_MAX_TIMEOUT;
245 } else
246 udelay(1000);
247 }
248 }
249
Jaehoon Chung7825d202016-07-19 16:33:36 +0900250 return timeout ? 0 : -ECOMM;
Marek Vasut92af6152012-07-06 21:25:55 +0000251}
Marek Vasut97c04d62012-07-06 21:25:56 +0000252
Marek Vasut92af6152012-07-06 21:25:55 +0000253static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
254{
255 uint32_t data_count = data->blocksize * data->blocks;
Marek Vasut92af6152012-07-06 21:25:55 +0000256 int dmach;
Marek Vasut042cfd62012-07-06 21:25:57 +0000257 struct mxs_dma_desc *desc = priv->desc;
Stephen Warren4a8629e2012-11-06 11:27:29 +0000258 void *addr;
259 unsigned int flags;
260 struct bounce_buffer bbstate;
Marek Vasut042cfd62012-07-06 21:25:57 +0000261
262 memset(desc, 0, sizeof(struct mxs_dma_desc));
263 desc->address = (dma_addr_t)desc;
Marek Vasut92af6152012-07-06 21:25:55 +0000264
Marek Vasut92af6152012-07-06 21:25:55 +0000265 if (data->flags & MMC_DATA_READ) {
266 priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE;
Marek Vasutacc8d6b2012-08-26 15:19:07 +0000267 addr = data->dest;
268 flags = GEN_BB_WRITE;
Marek Vasut92af6152012-07-06 21:25:55 +0000269 } else {
270 priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ;
Marek Vasutacc8d6b2012-08-26 15:19:07 +0000271 addr = (void *)data->src;
272 flags = GEN_BB_READ;
273 }
274
Stephen Warren4a8629e2012-11-06 11:27:29 +0000275 bounce_buffer_start(&bbstate, addr, data_count, flags);
Marek Vasutacc8d6b2012-08-26 15:19:07 +0000276
Stephen Warren4a8629e2012-11-06 11:27:29 +0000277 priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer;
Marek Vasut761fb5b2012-08-31 16:18:10 +0000278
Marek Vasut92af6152012-07-06 21:25:55 +0000279 priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |
280 (data_count << MXS_DMA_DESC_BYTES_OFFSET);
281
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200282#if !CONFIG_IS_ENABLED(DM_MMC)
Marek Vasuteadf3372013-02-23 02:42:58 +0000283 dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200284#else
285 dmach = priv->dma_channel;
286#endif
Marek Vasut92af6152012-07-06 21:25:55 +0000287 mxs_dma_desc_append(dmach, priv->desc);
Marek Vasutacc8d6b2012-08-26 15:19:07 +0000288 if (mxs_dma_go(dmach)) {
Stephen Warren4a8629e2012-11-06 11:27:29 +0000289 bounce_buffer_stop(&bbstate);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900290 return -ECOMM;
Marek Vasutacc8d6b2012-08-26 15:19:07 +0000291 }
Marek Vasut92af6152012-07-06 21:25:55 +0000292
Stephen Warren4a8629e2012-11-06 11:27:29 +0000293 bounce_buffer_stop(&bbstate);
Marek Vasutacc8d6b2012-08-26 15:19:07 +0000294
Marek Vasut92af6152012-07-06 21:25:55 +0000295 return 0;
296}
Marek Vasut92af6152012-07-06 21:25:55 +0000297
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200298#if !CONFIG_IS_ENABLED(DM_MMC)
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000299/*
300 * Sends a command out on the bus. Takes the mmc pointer,
301 * a command pointer, and an optional data pointer.
302 */
303static int
304mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
305{
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200306 struct mxsmmc_priv *priv = mmc->priv;
Otavio Salvador22f4ff92012-08-05 09:05:31 +0000307 struct mxs_ssp_regs *ssp_regs = priv->regs;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200308#else
309static int
310mxsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data)
311{
Simon Glassb75b15b2020-12-03 16:55:23 -0700312 struct mxsmmc_plat *plat = dev_get_plat(dev);
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200313 struct mxsmmc_priv *priv = dev_get_priv(dev);
314 struct mxs_ssp_regs *ssp_regs = priv->regs;
315 struct mmc *mmc = &plat->mmc;
316#endif
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000317 uint32_t reg;
318 int timeout;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000319 uint32_t ctrl0;
Marek Vasut92af6152012-07-06 21:25:55 +0000320 int ret;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200321#if !CONFIG_IS_ENABLED(DM_MMC)
322 int devnum = mmc->block_dev.devnum;
323#else
324 int devnum = mmc_get_blk_desc(mmc)->devnum;
325#endif
326 debug("MMC%d: CMD%d\n", devnum, cmd->cmdidx);
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000327
328 /* Check bus busy */
329 timeout = MXSMMC_MAX_TIMEOUT;
330 while (--timeout) {
331 udelay(1000);
332 reg = readl(&ssp_regs->hw_ssp_status);
333 if (!(reg &
334 (SSP_STATUS_BUSY | SSP_STATUS_DATA_BUSY |
335 SSP_STATUS_CMD_BUSY))) {
336 break;
337 }
338 }
339
340 if (!timeout) {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200341 printf("MMC%d: Bus busy timeout!\n", devnum);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900342 return -ETIMEDOUT;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000343 }
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200344#if !CONFIG_IS_ENABLED(DM_MMC)
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000345 /* See if card is present */
Marek Vasut722181e2013-01-22 15:01:03 +0000346 if (!mxsmmc_cd(priv)) {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200347 printf("MMC%d: No card detected!\n", devnum);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900348 return -ENOMEDIUM;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000349 }
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200350#endif
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000351 /* Start building CTRL0 contents */
352 ctrl0 = priv->buswidth;
353
354 /* Set up command */
355 if (!(cmd->resp_type & MMC_RSP_CRC))
356 ctrl0 |= SSP_CTRL0_IGNORE_CRC;
357 if (cmd->resp_type & MMC_RSP_PRESENT) /* Need to get response */
358 ctrl0 |= SSP_CTRL0_GET_RESP;
359 if (cmd->resp_type & MMC_RSP_136) /* It's a 136 bits response */
360 ctrl0 |= SSP_CTRL0_LONG_RESP;
361
Marek Vasut042cfd62012-07-06 21:25:57 +0000362 if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER))
363 writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr);
364 else
365 writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set);
366
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000367 /* Command index */
368 reg = readl(&ssp_regs->hw_ssp_cmd0);
369 reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC);
370 reg |= cmd->cmdidx << SSP_CMD0_CMD_OFFSET;
371 if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
372 reg |= SSP_CMD0_APPEND_8CYC;
373 writel(reg, &ssp_regs->hw_ssp_cmd0);
374
375 /* Command argument */
376 writel(cmd->cmdarg, &ssp_regs->hw_ssp_cmd1);
377
378 /* Set up data */
379 if (data) {
380 /* READ or WRITE */
381 if (data->flags & MMC_DATA_READ) {
382 ctrl0 |= SSP_CTRL0_READ;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200383#if !CONFIG_IS_ENABLED(DM_MMC)
Marek Vasut336ff282012-05-01 11:09:52 +0000384 } else if (priv->mmc_is_wp &&
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200385 priv->mmc_is_wp(devnum)) {
386 printf("MMC%d: Can not write a locked card!\n", devnum);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900387 return -EOPNOTSUPP;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200388#endif
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000389 }
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000390 ctrl0 |= SSP_CTRL0_DATA_XFER;
Marek Vasutecf843e2013-01-22 15:01:04 +0000391
392 reg = data->blocksize * data->blocks;
393#if defined(CONFIG_MX23)
394 ctrl0 |= reg & SSP_CTRL0_XFER_COUNT_MASK;
395
396 clrsetbits_le32(&ssp_regs->hw_ssp_cmd0,
397 SSP_CMD0_BLOCK_SIZE_MASK | SSP_CMD0_BLOCK_COUNT_MASK,
398 ((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) |
399 ((ffs(data->blocksize) - 1) <<
400 SSP_CMD0_BLOCK_SIZE_OFFSET));
401#elif defined(CONFIG_MX28)
402 writel(reg, &ssp_regs->hw_ssp_xfer_size);
403
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000404 reg = ((data->blocks - 1) <<
405 SSP_BLOCK_SIZE_BLOCK_COUNT_OFFSET) |
406 ((ffs(data->blocksize) - 1) <<
407 SSP_BLOCK_SIZE_BLOCK_SIZE_OFFSET);
408 writel(reg, &ssp_regs->hw_ssp_block_size);
Marek Vasutecf843e2013-01-22 15:01:04 +0000409#endif
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000410 }
411
412 /* Kick off the command */
413 ctrl0 |= SSP_CTRL0_WAIT_FOR_IRQ | SSP_CTRL0_ENABLE | SSP_CTRL0_RUN;
414 writel(ctrl0, &ssp_regs->hw_ssp_ctrl0);
415
416 /* Wait for the command to complete */
417 timeout = MXSMMC_MAX_TIMEOUT;
418 while (--timeout) {
419 udelay(1000);
420 reg = readl(&ssp_regs->hw_ssp_status);
421 if (!(reg & SSP_STATUS_CMD_BUSY))
422 break;
423 }
424
425 if (!timeout) {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200426 printf("MMC%d: Command %d busy\n", devnum, cmd->cmdidx);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900427 return -ETIMEDOUT;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000428 }
429
430 /* Check command timeout */
431 if (reg & SSP_STATUS_RESP_TIMEOUT) {
Lukasz Majewski058c1352019-09-05 09:55:00 +0200432 debug("MMC%d: Command %d timeout (status 0x%08x)\n",
433 devnum, cmd->cmdidx, reg);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900434 return -ETIMEDOUT;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000435 }
436
437 /* Check command errors */
438 if (reg & (SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR)) {
439 printf("MMC%d: Command %d error (status 0x%08x)!\n",
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200440 devnum, cmd->cmdidx, reg);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900441 return -ECOMM;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000442 }
443
444 /* Copy response to response buffer */
445 if (cmd->resp_type & MMC_RSP_136) {
446 cmd->response[3] = readl(&ssp_regs->hw_ssp_sdresp0);
447 cmd->response[2] = readl(&ssp_regs->hw_ssp_sdresp1);
448 cmd->response[1] = readl(&ssp_regs->hw_ssp_sdresp2);
449 cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp3);
450 } else
451 cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp0);
452
453 /* Return if no data to process */
454 if (!data)
455 return 0;
456
Marek Vasut97c04d62012-07-06 21:25:56 +0000457 if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) {
Marek Vasut97c04d62012-07-06 21:25:56 +0000458 ret = mxsmmc_send_cmd_pio(priv, data);
459 if (ret) {
460 printf("MMC%d: Data timeout with command %d "
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200461 "(status 0x%08x)!\n", devnum, cmd->cmdidx, reg);
Marek Vasut97c04d62012-07-06 21:25:56 +0000462 return ret;
463 }
Marek Vasut042cfd62012-07-06 21:25:57 +0000464 } else {
465 ret = mxsmmc_send_cmd_dma(priv, data);
466 if (ret) {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200467 printf("MMC%d: DMA transfer failed\n", devnum);
Marek Vasut042cfd62012-07-06 21:25:57 +0000468 return ret;
469 }
Marek Vasutdac199b2012-04-05 03:30:35 +0000470 }
Marek Vasut5796bed2012-03-15 18:33:21 +0000471
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000472 /* Check data errors */
473 reg = readl(&ssp_regs->hw_ssp_status);
474 if (reg &
475 (SSP_STATUS_TIMEOUT | SSP_STATUS_DATA_CRC_ERR |
476 SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW)) {
477 printf("MMC%d: Data error with command %d (status 0x%08x)!\n",
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200478 devnum, cmd->cmdidx, reg);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900479 return -ECOMM;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000480 }
481
482 return 0;
483}
484
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200485#if CONFIG_IS_ENABLED(DM_MMC)
486/* Base numbers of i.MX2[38] clk for ssp0 IP block */
487#define MXS_SSP_IMX23_CLKID_SSP0 33
488#define MXS_SSP_IMX28_CLKID_SSP0 46
489
490static int mxsmmc_get_cd(struct udevice *dev)
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000491{
Simon Glassb75b15b2020-12-03 16:55:23 -0700492 struct mxsmmc_plat *plat = dev_get_plat(dev);
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200493 struct mxsmmc_priv *priv = dev_get_priv(dev);
494 struct mxs_ssp_regs *ssp_regs = priv->regs;
495
496 if (plat->non_removable)
497 return 1;
498
499 return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT);
500}
501
502static int mxsmmc_set_ios(struct udevice *dev)
503{
Simon Glassb75b15b2020-12-03 16:55:23 -0700504 struct mxsmmc_plat *plat = dev_get_plat(dev);
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200505 struct mxsmmc_priv *priv = dev_get_priv(dev);
Otavio Salvador22f4ff92012-08-05 09:05:31 +0000506 struct mxs_ssp_regs *ssp_regs = priv->regs;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200507 struct mmc *mmc = &plat->mmc;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000508
509 /* Set the clock speed */
510 if (mmc->clock)
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200511 mxs_set_ssp_busclock(priv->clkid, mmc->clock / 1000);
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000512
513 switch (mmc->bus_width) {
514 case 1:
515 priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT;
516 break;
517 case 4:
518 priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT;
519 break;
520 case 8:
521 priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT;
522 break;
523 }
524
525 /* Set the bus width */
526 clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
527 SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth);
528
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200529 debug("MMC%d: Set %d bits bus width\n", mmc_get_blk_desc(mmc)->devnum,
530 mmc->bus_width);
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900531
532 return 0;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000533}
534
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200535static int mxsmmc_init(struct udevice *dev)
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000536{
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200537 struct mxsmmc_priv *priv = dev_get_priv(dev);
Otavio Salvador22f4ff92012-08-05 09:05:31 +0000538 struct mxs_ssp_regs *ssp_regs = priv->regs;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000539
540 /* Reset SSP */
Otavio Salvadorcbf0bf22012-08-13 09:53:12 +0000541 mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000542
Otavio Salvador254f2972013-01-22 15:01:02 +0000543 /* Reconfigure the SSP block for MMC operation */
544 writel(SSP_CTRL1_SSP_MODE_SD_MMC |
545 SSP_CTRL1_WORD_LENGTH_EIGHT_BITS |
546 SSP_CTRL1_DMA_ENABLE |
547 SSP_CTRL1_POLARITY |
548 SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
549 SSP_CTRL1_DATA_CRC_IRQ_EN |
550 SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
551 SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
552 SSP_CTRL1_RESP_ERR_IRQ_EN,
553 &ssp_regs->hw_ssp_ctrl1_set);
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000554
555 /* Set initial bit clock 400 KHz */
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200556 mxs_set_ssp_busclock(priv->clkid, 400);
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000557
558 /* Send initial 74 clock cycles (185 us @ 400 KHz)*/
559 writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set);
560 udelay(200);
561 writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr);
562
563 return 0;
564}
565
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200566static int mxsmmc_probe(struct udevice *dev)
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000567{
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200568 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassb75b15b2020-12-03 16:55:23 -0700569 struct mxsmmc_plat *plat = dev_get_plat(dev);
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200570 struct mxsmmc_priv *priv = dev_get_priv(dev);
571 struct blk_desc *bdesc;
572 struct mmc *mmc;
573 int ret, clkid;
Marek Vasut3b46aa22013-01-11 03:19:14 +0000574
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200575 debug("%s: probe\n", __func__);
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000576
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200577#if CONFIG_IS_ENABLED(OF_PLATDATA)
Walter Lozano69358932020-07-23 00:22:04 -0300578 struct dtd_fsl_imx23_mmc *dtplat = &plat->dtplat;
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200579 struct phandle_1_arg *p1a = &dtplat->clocks[0];
580
581 priv->buswidth = dtplat->bus_width;
582 priv->regs = (struct mxs_ssp_regs *)dtplat->reg[0];
583 priv->dma_channel = dtplat->dmas[1];
584 clkid = p1a->arg[0];
585 plat->non_removable = dtplat->non_removable;
586
587 debug("OF_PLATDATA: regs: 0x%p bw: %d clkid: %d non_removable: %d\n",
588 priv->regs, priv->buswidth, clkid, plat->non_removable);
589#else
590 priv->regs = (struct mxs_ssp_regs *)plat->base;
591 priv->dma_channel = plat->dma_id;
592 clkid = plat->clk_id;
593#endif
594
595#ifdef CONFIG_MX28
596 priv->clkid = clkid - MXS_SSP_IMX28_CLKID_SSP0;
597#else /* CONFIG_MX23 */
598 priv->clkid = clkid - MXS_SSP_IMX23_CLKID_SSP0;
599#endif
600 mmc = &plat->mmc;
601 mmc->cfg = &plat->cfg;
602 mmc->dev = dev;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000603
Marek Vasut5796bed2012-03-15 18:33:21 +0000604 priv->desc = mxs_dma_desc_alloc();
605 if (!priv->desc) {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200606 printf("%s: Cannot allocate DMA descriptor\n", __func__);
Marek Vasut5796bed2012-03-15 18:33:21 +0000607 return -ENOMEM;
608 }
609
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200610 ret = mxs_dma_init_channel(priv->dma_channel);
Marek Vasut93541b42012-04-08 17:34:46 +0000611 if (ret)
612 return ret;
613
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200614 plat->cfg.name = "MXS MMC";
615 plat->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000616
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200617 plat->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
618 MMC_MODE_HS_52MHz | MMC_MODE_HS;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000619
620 /*
621 * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
622 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
623 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
624 * CLOCK_RATE could be any integer from 0 to 255.
625 */
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200626 plat->cfg.f_min = 400000;
627 plat->cfg.f_max = mxc_get_clock(MXC_SSP0_CLK + priv->clkid) * 1000 / 2;
628 plat->cfg.b_max = 0x20;
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000629
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200630 bdesc = mmc_get_blk_desc(mmc);
631 if (!bdesc) {
632 printf("%s: No block device descriptor!\n", __func__);
633 return -ENODEV;
634 }
635
636 if (plat->non_removable)
637 bdesc->removable = 0;
638
639 ret = mxsmmc_init(dev);
640 if (ret)
641 printf("%s: MMC%d init error %d\n", __func__,
642 bdesc->devnum, ret);
643
644 /* Set the initial clock speed */
645 mmc_set_clock(mmc, 400000, MMC_CLK_ENABLE);
646
647 upriv->mmc = mmc;
648
649 return 0;
650};
651
652#if CONFIG_IS_ENABLED(BLK)
653static int mxsmmc_bind(struct udevice *dev)
654{
Simon Glassb75b15b2020-12-03 16:55:23 -0700655 struct mxsmmc_plat *plat = dev_get_plat(dev);
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200656
657 return mmc_bind(dev, &plat->mmc, &plat->cfg);
658}
659#endif
660
661static const struct dm_mmc_ops mxsmmc_ops = {
662 .get_cd = mxsmmc_get_cd,
663 .send_cmd = mxsmmc_send_cmd,
664 .set_ios = mxsmmc_set_ios,
665};
666
Simon Glass3580f6d2021-08-07 07:24:03 -0600667#if CONFIG_IS_ENABLED(OF_REAL)
Simon Glassaad29ae2020-12-03 16:55:21 -0700668static int mxsmmc_of_to_plat(struct udevice *bus)
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200669{
Simon Glass95588622020-12-22 19:30:28 -0700670 struct mxsmmc_plat *plat = dev_get_plat(bus);
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200671 u32 prop[2];
672 int ret;
673
674 plat->base = dev_read_addr(bus);
675 plat->buswidth =
676 dev_read_u32_default(bus, "bus-width", 1);
677 plat->non_removable = dev_read_bool(bus, "non-removable");
678
679 ret = dev_read_u32_array(bus, "dmas", prop, ARRAY_SIZE(prop));
680 if (ret) {
681 printf("%s: Reading 'dmas' property failed!\n", __func__);
682 return ret;
683 }
684 plat->dma_id = prop[1];
685
686 ret = dev_read_u32_array(bus, "clocks", prop, ARRAY_SIZE(prop));
687 if (ret) {
688 printf("%s: Reading 'clocks' property failed!\n", __func__);
689 return ret;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200690 }
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200691 plat->clk_id = prop[1];
692
693 debug("%s: base=0x%x, bus_width=%d %s dma_id=%d clk_id=%d\n",
694 __func__, (uint)plat->base, plat->buswidth,
695 plat->non_removable ? "non-removable" : NULL,
696 plat->dma_id, plat->clk_id);
697
Marek Vasutde0a6bf2011-11-08 23:18:09 +0000698 return 0;
699}
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200700
701static const struct udevice_id mxsmmc_ids[] = {
702 { .compatible = "fsl,imx23-mmc", },
703 { .compatible = "fsl,imx28-mmc", },
704 { /* sentinel */ }
705};
706#endif
707
Walter Lozano2901ac62020-06-25 01:10:04 -0300708U_BOOT_DRIVER(fsl_imx23_mmc) = {
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200709 .name = "fsl_imx23_mmc",
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200710 .id = UCLASS_MMC,
Simon Glass3580f6d2021-08-07 07:24:03 -0600711#if CONFIG_IS_ENABLED(OF_REAL)
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200712 .of_match = mxsmmc_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700713 .of_to_plat = mxsmmc_of_to_plat,
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200714#endif
715 .ops = &mxsmmc_ops,
716#if CONFIG_IS_ENABLED(BLK)
717 .bind = mxsmmc_bind,
718#endif
719 .probe = mxsmmc_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700720 .priv_auto = sizeof(struct mxsmmc_priv),
Simon Glassb75b15b2020-12-03 16:55:23 -0700721 .plat_auto = sizeof(struct mxsmmc_plat),
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200722};
723
Simon Glassdf65db82020-12-28 20:34:57 -0700724DM_DRIVER_ALIAS(fsl_imx23_mmc, fsl_imx28_mmc)
Lukasz Majewskiaa92b862019-09-05 09:54:59 +0200725#endif /* CONFIG_DM_MMC */