blob: 607a22368cba37df67d4bbae0a2246ab5a955132 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Reinhard Meyerc718a562010-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 Meyerc718a562010-08-13 10:31:06 +02009 */
10
11#include <common.h>
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080012#include <clk.h>
Simon Glass1ab16922022-07-31 12:28:48 -060013#include <display_options.h>
Simon Glass11c89f32017-05-17 17:18:03 -060014#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060015#include <log.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020016#include <mmc.h>
17#include <part.h>
18#include <malloc.h>
19#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060020#include <linux/delay.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090021#include <linux/errno.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020022#include <asm/byteorder.h>
23#include <asm/arch/clk.h>
Reinhard Meyer7f619cb2010-11-03 16:32:56 +010024#include <asm/arch/hardware.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020025#include "atmel_mci.h"
26
27#ifndef CONFIG_SYS_MMC_CLK_OD
28# define CONFIG_SYS_MMC_CLK_OD 150000
29#endif
30
31#define MMC_DEFAULT_BLKLEN 512
32
33#if defined(CONFIG_ATMEL_MCI_PORTB)
34# define MCI_BUS 1
35#else
36# define MCI_BUS 0
37#endif
38
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080039#ifdef CONFIG_DM_MMC
40struct atmel_mci_plat {
41 struct mmc mmc;
42 struct mmc_config cfg;
43 struct atmel_mci *mci;
44};
45#endif
46
Marek Vasut903fc1d2015-10-23 20:46:30 +020047struct atmel_mci_priv {
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080048#ifndef CONFIG_DM_MMC
Marek Vasut903fc1d2015-10-23 20:46:30 +020049 struct mmc_config cfg;
50 struct atmel_mci *mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080051#endif
Marek Vasut0b7d54e2015-10-23 20:46:31 +020052 unsigned int initialized:1;
Gregory CLEMENT31f8a002015-11-05 20:58:30 +010053 unsigned int curr_clk;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080054#ifdef CONFIG_DM_MMC
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080055 ulong bus_clk_rate;
56#endif
Marek Vasut903fc1d2015-10-23 20:46:30 +020057};
58
Bo Shen644b4762013-04-26 00:27:06 +000059/* Read Atmel MCI IP version */
60static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
61{
62 return readl(&mci->version) & 0x00000fff;
63}
64
Reinhard Meyerc718a562010-08-13 10:31:06 +020065/*
66 * Print command and status:
67 *
68 * - always when DEBUG is defined
69 * - on command errors
70 */
71static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
72{
Marek Vasut34524b12015-10-23 20:46:28 +020073 debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
74 cmdr, cmdr & 0x3F, arg, status, msg);
Reinhard Meyerc718a562010-08-13 10:31:06 +020075}
76
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +010077static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
78{
79 unsigned int version = atmel_mci_get_version(mci);
80
81 blklen &= 0xfffc;
82
83 /* MCI IP version >= 0x200 has blkr */
84 if (version >= 0x200)
85 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
86 &mci->blkr);
87 else
88 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
89}
90
Reinhard Meyerc718a562010-08-13 10:31:06 +020091/* Setup for MCI Clock and Block Size */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080092#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080093static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080094{
Simon Glassfa20e932020-12-03 16:55:20 -070095 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080096 struct atmel_mci_priv *priv = dev_get_priv(dev);
97 struct mmc *mmc = &plat->mmc;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080098 u32 bus_hz = priv->bus_clk_rate;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080099 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800100#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200101static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
102{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200103 struct atmel_mci_priv *priv = mmc->priv;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200104 u32 bus_hz = get_mci_clk_rate();
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800105 atmel_mci_t *mci = priv->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800106#endif
107
Reinhard Meyerc718a562010-08-13 10:31:06 +0200108 u32 clkdiv = 255;
Bo Shen02d77282014-07-31 14:39:30 +0800109 unsigned int version = atmel_mci_get_version(mci);
110 u32 clkodd = 0;
111 u32 mr;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200112
113 debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
114 bus_hz, hz, blklen);
115 if (hz > 0) {
Bo Shen02d77282014-07-31 14:39:30 +0800116 if (version >= 0x500) {
117 clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
118 if (clkdiv > 511)
119 clkdiv = 511;
120
121 clkodd = clkdiv & 1;
122 clkdiv >>= 1;
123
Marek Vasut34524b12015-10-23 20:46:28 +0200124 debug("mci: setting clock %u Hz, block size %u\n",
125 bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800126 } else {
127 /* find clkdiv yielding a rate <= than requested */
128 for (clkdiv = 0; clkdiv < 255; clkdiv++) {
129 if ((bus_hz / (clkdiv + 1) / 2) <= hz)
130 break;
131 }
Marek Vasut34524b12015-10-23 20:46:28 +0200132 debug("mci: setting clock %u Hz, block size %u\n",
133 (bus_hz / (clkdiv + 1)) / 2, blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800134
Reinhard Meyerc718a562010-08-13 10:31:06 +0200135 }
136 }
Gregory CLEMENT31f8a002015-11-05 20:58:30 +0100137 if (version >= 0x500)
138 priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
139 else
140 priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
Bo Shen02d77282014-07-31 14:39:30 +0800141
142 mr = MMCI_BF(CLKDIV, clkdiv);
143
144 /* MCI IP version >= 0x200 has R/WPROOF */
145 if (version >= 0x200)
146 mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
147
Wu, Joshd1e486b2012-09-13 22:22:04 +0000148 /*
Bo Shen02d77282014-07-31 14:39:30 +0800149 * MCI IP version >= 0x500 use bit 16 as clkodd.
150 * MCI IP version < 0x500 use upper 16 bits for blklen.
Wu, Joshd1e486b2012-09-13 22:22:04 +0000151 */
Bo Shen02d77282014-07-31 14:39:30 +0800152 if (version >= 0x500)
153 mr |= MMCI_BF(CLKODD, clkodd);
Bo Shen02d77282014-07-31 14:39:30 +0800154
155 writel(mr, &mci->mr);
156
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100157 mci_set_blklen(mci, blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800158
Bo Shen1dc856d2014-07-31 14:39:32 +0800159 if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
160 writel(MMCI_BIT(HSMODE), &mci->cfg);
161
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200162 priv->initialized = 1;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200163}
164
165/* Return the CMDR with flags for a given command and data packet */
166static u32 mci_encode_cmd(
167 struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
168{
169 u32 cmdr = 0;
170
171 /* Default Flags for Errors */
172 *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
173 MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
174
175 /* Default Flags for the Command */
176 cmdr |= MMCI_BIT(MAXLAT);
177
178 if (data) {
179 cmdr |= MMCI_BF(TRCMD, 1);
180 if (data->blocks > 1)
181 cmdr |= MMCI_BF(TRTYP, 1);
182 if (data->flags & MMC_DATA_READ)
183 cmdr |= MMCI_BIT(TRDIR);
184 }
185
186 if (cmd->resp_type & MMC_RSP_CRC)
187 *error_flags |= MMCI_BIT(RCRCE);
188 if (cmd->resp_type & MMC_RSP_136)
189 cmdr |= MMCI_BF(RSPTYP, 2);
190 else if (cmd->resp_type & MMC_RSP_BUSY)
191 cmdr |= MMCI_BF(RSPTYP, 3);
192 else if (cmd->resp_type & MMC_RSP_PRESENT)
193 cmdr |= MMCI_BF(RSPTYP, 1);
194
195 return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
196}
197
198/* Entered into function pointer in mci_send_cmd */
199static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
200{
201 u32 status;
202
203 do {
204 status = readl(&mci->sr);
205 if (status & (error_flags | MMCI_BIT(OVRE)))
206 goto io_fail;
207 } while (!(status & MMCI_BIT(RXRDY)));
208
209 if (status & MMCI_BIT(RXRDY)) {
210 *data = readl(&mci->rdr);
211 status = 0;
212 }
213io_fail:
214 return status;
215}
216
217/* Entered into function pointer in mci_send_cmd */
218static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
219{
220 u32 status;
221
222 do {
223 status = readl(&mci->sr);
224 if (status & (error_flags | MMCI_BIT(UNRE)))
225 goto io_fail;
226 } while (!(status & MMCI_BIT(TXRDY)));
227
228 if (status & MMCI_BIT(TXRDY)) {
229 writel(*data, &mci->tdr);
230 status = 0;
231 }
232io_fail:
233 return status;
234}
235
236/*
237 * Entered into mmc structure during driver init
238 *
239 * Sends a command out on the bus and deals with the block data.
240 * Takes the mmc pointer, a command pointer, and an optional data pointer.
241 */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800242#ifdef CONFIG_DM_MMC
243static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
244 struct mmc_data *data)
245{
Simon Glassfa20e932020-12-03 16:55:20 -0700246 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800247 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800248 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800249#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200250static int
251mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
252{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200253 struct atmel_mci_priv *priv = mmc->priv;
254 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800255#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200256 u32 cmdr;
257 u32 error_flags = 0;
258 u32 status;
259
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200260 if (!priv->initialized) {
Reinhard Meyerc718a562010-08-13 10:31:06 +0200261 puts ("MCI not initialized!\n");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900262 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200263 }
264
265 /* Figure out the transfer arguments */
266 cmdr = mci_encode_cmd(cmd, data, &error_flags);
267
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100268 mci_set_blklen(mci, data->blocksize);
269
Wu, Joshd1e486b2012-09-13 22:22:04 +0000270 /* For multi blocks read/write, set the block register */
271 if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
272 || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100273 writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
274 &mci->blkr);
Wu, Joshd1e486b2012-09-13 22:22:04 +0000275
Reinhard Meyerc718a562010-08-13 10:31:06 +0200276 /* Send the command */
277 writel(cmd->cmdarg, &mci->argr);
278 writel(cmdr, &mci->cmdr);
279
280#ifdef DEBUG
281 dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
282#endif
283
284 /* Wait for the command to complete */
285 while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
286
Bo Shen03a743f2013-04-26 00:27:07 +0000287 if ((status & error_flags) & MMCI_BIT(RTOE)) {
288 dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900289 return -ETIMEDOUT;
Bo Shen03a743f2013-04-26 00:27:07 +0000290 } else if (status & error_flags) {
Reinhard Meyerc718a562010-08-13 10:31:06 +0200291 dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900292 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200293 }
294
295 /* Copy the response to the response buffer */
296 if (cmd->resp_type & MMC_RSP_136) {
297 cmd->response[0] = readl(&mci->rspr);
298 cmd->response[1] = readl(&mci->rspr1);
299 cmd->response[2] = readl(&mci->rspr2);
300 cmd->response[3] = readl(&mci->rspr3);
301 } else
302 cmd->response[0] = readl(&mci->rspr);
303
304 /* transfer all of the blocks */
305 if (data) {
306 u32 word_count, block_count;
307 u32* ioptr;
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100308 u32 i;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200309 u32 (*mci_data_op)
310 (atmel_mci_t *mci, u32* data, u32 error_flags);
311
312 if (data->flags & MMC_DATA_READ) {
313 mci_data_op = mci_data_read;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200314 ioptr = (u32*)data->dest;
315 } else {
316 mci_data_op = mci_data_write;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200317 ioptr = (u32*)data->src;
318 }
319
320 status = 0;
321 for (block_count = 0;
322 block_count < data->blocks && !status;
323 block_count++) {
324 word_count = 0;
325 do {
326 status = mci_data_op(mci, ioptr, error_flags);
327 word_count++;
328 ioptr++;
329 } while (!status && word_count < (data->blocksize/4));
330#ifdef DEBUG
331 if (data->flags & MMC_DATA_READ)
332 {
Wu, Josh6bcb5622014-05-07 17:06:08 +0800333 u32 cnt = word_count * 4;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200334 printf("Read Data:\n");
Wu, Josh6bcb5622014-05-07 17:06:08 +0800335 print_buffer(0, data->dest + cnt * block_count,
336 1, cnt, 0);
Reinhard Meyerc718a562010-08-13 10:31:06 +0200337 }
338#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200339 if (status) {
340 dump_cmd(cmdr, cmd->cmdarg, status,
341 "Data Transfer Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900342 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200343 }
344 }
345
346 /* Wait for Transfer End */
347 i = 0;
348 do {
349 status = readl(&mci->sr);
350
351 if (status & error_flags) {
352 dump_cmd(cmdr, cmd->cmdarg, status,
353 "DTIP Wait Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900354 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200355 }
356 i++;
357 } while ((status & MMCI_BIT(DTIP)) && i < 10000);
358 if (status & MMCI_BIT(DTIP)) {
359 dump_cmd(cmdr, cmd->cmdarg, status,
360 "XFER DTIP never unset, ignoring");
361 }
362 }
363
Gregory CLEMENT31f8a002015-11-05 20:58:30 +0100364 /*
365 * After the switch command, wait for 8 clocks before the next
366 * command
367 */
368 if (cmd->cmdidx == MMC_CMD_SWITCH)
369 udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
370
Reinhard Meyerc718a562010-08-13 10:31:06 +0200371 return 0;
372}
373
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800374#ifdef CONFIG_DM_MMC
375static int atmel_mci_set_ios(struct udevice *dev)
376{
Simon Glassfa20e932020-12-03 16:55:20 -0700377 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800378 struct mmc *mmc = mmc_get_mmc_dev(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800379 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800380#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200381/* Entered into mmc structure during driver init */
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900382static int mci_set_ios(struct mmc *mmc)
Reinhard Meyerc718a562010-08-13 10:31:06 +0200383{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200384 struct atmel_mci_priv *priv = mmc->priv;
385 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800386#endif
Bo Shen644b4762013-04-26 00:27:06 +0000387 int bus_width = mmc->bus_width;
388 unsigned int version = atmel_mci_get_version(mci);
389 int busw;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200390
391 /* Set the clock speed */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800392#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800393 mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800394#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200395 mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800396#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200397
398 /*
399 * set the bus width and select slot for this interface
400 * there is no capability for multiple slots on the same interface yet
Reinhard Meyerc718a562010-08-13 10:31:06 +0200401 */
Bo Shen644b4762013-04-26 00:27:06 +0000402 if ((version & 0xf00) >= 0x300) {
403 switch (bus_width) {
404 case 8:
405 busw = 3;
406 break;
407 case 4:
408 busw = 2;
409 break;
410 default:
411 busw = 0;
412 break;
413 }
414
415 writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
416 } else {
417 busw = (bus_width == 4) ? 1 : 0;
418
419 writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
420 }
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900421
422 return 0;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200423}
424
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800425#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800426static int atmel_mci_hw_init(struct udevice *dev)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800427{
Simon Glassfa20e932020-12-03 16:55:20 -0700428 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800429 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800430#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200431/* Entered into mmc structure during driver init */
432static int mci_init(struct mmc *mmc)
433{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200434 struct atmel_mci_priv *priv = mmc->priv;
435 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800436#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200437
438 /* Initialize controller */
439 writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */
440 writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */
441 writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */
Reinhard Meyerf2675572010-11-16 09:24:41 +0100442 writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */
Reinhard Meyerc718a562010-08-13 10:31:06 +0200443
Wu, Joshec35c912012-09-13 22:22:06 +0000444 /* This delay can be optimized, but stick with max value */
445 writel(0x7f, &mci->dtor);
Reinhard Meyerc718a562010-08-13 10:31:06 +0200446 /* Disable Interrupts */
447 writel(~0UL, &mci->idr);
448
449 /* Set default clocks and blocklen */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800450#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800451 mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800452#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200453 mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800454#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200455
456 return 0;
457}
458
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800459#ifndef CONFIG_DM_MMC
Pantelis Antoniouc9e75912014-02-26 19:28:45 +0200460static const struct mmc_ops atmel_mci_ops = {
461 .send_cmd = mci_send_cmd,
462 .set_ios = mci_set_ios,
463 .init = mci_init,
464};
465
Reinhard Meyerc718a562010-08-13 10:31:06 +0200466/*
467 * This is the only exported function
468 *
469 * Call it with the MCI register base address
470 */
471int atmel_mci_init(void *regs)
472{
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200473 struct mmc *mmc;
474 struct mmc_config *cfg;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200475 struct atmel_mci_priv *priv;
Bo Shen644b4762013-04-26 00:27:06 +0000476 unsigned int version;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200477
Marek Vasut903fc1d2015-10-23 20:46:30 +0200478 priv = calloc(1, sizeof(*priv));
479 if (!priv)
480 return -ENOMEM;
Bo Shen644b4762013-04-26 00:27:06 +0000481
Marek Vasut903fc1d2015-10-23 20:46:30 +0200482 cfg = &priv->cfg;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200483
484 cfg->name = "mci";
485 cfg->ops = &atmel_mci_ops;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200486
Marek Vasut903fc1d2015-10-23 20:46:30 +0200487 priv->mci = (struct atmel_mci *)regs;
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200488 priv->initialized = 0;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200489
Reinhard Meyerc718a562010-08-13 10:31:06 +0200490 /* need to be able to pass these in on a board by board basis */
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200491 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200492 version = atmel_mci_get_version(priv->mci);
Bo Shen1dc856d2014-07-31 14:39:32 +0800493 if ((version & 0xf00) >= 0x300) {
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200494 cfg->host_caps = MMC_MODE_8BIT;
Bo Shen1dc856d2014-07-31 14:39:32 +0800495 cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
496 }
Bo Shen644b4762013-04-26 00:27:06 +0000497
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200498 cfg->host_caps |= MMC_MODE_4BIT;
Bo Shen644b4762013-04-26 00:27:06 +0000499
Reinhard Meyerc718a562010-08-13 10:31:06 +0200500 /*
501 * min and max frequencies determined by
502 * max and min of clock divider
503 */
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200504 cfg->f_min = get_mci_clk_rate() / (2*256);
505 cfg->f_max = get_mci_clk_rate() / (2*1);
506
507 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200508
Marek Vasut903fc1d2015-10-23 20:46:30 +0200509 mmc = mmc_create(cfg, priv);
John Rigbyf2f43662011-04-18 05:50:08 +0000510
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200511 if (mmc == NULL) {
Marek Vasut903fc1d2015-10-23 20:46:30 +0200512 free(priv);
513 return -ENODEV;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200514 }
Marek Vasut903fc1d2015-10-23 20:46:30 +0200515 /* NOTE: possibly leaking the priv structure */
Reinhard Meyerc718a562010-08-13 10:31:06 +0200516
517 return 0;
518}
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800519#endif
520
521#ifdef CONFIG_DM_MMC
522static const struct dm_mmc_ops atmel_mci_mmc_ops = {
523 .send_cmd = atmel_mci_send_cmd,
524 .set_ios = atmel_mci_set_ios,
525};
526
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800527static void atmel_mci_setup_cfg(struct udevice *dev)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800528{
Simon Glassfa20e932020-12-03 16:55:20 -0700529 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800530 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800531 struct mmc_config *cfg;
532 u32 version;
533
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800534 cfg = &plat->cfg;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800535 cfg->name = "Atmel mci";
536 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
537
538 /*
539 * If the version is above 3.0, the capabilities of the 8-bit
540 * bus width and high speed are supported.
541 */
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800542 version = atmel_mci_get_version(plat->mci);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800543 if ((version & 0xf00) >= 0x300) {
544 cfg->host_caps = MMC_MODE_8BIT |
545 MMC_MODE_HS | MMC_MODE_HS_52MHz;
546 }
547
548 cfg->host_caps |= MMC_MODE_4BIT;
549 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
550 cfg->f_min = priv->bus_clk_rate / (2 * 256);
551 cfg->f_max = priv->bus_clk_rate / 2;
552}
553
554static int atmel_mci_enable_clk(struct udevice *dev)
555{
556 struct atmel_mci_priv *priv = dev_get_priv(dev);
557 struct clk clk;
558 ulong clk_rate;
559 int ret = 0;
560
561 ret = clk_get_by_index(dev, 0, &clk);
562 if (ret) {
563 ret = -EINVAL;
564 goto failed;
565 }
566
567 ret = clk_enable(&clk);
568 if (ret)
569 goto failed;
570
571 clk_rate = clk_get_rate(&clk);
572 if (!clk_rate) {
573 ret = -EINVAL;
574 goto failed;
575 }
576
577 priv->bus_clk_rate = clk_rate;
578
579failed:
580 clk_free(&clk);
581
582 return ret;
583}
584
585static int atmel_mci_probe(struct udevice *dev)
586{
587 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700588 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800589 struct mmc *mmc;
590 int ret;
591
592 ret = atmel_mci_enable_clk(dev);
593 if (ret)
594 return ret;
595
Masahiro Yamada32822d02020-08-04 14:14:43 +0900596 plat->mci = dev_read_addr_ptr(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800597
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800598 atmel_mci_setup_cfg(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800599
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800600 mmc = &plat->mmc;
601 mmc->cfg = &plat->cfg;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800602 mmc->dev = dev;
603 upriv->mmc = mmc;
604
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800605 atmel_mci_hw_init(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800606
607 return 0;
608}
609
610static int atmel_mci_bind(struct udevice *dev)
611{
Simon Glassfa20e932020-12-03 16:55:20 -0700612 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800613
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800614 return mmc_bind(dev, &plat->mmc, &plat->cfg);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800615}
616
617static const struct udevice_id atmel_mci_ids[] = {
618 { .compatible = "atmel,hsmci" },
619 { }
620};
621
622U_BOOT_DRIVER(atmel_mci) = {
623 .name = "atmel-mci",
624 .id = UCLASS_MMC,
625 .of_match = atmel_mci_ids,
626 .bind = atmel_mci_bind,
627 .probe = atmel_mci_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700628 .plat_auto = sizeof(struct atmel_mci_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700629 .priv_auto = sizeof(struct atmel_mci_priv),
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800630 .ops = &atmel_mci_mmc_ops,
631};
632#endif