diff options
Diffstat (limited to 'drivers/dma/coh901318.c')
-rw-r--r-- | drivers/dma/coh901318.c | 153 |
1 files changed, 70 insertions, 83 deletions
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index e88588d8ecd3..fd22dd36985f 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c | |||
@@ -1690,7 +1690,7 @@ static u32 coh901318_get_bytes_left(struct dma_chan *chan) | |||
1690 | * Pauses a transfer without losing data. Enables power save. | 1690 | * Pauses a transfer without losing data. Enables power save. |
1691 | * Use this function in conjunction with coh901318_resume. | 1691 | * Use this function in conjunction with coh901318_resume. |
1692 | */ | 1692 | */ |
1693 | static void coh901318_pause(struct dma_chan *chan) | 1693 | static int coh901318_pause(struct dma_chan *chan) |
1694 | { | 1694 | { |
1695 | u32 val; | 1695 | u32 val; |
1696 | unsigned long flags; | 1696 | unsigned long flags; |
@@ -1730,12 +1730,13 @@ static void coh901318_pause(struct dma_chan *chan) | |||
1730 | enable_powersave(cohc); | 1730 | enable_powersave(cohc); |
1731 | 1731 | ||
1732 | spin_unlock_irqrestore(&cohc->lock, flags); | 1732 | spin_unlock_irqrestore(&cohc->lock, flags); |
1733 | return 0; | ||
1733 | } | 1734 | } |
1734 | 1735 | ||
1735 | /* Resumes a transfer that has been stopped via 300_dma_stop(..). | 1736 | /* Resumes a transfer that has been stopped via 300_dma_stop(..). |
1736 | Power save is handled. | 1737 | Power save is handled. |
1737 | */ | 1738 | */ |
1738 | static void coh901318_resume(struct dma_chan *chan) | 1739 | static int coh901318_resume(struct dma_chan *chan) |
1739 | { | 1740 | { |
1740 | u32 val; | 1741 | u32 val; |
1741 | unsigned long flags; | 1742 | unsigned long flags; |
@@ -1760,6 +1761,7 @@ static void coh901318_resume(struct dma_chan *chan) | |||
1760 | } | 1761 | } |
1761 | 1762 | ||
1762 | spin_unlock_irqrestore(&cohc->lock, flags); | 1763 | spin_unlock_irqrestore(&cohc->lock, flags); |
1764 | return 0; | ||
1763 | } | 1765 | } |
1764 | 1766 | ||
1765 | bool coh901318_filter_id(struct dma_chan *chan, void *chan_id) | 1767 | bool coh901318_filter_id(struct dma_chan *chan, void *chan_id) |
@@ -2114,6 +2116,57 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) | |||
2114 | return IRQ_HANDLED; | 2116 | return IRQ_HANDLED; |
2115 | } | 2117 | } |
2116 | 2118 | ||
2119 | static int coh901318_terminate_all(struct dma_chan *chan) | ||
2120 | { | ||
2121 | unsigned long flags; | ||
2122 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | ||
2123 | struct coh901318_desc *cohd; | ||
2124 | void __iomem *virtbase = cohc->base->virtbase; | ||
2125 | |||
2126 | /* The remainder of this function terminates the transfer */ | ||
2127 | coh901318_pause(chan); | ||
2128 | spin_lock_irqsave(&cohc->lock, flags); | ||
2129 | |||
2130 | /* Clear any pending BE or TC interrupt */ | ||
2131 | if (cohc->id < 32) { | ||
2132 | writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1); | ||
2133 | writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1); | ||
2134 | } else { | ||
2135 | writel(1 << (cohc->id - 32), virtbase + | ||
2136 | COH901318_BE_INT_CLEAR2); | ||
2137 | writel(1 << (cohc->id - 32), virtbase + | ||
2138 | COH901318_TC_INT_CLEAR2); | ||
2139 | } | ||
2140 | |||
2141 | enable_powersave(cohc); | ||
2142 | |||
2143 | while ((cohd = coh901318_first_active_get(cohc))) { | ||
2144 | /* release the lli allocation*/ | ||
2145 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); | ||
2146 | |||
2147 | /* return desc to free-list */ | ||
2148 | coh901318_desc_remove(cohd); | ||
2149 | coh901318_desc_free(cohc, cohd); | ||
2150 | } | ||
2151 | |||
2152 | while ((cohd = coh901318_first_queued(cohc))) { | ||
2153 | /* release the lli allocation*/ | ||
2154 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); | ||
2155 | |||
2156 | /* return desc to free-list */ | ||
2157 | coh901318_desc_remove(cohd); | ||
2158 | coh901318_desc_free(cohc, cohd); | ||
2159 | } | ||
2160 | |||
2161 | |||
2162 | cohc->nbr_active_done = 0; | ||
2163 | cohc->busy = 0; | ||
2164 | |||
2165 | spin_unlock_irqrestore(&cohc->lock, flags); | ||
2166 | |||
2167 | return 0; | ||
2168 | } | ||
2169 | |||
2117 | static int coh901318_alloc_chan_resources(struct dma_chan *chan) | 2170 | static int coh901318_alloc_chan_resources(struct dma_chan *chan) |
2118 | { | 2171 | { |
2119 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 2172 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
@@ -2156,7 +2209,7 @@ coh901318_free_chan_resources(struct dma_chan *chan) | |||
2156 | 2209 | ||
2157 | spin_unlock_irqrestore(&cohc->lock, flags); | 2210 | spin_unlock_irqrestore(&cohc->lock, flags); |
2158 | 2211 | ||
2159 | dmaengine_terminate_all(chan); | 2212 | coh901318_terminate_all(chan); |
2160 | } | 2213 | } |
2161 | 2214 | ||
2162 | 2215 | ||
@@ -2461,8 +2514,8 @@ static const struct burst_table burst_sizes[] = { | |||
2461 | }, | 2514 | }, |
2462 | }; | 2515 | }; |
2463 | 2516 | ||
2464 | static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan, | 2517 | static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan, |
2465 | struct dma_slave_config *config) | 2518 | struct dma_slave_config *config) |
2466 | { | 2519 | { |
2467 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | 2520 | struct coh901318_chan *cohc = to_coh901318_chan(chan); |
2468 | dma_addr_t addr; | 2521 | dma_addr_t addr; |
@@ -2482,7 +2535,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan, | |||
2482 | maxburst = config->dst_maxburst; | 2535 | maxburst = config->dst_maxburst; |
2483 | } else { | 2536 | } else { |
2484 | dev_err(COHC_2_DEV(cohc), "illegal channel mode\n"); | 2537 | dev_err(COHC_2_DEV(cohc), "illegal channel mode\n"); |
2485 | return; | 2538 | return -EINVAL; |
2486 | } | 2539 | } |
2487 | 2540 | ||
2488 | dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n", | 2541 | dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n", |
@@ -2528,7 +2581,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan, | |||
2528 | default: | 2581 | default: |
2529 | dev_err(COHC_2_DEV(cohc), | 2582 | dev_err(COHC_2_DEV(cohc), |
2530 | "bad runtimeconfig: alien address width\n"); | 2583 | "bad runtimeconfig: alien address width\n"); |
2531 | return; | 2584 | return -EINVAL; |
2532 | } | 2585 | } |
2533 | 2586 | ||
2534 | ctrl |= burst_sizes[i].reg; | 2587 | ctrl |= burst_sizes[i].reg; |
@@ -2538,84 +2591,12 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan, | |||
2538 | 2591 | ||
2539 | cohc->addr = addr; | 2592 | cohc->addr = addr; |
2540 | cohc->ctrl = ctrl; | 2593 | cohc->ctrl = ctrl; |
2541 | } | ||
2542 | |||
2543 | static int | ||
2544 | coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | ||
2545 | unsigned long arg) | ||
2546 | { | ||
2547 | unsigned long flags; | ||
2548 | struct coh901318_chan *cohc = to_coh901318_chan(chan); | ||
2549 | struct coh901318_desc *cohd; | ||
2550 | void __iomem *virtbase = cohc->base->virtbase; | ||
2551 | |||
2552 | if (cmd == DMA_SLAVE_CONFIG) { | ||
2553 | struct dma_slave_config *config = | ||
2554 | (struct dma_slave_config *) arg; | ||
2555 | |||
2556 | coh901318_dma_set_runtimeconfig(chan, config); | ||
2557 | return 0; | ||
2558 | } | ||
2559 | |||
2560 | if (cmd == DMA_PAUSE) { | ||
2561 | coh901318_pause(chan); | ||
2562 | return 0; | ||
2563 | } | ||
2564 | |||
2565 | if (cmd == DMA_RESUME) { | ||
2566 | coh901318_resume(chan); | ||
2567 | return 0; | ||
2568 | } | ||
2569 | |||
2570 | if (cmd != DMA_TERMINATE_ALL) | ||
2571 | return -ENXIO; | ||
2572 | |||
2573 | /* The remainder of this function terminates the transfer */ | ||
2574 | coh901318_pause(chan); | ||
2575 | spin_lock_irqsave(&cohc->lock, flags); | ||
2576 | |||
2577 | /* Clear any pending BE or TC interrupt */ | ||
2578 | if (cohc->id < 32) { | ||
2579 | writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1); | ||
2580 | writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1); | ||
2581 | } else { | ||
2582 | writel(1 << (cohc->id - 32), virtbase + | ||
2583 | COH901318_BE_INT_CLEAR2); | ||
2584 | writel(1 << (cohc->id - 32), virtbase + | ||
2585 | COH901318_TC_INT_CLEAR2); | ||
2586 | } | ||
2587 | |||
2588 | enable_powersave(cohc); | ||
2589 | |||
2590 | while ((cohd = coh901318_first_active_get(cohc))) { | ||
2591 | /* release the lli allocation*/ | ||
2592 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); | ||
2593 | |||
2594 | /* return desc to free-list */ | ||
2595 | coh901318_desc_remove(cohd); | ||
2596 | coh901318_desc_free(cohc, cohd); | ||
2597 | } | ||
2598 | |||
2599 | while ((cohd = coh901318_first_queued(cohc))) { | ||
2600 | /* release the lli allocation*/ | ||
2601 | coh901318_lli_free(&cohc->base->pool, &cohd->lli); | ||
2602 | |||
2603 | /* return desc to free-list */ | ||
2604 | coh901318_desc_remove(cohd); | ||
2605 | coh901318_desc_free(cohc, cohd); | ||
2606 | } | ||
2607 | |||
2608 | |||
2609 | cohc->nbr_active_done = 0; | ||
2610 | cohc->busy = 0; | ||
2611 | |||
2612 | spin_unlock_irqrestore(&cohc->lock, flags); | ||
2613 | 2594 | ||
2614 | return 0; | 2595 | return 0; |
2615 | } | 2596 | } |
2616 | 2597 | ||
2617 | void coh901318_base_init(struct dma_device *dma, const int *pick_chans, | 2598 | static void coh901318_base_init(struct dma_device *dma, const int *pick_chans, |
2618 | struct coh901318_base *base) | 2599 | struct coh901318_base *base) |
2619 | { | 2600 | { |
2620 | int chans_i; | 2601 | int chans_i; |
2621 | int i = 0; | 2602 | int i = 0; |
@@ -2717,7 +2698,10 @@ static int __init coh901318_probe(struct platform_device *pdev) | |||
2717 | base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; | 2698 | base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; |
2718 | base->dma_slave.device_tx_status = coh901318_tx_status; | 2699 | base->dma_slave.device_tx_status = coh901318_tx_status; |
2719 | base->dma_slave.device_issue_pending = coh901318_issue_pending; | 2700 | base->dma_slave.device_issue_pending = coh901318_issue_pending; |
2720 | base->dma_slave.device_control = coh901318_control; | 2701 | base->dma_slave.device_config = coh901318_dma_set_runtimeconfig; |
2702 | base->dma_slave.device_pause = coh901318_pause; | ||
2703 | base->dma_slave.device_resume = coh901318_resume; | ||
2704 | base->dma_slave.device_terminate_all = coh901318_terminate_all; | ||
2721 | base->dma_slave.dev = &pdev->dev; | 2705 | base->dma_slave.dev = &pdev->dev; |
2722 | 2706 | ||
2723 | err = dma_async_device_register(&base->dma_slave); | 2707 | err = dma_async_device_register(&base->dma_slave); |
@@ -2737,7 +2721,10 @@ static int __init coh901318_probe(struct platform_device *pdev) | |||
2737 | base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; | 2721 | base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; |
2738 | base->dma_memcpy.device_tx_status = coh901318_tx_status; | 2722 | base->dma_memcpy.device_tx_status = coh901318_tx_status; |
2739 | base->dma_memcpy.device_issue_pending = coh901318_issue_pending; | 2723 | base->dma_memcpy.device_issue_pending = coh901318_issue_pending; |
2740 | base->dma_memcpy.device_control = coh901318_control; | 2724 | base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig; |
2725 | base->dma_memcpy.device_pause = coh901318_pause; | ||
2726 | base->dma_memcpy.device_resume = coh901318_resume; | ||
2727 | base->dma_memcpy.device_terminate_all = coh901318_terminate_all; | ||
2741 | base->dma_memcpy.dev = &pdev->dev; | 2728 | base->dma_memcpy.dev = &pdev->dev; |
2742 | /* | 2729 | /* |
2743 | * This controller can only access address at even 32bit boundaries, | 2730 | * This controller can only access address at even 32bit boundaries, |