| .. | .. |
|---|
| 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 | /* |
|---|