.. | .. |
---|
25 | 25 | #include "mpp_debug.h" |
---|
26 | 26 | #include "mpp_common.h" |
---|
27 | 27 | #include "mpp_iommu.h" |
---|
| 28 | +#include <soc/rockchip/rockchip_iommu.h> |
---|
28 | 29 | |
---|
29 | 30 | #define VDPU1_DRIVER_NAME "mpp_vdpu1" |
---|
30 | 31 | |
---|
.. | .. |
---|
57 | 58 | /* NOTE: Don't enable it or decoding AVC would meet problem at rk3288 */ |
---|
58 | 59 | #define VDPU1_REG_DEC_EN 0x008 |
---|
59 | 60 | #define VDPU1_CLOCK_GATE_EN BIT(10) |
---|
| 61 | + |
---|
| 62 | +#define VDPU1_REG_SOFT_RESET 0x194 |
---|
| 63 | +#define VDPU1_REG_SOFT_RESET_INDEX (101) |
---|
60 | 64 | |
---|
61 | 65 | #define VDPU1_REG_SYS_CTRL 0x00c |
---|
62 | 66 | #define VDPU1_REG_SYS_CTRL_INDEX (3) |
---|
.. | .. |
---|
263 | 267 | offset = task->reg[idx] >> 10 << 4; |
---|
264 | 268 | } |
---|
265 | 269 | mem_region = mpp_task_attach_fd(&task->mpp_task, fd); |
---|
266 | | - if (IS_ERR(mem_region)) |
---|
| 270 | + if (IS_ERR(mem_region)) { |
---|
| 271 | + mpp_err("reg[%03d]: %08x fd %d attach failed\n", |
---|
| 272 | + idx, task->reg[idx], fd); |
---|
267 | 273 | goto fail; |
---|
| 274 | + } |
---|
268 | 275 | |
---|
269 | 276 | iova = mem_region->iova; |
---|
270 | 277 | mpp_debug(DEBUG_IOMMU, "DMV[%3d]: %3d => %pad + offset %10d\n", |
---|
.. | .. |
---|
387 | 394 | u32 i; |
---|
388 | 395 | u32 reg_en; |
---|
389 | 396 | struct vdpu_task *task = to_vdpu_task(mpp_task); |
---|
| 397 | + u32 timing_en = mpp->srv->timing_en; |
---|
390 | 398 | |
---|
391 | 399 | mpp_debug_enter(); |
---|
392 | 400 | |
---|
.. | .. |
---|
401 | 409 | |
---|
402 | 410 | mpp_write_req(mpp, task->reg, s, e, reg_en); |
---|
403 | 411 | } |
---|
| 412 | + |
---|
| 413 | + /* flush tlb before starting hardware */ |
---|
| 414 | + mpp_iommu_flush_tlb(mpp->iommu_info); |
---|
| 415 | + |
---|
404 | 416 | /* init current task */ |
---|
405 | 417 | mpp->cur_task = mpp_task; |
---|
| 418 | + |
---|
| 419 | + mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); |
---|
| 420 | + |
---|
406 | 421 | /* Flush the register before the start the device */ |
---|
407 | 422 | wmb(); |
---|
408 | 423 | mpp_write(mpp, VDPU1_REG_DEC_INT_EN, |
---|
409 | 424 | task->reg[reg_en] | VDPU1_DEC_START); |
---|
| 425 | + |
---|
| 426 | + mpp_task_run_end(mpp_task, timing_en); |
---|
410 | 427 | |
---|
411 | 428 | mpp_debug_leave(); |
---|
412 | 429 | |
---|
.. | .. |
---|
503 | 520 | dec->procfs = NULL; |
---|
504 | 521 | return -EIO; |
---|
505 | 522 | } |
---|
| 523 | + |
---|
| 524 | + /* for common mpp_dev options */ |
---|
| 525 | + mpp_procfs_create_common(dec->procfs, mpp); |
---|
| 526 | + |
---|
506 | 527 | mpp_procfs_create_u32("aclk", 0644, |
---|
507 | 528 | dec->procfs, &dec->aclk_info.debug_rate_hz); |
---|
508 | 529 | mpp_procfs_create_u32("session_buffers", 0644, |
---|
.. | .. |
---|
547 | 568 | if (!dec->rst_h) |
---|
548 | 569 | mpp_err("No hclk reset resource define\n"); |
---|
549 | 570 | |
---|
| 571 | + return 0; |
---|
| 572 | +} |
---|
| 573 | + |
---|
| 574 | +static int vdpu_3036_init(struct mpp_dev *mpp) |
---|
| 575 | +{ |
---|
| 576 | + vdpu_init(mpp); |
---|
| 577 | + set_bit(mpp->var->device_type, &mpp->queue->dev_active_flags); |
---|
550 | 578 | return 0; |
---|
551 | 579 | } |
---|
552 | 580 | |
---|
.. | .. |
---|
663 | 691 | return IRQ_HANDLED; |
---|
664 | 692 | } |
---|
665 | 693 | |
---|
| 694 | +static int vdpu_soft_reset(struct mpp_dev *mpp) |
---|
| 695 | +{ |
---|
| 696 | + u32 val; |
---|
| 697 | + u32 ret; |
---|
| 698 | + |
---|
| 699 | + mpp_write(mpp, VDPU1_REG_SOFT_RESET, 1); |
---|
| 700 | + ret = readl_relaxed_poll_timeout(mpp->reg_base + VDPU1_REG_SOFT_RESET, |
---|
| 701 | + val, !val, 0, 5); |
---|
| 702 | + |
---|
| 703 | + return ret; |
---|
| 704 | +} |
---|
| 705 | + |
---|
666 | 706 | static int vdpu_reset(struct mpp_dev *mpp) |
---|
667 | 707 | { |
---|
668 | 708 | struct vdpu_dev *dec = to_vdpu_dev(mpp); |
---|
| 709 | + u32 ret = 0; |
---|
669 | 710 | |
---|
670 | | - if (dec->rst_a && dec->rst_h) { |
---|
| 711 | + /* soft reset first */ |
---|
| 712 | + ret = vdpu_soft_reset(mpp); |
---|
| 713 | + if (ret && dec->rst_a && dec->rst_h) { |
---|
| 714 | + mpp_err("soft reset failed, use cru reset!\n"); |
---|
671 | 715 | mpp_debug(DEBUG_RESET, "reset in\n"); |
---|
672 | 716 | |
---|
673 | 717 | /* Don't skip this or iommu won't work after reset */ |
---|
674 | | - rockchip_pmu_idle_request(mpp->dev, true); |
---|
| 718 | + mpp_pmu_idle_request(mpp, true); |
---|
675 | 719 | mpp_safe_reset(dec->rst_a); |
---|
676 | 720 | mpp_safe_reset(dec->rst_h); |
---|
677 | 721 | udelay(5); |
---|
678 | 722 | mpp_safe_unreset(dec->rst_a); |
---|
679 | 723 | mpp_safe_unreset(dec->rst_h); |
---|
680 | | - rockchip_pmu_idle_request(mpp->dev, false); |
---|
| 724 | + mpp_pmu_idle_request(mpp, false); |
---|
681 | 725 | |
---|
682 | 726 | mpp_debug(DEBUG_RESET, "reset out\n"); |
---|
683 | 727 | } |
---|
684 | 728 | mpp_write(mpp, VDPU1_REG_DEC_INT_EN, 0); |
---|
| 729 | + |
---|
| 730 | + return 0; |
---|
| 731 | +} |
---|
| 732 | + |
---|
| 733 | +static int vdpu_3036_set_grf(struct mpp_dev *mpp) |
---|
| 734 | +{ |
---|
| 735 | + int grf_changed; |
---|
| 736 | + struct mpp_dev *loop = NULL, *n; |
---|
| 737 | + struct mpp_taskqueue *queue = mpp->queue; |
---|
| 738 | + bool pd_is_on; |
---|
| 739 | + |
---|
| 740 | + grf_changed = mpp_grf_is_changed(mpp->grf_info); |
---|
| 741 | + if (grf_changed) { |
---|
| 742 | + |
---|
| 743 | + /* |
---|
| 744 | + * in this case, devices share the queue also share the same pd&clk, |
---|
| 745 | + * so use mpp->dev's pd to control all the process is okay |
---|
| 746 | + */ |
---|
| 747 | + pd_is_on = rockchip_pmu_pd_is_on(mpp->dev); |
---|
| 748 | + if (!pd_is_on) |
---|
| 749 | + rockchip_pmu_pd_on(mpp->dev); |
---|
| 750 | + mpp->hw_ops->clk_on(mpp); |
---|
| 751 | + |
---|
| 752 | + list_for_each_entry_safe(loop, n, &queue->dev_list, queue_link) { |
---|
| 753 | + if (test_bit(loop->var->device_type, &queue->dev_active_flags)) { |
---|
| 754 | + mpp_set_grf(loop->grf_info); |
---|
| 755 | + if (loop->hw_ops->clk_on) |
---|
| 756 | + loop->hw_ops->clk_on(loop); |
---|
| 757 | + if (loop->hw_ops->reset) |
---|
| 758 | + loop->hw_ops->reset(loop); |
---|
| 759 | + rockchip_iommu_disable(loop->dev); |
---|
| 760 | + if (loop->hw_ops->clk_off) |
---|
| 761 | + loop->hw_ops->clk_off(loop); |
---|
| 762 | + clear_bit(loop->var->device_type, &queue->dev_active_flags); |
---|
| 763 | + } |
---|
| 764 | + } |
---|
| 765 | + |
---|
| 766 | + mpp_set_grf(mpp->grf_info); |
---|
| 767 | + rockchip_iommu_enable(mpp->dev); |
---|
| 768 | + set_bit(mpp->var->device_type, &queue->dev_active_flags); |
---|
| 769 | + |
---|
| 770 | + mpp->hw_ops->clk_off(mpp); |
---|
| 771 | + if (!pd_is_on) |
---|
| 772 | + rockchip_pmu_pd_off(mpp->dev); |
---|
| 773 | + } |
---|
685 | 774 | |
---|
686 | 775 | return 0; |
---|
687 | 776 | } |
---|
.. | .. |
---|
693 | 782 | .set_freq = vdpu_set_freq, |
---|
694 | 783 | .reduce_freq = vdpu_reduce_freq, |
---|
695 | 784 | .reset = vdpu_reset, |
---|
| 785 | + .set_grf = vdpu_3036_set_grf, |
---|
| 786 | +}; |
---|
| 787 | + |
---|
| 788 | +static struct mpp_hw_ops vdpu_3036_hw_ops = { |
---|
| 789 | + .init = vdpu_3036_init, |
---|
| 790 | + .clk_on = vdpu_clk_on, |
---|
| 791 | + .clk_off = vdpu_clk_off, |
---|
| 792 | + .set_freq = vdpu_set_freq, |
---|
| 793 | + .reduce_freq = vdpu_reduce_freq, |
---|
| 794 | + .reset = vdpu_reset, |
---|
| 795 | + .set_grf = vdpu_3036_set_grf, |
---|
696 | 796 | }; |
---|
697 | 797 | |
---|
698 | 798 | static struct mpp_hw_ops vdpu_3288_hw_ops = { |
---|
.. | .. |
---|
733 | 833 | .dev_ops = &vdpu_v1_dev_ops, |
---|
734 | 834 | }; |
---|
735 | 835 | |
---|
| 836 | +static const struct mpp_dev_var vdpu_3036_data = { |
---|
| 837 | + .device_type = MPP_DEVICE_VDPU1, |
---|
| 838 | + .hw_info = &vdpu_v1_hw_info, |
---|
| 839 | + .trans_info = vdpu_v1_trans, |
---|
| 840 | + .hw_ops = &vdpu_3036_hw_ops, |
---|
| 841 | + .dev_ops = &vdpu_v1_dev_ops, |
---|
| 842 | +}; |
---|
| 843 | + |
---|
736 | 844 | static const struct mpp_dev_var vdpu_3288_data = { |
---|
737 | 845 | .device_type = MPP_DEVICE_VDPU1, |
---|
738 | 846 | .hw_info = &vdpu_v1_hw_info, |
---|
.. | .. |
---|
768 | 876 | .data = &vdpu_3288_data, |
---|
769 | 877 | }, |
---|
770 | 878 | #endif |
---|
| 879 | +#ifdef CONFIG_CPU_RK3036 |
---|
| 880 | + { |
---|
| 881 | + .compatible = "rockchip,vpu-decoder-rk3036", |
---|
| 882 | + .data = &vdpu_3036_data, |
---|
| 883 | + }, |
---|
| 884 | +#endif |
---|
771 | 885 | #ifdef CONFIG_CPU_RK3368 |
---|
772 | 886 | { |
---|
773 | 887 | .compatible = "rockchip,vpu-decoder-rk3368", |
---|
774 | 888 | .data = &vdpu_3368_data, |
---|
775 | 889 | }, |
---|
776 | 890 | #endif |
---|
777 | | -#ifdef CONFIG_CPU_RK3328 |
---|
778 | 891 | { |
---|
779 | 892 | .compatible = "rockchip,avs-plus-decoder", |
---|
780 | 893 | .data = &avsd_plus_data, |
---|
781 | 894 | }, |
---|
782 | | -#endif |
---|
783 | 895 | {}, |
---|
784 | 896 | }; |
---|
785 | 897 | |
---|
.. | .. |
---|
795 | 907 | dec = devm_kzalloc(dev, sizeof(struct vdpu_dev), GFP_KERNEL); |
---|
796 | 908 | if (!dec) |
---|
797 | 909 | return -ENOMEM; |
---|
798 | | - platform_set_drvdata(pdev, dec); |
---|
799 | | - |
---|
800 | 910 | mpp = &dec->mpp; |
---|
| 911 | + platform_set_drvdata(pdev, mpp); |
---|
| 912 | + |
---|
801 | 913 | if (pdev->dev.of_node) { |
---|
802 | 914 | match = of_match_node(mpp_vdpu1_dt_match, pdev->dev.of_node); |
---|
803 | 915 | if (match) |
---|
804 | 916 | mpp->var = (struct mpp_dev_var *)match->data; |
---|
| 917 | + |
---|
| 918 | + mpp->core_id = of_alias_get_id(pdev->dev.of_node, "vdpu"); |
---|
805 | 919 | } |
---|
806 | 920 | |
---|
807 | 921 | ret = mpp_dev_probe(mpp, pdev); |
---|
.. | .. |
---|
837 | 951 | static int vdpu_remove(struct platform_device *pdev) |
---|
838 | 952 | { |
---|
839 | 953 | struct device *dev = &pdev->dev; |
---|
840 | | - struct vdpu_dev *dec = platform_get_drvdata(pdev); |
---|
| 954 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
---|
841 | 955 | |
---|
842 | 956 | dev_info(dev, "remove device\n"); |
---|
843 | | - mpp_dev_remove(&dec->mpp); |
---|
844 | | - vdpu_procfs_remove(&dec->mpp); |
---|
| 957 | + mpp_dev_remove(mpp); |
---|
| 958 | + vdpu_procfs_remove(mpp); |
---|
845 | 959 | |
---|
846 | 960 | return 0; |
---|
847 | | -} |
---|
848 | | - |
---|
849 | | -static void vdpu_shutdown(struct platform_device *pdev) |
---|
850 | | -{ |
---|
851 | | - int ret; |
---|
852 | | - int val; |
---|
853 | | - struct device *dev = &pdev->dev; |
---|
854 | | - struct vdpu_dev *dec = platform_get_drvdata(pdev); |
---|
855 | | - struct mpp_dev *mpp = &dec->mpp; |
---|
856 | | - |
---|
857 | | - dev_info(dev, "shutdown device\n"); |
---|
858 | | - |
---|
859 | | - atomic_inc(&mpp->srv->shutdown_request); |
---|
860 | | - ret = readx_poll_timeout(atomic_read, |
---|
861 | | - &mpp->task_count, |
---|
862 | | - val, val == 0, 20000, 200000); |
---|
863 | | - if (ret == -ETIMEDOUT) |
---|
864 | | - dev_err(dev, "wait total running time out\n"); |
---|
865 | 961 | } |
---|
866 | 962 | |
---|
867 | 963 | struct platform_driver rockchip_vdpu1_driver = { |
---|
868 | 964 | .probe = vdpu_probe, |
---|
869 | 965 | .remove = vdpu_remove, |
---|
870 | | - .shutdown = vdpu_shutdown, |
---|
| 966 | + .shutdown = mpp_dev_shutdown, |
---|
871 | 967 | .driver = { |
---|
872 | 968 | .name = VDPU1_DRIVER_NAME, |
---|
873 | 969 | .of_match_table = of_match_ptr(mpp_vdpu1_dt_match), |
---|