blob: da81425038d4ed5952bcdd9abd34ad3bed4c7135 [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 Glass11c89f32017-05-17 17:18:03 -060013#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.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>
Simon Glassdbd79542020-05-10 11:40:11 -060019#include <linux/delay.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090020#include <linux/errno.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020021#include <asm/byteorder.h>
22#include <asm/arch/clk.h>
Reinhard Meyer7f619cb2010-11-03 16:32:56 +010023#include <asm/arch/hardware.h>
Reinhard Meyerc718a562010-08-13 10:31:06 +020024#include "atmel_mci.h"
25
26#ifndef CONFIG_SYS_MMC_CLK_OD
27# define CONFIG_SYS_MMC_CLK_OD 150000
28#endif
29
30#define MMC_DEFAULT_BLKLEN 512
31
32#if defined(CONFIG_ATMEL_MCI_PORTB)
33# define MCI_BUS 1
34#else
35# define MCI_BUS 0
36#endif
37
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080038#ifdef CONFIG_DM_MMC
39struct atmel_mci_plat {
40 struct mmc mmc;
41 struct mmc_config cfg;
42 struct atmel_mci *mci;
43};
44#endif
45
Marek Vasut903fc1d2015-10-23 20:46:30 +020046struct atmel_mci_priv {
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080047#ifndef CONFIG_DM_MMC
Marek Vasut903fc1d2015-10-23 20:46:30 +020048 struct mmc_config cfg;
49 struct atmel_mci *mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080050#endif
Marek Vasut0b7d54e2015-10-23 20:46:31 +020051 unsigned int initialized:1;
Gregory CLEMENT31f8a002015-11-05 20:58:30 +010052 unsigned int curr_clk;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080053#ifdef CONFIG_DM_MMC
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080054 ulong bus_clk_rate;
55#endif
Marek Vasut903fc1d2015-10-23 20:46:30 +020056};
57
Bo Shen644b4762013-04-26 00:27:06 +000058/* Read Atmel MCI IP version */
59static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
60{
61 return readl(&mci->version) & 0x00000fff;
62}
63
Reinhard Meyerc718a562010-08-13 10:31:06 +020064/*
65 * Print command and status:
66 *
67 * - always when DEBUG is defined
68 * - on command errors
69 */
70static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
71{
Marek Vasut34524b12015-10-23 20:46:28 +020072 debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
73 cmdr, cmdr & 0x3F, arg, status, msg);
Reinhard Meyerc718a562010-08-13 10:31:06 +020074}
75
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +010076static inline void mci_set_blklen(atmel_mci_t *mci, int blklen)
77{
78 unsigned int version = atmel_mci_get_version(mci);
79
80 blklen &= 0xfffc;
81
82 /* MCI IP version >= 0x200 has blkr */
83 if (version >= 0x200)
84 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->blkr)),
85 &mci->blkr);
86 else
87 writel(MMCI_BFINS(BLKLEN, blklen, readl(&mci->mr)), &mci->mr);
88}
89
Reinhard Meyerc718a562010-08-13 10:31:06 +020090/* Setup for MCI Clock and Block Size */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080091#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080092static void mci_set_mode(struct udevice *dev, u32 hz, u32 blklen)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080093{
Simon Glassfa20e932020-12-03 16:55:20 -070094 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080095 struct atmel_mci_priv *priv = dev_get_priv(dev);
96 struct mmc *mmc = &plat->mmc;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080097 u32 bus_hz = priv->bus_clk_rate;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +080098 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +080099#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200100static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
101{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200102 struct atmel_mci_priv *priv = mmc->priv;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200103 u32 bus_hz = get_mci_clk_rate();
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800104 atmel_mci_t *mci = priv->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800105#endif
106
Reinhard Meyerc718a562010-08-13 10:31:06 +0200107 u32 clkdiv = 255;
Bo Shen02d77282014-07-31 14:39:30 +0800108 unsigned int version = atmel_mci_get_version(mci);
109 u32 clkodd = 0;
110 u32 mr;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200111
112 debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
113 bus_hz, hz, blklen);
114 if (hz > 0) {
Bo Shen02d77282014-07-31 14:39:30 +0800115 if (version >= 0x500) {
116 clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2;
117 if (clkdiv > 511)
118 clkdiv = 511;
119
120 clkodd = clkdiv & 1;
121 clkdiv >>= 1;
122
Marek Vasut34524b12015-10-23 20:46:28 +0200123 debug("mci: setting clock %u Hz, block size %u\n",
124 bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800125 } else {
126 /* find clkdiv yielding a rate <= than requested */
127 for (clkdiv = 0; clkdiv < 255; clkdiv++) {
128 if ((bus_hz / (clkdiv + 1) / 2) <= hz)
129 break;
130 }
Marek Vasut34524b12015-10-23 20:46:28 +0200131 debug("mci: setting clock %u Hz, block size %u\n",
132 (bus_hz / (clkdiv + 1)) / 2, blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800133
Reinhard Meyerc718a562010-08-13 10:31:06 +0200134 }
135 }
Gregory CLEMENT31f8a002015-11-05 20:58:30 +0100136 if (version >= 0x500)
137 priv->curr_clk = bus_hz / (clkdiv * 2 + clkodd + 2);
138 else
139 priv->curr_clk = (bus_hz / (clkdiv + 1)) / 2;
Bo Shen02d77282014-07-31 14:39:30 +0800140
141 mr = MMCI_BF(CLKDIV, clkdiv);
142
143 /* MCI IP version >= 0x200 has R/WPROOF */
144 if (version >= 0x200)
145 mr |= MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF);
146
Wu, Joshd1e486b2012-09-13 22:22:04 +0000147 /*
Bo Shen02d77282014-07-31 14:39:30 +0800148 * MCI IP version >= 0x500 use bit 16 as clkodd.
149 * MCI IP version < 0x500 use upper 16 bits for blklen.
Wu, Joshd1e486b2012-09-13 22:22:04 +0000150 */
Bo Shen02d77282014-07-31 14:39:30 +0800151 if (version >= 0x500)
152 mr |= MMCI_BF(CLKODD, clkodd);
Bo Shen02d77282014-07-31 14:39:30 +0800153
154 writel(mr, &mci->mr);
155
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100156 mci_set_blklen(mci, blklen);
Bo Shen02d77282014-07-31 14:39:30 +0800157
Bo Shen1dc856d2014-07-31 14:39:32 +0800158 if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
159 writel(MMCI_BIT(HSMODE), &mci->cfg);
160
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200161 priv->initialized = 1;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200162}
163
164/* Return the CMDR with flags for a given command and data packet */
165static u32 mci_encode_cmd(
166 struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
167{
168 u32 cmdr = 0;
169
170 /* Default Flags for Errors */
171 *error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
172 MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
173
174 /* Default Flags for the Command */
175 cmdr |= MMCI_BIT(MAXLAT);
176
177 if (data) {
178 cmdr |= MMCI_BF(TRCMD, 1);
179 if (data->blocks > 1)
180 cmdr |= MMCI_BF(TRTYP, 1);
181 if (data->flags & MMC_DATA_READ)
182 cmdr |= MMCI_BIT(TRDIR);
183 }
184
185 if (cmd->resp_type & MMC_RSP_CRC)
186 *error_flags |= MMCI_BIT(RCRCE);
187 if (cmd->resp_type & MMC_RSP_136)
188 cmdr |= MMCI_BF(RSPTYP, 2);
189 else if (cmd->resp_type & MMC_RSP_BUSY)
190 cmdr |= MMCI_BF(RSPTYP, 3);
191 else if (cmd->resp_type & MMC_RSP_PRESENT)
192 cmdr |= MMCI_BF(RSPTYP, 1);
193
194 return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
195}
196
197/* Entered into function pointer in mci_send_cmd */
198static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
199{
200 u32 status;
201
202 do {
203 status = readl(&mci->sr);
204 if (status & (error_flags | MMCI_BIT(OVRE)))
205 goto io_fail;
206 } while (!(status & MMCI_BIT(RXRDY)));
207
208 if (status & MMCI_BIT(RXRDY)) {
209 *data = readl(&mci->rdr);
210 status = 0;
211 }
212io_fail:
213 return status;
214}
215
216/* Entered into function pointer in mci_send_cmd */
217static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
218{
219 u32 status;
220
221 do {
222 status = readl(&mci->sr);
223 if (status & (error_flags | MMCI_BIT(UNRE)))
224 goto io_fail;
225 } while (!(status & MMCI_BIT(TXRDY)));
226
227 if (status & MMCI_BIT(TXRDY)) {
228 writel(*data, &mci->tdr);
229 status = 0;
230 }
231io_fail:
232 return status;
233}
234
235/*
236 * Entered into mmc structure during driver init
237 *
238 * Sends a command out on the bus and deals with the block data.
239 * Takes the mmc pointer, a command pointer, and an optional data pointer.
240 */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800241#ifdef CONFIG_DM_MMC
242static int atmel_mci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
243 struct mmc_data *data)
244{
Simon Glassfa20e932020-12-03 16:55:20 -0700245 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800246 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800247 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800248#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200249static int
250mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
251{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200252 struct atmel_mci_priv *priv = mmc->priv;
253 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800254#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200255 u32 cmdr;
256 u32 error_flags = 0;
257 u32 status;
258
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200259 if (!priv->initialized) {
Reinhard Meyerc718a562010-08-13 10:31:06 +0200260 puts ("MCI not initialized!\n");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900261 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200262 }
263
264 /* Figure out the transfer arguments */
265 cmdr = mci_encode_cmd(cmd, data, &error_flags);
266
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100267 mci_set_blklen(mci, data->blocksize);
268
Wu, Joshd1e486b2012-09-13 22:22:04 +0000269 /* For multi blocks read/write, set the block register */
270 if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
271 || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100272 writel(data->blocks | MMCI_BF(BLKLEN, data->blocksize),
273 &mci->blkr);
Wu, Joshd1e486b2012-09-13 22:22:04 +0000274
Reinhard Meyerc718a562010-08-13 10:31:06 +0200275 /* Send the command */
276 writel(cmd->cmdarg, &mci->argr);
277 writel(cmdr, &mci->cmdr);
278
279#ifdef DEBUG
280 dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
281#endif
282
283 /* Wait for the command to complete */
284 while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
285
Bo Shen03a743f2013-04-26 00:27:07 +0000286 if ((status & error_flags) & MMCI_BIT(RTOE)) {
287 dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900288 return -ETIMEDOUT;
Bo Shen03a743f2013-04-26 00:27:07 +0000289 } else if (status & error_flags) {
Reinhard Meyerc718a562010-08-13 10:31:06 +0200290 dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900291 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200292 }
293
294 /* Copy the response to the response buffer */
295 if (cmd->resp_type & MMC_RSP_136) {
296 cmd->response[0] = readl(&mci->rspr);
297 cmd->response[1] = readl(&mci->rspr1);
298 cmd->response[2] = readl(&mci->rspr2);
299 cmd->response[3] = readl(&mci->rspr3);
300 } else
301 cmd->response[0] = readl(&mci->rspr);
302
303 /* transfer all of the blocks */
304 if (data) {
305 u32 word_count, block_count;
306 u32* ioptr;
Jean-Jacques Hiblotdcfb6252018-01-04 15:23:29 +0100307 u32 i;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200308 u32 (*mci_data_op)
309 (atmel_mci_t *mci, u32* data, u32 error_flags);
310
311 if (data->flags & MMC_DATA_READ) {
312 mci_data_op = mci_data_read;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200313 ioptr = (u32*)data->dest;
314 } else {
315 mci_data_op = mci_data_write;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200316 ioptr = (u32*)data->src;
317 }
318
319 status = 0;
320 for (block_count = 0;
321 block_count < data->blocks && !status;
322 block_count++) {
323 word_count = 0;
324 do {
325 status = mci_data_op(mci, ioptr, error_flags);
326 word_count++;
327 ioptr++;
328 } while (!status && word_count < (data->blocksize/4));
329#ifdef DEBUG
330 if (data->flags & MMC_DATA_READ)
331 {
Wu, Josh6bcb5622014-05-07 17:06:08 +0800332 u32 cnt = word_count * 4;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200333 printf("Read Data:\n");
Wu, Josh6bcb5622014-05-07 17:06:08 +0800334 print_buffer(0, data->dest + cnt * block_count,
335 1, cnt, 0);
Reinhard Meyerc718a562010-08-13 10:31:06 +0200336 }
337#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200338 if (status) {
339 dump_cmd(cmdr, cmd->cmdarg, status,
340 "Data Transfer Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900341 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200342 }
343 }
344
345 /* Wait for Transfer End */
346 i = 0;
347 do {
348 status = readl(&mci->sr);
349
350 if (status & error_flags) {
351 dump_cmd(cmdr, cmd->cmdarg, status,
352 "DTIP Wait Failed");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900353 return -ECOMM;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200354 }
355 i++;
356 } while ((status & MMCI_BIT(DTIP)) && i < 10000);
357 if (status & MMCI_BIT(DTIP)) {
358 dump_cmd(cmdr, cmd->cmdarg, status,
359 "XFER DTIP never unset, ignoring");
360 }
361 }
362
Gregory CLEMENT31f8a002015-11-05 20:58:30 +0100363 /*
364 * After the switch command, wait for 8 clocks before the next
365 * command
366 */
367 if (cmd->cmdidx == MMC_CMD_SWITCH)
368 udelay(8*1000000 / priv->curr_clk); /* 8 clk in us */
369
Reinhard Meyerc718a562010-08-13 10:31:06 +0200370 return 0;
371}
372
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800373#ifdef CONFIG_DM_MMC
374static int atmel_mci_set_ios(struct udevice *dev)
375{
Simon Glassfa20e932020-12-03 16:55:20 -0700376 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800377 struct mmc *mmc = mmc_get_mmc_dev(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800378 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800379#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200380/* Entered into mmc structure during driver init */
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900381static int mci_set_ios(struct mmc *mmc)
Reinhard Meyerc718a562010-08-13 10:31:06 +0200382{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200383 struct atmel_mci_priv *priv = mmc->priv;
384 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800385#endif
Bo Shen644b4762013-04-26 00:27:06 +0000386 int bus_width = mmc->bus_width;
387 unsigned int version = atmel_mci_get_version(mci);
388 int busw;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200389
390 /* Set the clock speed */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800391#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800392 mci_set_mode(dev, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800393#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200394 mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800395#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200396
397 /*
398 * set the bus width and select slot for this interface
399 * there is no capability for multiple slots on the same interface yet
Reinhard Meyerc718a562010-08-13 10:31:06 +0200400 */
Bo Shen644b4762013-04-26 00:27:06 +0000401 if ((version & 0xf00) >= 0x300) {
402 switch (bus_width) {
403 case 8:
404 busw = 3;
405 break;
406 case 4:
407 busw = 2;
408 break;
409 default:
410 busw = 0;
411 break;
412 }
413
414 writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
415 } else {
416 busw = (bus_width == 4) ? 1 : 0;
417
418 writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
419 }
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900420
421 return 0;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200422}
423
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800424#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800425static int atmel_mci_hw_init(struct udevice *dev)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800426{
Simon Glassfa20e932020-12-03 16:55:20 -0700427 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800428 atmel_mci_t *mci = plat->mci;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800429#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200430/* Entered into mmc structure during driver init */
431static int mci_init(struct mmc *mmc)
432{
Marek Vasut903fc1d2015-10-23 20:46:30 +0200433 struct atmel_mci_priv *priv = mmc->priv;
434 atmel_mci_t *mci = priv->mci;
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800435#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200436
437 /* Initialize controller */
438 writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */
439 writel(MMCI_BIT(PWSDIS), &mci->cr); /* disable power save */
440 writel(MMCI_BIT(MCIEN), &mci->cr); /* enable mci */
Reinhard Meyerf2675572010-11-16 09:24:41 +0100441 writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr); /* select port */
Reinhard Meyerc718a562010-08-13 10:31:06 +0200442
Wu, Joshec35c912012-09-13 22:22:06 +0000443 /* This delay can be optimized, but stick with max value */
444 writel(0x7f, &mci->dtor);
Reinhard Meyerc718a562010-08-13 10:31:06 +0200445 /* Disable Interrupts */
446 writel(~0UL, &mci->idr);
447
448 /* Set default clocks and blocklen */
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800449#ifdef CONFIG_DM_MMC
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800450 mci_set_mode(dev, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800451#else
Reinhard Meyerc718a562010-08-13 10:31:06 +0200452 mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800453#endif
Reinhard Meyerc718a562010-08-13 10:31:06 +0200454
455 return 0;
456}
457
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800458#ifndef CONFIG_DM_MMC
Pantelis Antoniouc9e75912014-02-26 19:28:45 +0200459static const struct mmc_ops atmel_mci_ops = {
460 .send_cmd = mci_send_cmd,
461 .set_ios = mci_set_ios,
462 .init = mci_init,
463};
464
Reinhard Meyerc718a562010-08-13 10:31:06 +0200465/*
466 * This is the only exported function
467 *
468 * Call it with the MCI register base address
469 */
470int atmel_mci_init(void *regs)
471{
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200472 struct mmc *mmc;
473 struct mmc_config *cfg;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200474 struct atmel_mci_priv *priv;
Bo Shen644b4762013-04-26 00:27:06 +0000475 unsigned int version;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200476
Marek Vasut903fc1d2015-10-23 20:46:30 +0200477 priv = calloc(1, sizeof(*priv));
478 if (!priv)
479 return -ENOMEM;
Bo Shen644b4762013-04-26 00:27:06 +0000480
Marek Vasut903fc1d2015-10-23 20:46:30 +0200481 cfg = &priv->cfg;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200482
483 cfg->name = "mci";
484 cfg->ops = &atmel_mci_ops;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200485
Marek Vasut903fc1d2015-10-23 20:46:30 +0200486 priv->mci = (struct atmel_mci *)regs;
Marek Vasut0b7d54e2015-10-23 20:46:31 +0200487 priv->initialized = 0;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200488
Reinhard Meyerc718a562010-08-13 10:31:06 +0200489 /* need to be able to pass these in on a board by board basis */
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200490 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
Marek Vasut903fc1d2015-10-23 20:46:30 +0200491 version = atmel_mci_get_version(priv->mci);
Bo Shen1dc856d2014-07-31 14:39:32 +0800492 if ((version & 0xf00) >= 0x300) {
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200493 cfg->host_caps = MMC_MODE_8BIT;
Bo Shen1dc856d2014-07-31 14:39:32 +0800494 cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
495 }
Bo Shen644b4762013-04-26 00:27:06 +0000496
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200497 cfg->host_caps |= MMC_MODE_4BIT;
Bo Shen644b4762013-04-26 00:27:06 +0000498
Reinhard Meyerc718a562010-08-13 10:31:06 +0200499 /*
500 * min and max frequencies determined by
501 * max and min of clock divider
502 */
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200503 cfg->f_min = get_mci_clk_rate() / (2*256);
504 cfg->f_max = get_mci_clk_rate() / (2*1);
505
506 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
Reinhard Meyerc718a562010-08-13 10:31:06 +0200507
Marek Vasut903fc1d2015-10-23 20:46:30 +0200508 mmc = mmc_create(cfg, priv);
John Rigbyf2f43662011-04-18 05:50:08 +0000509
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200510 if (mmc == NULL) {
Marek Vasut903fc1d2015-10-23 20:46:30 +0200511 free(priv);
512 return -ENODEV;
Pantelis Antoniou2c850462014-03-11 19:34:20 +0200513 }
Marek Vasut903fc1d2015-10-23 20:46:30 +0200514 /* NOTE: possibly leaking the priv structure */
Reinhard Meyerc718a562010-08-13 10:31:06 +0200515
516 return 0;
517}
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800518#endif
519
520#ifdef CONFIG_DM_MMC
521static const struct dm_mmc_ops atmel_mci_mmc_ops = {
522 .send_cmd = atmel_mci_send_cmd,
523 .set_ios = atmel_mci_set_ios,
524};
525
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800526static void atmel_mci_setup_cfg(struct udevice *dev)
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800527{
Simon Glassfa20e932020-12-03 16:55:20 -0700528 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800529 struct atmel_mci_priv *priv = dev_get_priv(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800530 struct mmc_config *cfg;
531 u32 version;
532
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800533 cfg = &plat->cfg;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800534 cfg->name = "Atmel mci";
535 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
536
537 /*
538 * If the version is above 3.0, the capabilities of the 8-bit
539 * bus width and high speed are supported.
540 */
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800541 version = atmel_mci_get_version(plat->mci);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800542 if ((version & 0xf00) >= 0x300) {
543 cfg->host_caps = MMC_MODE_8BIT |
544 MMC_MODE_HS | MMC_MODE_HS_52MHz;
545 }
546
547 cfg->host_caps |= MMC_MODE_4BIT;
548 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
549 cfg->f_min = priv->bus_clk_rate / (2 * 256);
550 cfg->f_max = priv->bus_clk_rate / 2;
551}
552
553static int atmel_mci_enable_clk(struct udevice *dev)
554{
555 struct atmel_mci_priv *priv = dev_get_priv(dev);
556 struct clk clk;
557 ulong clk_rate;
558 int ret = 0;
559
560 ret = clk_get_by_index(dev, 0, &clk);
561 if (ret) {
562 ret = -EINVAL;
563 goto failed;
564 }
565
566 ret = clk_enable(&clk);
567 if (ret)
568 goto failed;
569
570 clk_rate = clk_get_rate(&clk);
571 if (!clk_rate) {
572 ret = -EINVAL;
573 goto failed;
574 }
575
576 priv->bus_clk_rate = clk_rate;
577
578failed:
579 clk_free(&clk);
580
581 return ret;
582}
583
584static int atmel_mci_probe(struct udevice *dev)
585{
586 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700587 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800588 struct mmc *mmc;
589 int ret;
590
591 ret = atmel_mci_enable_clk(dev);
592 if (ret)
593 return ret;
594
Masahiro Yamada32822d02020-08-04 14:14:43 +0900595 plat->mci = dev_read_addr_ptr(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800596
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800597 atmel_mci_setup_cfg(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800598
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800599 mmc = &plat->mmc;
600 mmc->cfg = &plat->cfg;
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800601 mmc->dev = dev;
602 upriv->mmc = mmc;
603
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800604 atmel_mci_hw_init(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800605
606 return 0;
607}
608
609static int atmel_mci_bind(struct udevice *dev)
610{
Simon Glassfa20e932020-12-03 16:55:20 -0700611 struct atmel_mci_plat *plat = dev_get_plat(dev);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800612
Wenyou.Yang@microchip.comedc1dff2017-07-26 14:35:42 +0800613 return mmc_bind(dev, &plat->mmc, &plat->cfg);
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800614}
615
616static const struct udevice_id atmel_mci_ids[] = {
617 { .compatible = "atmel,hsmci" },
618 { }
619};
620
621U_BOOT_DRIVER(atmel_mci) = {
622 .name = "atmel-mci",
623 .id = UCLASS_MMC,
624 .of_match = atmel_mci_ids,
625 .bind = atmel_mci_bind,
626 .probe = atmel_mci_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700627 .plat_auto = sizeof(struct atmel_mci_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700628 .priv_auto = sizeof(struct atmel_mci_priv),
Wenyou Yang7a7a64c2017-04-13 10:29:22 +0800629 .ops = &atmel_mci_mmc_ops,
630};
631#endif