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); | ||
