diff options
-rw-r--r-- | drivers/remoteproc/qcom_q6v5_pil.c | 106 |
1 files changed, 101 insertions, 5 deletions
diff --git a/drivers/remoteproc/qcom_q6v5_pil.c b/drivers/remoteproc/qcom_q6v5_pil.c index 39b9ee4a63b7..728179ba7db2 100644 --- a/drivers/remoteproc/qcom_q6v5_pil.c +++ b/drivers/remoteproc/qcom_q6v5_pil.c | |||
@@ -110,6 +110,7 @@ struct rproc_hexagon_res { | |||
110 | struct qcom_mss_reg_res *active_supply; | 110 | struct qcom_mss_reg_res *active_supply; |
111 | char **proxy_clk_names; | 111 | char **proxy_clk_names; |
112 | char **active_clk_names; | 112 | char **active_clk_names; |
113 | bool need_mem_protection; | ||
113 | }; | 114 | }; |
114 | 115 | ||
115 | struct q6v5 { | 116 | struct q6v5 { |
@@ -154,6 +155,10 @@ struct q6v5 { | |||
154 | 155 | ||
155 | struct qcom_rproc_subdev smd_subdev; | 156 | struct qcom_rproc_subdev smd_subdev; |
156 | struct qcom_rproc_ssr ssr_subdev; | 157 | struct qcom_rproc_ssr ssr_subdev; |
158 | bool need_mem_protection; | ||
159 | int mpss_perm; | ||
160 | int mba_perm; | ||
161 | |||
157 | }; | 162 | }; |
158 | 163 | ||
159 | static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, | 164 | static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, |
@@ -289,6 +294,35 @@ static struct resource_table *q6v5_find_rsc_table(struct rproc *rproc, | |||
289 | return &table; | 294 | return &table; |
290 | } | 295 | } |
291 | 296 | ||
297 | static int q6v5_xfer_mem_ownership(struct q6v5 *qproc, int *current_perm, | ||
298 | bool remote_owner, phys_addr_t addr, | ||
299 | size_t size) | ||
300 | { | ||
301 | struct qcom_scm_vmperm next; | ||
302 | int ret; | ||
303 | |||
304 | if (!qproc->need_mem_protection) | ||
305 | return 0; | ||
306 | if (remote_owner && *current_perm == BIT(QCOM_SCM_VMID_MSS_MSA)) | ||
307 | return 0; | ||
308 | if (!remote_owner && *current_perm == BIT(QCOM_SCM_VMID_HLOS)) | ||
309 | return 0; | ||
310 | |||
311 | next.vmid = remote_owner ? QCOM_SCM_VMID_MSS_MSA : QCOM_SCM_VMID_HLOS; | ||
312 | next.perm = remote_owner ? QCOM_SCM_PERM_RW : QCOM_SCM_PERM_RWX; | ||
313 | |||
314 | ret = qcom_scm_assign_mem(addr, ALIGN(size, SZ_4K), | ||
315 | current_perm, &next, 1); | ||
316 | if (ret < 0) { | ||
317 | pr_err("Failed to assign memory access in range %p to %p to %s ret = %d\n", | ||
318 | (void *)addr, (void *)(addr + size), | ||
319 | remote_owner ? "mss" : "hlos", ret); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
292 | static int q6v5_load(struct rproc *rproc, const struct firmware *fw) | 326 | static int q6v5_load(struct rproc *rproc, const struct firmware *fw) |
293 | { | 327 | { |
294 | struct q6v5 *qproc = rproc->priv; | 328 | struct q6v5 *qproc = rproc->priv; |
@@ -451,6 +485,8 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) | |||
451 | { | 485 | { |
452 | unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; | 486 | unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; |
453 | dma_addr_t phys; | 487 | dma_addr_t phys; |
488 | int mdata_perm; | ||
489 | int xferop_ret; | ||
454 | void *ptr; | 490 | void *ptr; |
455 | int ret; | 491 | int ret; |
456 | 492 | ||
@@ -462,6 +498,13 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) | |||
462 | 498 | ||
463 | memcpy(ptr, fw->data, fw->size); | 499 | memcpy(ptr, fw->data, fw->size); |
464 | 500 | ||
501 | /* Hypervisor mapping to access metadata by modem */ | ||
502 | mdata_perm = BIT(QCOM_SCM_VMID_HLOS); | ||
503 | ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, | ||
504 | true, phys, fw->size); | ||
505 | if (ret) | ||
506 | return -EAGAIN; | ||
507 | |||
465 | writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG); | 508 | writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG); |
466 | writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); | 509 | writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); |
467 | 510 | ||
@@ -471,6 +514,13 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw) | |||
471 | else if (ret < 0) | 514 | else if (ret < 0) |
472 | dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret); | 515 | dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret); |
473 | 516 | ||
517 | /* Metadata authentication done, remove modem access */ | ||
518 | xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, | ||
519 | false, phys, fw->size); | ||
520 | if (xferop_ret) | ||
521 | dev_warn(qproc->dev, | ||
522 | "mdt buffer not reclaimed system may become unstable\n"); | ||
523 | |||
474 | dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs); | 524 | dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs); |
475 | 525 | ||
476 | return ret < 0 ? ret : 0; | 526 | return ret < 0 ? ret : 0; |
@@ -578,7 +628,12 @@ static int q6v5_mpss_load(struct q6v5 *qproc) | |||
578 | size += phdr->p_memsz; | 628 | size += phdr->p_memsz; |
579 | } | 629 | } |
580 | 630 | ||
581 | /* Transfer ownership of modem ddr region with q6*/ | 631 | /* Transfer ownership of modem ddr region to q6 */ |
632 | ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, true, | ||
633 | qproc->mpss_phys, qproc->mpss_size); | ||
634 | if (ret) | ||
635 | return -EAGAIN; | ||
636 | |||
582 | boot_addr = relocate ? qproc->mpss_phys : min_addr; | 637 | boot_addr = relocate ? qproc->mpss_phys : min_addr; |
583 | writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG); | 638 | writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG); |
584 | writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); | 639 | writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); |
@@ -599,6 +654,7 @@ release_firmware: | |||
599 | static int q6v5_start(struct rproc *rproc) | 654 | static int q6v5_start(struct rproc *rproc) |
600 | { | 655 | { |
601 | struct q6v5 *qproc = (struct q6v5 *)rproc->priv; | 656 | struct q6v5 *qproc = (struct q6v5 *)rproc->priv; |
657 | int xfermemop_ret; | ||
602 | int ret; | 658 | int ret; |
603 | 659 | ||
604 | ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, | 660 | ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, |
@@ -634,11 +690,18 @@ static int q6v5_start(struct rproc *rproc) | |||
634 | goto assert_reset; | 690 | goto assert_reset; |
635 | } | 691 | } |
636 | 692 | ||
693 | /* Assign MBA image access in DDR to q6 */ | ||
694 | xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, | ||
695 | qproc->mba_phys, | ||
696 | qproc->mba_size); | ||
697 | if (xfermemop_ret) | ||
698 | goto disable_active_clks; | ||
699 | |||
637 | writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); | 700 | writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); |
638 | 701 | ||
639 | ret = q6v5proc_reset(qproc); | 702 | ret = q6v5proc_reset(qproc); |
640 | if (ret) | 703 | if (ret) |
641 | goto halt_axi_ports; | 704 | goto reclaim_mba; |
642 | 705 | ||
643 | ret = q6v5_rmb_mba_wait(qproc, 0, 5000); | 706 | ret = q6v5_rmb_mba_wait(qproc, 0, 5000); |
644 | if (ret == -ETIMEDOUT) { | 707 | if (ret == -ETIMEDOUT) { |
@@ -655,16 +718,22 @@ static int q6v5_start(struct rproc *rproc) | |||
655 | 718 | ||
656 | ret = q6v5_mpss_load(qproc); | 719 | ret = q6v5_mpss_load(qproc); |
657 | if (ret) | 720 | if (ret) |
658 | goto halt_axi_ports; | 721 | goto reclaim_mpss; |
659 | 722 | ||
660 | ret = wait_for_completion_timeout(&qproc->start_done, | 723 | ret = wait_for_completion_timeout(&qproc->start_done, |
661 | msecs_to_jiffies(5000)); | 724 | msecs_to_jiffies(5000)); |
662 | if (ret == 0) { | 725 | if (ret == 0) { |
663 | dev_err(qproc->dev, "start timed out\n"); | 726 | dev_err(qproc->dev, "start timed out\n"); |
664 | ret = -ETIMEDOUT; | 727 | ret = -ETIMEDOUT; |
665 | goto halt_axi_ports; | 728 | goto reclaim_mpss; |
666 | } | 729 | } |
667 | 730 | ||
731 | xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false, | ||
732 | qproc->mba_phys, | ||
733 | qproc->mba_size); | ||
734 | if (xfermemop_ret) | ||
735 | dev_err(qproc->dev, | ||
736 | "Failed to reclaim mba buffer system may become unstable\n"); | ||
668 | qproc->running = true; | 737 | qproc->running = true; |
669 | 738 | ||
670 | q6v5_clk_disable(qproc->dev, qproc->proxy_clks, | 739 | q6v5_clk_disable(qproc->dev, qproc->proxy_clks, |
@@ -674,12 +743,30 @@ static int q6v5_start(struct rproc *rproc) | |||
674 | 743 | ||
675 | return 0; | 744 | return 0; |
676 | 745 | ||
746 | reclaim_mpss: | ||
747 | xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, | ||
748 | false, qproc->mpss_phys, | ||
749 | qproc->mpss_size); | ||
750 | WARN_ON(xfermemop_ret); | ||
751 | |||
677 | halt_axi_ports: | 752 | halt_axi_ports: |
678 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); | 753 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); |
679 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); | 754 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); |
680 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); | 755 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); |
756 | |||
757 | reclaim_mba: | ||
758 | xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false, | ||
759 | qproc->mba_phys, | ||
760 | qproc->mba_size); | ||
761 | if (xfermemop_ret) { | ||
762 | dev_err(qproc->dev, | ||
763 | "Failed to reclaim mba buffer, system may become unstable\n"); | ||
764 | } | ||
765 | |||
766 | disable_active_clks: | ||
681 | q6v5_clk_disable(qproc->dev, qproc->active_clks, | 767 | q6v5_clk_disable(qproc->dev, qproc->active_clks, |
682 | qproc->active_clk_count); | 768 | qproc->active_clk_count); |
769 | |||
683 | assert_reset: | 770 | assert_reset: |
684 | reset_control_assert(qproc->mss_restart); | 771 | reset_control_assert(qproc->mss_restart); |
685 | disable_vdd: | 772 | disable_vdd: |
@@ -699,6 +786,7 @@ static int q6v5_stop(struct rproc *rproc) | |||
699 | { | 786 | { |
700 | struct q6v5 *qproc = (struct q6v5 *)rproc->priv; | 787 | struct q6v5 *qproc = (struct q6v5 *)rproc->priv; |
701 | int ret; | 788 | int ret; |
789 | u32 val; | ||
702 | 790 | ||
703 | qproc->running = false; | 791 | qproc->running = false; |
704 | 792 | ||
@@ -716,6 +804,10 @@ static int q6v5_stop(struct rproc *rproc) | |||
716 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); | 804 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); |
717 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); | 805 | q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); |
718 | 806 | ||
807 | ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, false, | ||
808 | qproc->mpss_phys, qproc->mpss_size); | ||
809 | WARN_ON(ret); | ||
810 | |||
719 | reset_control_assert(qproc->mss_restart); | 811 | reset_control_assert(qproc->mss_restart); |
720 | q6v5_clk_disable(qproc->dev, qproc->active_clks, | 812 | q6v5_clk_disable(qproc->dev, qproc->active_clks, |
721 | qproc->active_clk_count); | 813 | qproc->active_clk_count); |
@@ -1014,6 +1106,7 @@ static int q6v5_probe(struct platform_device *pdev) | |||
1014 | if (ret) | 1106 | if (ret) |
1015 | goto free_rproc; | 1107 | goto free_rproc; |
1016 | 1108 | ||
1109 | qproc->need_mem_protection = desc->need_mem_protection; | ||
1017 | ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt); | 1110 | ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt); |
1018 | if (ret < 0) | 1111 | if (ret < 0) |
1019 | goto free_rproc; | 1112 | goto free_rproc; |
@@ -1035,7 +1128,8 @@ static int q6v5_probe(struct platform_device *pdev) | |||
1035 | ret = PTR_ERR(qproc->state); | 1128 | ret = PTR_ERR(qproc->state); |
1036 | goto free_rproc; | 1129 | goto free_rproc; |
1037 | } | 1130 | } |
1038 | 1131 | qproc->mpss_perm = BIT(QCOM_SCM_VMID_HLOS); | |
1132 | qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); | ||
1039 | qcom_add_smd_subdev(rproc, &qproc->smd_subdev); | 1133 | qcom_add_smd_subdev(rproc, &qproc->smd_subdev); |
1040 | qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); | 1134 | qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); |
1041 | 1135 | ||
@@ -1091,6 +1185,7 @@ static const struct rproc_hexagon_res msm8916_mss = { | |||
1091 | "mem", | 1185 | "mem", |
1092 | NULL | 1186 | NULL |
1093 | }, | 1187 | }, |
1188 | .need_mem_protection = false, | ||
1094 | }; | 1189 | }; |
1095 | 1190 | ||
1096 | static const struct rproc_hexagon_res msm8974_mss = { | 1191 | static const struct rproc_hexagon_res msm8974_mss = { |
@@ -1128,6 +1223,7 @@ static const struct rproc_hexagon_res msm8974_mss = { | |||
1128 | "mem", | 1223 | "mem", |
1129 | NULL | 1224 | NULL |
1130 | }, | 1225 | }, |
1226 | .need_mem_protection = false, | ||
1131 | }; | 1227 | }; |
1132 | 1228 | ||
1133 | static const struct of_device_id q6v5_of_match[] = { | 1229 | static const struct of_device_id q6v5_of_match[] = { |