.. | .. |
---|
22 | 22 | #include <linux/proc_fs.h> |
---|
23 | 23 | #include <linux/nospec.h> |
---|
24 | 24 | #include <soc/rockchip/pm_domains.h> |
---|
| 25 | +#include <soc/rockchip/rockchip_iommu.h> |
---|
25 | 26 | |
---|
26 | 27 | #include "mpp_debug.h" |
---|
27 | 28 | #include "mpp_common.h" |
---|
.. | .. |
---|
36 | 37 | #define VEPU2_REG_HW_ID_INDEX -1 /* INVALID */ |
---|
37 | 38 | #define VEPU2_REG_START_INDEX 0 |
---|
38 | 39 | #define VEPU2_REG_END_INDEX 183 |
---|
| 40 | +#define VEPU2_REG_OUT_INDEX (77) |
---|
| 41 | +#define VEPU2_REG_STRM_INDEX (53) |
---|
39 | 42 | |
---|
40 | 43 | #define VEPU2_REG_ENC_EN 0x19c |
---|
41 | 44 | #define VEPU2_REG_ENC_EN_INDEX (103) |
---|
.. | .. |
---|
97 | 100 | u32 width; |
---|
98 | 101 | u32 height; |
---|
99 | 102 | u32 pixels; |
---|
| 103 | + struct mpp_dma_buffer *bs_buf; |
---|
| 104 | + u32 offset_bs; |
---|
100 | 105 | }; |
---|
101 | 106 | |
---|
102 | 107 | struct vepu_session_priv { |
---|
.. | .. |
---|
121 | 126 | #endif |
---|
122 | 127 | struct reset_control *rst_a; |
---|
123 | 128 | struct reset_control *rst_h; |
---|
| 129 | + /* for ccu(central control unit) */ |
---|
| 130 | + struct vepu_ccu *ccu; |
---|
| 131 | + bool disable_work; |
---|
| 132 | +}; |
---|
| 133 | + |
---|
| 134 | +struct vepu_ccu { |
---|
| 135 | + u32 core_num; |
---|
| 136 | + /* lock for core attach */ |
---|
| 137 | + spinlock_t lock; |
---|
| 138 | + struct mpp_dev *main_core; |
---|
| 139 | + struct mpp_dev *cores[MPP_MAX_CORE_NUM]; |
---|
| 140 | + unsigned long core_idle; |
---|
124 | 141 | }; |
---|
125 | 142 | |
---|
126 | 143 | static struct mpp_hw_info vepu_v2_hw_info = { |
---|
.. | .. |
---|
167 | 184 | struct mpp_task_msgs *msgs) |
---|
168 | 185 | { |
---|
169 | 186 | int ret; |
---|
| 187 | + int fd_bs; |
---|
170 | 188 | int fmt = VEPU2_GET_FORMAT(task->reg[VEPU2_REG_ENC_EN_INDEX]); |
---|
| 189 | + |
---|
| 190 | + if (session->msg_flags & MPP_FLAGS_REG_NO_OFFSET) |
---|
| 191 | + fd_bs = task->reg[VEPU2_REG_OUT_INDEX]; |
---|
| 192 | + else |
---|
| 193 | + fd_bs = task->reg[VEPU2_REG_OUT_INDEX] & 0x3ff; |
---|
171 | 194 | |
---|
172 | 195 | ret = mpp_translate_reg_address(session, &task->mpp_task, |
---|
173 | 196 | fmt, task->reg, &task->off_inf); |
---|
.. | .. |
---|
176 | 199 | |
---|
177 | 200 | mpp_translate_reg_offset_info(&task->mpp_task, |
---|
178 | 201 | &task->off_inf, task->reg); |
---|
| 202 | + |
---|
| 203 | + if (fmt == VEPU2_FMT_JPEGE) { |
---|
| 204 | + struct mpp_dma_buffer *bs_buf = mpp_dma_find_buffer_fd(session->dma, fd_bs); |
---|
| 205 | + |
---|
| 206 | + task->offset_bs = mpp_query_reg_offset_info(&task->off_inf, VEPU2_REG_OUT_INDEX); |
---|
| 207 | + if (bs_buf && task->offset_bs > 0) |
---|
| 208 | + mpp_dma_buf_sync(bs_buf, 0, task->offset_bs, DMA_TO_DEVICE, false); |
---|
| 209 | + task->bs_buf = bs_buf; |
---|
| 210 | + } |
---|
179 | 211 | |
---|
180 | 212 | return 0; |
---|
181 | 213 | } |
---|
.. | .. |
---|
281 | 313 | return NULL; |
---|
282 | 314 | } |
---|
283 | 315 | |
---|
| 316 | +static void *vepu_prepare(struct mpp_dev *mpp, struct mpp_task *mpp_task) |
---|
| 317 | +{ |
---|
| 318 | + struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 319 | + struct vepu_ccu *ccu = enc->ccu; |
---|
| 320 | + unsigned long core_idle; |
---|
| 321 | + unsigned long flags; |
---|
| 322 | + s32 core_id; |
---|
| 323 | + u32 i; |
---|
| 324 | + |
---|
| 325 | + spin_lock_irqsave(&ccu->lock, flags); |
---|
| 326 | + |
---|
| 327 | + core_idle = ccu->core_idle; |
---|
| 328 | + |
---|
| 329 | + for (i = 0; i < ccu->core_num; i++) { |
---|
| 330 | + struct mpp_dev *mpp = ccu->cores[i]; |
---|
| 331 | + |
---|
| 332 | + if (mpp && mpp->disable) |
---|
| 333 | + clear_bit(mpp->core_id, &core_idle); |
---|
| 334 | + } |
---|
| 335 | + |
---|
| 336 | + core_id = find_first_bit(&core_idle, ccu->core_num); |
---|
| 337 | + if (core_id >= ARRAY_SIZE(ccu->cores)) { |
---|
| 338 | + mpp_task = NULL; |
---|
| 339 | + mpp_dbg_core("core %d all busy %lx\n", core_id, ccu->core_idle); |
---|
| 340 | + goto done; |
---|
| 341 | + } |
---|
| 342 | + |
---|
| 343 | + core_id = array_index_nospec(core_id, MPP_MAX_CORE_NUM); |
---|
| 344 | + clear_bit(core_id, &ccu->core_idle); |
---|
| 345 | + mpp_task->mpp = ccu->cores[core_id]; |
---|
| 346 | + mpp_task->core_id = core_id; |
---|
| 347 | + |
---|
| 348 | + mpp_dbg_core("core cnt %d core %d set idle %lx -> %lx\n", |
---|
| 349 | + ccu->core_num, core_id, core_idle, ccu->core_idle); |
---|
| 350 | + |
---|
| 351 | +done: |
---|
| 352 | + spin_unlock_irqrestore(&ccu->lock, flags); |
---|
| 353 | + |
---|
| 354 | + return mpp_task; |
---|
| 355 | +} |
---|
| 356 | + |
---|
284 | 357 | static int vepu_run(struct mpp_dev *mpp, |
---|
285 | 358 | struct mpp_task *mpp_task) |
---|
286 | 359 | { |
---|
287 | 360 | u32 i; |
---|
288 | 361 | u32 reg_en; |
---|
289 | 362 | struct vepu_task *task = to_vepu_task(mpp_task); |
---|
| 363 | + u32 timing_en = mpp->srv->timing_en; |
---|
290 | 364 | |
---|
291 | 365 | mpp_debug_enter(); |
---|
292 | 366 | |
---|
.. | .. |
---|
305 | 379 | |
---|
306 | 380 | mpp_write_req(mpp, task->reg, s, e, reg_en); |
---|
307 | 381 | } |
---|
| 382 | + |
---|
| 383 | + /* flush tlb before starting hardware */ |
---|
| 384 | + mpp_iommu_flush_tlb(mpp->iommu_info); |
---|
| 385 | + |
---|
308 | 386 | /* init current task */ |
---|
309 | 387 | mpp->cur_task = mpp_task; |
---|
| 388 | + |
---|
| 389 | + mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); |
---|
| 390 | + |
---|
310 | 391 | /* Last, flush the registers */ |
---|
311 | 392 | wmb(); |
---|
312 | 393 | mpp_write(mpp, VEPU2_REG_ENC_EN, |
---|
313 | 394 | task->reg[reg_en] | VEPU2_ENC_START); |
---|
314 | 395 | |
---|
| 396 | + mpp_task_run_end(mpp_task, timing_en); |
---|
| 397 | + |
---|
315 | 398 | mpp_debug_leave(); |
---|
316 | 399 | |
---|
317 | 400 | return 0; |
---|
| 401 | +} |
---|
| 402 | + |
---|
| 403 | +static int vepu_px30_run(struct mpp_dev *mpp, |
---|
| 404 | + struct mpp_task *mpp_task) |
---|
| 405 | +{ |
---|
| 406 | + mpp_iommu_flush_tlb(mpp->iommu_info); |
---|
| 407 | + return vepu_run(mpp, mpp_task); |
---|
318 | 408 | } |
---|
319 | 409 | |
---|
320 | 410 | static int vepu_irq(struct mpp_dev *mpp) |
---|
.. | .. |
---|
333 | 423 | u32 err_mask; |
---|
334 | 424 | struct vepu_task *task = NULL; |
---|
335 | 425 | struct mpp_task *mpp_task = mpp->cur_task; |
---|
| 426 | + unsigned long core_idle; |
---|
| 427 | + struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 428 | + struct vepu_ccu *ccu = enc->ccu; |
---|
336 | 429 | |
---|
337 | 430 | /* FIXME use a spin lock here */ |
---|
338 | 431 | if (!mpp_task) { |
---|
.. | .. |
---|
354 | 447 | atomic_inc(&mpp->reset_request); |
---|
355 | 448 | |
---|
356 | 449 | mpp_task_finish(mpp_task->session, mpp_task); |
---|
| 450 | + /* the whole vepu has no ccu that manage multi core */ |
---|
| 451 | + if (ccu) { |
---|
| 452 | + core_idle = ccu->core_idle; |
---|
| 453 | + set_bit(mpp->core_id, &ccu->core_idle); |
---|
| 454 | + |
---|
| 455 | + mpp_dbg_core("core %d isr idle %lx -> %lx\n", mpp->core_id, core_idle, |
---|
| 456 | + ccu->core_idle); |
---|
| 457 | + } |
---|
357 | 458 | |
---|
358 | 459 | mpp_debug_leave(); |
---|
359 | 460 | |
---|
.. | .. |
---|
380 | 481 | /* revert hack for irq status */ |
---|
381 | 482 | task->reg[VEPU2_REG_INT_INDEX] = task->irq_status; |
---|
382 | 483 | |
---|
| 484 | + if (task->bs_buf) |
---|
| 485 | + mpp_dma_buf_sync(task->bs_buf, 0, |
---|
| 486 | + task->reg[VEPU2_REG_STRM_INDEX] / 8 + |
---|
| 487 | + task->offset_bs, |
---|
| 488 | + DMA_FROM_DEVICE, true); |
---|
383 | 489 | mpp_debug_leave(); |
---|
384 | 490 | |
---|
385 | 491 | return 0; |
---|
.. | .. |
---|
522 | 628 | } |
---|
523 | 629 | seq_puts(seq, "\n"); |
---|
524 | 630 | /* item data*/ |
---|
525 | | - seq_printf(seq, "|%8p|", session); |
---|
| 631 | + seq_printf(seq, "|%8d|", session->index); |
---|
526 | 632 | seq_printf(seq, "%8s|", mpp_device_name[session->device_type]); |
---|
527 | 633 | for (i = ENC_INFO_BASE; i < ENC_INFO_BUTT; i++) { |
---|
528 | 634 | u32 flag = priv->codec_info[i].flag; |
---|
.. | .. |
---|
555 | 661 | mutex_lock(&mpp->srv->session_lock); |
---|
556 | 662 | list_for_each_entry_safe(session, n, |
---|
557 | 663 | &mpp->srv->session_list, |
---|
558 | | - session_link) { |
---|
559 | | - if (session->device_type != MPP_DEVICE_VEPU2) |
---|
| 664 | + service_link) { |
---|
| 665 | + if (session->device_type != MPP_DEVICE_VEPU2 && |
---|
| 666 | + session->device_type != MPP_DEVICE_VEPU2_JPEG) |
---|
560 | 667 | continue; |
---|
561 | 668 | if (!session->priv) |
---|
562 | 669 | continue; |
---|
.. | .. |
---|
571 | 678 | static int vepu_procfs_init(struct mpp_dev *mpp) |
---|
572 | 679 | { |
---|
573 | 680 | struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 681 | + char name[32]; |
---|
574 | 682 | |
---|
575 | | - enc->procfs = proc_mkdir(mpp->dev->of_node->name, mpp->srv->procfs); |
---|
| 683 | + if (!mpp->dev || !mpp->dev->of_node || !mpp->dev->of_node->name || |
---|
| 684 | + !mpp->srv || !mpp->srv->procfs) |
---|
| 685 | + return -EINVAL; |
---|
| 686 | + if (enc->ccu) |
---|
| 687 | + snprintf(name, sizeof(name) - 1, "%s%d", |
---|
| 688 | + mpp->dev->of_node->name, mpp->core_id); |
---|
| 689 | + else |
---|
| 690 | + snprintf(name, sizeof(name) - 1, "%s", |
---|
| 691 | + mpp->dev->of_node->name); |
---|
| 692 | + |
---|
| 693 | + enc->procfs = proc_mkdir(name, mpp->srv->procfs); |
---|
576 | 694 | if (IS_ERR_OR_NULL(enc->procfs)) { |
---|
577 | 695 | mpp_err("failed on open procfs\n"); |
---|
578 | 696 | enc->procfs = NULL; |
---|
579 | 697 | return -EIO; |
---|
580 | 698 | } |
---|
| 699 | + |
---|
| 700 | + /* for common mpp_dev options */ |
---|
| 701 | + mpp_procfs_create_common(enc->procfs, mpp); |
---|
| 702 | + |
---|
581 | 703 | mpp_procfs_create_u32("aclk", 0644, |
---|
582 | 704 | enc->procfs, &enc->aclk_info.debug_rate_hz); |
---|
583 | 705 | mpp_procfs_create_u32("session_buffers", 0644, |
---|
.. | .. |
---|
588 | 710 | |
---|
589 | 711 | return 0; |
---|
590 | 712 | } |
---|
| 713 | + |
---|
| 714 | +static int vepu_procfs_ccu_init(struct mpp_dev *mpp) |
---|
| 715 | +{ |
---|
| 716 | + struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 717 | + |
---|
| 718 | + if (!enc->procfs) |
---|
| 719 | + goto done; |
---|
| 720 | + |
---|
| 721 | +done: |
---|
| 722 | + return 0; |
---|
| 723 | +} |
---|
591 | 724 | #else |
---|
592 | 725 | static inline int vepu_procfs_remove(struct mpp_dev *mpp) |
---|
593 | 726 | { |
---|
.. | .. |
---|
595 | 728 | } |
---|
596 | 729 | |
---|
597 | 730 | static inline int vepu_procfs_init(struct mpp_dev *mpp) |
---|
| 731 | +{ |
---|
| 732 | + return 0; |
---|
| 733 | +} |
---|
| 734 | + |
---|
| 735 | +static inline int vepu_procfs_ccu_init(struct mpp_dev *mpp) |
---|
598 | 736 | { |
---|
599 | 737 | return 0; |
---|
600 | 738 | } |
---|
.. | .. |
---|
721 | 859 | static int vepu_reset(struct mpp_dev *mpp) |
---|
722 | 860 | { |
---|
723 | 861 | struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 862 | + struct vepu_ccu *ccu = enc->ccu; |
---|
724 | 863 | |
---|
| 864 | + mpp_write(mpp, VEPU2_REG_ENC_EN, 0); |
---|
| 865 | + udelay(5); |
---|
725 | 866 | if (enc->rst_a && enc->rst_h) { |
---|
726 | 867 | /* Don't skip this or iommu won't work after reset */ |
---|
727 | | - rockchip_pmu_idle_request(mpp->dev, true); |
---|
| 868 | + mpp_pmu_idle_request(mpp, true); |
---|
728 | 869 | mpp_safe_reset(enc->rst_a); |
---|
729 | 870 | mpp_safe_reset(enc->rst_h); |
---|
730 | 871 | udelay(5); |
---|
731 | 872 | mpp_safe_unreset(enc->rst_a); |
---|
732 | 873 | mpp_safe_unreset(enc->rst_h); |
---|
733 | | - rockchip_pmu_idle_request(mpp->dev, false); |
---|
| 874 | + mpp_pmu_idle_request(mpp, false); |
---|
734 | 875 | } |
---|
735 | 876 | mpp_write(mpp, VEPU2_REG_INT, VEPU2_INT_CLEAR); |
---|
| 877 | + |
---|
| 878 | + if (ccu) { |
---|
| 879 | + set_bit(mpp->core_id, &ccu->core_idle); |
---|
| 880 | + mpp_dbg_core("core %d reset idle %lx\n", mpp->core_id, ccu->core_idle); |
---|
| 881 | + } |
---|
| 882 | + |
---|
| 883 | + return 0; |
---|
| 884 | +} |
---|
| 885 | + |
---|
| 886 | +static int vepu2_iommu_fault_handle(struct iommu_domain *iommu, struct device *iommu_dev, |
---|
| 887 | + unsigned long iova, int status, void *arg) |
---|
| 888 | +{ |
---|
| 889 | + struct mpp_dev *mpp = (struct mpp_dev *)arg; |
---|
| 890 | + struct mpp_task *mpp_task; |
---|
| 891 | + struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 892 | + struct vepu_ccu *ccu = enc->ccu; |
---|
| 893 | + |
---|
| 894 | + dev_err(iommu_dev, "fault addr 0x%08lx status %x arg %p\n", |
---|
| 895 | + iova, status, arg); |
---|
| 896 | + |
---|
| 897 | + if (ccu) { |
---|
| 898 | + int i; |
---|
| 899 | + struct mpp_dev *core; |
---|
| 900 | + |
---|
| 901 | + for (i = 0; i < ccu->core_num; i++) { |
---|
| 902 | + core = ccu->cores[i]; |
---|
| 903 | + if (core->iommu_info && (&core->iommu_info->pdev->dev == iommu_dev)) { |
---|
| 904 | + mpp = core; |
---|
| 905 | + break; |
---|
| 906 | + } |
---|
| 907 | + } |
---|
| 908 | + } |
---|
| 909 | + |
---|
| 910 | + if (!mpp) { |
---|
| 911 | + dev_err(iommu_dev, "pagefault without device to handle\n"); |
---|
| 912 | + return 0; |
---|
| 913 | + } |
---|
| 914 | + mpp_task = mpp->cur_task; |
---|
| 915 | + if (mpp_task) |
---|
| 916 | + mpp_task_dump_mem_region(mpp, mpp_task); |
---|
| 917 | + |
---|
| 918 | + mpp_task_dump_hw_reg(mpp); |
---|
| 919 | + /* |
---|
| 920 | + * Mask iommu irq, in order for iommu not repeatedly trigger pagefault. |
---|
| 921 | + * Until the pagefault task finish by hw timeout. |
---|
| 922 | + */ |
---|
| 923 | + rockchip_iommu_mask_irq(mpp->dev); |
---|
736 | 924 | |
---|
737 | 925 | return 0; |
---|
738 | 926 | } |
---|
.. | .. |
---|
771 | 959 | .dump_session = vepu_dump_session, |
---|
772 | 960 | }; |
---|
773 | 961 | |
---|
| 962 | +static struct mpp_dev_ops vepu_px30_dev_ops = { |
---|
| 963 | + .alloc_task = vepu_alloc_task, |
---|
| 964 | + .run = vepu_px30_run, |
---|
| 965 | + .irq = vepu_irq, |
---|
| 966 | + .isr = vepu_isr, |
---|
| 967 | + .finish = vepu_finish, |
---|
| 968 | + .result = vepu_result, |
---|
| 969 | + .free_task = vepu_free_task, |
---|
| 970 | + .ioctl = vepu_control, |
---|
| 971 | + .init_session = vepu_init_session, |
---|
| 972 | + .free_session = vepu_free_session, |
---|
| 973 | + .dump_session = vepu_dump_session, |
---|
| 974 | +}; |
---|
| 975 | + |
---|
| 976 | +static struct mpp_dev_ops vepu_ccu_dev_ops = { |
---|
| 977 | + .alloc_task = vepu_alloc_task, |
---|
| 978 | + .prepare = vepu_prepare, |
---|
| 979 | + .run = vepu_run, |
---|
| 980 | + .irq = vepu_irq, |
---|
| 981 | + .isr = vepu_isr, |
---|
| 982 | + .finish = vepu_finish, |
---|
| 983 | + .result = vepu_result, |
---|
| 984 | + .free_task = vepu_free_task, |
---|
| 985 | + .ioctl = vepu_control, |
---|
| 986 | + .init_session = vepu_init_session, |
---|
| 987 | + .free_session = vepu_free_session, |
---|
| 988 | + .dump_session = vepu_dump_session, |
---|
| 989 | +}; |
---|
| 990 | + |
---|
| 991 | + |
---|
774 | 992 | static const struct mpp_dev_var vepu_v2_data = { |
---|
775 | 993 | .device_type = MPP_DEVICE_VEPU2, |
---|
776 | 994 | .hw_info = &vepu_v2_hw_info, |
---|
.. | .. |
---|
784 | 1002 | .hw_info = &vepu_v2_hw_info, |
---|
785 | 1003 | .trans_info = trans_rk_vepu2, |
---|
786 | 1004 | .hw_ops = &vepu_px30_hw_ops, |
---|
787 | | - .dev_ops = &vepu_v2_dev_ops, |
---|
| 1005 | + .dev_ops = &vepu_px30_dev_ops, |
---|
| 1006 | +}; |
---|
| 1007 | + |
---|
| 1008 | +static const struct mpp_dev_var vepu_ccu_data = { |
---|
| 1009 | + .device_type = MPP_DEVICE_VEPU2_JPEG, |
---|
| 1010 | + .hw_info = &vepu_v2_hw_info, |
---|
| 1011 | + .trans_info = trans_rk_vepu2, |
---|
| 1012 | + .hw_ops = &vepu_v2_hw_ops, |
---|
| 1013 | + .dev_ops = &vepu_ccu_dev_ops, |
---|
788 | 1014 | }; |
---|
789 | 1015 | |
---|
790 | 1016 | static const struct of_device_id mpp_vepu2_dt_match[] = { |
---|
.. | .. |
---|
798 | 1024 | .data = &vepu_px30_data, |
---|
799 | 1025 | }, |
---|
800 | 1026 | #endif |
---|
| 1027 | +#ifdef CONFIG_CPU_RK3588 |
---|
| 1028 | + { |
---|
| 1029 | + .compatible = "rockchip,vpu-jpege-core", |
---|
| 1030 | + .data = &vepu_ccu_data, |
---|
| 1031 | + }, |
---|
| 1032 | + { |
---|
| 1033 | + .compatible = "rockchip,vpu-jpege-ccu", |
---|
| 1034 | + }, |
---|
| 1035 | +#endif |
---|
801 | 1036 | {}, |
---|
802 | 1037 | }; |
---|
803 | 1038 | |
---|
804 | | -static int vepu_probe(struct platform_device *pdev) |
---|
| 1039 | +static int vepu_ccu_probe(struct platform_device *pdev) |
---|
| 1040 | +{ |
---|
| 1041 | + struct vepu_ccu *ccu; |
---|
| 1042 | + struct device *dev = &pdev->dev; |
---|
| 1043 | + |
---|
| 1044 | + ccu = devm_kzalloc(dev, sizeof(*ccu), GFP_KERNEL); |
---|
| 1045 | + if (!ccu) |
---|
| 1046 | + return -ENOMEM; |
---|
| 1047 | + |
---|
| 1048 | + platform_set_drvdata(pdev, ccu); |
---|
| 1049 | + spin_lock_init(&ccu->lock); |
---|
| 1050 | + return 0; |
---|
| 1051 | +} |
---|
| 1052 | + |
---|
| 1053 | +static int vepu_attach_ccu(struct device *dev, struct vepu_dev *enc) |
---|
| 1054 | +{ |
---|
| 1055 | + struct device_node *np; |
---|
| 1056 | + struct platform_device *pdev; |
---|
| 1057 | + struct vepu_ccu *ccu; |
---|
| 1058 | + unsigned long flags; |
---|
| 1059 | + |
---|
| 1060 | + np = of_parse_phandle(dev->of_node, "rockchip,ccu", 0); |
---|
| 1061 | + if (!np || !of_device_is_available(np)) |
---|
| 1062 | + return -ENODEV; |
---|
| 1063 | + |
---|
| 1064 | + pdev = of_find_device_by_node(np); |
---|
| 1065 | + of_node_put(np); |
---|
| 1066 | + if (!pdev) |
---|
| 1067 | + return -ENODEV; |
---|
| 1068 | + |
---|
| 1069 | + ccu = platform_get_drvdata(pdev); |
---|
| 1070 | + if (!ccu) |
---|
| 1071 | + return -ENOMEM; |
---|
| 1072 | + |
---|
| 1073 | + spin_lock_irqsave(&ccu->lock, flags); |
---|
| 1074 | + ccu->core_num++; |
---|
| 1075 | + ccu->cores[enc->mpp.core_id] = &enc->mpp; |
---|
| 1076 | + set_bit(enc->mpp.core_id, &ccu->core_idle); |
---|
| 1077 | + spin_unlock_irqrestore(&ccu->lock, flags); |
---|
| 1078 | + |
---|
| 1079 | + /* attach the ccu-domain to current core */ |
---|
| 1080 | + if (!ccu->main_core) { |
---|
| 1081 | + /** |
---|
| 1082 | + * set the first device for the main-core, |
---|
| 1083 | + * then the domain of the main-core named ccu-domain |
---|
| 1084 | + */ |
---|
| 1085 | + ccu->main_core = &enc->mpp; |
---|
| 1086 | + } else { |
---|
| 1087 | + struct mpp_iommu_info *ccu_info, *cur_info; |
---|
| 1088 | + |
---|
| 1089 | + /* set the ccu domain for current device */ |
---|
| 1090 | + ccu_info = ccu->main_core->iommu_info; |
---|
| 1091 | + cur_info = enc->mpp.iommu_info; |
---|
| 1092 | + |
---|
| 1093 | + if (cur_info) |
---|
| 1094 | + cur_info->domain = ccu_info->domain; |
---|
| 1095 | + mpp_iommu_attach(cur_info); |
---|
| 1096 | + } |
---|
| 1097 | + enc->ccu = ccu; |
---|
| 1098 | + |
---|
| 1099 | + dev_info(dev, "attach ccu success\n"); |
---|
| 1100 | + return 0; |
---|
| 1101 | +} |
---|
| 1102 | + |
---|
| 1103 | +static int vepu_core_probe(struct platform_device *pdev) |
---|
805 | 1104 | { |
---|
806 | 1105 | struct device *dev = &pdev->dev; |
---|
807 | 1106 | struct vepu_dev *enc = NULL; |
---|
.. | .. |
---|
809 | 1108 | const struct of_device_id *match = NULL; |
---|
810 | 1109 | int ret = 0; |
---|
811 | 1110 | |
---|
812 | | - dev_info(dev, "probe device\n"); |
---|
813 | 1111 | enc = devm_kzalloc(dev, sizeof(struct vepu_dev), GFP_KERNEL); |
---|
814 | 1112 | if (!enc) |
---|
815 | 1113 | return -ENOMEM; |
---|
816 | 1114 | |
---|
817 | 1115 | mpp = &enc->mpp; |
---|
818 | | - platform_set_drvdata(pdev, enc); |
---|
| 1116 | + platform_set_drvdata(pdev, mpp); |
---|
819 | 1117 | |
---|
820 | 1118 | if (pdev->dev.of_node) { |
---|
821 | 1119 | match = of_match_node(mpp_vepu2_dt_match, pdev->dev.of_node); |
---|
822 | 1120 | if (match) |
---|
823 | 1121 | mpp->var = (struct mpp_dev_var *)match->data; |
---|
| 1122 | + |
---|
| 1123 | + mpp->core_id = of_alias_get_id(pdev->dev.of_node, "jpege"); |
---|
| 1124 | + } |
---|
| 1125 | + |
---|
| 1126 | + ret = mpp_dev_probe(mpp, pdev); |
---|
| 1127 | + if (ret) { |
---|
| 1128 | + dev_err(dev, "probe sub driver failed\n"); |
---|
| 1129 | + return -EINVAL; |
---|
| 1130 | + } |
---|
| 1131 | + /* current device attach to ccu */ |
---|
| 1132 | + ret = vepu_attach_ccu(dev, enc); |
---|
| 1133 | + if (ret) |
---|
| 1134 | + return ret; |
---|
| 1135 | + |
---|
| 1136 | + ret = devm_request_threaded_irq(dev, mpp->irq, |
---|
| 1137 | + mpp_dev_irq, |
---|
| 1138 | + mpp_dev_isr_sched, |
---|
| 1139 | + IRQF_SHARED, |
---|
| 1140 | + dev_name(dev), mpp); |
---|
| 1141 | + if (ret) { |
---|
| 1142 | + dev_err(dev, "register interrupter runtime failed\n"); |
---|
| 1143 | + return -EINVAL; |
---|
| 1144 | + } |
---|
| 1145 | + |
---|
| 1146 | + mpp->fault_handler = vepu2_iommu_fault_handle; |
---|
| 1147 | + mpp->session_max_buffers = VEPU2_SESSION_MAX_BUFFERS; |
---|
| 1148 | + vepu_procfs_init(mpp); |
---|
| 1149 | + vepu_procfs_ccu_init(mpp); |
---|
| 1150 | + /* if current is main-core, register current device to mpp service */ |
---|
| 1151 | + if (mpp == enc->ccu->main_core) |
---|
| 1152 | + mpp_dev_register_srv(mpp, mpp->srv); |
---|
| 1153 | + |
---|
| 1154 | + return 0; |
---|
| 1155 | +} |
---|
| 1156 | + |
---|
| 1157 | +static int vepu_probe_default(struct platform_device *pdev) |
---|
| 1158 | +{ |
---|
| 1159 | + struct device *dev = &pdev->dev; |
---|
| 1160 | + struct vepu_dev *enc = NULL; |
---|
| 1161 | + struct mpp_dev *mpp = NULL; |
---|
| 1162 | + const struct of_device_id *match = NULL; |
---|
| 1163 | + int ret = 0; |
---|
| 1164 | + |
---|
| 1165 | + enc = devm_kzalloc(dev, sizeof(struct vepu_dev), GFP_KERNEL); |
---|
| 1166 | + if (!enc) |
---|
| 1167 | + return -ENOMEM; |
---|
| 1168 | + |
---|
| 1169 | + mpp = &enc->mpp; |
---|
| 1170 | + platform_set_drvdata(pdev, mpp); |
---|
| 1171 | + |
---|
| 1172 | + if (pdev->dev.of_node) { |
---|
| 1173 | + match = of_match_node(mpp_vepu2_dt_match, pdev->dev.of_node); |
---|
| 1174 | + if (match) |
---|
| 1175 | + mpp->var = (struct mpp_dev_var *)match->data; |
---|
| 1176 | + |
---|
| 1177 | + mpp->core_id = of_alias_get_id(pdev->dev.of_node, "vepu"); |
---|
824 | 1178 | } |
---|
825 | 1179 | |
---|
826 | 1180 | ret = mpp_dev_probe(mpp, pdev); |
---|
.. | .. |
---|
839 | 1193 | return -EINVAL; |
---|
840 | 1194 | } |
---|
841 | 1195 | |
---|
| 1196 | + mpp->fault_handler = vepu2_iommu_fault_handle; |
---|
842 | 1197 | mpp->session_max_buffers = VEPU2_SESSION_MAX_BUFFERS; |
---|
843 | 1198 | vepu_procfs_init(mpp); |
---|
844 | 1199 | /* register current device to mpp service */ |
---|
845 | 1200 | mpp_dev_register_srv(mpp, mpp->srv); |
---|
846 | | - dev_info(dev, "probing finish\n"); |
---|
847 | 1201 | |
---|
848 | 1202 | return 0; |
---|
| 1203 | +} |
---|
| 1204 | + |
---|
| 1205 | +static int vepu_probe(struct platform_device *pdev) |
---|
| 1206 | +{ |
---|
| 1207 | + int ret; |
---|
| 1208 | + struct device *dev = &pdev->dev; |
---|
| 1209 | + struct device_node *np = dev->of_node; |
---|
| 1210 | + |
---|
| 1211 | + dev_info(dev, "probing start\n"); |
---|
| 1212 | + |
---|
| 1213 | + if (strstr(np->name, "ccu")) |
---|
| 1214 | + ret = vepu_ccu_probe(pdev); |
---|
| 1215 | + else if (strstr(np->name, "core")) |
---|
| 1216 | + ret = vepu_core_probe(pdev); |
---|
| 1217 | + else |
---|
| 1218 | + ret = vepu_probe_default(pdev); |
---|
| 1219 | + |
---|
| 1220 | + dev_info(dev, "probing finish\n"); |
---|
| 1221 | + |
---|
| 1222 | + return ret; |
---|
849 | 1223 | } |
---|
850 | 1224 | |
---|
851 | 1225 | static int vepu_remove(struct platform_device *pdev) |
---|
852 | 1226 | { |
---|
853 | 1227 | struct device *dev = &pdev->dev; |
---|
854 | | - struct vepu_dev *enc = platform_get_drvdata(pdev); |
---|
| 1228 | + struct device_node *np = dev->of_node; |
---|
855 | 1229 | |
---|
856 | | - dev_info(dev, "remove device\n"); |
---|
857 | | - mpp_dev_remove(&enc->mpp); |
---|
858 | | - vepu_procfs_remove(&enc->mpp); |
---|
| 1230 | + if (strstr(np->name, "ccu")) { |
---|
| 1231 | + dev_info(dev, "remove ccu device\n"); |
---|
| 1232 | + } else if (strstr(np->name, "core")) { |
---|
| 1233 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
---|
| 1234 | + struct vepu_dev *enc = to_vepu_dev(mpp); |
---|
| 1235 | + |
---|
| 1236 | + dev_info(dev, "remove core\n"); |
---|
| 1237 | + if (enc->ccu) { |
---|
| 1238 | + s32 core_id = mpp->core_id; |
---|
| 1239 | + struct vepu_ccu *ccu = enc->ccu; |
---|
| 1240 | + unsigned long flags; |
---|
| 1241 | + |
---|
| 1242 | + spin_lock_irqsave(&ccu->lock, flags); |
---|
| 1243 | + ccu->core_num--; |
---|
| 1244 | + ccu->cores[core_id] = NULL; |
---|
| 1245 | + clear_bit(core_id, &ccu->core_idle); |
---|
| 1246 | + spin_unlock_irqrestore(&ccu->lock, flags); |
---|
| 1247 | + } |
---|
| 1248 | + mpp_dev_remove(&enc->mpp); |
---|
| 1249 | + vepu_procfs_remove(&enc->mpp); |
---|
| 1250 | + } else { |
---|
| 1251 | + struct mpp_dev *mpp = dev_get_drvdata(dev); |
---|
| 1252 | + |
---|
| 1253 | + dev_info(dev, "remove device\n"); |
---|
| 1254 | + mpp_dev_remove(mpp); |
---|
| 1255 | + vepu_procfs_remove(mpp); |
---|
| 1256 | + } |
---|
859 | 1257 | |
---|
860 | 1258 | return 0; |
---|
861 | 1259 | } |
---|
862 | 1260 | |
---|
863 | 1261 | static void vepu_shutdown(struct platform_device *pdev) |
---|
864 | 1262 | { |
---|
865 | | - int ret; |
---|
866 | | - int val; |
---|
867 | 1263 | struct device *dev = &pdev->dev; |
---|
868 | | - struct vepu_dev *enc = platform_get_drvdata(pdev); |
---|
869 | | - struct mpp_dev *mpp = &enc->mpp; |
---|
870 | 1264 | |
---|
871 | | - dev_info(dev, "shutdown device\n"); |
---|
872 | | - |
---|
873 | | - atomic_inc(&mpp->srv->shutdown_request); |
---|
874 | | - ret = readx_poll_timeout(atomic_read, |
---|
875 | | - &mpp->task_count, |
---|
876 | | - val, val == 0, 20000, 200000); |
---|
877 | | - if (ret == -ETIMEDOUT) |
---|
878 | | - dev_err(dev, "wait total running time out\n"); |
---|
| 1265 | + if (!strstr(dev_name(dev), "ccu")) |
---|
| 1266 | + mpp_dev_shutdown(pdev); |
---|
879 | 1267 | } |
---|
880 | 1268 | |
---|
881 | 1269 | struct platform_driver rockchip_vepu2_driver = { |
---|