blob: 93b88d17d4041ad0dfe9cf674971eaf54977ebb6 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Reinhard Meyer1592ef82010-08-13 10:31:06 +02002/*
3 * Copyright (C) 2010
4 * Rob Emanuele <rob@emanuele.us>
5 * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
6 *
7 * Original Driver:
8 * Copyright (C) 2004-2006 Atmel Corporation
Reinhard Meyer1592ef82010-08-13 10:31:06 +02009 */
10
11#include <common.h>
Wenyou Yangc86c0152017-04-13 10:29:22 +080012#include <clk.h>
Simon Glass9d922452017-05-17 17:18:03 -060013#include <dm.h>
Reinhard Meyer1592ef82010-08-13 10:31:06 +020014#include <mmc.h>
15#include <part.h>
16#include <malloc.h>
17#include <asm/io.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090018#include <linux/errno.h>
Reinhard Meyer1592ef82010-08-13 10:31:06 +020019#include <asm/byteorder.h>
20#include <asm/arch/clk.h>
Reinhard Meyer329f0f52010-11-03 16:32:56 +010021#include <asm/arch/hardware.h>
Reinhard Meyer1592ef82010-08-13 10:31:06 +020022#include "atmel_mci.h"
23
24#ifndef CONFIG_SYS_MMC_CLK_OD
25# define CONFIG_SYS_MMC_CLK_OD 150000
26#endif
27
28#define MMC_DEFAULT_BLKLEN 512
29
30#if defined(CONFIG_ATMEL_MCI_PORTB)
31# define MCI_BUS 1
32#else
33# define MCI_BUS 0
34#endif
35
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +080036#ifdef CONFIG_DM_MMC
37struct atmel_mci_plat {
38 struct mmc mmc;
Marek Vasut6b75d352015-10-23 20:46:30 +020039 struct mmc_config cfg;
40 struct atmel_mci *mci;
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +080041};
42#endif
43
44struct atmel_mci_priv {
45#ifndef CONFIG_DM_MMC
46 struct mmc_config cfg;
47 struct atmel_mci *mci;
48#endif
Marek Vasut877807e2015-10-23 20:46:31 +020049 unsigned int initialized:1;
Gregory CLEMENTb4670a02015-11-05 20:58:30 +010050 unsigned int curr_clk;
Wenyou Yangc86c0152017-04-13 10:29:22 +080051#ifdef CONFIG_DM_MMC
Wenyou Yangc86c0152017-04-13 10:29:22 +080052 ulong bus_clk_rate;
53#endif
Marek Vasut6b75d352015-10-23 20:46:30 +020054};
55
Bo Shenaac4b692013-04-26 00:27:06 +000056/* Read Atmel MCI IP version */
57static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
58{
59 return readl(&mci->version) & 0x00000fff;
60}
61
Reinhard Meyer1592ef82010-08-13 10:31:06 +020062/*
63 * Print command and status:
64 *
65 * - always when DEBUG is defined
66 * - on command errors
67 */
68static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
69{
Marek Vasutb84c9c92015-10-23 20:46:28 +020070 debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
71 cmdr, cmdr & 0x3F, arg, status, msg);
Reinhard Meyer1592ef82010-08-13 10:31:06 +020072}
73
Jean-Jacques Hiblot9b79dbd2018-01-04 15:23:29 +010074static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
75{
76 unsigned int version = atmel_mci_get_version(mci);
77
78 blklen &= 0xfffc;
79
80 /* MCI IP version >= 0x200 has blkr */
81 if (version >= 0x200)
82 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
83 &mci->blkr);
84 else
85 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
86}
87
Reinhard Meyer1592ef82010-08-13 10:31:06 +020088/* Setup for MCI Clock and Block Size */
Wenyou Yangc86c0152017-04-13 10:29:22 +080089#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +080090static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
Wenyou Yangc86c0152017-04-13 10:29:22 +080091{
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +080092 struct atmel_mci_plat *plat = dev_get_platdata(dev);
93 struct atmel_mci_priv *priv = dev_get_priv(dev);
94 struct mmc *mmc = &plat->mmc;
Wenyou Yangc86c0152017-04-13 10:29:22 +080095 u32 bus_hz = priv->bus_clk_rate;
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +080096 atmel_mci_t *mci = plat->mci;
Wenyou Yangc86c0152017-04-13 10:29:22 +080097#else
Reinhard Meyer1592ef82010-08-13 10:31:06 +020098static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
99{
Marek Vasut6b75d352015-10-23 20:46:30 +0200100 struct atmel_mci_priv *priv = mmc->priv;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200101 u32 bus_hz = get_mci_clk_rate();
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800102 atmel_mci_t *mci = priv->mci;
Wenyou Yangc86c0152017-04-13 10:29:22 +0800103#endif
104
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200105 u32 clkdiv = 255;
Bo Shencd60ebd42014-07-31 14:39:30 +0800106 unsigned int version = atmel_mci_get_version(mci);
107 u32 clkodd = 0;
108 u32 mr;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200109
110 debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
111 bus_hz, hz, blklen);
112 if (hz > 0) {
Bo Shencd60ebd42014-07-31 14:39:30 +0800113 if (version >= 0x500) {
114 clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
115 if (clkdiv > 511)
116 clkdiv = 511;
117
118 clkodd = clkdiv & 1;
119 clkdiv >>= 1;
120
Marek Vasutb84c9c92015-10-23 20:46:28 +0200121 debug("mci: setting clock %u Hz, block size %u\n",
122 bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
Bo Shencd60ebd42014-07-31 14:39:30 +0800123 } else {
124 /* find clkdiv yielding a rate <= than requested */
125 for (clkdiv = 0; clkdiv < 255; clkdiv++) {
126 if ((bus_hz / (clkdiv + 1) / 2) <= hz)
127 break;
128 }
Marek Vasutb84c9c92015-10-23 20:46:28 +0200129 debug("mci: setting clock %u Hz, block size %u\n",
130 (bus_hz / (clkdiv + 1)) / 2, blklen);
Bo Shencd60ebd42014-07-31 14:39:30 +0800131
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200132 }
133 }
Gregory CLEMENTb4670a02015-11-05 20:58:30 +0100134 if (version >= 0x500)
135 priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
136 else
137 priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
Bo Shencd60ebd42014-07-31 14:39:30 +0800138
139 mr = MMCI_BF(CLKDIV, clkdiv);
140
141 /* MCI IP version >= 0x200 has R/WPROOF */
142 if (version >= 0x200)
143 mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
144
Wu, Josh1db73772012-09-13 22:22:04 +0000145 /*
Bo Shencd60ebd42014-07-31 14:39:30 +0800146 * MCI IP version >= 0x500 use bit 16 as clkodd.
147 * MCI IP version < 0x500 use upper 16 bits for blklen.
Wu, Josh1db73772012-09-13 22:22:04 +0000148 */
Bo Shencd60ebd42014-07-31 14:39:30 +0800149 if (version >= 0x500)
150 mr |= MMCI_BF(CLKODD, clkodd);
Bo Shencd60ebd42014-07-31 14:39:30 +0800151
152 writel(mr, &mci->mr);
153
Jean-Jacques Hiblot9b79dbd2018-01-04 15:23:29 +0100154 mci_set_blklen(mci, blklen);
Bo Shencd60ebd42014-07-31 14:39:30 +0800155
Bo Shenda55c662014-07-31 14:39:32 +0800156 if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
157 writel(MMCI_BIT(HSMODE), &mci->cfg);
158
Marek Vasut877807e2015-10-23 20:46:31 +0200159 priv->initialized = 1;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200160}
161
162/* Return the CMDR with flags for a given command and data packet */
163static u32 mci_encode_cmd(
164 struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
165{
166 u32 cmdr = 0;
167
168 /* Default Flags for Errors */
169 *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
170 MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
171
172 /* Default Flags for the Command */
173 cmdr |= MMCI_BIT(MAXLAT);
174
175 if (data) {
176 cmdr |= MMCI_BF(TRCMD, 1);
177 if (data->blocks > 1)
178 cmdr |= MMCI_BF(TRTYP, 1);
179 if (data->flags & MMC_DATA_READ)
180 cmdr |= MMCI_BIT(TRDIR);
181 }
182
183 if (cmd->resp_type & MMC_RSP_CRC)
184 *error_flags |= MMCI_BIT(RCRCE);
185 if (cmd->resp_type & MMC_RSP_136)
186 cmdr |= MMCI_BF(RSPTYP, 2);
187 else if (cmd->resp_type & MMC_RSP_BUSY)
188 cmdr |= MMCI_BF(RSPTYP, 3);
189 else if (cmd->resp_type & MMC_RSP_PRESENT)
190 cmdr |= MMCI_BF(RSPTYP, 1);
191
192 return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
193}
194
195/* Entered into function pointer in mci_send_cmd */
196static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
197{
198 u32 status;
199
200 do {
201 status = readl(&mci->sr);
202 if (status & (error_flags | MMCI_BIT(OVRE)))
203 goto io_fail;
204 } while (!(status & MMCI_BIT(RXRDY)));
205
206 if (status & MMCI_BIT(RXRDY)) {
207 *data = readl(&mci->rdr);
208 status = 0;
209 }
210io_fail:
211 return status;
212}
213
214/* Entered into function pointer in mci_send_cmd */
215static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
216{
217 u32 status;
218
219 do {
220 status = readl(&mci->sr);
221 if (status & (error_flags | MMCI_BIT(UNRE)))
222 goto io_fail;
223 } while (!(status & MMCI_BIT(TXRDY)));
224
225 if (status & MMCI_BIT(TXRDY)) {
226 writel(*data, &mci->tdr);
227 status = 0;
228 }
229io_fail:
230 return status;
231}
232
233/*
234 * Entered into mmc structure during driver init
235 *
236 * Sends a command out on the bus and deals with the block data.
237 * Takes the mmc pointer, a command pointer, and an optional data pointer.
238 */
Wenyou Yangc86c0152017-04-13 10:29:22 +0800239#ifdef CONFIG_DM_MMC
240static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
241 struct mmc_data *data)
242{
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800243 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800244 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800245 atmel_mci_t *mci = plat->mci;
Wenyou Yangc86c0152017-04-13 10:29:22 +0800246#else
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200247static int
248mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
249{
Marek Vasut6b75d352015-10-23 20:46:30 +0200250 struct atmel_mci_priv *priv = mmc->priv;
251 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800252#endif
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200253 u32 cmdr;
254 u32 error_flags = 0;
255 u32 status;
256
Marek Vasut877807e2015-10-23 20:46:31 +0200257 if (!priv->initialized) {
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200258 puts ("MCI not initialized!\n");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900259 return -ECOMM;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200260 }
261
262 /* Figure out the transfer arguments */
263 cmdr = mci_encode_cmd(cmd, data, &error_flags);
264
Jean-Jacques Hiblot9b79dbd2018-01-04 15:23:29 +0100265 mci_set_blklen(mci, data->blocksize);
266
Wu, Josh1db73772012-09-13 22:22:04 +0000267 /* For multi blocks read/write, set the block register */
268 if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
269 || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
Jean-Jacques Hiblot9b79dbd2018-01-04 15:23:29 +0100270 writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
271 &mci->blkr);
Wu, Josh1db73772012-09-13 22:22:04 +0000272
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200273 /* Send the command */
274 writel(cmd->cmdarg, &mci->argr);
275 writel(cmdr, &mci->cmdr);
276
277#ifdef DEBUG
278 dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
279#endif
280
281 /* Wait for the command to complete */
282 while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
283
Bo Shen93e32362013-04-26 00:27:07 +0000284 if ((status & error_flags) & MMCI_BIT(RTOE)) {
285 dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900286 return -ETIMEDOUT;
Bo Shen93e32362013-04-26 00:27:07 +0000287 } else if (status & error_flags) {
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200288 dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900289 return -ECOMM;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200290 }
291
292 /* Copy the response to the response buffer */
293 if (cmd->resp_type & MMC_RSP_136) {
294 cmd->response[0] = readl(&mci->rspr);
295 cmd->response[1] = readl(&mci->rspr1);
296 cmd->response[2] = readl(&mci->rspr2);
297 cmd->response[3] = readl(&mci->rspr3);
298 } else
299 cmd->response[0] = readl(&mci->rspr);
300
301 /* transfer all of the blocks */
302 if (data) {
303 u32 word_count, block_count;
304 u32* ioptr;
Jean-Jacques Hiblot9b79dbd2018-01-04 15:23:29 +0100305 u32 i;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200306 u32 (*mci_data_op)
307 (atmel_mci_t *mci, u32* data, u32 error_flags);
308
309 if (data->flags & MMC_DATA_READ) {
310 mci_data_op = mci_data_read;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200311 ioptr = (u32*)data->dest;
312 } else {
313 mci_data_op = mci_data_write;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200314 ioptr = (u32*)data->src;
315 }
316
317 status = 0;
318 for (block_count = 0;
319 block_count < data->blocks && !status;
320 block_count++) {
321 word_count = 0;
322 do {
323 status = mci_data_op(mci, ioptr, error_flags);
324 word_count++;
325 ioptr++;
326 } while (!status && word_count < (data->blocksize/4));
327#ifdef DEBUG
328 if (data->flags & MMC_DATA_READ)
329 {
Wu, Josh9902c7b2014-05-07 17:06:08 +0800330 u32 cnt = word_count * 4;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200331 printf("Read Data:\n");
Wu, Josh9902c7b2014-05-07 17:06:08 +0800332 print_buffer(0, data->dest + cnt * block_count,
333 1, cnt, 0);
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200334 }
335#endif
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200336 if (status) {
337 dump_cmd(cmdr, cmd->cmdarg, status,
338 "Data Transfer Failed");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900339 return -ECOMM;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200340 }
341 }
342
343 /* Wait for Transfer End */
344 i = 0;
345 do {
346 status = readl(&mci->sr);
347
348 if (status & error_flags) {
349 dump_cmd(cmdr, cmd->cmdarg, status,
350 "DTIP Wait Failed");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900351 return -ECOMM;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200352 }
353 i++;
354 } while ((status & MMCI_BIT(DTIP)) && i < 10000);
355 if (status & MMCI_BIT(DTIP)) {
356 dump_cmd(cmdr, cmd->cmdarg, status,
357 "XFER DTIP never unset, ignoring");
358 }
359 }
360
Gregory CLEMENTb4670a02015-11-05 20:58:30 +0100361 /*
362 * After the switch command, wait for 8 clocks before the next
363 * command
364 */
365 if (cmd->cmdidx == MMC_CMD_SWITCH)
366 udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
367
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200368 return 0;
369}
370
Wenyou Yangc86c0152017-04-13 10:29:22 +0800371#ifdef CONFIG_DM_MMC
372static int atmel_mci_set_ios(struct udevice *dev)
373{
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800374 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800375 struct mmc *mmc = mmc_get_mmc_dev(dev);
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800376 atmel_mci_t *mci = plat->mci;
Wenyou Yangc86c0152017-04-13 10:29:22 +0800377#else
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200378/* Entered into mmc structure during driver init */
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900379static int mci_set_ios(struct mmc *mmc)
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200380{
Marek Vasut6b75d352015-10-23 20:46:30 +0200381 struct atmel_mci_priv *priv = mmc->priv;
382 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800383#endif
Bo Shenaac4b692013-04-26 00:27:06 +0000384 int bus_width = mmc->bus_width;
385 unsigned int version = atmel_mci_get_version(mci);
386 int busw;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200387
388 /* Set the clock speed */
Wenyou Yangc86c0152017-04-13 10:29:22 +0800389#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800390 mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800391#else
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200392 mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800393#endif
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200394
395 /*
396 * set the bus width and select slot for this interface
397 * there is no capability for multiple slots on the same interface yet
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200398 */
Bo Shenaac4b692013-04-26 00:27:06 +0000399 if ((version & 0xf00) >= 0x300) {
400 switch (bus_width) {
401 case 8:
402 busw = 3;
403 break;
404 case 4:
405 busw = 2;
406 break;
407 default:
408 busw = 0;
409 break;
410 }
411
412 writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
413 } else {
414 busw = (bus_width == 4) ? 1 : 0;
415
416 writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
417 }
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900418
419 return 0;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200420}
421
Wenyou Yangc86c0152017-04-13 10:29:22 +0800422#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800423static int atmel_mci_hw_init(struct udevice *dev)
Wenyou Yangc86c0152017-04-13 10:29:22 +0800424{
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800425 struct atmel_mci_plat *plat = dev_get_platdata(dev);
426 atmel_mci_t *mci = plat->mci;
Wenyou Yangc86c0152017-04-13 10:29:22 +0800427#else
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200428/* Entered into mmc structure during driver init */
429static int mci_init(struct mmc *mmc)
430{
Marek Vasut6b75d352015-10-23 20:46:30 +0200431 struct atmel_mci_priv *priv = mmc->priv;
432 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800433#endif
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200434
435 /* Initialize controller */
436 writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */
437 writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */
438 writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */
Reinhard Meyer2aed9d12010-11-16 09:24:41 +0100439 writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200440
Wu, Josh9924ca62012-09-13 22:22:06 +0000441 /* This delay can be optimized, but stick with max value */
442 writel(0x7f, &mci->dtor);
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200443 /* Disable Interrupts */
444 writel(~0UL, &mci->idr);
445
446 /* Set default clocks and blocklen */
Wenyou Yangc86c0152017-04-13 10:29:22 +0800447#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800448 mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800449#else
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200450 mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800451#endif
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200452
453 return 0;
454}
455
Wenyou Yangc86c0152017-04-13 10:29:22 +0800456#ifndef CONFIG_DM_MMC
Pantelis Antoniouab769f22014-02-26 19:28:45 +0200457static const struct mmc_ops atmel_mci_ops = {
458 .send_cmd = mci_send_cmd,
459 .set_ios = mci_set_ios,
460 .init = mci_init,
461};
462
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200463/*
464 * This is the only exported function
465 *
466 * Call it with the MCI register base address
467 */
468int atmel_mci_init(void *regs)
469{
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200470 struct mmc *mmc;
471 struct mmc_config *cfg;
Marek Vasut6b75d352015-10-23 20:46:30 +0200472 struct atmel_mci_priv *priv;
Bo Shenaac4b692013-04-26 00:27:06 +0000473 unsigned int version;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200474
Marek Vasut6b75d352015-10-23 20:46:30 +0200475 priv = calloc(1, sizeof(*priv));
476 if (!priv)
477 return -ENOMEM;
Bo Shenaac4b692013-04-26 00:27:06 +0000478
Marek Vasut6b75d352015-10-23 20:46:30 +0200479 cfg = &priv->cfg;
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200480
481 cfg->name = "mci";
482 cfg->ops = &atmel_mci_ops;
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200483
Marek Vasut6b75d352015-10-23 20:46:30 +0200484 priv->mci = (struct atmel_mci *)regs;
Marek Vasut877807e2015-10-23 20:46:31 +0200485 priv->initialized = 0;
Marek Vasut6b75d352015-10-23 20:46:30 +0200486
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200487 /* need to be able to pass these in on a board by board basis */
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200488 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
Marek Vasut6b75d352015-10-23 20:46:30 +0200489 version = atmel_mci_get_version(priv->mci);
Bo Shenda55c662014-07-31 14:39:32 +0800490 if ((version & 0xf00) >= 0x300) {
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200491 cfg->host_caps = MMC_MODE_8BIT;
Bo Shenda55c662014-07-31 14:39:32 +0800492 cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
493 }
Bo Shenaac4b692013-04-26 00:27:06 +0000494
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200495 cfg->host_caps |= MMC_MODE_4BIT;
Bo Shenaac4b692013-04-26 00:27:06 +0000496
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200497 /*
498 * min and max frequencies determined by
499 * max and min of clock divider
500 */
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200501 cfg->f_min = get_mci_clk_rate() / (2*256);
502 cfg->f_max = get_mci_clk_rate() / (2*1);
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200503
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200504 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
John Rigby8feafcc2011-04-18 05:50:08 +0000505
Marek Vasut6b75d352015-10-23 20:46:30 +0200506 mmc = mmc_create(cfg, priv);
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200507
508 if (mmc == NULL) {
Marek Vasut6b75d352015-10-23 20:46:30 +0200509 free(priv);
510 return -ENODEV;
Pantelis Antoniou93bfd612014-03-11 19:34:20 +0200511 }
Marek Vasut6b75d352015-10-23 20:46:30 +0200512 /* NOTE: possibly leaking the priv structure */
Reinhard Meyer1592ef82010-08-13 10:31:06 +0200513
514 return 0;
515}
Wenyou Yangc86c0152017-04-13 10:29:22 +0800516#endif
517
518#ifdef CONFIG_DM_MMC
519static const struct dm_mmc_ops atmel_mci_mmc_ops = {
520 .send_cmd = atmel_mci_send_cmd,
521 .set_ios = atmel_mci_set_ios,
522};
523
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800524static void atmel_mci_setup_cfg(struct udevice *dev)
Wenyou Yangc86c0152017-04-13 10:29:22 +0800525{
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800526 struct atmel_mci_plat *plat = dev_get_platdata(dev);
527 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800528 struct mmc_config *cfg;
529 u32 version;
530
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800531 cfg = &plat->cfg;
Wenyou Yangc86c0152017-04-13 10:29:22 +0800532 cfg->name = "Atmel mci";
533 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
534
535 /*
536 * If the version is above 3.0, the capabilities of the 8-bit
537 * bus width and high speed are supported.
538 */
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800539 version = atmel_mci_get_version(plat->mci);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800540 if ((version & 0xf00) >= 0x300) {
541 cfg->host_caps = MMC_MODE_8BIT |
542 MMC_MODE_HS | MMC_MODE_HS_52MHz;
543 }
544
545 cfg->host_caps |= MMC_MODE_4BIT;
546 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
547 cfg->f_min = priv->bus_clk_rate / (2 * 256);
548 cfg->f_max = priv->bus_clk_rate / 2;
549}
550
551static int atmel_mci_enable_clk(struct udevice *dev)
552{
553 struct atmel_mci_priv *priv = dev_get_priv(dev);
554 struct clk clk;
555 ulong clk_rate;
556 int ret = 0;
557
558 ret = clk_get_by_index(dev, 0, &clk);
559 if (ret) {
560 ret = -EINVAL;
561 goto failed;
562 }
563
564 ret = clk_enable(&clk);
565 if (ret)
566 goto failed;
567
568 clk_rate = clk_get_rate(&clk);
569 if (!clk_rate) {
570 ret = -EINVAL;
571 goto failed;
572 }
573
574 priv->bus_clk_rate = clk_rate;
575
576failed:
577 clk_free(&clk);
578
579 return ret;
580}
581
582static int atmel_mci_probe(struct udevice *dev)
583{
584 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800585 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800586 struct mmc *mmc;
587 int ret;
588
589 ret = atmel_mci_enable_clk(dev);
590 if (ret)
591 return ret;
592
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800593 plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800594
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800595 atmel_mci_setup_cfg(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800596
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800597 mmc = &plat->mmc;
598 mmc->cfg = &plat->cfg;
Wenyou Yangc86c0152017-04-13 10:29:22 +0800599 mmc->dev = dev;
600 upriv->mmc = mmc;
601
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800602 atmel_mci_hw_init(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800603
604 return 0;
605}
606
607static int atmel_mci_bind(struct udevice *dev)
608{
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800609 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800610
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800611 return mmc_bind(dev, &plat->mmc, &plat->cfg);
Wenyou Yangc86c0152017-04-13 10:29:22 +0800612}
613
614static const struct udevice_id atmel_mci_ids[] = {
615 { .compatible = "atmel,hsmci" },
616 { }
617};
618
619U_BOOT_DRIVER(atmel_mci) = {
620 .name = "atmel-mci",
621 .id = UCLASS_MMC,
622 .of_match = atmel_mci_ids,
623 .bind = atmel_mci_bind,
624 .probe = atmel_mci_probe,
Wenyou.Yang@microchip.com722b1502017-07-26 14:35:42 +0800625 .platdata_auto_alloc_size = sizeof(struct atmel_mci_plat),
Wenyou Yangc86c0152017-04-13 10:29:22 +0800626 .priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
627 .ops = &atmel_mci_mmc_ops,
628};
629#endif