.. | .. |
---|
20 | 20 | #include <linux/regmap.h> |
---|
21 | 21 | #include <linux/pm_runtime.h> |
---|
22 | 22 | #include <linux/proc_fs.h> |
---|
| 23 | +#include <linux/mfd/syscon.h> |
---|
| 24 | +#include <linux/rockchip/cpu.h> |
---|
23 | 25 | #include <soc/rockchip/pm_domains.h> |
---|
24 | 26 | |
---|
25 | 27 | #include "rockchip_iep2_regs.h" |
---|
.. | .. |
---|
389 | 391 | | IEP2_REG_DIL_OSD_EN |
---|
390 | 392 | | IEP2_REG_DIL_PD_EN |
---|
391 | 393 | | IEP2_REG_DIL_FF_EN |
---|
392 | | - | IEP2_REG_DIL_MD_PRE_EN |
---|
393 | 394 | | IEP2_REG_DIL_FIELD_ORDER(cfg->dil_field_order) |
---|
394 | 395 | | IEP2_REG_DIL_OUT_MODE(cfg->dil_out_mode) |
---|
395 | 396 | | IEP2_REG_DIL_MODE(cfg->dil_mode); |
---|
396 | 397 | if (cfg->roi_en) |
---|
397 | 398 | reg |= IEP2_REG_DIL_ROI_EN; |
---|
| 399 | + if (cfg->md_lambda < 8) |
---|
| 400 | + reg |= IEP2_REG_DIL_MD_PRE_EN; |
---|
398 | 401 | mpp_write_relaxed(mpp, IEP2_REG_DIL_CONFIG0, reg); |
---|
399 | 402 | |
---|
400 | 403 | if (cfg->dil_mode != ROCKCHIP_IEP2_DIL_MODE_PD) { |
---|
.. | .. |
---|
437 | 440 | mpp_write_relaxed(mpp, IEP2_REG_SRC_ADDR_NXTUV, bot->cbcr); |
---|
438 | 441 | mpp_write_relaxed(mpp, IEP2_REG_SRC_ADDR_NXTV, bot->cr); |
---|
439 | 442 | } |
---|
| 443 | + |
---|
| 444 | + reg = IEP2_REG_TIMEOUT_CFG_EN | 0x3ffffff; |
---|
| 445 | + mpp_write_relaxed(mpp, IEP2_REG_TIMEOUT_CFG, reg); |
---|
440 | 446 | |
---|
441 | 447 | mpp_write_relaxed(mpp, IEP2_REG_SRC_ADDR_PREY, cfg->src[2].y); |
---|
442 | 448 | mpp_write_relaxed(mpp, IEP2_REG_SRC_ADDR_PREUV, cfg->src[2].cbcr); |
---|
.. | .. |
---|
580 | 586 | struct mpp_task *mpp_task) |
---|
581 | 587 | { |
---|
582 | 588 | struct iep_task *task = NULL; |
---|
| 589 | + u32 timing_en = mpp->srv->timing_en; |
---|
583 | 590 | |
---|
584 | 591 | mpp_debug_enter(); |
---|
585 | 592 | |
---|
.. | .. |
---|
598 | 605 | mpp_write_relaxed(mpp, IEP2_REG_INT_EN, |
---|
599 | 606 | IEP2_REG_FRM_DONE_EN |
---|
600 | 607 | | IEP2_REG_OSD_MAX_EN |
---|
601 | | - | IEP2_REG_BUS_ERROR_EN); |
---|
| 608 | + | IEP2_REG_BUS_ERROR_EN |
---|
| 609 | + | IEP2_REG_TIMEOUT_EN); |
---|
| 610 | + |
---|
| 611 | + /* flush tlb before starting hardware */ |
---|
| 612 | + mpp_iommu_flush_tlb(mpp->iommu_info); |
---|
| 613 | + |
---|
| 614 | + mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); |
---|
602 | 615 | |
---|
603 | 616 | /* Last, flush the registers */ |
---|
604 | 617 | wmb(); |
---|
605 | 618 | /* start iep2 */ |
---|
606 | 619 | mpp_write(mpp, IEP2_REG_FRM_START, 1); |
---|
| 620 | + |
---|
| 621 | + mpp_task_run_end(mpp_task, timing_en); |
---|
607 | 622 | |
---|
608 | 623 | mpp_debug_leave(); |
---|
609 | 624 | |
---|
.. | .. |
---|
612 | 627 | |
---|
613 | 628 | static int iep2_irq(struct mpp_dev *mpp) |
---|
614 | 629 | { |
---|
| 630 | + u32 work_mode = mpp_read(mpp, IEP2_REG_WORK_MODE); |
---|
| 631 | + |
---|
| 632 | + if (work_mode && !(work_mode & IEP2_REG_IEP2_MODE)) |
---|
| 633 | + return IRQ_NONE; |
---|
615 | 634 | mpp->irq_status = mpp_read(mpp, IEP2_REG_INT_STS); |
---|
616 | 635 | mpp_write(mpp, IEP2_REG_INT_CLR, 0xffffffff); |
---|
617 | 636 | |
---|
.. | .. |
---|
640 | 659 | mpp_debug(DEBUG_IRQ_STATUS, "irq_status: %08x\n", |
---|
641 | 660 | task->irq_status); |
---|
642 | 661 | |
---|
643 | | - if (IEP2_REG_RO_BUS_ERROR_STS(task->irq_status)) |
---|
| 662 | + if (IEP2_REG_RO_BUS_ERROR_STS(task->irq_status) || |
---|
| 663 | + IEP2_REG_RO_TIMEOUT_STS(task->irq_status)) |
---|
644 | 664 | atomic_inc(&mpp->reset_request); |
---|
645 | 665 | |
---|
646 | 666 | mpp_task_finish(mpp_task->session, mpp_task); |
---|
.. | .. |
---|
769 | 789 | iep->procfs = NULL; |
---|
770 | 790 | return -EIO; |
---|
771 | 791 | } |
---|
| 792 | + |
---|
| 793 | + /* for common mpp_dev options */ |
---|
| 794 | + mpp_procfs_create_common(iep->procfs, mpp); |
---|
| 795 | + |
---|
772 | 796 | mpp_procfs_create_u32("aclk", 0644, |
---|
773 | 797 | iep->procfs, &iep->aclk_info.debug_rate_hz); |
---|
774 | 798 | mpp_procfs_create_u32("session_buffers", 0644, |
---|
.. | .. |
---|
870 | 894 | { |
---|
871 | 895 | struct iep2_dev *iep = to_iep2_dev(mpp); |
---|
872 | 896 | |
---|
873 | | - if (iep->rst_a && iep->rst_h && iep->rst_s) { |
---|
874 | | - /* Don't skip this or iommu won't work after reset */ |
---|
875 | | - rockchip_pmu_idle_request(mpp->dev, true); |
---|
876 | | - mpp_safe_reset(iep->rst_a); |
---|
877 | | - mpp_safe_reset(iep->rst_h); |
---|
878 | | - mpp_safe_reset(iep->rst_s); |
---|
879 | | - udelay(5); |
---|
880 | | - mpp_safe_unreset(iep->rst_a); |
---|
881 | | - mpp_safe_unreset(iep->rst_h); |
---|
882 | | - mpp_safe_unreset(iep->rst_s); |
---|
883 | | - rockchip_pmu_idle_request(mpp->dev, false); |
---|
| 897 | + int ret = 0; |
---|
| 898 | + u32 rst_status = 0; |
---|
| 899 | + |
---|
| 900 | + /* soft rest first */ |
---|
| 901 | + mpp_write(mpp, IEP2_REG_IEP_CONFIG0, IEP2_REG_ACLK_SRESET_P); |
---|
| 902 | + ret = readl_relaxed_poll_timeout(mpp->reg_base + IEP2_REG_STATUS, |
---|
| 903 | + rst_status, |
---|
| 904 | + rst_status & IEP2_REG_ARST_FINISH_DONE, |
---|
| 905 | + 0, 5); |
---|
| 906 | + if (ret) { |
---|
| 907 | + mpp_err("soft reset timeout, use cru reset\n"); |
---|
| 908 | + if (iep->rst_a && iep->rst_h && iep->rst_s) { |
---|
| 909 | + /* Don't skip this or iommu won't work after reset */ |
---|
| 910 | + mpp_pmu_idle_request(mpp, true); |
---|
| 911 | + mpp_safe_reset(iep->rst_a); |
---|
| 912 | + mpp_safe_reset(iep->rst_h); |
---|
| 913 | + mpp_safe_reset(iep->rst_s); |
---|
| 914 | + udelay(5); |
---|
| 915 | + mpp_safe_unreset(iep->rst_a); |
---|
| 916 | + mpp_safe_unreset(iep->rst_h); |
---|
| 917 | + mpp_safe_unreset(iep->rst_s); |
---|
| 918 | + mpp_pmu_idle_request(mpp, false); |
---|
| 919 | + } |
---|
884 | 920 | } |
---|
885 | 921 | |
---|
886 | 922 | return 0; |
---|
.. | .. |
---|
1008 | 1044 | dev_err(dev, "wait total running time out\n"); |
---|
1009 | 1045 | } |
---|
1010 | 1046 | |
---|
| 1047 | +static int iep2_runtime_suspend(struct device *dev) |
---|
| 1048 | +{ |
---|
| 1049 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
---|
| 1050 | + struct mpp_grf_info *info = mpp->grf_info; |
---|
| 1051 | + struct mpp_taskqueue *queue = mpp->queue; |
---|
| 1052 | + |
---|
| 1053 | + if (cpu_is_rk3528() && info && info->mem_offset) { |
---|
| 1054 | + mutex_lock(&queue->ref_lock); |
---|
| 1055 | + if (!atomic_dec_if_positive(&queue->runtime_cnt)) { |
---|
| 1056 | + regmap_write(info->grf, info->mem_offset, |
---|
| 1057 | + info->val_mem_off); |
---|
| 1058 | + } |
---|
| 1059 | + mutex_unlock(&queue->ref_lock); |
---|
| 1060 | + } |
---|
| 1061 | + |
---|
| 1062 | + return 0; |
---|
| 1063 | +} |
---|
| 1064 | + |
---|
| 1065 | +static int iep2_runtime_resume(struct device *dev) |
---|
| 1066 | +{ |
---|
| 1067 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
---|
| 1068 | + struct mpp_grf_info *info = mpp->grf_info; |
---|
| 1069 | + struct mpp_taskqueue *queue = mpp->queue; |
---|
| 1070 | + |
---|
| 1071 | + if (cpu_is_rk3528() && info && info->mem_offset) { |
---|
| 1072 | + mutex_lock(&queue->ref_lock); |
---|
| 1073 | + regmap_write(info->grf, info->mem_offset, |
---|
| 1074 | + info->val_mem_on); |
---|
| 1075 | + atomic_inc(&queue->runtime_cnt); |
---|
| 1076 | + mutex_unlock(&queue->ref_lock); |
---|
| 1077 | + } |
---|
| 1078 | + |
---|
| 1079 | + return 0; |
---|
| 1080 | +} |
---|
| 1081 | + |
---|
| 1082 | +static const struct dev_pm_ops iep2_pm_ops = { |
---|
| 1083 | + .runtime_suspend = iep2_runtime_suspend, |
---|
| 1084 | + .runtime_resume = iep2_runtime_resume, |
---|
| 1085 | +}; |
---|
| 1086 | + |
---|
1011 | 1087 | struct platform_driver rockchip_iep2_driver = { |
---|
1012 | 1088 | .probe = iep2_probe, |
---|
1013 | 1089 | .remove = iep2_remove, |
---|
1014 | 1090 | .shutdown = iep2_shutdown, |
---|
1015 | 1091 | .driver = { |
---|
1016 | 1092 | .name = IEP2_DRIVER_NAME, |
---|
| 1093 | + .pm = &iep2_pm_ops, |
---|
1017 | 1094 | .of_match_table = of_match_ptr(mpp_iep2_match), |
---|
1018 | 1095 | }, |
---|
1019 | 1096 | }; |
---|