blob: 186b3d7dbf1a71447c0734eab3a46ee576259230 [file] [log] [blame]
Reinhard Meyerc718a562010-08-13 10:31:06 +02001/*
2 * Copyright (C) 2010
3 * Rob Emanuele <rob@emanuele.us>
4 * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
5 *
6 * Original Driver:
7 * Copyright (C) 2004-2006 Atmel Corporation
8 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02009 * SPDX-License-Identifier: GPL-2.0+
Reinhard Meyerc718a562010-08-13 10:31:06 +020010 */
11
12#include <common.h>
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080013#include <clk.h>
Simon Glass11c89f32017-05-17 17:18:03 -060014#include <dm.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020015#include <mmc.h>
16#include <part.h>
17#include <malloc.h>
18#include <asm/io.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090019#include <linux/errno.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020020#include <asm/byteorder.h>
21#include <asm/arch/clk.h>
Reinhard Meyer7f619cb2010-11-03 16:32:56 +010022#include <asm/arch/hardware.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020023#include "atmel_mci.h"
24
25#ifndef CONFIG_SYS_MMC_CLK_OD
26# define CONFIG_SYS_MMC_CLK_OD 150000
27#endif
28
29#define MMC_DEFAULT_BLKLEN 512
30
31#if defined(CONFIG_ATMEL_MCI_PORTB)
32# define MCI_BUS 1
33#else
34# define MCI_BUS 0
35#endif
36
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080037#ifdef CONFIG_DM_MMC
38struct atmel_mci_plat {
39 struct mmc mmc;
40 struct mmc_config cfg;
41 struct atmel_mci *mci;
42};
43#endif
44
Marek Vasut903fc1d2015-10-23 20:46:30 +020045struct atmel_mci_priv {
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080046#ifndef CONFIG_DM_MMC
Marek Vasut903fc1d2015-10-23 20:46:30 +020047 struct mmc_config cfg;
48 struct atmel_mci *mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080049#endif
Marek Vasut0b7d54e2015-10-23 20:46:31 +020050 unsigned int initialized:1;
Gregory CLEMENT31f8a002015-11-05 20:58:30 +010051 unsigned int curr_clk;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080052#ifdef CONFIG_DM_MMC
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080053 ulong bus_clk_rate;
54#endif
Marek Vasut903fc1d2015-10-23 20:46:30 +020055};
56
Bo Shen644b4762013-04-26 00:27:06 +000057/* Read Atmel MCI IP version */
58static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
59{
60 return readl(&mci->version) & 0x00000fff;
61}
62
Reinhard Meyerc718a562010-08-13 10:31:06 +020063/*
64 * Print command and status:
65 *
66 * - always when DEBUG is defined
67 * - on command errors
68 */
69static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
70{
Marek Vasut34524b12015-10-23 20:46:28 +020071 debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
72 cmdr, cmdr & 0x3F, arg, status, msg);
Reinhard Meyerc718a562010-08-13 10:31:06 +020073}
74
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +010075static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
76{
77 unsigned int version = atmel_mci_get_version(mci);
78
79 blklen &= 0xfffc;
80
81 /* MCI IP version >= 0x200 has blkr */
82 if (version >= 0x200)
83 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
84 &mci->blkr);
85 else
86 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
87}
88
Reinhard Meyerc718a562010-08-13 10:31:06 +020089/* Setup for MCI Clock and Block Size */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080090#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080091static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080092{
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080093 struct atmel_mci_plat *plat = dev_get_platdata(dev);
94 struct atmel_mci_priv *priv = dev_get_priv(dev);
95 struct mmc *mmc = &plat->mmc;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080096 u32 bus_hz = priv->bus_clk_rate;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080097 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080098#else
Reinhard Meyerc718a562010-08-13 10:31:06 +020099static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
100{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200101 struct atmel_mci_priv *priv = mmc->priv;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200102 u32 bus_hz = get_mci_clk_rate();
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800103 atmel_mci_t *mci = priv->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800104#endif
105
Reinhard Meyerc718a562010-08-13 10:31:06 +0200106 u32 clkdiv = 255;
Bo Shen02d77282014-07-31 14:39:30 +0800107 unsigned int version = atmel_mci_get_version(mci);
108 u32 clkodd = 0;
109 u32 mr;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200110
111 debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
112 bus_hz, hz, blklen);
113 if (hz > 0) {
Bo Shen02d77282014-07-31 14:39:30 +0800114 if (version >= 0x500) {
115 clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
116 if (clkdiv > 511)
117 clkdiv = 511;
118
119 clkodd = clkdiv & 1;
120 clkdiv >>= 1;
121
Marek Vasut34524b12015-10-23 20:46:28 +0200122 debug("mci: setting clock %u Hz, block size %u\n",
123 bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800124 } else {
125 /* find clkdiv yielding a rate <= than requested */
126 for (clkdiv = 0; clkdiv < 255; clkdiv++) {
127 if ((bus_hz / (clkdiv + 1) / 2) <= hz)
128 break;
129 }
Marek Vasut34524b12015-10-23 20:46:28 +0200130 debug("mci: setting clock %u Hz, block size %u\n",
131 (bus_hz / (clkdiv + 1)) / 2, blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800132
Reinhard Meyerc718a562010-08-13 10:31:06 +0200133 }
134 }
Gregory CLEMENT31f8a002015-11-05 20:58:30 +0100135 if (version >= 0x500)
136 priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
137 else
138 priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
Bo Shen02d77282014-07-31 14:39:30 +0800139
140 mr = MMCI_BF(CLKDIV, clkdiv);
141
142 /* MCI IP version >= 0x200 has R/WPROOF */
143 if (version >= 0x200)
144 mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
145
Wu, Joshd1e486b2012-09-13 22:22:04 +0000146 /*
Bo Shen02d77282014-07-31 14:39:30 +0800147 * MCI IP version >= 0x500 use bit 16 as clkodd.
148 * MCI IP version < 0x500 use upper 16 bits for blklen.
Wu, Joshd1e486b2012-09-13 22:22:04 +0000149 */
Bo Shen02d77282014-07-31 14:39:30 +0800150 if (version >= 0x500)
151 mr |= MMCI_BF(CLKODD, clkodd);
Bo Shen02d77282014-07-31 14:39:30 +0800152
153 writel(mr, &mci->mr);
154
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100155 mci_set_blklen(mci, blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800156
Bo Shen1dc856d2014-07-31 14:39:32 +0800157 if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
158 writel(MMCI_BIT(HSMODE), &mci->cfg);
159
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200160 priv->initialized = 1;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200161}
162
163/* Return the CMDR with flags for a given command and data packet */
164static u32 mci_encode_cmd(
165 struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
166{
167 u32 cmdr = 0;
168
169 /* Default Flags for Errors */
170 *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
171 MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
172
173 /* Default Flags for the Command */
174 cmdr |= MMCI_BIT(MAXLAT);
175
176 if (data) {
177 cmdr |= MMCI_BF(TRCMD, 1);
178 if (data->blocks > 1)
179 cmdr |= MMCI_BF(TRTYP, 1);
180 if (data->flags & MMC_DATA_READ)
181 cmdr |= MMCI_BIT(TRDIR);
182 }
183
184 if (cmd->resp_type & MMC_RSP_CRC)
185 *error_flags |= MMCI_BIT(RCRCE);
186 if (cmd->resp_type & MMC_RSP_136)
187 cmdr |= MMCI_BF(RSPTYP, 2);
188 else if (cmd->resp_type & MMC_RSP_BUSY)
189 cmdr |= MMCI_BF(RSPTYP, 3);
190 else if (cmd->resp_type & MMC_RSP_PRESENT)
191 cmdr |= MMCI_BF(RSPTYP, 1);
192
193 return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
194}
195
196/* Entered into function pointer in mci_send_cmd */
197static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
198{
199 u32 status;
200
201 do {
202 status = readl(&mci->sr);
203 if (status & (error_flags | MMCI_BIT(OVRE)))
204 goto io_fail;
205 } while (!(status & MMCI_BIT(RXRDY)));
206
207 if (status & MMCI_BIT(RXRDY)) {
208 *data = readl(&mci->rdr);
209 status = 0;
210 }
211io_fail:
212 return status;
213}
214
215/* Entered into function pointer in mci_send_cmd */
216static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
217{
218 u32 status;
219
220 do {
221 status = readl(&mci->sr);
222 if (status & (error_flags | MMCI_BIT(UNRE)))
223 goto io_fail;
224 } while (!(status & MMCI_BIT(TXRDY)));
225
226 if (status & MMCI_BIT(TXRDY)) {
227 writel(*data, &mci->tdr);
228 status = 0;
229 }
230io_fail:
231 return status;
232}
233
234/*
235 * Entered into mmc structure during driver init
236 *
237 * Sends a command out on the bus and deals with the block data.
238 * Takes the mmc pointer, a command pointer, and an optional data pointer.
239 */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800240#ifdef CONFIG_DM_MMC
241static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
242 struct mmc_data *data)
243{
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800244 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800245 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800246 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800247#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200248static int
249mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
250{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200251 struct atmel_mci_priv *priv = mmc->priv;
252 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800253#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200254 u32 cmdr;
255 u32 error_flags = 0;
256 u32 status;
257
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200258 if (!priv->initialized) {
Reinhard Meyerc718a562010-08-13 10:31:06 +0200259 puts ("MCI not initialized!\n");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900260 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200261 }
262
263 /* Figure out the transfer arguments */
264 cmdr = mci_encode_cmd(cmd, data, &error_flags);
265
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100266 mci_set_blklen(mci, data->blocksize);
267
Wu, Joshd1e486b2012-09-13 22:22:04 +0000268 /* For multi blocks read/write, set the block register */
269 if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
270 || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100271 writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
272 &mci->blkr);
Wu, Joshd1e486b2012-09-13 22:22:04 +0000273
Reinhard Meyerc718a562010-08-13 10:31:06 +0200274 /* Send the command */
275 writel(cmd->cmdarg, &mci->argr);
276 writel(cmdr, &mci->cmdr);
277
278#ifdef DEBUG
279 dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
280#endif
281
282 /* Wait for the command to complete */
283 while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
284
Bo Shen03a743f2013-04-26 00:27:07 +0000285 if ((status & error_flags) & MMCI_BIT(RTOE)) {
286 dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900287 return -ETIMEDOUT;
Bo Shen03a743f2013-04-26 00:27:07 +0000288 } else if (status & error_flags) {
Reinhard Meyerc718a562010-08-13 10:31:06 +0200289 dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900290 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200291 }
292
293 /* Copy the response to the response buffer */
294 if (cmd->resp_type & MMC_RSP_136) {
295 cmd->response[0] = readl(&mci->rspr);
296 cmd->response[1] = readl(&mci->rspr1);
297 cmd->response[2] = readl(&mci->rspr2);
298 cmd->response[3] = readl(&mci->rspr3);
299 } else
300 cmd->response[0] = readl(&mci->rspr);
301
302 /* transfer all of the blocks */
303 if (data) {
304 u32 word_count, block_count;
305 u32* ioptr;
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100306 u32 i;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200307 u32 (*mci_data_op)
308 (atmel_mci_t *mci, u32* data, u32 error_flags);
309
310 if (data->flags & MMC_DATA_READ) {
311 mci_data_op = mci_data_read;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200312 ioptr = (u32*)data->dest;
313 } else {
314 mci_data_op = mci_data_write;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200315 ioptr = (u32*)data->src;
316 }
317
318 status = 0;
319 for (block_count = 0;
320 block_count < data->blocks && !status;
321 block_count++) {
322 word_count = 0;
323 do {
324 status = mci_data_op(mci, ioptr, error_flags);
325 word_count++;
326 ioptr++;
327 } while (!status && word_count < (data->blocksize/4));
328#ifdef DEBUG
329 if (data->flags & MMC_DATA_READ)
330 {
Wu, Josh6bcb5622014-05-07 17:06:08 +0800331 u32 cnt = word_count * 4;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200332 printf("Read Data:\n");
Wu, Josh6bcb5622014-05-07 17:06:08 +0800333 print_buffer(0, data->dest + cnt * block_count,
334 1, cnt, 0);
Reinhard Meyerc718a562010-08-13 10:31:06 +0200335 }
336#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200337 if (status) {
338 dump_cmd(cmdr, cmd->cmdarg, status,
339 "Data Transfer Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900340 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200341 }
342 }
343
344 /* Wait for Transfer End */
345 i = 0;
346 do {
347 status = readl(&mci->sr);
348
349 if (status & error_flags) {
350 dump_cmd(cmdr, cmd->cmdarg, status,
351 "DTIP Wait Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900352 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200353 }
354 i++;
355 } while ((status & MMCI_BIT(DTIP)) && i < 10000);
356 if (status & MMCI_BIT(DTIP)) {
357 dump_cmd(cmdr, cmd->cmdarg, status,
358 "XFER DTIP never unset, ignoring");
359 }
360 }
361
Gregory CLEMENT31f8a002015-11-05 20:58:30 +0100362 /*
363 * After the switch command, wait for 8 clocks before the next
364 * command
365 */
366 if (cmd->cmdidx == MMC_CMD_SWITCH)
367 udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
368
Reinhard Meyerc718a562010-08-13 10:31:06 +0200369 return 0;
370}
371
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800372#ifdef CONFIG_DM_MMC
373static int atmel_mci_set_ios(struct udevice *dev)
374{
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800375 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800376 struct mmc *mmc = mmc_get_mmc_dev(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800377 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800378#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200379/* Entered into mmc structure during driver init */
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900380static int mci_set_ios(struct mmc *mmc)
Reinhard Meyerc718a562010-08-13 10:31:06 +0200381{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200382 struct atmel_mci_priv *priv = mmc->priv;
383 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800384#endif
Bo Shen644b4762013-04-26 00:27:06 +0000385 int bus_width = mmc->bus_width;
386 unsigned int version = atmel_mci_get_version(mci);
387 int busw;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200388
389 /* Set the clock speed */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800390#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800391 mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800392#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200393 mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800394#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200395
396 /*
397 * set the bus width and select slot for this interface
398 * there is no capability for multiple slots on the same interface yet
Reinhard Meyerc718a562010-08-13 10:31:06 +0200399 */
Bo Shen644b4762013-04-26 00:27:06 +0000400 if ((version & 0xf00) >= 0x300) {
401 switch (bus_width) {
402 case 8:
403 busw = 3;
404 break;
405 case 4:
406 busw = 2;
407 break;
408 default:
409 busw = 0;
410 break;
411 }
412
413 writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
414 } else {
415 busw = (bus_width == 4) ? 1 : 0;
416
417 writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
418 }
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900419
420 return 0;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200421}
422
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800423#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800424static int atmel_mci_hw_init(struct udevice *dev)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800425{
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800426 struct atmel_mci_plat *plat = dev_get_platdata(dev);
427 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800428#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200429/* Entered into mmc structure during driver init */
430static int mci_init(struct mmc *mmc)
431{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200432 struct atmel_mci_priv *priv = mmc->priv;
433 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800434#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200435
436 /* Initialize controller */
437 writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */
438 writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */
439 writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */
Reinhard Meyerf2675572010-11-16 09:24:41 +0100440 writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */
Reinhard Meyerc718a562010-08-13 10:31:06 +0200441
Wu, Joshec35c912012-09-13 22:22:06 +0000442 /* This delay can be optimized, but stick with max value */
443 writel(0x7f, &mci->dtor);
Reinhard Meyerc718a562010-08-13 10:31:06 +0200444 /* Disable Interrupts */
445 writel(~0UL, &mci->idr);
446
447 /* Set default clocks and blocklen */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800448#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800449 mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800450#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200451 mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800452#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200453
454 return 0;
455}
456
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800457#ifndef CONFIG_DM_MMC
Pantelis Antoniouc9e75912014-02-26 19:28:45 +0200458static const struct mmc_ops atmel_mci_ops = {
459 .send_cmd = mci_send_cmd,
460 .set_ios = mci_set_ios,
461 .init = mci_init,
462};
463
Reinhard Meyerc718a562010-08-13 10:31:06 +0200464/*
465 * This is the only exported function
466 *
467 * Call it with the MCI register base address
468 */
469int atmel_mci_init(void *regs)
470{
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200471 struct mmc *mmc;
472 struct mmc_config *cfg;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200473 struct atmel_mci_priv *priv;
Bo Shen644b4762013-04-26 00:27:06 +0000474 unsigned int version;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200475
Marek Vasut903fc1d2015-10-23 20:46:30 +0200476 priv = calloc(1, sizeof(*priv));
477 if (!priv)
478 return -ENOMEM;
Bo Shen644b4762013-04-26 00:27:06 +0000479
Marek Vasut903fc1d2015-10-23 20:46:30 +0200480 cfg = &priv->cfg;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200481
482 cfg->name = "mci";
483 cfg->ops = &atmel_mci_ops;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200484
Marek Vasut903fc1d2015-10-23 20:46:30 +0200485 priv->mci = (struct atmel_mci *)regs;
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200486 priv->initialized = 0;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200487
Reinhard Meyerc718a562010-08-13 10:31:06 +0200488 /* need to be able to pass these in on a board by board basis */
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200489 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200490 version = atmel_mci_get_version(priv->mci);
Bo Shen1dc856d2014-07-31 14:39:32 +0800491 if ((version & 0xf00) >= 0x300) {
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200492 cfg->host_caps = MMC_MODE_8BIT;
Bo Shen1dc856d2014-07-31 14:39:32 +0800493 cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
494 }
Bo Shen644b4762013-04-26 00:27:06 +0000495
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200496 cfg->host_caps |= MMC_MODE_4BIT;
Bo Shen644b4762013-04-26 00:27:06 +0000497
Reinhard Meyerc718a562010-08-13 10:31:06 +0200498 /*
499 * min and max frequencies determined by
500 * max and min of clock divider
501 */
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200502 cfg->f_min = get_mci_clk_rate() / (2*256);
503 cfg->f_max = get_mci_clk_rate() / (2*1);
504
505 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200506
Marek Vasut903fc1d2015-10-23 20:46:30 +0200507 mmc = mmc_create(cfg, priv);
John Rigbyf2f43662011-04-18 05:50:08 +0000508
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200509 if (mmc == NULL) {
Marek Vasut903fc1d2015-10-23 20:46:30 +0200510 free(priv);
511 return -ENODEV;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200512 }
Marek Vasut903fc1d2015-10-23 20:46:30 +0200513 /* NOTE: possibly leaking the priv structure */
Reinhard Meyerc718a562010-08-13 10:31:06 +0200514
515 return 0;
516}
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800517#endif
518
519#ifdef CONFIG_DM_MMC
520static const struct dm_mmc_ops atmel_mci_mmc_ops = {
521 .send_cmd = atmel_mci_send_cmd,
522 .set_ios = atmel_mci_set_ios,
523};
524
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800525static void atmel_mci_setup_cfg(struct udevice *dev)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800526{
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800527 struct atmel_mci_plat *plat = dev_get_platdata(dev);
528 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800529 struct mmc_config *cfg;
530 u32 version;
531
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800532 cfg = &plat->cfg;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800533 cfg->name = "Atmel mci";
534 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
535
536 /*
537 * If the version is above 3.0, the capabilities of the 8-bit
538 * bus width and high speed are supported.
539 */
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800540 version = atmel_mci_get_version(plat->mci);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800541 if ((version & 0xf00) >= 0x300) {
542 cfg->host_caps = MMC_MODE_8BIT |
543 MMC_MODE_HS | MMC_MODE_HS_52MHz;
544 }
545
546 cfg->host_caps |= MMC_MODE_4BIT;
547 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
548 cfg->f_min = priv->bus_clk_rate / (2 * 256);
549 cfg->f_max = priv->bus_clk_rate / 2;
550}
551
552static int atmel_mci_enable_clk(struct udevice *dev)
553{
554 struct atmel_mci_priv *priv = dev_get_priv(dev);
555 struct clk clk;
556 ulong clk_rate;
557 int ret = 0;
558
559 ret = clk_get_by_index(dev, 0, &clk);
560 if (ret) {
561 ret = -EINVAL;
562 goto failed;
563 }
564
565 ret = clk_enable(&clk);
566 if (ret)
567 goto failed;
568
569 clk_rate = clk_get_rate(&clk);
570 if (!clk_rate) {
571 ret = -EINVAL;
572 goto failed;
573 }
574
575 priv->bus_clk_rate = clk_rate;
576
577failed:
578 clk_free(&clk);
579
580 return ret;
581}
582
583static int atmel_mci_probe(struct udevice *dev)
584{
585 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800586 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800587 struct mmc *mmc;
588 int ret;
589
590 ret = atmel_mci_enable_clk(dev);
591 if (ret)
592 return ret;
593
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800594 plat->mci = (struct atmel_mci *)devfdt_get_addr_ptr(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800595
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800596 atmel_mci_setup_cfg(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800597
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800598 mmc = &plat->mmc;
599 mmc->cfg = &plat->cfg;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800600 mmc->dev = dev;
601 upriv->mmc = mmc;
602
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800603 atmel_mci_hw_init(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800604
605 return 0;
606}
607
608static int atmel_mci_bind(struct udevice *dev)
609{
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800610 struct atmel_mci_plat *plat = dev_get_platdata(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800611
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800612 return mmc_bind(dev, &plat->mmc, &plat->cfg);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800613}
614
615static const struct udevice_id atmel_mci_ids[] = {
616 { .compatible = "atmel,hsmci" },
617 { }
618};
619
620U_BOOT_DRIVER(atmel_mci) = {
621 .name = "atmel-mci",
622 .id = UCLASS_MMC,
623 .of_match = atmel_mci_ids,
624 .bind = atmel_mci_bind,
625 .probe = atmel_mci_probe,
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800626 .platdata_auto_alloc_size = sizeof(struct atmel_mci_plat),
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800627 .priv_auto_alloc_size = sizeof(struct atmel_mci_priv),
628 .ops = &atmel_mci_mmc_ops,
629};
630#endif