| .. | .. |
|---|
| 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 | }; |
|---|