blob: 2988e9df85e3ecec13b72889b8041b5dc04a672b [file] [log] [blame]
Pete Popovba264b32005-09-21 06:18:27 +00001/*
Pierre Ossman70f10482007-07-11 20:04:50 +02002 * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
Pete Popovba264b32005-09-21 06:18:27 +00003 *
4 * Copyright (c) 2005, Advanced Micro Devices, Inc.
5 *
6 * Developed with help from the 2.4.30 MMC AU1XXX controller including
7 * the following copyright notices:
8 * Copyright (c) 2003-2004 Embedded Edge, LLC.
9 * Portions Copyright (C) 2002 Embedix, Inc
10 * Copyright 2002 Hewlett-Packard Company
11
12 * 2.6 version of this driver inspired by:
13 * (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
14 * All Rights Reserved.
15 * (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
16 * All Rights Reserved.
17 *
18
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License version 2 as
21 * published by the Free Software Foundation.
22 */
23
Manuel Lausse2d26472008-06-27 18:25:18 +020024/* Why don't we use the SD controllers' carddetect feature?
Pete Popovba264b32005-09-21 06:18:27 +000025 *
26 * From the AU1100 MMC application guide:
27 * If the Au1100-based design is intended to support both MultiMediaCards
28 * and 1- or 4-data bit SecureDigital cards, then the solution is to
29 * connect a weak (560KOhm) pull-up resistor to connector pin 1.
30 * In doing so, a MMC card never enters SPI-mode communications,
31 * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
32 * (the low to high transition will not occur).
Pete Popovba264b32005-09-21 06:18:27 +000033 */
34
Pete Popovba264b32005-09-21 06:18:27 +000035#include <linux/module.h>
36#include <linux/init.h>
Martin Michlmayrb256f9d2006-03-04 23:01:13 +000037#include <linux/platform_device.h>
Pete Popovba264b32005-09-21 06:18:27 +000038#include <linux/mm.h>
39#include <linux/interrupt.h>
40#include <linux/dma-mapping.h>
Al Viro0ada7a02007-10-27 19:40:46 +010041#include <linux/scatterlist.h>
Manuel Laussc4223c22008-06-09 08:36:13 +020042#include <linux/leds.h>
Pete Popovba264b32005-09-21 06:18:27 +000043#include <linux/mmc/host.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090044#include <linux/slab.h>
Manuel Laussc4223c22008-06-09 08:36:13 +020045
Pete Popovba264b32005-09-21 06:18:27 +000046#include <asm/io.h>
47#include <asm/mach-au1x00/au1000.h>
48#include <asm/mach-au1x00/au1xxx_dbdma.h>
49#include <asm/mach-au1x00/au1100_mmc.h>
Pete Popovba264b32005-09-21 06:18:27 +000050
Pete Popovba264b32005-09-21 06:18:27 +000051#define DRIVER_NAME "au1xxx-mmc"
52
53/* Set this to enable special debugging macros */
Manuel Laussc4223c22008-06-09 08:36:13 +020054/* #define DEBUG */
Pete Popovba264b32005-09-21 06:18:27 +000055
Russell Kingc6563172006-03-29 09:30:20 +010056#ifdef DEBUG
Manuel Lauss5c0a8892008-06-09 08:38:35 +020057#define DBG(fmt, idx, args...) \
Girish K Sa3c76eb2011-10-11 11:44:09 +053058 pr_debug("au1xmmc(%d): DEBUG: " fmt, idx, ##args)
Pete Popovba264b32005-09-21 06:18:27 +000059#else
Manuel Lauss5c0a8892008-06-09 08:38:35 +020060#define DBG(fmt, idx, args...) do {} while (0)
Pete Popovba264b32005-09-21 06:18:27 +000061#endif
62
Manuel Lauss5c0a8892008-06-09 08:38:35 +020063/* Hardware definitions */
64#define AU1XMMC_DESCRIPTOR_COUNT 1
Manuel Lausse491d232008-07-29 10:10:49 +020065
66/* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */
Manuel Lauss1177d992011-08-02 19:51:07 +020067#define AU1100_MMC_DESCRIPTOR_SIZE 0x0000ffff
68#define AU1200_MMC_DESCRIPTOR_SIZE 0x003fffff
Manuel Lauss5c0a8892008-06-09 08:38:35 +020069
70#define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \
71 MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
72 MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
73
74/* This gives us a hard value for the stop command that we can write directly
75 * to the command register.
76 */
77#define STOP_CMD \
78 (SD_CMD_RT_1B | SD_CMD_CT_7 | (0xC << SD_CMD_CI_SHIFT) | SD_CMD_GO)
79
80/* This is the set of interrupts that we configure by default. */
81#define AU1XMMC_INTERRUPTS \
82 (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_RAT | \
83 SD_CONFIG_CR | SD_CONFIG_I)
84
85/* The poll event (looking for insert/remove events runs twice a second. */
86#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
87
88struct au1xmmc_host {
89 struct mmc_host *mmc;
90 struct mmc_request *mrq;
91
92 u32 flags;
Manuel Lauss2f73bfb2014-07-23 16:36:26 +020093 void __iomem *iobase;
Manuel Lauss5c0a8892008-06-09 08:38:35 +020094 u32 clock;
95 u32 bus_width;
96 u32 power_mode;
97
98 int status;
99
100 struct {
101 int len;
102 int dir;
103 } dma;
104
105 struct {
106 int index;
107 int offset;
108 int len;
109 } pio;
110
111 u32 tx_chan;
112 u32 rx_chan;
113
114 int irq;
115
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200116 struct tasklet_struct finish_task;
117 struct tasklet_struct data_task;
118 struct au1xmmc_platform_data *platdata;
119 struct platform_device *pdev;
120 struct resource *ioarea;
121};
122
123/* Status flags used by the host structure */
124#define HOST_F_XMIT 0x0001
125#define HOST_F_RECV 0x0002
126#define HOST_F_DMA 0x0010
Manuel Lauss1177d992011-08-02 19:51:07 +0200127#define HOST_F_DBDMA 0x0020
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200128#define HOST_F_ACTIVE 0x0100
129#define HOST_F_STOP 0x1000
130
131#define HOST_S_IDLE 0x0001
132#define HOST_S_CMD 0x0002
133#define HOST_S_DATA 0x0003
134#define HOST_S_STOP 0x0004
135
136/* Easy access macros */
137#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
138#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
139#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
140#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
141#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
142#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
143#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE)
144#define HOST_CMD(h) ((h)->iobase + SD_CMD)
145#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2)
146#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT)
147#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG)
148
149#define DMA_CHANNEL(h) \
150 (((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
151
Manuel Lauss1177d992011-08-02 19:51:07 +0200152static inline int has_dbdma(void)
153{
154 switch (alchemy_get_cputype()) {
155 case ALCHEMY_CPU_AU1200:
Manuel Lauss809f36c2011-11-01 20:03:30 +0100156 case ALCHEMY_CPU_AU1300:
Manuel Lauss1177d992011-08-02 19:51:07 +0200157 return 1;
158 default:
159 return 0;
160 }
161}
162
Pete Popovba264b32005-09-21 06:18:27 +0000163static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
164{
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200165 u32 val = __raw_readl(HOST_CONFIG(host));
Pete Popovba264b32005-09-21 06:18:27 +0000166 val |= mask;
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200167 __raw_writel(val, HOST_CONFIG(host));
168 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000169}
170
171static inline void FLUSH_FIFO(struct au1xmmc_host *host)
172{
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200173 u32 val = __raw_readl(HOST_CONFIG2(host));
Pete Popovba264b32005-09-21 06:18:27 +0000174
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200175 __raw_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
176 wmb(); /* drain writebuffer */
177 mdelay(1);
Pete Popovba264b32005-09-21 06:18:27 +0000178
179 /* SEND_STOP will turn off clock control - this re-enables it */
180 val &= ~SD_CONFIG2_DF;
181
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200182 __raw_writel(val, HOST_CONFIG2(host));
183 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000184}
185
186static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
187{
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200188 u32 val = __raw_readl(HOST_CONFIG(host));
Pete Popovba264b32005-09-21 06:18:27 +0000189 val &= ~mask;
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200190 __raw_writel(val, HOST_CONFIG(host));
191 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000192}
193
194static inline void SEND_STOP(struct au1xmmc_host *host)
195{
Manuel Lauss281dd232008-06-09 08:37:33 +0200196 u32 config2;
Pete Popovba264b32005-09-21 06:18:27 +0000197
198 WARN_ON(host->status != HOST_S_DATA);
199 host->status = HOST_S_STOP;
200
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200201 config2 = __raw_readl(HOST_CONFIG2(host));
202 __raw_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host));
203 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000204
Uwe Kleine-Königb5950762010-11-01 15:38:34 -0400205 /* Send the stop command */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200206 __raw_writel(STOP_CMD, HOST_CMD(host));
207 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000208}
209
210static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
211{
Manuel Laussc4223c22008-06-09 08:36:13 +0200212 if (host->platdata && host->platdata->set_power)
213 host->platdata->set_power(host->mmc, state);
Pete Popovba264b32005-09-21 06:18:27 +0000214}
215
Manuel Lausse2d26472008-06-27 18:25:18 +0200216static int au1xmmc_card_inserted(struct mmc_host *mmc)
Pete Popovba264b32005-09-21 06:18:27 +0000217{
Manuel Lausse2d26472008-06-27 18:25:18 +0200218 struct au1xmmc_host *host = mmc_priv(mmc);
Manuel Laussc4223c22008-06-09 08:36:13 +0200219
220 if (host->platdata && host->platdata->card_inserted)
Manuel Lausse2d26472008-06-27 18:25:18 +0200221 return !!host->platdata->card_inserted(host->mmc);
Manuel Laussc4223c22008-06-09 08:36:13 +0200222
Manuel Lausse2d26472008-06-27 18:25:18 +0200223 return -ENOSYS;
Pete Popovba264b32005-09-21 06:18:27 +0000224}
225
Manuel Lauss82999772007-01-25 10:29:24 +0100226static int au1xmmc_card_readonly(struct mmc_host *mmc)
Pete Popovba264b32005-09-21 06:18:27 +0000227{
Manuel Lauss82999772007-01-25 10:29:24 +0100228 struct au1xmmc_host *host = mmc_priv(mmc);
Manuel Laussc4223c22008-06-09 08:36:13 +0200229
230 if (host->platdata && host->platdata->card_readonly)
Manuel Lausse2d26472008-06-27 18:25:18 +0200231 return !!host->platdata->card_readonly(mmc);
Manuel Laussc4223c22008-06-09 08:36:13 +0200232
Manuel Lausse2d26472008-06-27 18:25:18 +0200233 return -ENOSYS;
Pete Popovba264b32005-09-21 06:18:27 +0000234}
235
236static void au1xmmc_finish_request(struct au1xmmc_host *host)
237{
Pete Popovba264b32005-09-21 06:18:27 +0000238 struct mmc_request *mrq = host->mrq;
239
240 host->mrq = NULL;
Manuel Laussc4223c22008-06-09 08:36:13 +0200241 host->flags &= HOST_F_ACTIVE | HOST_F_DMA;
Pete Popovba264b32005-09-21 06:18:27 +0000242
243 host->dma.len = 0;
244 host->dma.dir = 0;
245
246 host->pio.index = 0;
247 host->pio.offset = 0;
248 host->pio.len = 0;
249
250 host->status = HOST_S_IDLE;
251
Pete Popovba264b32005-09-21 06:18:27 +0000252 mmc_request_done(host->mmc, mrq);
253}
254
255static void au1xmmc_tasklet_finish(unsigned long param)
256{
257 struct au1xmmc_host *host = (struct au1xmmc_host *) param;
258 au1xmmc_finish_request(host);
259}
260
261static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200262 struct mmc_command *cmd, struct mmc_data *data)
Pete Popovba264b32005-09-21 06:18:27 +0000263{
Pete Popovba264b32005-09-21 06:18:27 +0000264 u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
265
Martin Michlmayre142c242006-03-04 23:01:39 +0000266 switch (mmc_resp_type(cmd)) {
Manuel Lauss279bc442007-01-25 10:27:41 +0100267 case MMC_RSP_NONE:
268 break;
Pete Popovba264b32005-09-21 06:18:27 +0000269 case MMC_RSP_R1:
270 mmccmd |= SD_CMD_RT_1;
271 break;
272 case MMC_RSP_R1B:
273 mmccmd |= SD_CMD_RT_1B;
274 break;
275 case MMC_RSP_R2:
276 mmccmd |= SD_CMD_RT_2;
277 break;
278 case MMC_RSP_R3:
279 mmccmd |= SD_CMD_RT_3;
280 break;
Manuel Lauss279bc442007-01-25 10:27:41 +0100281 default:
Girish K Sa3c76eb2011-10-11 11:44:09 +0530282 pr_info("au1xmmc: unhandled response type %02x\n",
Manuel Lauss279bc442007-01-25 10:27:41 +0100283 mmc_resp_type(cmd));
Pierre Ossman17b04292007-07-22 22:18:46 +0200284 return -EINVAL;
Pete Popovba264b32005-09-21 06:18:27 +0000285 }
286
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200287 if (data) {
Pierre Ossman6356a9d2007-10-22 18:16:16 +0200288 if (data->flags & MMC_DATA_READ) {
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200289 if (data->blocks > 1)
290 mmccmd |= SD_CMD_CT_4;
291 else
292 mmccmd |= SD_CMD_CT_2;
Pierre Ossman6356a9d2007-10-22 18:16:16 +0200293 } else if (data->flags & MMC_DATA_WRITE) {
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200294 if (data->blocks > 1)
295 mmccmd |= SD_CMD_CT_3;
296 else
297 mmccmd |= SD_CMD_CT_1;
298 }
Pete Popovba264b32005-09-21 06:18:27 +0000299 }
300
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200301 __raw_writel(cmd->arg, HOST_CMDARG(host));
302 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000303
304 if (wait)
305 IRQ_OFF(host, SD_CONFIG_CR);
306
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200307 __raw_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
308 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000309
310 /* Wait for the command to go on the line */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200311 while (__raw_readl(HOST_CMD(host)) & SD_CMD_GO)
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200312 /* nop */;
Pete Popovba264b32005-09-21 06:18:27 +0000313
314 /* Wait for the command to come back */
Pete Popovba264b32005-09-21 06:18:27 +0000315 if (wait) {
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200316 u32 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000317
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200318 while (!(status & SD_STATUS_CR))
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200319 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000320
321 /* Clear the CR status */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200322 __raw_writel(SD_STATUS_CR, HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000323
324 IRQ_ON(host, SD_CONFIG_CR);
325 }
326
Pierre Ossman17b04292007-07-22 22:18:46 +0200327 return 0;
Pete Popovba264b32005-09-21 06:18:27 +0000328}
329
330static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
331{
Pete Popovba264b32005-09-21 06:18:27 +0000332 struct mmc_request *mrq = host->mrq;
333 struct mmc_data *data;
334 u32 crc;
335
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200336 WARN_ON((host->status != HOST_S_DATA) && (host->status != HOST_S_STOP));
Pete Popovba264b32005-09-21 06:18:27 +0000337
338 if (host->mrq == NULL)
339 return;
340
341 data = mrq->cmd->data;
342
343 if (status == 0)
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200344 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000345
346 /* The transaction is really over when the SD_STATUS_DB bit is clear */
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200347 while ((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200348 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000349
Pierre Ossman17b04292007-07-22 22:18:46 +0200350 data->error = 0;
Pete Popovba264b32005-09-21 06:18:27 +0000351 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
352
353 /* Process any errors */
Pete Popovba264b32005-09-21 06:18:27 +0000354 crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
355 if (host->flags & HOST_F_XMIT)
356 crc |= ((status & 0x07) == 0x02) ? 0 : 1;
357
358 if (crc)
Pierre Ossman17b04292007-07-22 22:18:46 +0200359 data->error = -EILSEQ;
Pete Popovba264b32005-09-21 06:18:27 +0000360
361 /* Clear the CRC bits */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200362 __raw_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000363
364 data->bytes_xfered = 0;
365
Pierre Ossman17b04292007-07-22 22:18:46 +0200366 if (!data->error) {
Manuel Lauss1177d992011-08-02 19:51:07 +0200367 if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) {
Pete Popovba264b32005-09-21 06:18:27 +0000368 u32 chan = DMA_CHANNEL(host);
369
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200370 chan_tab_t *c = *((chan_tab_t **)chan);
Pete Popovba264b32005-09-21 06:18:27 +0000371 au1x_dma_chan_t *cp = c->chan_ptr;
372 data->bytes_xfered = cp->ddma_bytecnt;
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200373 } else
Pete Popovba264b32005-09-21 06:18:27 +0000374 data->bytes_xfered =
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200375 (data->blocks * data->blksz) - host->pio.len;
Pete Popovba264b32005-09-21 06:18:27 +0000376 }
377
378 au1xmmc_finish_request(host);
379}
380
381static void au1xmmc_tasklet_data(unsigned long param)
382{
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200383 struct au1xmmc_host *host = (struct au1xmmc_host *)param;
Pete Popovba264b32005-09-21 06:18:27 +0000384
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200385 u32 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000386 au1xmmc_data_complete(host, status);
387}
388
389#define AU1XMMC_MAX_TRANSFER 8
390
391static void au1xmmc_send_pio(struct au1xmmc_host *host)
392{
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200393 struct mmc_data *data;
394 int sg_len, max, count;
395 unsigned char *sg_ptr, val;
396 u32 status;
Pete Popovba264b32005-09-21 06:18:27 +0000397 struct scatterlist *sg;
398
399 data = host->mrq->data;
400
401 if (!(host->flags & HOST_F_XMIT))
402 return;
403
404 /* This is the pointer to the data buffer */
405 sg = &data->sg[host->pio.index];
Jens Axboe45711f12007-10-22 21:19:53 +0200406 sg_ptr = sg_virt(sg) + host->pio.offset;
Pete Popovba264b32005-09-21 06:18:27 +0000407
408 /* This is the space left inside the buffer */
409 sg_len = data->sg[host->pio.index].length - host->pio.offset;
410
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200411 /* Check if we need less than the size of the sg_buffer */
Pete Popovba264b32005-09-21 06:18:27 +0000412 max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200413 if (max > AU1XMMC_MAX_TRANSFER)
414 max = AU1XMMC_MAX_TRANSFER;
Pete Popovba264b32005-09-21 06:18:27 +0000415
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200416 for (count = 0; count < max; count++) {
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200417 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000418
419 if (!(status & SD_STATUS_TH))
420 break;
421
422 val = *sg_ptr++;
423
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200424 __raw_writel((unsigned long)val, HOST_TXPORT(host));
425 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000426 }
427
428 host->pio.len -= count;
429 host->pio.offset += count;
430
431 if (count == sg_len) {
432 host->pio.index++;
433 host->pio.offset = 0;
434 }
435
436 if (host->pio.len == 0) {
437 IRQ_OFF(host, SD_CONFIG_TH);
438
439 if (host->flags & HOST_F_STOP)
440 SEND_STOP(host);
441
442 tasklet_schedule(&host->data_task);
443 }
444}
445
446static void au1xmmc_receive_pio(struct au1xmmc_host *host)
447{
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200448 struct mmc_data *data;
449 int max, count, sg_len = 0;
450 unsigned char *sg_ptr = NULL;
451 u32 status, val;
Pete Popovba264b32005-09-21 06:18:27 +0000452 struct scatterlist *sg;
453
454 data = host->mrq->data;
455
456 if (!(host->flags & HOST_F_RECV))
457 return;
458
459 max = host->pio.len;
460
461 if (host->pio.index < host->dma.len) {
462 sg = &data->sg[host->pio.index];
Jens Axboe45711f12007-10-22 21:19:53 +0200463 sg_ptr = sg_virt(sg) + host->pio.offset;
Pete Popovba264b32005-09-21 06:18:27 +0000464
465 /* This is the space left inside the buffer */
466 sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
467
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200468 /* Check if we need less than the size of the sg_buffer */
469 if (sg_len < max)
470 max = sg_len;
Pete Popovba264b32005-09-21 06:18:27 +0000471 }
472
473 if (max > AU1XMMC_MAX_TRANSFER)
474 max = AU1XMMC_MAX_TRANSFER;
475
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200476 for (count = 0; count < max; count++) {
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200477 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000478
479 if (!(status & SD_STATUS_NE))
480 break;
481
482 if (status & SD_STATUS_RC) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200483 DBG("RX CRC Error [%d + %d].\n", host->pdev->id,
Pete Popovba264b32005-09-21 06:18:27 +0000484 host->pio.len, count);
485 break;
486 }
487
488 if (status & SD_STATUS_RO) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200489 DBG("RX Overrun [%d + %d]\n", host->pdev->id,
Pete Popovba264b32005-09-21 06:18:27 +0000490 host->pio.len, count);
491 break;
492 }
493 else if (status & SD_STATUS_RU) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200494 DBG("RX Underrun [%d + %d]\n", host->pdev->id,
Pete Popovba264b32005-09-21 06:18:27 +0000495 host->pio.len, count);
496 break;
497 }
498
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200499 val = __raw_readl(HOST_RXPORT(host));
Pete Popovba264b32005-09-21 06:18:27 +0000500
501 if (sg_ptr)
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200502 *sg_ptr++ = (unsigned char)(val & 0xFF);
Pete Popovba264b32005-09-21 06:18:27 +0000503 }
504
505 host->pio.len -= count;
506 host->pio.offset += count;
507
508 if (sg_len && count == sg_len) {
509 host->pio.index++;
510 host->pio.offset = 0;
511 }
512
513 if (host->pio.len == 0) {
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200514 /* IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); */
Pete Popovba264b32005-09-21 06:18:27 +0000515 IRQ_OFF(host, SD_CONFIG_NE);
516
517 if (host->flags & HOST_F_STOP)
518 SEND_STOP(host);
519
520 tasklet_schedule(&host->data_task);
521 }
522}
523
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200524/* This is called when a command has been completed - grab the response
525 * and check for errors. Then start the data transfer if it is indicated.
526 */
Pete Popovba264b32005-09-21 06:18:27 +0000527static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
528{
Pete Popovba264b32005-09-21 06:18:27 +0000529 struct mmc_request *mrq = host->mrq;
530 struct mmc_command *cmd;
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200531 u32 r[4];
532 int i, trans;
Pete Popovba264b32005-09-21 06:18:27 +0000533
534 if (!host->mrq)
535 return;
536
537 cmd = mrq->cmd;
Pierre Ossman17b04292007-07-22 22:18:46 +0200538 cmd->error = 0;
Pete Popovba264b32005-09-21 06:18:27 +0000539
Russell Kinge9225172006-02-02 12:23:12 +0000540 if (cmd->flags & MMC_RSP_PRESENT) {
541 if (cmd->flags & MMC_RSP_136) {
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200542 r[0] = __raw_readl(host->iobase + SD_RESP3);
543 r[1] = __raw_readl(host->iobase + SD_RESP2);
544 r[2] = __raw_readl(host->iobase + SD_RESP1);
545 r[3] = __raw_readl(host->iobase + SD_RESP0);
Pete Popovba264b32005-09-21 06:18:27 +0000546
Russell Kinge9225172006-02-02 12:23:12 +0000547 /* The CRC is omitted from the response, so really
548 * we only got 120 bytes, but the engine expects
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200549 * 128 bits, so we have to shift things up.
Russell Kinge9225172006-02-02 12:23:12 +0000550 */
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200551 for (i = 0; i < 4; i++) {
Russell Kinge9225172006-02-02 12:23:12 +0000552 cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
553 if (i != 3)
554 cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
555 }
556 } else {
557 /* Techincally, we should be getting all 48 bits of
558 * the response (SD_RESP1 + SD_RESP2), but because
559 * our response omits the CRC, our data ends up
560 * being shifted 8 bits to the right. In this case,
561 * that means that the OSR data starts at bit 31,
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200562 * so we can just read RESP0 and return that.
Russell Kinge9225172006-02-02 12:23:12 +0000563 */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200564 cmd->resp[0] = __raw_readl(host->iobase + SD_RESP0);
Pete Popovba264b32005-09-21 06:18:27 +0000565 }
566 }
567
568 /* Figure out errors */
Pete Popovba264b32005-09-21 06:18:27 +0000569 if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
Pierre Ossman17b04292007-07-22 22:18:46 +0200570 cmd->error = -EILSEQ;
Pete Popovba264b32005-09-21 06:18:27 +0000571
572 trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
573
Pierre Ossman17b04292007-07-22 22:18:46 +0200574 if (!trans || cmd->error) {
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200575 IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF);
Pete Popovba264b32005-09-21 06:18:27 +0000576 tasklet_schedule(&host->finish_task);
577 return;
578 }
579
580 host->status = HOST_S_DATA;
581
Manuel Lauss1177d992011-08-02 19:51:07 +0200582 if ((host->flags & (HOST_F_DMA | HOST_F_DBDMA))) {
Pete Popovba264b32005-09-21 06:18:27 +0000583 u32 channel = DMA_CHANNEL(host);
584
Manuel Lauss1177d992011-08-02 19:51:07 +0200585 /* Start the DBDMA as soon as the buffer gets something in it */
Pete Popovba264b32005-09-21 06:18:27 +0000586
587 if (host->flags & HOST_F_RECV) {
588 u32 mask = SD_STATUS_DB | SD_STATUS_NE;
589
590 while((status & mask) != mask)
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200591 status = __raw_readl(HOST_STATUS(host));
Pete Popovba264b32005-09-21 06:18:27 +0000592 }
593
594 au1xxx_dbdma_start(channel);
595 }
596}
597
598static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
599{
Pete Popovba264b32005-09-21 06:18:27 +0000600 unsigned int pbus = get_au1x00_speed();
601 unsigned int divisor;
602 u32 config;
603
604 /* From databook:
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200605 * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
606 */
Manuel Lauss1d09de72014-07-23 16:36:24 +0200607 pbus /= ((alchemy_rdsys(AU1000_SYS_POWERCTRL) & 0x3) + 2);
Pete Popovba264b32005-09-21 06:18:27 +0000608 pbus /= 2;
Pete Popovba264b32005-09-21 06:18:27 +0000609 divisor = ((pbus / rate) / 2) - 1;
610
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200611 config = __raw_readl(HOST_CONFIG(host));
Pete Popovba264b32005-09-21 06:18:27 +0000612
613 config &= ~(SD_CONFIG_DIV);
614 config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
615
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200616 __raw_writel(config, HOST_CONFIG(host));
617 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000618}
619
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200620static int au1xmmc_prepare_data(struct au1xmmc_host *host,
621 struct mmc_data *data)
Pete Popovba264b32005-09-21 06:18:27 +0000622{
Pavel Pisa2c171bf2006-05-19 21:48:03 +0100623 int datalen = data->blocks * data->blksz;
Pete Popovba264b32005-09-21 06:18:27 +0000624
Pete Popovba264b32005-09-21 06:18:27 +0000625 if (data->flags & MMC_DATA_READ)
626 host->flags |= HOST_F_RECV;
627 else
628 host->flags |= HOST_F_XMIT;
629
630 if (host->mrq->stop)
631 host->flags |= HOST_F_STOP;
632
633 host->dma.dir = DMA_BIDIRECTIONAL;
634
635 host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
636 data->sg_len, host->dma.dir);
637
638 if (host->dma.len == 0)
Pierre Ossman17b04292007-07-22 22:18:46 +0200639 return -ETIMEDOUT;
Pete Popovba264b32005-09-21 06:18:27 +0000640
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200641 __raw_writel(data->blksz - 1, HOST_BLKSIZE(host));
Pete Popovba264b32005-09-21 06:18:27 +0000642
Manuel Lauss1177d992011-08-02 19:51:07 +0200643 if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) {
Pete Popovba264b32005-09-21 06:18:27 +0000644 int i;
645 u32 channel = DMA_CHANNEL(host);
646
647 au1xxx_dbdma_stop(channel);
648
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200649 for (i = 0; i < host->dma.len; i++) {
Pete Popovba264b32005-09-21 06:18:27 +0000650 u32 ret = 0, flags = DDMA_FLAGS_NOIE;
651 struct scatterlist *sg = &data->sg[i];
652 int sg_len = sg->length;
653
654 int len = (datalen > sg_len) ? sg_len : datalen;
655
656 if (i == host->dma.len - 1)
657 flags = DDMA_FLAGS_IE;
658
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200659 if (host->flags & HOST_F_XMIT) {
Manuel Laussea071cc2009-10-13 20:22:34 +0200660 ret = au1xxx_dbdma_put_source(channel,
Manuel Lauss963accb2009-10-13 20:22:35 +0200661 sg_phys(sg), len, flags);
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200662 } else {
Manuel Laussea071cc2009-10-13 20:22:34 +0200663 ret = au1xxx_dbdma_put_dest(channel,
Manuel Lauss963accb2009-10-13 20:22:35 +0200664 sg_phys(sg), len, flags);
Pete Popovba264b32005-09-21 06:18:27 +0000665 }
666
Manuel Laussc4223c22008-06-09 08:36:13 +0200667 if (!ret)
Pete Popovba264b32005-09-21 06:18:27 +0000668 goto dataerr;
669
670 datalen -= len;
671 }
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200672 } else {
Pete Popovba264b32005-09-21 06:18:27 +0000673 host->pio.index = 0;
674 host->pio.offset = 0;
675 host->pio.len = datalen;
676
677 if (host->flags & HOST_F_XMIT)
678 IRQ_ON(host, SD_CONFIG_TH);
679 else
680 IRQ_ON(host, SD_CONFIG_NE);
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200681 /* IRQ_ON(host, SD_CONFIG_RA | SD_CONFIG_RF); */
Pete Popovba264b32005-09-21 06:18:27 +0000682 }
683
Pierre Ossman17b04292007-07-22 22:18:46 +0200684 return 0;
Pete Popovba264b32005-09-21 06:18:27 +0000685
Manuel Laussc4223c22008-06-09 08:36:13 +0200686dataerr:
687 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
688 host->dma.dir);
Pierre Ossman17b04292007-07-22 22:18:46 +0200689 return -ETIMEDOUT;
Pete Popovba264b32005-09-21 06:18:27 +0000690}
691
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200692/* This actually starts a command or data transaction */
Pete Popovba264b32005-09-21 06:18:27 +0000693static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
694{
Pete Popovba264b32005-09-21 06:18:27 +0000695 struct au1xmmc_host *host = mmc_priv(mmc);
Pierre Ossman17b04292007-07-22 22:18:46 +0200696 int ret = 0;
Pete Popovba264b32005-09-21 06:18:27 +0000697
698 WARN_ON(irqs_disabled());
699 WARN_ON(host->status != HOST_S_IDLE);
700
701 host->mrq = mrq;
702 host->status = HOST_S_CMD;
703
Manuel Lauss88b8d9a2008-06-09 08:39:11 +0200704 /* fail request immediately if no card is present */
Manuel Lausse2d26472008-06-27 18:25:18 +0200705 if (0 == au1xmmc_card_inserted(mmc)) {
Manuel Lauss88b8d9a2008-06-09 08:39:11 +0200706 mrq->cmd->error = -ENOMEDIUM;
707 au1xmmc_finish_request(host);
708 return;
709 }
710
Pete Popovba264b32005-09-21 06:18:27 +0000711 if (mrq->data) {
712 FLUSH_FIFO(host);
713 ret = au1xmmc_prepare_data(host, mrq->data);
714 }
715
Pierre Ossman17b04292007-07-22 22:18:46 +0200716 if (!ret)
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200717 ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data);
Pete Popovba264b32005-09-21 06:18:27 +0000718
Pierre Ossman17b04292007-07-22 22:18:46 +0200719 if (ret) {
Pete Popovba264b32005-09-21 06:18:27 +0000720 mrq->cmd->error = ret;
721 au1xmmc_finish_request(host);
722 }
723}
724
725static void au1xmmc_reset_controller(struct au1xmmc_host *host)
726{
Pete Popovba264b32005-09-21 06:18:27 +0000727 /* Apply the clock */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200728 __raw_writel(SD_ENABLE_CE, HOST_ENABLE(host));
729 wmb(); /* drain writebuffer */
730 mdelay(1);
Pete Popovba264b32005-09-21 06:18:27 +0000731
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200732 __raw_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
733 wmb(); /* drain writebuffer */
734 mdelay(5);
Pete Popovba264b32005-09-21 06:18:27 +0000735
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200736 __raw_writel(~0, HOST_STATUS(host));
737 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000738
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200739 __raw_writel(0, HOST_BLKSIZE(host));
740 __raw_writel(0x001fffff, HOST_TIMEOUT(host));
741 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000742
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200743 __raw_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
744 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000745
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200746 __raw_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
747 wmb(); /* drain writebuffer */
748 mdelay(1);
Pete Popovba264b32005-09-21 06:18:27 +0000749
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200750 __raw_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
751 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000752
753 /* Configure interrupts */
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200754 __raw_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
755 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000756}
757
758
Manuel Lauss5c0a8892008-06-09 08:38:35 +0200759static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
Pete Popovba264b32005-09-21 06:18:27 +0000760{
761 struct au1xmmc_host *host = mmc_priv(mmc);
Manuel Lauss281dd232008-06-09 08:37:33 +0200762 u32 config2;
Pete Popovba264b32005-09-21 06:18:27 +0000763
Pete Popovba264b32005-09-21 06:18:27 +0000764 if (ios->power_mode == MMC_POWER_OFF)
765 au1xmmc_set_power(host, 0);
766 else if (ios->power_mode == MMC_POWER_ON) {
767 au1xmmc_set_power(host, 1);
768 }
769
770 if (ios->clock && ios->clock != host->clock) {
771 au1xmmc_set_clock(host, ios->clock);
772 host->clock = ios->clock;
773 }
Manuel Lauss281dd232008-06-09 08:37:33 +0200774
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200775 config2 = __raw_readl(HOST_CONFIG2(host));
Manuel Lauss281dd232008-06-09 08:37:33 +0200776 switch (ios->bus_width) {
Manuel Lauss809f36c2011-11-01 20:03:30 +0100777 case MMC_BUS_WIDTH_8:
778 config2 |= SD_CONFIG2_BB;
779 break;
Manuel Lauss281dd232008-06-09 08:37:33 +0200780 case MMC_BUS_WIDTH_4:
Manuel Lauss809f36c2011-11-01 20:03:30 +0100781 config2 &= ~SD_CONFIG2_BB;
Manuel Lauss281dd232008-06-09 08:37:33 +0200782 config2 |= SD_CONFIG2_WB;
783 break;
784 case MMC_BUS_WIDTH_1:
Manuel Lauss809f36c2011-11-01 20:03:30 +0100785 config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB);
Manuel Lauss281dd232008-06-09 08:37:33 +0200786 break;
787 }
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200788 __raw_writel(config2, HOST_CONFIG2(host));
789 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +0000790}
791
Manuel Laussc4223c22008-06-09 08:36:13 +0200792#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
793#define STATUS_DATA_IN (SD_STATUS_NE)
794#define STATUS_DATA_OUT (SD_STATUS_TH)
795
796static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
Pete Popovba264b32005-09-21 06:18:27 +0000797{
Manuel Laussc4223c22008-06-09 08:36:13 +0200798 struct au1xmmc_host *host = dev_id;
799 u32 status;
800
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200801 status = __raw_readl(HOST_STATUS(host));
Manuel Laussc4223c22008-06-09 08:36:13 +0200802
803 if (!(status & SD_STATUS_I))
804 return IRQ_NONE; /* not ours */
805
Manuel Lauss20f522f2008-06-09 08:38:03 +0200806 if (status & SD_STATUS_SI) /* SDIO */
807 mmc_signal_sdio_irq(host->mmc);
808
Manuel Laussc4223c22008-06-09 08:36:13 +0200809 if (host->mrq && (status & STATUS_TIMEOUT)) {
810 if (status & SD_STATUS_RAT)
811 host->mrq->cmd->error = -ETIMEDOUT;
812 else if (status & SD_STATUS_DT)
813 host->mrq->data->error = -ETIMEDOUT;
814
815 /* In PIO mode, interrupts might still be enabled */
816 IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
817
818 /* IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); */
819 tasklet_schedule(&host->finish_task);
820 }
821#if 0
822 else if (status & SD_STATUS_DD) {
823 /* Sometimes we get a DD before a NE in PIO mode */
824 if (!(host->flags & HOST_F_DMA) && (status & SD_STATUS_NE))
825 au1xmmc_receive_pio(host);
826 else {
827 au1xmmc_data_complete(host, status);
828 /* tasklet_schedule(&host->data_task); */
829 }
830 }
831#endif
832 else if (status & SD_STATUS_CR) {
833 if (host->status == HOST_S_CMD)
834 au1xmmc_cmd_complete(host, status);
835
836 } else if (!(host->flags & HOST_F_DMA)) {
837 if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT))
838 au1xmmc_send_pio(host);
839 else if ((host->flags & HOST_F_RECV) && (status & STATUS_DATA_IN))
840 au1xmmc_receive_pio(host);
841
842 } else if (status & 0x203F3C70) {
843 DBG("Unhandled status %8.8x\n", host->pdev->id,
844 status);
845 }
846
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200847 __raw_writel(status, HOST_STATUS(host));
848 wmb(); /* drain writebuffer */
Manuel Laussc4223c22008-06-09 08:36:13 +0200849
850 return IRQ_HANDLED;
851}
852
Manuel Laussc4223c22008-06-09 08:36:13 +0200853/* 8bit memory DMA device */
854static dbdev_tab_t au1xmmc_mem_dbdev = {
855 .dev_id = DSCR_CMD0_ALWAYS,
856 .dev_flags = DEV_FLAGS_ANYUSE,
857 .dev_tsize = 0,
858 .dev_devwidth = 8,
859 .dev_physaddr = 0x00000000,
860 .dev_intlevel = 0,
861 .dev_intpolarity = 0,
862};
863static int memid;
864
865static void au1xmmc_dbdma_callback(int irq, void *dev_id)
866{
867 struct au1xmmc_host *host = (struct au1xmmc_host *)dev_id;
Pete Popovba264b32005-09-21 06:18:27 +0000868
869 /* Avoid spurious interrupts */
Pete Popovba264b32005-09-21 06:18:27 +0000870 if (!host->mrq)
871 return;
872
873 if (host->flags & HOST_F_STOP)
874 SEND_STOP(host);
875
876 tasklet_schedule(&host->data_task);
877}
878
Manuel Laussc4223c22008-06-09 08:36:13 +0200879static int au1xmmc_dbdma_init(struct au1xmmc_host *host)
Pete Popovba264b32005-09-21 06:18:27 +0000880{
Manuel Laussc4223c22008-06-09 08:36:13 +0200881 struct resource *res;
882 int txid, rxid;
Pete Popovba264b32005-09-21 06:18:27 +0000883
Manuel Laussc4223c22008-06-09 08:36:13 +0200884 res = platform_get_resource(host->pdev, IORESOURCE_DMA, 0);
885 if (!res)
886 return -ENODEV;
887 txid = res->start;
Pete Popovba264b32005-09-21 06:18:27 +0000888
Manuel Laussc4223c22008-06-09 08:36:13 +0200889 res = platform_get_resource(host->pdev, IORESOURCE_DMA, 1);
890 if (!res)
891 return -ENODEV;
892 rxid = res->start;
Pete Popovba264b32005-09-21 06:18:27 +0000893
Manuel Laussc4223c22008-06-09 08:36:13 +0200894 if (!memid)
895 return -ENODEV;
Pete Popovba264b32005-09-21 06:18:27 +0000896
Manuel Laussc4223c22008-06-09 08:36:13 +0200897 host->tx_chan = au1xxx_dbdma_chan_alloc(memid, txid,
898 au1xmmc_dbdma_callback, (void *)host);
899 if (!host->tx_chan) {
900 dev_err(&host->pdev->dev, "cannot allocate TX DMA\n");
901 return -ENODEV;
902 }
Pete Popovba264b32005-09-21 06:18:27 +0000903
Manuel Laussc4223c22008-06-09 08:36:13 +0200904 host->rx_chan = au1xxx_dbdma_chan_alloc(rxid, memid,
905 au1xmmc_dbdma_callback, (void *)host);
906 if (!host->rx_chan) {
907 dev_err(&host->pdev->dev, "cannot allocate RX DMA\n");
908 au1xxx_dbdma_chan_free(host->tx_chan);
909 return -ENODEV;
910 }
Pete Popovba264b32005-09-21 06:18:27 +0000911
Manuel Laussc4223c22008-06-09 08:36:13 +0200912 au1xxx_dbdma_set_devwidth(host->tx_chan, 8);
913 au1xxx_dbdma_set_devwidth(host->rx_chan, 8);
Pete Popovba264b32005-09-21 06:18:27 +0000914
Manuel Laussc4223c22008-06-09 08:36:13 +0200915 au1xxx_dbdma_ring_alloc(host->tx_chan, AU1XMMC_DESCRIPTOR_COUNT);
916 au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT);
Pete Popovba264b32005-09-21 06:18:27 +0000917
Manuel Laussc4223c22008-06-09 08:36:13 +0200918 /* DBDMA is good to go */
Manuel Lauss1177d992011-08-02 19:51:07 +0200919 host->flags |= HOST_F_DMA | HOST_F_DBDMA;
Pete Popovba264b32005-09-21 06:18:27 +0000920
Manuel Laussc4223c22008-06-09 08:36:13 +0200921 return 0;
922}
Pete Popovba264b32005-09-21 06:18:27 +0000923
Manuel Laussc4223c22008-06-09 08:36:13 +0200924static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host)
925{
926 if (host->flags & HOST_F_DMA) {
927 host->flags &= ~HOST_F_DMA;
928 au1xxx_dbdma_chan_free(host->tx_chan);
929 au1xxx_dbdma_chan_free(host->rx_chan);
930 }
931}
Pete Popovba264b32005-09-21 06:18:27 +0000932
Manuel Lauss20f522f2008-06-09 08:38:03 +0200933static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en)
934{
935 struct au1xmmc_host *host = mmc_priv(mmc);
936
937 if (en)
938 IRQ_ON(host, SD_CONFIG_SI);
939 else
940 IRQ_OFF(host, SD_CONFIG_SI);
941}
942
Yoichi Yuasabf8c80a2006-12-05 07:43:38 +0100943static const struct mmc_host_ops au1xmmc_ops = {
Pete Popovba264b32005-09-21 06:18:27 +0000944 .request = au1xmmc_request,
945 .set_ios = au1xmmc_set_ios,
Manuel Lauss82999772007-01-25 10:29:24 +0100946 .get_ro = au1xmmc_card_readonly,
Manuel Lausse2d26472008-06-27 18:25:18 +0200947 .get_cd = au1xmmc_card_inserted,
Manuel Lauss20f522f2008-06-09 08:38:03 +0200948 .enable_sdio_irq = au1xmmc_enable_sdio_irq,
Pete Popovba264b32005-09-21 06:18:27 +0000949};
950
Bill Pembertonc3be1ef2012-11-19 13:23:06 -0500951static int au1xmmc_probe(struct platform_device *pdev)
Pete Popovba264b32005-09-21 06:18:27 +0000952{
Manuel Laussc4223c22008-06-09 08:36:13 +0200953 struct mmc_host *mmc;
954 struct au1xmmc_host *host;
955 struct resource *r;
Manuel Lauss809f36c2011-11-01 20:03:30 +0100956 int ret, iflag;
Pete Popovba264b32005-09-21 06:18:27 +0000957
Manuel Laussc4223c22008-06-09 08:36:13 +0200958 mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
959 if (!mmc) {
960 dev_err(&pdev->dev, "no memory for mmc_host\n");
961 ret = -ENOMEM;
962 goto out0;
Pete Popovba264b32005-09-21 06:18:27 +0000963 }
964
Manuel Laussc4223c22008-06-09 08:36:13 +0200965 host = mmc_priv(mmc);
966 host->mmc = mmc;
967 host->platdata = pdev->dev.platform_data;
968 host->pdev = pdev;
Pete Popovba264b32005-09-21 06:18:27 +0000969
Manuel Laussc4223c22008-06-09 08:36:13 +0200970 ret = -ENODEV;
971 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
972 if (!r) {
973 dev_err(&pdev->dev, "no mmio defined\n");
974 goto out1;
975 }
Pete Popovba264b32005-09-21 06:18:27 +0000976
H Hartley Sweeten7a5ea56a2009-12-14 14:28:06 -0500977 host->ioarea = request_mem_region(r->start, resource_size(r),
Manuel Laussc4223c22008-06-09 08:36:13 +0200978 pdev->name);
979 if (!host->ioarea) {
980 dev_err(&pdev->dev, "mmio already in use\n");
981 goto out1;
982 }
983
Manuel Lauss2f73bfb2014-07-23 16:36:26 +0200984 host->iobase = ioremap(r->start, 0x3c);
Manuel Laussc4223c22008-06-09 08:36:13 +0200985 if (!host->iobase) {
986 dev_err(&pdev->dev, "cannot remap mmio\n");
987 goto out2;
988 }
989
990 r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
991 if (!r) {
992 dev_err(&pdev->dev, "no IRQ defined\n");
993 goto out3;
994 }
Manuel Laussc4223c22008-06-09 08:36:13 +0200995 host->irq = r->start;
Manuel Laussc4223c22008-06-09 08:36:13 +0200996
997 mmc->ops = &au1xmmc_ops;
998
999 mmc->f_min = 450000;
1000 mmc->f_max = 24000000;
1001
Manuel Laussc4223c22008-06-09 08:36:13 +02001002 mmc->max_blk_size = 2048;
1003 mmc->max_blk_count = 512;
1004
1005 mmc->ocr_avail = AU1XMMC_OCR;
Manuel Lauss20f522f2008-06-09 08:38:03 +02001006 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
Manuel Lauss809f36c2011-11-01 20:03:30 +01001007 mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
1008
1009 iflag = IRQF_SHARED; /* Au1100/Au1200: one int for both ctrls */
1010
1011 switch (alchemy_get_cputype()) {
1012 case ALCHEMY_CPU_AU1100:
1013 mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE;
1014 break;
1015 case ALCHEMY_CPU_AU1200:
1016 mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
1017 break;
1018 case ALCHEMY_CPU_AU1300:
1019 iflag = 0; /* nothing is shared */
1020 mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
1021 mmc->f_max = 52000000;
1022 if (host->ioarea->start == AU1100_SD0_PHYS_ADDR)
1023 mmc->caps |= MMC_CAP_8_BIT_DATA;
1024 break;
1025 }
1026
1027 ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host);
1028 if (ret) {
1029 dev_err(&pdev->dev, "cannot grab IRQ\n");
1030 goto out3;
1031 }
Manuel Laussc4223c22008-06-09 08:36:13 +02001032
1033 host->status = HOST_S_IDLE;
1034
1035 /* board-specific carddetect setup, if any */
1036 if (host->platdata && host->platdata->cd_setup) {
1037 ret = host->platdata->cd_setup(mmc, 1);
1038 if (ret) {
Manuel Lausse2d26472008-06-27 18:25:18 +02001039 dev_warn(&pdev->dev, "board CD setup failed\n");
1040 mmc->caps |= MMC_CAP_NEEDS_POLL;
Pete Popovba264b32005-09-21 06:18:27 +00001041 }
Manuel Lausse2d26472008-06-27 18:25:18 +02001042 } else
1043 mmc->caps |= MMC_CAP_NEEDS_POLL;
Pete Popovba264b32005-09-21 06:18:27 +00001044
Manuel Lauss3b839072009-10-14 09:38:06 +02001045 /* platform may not be able to use all advertised caps */
1046 if (host->platdata)
1047 mmc->caps &= ~(host->platdata->mask_host_caps);
1048
Manuel Laussc4223c22008-06-09 08:36:13 +02001049 tasklet_init(&host->data_task, au1xmmc_tasklet_data,
1050 (unsigned long)host);
Pete Popovba264b32005-09-21 06:18:27 +00001051
Manuel Laussc4223c22008-06-09 08:36:13 +02001052 tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
1053 (unsigned long)host);
Pete Popovba264b32005-09-21 06:18:27 +00001054
Manuel Lauss1177d992011-08-02 19:51:07 +02001055 if (has_dbdma()) {
1056 ret = au1xmmc_dbdma_init(host);
1057 if (ret)
Linus Torvaldsd6748062011-11-03 13:28:14 -07001058 pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n");
Manuel Lauss1177d992011-08-02 19:51:07 +02001059 }
Pete Popovba264b32005-09-21 06:18:27 +00001060
Manuel Laussc4223c22008-06-09 08:36:13 +02001061#ifdef CONFIG_LEDS_CLASS
1062 if (host->platdata && host->platdata->led) {
1063 struct led_classdev *led = host->platdata->led;
1064 led->name = mmc_hostname(mmc);
1065 led->brightness = LED_OFF;
1066 led->default_trigger = mmc_hostname(mmc);
1067 ret = led_classdev_register(mmc_dev(mmc), led);
1068 if (ret)
1069 goto out5;
1070 }
1071#endif
Pierre Ossmanfe4a3c72006-11-21 17:54:23 +01001072
Manuel Laussc4223c22008-06-09 08:36:13 +02001073 au1xmmc_reset_controller(host);
Pete Popovba264b32005-09-21 06:18:27 +00001074
Manuel Laussc4223c22008-06-09 08:36:13 +02001075 ret = mmc_add_host(mmc);
1076 if (ret) {
1077 dev_err(&pdev->dev, "cannot add mmc host\n");
1078 goto out6;
1079 }
Pete Popovba264b32005-09-21 06:18:27 +00001080
Manuel Laussdd8572a2008-07-17 13:07:28 +02001081 platform_set_drvdata(pdev, host);
Pete Popovba264b32005-09-21 06:18:27 +00001082
Manuel Lauss2f73bfb2014-07-23 16:36:26 +02001083 pr_info(DRIVER_NAME ": MMC Controller %d set up at %p"
Manuel Laussc4223c22008-06-09 08:36:13 +02001084 " (mode=%s)\n", pdev->id, host->iobase,
1085 host->flags & HOST_F_DMA ? "dma" : "pio");
Pete Popovba264b32005-09-21 06:18:27 +00001086
Manuel Laussc4223c22008-06-09 08:36:13 +02001087 return 0; /* all ok */
Pete Popovba264b32005-09-21 06:18:27 +00001088
Manuel Laussc4223c22008-06-09 08:36:13 +02001089out6:
1090#ifdef CONFIG_LEDS_CLASS
1091 if (host->platdata && host->platdata->led)
1092 led_classdev_unregister(host->platdata->led);
1093out5:
1094#endif
Manuel Lauss2f73bfb2014-07-23 16:36:26 +02001095 __raw_writel(0, HOST_ENABLE(host));
1096 __raw_writel(0, HOST_CONFIG(host));
1097 __raw_writel(0, HOST_CONFIG2(host));
1098 wmb(); /* drain writebuffer */
Manuel Laussc4223c22008-06-09 08:36:13 +02001099
Manuel Lauss1177d992011-08-02 19:51:07 +02001100 if (host->flags & HOST_F_DBDMA)
1101 au1xmmc_dbdma_shutdown(host);
Manuel Laussc4223c22008-06-09 08:36:13 +02001102
1103 tasklet_kill(&host->data_task);
1104 tasklet_kill(&host->finish_task);
1105
Manuel Lausse2d26472008-06-27 18:25:18 +02001106 if (host->platdata && host->platdata->cd_setup &&
1107 !(mmc->caps & MMC_CAP_NEEDS_POLL))
Manuel Laussc4223c22008-06-09 08:36:13 +02001108 host->platdata->cd_setup(mmc, 0);
Manuel Lausse2d26472008-06-27 18:25:18 +02001109
Manuel Laussc4223c22008-06-09 08:36:13 +02001110 free_irq(host->irq, host);
1111out3:
1112 iounmap((void *)host->iobase);
1113out2:
1114 release_resource(host->ioarea);
1115 kfree(host->ioarea);
1116out1:
1117 mmc_free_host(mmc);
1118out0:
1119 return ret;
Pete Popovba264b32005-09-21 06:18:27 +00001120}
1121
Bill Pemberton6e0ee712012-11-19 13:26:03 -05001122static int au1xmmc_remove(struct platform_device *pdev)
Pete Popovba264b32005-09-21 06:18:27 +00001123{
Manuel Laussdd8572a2008-07-17 13:07:28 +02001124 struct au1xmmc_host *host = platform_get_drvdata(pdev);
Pete Popovba264b32005-09-21 06:18:27 +00001125
Manuel Laussdd8572a2008-07-17 13:07:28 +02001126 if (host) {
1127 mmc_remove_host(host->mmc);
Pete Popovba264b32005-09-21 06:18:27 +00001128
Manuel Laussc4223c22008-06-09 08:36:13 +02001129#ifdef CONFIG_LEDS_CLASS
1130 if (host->platdata && host->platdata->led)
1131 led_classdev_unregister(host->platdata->led);
1132#endif
1133
Manuel Lausse2d26472008-06-27 18:25:18 +02001134 if (host->platdata && host->platdata->cd_setup &&
Manuel Laussdd8572a2008-07-17 13:07:28 +02001135 !(host->mmc->caps & MMC_CAP_NEEDS_POLL))
1136 host->platdata->cd_setup(host->mmc, 0);
Manuel Laussc4223c22008-06-09 08:36:13 +02001137
Manuel Lauss2f73bfb2014-07-23 16:36:26 +02001138 __raw_writel(0, HOST_ENABLE(host));
1139 __raw_writel(0, HOST_CONFIG(host));
1140 __raw_writel(0, HOST_CONFIG2(host));
1141 wmb(); /* drain writebuffer */
Pete Popovba264b32005-09-21 06:18:27 +00001142
1143 tasklet_kill(&host->data_task);
1144 tasklet_kill(&host->finish_task);
1145
Manuel Lauss1177d992011-08-02 19:51:07 +02001146 if (host->flags & HOST_F_DBDMA)
1147 au1xmmc_dbdma_shutdown(host);
1148
Pete Popovba264b32005-09-21 06:18:27 +00001149 au1xmmc_set_power(host, 0);
1150
Manuel Laussc4223c22008-06-09 08:36:13 +02001151 free_irq(host->irq, host);
1152 iounmap((void *)host->iobase);
1153 release_resource(host->ioarea);
1154 kfree(host->ioarea);
Pete Popovba264b32005-09-21 06:18:27 +00001155
Manuel Laussdd8572a2008-07-17 13:07:28 +02001156 mmc_free_host(host->mmc);
Pete Popovba264b32005-09-21 06:18:27 +00001157 }
Pete Popovba264b32005-09-21 06:18:27 +00001158 return 0;
1159}
1160
Manuel Laussdd8572a2008-07-17 13:07:28 +02001161#ifdef CONFIG_PM
1162static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
1163{
1164 struct au1xmmc_host *host = platform_get_drvdata(pdev);
Manuel Laussdd8572a2008-07-17 13:07:28 +02001165
Manuel Lauss2f73bfb2014-07-23 16:36:26 +02001166 __raw_writel(0, HOST_CONFIG2(host));
1167 __raw_writel(0, HOST_CONFIG(host));
1168 __raw_writel(0xffffffff, HOST_STATUS(host));
1169 __raw_writel(0, HOST_ENABLE(host));
1170 wmb(); /* drain writebuffer */
Manuel Laussdd8572a2008-07-17 13:07:28 +02001171
1172 return 0;
1173}
1174
1175static int au1xmmc_resume(struct platform_device *pdev)
1176{
1177 struct au1xmmc_host *host = platform_get_drvdata(pdev);
1178
1179 au1xmmc_reset_controller(host);
1180
Ulf Hansson1e63d482013-09-25 10:55:23 +02001181 return 0;
Manuel Laussdd8572a2008-07-17 13:07:28 +02001182}
1183#else
1184#define au1xmmc_suspend NULL
1185#define au1xmmc_resume NULL
1186#endif
1187
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001188static struct platform_driver au1xmmc_driver = {
Pete Popovba264b32005-09-21 06:18:27 +00001189 .probe = au1xmmc_probe,
1190 .remove = au1xmmc_remove,
Manuel Laussdd8572a2008-07-17 13:07:28 +02001191 .suspend = au1xmmc_suspend,
1192 .resume = au1xmmc_resume,
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001193 .driver = {
1194 .name = DRIVER_NAME,
Kay Sieversbc65c722008-04-15 14:34:28 -07001195 .owner = THIS_MODULE,
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001196 },
Pete Popovba264b32005-09-21 06:18:27 +00001197};
1198
1199static int __init au1xmmc_init(void)
1200{
Manuel Lauss1177d992011-08-02 19:51:07 +02001201 if (has_dbdma()) {
1202 /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
1203 * of 8 bits. And since devices are shared, we need to create
1204 * our own to avoid freaking out other devices.
1205 */
1206 memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
1207 if (!memid)
Linus Torvaldsd6748062011-11-03 13:28:14 -07001208 pr_err("au1xmmc: cannot add memory dbdma\n");
Manuel Lauss1177d992011-08-02 19:51:07 +02001209 }
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001210 return platform_driver_register(&au1xmmc_driver);
Pete Popovba264b32005-09-21 06:18:27 +00001211}
1212
1213static void __exit au1xmmc_exit(void)
1214{
Manuel Lauss1177d992011-08-02 19:51:07 +02001215 if (has_dbdma() && memid)
Manuel Laussc4223c22008-06-09 08:36:13 +02001216 au1xxx_ddma_del_device(memid);
Manuel Lauss1177d992011-08-02 19:51:07 +02001217
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001218 platform_driver_unregister(&au1xmmc_driver);
Pete Popovba264b32005-09-21 06:18:27 +00001219}
1220
1221module_init(au1xmmc_init);
1222module_exit(au1xmmc_exit);
1223
Pete Popovba264b32005-09-21 06:18:27 +00001224MODULE_AUTHOR("Advanced Micro Devices, Inc");
1225MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
1226MODULE_LICENSE("GPL");
Kay Sieversbc65c722008-04-15 14:34:28 -07001227MODULE_ALIAS("platform:au1xxx-mmc");