aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/tifm_sd.c259
1 files changed, 137 insertions, 122 deletions
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index 52499548abe8..103060f490a6 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -70,19 +70,14 @@ module_param(fixed_timeout, bool, 0644);
70#define TIFM_MMCSD_CMD_AC 0x2000 70#define TIFM_MMCSD_CMD_AC 0x2000
71#define TIFM_MMCSD_CMD_ADTC 0x3000 71#define TIFM_MMCSD_CMD_ADTC 0x3000
72 72
73typedef enum {
74 IDLE = 0,
75 CMD, /* main command ended */
76 BRS, /* block transfer finished */
77 SCMD, /* stop command ended */
78 CARD, /* card left busy state */
79 FIFO, /* FIFO operation completed (uncertain) */
80 READY
81} card_state_t;
82
83enum { 73enum {
84 FIFO_RDY = 0x0001, /* hardware dependent value */ 74 CMD_READY = 0x0001,
85 CARD_BUSY = 0x0010 75 FIFO_READY = 0x0002,
76 BRS_READY = 0x0004,
77 SCMD_ACTIVE = 0x0008,
78 SCMD_READY = 0x0010,
79 CARD_BUSY = 0x0020,
80 DATA_CARRY = 0x0040
86}; 81};
87 82
88struct tifm_sd { 83struct tifm_sd {
@@ -92,7 +87,7 @@ struct tifm_sd {
92 open_drain:1, 87 open_drain:1,
93 no_dma:1; 88 no_dma:1;
94 unsigned short cmd_flags; 89 unsigned short cmd_flags;
95 card_state_t state; 90
96 unsigned int clk_freq; 91 unsigned int clk_freq;
97 unsigned int clk_div; 92 unsigned int clk_div;
98 unsigned long timeout_jiffies; 93 unsigned long timeout_jiffies;
@@ -234,87 +229,76 @@ static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
234 | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00); 229 | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
235} 230}
236 231
237static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host, 232static void tifm_sd_check_status(struct tifm_sd *host)
238 unsigned int host_status)
239{ 233{
234 struct tifm_dev *sock = host->dev;
240 struct mmc_command *cmd = host->req->cmd; 235 struct mmc_command *cmd = host->req->cmd;
241 236
242change_state: 237 if (cmd->error != MMC_ERR_NONE)
243 switch (host->state) { 238 goto finish_request;
244 case IDLE: 239
240 if (!(host->cmd_flags & CMD_READY))
245 return; 241 return;
246 case CMD: 242
247 if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { 243 if (cmd->data) {
248 tifm_sd_fetch_resp(cmd, sock); 244 if (cmd->data->error != MMC_ERR_NONE) {
249 if (cmd->data) { 245 if ((host->cmd_flags & SCMD_ACTIVE)
250 host->state = BRS; 246 && !(host->cmd_flags & SCMD_READY))
251 } else { 247 return;
252 host->state = READY; 248
253 } 249 goto finish_request;
254 goto change_state;
255 }
256 break;
257 case BRS:
258 if (tifm_sd_transfer_data(sock, host, host_status)) {
259 if (cmd->data->flags & MMC_DATA_WRITE) {
260 host->state = CARD;
261 } else {
262 if (host->no_dma) {
263 if (host->req->stop) {
264 tifm_sd_exec(host, host->req->stop);
265 host->state = SCMD;
266 } else {
267 host->state = READY;
268 }
269 } else {
270 host->state = FIFO;
271 }
272 }
273 goto change_state;
274 }
275 break;
276 case SCMD:
277 if (host_status & TIFM_MMCSD_EOC) {
278 tifm_sd_fetch_resp(host->req->stop, sock);
279 host->state = READY;
280 goto change_state;
281 } 250 }
282 break; 251
283 case CARD: 252 if (!(host->cmd_flags & BRS_READY))
284 dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n", 253 return;
285 host->written_blocks); 254
286 if (!(host->cmd_flags & CARD_BUSY) 255 if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
287 && (host->written_blocks == cmd->data->blocks)) { 256 return;
288 if (host->no_dma) { 257
289 if (host->req->stop) { 258 if (cmd->data->flags & MMC_DATA_WRITE) {
259 if (host->req->stop) {
260 if (!(host->cmd_flags & SCMD_ACTIVE)) {
261 host->cmd_flags |= SCMD_ACTIVE;
262 writel(TIFM_MMCSD_EOFB
263 | readl(sock->addr
264 + SOCK_MMCSD_INT_ENABLE),
265 sock->addr
266 + SOCK_MMCSD_INT_ENABLE);
290 tifm_sd_exec(host, host->req->stop); 267 tifm_sd_exec(host, host->req->stop);
291 host->state = SCMD; 268 return;
292 } else { 269 } else {
293 host->state = READY; 270 if (!(host->cmd_flags & SCMD_READY)
271 || (host->cmd_flags & CARD_BUSY))
272 return;
273 writel((~TIFM_MMCSD_EOFB)
274 & readl(sock->addr
275 + SOCK_MMCSD_INT_ENABLE),
276 sock->addr
277 + SOCK_MMCSD_INT_ENABLE);
294 } 278 }
295 } else { 279 } else {
296 host->state = FIFO; 280 if (host->cmd_flags & CARD_BUSY)
281 return;
282 writel((~TIFM_MMCSD_EOFB)
283 & readl(sock->addr
284 + SOCK_MMCSD_INT_ENABLE),
285 sock->addr + SOCK_MMCSD_INT_ENABLE);
297 } 286 }
298 goto change_state; 287 } else {
299 }
300 break;
301 case FIFO:
302 if (host->cmd_flags & FIFO_RDY) {
303 host->cmd_flags &= ~FIFO_RDY;
304 if (host->req->stop) { 288 if (host->req->stop) {
305 tifm_sd_exec(host, host->req->stop); 289 if (!(host->cmd_flags & SCMD_ACTIVE)) {
306 host->state = SCMD; 290 host->cmd_flags |= SCMD_ACTIVE;
307 } else { 291 tifm_sd_exec(host, host->req->stop);
308 host->state = READY; 292 return;
293 } else {
294 if (!(host->cmd_flags & SCMD_READY))
295 return;
296 }
309 } 297 }
310 goto change_state;
311 } 298 }
312 break;
313 case READY:
314 tasklet_schedule(&host->finish_tasklet);
315 return;
316 } 299 }
317 300finish_request:
301 tasklet_schedule(&host->finish_tasklet);
318} 302}
319 303
320/* Called from interrupt handler */ 304/* Called from interrupt handler */
@@ -322,21 +306,25 @@ static void tifm_sd_data_event(struct tifm_dev *sock)
322{ 306{
323 struct tifm_sd *host; 307 struct tifm_sd *host;
324 unsigned int fifo_status = 0; 308 unsigned int fifo_status = 0;
309 struct mmc_data *r_data = NULL;
325 310
326 spin_lock(&sock->lock); 311 spin_lock(&sock->lock);
327 host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); 312 host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
328
329 fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); 313 fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
330 writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); 314 dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
315 fifo_status, host->cmd_flags);
331 316
332 host->cmd_flags |= fifo_status & FIFO_RDY; 317 if (host->req) {
318 r_data = host->req->cmd->data;
333 319
334 if (host->req) 320 if (r_data && (fifo_status & TIFM_FIFO_READY)) {
335 tifm_sd_process_cmd(sock, host, 0); 321 host->cmd_flags |= FIFO_READY;
322 tifm_sd_check_status(host);
323 }
324 }
336 325
337 dev_dbg(&sock->dev, "fifo_status %x\n", fifo_status); 326 writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
338 spin_unlock(&sock->lock); 327 spin_unlock(&sock->lock);
339
340} 328}
341 329
342/* Called from interrupt handler */ 330/* Called from interrupt handler */
@@ -344,60 +332,88 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
344{ 332{
345 struct tifm_sd *host; 333 struct tifm_sd *host;
346 unsigned int host_status = 0; 334 unsigned int host_status = 0;
347 int error_code = 0; 335 int cmd_error = MMC_ERR_NONE;
336 struct mmc_command *cmd = NULL;
337 unsigned long flags;
348 338
349 spin_lock(&sock->lock); 339 spin_lock(&sock->lock);
350 host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); 340 host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
341 host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
342 dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
343 host_status, host->cmd_flags);
351 344
352 345 if (host->req) {
353 host_status = readl(sock->addr + SOCK_MMCSD_STATUS); 346 cmd = host->req->cmd;
354 writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
355
356 if (!host->req)
357 goto done;
358 347
359 if (host_status & TIFM_MMCSD_ERRMASK) { 348 if (host_status & TIFM_MMCSD_ERRMASK) {
360 if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) 349 writel(host_status & TIFM_MMCSD_ERRMASK,
361 error_code = MMC_ERR_TIMEOUT; 350 sock->addr + SOCK_MMCSD_STATUS);
362 else if (host_status 351 if (host_status & TIFM_MMCSD_CTO)
363 & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) 352 cmd_error = MMC_ERR_TIMEOUT;
364 error_code = MMC_ERR_BADCRC; 353 else if (host_status & TIFM_MMCSD_CCRC)
354 cmd_error = MMC_ERR_BADCRC;
355
356 if (cmd->data) {
357 if (host_status & TIFM_MMCSD_DTO)
358 cmd->data->error = MMC_ERR_TIMEOUT;
359 else if (host_status & TIFM_MMCSD_DCRC)
360 cmd->data->error = MMC_ERR_BADCRC;
361 }
365 362
366 writel(TIFM_FIFO_INT_SETALL, 363 writel(TIFM_FIFO_INT_SETALL,
367 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); 364 sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
368 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL); 365 writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
369 366
370 if (host->req->stop) { 367 if (host->req->stop) {
371 if (host->state == SCMD) { 368 if (host->cmd_flags & SCMD_ACTIVE) {
372 host->req->stop->error = error_code; 369 host->req->stop->error = cmd_error;
373 } else if (host->state == BRS 370 host->cmd_flags |= SCMD_READY;
374 || host->state == CARD 371 } else {
375 || host->state == FIFO) { 372 cmd->error = cmd_error;
376 host->req->cmd->error = error_code; 373 host->cmd_flags |= SCMD_ACTIVE;
377 tifm_sd_exec(host, host->req->stop); 374 tifm_sd_exec(host, host->req->stop);
378 host->state = SCMD;
379 goto done; 375 goto done;
380 } else {
381 host->req->cmd->error = error_code;
382 } 376 }
383 } else { 377 } else
384 host->req->cmd->error = error_code; 378 cmd->error = cmd_error;
379 } else {
380 if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
381 if (!(host->cmd_flags & CMD_READY)) {
382 host->cmd_flags |= CMD_READY;
383 tifm_sd_fetch_resp(cmd, sock);
384 } else if (host->cmd_flags & SCMD_ACTIVE) {
385 host->cmd_flags |= SCMD_READY;
386 tifm_sd_fetch_resp(host->req->stop,
387 sock);
388 }
385 } 389 }
386 host->state = READY; 390 if (host_status & TIFM_MMCSD_BRS)
391 host->cmd_flags |= BRS_READY;
387 } 392 }
388 393
389 if (host_status & TIFM_MMCSD_CB) 394 if (host->no_dma && cmd->data) {
390 host->cmd_flags |= CARD_BUSY; 395 if (host_status & TIFM_MMCSD_AE)
391 if ((host_status & TIFM_MMCSD_EOFB) 396 writel(host_status & TIFM_MMCSD_AE,
392 && (host->cmd_flags & CARD_BUSY)) { 397 sock->addr + SOCK_MMCSD_STATUS);
393 host->written_blocks++; 398
394 host->cmd_flags &= ~CARD_BUSY; 399 if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
400 | TIFM_MMCSD_BRS)) {
401 local_irq_save(flags);
402 tifm_sd_transfer_data(sock, host, host_status);
403 local_irq_restore(flags);
404 host_status &= ~TIFM_MMCSD_AE;
405 }
395 } 406 }
396 407
397 if (host->req) 408 if (host_status & TIFM_MMCSD_EOFB)
398 tifm_sd_process_cmd(sock, host, host_status); 409 host->cmd_flags &= ~CARD_BUSY;
410 else if (host_status & TIFM_MMCSD_CB)
411 host->cmd_flags |= CARD_BUSY;
412
413 tifm_sd_check_status(host);
414 }
399done: 415done:
400 dev_dbg(&sock->dev, "host_status %x\n", host_status); 416 writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
401 spin_unlock(&sock->lock); 417 spin_unlock(&sock->lock);
402} 418}
403 419
@@ -522,7 +538,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
522 538
523 host->req = mrq; 539 host->req = mrq;
524 mod_timer(&host->timer, jiffies + host->timeout_jiffies); 540 mod_timer(&host->timer, jiffies + host->timeout_jiffies);
525 host->state = CMD; 541 host->cmd_flags = 0;
526 writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), 542 writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
527 sock->addr + SOCK_CONTROL); 543 sock->addr + SOCK_CONTROL);
528 tifm_sd_exec(host, mrq->cmd); 544 tifm_sd_exec(host, mrq->cmd);
@@ -553,7 +569,6 @@ static void tifm_sd_end_cmd(unsigned long data)
553 del_timer(&host->timer); 569 del_timer(&host->timer);
554 mrq = host->req; 570 mrq = host->req;
555 host->req = NULL; 571 host->req = NULL;
556 host->state = IDLE;
557 572
558 if (!mrq) { 573 if (!mrq) {
559 printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); 574 printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");