diff options
Diffstat (limited to 'drivers/memstick/host/jmb38x_ms.c')
-rw-r--r-- | drivers/memstick/host/jmb38x_ms.c | 113 |
1 files changed, 61 insertions, 52 deletions
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 03fe8783b1ee..8770a5fac3b6 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/spinlock.h> | 12 | #include <linux/spinlock.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
15 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
16 | #include <linux/highmem.h> | 17 | #include <linux/highmem.h> |
17 | #include <linux/memstick.h> | 18 | #include <linux/memstick.h> |
@@ -56,8 +57,6 @@ struct jmb38x_ms_host { | |||
56 | unsigned long timeout_jiffies; | 57 | unsigned long timeout_jiffies; |
57 | struct timer_list timer; | 58 | struct timer_list timer; |
58 | struct memstick_request *req; | 59 | struct memstick_request *req; |
59 | unsigned char eject:1, | ||
60 | use_dma:1; | ||
61 | unsigned char cmd_flags; | 60 | unsigned char cmd_flags; |
62 | unsigned char io_pos; | 61 | unsigned char io_pos; |
63 | unsigned int io_word[2]; | 62 | unsigned int io_word[2]; |
@@ -94,9 +93,22 @@ struct jmb38x_ms { | |||
94 | #define HOST_CONTROL_IF_PAR4 0x1 | 93 | #define HOST_CONTROL_IF_PAR4 0x1 |
95 | #define HOST_CONTROL_IF_PAR8 0x3 | 94 | #define HOST_CONTROL_IF_PAR8 0x3 |
96 | 95 | ||
96 | #define STATUS_BUSY 0x00080000 | ||
97 | #define STATUS_MS_DAT7 0x00040000 | ||
98 | #define STATUS_MS_DAT6 0x00020000 | ||
99 | #define STATUS_MS_DAT5 0x00010000 | ||
100 | #define STATUS_MS_DAT4 0x00008000 | ||
101 | #define STATUS_MS_DAT3 0x00004000 | ||
102 | #define STATUS_MS_DAT2 0x00002000 | ||
103 | #define STATUS_MS_DAT1 0x00001000 | ||
104 | #define STATUS_MS_DAT0 0x00000800 | ||
97 | #define STATUS_HAS_MEDIA 0x00000400 | 105 | #define STATUS_HAS_MEDIA 0x00000400 |
98 | #define STATUS_FIFO_EMPTY 0x00000200 | 106 | #define STATUS_FIFO_EMPTY 0x00000200 |
99 | #define STATUS_FIFO_FULL 0x00000100 | 107 | #define STATUS_FIFO_FULL 0x00000100 |
108 | #define STATUS_MS_CED 0x00000080 | ||
109 | #define STATUS_MS_ERR 0x00000040 | ||
110 | #define STATUS_MS_BRQ 0x00000020 | ||
111 | #define STATUS_MS_CNK 0x00000001 | ||
100 | 112 | ||
101 | #define INT_STATUS_TPC_ERR 0x00080000 | 113 | #define INT_STATUS_TPC_ERR 0x00080000 |
102 | #define INT_STATUS_CRC_ERR 0x00040000 | 114 | #define INT_STATUS_CRC_ERR 0x00040000 |
@@ -119,11 +131,17 @@ struct jmb38x_ms { | |||
119 | #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 | 131 | #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 |
120 | #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 | 132 | #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 |
121 | 133 | ||
134 | #define CLOCK_CONTROL_40MHZ 0x00000001 | ||
135 | #define CLOCK_CONTROL_50MHZ 0x00000002 | ||
136 | #define CLOCK_CONTROL_60MHZ 0x00000008 | ||
137 | #define CLOCK_CONTROL_62_5MHZ 0x0000000c | ||
138 | #define CLOCK_CONTROL_OFF 0x00000000 | ||
139 | |||
122 | enum { | 140 | enum { |
123 | CMD_READY = 0x01, | 141 | CMD_READY = 0x01, |
124 | FIFO_READY = 0x02, | 142 | FIFO_READY = 0x02, |
125 | REG_DATA = 0x04, | 143 | REG_DATA = 0x04, |
126 | AUTO_GET_INT = 0x08 | 144 | DMA_DATA = 0x08 |
127 | }; | 145 | }; |
128 | 146 | ||
129 | static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, | 147 | static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host, |
@@ -273,7 +291,7 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) | |||
273 | { | 291 | { |
274 | unsigned int length; | 292 | unsigned int length; |
275 | unsigned int off; | 293 | unsigned int off; |
276 | unsigned int t_size, p_off, p_cnt; | 294 | unsigned int t_size, p_cnt; |
277 | unsigned char *buf; | 295 | unsigned char *buf; |
278 | struct page *pg; | 296 | struct page *pg; |
279 | unsigned long flags = 0; | 297 | unsigned long flags = 0; |
@@ -287,6 +305,8 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) | |||
287 | } | 305 | } |
288 | 306 | ||
289 | while (length) { | 307 | while (length) { |
308 | unsigned int uninitialized_var(p_off); | ||
309 | |||
290 | if (host->req->long_data) { | 310 | if (host->req->long_data) { |
291 | pg = nth_page(sg_page(&host->req->sg), | 311 | pg = nth_page(sg_page(&host->req->sg), |
292 | off >> PAGE_SHIFT); | 312 | off >> PAGE_SHIFT); |
@@ -364,28 +384,27 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) | |||
364 | cmd |= TPC_DIR; | 384 | cmd |= TPC_DIR; |
365 | if (host->req->need_card_int) | 385 | if (host->req->need_card_int) |
366 | cmd |= TPC_WAIT_INT; | 386 | cmd |= TPC_WAIT_INT; |
367 | if (host->req->get_int_reg) | ||
368 | cmd |= TPC_GET_INT; | ||
369 | 387 | ||
370 | data = host->req->data; | 388 | data = host->req->data; |
371 | 389 | ||
372 | host->use_dma = !no_dma; | 390 | if (!no_dma) |
391 | host->cmd_flags |= DMA_DATA; | ||
373 | 392 | ||
374 | if (host->req->long_data) { | 393 | if (host->req->long_data) { |
375 | data_len = host->req->sg.length; | 394 | data_len = host->req->sg.length; |
376 | } else { | 395 | } else { |
377 | data_len = host->req->data_len; | 396 | data_len = host->req->data_len; |
378 | host->use_dma = 0; | 397 | host->cmd_flags &= ~DMA_DATA; |
379 | } | 398 | } |
380 | 399 | ||
381 | if (data_len <= 8) { | 400 | if (data_len <= 8) { |
382 | cmd &= ~(TPC_DATA_SEL | 0xf); | 401 | cmd &= ~(TPC_DATA_SEL | 0xf); |
383 | host->cmd_flags |= REG_DATA; | 402 | host->cmd_flags |= REG_DATA; |
384 | cmd |= data_len & 0xf; | 403 | cmd |= data_len & 0xf; |
385 | host->use_dma = 0; | 404 | host->cmd_flags &= ~DMA_DATA; |
386 | } | 405 | } |
387 | 406 | ||
388 | if (host->use_dma) { | 407 | if (host->cmd_flags & DMA_DATA) { |
389 | if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1, | 408 | if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1, |
390 | host->req->data_dir == READ | 409 | host->req->data_dir == READ |
391 | ? PCI_DMA_FROMDEVICE | 410 | ? PCI_DMA_FROMDEVICE |
@@ -448,13 +467,12 @@ static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last) | |||
448 | readl(host->addr + INT_STATUS)); | 467 | readl(host->addr + INT_STATUS)); |
449 | dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); | 468 | dev_dbg(msh->cdev.dev, "c hstatus %08x\n", readl(host->addr + STATUS)); |
450 | 469 | ||
451 | if (host->req->get_int_reg) { | 470 | host->req->int_reg = readl(host->addr + STATUS) & 0xff; |
452 | t_val = readl(host->addr + TPC_P0); | 471 | |
453 | host->req->int_reg = (t_val & 0xff); | 472 | writel(0, host->addr + BLOCK); |
454 | } | 473 | writel(0, host->addr + DMA_CONTROL); |
455 | 474 | ||
456 | if (host->use_dma) { | 475 | if (host->cmd_flags & DMA_DATA) { |
457 | writel(0, host->addr + DMA_CONTROL); | ||
458 | pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, | 476 | pci_unmap_sg(host->chip->pdev, &host->req->sg, 1, |
459 | host->req->data_dir == READ | 477 | host->req->data_dir == READ |
460 | ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); | 478 | ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); |
@@ -506,7 +524,7 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) | |||
506 | else | 524 | else |
507 | host->req->error = -ETIME; | 525 | host->req->error = -ETIME; |
508 | } else { | 526 | } else { |
509 | if (host->use_dma) { | 527 | if (host->cmd_flags & DMA_DATA) { |
510 | if (irq_status & INT_STATUS_EOTRAN) | 528 | if (irq_status & INT_STATUS_EOTRAN) |
511 | host->cmd_flags |= FIFO_READY; | 529 | host->cmd_flags |= FIFO_READY; |
512 | } else { | 530 | } else { |
@@ -595,19 +613,18 @@ static void jmb38x_ms_reset(struct jmb38x_ms_host *host) | |||
595 | { | 613 | { |
596 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); | 614 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); |
597 | 615 | ||
598 | writel(host_ctl | HOST_CONTROL_RESET_REQ | HOST_CONTROL_RESET, | 616 | writel(HOST_CONTROL_RESET_REQ, host->addr + HOST_CONTROL); |
599 | host->addr + HOST_CONTROL); | ||
600 | 617 | ||
601 | while (HOST_CONTROL_RESET_REQ | 618 | while (HOST_CONTROL_RESET_REQ |
602 | & (host_ctl = readl(host->addr + HOST_CONTROL))) { | 619 | & (host_ctl = readl(host->addr + HOST_CONTROL))) { |
603 | ndelay(100); | 620 | ndelay(20); |
604 | dev_dbg(&host->chip->pdev->dev, "reset\n"); | 621 | dev_dbg(&host->chip->pdev->dev, "reset %08x\n", host_ctl); |
605 | } | 622 | } |
606 | 623 | ||
607 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); | 624 | writel(HOST_CONTROL_RESET, host->addr + HOST_CONTROL); |
625 | mmiowb(); | ||
608 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); | 626 | writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE); |
609 | 627 | writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE); | |
610 | dev_dbg(&host->chip->pdev->dev, "reset\n"); | ||
611 | } | 628 | } |
612 | 629 | ||
613 | static void jmb38x_ms_set_param(struct memstick_host *msh, | 630 | static void jmb38x_ms_set_param(struct memstick_host *msh, |
@@ -615,10 +632,8 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
615 | int value) | 632 | int value) |
616 | { | 633 | { |
617 | struct jmb38x_ms_host *host = memstick_priv(msh); | 634 | struct jmb38x_ms_host *host = memstick_priv(msh); |
618 | unsigned int host_ctl; | 635 | unsigned int host_ctl = readl(host->addr + HOST_CONTROL); |
619 | unsigned long flags; | 636 | unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; |
620 | |||
621 | spin_lock_irqsave(&host->lock, flags); | ||
622 | 637 | ||
623 | switch (param) { | 638 | switch (param) { |
624 | case MEMSTICK_POWER: | 639 | case MEMSTICK_POWER: |
@@ -626,60 +641,57 @@ static void jmb38x_ms_set_param(struct memstick_host *msh, | |||
626 | jmb38x_ms_reset(host); | 641 | jmb38x_ms_reset(host); |
627 | 642 | ||
628 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 | 643 | writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 |
629 | : PAD_PU_PD_ON_MS_SOCK0, | 644 | : PAD_PU_PD_ON_MS_SOCK0, |
630 | host->addr + PAD_PU_PD); | 645 | host->addr + PAD_PU_PD); |
631 | 646 | ||
632 | writel(PAD_OUTPUT_ENABLE_MS, | 647 | writel(PAD_OUTPUT_ENABLE_MS, |
633 | host->addr + PAD_OUTPUT_ENABLE); | 648 | host->addr + PAD_OUTPUT_ENABLE); |
634 | 649 | ||
635 | host_ctl = readl(host->addr + HOST_CONTROL); | 650 | host_ctl = 7; |
636 | host_ctl |= 7; | 651 | host_ctl |= HOST_CONTROL_POWER_EN |
637 | writel(host_ctl | (HOST_CONTROL_POWER_EN | 652 | | HOST_CONTROL_CLOCK_EN; |
638 | | HOST_CONTROL_CLOCK_EN), | 653 | writel(host_ctl, host->addr + HOST_CONTROL); |
639 | host->addr + HOST_CONTROL); | ||
640 | 654 | ||
641 | dev_dbg(&host->chip->pdev->dev, "power on\n"); | 655 | dev_dbg(&host->chip->pdev->dev, "power on\n"); |
642 | } else if (value == MEMSTICK_POWER_OFF) { | 656 | } else if (value == MEMSTICK_POWER_OFF) { |
643 | writel(readl(host->addr + HOST_CONTROL) | 657 | host_ctl &= ~(HOST_CONTROL_POWER_EN |
644 | & ~(HOST_CONTROL_POWER_EN | 658 | | HOST_CONTROL_CLOCK_EN); |
645 | | HOST_CONTROL_CLOCK_EN), | 659 | writel(host_ctl, host->addr + HOST_CONTROL); |
646 | host->addr + HOST_CONTROL); | ||
647 | writel(0, host->addr + PAD_OUTPUT_ENABLE); | 660 | writel(0, host->addr + PAD_OUTPUT_ENABLE); |
648 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); | 661 | writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD); |
649 | dev_dbg(&host->chip->pdev->dev, "power off\n"); | 662 | dev_dbg(&host->chip->pdev->dev, "power off\n"); |
650 | } | 663 | } |
651 | break; | 664 | break; |
652 | case MEMSTICK_INTERFACE: | 665 | case MEMSTICK_INTERFACE: |
653 | /* jmb38x_ms_reset(host); */ | ||
654 | |||
655 | host_ctl = readl(host->addr + HOST_CONTROL); | ||
656 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); | 666 | host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); |
657 | /* host_ctl |= 7; */ | ||
658 | 667 | ||
659 | if (value == MEMSTICK_SERIAL) { | 668 | if (value == MEMSTICK_SERIAL) { |
660 | host_ctl &= ~HOST_CONTROL_FAST_CLK; | 669 | host_ctl &= ~HOST_CONTROL_FAST_CLK; |
661 | host_ctl |= HOST_CONTROL_IF_SERIAL | 670 | host_ctl |= HOST_CONTROL_IF_SERIAL |
662 | << HOST_CONTROL_IF_SHIFT; | 671 | << HOST_CONTROL_IF_SHIFT; |
663 | host_ctl |= HOST_CONTROL_REI; | 672 | host_ctl |= HOST_CONTROL_REI; |
664 | writel(0, host->addr + CLOCK_DELAY); | 673 | clock_ctl = CLOCK_CONTROL_40MHZ; |
674 | clock_delay = 0; | ||
665 | } else if (value == MEMSTICK_PAR4) { | 675 | } else if (value == MEMSTICK_PAR4) { |
666 | host_ctl |= HOST_CONTROL_FAST_CLK; | 676 | host_ctl |= HOST_CONTROL_FAST_CLK; |
667 | host_ctl |= HOST_CONTROL_IF_PAR4 | 677 | host_ctl |= HOST_CONTROL_IF_PAR4 |
668 | << HOST_CONTROL_IF_SHIFT; | 678 | << HOST_CONTROL_IF_SHIFT; |
669 | host_ctl &= ~HOST_CONTROL_REI; | 679 | host_ctl &= ~HOST_CONTROL_REI; |
670 | writel(4, host->addr + CLOCK_DELAY); | 680 | clock_ctl = CLOCK_CONTROL_40MHZ; |
681 | clock_delay = 4; | ||
671 | } else if (value == MEMSTICK_PAR8) { | 682 | } else if (value == MEMSTICK_PAR8) { |
672 | host_ctl |= HOST_CONTROL_FAST_CLK; | 683 | host_ctl |= HOST_CONTROL_FAST_CLK; |
673 | host_ctl |= HOST_CONTROL_IF_PAR8 | 684 | host_ctl |= HOST_CONTROL_IF_PAR8 |
674 | << HOST_CONTROL_IF_SHIFT; | 685 | << HOST_CONTROL_IF_SHIFT; |
675 | host_ctl &= ~HOST_CONTROL_REI; | 686 | host_ctl &= ~HOST_CONTROL_REI; |
676 | writel(4, host->addr + CLOCK_DELAY); | 687 | clock_ctl = CLOCK_CONTROL_60MHZ; |
688 | clock_delay = 0; | ||
677 | } | 689 | } |
678 | writel(host_ctl, host->addr + HOST_CONTROL); | 690 | writel(host_ctl, host->addr + HOST_CONTROL); |
691 | writel(clock_ctl, host->addr + CLOCK_CONTROL); | ||
692 | writel(clock_delay, host->addr + CLOCK_DELAY); | ||
679 | break; | 693 | break; |
680 | }; | 694 | }; |
681 | |||
682 | spin_unlock_irqrestore(&host->lock, flags); | ||
683 | } | 695 | } |
684 | 696 | ||
685 | #ifdef CONFIG_PM | 697 | #ifdef CONFIG_PM |
@@ -772,13 +784,10 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) | |||
772 | snprintf(host->host_id, DEVICE_ID_SIZE, DRIVER_NAME ":slot%d", | 784 | snprintf(host->host_id, DEVICE_ID_SIZE, DRIVER_NAME ":slot%d", |
773 | host->id); | 785 | host->id); |
774 | host->irq = jm->pdev->irq; | 786 | host->irq = jm->pdev->irq; |
775 | host->timeout_jiffies = msecs_to_jiffies(4000); | 787 | host->timeout_jiffies = msecs_to_jiffies(1000); |
776 | msh->request = jmb38x_ms_request; | 788 | msh->request = jmb38x_ms_request; |
777 | msh->set_param = jmb38x_ms_set_param; | 789 | msh->set_param = jmb38x_ms_set_param; |
778 | /* | 790 | |
779 | msh->caps = MEMSTICK_CAP_AUTO_GET_INT | MEMSTICK_CAP_PAR4 | ||
780 | | MEMSTICK_CAP_PAR8; | ||
781 | */ | ||
782 | msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; | 791 | msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8; |
783 | 792 | ||
784 | setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh); | 793 | setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh); |