.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/arch/arm/plat-omap/dma.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
15 | 16 | * |
---|
16 | 17 | * Support functions for the OMAP internal DMA channels. |
---|
17 | 18 | * |
---|
18 | | - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ |
---|
| 19 | + * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ |
---|
19 | 20 | * Converted DMA library into DMA platform driver. |
---|
20 | 21 | * - G, Manjunath Kondaiah <manjugk@ti.com> |
---|
21 | | - * |
---|
22 | | - * This program is free software; you can redistribute it and/or modify |
---|
23 | | - * it under the terms of the GNU General Public License version 2 as |
---|
24 | | - * published by the Free Software Foundation. |
---|
25 | | - * |
---|
26 | 22 | */ |
---|
27 | 23 | |
---|
28 | 24 | #include <linux/module.h> |
---|
.. | .. |
---|
69 | 65 | static struct omap_system_dma_plat_info *p; |
---|
70 | 66 | static struct omap_dma_dev_attr *d; |
---|
71 | 67 | static void omap_clear_dma(int lch); |
---|
72 | | -static int omap_dma_set_prio_lch(int lch, unsigned char read_prio, |
---|
73 | | - unsigned char write_prio); |
---|
74 | 68 | static int enable_1510_mode; |
---|
75 | 69 | static u32 errata; |
---|
76 | | - |
---|
77 | | -static struct omap_dma_global_context_registers { |
---|
78 | | - u32 dma_irqenable_l0; |
---|
79 | | - u32 dma_irqenable_l1; |
---|
80 | | - u32 dma_ocp_sysconfig; |
---|
81 | | - u32 dma_gcr; |
---|
82 | | -} omap_dma_global_context; |
---|
83 | 70 | |
---|
84 | 71 | struct dma_link_info { |
---|
85 | 72 | int *linked_dmach_q; |
---|
.. | .. |
---|
94 | 81 | |
---|
95 | 82 | }; |
---|
96 | 83 | |
---|
97 | | -static struct dma_link_info *dma_linked_lch; |
---|
98 | | - |
---|
99 | | -#ifndef CONFIG_ARCH_OMAP1 |
---|
100 | | - |
---|
101 | | -/* Chain handling macros */ |
---|
102 | | -#define OMAP_DMA_CHAIN_QINIT(chain_id) \ |
---|
103 | | - do { \ |
---|
104 | | - dma_linked_lch[chain_id].q_head = \ |
---|
105 | | - dma_linked_lch[chain_id].q_tail = \ |
---|
106 | | - dma_linked_lch[chain_id].q_count = 0; \ |
---|
107 | | - } while (0) |
---|
108 | | -#define OMAP_DMA_CHAIN_QFULL(chain_id) \ |
---|
109 | | - (dma_linked_lch[chain_id].no_of_lchs_linked == \ |
---|
110 | | - dma_linked_lch[chain_id].q_count) |
---|
111 | | -#define OMAP_DMA_CHAIN_QLAST(chain_id) \ |
---|
112 | | - do { \ |
---|
113 | | - ((dma_linked_lch[chain_id].no_of_lchs_linked-1) == \ |
---|
114 | | - dma_linked_lch[chain_id].q_count) \ |
---|
115 | | - } while (0) |
---|
116 | | -#define OMAP_DMA_CHAIN_QEMPTY(chain_id) \ |
---|
117 | | - (0 == dma_linked_lch[chain_id].q_count) |
---|
118 | | -#define __OMAP_DMA_CHAIN_INCQ(end) \ |
---|
119 | | - ((end) = ((end)+1) % dma_linked_lch[chain_id].no_of_lchs_linked) |
---|
120 | | -#define OMAP_DMA_CHAIN_INCQHEAD(chain_id) \ |
---|
121 | | - do { \ |
---|
122 | | - __OMAP_DMA_CHAIN_INCQ(dma_linked_lch[chain_id].q_head); \ |
---|
123 | | - dma_linked_lch[chain_id].q_count--; \ |
---|
124 | | - } while (0) |
---|
125 | | - |
---|
126 | | -#define OMAP_DMA_CHAIN_INCQTAIL(chain_id) \ |
---|
127 | | - do { \ |
---|
128 | | - __OMAP_DMA_CHAIN_INCQ(dma_linked_lch[chain_id].q_tail); \ |
---|
129 | | - dma_linked_lch[chain_id].q_count++; \ |
---|
130 | | - } while (0) |
---|
131 | | -#endif |
---|
132 | | - |
---|
133 | 84 | static int dma_lch_count; |
---|
134 | 85 | static int dma_chan_count; |
---|
135 | 86 | static int omap_dma_reserve_channels; |
---|
.. | .. |
---|
140 | 91 | static inline void disable_lnk(int lch); |
---|
141 | 92 | static void omap_disable_channel_irq(int lch); |
---|
142 | 93 | static inline void omap_enable_channel_irq(int lch); |
---|
143 | | - |
---|
144 | | -#define REVISIT_24XX() printk(KERN_ERR "FIXME: no %s on 24xx\n", \ |
---|
145 | | - __func__); |
---|
146 | 94 | |
---|
147 | 95 | #ifdef CONFIG_ARCH_OMAP15XX |
---|
148 | 96 | /* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */ |
---|
.. | .. |
---|
282 | 230 | } |
---|
283 | 231 | EXPORT_SYMBOL(omap_set_dma_transfer_params); |
---|
284 | 232 | |
---|
285 | | -void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode) |
---|
286 | | -{ |
---|
287 | | - if (dma_omap2plus()) { |
---|
288 | | - u32 csdp; |
---|
289 | | - |
---|
290 | | - csdp = p->dma_read(CSDP, lch); |
---|
291 | | - csdp &= ~(0x3 << 16); |
---|
292 | | - csdp |= (mode << 16); |
---|
293 | | - p->dma_write(csdp, CSDP, lch); |
---|
294 | | - } |
---|
295 | | -} |
---|
296 | | -EXPORT_SYMBOL(omap_set_dma_write_mode); |
---|
297 | | - |
---|
298 | 233 | void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode) |
---|
299 | 234 | { |
---|
300 | 235 | if (dma_omap1() && !dma_omap15xx()) { |
---|
.. | .. |
---|
336 | 271 | } |
---|
337 | 272 | EXPORT_SYMBOL(omap_set_dma_src_params); |
---|
338 | 273 | |
---|
339 | | -void omap_set_dma_params(int lch, struct omap_dma_channel_params *params) |
---|
340 | | -{ |
---|
341 | | - omap_set_dma_transfer_params(lch, params->data_type, |
---|
342 | | - params->elem_count, params->frame_count, |
---|
343 | | - params->sync_mode, params->trigger, |
---|
344 | | - params->src_or_dst_synch); |
---|
345 | | - omap_set_dma_src_params(lch, params->src_port, |
---|
346 | | - params->src_amode, params->src_start, |
---|
347 | | - params->src_ei, params->src_fi); |
---|
348 | | - |
---|
349 | | - omap_set_dma_dest_params(lch, params->dst_port, |
---|
350 | | - params->dst_amode, params->dst_start, |
---|
351 | | - params->dst_ei, params->dst_fi); |
---|
352 | | - if (params->read_prio || params->write_prio) |
---|
353 | | - omap_dma_set_prio_lch(lch, params->read_prio, |
---|
354 | | - params->write_prio); |
---|
355 | | -} |
---|
356 | | -EXPORT_SYMBOL(omap_set_dma_params); |
---|
357 | | - |
---|
358 | 274 | void omap_set_dma_src_data_pack(int lch, int enable) |
---|
359 | 275 | { |
---|
360 | 276 | u32 l; |
---|
.. | .. |
---|
392 | 308 | /* |
---|
393 | 309 | * not supported by current hardware on OMAP1 |
---|
394 | 310 | * w |= (0x03 << 7); |
---|
395 | | - * fall through |
---|
396 | 311 | */ |
---|
| 312 | + fallthrough; |
---|
397 | 313 | case OMAP_DMA_DATA_BURST_16: |
---|
398 | 314 | if (dma_omap2plus()) { |
---|
399 | 315 | burst = 0x3; |
---|
400 | 316 | break; |
---|
401 | 317 | } |
---|
402 | | - /* |
---|
403 | | - * OMAP1 don't support burst 16 |
---|
404 | | - * fall through |
---|
405 | | - */ |
---|
| 318 | + /* OMAP1 don't support burst 16 */ |
---|
| 319 | + fallthrough; |
---|
406 | 320 | default: |
---|
407 | 321 | BUG(); |
---|
408 | 322 | } |
---|
.. | .. |
---|
478 | 392 | burst = 0x3; |
---|
479 | 393 | break; |
---|
480 | 394 | } |
---|
481 | | - /* |
---|
482 | | - * OMAP1 don't support burst 16 |
---|
483 | | - * fall through |
---|
484 | | - */ |
---|
| 395 | + /* OMAP1 don't support burst 16 */ |
---|
| 396 | + fallthrough; |
---|
485 | 397 | default: |
---|
486 | 398 | printk(KERN_ERR "Invalid DMA burst mode\n"); |
---|
487 | 399 | BUG(); |
---|
.. | .. |
---|
515 | 427 | p->dma_write(OMAP2_DMA_CSR_CLEAR_MASK, CSR, lch); |
---|
516 | 428 | } |
---|
517 | 429 | |
---|
518 | | -void omap_enable_dma_irq(int lch, u16 bits) |
---|
519 | | -{ |
---|
520 | | - dma_chan[lch].enabled_irqs |= bits; |
---|
521 | | -} |
---|
522 | | -EXPORT_SYMBOL(omap_enable_dma_irq); |
---|
523 | | - |
---|
524 | 430 | void omap_disable_dma_irq(int lch, u16 bits) |
---|
525 | 431 | { |
---|
526 | 432 | dma_chan[lch].enabled_irqs &= ~bits; |
---|
.. | .. |
---|
539 | 445 | /* Set the ENABLE_LNK bits */ |
---|
540 | 446 | if (dma_chan[lch].next_lch != -1) |
---|
541 | 447 | l = dma_chan[lch].next_lch | (1 << 15); |
---|
542 | | - |
---|
543 | | -#ifndef CONFIG_ARCH_OMAP1 |
---|
544 | | - if (dma_omap2plus()) |
---|
545 | | - if (dma_chan[lch].next_linked_ch != -1) |
---|
546 | | - l = dma_chan[lch].next_linked_ch | (1 << 15); |
---|
547 | | -#endif |
---|
548 | 448 | |
---|
549 | 449 | p->dma_write(l, CLNK_CTRL, lch); |
---|
550 | 450 | } |
---|
.. | .. |
---|
570 | 470 | |
---|
571 | 471 | p->dma_write(l, CLNK_CTRL, lch); |
---|
572 | 472 | dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE; |
---|
573 | | -} |
---|
574 | | - |
---|
575 | | -static inline void omap2_enable_irq_lch(int lch) |
---|
576 | | -{ |
---|
577 | | - u32 val; |
---|
578 | | - unsigned long flags; |
---|
579 | | - |
---|
580 | | - if (dma_omap1()) |
---|
581 | | - return; |
---|
582 | | - |
---|
583 | | - spin_lock_irqsave(&dma_chan_lock, flags); |
---|
584 | | - /* clear IRQ STATUS */ |
---|
585 | | - p->dma_write(1 << lch, IRQSTATUS_L0, lch); |
---|
586 | | - /* Enable interrupt */ |
---|
587 | | - val = p->dma_read(IRQENABLE_L0, lch); |
---|
588 | | - val |= 1 << lch; |
---|
589 | | - p->dma_write(val, IRQENABLE_L0, lch); |
---|
590 | | - spin_unlock_irqrestore(&dma_chan_lock, flags); |
---|
591 | | -} |
---|
592 | | - |
---|
593 | | -static inline void omap2_disable_irq_lch(int lch) |
---|
594 | | -{ |
---|
595 | | - u32 val; |
---|
596 | | - unsigned long flags; |
---|
597 | | - |
---|
598 | | - if (dma_omap1()) |
---|
599 | | - return; |
---|
600 | | - |
---|
601 | | - spin_lock_irqsave(&dma_chan_lock, flags); |
---|
602 | | - /* Disable interrupt */ |
---|
603 | | - val = p->dma_read(IRQENABLE_L0, lch); |
---|
604 | | - val &= ~(1 << lch); |
---|
605 | | - p->dma_write(val, IRQENABLE_L0, lch); |
---|
606 | | - /* clear IRQ STATUS */ |
---|
607 | | - p->dma_write(1 << lch, IRQSTATUS_L0, lch); |
---|
608 | | - spin_unlock_irqrestore(&dma_chan_lock, flags); |
---|
609 | 473 | } |
---|
610 | 474 | |
---|
611 | 475 | int omap_request_dma(int dev_id, const char *dev_name, |
---|
.. | .. |
---|
636 | 500 | if (p->clear_lch_regs) |
---|
637 | 501 | p->clear_lch_regs(free_ch); |
---|
638 | 502 | |
---|
639 | | - if (dma_omap2plus()) |
---|
640 | | - omap_clear_dma(free_ch); |
---|
641 | | - |
---|
642 | 503 | spin_unlock_irqrestore(&dma_chan_lock, flags); |
---|
643 | 504 | |
---|
644 | 505 | chan->dev_name = dev_name; |
---|
.. | .. |
---|
646 | 507 | chan->data = data; |
---|
647 | 508 | chan->flags = 0; |
---|
648 | 509 | |
---|
649 | | -#ifndef CONFIG_ARCH_OMAP1 |
---|
650 | | - if (dma_omap2plus()) { |
---|
651 | | - chan->chain_id = -1; |
---|
652 | | - chan->next_linked_ch = -1; |
---|
653 | | - } |
---|
654 | | -#endif |
---|
655 | | - |
---|
656 | 510 | chan->enabled_irqs = OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; |
---|
657 | 511 | |
---|
658 | 512 | if (dma_omap1()) |
---|
659 | 513 | chan->enabled_irqs |= OMAP1_DMA_TOUT_IRQ; |
---|
660 | | - else if (dma_omap2plus()) |
---|
661 | | - chan->enabled_irqs |= OMAP2_DMA_MISALIGNED_ERR_IRQ | |
---|
662 | | - OMAP2_DMA_TRANS_ERR_IRQ; |
---|
663 | 514 | |
---|
664 | 515 | if (dma_omap16xx()) { |
---|
665 | 516 | /* If the sync device is set, configure it dynamically. */ |
---|
.. | .. |
---|
674 | 525 | p->dma_write(dev_id | (1 << 10), CCR, free_ch); |
---|
675 | 526 | } else if (dma_omap1()) { |
---|
676 | 527 | p->dma_write(dev_id, CCR, free_ch); |
---|
677 | | - } |
---|
678 | | - |
---|
679 | | - if (dma_omap2plus()) { |
---|
680 | | - omap_enable_channel_irq(free_ch); |
---|
681 | | - omap2_enable_irq_lch(free_ch); |
---|
682 | 528 | } |
---|
683 | 529 | |
---|
684 | 530 | *dma_ch_out = free_ch; |
---|
.. | .. |
---|
697 | 543 | return; |
---|
698 | 544 | } |
---|
699 | 545 | |
---|
700 | | - /* Disable interrupt for logical channel */ |
---|
701 | | - if (dma_omap2plus()) |
---|
702 | | - omap2_disable_irq_lch(lch); |
---|
703 | | - |
---|
704 | 546 | /* Disable all DMA interrupts for the channel. */ |
---|
705 | 547 | omap_disable_channel_irq(lch); |
---|
706 | 548 | |
---|
707 | 549 | /* Make sure the DMA transfer is stopped. */ |
---|
708 | 550 | p->dma_write(0, CCR, lch); |
---|
709 | | - |
---|
710 | | - /* Clear registers */ |
---|
711 | | - if (dma_omap2plus()) |
---|
712 | | - omap_clear_dma(lch); |
---|
713 | 551 | |
---|
714 | 552 | spin_lock_irqsave(&dma_chan_lock, flags); |
---|
715 | 553 | dma_chan[lch].dev_id = -1; |
---|
.. | .. |
---|
718 | 556 | spin_unlock_irqrestore(&dma_chan_lock, flags); |
---|
719 | 557 | } |
---|
720 | 558 | EXPORT_SYMBOL(omap_free_dma); |
---|
721 | | - |
---|
722 | | -/** |
---|
723 | | - * @brief omap_dma_set_global_params : Set global priority settings for dma |
---|
724 | | - * |
---|
725 | | - * @param arb_rate |
---|
726 | | - * @param max_fifo_depth |
---|
727 | | - * @param tparams - Number of threads to reserve : DMA_THREAD_RESERVE_NORM |
---|
728 | | - * DMA_THREAD_RESERVE_ONET |
---|
729 | | - * DMA_THREAD_RESERVE_TWOT |
---|
730 | | - * DMA_THREAD_RESERVE_THREET |
---|
731 | | - */ |
---|
732 | | -void |
---|
733 | | -omap_dma_set_global_params(int arb_rate, int max_fifo_depth, int tparams) |
---|
734 | | -{ |
---|
735 | | - u32 reg; |
---|
736 | | - |
---|
737 | | - if (dma_omap1()) { |
---|
738 | | - printk(KERN_ERR "FIXME: no %s on 15xx/16xx\n", __func__); |
---|
739 | | - return; |
---|
740 | | - } |
---|
741 | | - |
---|
742 | | - if (max_fifo_depth == 0) |
---|
743 | | - max_fifo_depth = 1; |
---|
744 | | - if (arb_rate == 0) |
---|
745 | | - arb_rate = 1; |
---|
746 | | - |
---|
747 | | - reg = 0xff & max_fifo_depth; |
---|
748 | | - reg |= (0x3 & tparams) << 12; |
---|
749 | | - reg |= (arb_rate & 0xff) << 16; |
---|
750 | | - |
---|
751 | | - p->dma_write(reg, GCR, 0); |
---|
752 | | -} |
---|
753 | | -EXPORT_SYMBOL(omap_dma_set_global_params); |
---|
754 | | - |
---|
755 | | -/** |
---|
756 | | - * @brief omap_dma_set_prio_lch : Set channel wise priority settings |
---|
757 | | - * |
---|
758 | | - * @param lch |
---|
759 | | - * @param read_prio - Read priority |
---|
760 | | - * @param write_prio - Write priority |
---|
761 | | - * Both of the above can be set with one of the following values : |
---|
762 | | - * DMA_CH_PRIO_HIGH/DMA_CH_PRIO_LOW |
---|
763 | | - */ |
---|
764 | | -static int |
---|
765 | | -omap_dma_set_prio_lch(int lch, unsigned char read_prio, |
---|
766 | | - unsigned char write_prio) |
---|
767 | | -{ |
---|
768 | | - u32 l; |
---|
769 | | - |
---|
770 | | - if (unlikely((lch < 0 || lch >= dma_lch_count))) { |
---|
771 | | - printk(KERN_ERR "Invalid channel id\n"); |
---|
772 | | - return -EINVAL; |
---|
773 | | - } |
---|
774 | | - l = p->dma_read(CCR, lch); |
---|
775 | | - l &= ~((1 << 6) | (1 << 26)); |
---|
776 | | - if (d->dev_caps & IS_RW_PRIORITY) |
---|
777 | | - l |= ((read_prio & 0x1) << 6) | ((write_prio & 0x1) << 26); |
---|
778 | | - else |
---|
779 | | - l |= ((read_prio & 0x1) << 6); |
---|
780 | | - |
---|
781 | | - p->dma_write(l, CCR, lch); |
---|
782 | | - |
---|
783 | | - return 0; |
---|
784 | | -} |
---|
785 | | - |
---|
786 | 559 | |
---|
787 | 560 | /* |
---|
788 | 561 | * Clears any DMA state so the DMA engine is ready to restart with new buffers |
---|
.. | .. |
---|
934 | 707 | * Allows changing the DMA callback function or data. This may be needed if |
---|
935 | 708 | * the driver shares a single DMA channel for multiple dma triggers. |
---|
936 | 709 | */ |
---|
937 | | -int omap_set_dma_callback(int lch, |
---|
938 | | - void (*callback)(int lch, u16 ch_status, void *data), |
---|
939 | | - void *data) |
---|
940 | | -{ |
---|
941 | | - unsigned long flags; |
---|
942 | | - |
---|
943 | | - if (lch < 0) |
---|
944 | | - return -ENODEV; |
---|
945 | | - |
---|
946 | | - spin_lock_irqsave(&dma_chan_lock, flags); |
---|
947 | | - if (dma_chan[lch].dev_id == -1) { |
---|
948 | | - printk(KERN_ERR "DMA callback for not set for free channel\n"); |
---|
949 | | - spin_unlock_irqrestore(&dma_chan_lock, flags); |
---|
950 | | - return -EINVAL; |
---|
951 | | - } |
---|
952 | | - dma_chan[lch].callback = callback; |
---|
953 | | - dma_chan[lch].data = data; |
---|
954 | | - spin_unlock_irqrestore(&dma_chan_lock, flags); |
---|
955 | | - |
---|
956 | | - return 0; |
---|
957 | | -} |
---|
958 | | -EXPORT_SYMBOL(omap_set_dma_callback); |
---|
959 | | - |
---|
960 | 710 | /* |
---|
961 | 711 | * Returns current physical source address for the given DMA channel. |
---|
962 | 712 | * If the channel is running the caller must disable interrupts prior calling |
---|
.. | .. |
---|
1056 | 806 | return 0; |
---|
1057 | 807 | } |
---|
1058 | 808 | |
---|
1059 | | -/* |
---|
1060 | | - * lch_queue DMA will start right after lch_head one is finished. |
---|
1061 | | - * For this DMA link to start, you still need to start (see omap_start_dma) |
---|
1062 | | - * the first one. That will fire up the entire queue. |
---|
1063 | | - */ |
---|
1064 | | -void omap_dma_link_lch(int lch_head, int lch_queue) |
---|
1065 | | -{ |
---|
1066 | | - if (omap_dma_in_1510_mode()) { |
---|
1067 | | - if (lch_head == lch_queue) { |
---|
1068 | | - p->dma_write(p->dma_read(CCR, lch_head) | (3 << 8), |
---|
1069 | | - CCR, lch_head); |
---|
1070 | | - return; |
---|
1071 | | - } |
---|
1072 | | - printk(KERN_ERR "DMA linking is not supported in 1510 mode\n"); |
---|
1073 | | - BUG(); |
---|
1074 | | - return; |
---|
1075 | | - } |
---|
1076 | | - |
---|
1077 | | - if ((dma_chan[lch_head].dev_id == -1) || |
---|
1078 | | - (dma_chan[lch_queue].dev_id == -1)) { |
---|
1079 | | - pr_err("omap_dma: trying to link non requested channels\n"); |
---|
1080 | | - dump_stack(); |
---|
1081 | | - } |
---|
1082 | | - |
---|
1083 | | - dma_chan[lch_head].next_lch = lch_queue; |
---|
1084 | | -} |
---|
1085 | | -EXPORT_SYMBOL(omap_dma_link_lch); |
---|
1086 | | - |
---|
1087 | 809 | /*----------------------------------------------------------------------------*/ |
---|
1088 | 810 | |
---|
1089 | 811 | #ifdef CONFIG_ARCH_OMAP1 |
---|
.. | .. |
---|
1144 | 866 | #define omap1_dma_irq_handler NULL |
---|
1145 | 867 | #endif |
---|
1146 | 868 | |
---|
1147 | | -#ifdef CONFIG_ARCH_OMAP2PLUS |
---|
1148 | | - |
---|
1149 | | -static int omap2_dma_handle_ch(int ch) |
---|
1150 | | -{ |
---|
1151 | | - u32 status = p->dma_read(CSR, ch); |
---|
1152 | | - |
---|
1153 | | - if (!status) { |
---|
1154 | | - if (printk_ratelimit()) |
---|
1155 | | - pr_warn("Spurious DMA IRQ for lch %d\n", ch); |
---|
1156 | | - p->dma_write(1 << ch, IRQSTATUS_L0, ch); |
---|
1157 | | - return 0; |
---|
1158 | | - } |
---|
1159 | | - if (unlikely(dma_chan[ch].dev_id == -1)) { |
---|
1160 | | - if (printk_ratelimit()) |
---|
1161 | | - pr_warn("IRQ %04x for non-allocated DMA channel %d\n", |
---|
1162 | | - status, ch); |
---|
1163 | | - return 0; |
---|
1164 | | - } |
---|
1165 | | - if (unlikely(status & OMAP_DMA_DROP_IRQ)) |
---|
1166 | | - pr_info("DMA synchronization event drop occurred with device %d\n", |
---|
1167 | | - dma_chan[ch].dev_id); |
---|
1168 | | - if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ)) { |
---|
1169 | | - printk(KERN_INFO "DMA transaction error with device %d\n", |
---|
1170 | | - dma_chan[ch].dev_id); |
---|
1171 | | - if (IS_DMA_ERRATA(DMA_ERRATA_i378)) { |
---|
1172 | | - u32 ccr; |
---|
1173 | | - |
---|
1174 | | - ccr = p->dma_read(CCR, ch); |
---|
1175 | | - ccr &= ~OMAP_DMA_CCR_EN; |
---|
1176 | | - p->dma_write(ccr, CCR, ch); |
---|
1177 | | - dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE; |
---|
1178 | | - } |
---|
1179 | | - } |
---|
1180 | | - if (unlikely(status & OMAP2_DMA_SECURE_ERR_IRQ)) |
---|
1181 | | - printk(KERN_INFO "DMA secure error with device %d\n", |
---|
1182 | | - dma_chan[ch].dev_id); |
---|
1183 | | - if (unlikely(status & OMAP2_DMA_MISALIGNED_ERR_IRQ)) |
---|
1184 | | - printk(KERN_INFO "DMA misaligned error with device %d\n", |
---|
1185 | | - dma_chan[ch].dev_id); |
---|
1186 | | - |
---|
1187 | | - p->dma_write(status, CSR, ch); |
---|
1188 | | - p->dma_write(1 << ch, IRQSTATUS_L0, ch); |
---|
1189 | | - /* read back the register to flush the write */ |
---|
1190 | | - p->dma_read(IRQSTATUS_L0, ch); |
---|
1191 | | - |
---|
1192 | | - /* If the ch is not chained then chain_id will be -1 */ |
---|
1193 | | - if (dma_chan[ch].chain_id != -1) { |
---|
1194 | | - int chain_id = dma_chan[ch].chain_id; |
---|
1195 | | - dma_chan[ch].state = DMA_CH_NOTSTARTED; |
---|
1196 | | - if (p->dma_read(CLNK_CTRL, ch) & (1 << 15)) |
---|
1197 | | - dma_chan[dma_chan[ch].next_linked_ch].state = |
---|
1198 | | - DMA_CH_STARTED; |
---|
1199 | | - if (dma_linked_lch[chain_id].chain_mode == |
---|
1200 | | - OMAP_DMA_DYNAMIC_CHAIN) |
---|
1201 | | - disable_lnk(ch); |
---|
1202 | | - |
---|
1203 | | - if (!OMAP_DMA_CHAIN_QEMPTY(chain_id)) |
---|
1204 | | - OMAP_DMA_CHAIN_INCQHEAD(chain_id); |
---|
1205 | | - |
---|
1206 | | - status = p->dma_read(CSR, ch); |
---|
1207 | | - p->dma_write(status, CSR, ch); |
---|
1208 | | - } |
---|
1209 | | - |
---|
1210 | | - if (likely(dma_chan[ch].callback != NULL)) |
---|
1211 | | - dma_chan[ch].callback(ch, status, dma_chan[ch].data); |
---|
1212 | | - |
---|
1213 | | - return 0; |
---|
1214 | | -} |
---|
1215 | | - |
---|
1216 | | -/* STATUS register count is from 1-32 while our is 0-31 */ |
---|
1217 | | -static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id) |
---|
1218 | | -{ |
---|
1219 | | - u32 val, enable_reg; |
---|
1220 | | - int i; |
---|
1221 | | - |
---|
1222 | | - val = p->dma_read(IRQSTATUS_L0, 0); |
---|
1223 | | - if (val == 0) { |
---|
1224 | | - if (printk_ratelimit()) |
---|
1225 | | - printk(KERN_WARNING "Spurious DMA IRQ\n"); |
---|
1226 | | - return IRQ_HANDLED; |
---|
1227 | | - } |
---|
1228 | | - enable_reg = p->dma_read(IRQENABLE_L0, 0); |
---|
1229 | | - val &= enable_reg; /* Dispatch only relevant interrupts */ |
---|
1230 | | - for (i = 0; i < dma_lch_count && val != 0; i++) { |
---|
1231 | | - if (val & 1) |
---|
1232 | | - omap2_dma_handle_ch(i); |
---|
1233 | | - val >>= 1; |
---|
1234 | | - } |
---|
1235 | | - |
---|
1236 | | - return IRQ_HANDLED; |
---|
1237 | | -} |
---|
1238 | | - |
---|
1239 | | -static struct irqaction omap24xx_dma_irq = { |
---|
1240 | | - .name = "DMA", |
---|
1241 | | - .handler = omap2_dma_irq_handler, |
---|
1242 | | -}; |
---|
1243 | | - |
---|
1244 | | -#else |
---|
1245 | | -static struct irqaction omap24xx_dma_irq; |
---|
1246 | | -#endif |
---|
1247 | | - |
---|
1248 | | -/*----------------------------------------------------------------------------*/ |
---|
1249 | | - |
---|
1250 | | -/* |
---|
1251 | | - * Note that we are currently using only IRQENABLE_L0 and L1. |
---|
1252 | | - * As the DSP may be using IRQENABLE_L2 and L3, let's not |
---|
1253 | | - * touch those for now. |
---|
1254 | | - */ |
---|
1255 | | -void omap_dma_global_context_save(void) |
---|
1256 | | -{ |
---|
1257 | | - omap_dma_global_context.dma_irqenable_l0 = |
---|
1258 | | - p->dma_read(IRQENABLE_L0, 0); |
---|
1259 | | - omap_dma_global_context.dma_irqenable_l1 = |
---|
1260 | | - p->dma_read(IRQENABLE_L1, 0); |
---|
1261 | | - omap_dma_global_context.dma_ocp_sysconfig = |
---|
1262 | | - p->dma_read(OCP_SYSCONFIG, 0); |
---|
1263 | | - omap_dma_global_context.dma_gcr = p->dma_read(GCR, 0); |
---|
1264 | | -} |
---|
1265 | | - |
---|
1266 | | -void omap_dma_global_context_restore(void) |
---|
1267 | | -{ |
---|
1268 | | - int ch; |
---|
1269 | | - |
---|
1270 | | - p->dma_write(omap_dma_global_context.dma_gcr, GCR, 0); |
---|
1271 | | - p->dma_write(omap_dma_global_context.dma_ocp_sysconfig, |
---|
1272 | | - OCP_SYSCONFIG, 0); |
---|
1273 | | - p->dma_write(omap_dma_global_context.dma_irqenable_l0, |
---|
1274 | | - IRQENABLE_L0, 0); |
---|
1275 | | - p->dma_write(omap_dma_global_context.dma_irqenable_l1, |
---|
1276 | | - IRQENABLE_L1, 0); |
---|
1277 | | - |
---|
1278 | | - if (IS_DMA_ERRATA(DMA_ROMCODE_BUG)) |
---|
1279 | | - p->dma_write(0x3 , IRQSTATUS_L0, 0); |
---|
1280 | | - |
---|
1281 | | - for (ch = 0; ch < dma_chan_count; ch++) |
---|
1282 | | - if (dma_chan[ch].dev_id != -1) |
---|
1283 | | - omap_clear_dma(ch); |
---|
1284 | | -} |
---|
1285 | | - |
---|
1286 | 869 | struct omap_system_dma_plat_info *omap_get_plat_info(void) |
---|
1287 | 870 | { |
---|
1288 | 871 | return p; |
---|
.. | .. |
---|
1294 | 877 | int ch, ret = 0; |
---|
1295 | 878 | int dma_irq; |
---|
1296 | 879 | char irq_name[4]; |
---|
1297 | | - int irq_rel; |
---|
1298 | 880 | |
---|
1299 | 881 | p = pdev->dev.platform_data; |
---|
1300 | 882 | if (!p) { |
---|
.. | .. |
---|
1320 | 902 | if (!dma_chan) |
---|
1321 | 903 | return -ENOMEM; |
---|
1322 | 904 | |
---|
1323 | | - if (dma_omap2plus()) { |
---|
1324 | | - dma_linked_lch = kcalloc(dma_lch_count, |
---|
1325 | | - sizeof(*dma_linked_lch), |
---|
1326 | | - GFP_KERNEL); |
---|
1327 | | - if (!dma_linked_lch) { |
---|
1328 | | - ret = -ENOMEM; |
---|
1329 | | - goto exit_dma_lch_fail; |
---|
1330 | | - } |
---|
1331 | | - } |
---|
1332 | | - |
---|
1333 | 905 | spin_lock_init(&dma_chan_lock); |
---|
1334 | 906 | for (ch = 0; ch < dma_chan_count; ch++) { |
---|
1335 | 907 | omap_clear_dma(ch); |
---|
1336 | | - if (dma_omap2plus()) |
---|
1337 | | - omap2_disable_irq_lch(ch); |
---|
1338 | 908 | |
---|
1339 | 909 | dma_chan[ch].dev_id = -1; |
---|
1340 | 910 | dma_chan[ch].next_lch = -1; |
---|
.. | .. |
---|
1367 | 937 | } |
---|
1368 | 938 | } |
---|
1369 | 939 | |
---|
1370 | | - if (d->dev_caps & IS_RW_PRIORITY) |
---|
1371 | | - omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, |
---|
1372 | | - DMA_DEFAULT_FIFO_DEPTH, 0); |
---|
1373 | | - |
---|
1374 | | - if (dma_omap2plus() && !(d->dev_caps & DMA_ENGINE_HANDLE_IRQ)) { |
---|
1375 | | - strcpy(irq_name, "0"); |
---|
1376 | | - dma_irq = platform_get_irq_byname(pdev, irq_name); |
---|
1377 | | - if (dma_irq < 0) { |
---|
1378 | | - dev_err(&pdev->dev, "failed: request IRQ %d", dma_irq); |
---|
1379 | | - ret = dma_irq; |
---|
1380 | | - goto exit_dma_lch_fail; |
---|
1381 | | - } |
---|
1382 | | - ret = setup_irq(dma_irq, &omap24xx_dma_irq); |
---|
1383 | | - if (ret) { |
---|
1384 | | - dev_err(&pdev->dev, "set_up failed for IRQ %d for DMA (error %d)\n", |
---|
1385 | | - dma_irq, ret); |
---|
1386 | | - goto exit_dma_lch_fail; |
---|
1387 | | - } |
---|
1388 | | - } |
---|
1389 | | - |
---|
1390 | 940 | /* reserve dma channels 0 and 1 in high security devices on 34xx */ |
---|
1391 | 941 | if (d->dev_caps & HS_CHANNELS_RESERVED) { |
---|
1392 | 942 | pr_info("Reserving DMA channels 0 and 1 for HS ROM code\n"); |
---|
.. | .. |
---|
1397 | 947 | return 0; |
---|
1398 | 948 | |
---|
1399 | 949 | exit_dma_irq_fail: |
---|
1400 | | - dev_err(&pdev->dev, "unable to request IRQ %d for DMA (error %d)\n", |
---|
1401 | | - dma_irq, ret); |
---|
1402 | | - for (irq_rel = 0; irq_rel < ch; irq_rel++) { |
---|
1403 | | - dma_irq = platform_get_irq(pdev, irq_rel); |
---|
1404 | | - free_irq(dma_irq, (void *)(irq_rel + 1)); |
---|
1405 | | - } |
---|
1406 | | - |
---|
1407 | | -exit_dma_lch_fail: |
---|
1408 | 950 | return ret; |
---|
1409 | 951 | } |
---|
1410 | 952 | |
---|
1411 | 953 | static int omap_system_dma_remove(struct platform_device *pdev) |
---|
1412 | 954 | { |
---|
1413 | | - int dma_irq; |
---|
| 955 | + int dma_irq, irq_rel = 0; |
---|
1414 | 956 | |
---|
1415 | | - if (dma_omap2plus()) { |
---|
1416 | | - char irq_name[4]; |
---|
1417 | | - strcpy(irq_name, "0"); |
---|
1418 | | - dma_irq = platform_get_irq_byname(pdev, irq_name); |
---|
1419 | | - if (dma_irq >= 0) |
---|
1420 | | - remove_irq(dma_irq, &omap24xx_dma_irq); |
---|
1421 | | - } else { |
---|
1422 | | - int irq_rel = 0; |
---|
1423 | | - for ( ; irq_rel < dma_chan_count; irq_rel++) { |
---|
1424 | | - dma_irq = platform_get_irq(pdev, irq_rel); |
---|
1425 | | - free_irq(dma_irq, (void *)(irq_rel + 1)); |
---|
1426 | | - } |
---|
| 957 | + if (dma_omap2plus()) |
---|
| 958 | + return 0; |
---|
| 959 | + |
---|
| 960 | + for ( ; irq_rel < dma_chan_count; irq_rel++) { |
---|
| 961 | + dma_irq = platform_get_irq(pdev, irq_rel); |
---|
| 962 | + free_irq(dma_irq, (void *)(irq_rel + 1)); |
---|
1427 | 963 | } |
---|
| 964 | + |
---|
1428 | 965 | return 0; |
---|
1429 | 966 | } |
---|
1430 | 967 | |
---|
.. | .. |
---|
1449 | 986 | |
---|
1450 | 987 | MODULE_DESCRIPTION("OMAP SYSTEM DMA DRIVER"); |
---|
1451 | 988 | MODULE_LICENSE("GPL"); |
---|
1452 | | -MODULE_ALIAS("platform:" DRIVER_NAME); |
---|
1453 | 989 | MODULE_AUTHOR("Texas Instruments Inc"); |
---|
1454 | 990 | |
---|
1455 | 991 | /* |
---|