| .. | .. |
|---|
| 18 | 18 | #include <linux/uaccess.h> |
|---|
| 19 | 19 | #include <linux/regmap.h> |
|---|
| 20 | 20 | #include <linux/proc_fs.h> |
|---|
| 21 | +#include <linux/mfd/syscon.h> |
|---|
| 22 | +#include <linux/rockchip/cpu.h> |
|---|
| 21 | 23 | #include <soc/rockchip/pm_domains.h> |
|---|
| 22 | 24 | |
|---|
| 23 | 25 | #include "mpp_debug.h" |
|---|
| .. | .. |
|---|
| 27 | 29 | #define VDPP_DRIVER_NAME "mpp_vdpp" |
|---|
| 28 | 30 | |
|---|
| 29 | 31 | #define VDPP_SESSION_MAX_BUFFERS 15 |
|---|
| 32 | +#define VDPP_REG_WORK_MODE 0x0008 |
|---|
| 33 | +#define VDPP_REG_VDPP_MODE BIT(1) |
|---|
| 30 | 34 | |
|---|
| 31 | 35 | #define to_vdpp_info(info) \ |
|---|
| 32 | 36 | container_of(info, struct vdpp_hw_info, hw) |
|---|
| .. | .. |
|---|
| 87 | 91 | struct reset_control *rst_s; |
|---|
| 88 | 92 | /* for zme */ |
|---|
| 89 | 93 | void __iomem *zme_base; |
|---|
| 94 | + struct regmap *grf; |
|---|
| 90 | 95 | }; |
|---|
| 91 | 96 | |
|---|
| 92 | 97 | static struct vdpp_hw_info vdpp_v1_hw_info = { |
|---|
| .. | .. |
|---|
| 332 | 337 | } |
|---|
| 333 | 338 | } |
|---|
| 334 | 339 | |
|---|
| 340 | + /* flush tlb before starting hardware */ |
|---|
| 341 | + mpp_iommu_flush_tlb(mpp->iommu_info); |
|---|
| 342 | + |
|---|
| 335 | 343 | /* init current task */ |
|---|
| 336 | 344 | mpp->cur_task = mpp_task; |
|---|
| 337 | 345 | /* Flush the register before the start the device */ |
|---|
| .. | .. |
|---|
| 474 | 482 | int ret; |
|---|
| 475 | 483 | struct vdpp_dev *vdpp = to_vdpp_dev(mpp); |
|---|
| 476 | 484 | |
|---|
| 485 | + mpp->grf_info = &mpp->srv->grf_infos[MPP_DRIVER_VDPP]; |
|---|
| 486 | + |
|---|
| 477 | 487 | /* Get clock info from dtsi */ |
|---|
| 478 | 488 | ret = mpp_get_clk_info(mpp, &vdpp->aclk_info, "aclk"); |
|---|
| 479 | 489 | if (ret) |
|---|
| .. | .. |
|---|
| 546 | 556 | { |
|---|
| 547 | 557 | struct vdpp_dev *vdpp = to_vdpp_dev(mpp); |
|---|
| 548 | 558 | struct vdpp_hw_info *hw_info = vdpp->hw_info; |
|---|
| 559 | + u32 work_mode = mpp_read(mpp, VDPP_REG_WORK_MODE); |
|---|
| 549 | 560 | |
|---|
| 561 | + if (!(work_mode & VDPP_REG_VDPP_MODE)) |
|---|
| 562 | + return IRQ_NONE; |
|---|
| 550 | 563 | mpp->irq_status = mpp_read(mpp, hw_info->int_sta_base); |
|---|
| 551 | 564 | if (!(mpp->irq_status & hw_info->int_mask)) |
|---|
| 552 | 565 | return IRQ_NONE; |
|---|
| 553 | 566 | mpp_write(mpp, hw_info->int_en_base, 0); |
|---|
| 554 | 567 | mpp_write(mpp, hw_info->int_clr_base, mpp->irq_status); |
|---|
| 568 | + |
|---|
| 569 | + /* ensure hardware is being off status */ |
|---|
| 570 | + mpp_write(mpp, hw_info->start_base, 0); |
|---|
| 555 | 571 | |
|---|
| 556 | 572 | return IRQ_WAKE_THREAD; |
|---|
| 557 | 573 | } |
|---|
| .. | .. |
|---|
| 590 | 606 | mpp_debug(DEBUG_RESET, "reset in\n"); |
|---|
| 591 | 607 | |
|---|
| 592 | 608 | /* Don't skip this or iommu won't work after reset */ |
|---|
| 593 | | - rockchip_pmu_idle_request(mpp->dev, true); |
|---|
| 609 | + mpp_pmu_idle_request(mpp, true); |
|---|
| 594 | 610 | mpp_safe_reset(vdpp->rst_a); |
|---|
| 595 | 611 | mpp_safe_reset(vdpp->rst_h); |
|---|
| 596 | 612 | mpp_safe_reset(vdpp->rst_s); |
|---|
| .. | .. |
|---|
| 598 | 614 | mpp_safe_unreset(vdpp->rst_a); |
|---|
| 599 | 615 | mpp_safe_unreset(vdpp->rst_h); |
|---|
| 600 | 616 | mpp_safe_unreset(vdpp->rst_s); |
|---|
| 601 | | - rockchip_pmu_idle_request(mpp->dev, false); |
|---|
| 617 | + mpp_pmu_idle_request(mpp, false); |
|---|
| 602 | 618 | |
|---|
| 603 | 619 | mpp_debug(DEBUG_RESET, "reset out\n"); |
|---|
| 604 | 620 | } |
|---|
| .. | .. |
|---|
| 617 | 633 | mpp_write(mpp, hw_info->cfg_base, hw_info->bit_rst_en); |
|---|
| 618 | 634 | ret = readl_relaxed_poll_timeout(mpp->reg_base + hw_info->rst_sta_base, |
|---|
| 619 | 635 | rst_status, |
|---|
| 620 | | - !(rst_status & hw_info->bit_rst_done), |
|---|
| 621 | | - 0, 2); |
|---|
| 636 | + rst_status & hw_info->bit_rst_done, |
|---|
| 637 | + 0, 5); |
|---|
| 622 | 638 | if (ret) { |
|---|
| 623 | 639 | mpp_err("soft reset timeout, use cru reset\n"); |
|---|
| 624 | 640 | return _vdpp_reset(mpp, vdpp); |
|---|
| 625 | 641 | } |
|---|
| 626 | 642 | |
|---|
| 627 | 643 | mpp_write(mpp, hw_info->rst_sta_base, 0); |
|---|
| 644 | + |
|---|
| 645 | + /* ensure hardware is being off status */ |
|---|
| 646 | + mpp_write(mpp, hw_info->start_base, 0); |
|---|
| 647 | + |
|---|
| 628 | 648 | |
|---|
| 629 | 649 | return 0; |
|---|
| 630 | 650 | } |
|---|
| .. | .. |
|---|
| 710 | 730 | dev_err(dev, "register interrupter runtime failed\n"); |
|---|
| 711 | 731 | return -EINVAL; |
|---|
| 712 | 732 | } |
|---|
| 733 | + |
|---|
| 713 | 734 | mpp->session_max_buffers = VDPP_SESSION_MAX_BUFFERS; |
|---|
| 714 | 735 | vdpp->hw_info = to_vdpp_info(mpp->var->hw_info); |
|---|
| 715 | 736 | vdpp_procfs_init(mpp); |
|---|
| .. | .. |
|---|
| 751 | 772 | dev_err(dev, "wait total running time out\n"); |
|---|
| 752 | 773 | } |
|---|
| 753 | 774 | |
|---|
| 775 | +static int vdpp_runtime_suspend(struct device *dev) |
|---|
| 776 | +{ |
|---|
| 777 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
|---|
| 778 | + struct mpp_grf_info *info = mpp->grf_info; |
|---|
| 779 | + struct mpp_taskqueue *queue = mpp->queue; |
|---|
| 780 | + |
|---|
| 781 | + if (cpu_is_rk3528() && info && info->mem_offset) { |
|---|
| 782 | + mutex_lock(&queue->ref_lock); |
|---|
| 783 | + if (!atomic_dec_if_positive(&queue->runtime_cnt)) { |
|---|
| 784 | + regmap_write(info->grf, info->mem_offset, |
|---|
| 785 | + info->val_mem_off); |
|---|
| 786 | + } |
|---|
| 787 | + mutex_unlock(&queue->ref_lock); |
|---|
| 788 | + } |
|---|
| 789 | + |
|---|
| 790 | + return 0; |
|---|
| 791 | +} |
|---|
| 792 | + |
|---|
| 793 | +static int vdpp_runtime_resume(struct device *dev) |
|---|
| 794 | +{ |
|---|
| 795 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
|---|
| 796 | + struct mpp_grf_info *info = mpp->grf_info; |
|---|
| 797 | + struct mpp_taskqueue *queue = mpp->queue; |
|---|
| 798 | + |
|---|
| 799 | + if (cpu_is_rk3528() && info && info->mem_offset) { |
|---|
| 800 | + mutex_lock(&queue->ref_lock); |
|---|
| 801 | + regmap_write(info->grf, info->mem_offset, |
|---|
| 802 | + info->val_mem_on); |
|---|
| 803 | + atomic_inc(&queue->runtime_cnt); |
|---|
| 804 | + mutex_unlock(&queue->ref_lock); |
|---|
| 805 | + } |
|---|
| 806 | + |
|---|
| 807 | + return 0; |
|---|
| 808 | +} |
|---|
| 809 | + |
|---|
| 810 | +static const struct dev_pm_ops vdpp_pm_ops = { |
|---|
| 811 | + .runtime_suspend = vdpp_runtime_suspend, |
|---|
| 812 | + .runtime_resume = vdpp_runtime_resume, |
|---|
| 813 | +}; |
|---|
| 814 | + |
|---|
| 754 | 815 | struct platform_driver rockchip_vdpp_driver = { |
|---|
| 755 | 816 | .probe = vdpp_probe, |
|---|
| 756 | 817 | .remove = vdpp_remove, |
|---|
| 757 | 818 | .shutdown = vdpp_shutdown, |
|---|
| 758 | 819 | .driver = { |
|---|
| 759 | 820 | .name = VDPP_DRIVER_NAME, |
|---|
| 821 | + .pm = &vdpp_pm_ops, |
|---|
| 760 | 822 | .of_match_table = of_match_ptr(mpp_vdpp_dt_match), |
|---|
| 761 | 823 | }, |
|---|
| 762 | 824 | }; |
|---|