Lines Matching +full:reset +full:- +full:assert +full:- +full:ms
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Qualcomm self-authenticating modem subsystem remoteproc driver
7 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
13 #include <linux/dma-mapping.h>
26 #include <linux/reset.h>
235 if (rc != -EPROBE_DEFER) in q6v5_regulator_init()
259 dev_err(qproc->dev, in q6v5_regulator_enable()
270 dev_err(qproc->dev, in q6v5_regulator_enable()
278 dev_err(qproc->dev, "Regulator enable failed\n"); in q6v5_regulator_enable()
285 for (; i >= 0; i--) { in q6v5_regulator_enable()
330 for (i--; i >= 0; i--) in q6v5_clk_enable()
364 for (i--; i >= 0; i--) { in q6v5_pds_enable()
390 if (!qproc->need_mem_protection) in q6v5_xfer_mem_ownership()
417 if (request_firmware_direct(&dp_fw, "msadp", qproc->dev)) in q6v5_debug_policy_load()
420 if (SZ_1M + dp_fw->size <= qproc->mba_size) { in q6v5_debug_policy_load()
421 memcpy(mba_region + SZ_1M, dp_fw->data, dp_fw->size); in q6v5_debug_policy_load()
422 qproc->dp_size = dp_fw->size; in q6v5_debug_policy_load()
430 struct q6v5 *qproc = rproc->priv; in q6v5_load()
434 if (fw->size > qproc->mba_size || fw->size > SZ_1M) { in q6v5_load()
435 dev_err(qproc->dev, "MBA firmware load failed\n"); in q6v5_load()
436 return -EINVAL; in q6v5_load()
439 mba_region = memremap(qproc->mba_phys, qproc->mba_size, MEMREMAP_WC); in q6v5_load()
441 dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", in q6v5_load()
442 &qproc->mba_phys, qproc->mba_size); in q6v5_load()
443 return -EBUSY; in q6v5_load()
446 memcpy(mba_region, fw->data, fw->size); in q6v5_load()
457 if (qproc->has_alt_reset) { in q6v5_reset_assert()
458 reset_control_assert(qproc->pdc_reset); in q6v5_reset_assert()
459 ret = reset_control_reset(qproc->mss_restart); in q6v5_reset_assert()
460 reset_control_deassert(qproc->pdc_reset); in q6v5_reset_assert()
461 } else if (qproc->has_spare_reg) { in q6v5_reset_assert()
463 * When the AXI pipeline is being reset with the Q6 modem partly in q6v5_reset_assert()
467 * BIT before triggering Q6 MSS reset. AXI_GATING_VALID_OVERRIDE in q6v5_reset_assert()
468 * is withdrawn post MSS assert followed by a MSS deassert, in q6v5_reset_assert()
469 * while holding the PDC reset. in q6v5_reset_assert()
471 reset_control_assert(qproc->pdc_reset); in q6v5_reset_assert()
472 regmap_update_bits(qproc->conn_map, qproc->conn_box, in q6v5_reset_assert()
474 reset_control_assert(qproc->mss_restart); in q6v5_reset_assert()
475 reset_control_deassert(qproc->pdc_reset); in q6v5_reset_assert()
476 regmap_update_bits(qproc->conn_map, qproc->conn_box, in q6v5_reset_assert()
478 ret = reset_control_deassert(qproc->mss_restart); in q6v5_reset_assert()
480 ret = reset_control_assert(qproc->mss_restart); in q6v5_reset_assert()
490 if (qproc->has_alt_reset) { in q6v5_reset_deassert()
491 reset_control_assert(qproc->pdc_reset); in q6v5_reset_deassert()
492 writel(1, qproc->rmb_base + RMB_MBA_ALT_RESET); in q6v5_reset_deassert()
493 ret = reset_control_reset(qproc->mss_restart); in q6v5_reset_deassert()
494 writel(0, qproc->rmb_base + RMB_MBA_ALT_RESET); in q6v5_reset_deassert()
495 reset_control_deassert(qproc->pdc_reset); in q6v5_reset_deassert()
496 } else if (qproc->has_spare_reg) { in q6v5_reset_deassert()
497 ret = reset_control_reset(qproc->mss_restart); in q6v5_reset_deassert()
499 ret = reset_control_deassert(qproc->mss_restart); in q6v5_reset_deassert()
505 static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms) in q6v5_rmb_pbl_wait() argument
510 timeout = jiffies + msecs_to_jiffies(ms); in q6v5_rmb_pbl_wait()
512 val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG); in q6v5_rmb_pbl_wait()
517 return -ETIMEDOUT; in q6v5_rmb_pbl_wait()
525 static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms) in q6v5_rmb_mba_wait() argument
531 timeout = jiffies + msecs_to_jiffies(ms); in q6v5_rmb_mba_wait()
533 val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG); in q6v5_rmb_mba_wait()
543 return -ETIMEDOUT; in q6v5_rmb_mba_wait()
553 struct rproc *rproc = qproc->rproc; in q6v5_dump_mba_logs()
557 if (!qproc->has_mba_logs) in q6v5_dump_mba_logs()
560 if (q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, false, qproc->mba_phys, in q6v5_dump_mba_logs()
561 qproc->mba_size)) in q6v5_dump_mba_logs()
564 mba_region = memremap(qproc->mba_phys, qproc->mba_size, MEMREMAP_WC); in q6v5_dump_mba_logs()
571 dev_coredumpv(&rproc->dev, data, MBA_LOG_SIZE, GFP_KERNEL); in q6v5_dump_mba_logs()
582 if (qproc->version == MSS_SDM845) { in q6v5proc_reset()
583 val = readl(qproc->reg_base + QDSP6SS_SLEEP); in q6v5proc_reset()
585 writel(val, qproc->reg_base + QDSP6SS_SLEEP); in q6v5proc_reset()
587 ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_SLEEP, in q6v5proc_reset()
591 dev_err(qproc->dev, "QDSP6SS Sleep clock timed out\n"); in q6v5proc_reset()
592 return -ETIMEDOUT; in q6v5proc_reset()
595 /* De-assert QDSP6 stop core */ in q6v5proc_reset()
596 writel(1, qproc->reg_base + QDSP6SS_BOOT_CORE_START); in q6v5proc_reset()
598 writel(1, qproc->reg_base + QDSP6SS_BOOT_CMD); in q6v5proc_reset()
600 ret = readl_poll_timeout(qproc->rmb_base + RMB_MBA_MSS_STATUS, in q6v5proc_reset()
603 dev_err(qproc->dev, "Boot FSM failed to complete.\n"); in q6v5proc_reset()
604 /* Reset the modem so that boot FSM is in reset state */ in q6v5proc_reset()
610 } else if (qproc->version == MSS_SC7180) { in q6v5proc_reset()
611 val = readl(qproc->reg_base + QDSP6SS_SLEEP); in q6v5proc_reset()
613 writel(val, qproc->reg_base + QDSP6SS_SLEEP); in q6v5proc_reset()
615 ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_SLEEP, in q6v5proc_reset()
619 dev_err(qproc->dev, "QDSP6SS Sleep clock timed out\n"); in q6v5proc_reset()
620 return -ETIMEDOUT; in q6v5proc_reset()
624 val = readl(qproc->reg_base + QDSP6SS_XO_CBCR); in q6v5proc_reset()
626 writel(val, qproc->reg_base + QDSP6SS_XO_CBCR); in q6v5proc_reset()
628 ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_XO_CBCR, in q6v5proc_reset()
632 dev_err(qproc->dev, "QDSP6SS XO clock timed out\n"); in q6v5proc_reset()
633 return -ETIMEDOUT; in q6v5proc_reset()
636 /* Configure Q6 core CBCR to auto-enable after reset sequence */ in q6v5proc_reset()
637 val = readl(qproc->reg_base + QDSP6SS_CORE_CBCR); in q6v5proc_reset()
639 writel(val, qproc->reg_base + QDSP6SS_CORE_CBCR); in q6v5proc_reset()
641 /* De-assert the Q6 stop core signal */ in q6v5proc_reset()
642 writel(1, qproc->reg_base + QDSP6SS_BOOT_CORE_START); in q6v5proc_reset()
647 /* Trigger the boot FSM to start the Q6 out-of-reset sequence */ in q6v5proc_reset()
648 writel(1, qproc->reg_base + QDSP6SS_BOOT_CMD); in q6v5proc_reset()
651 ret = readl_poll_timeout(qproc->rmb_base + RMB_MBA_MSS_STATUS, in q6v5proc_reset()
654 dev_err(qproc->dev, "Boot FSM failed to complete.\n"); in q6v5proc_reset()
655 /* Reset the modem so that boot FSM is in reset state */ in q6v5proc_reset()
660 } else if (qproc->version == MSS_MSM8996 || in q6v5proc_reset()
661 qproc->version == MSS_MSM8998) { in q6v5proc_reset()
666 qproc->reg_base + QDSP6SS_STRAP_ACC); in q6v5proc_reset()
668 /* Assert resets, stop core */ in q6v5proc_reset()
669 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
671 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
674 val = readl(qproc->reg_base + QDSP6SS_XO_CBCR); in q6v5proc_reset()
676 writel(val, qproc->reg_base + QDSP6SS_XO_CBCR); in q6v5proc_reset()
679 ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_XO_CBCR, in q6v5proc_reset()
683 dev_err(qproc->dev, in q6v5proc_reset()
688 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
690 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
691 val |= readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
696 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
699 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
701 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
705 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
708 if (qproc->version == MSS_MSM8996) { in q6v5proc_reset()
716 val = readl(qproc->reg_base + mem_pwr_ctl); in q6v5proc_reset()
717 for (; i >= 0; i--) { in q6v5proc_reset()
719 writel(val, qproc->reg_base + mem_pwr_ctl); in q6v5proc_reset()
725 val |= readl(qproc->reg_base + mem_pwr_ctl); in q6v5proc_reset()
729 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
731 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
733 /* Assert resets, stop core */ in q6v5proc_reset()
734 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
736 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
739 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
741 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
742 val |= readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
748 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
751 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
753 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
755 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
757 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
761 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5proc_reset()
763 /* Bring core out of reset */ in q6v5proc_reset()
764 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
766 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
769 val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); in q6v5proc_reset()
771 writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG); in q6v5proc_reset()
774 val = readl(qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
776 writel(val, qproc->reg_base + QDSP6SS_RESET_REG); in q6v5proc_reset()
781 if (ret == -ETIMEDOUT) { in q6v5proc_reset()
782 dev_err(qproc->dev, "PBL boot timed out\n"); in q6v5proc_reset()
784 dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret); in q6v5proc_reset()
785 ret = -EINVAL; in q6v5proc_reset()
805 /* Assert halt request */ in q6v5proc_halt_axi_port()
814 dev_err(qproc->dev, "port failed halt\n"); in q6v5proc_halt_axi_port()
816 /* Clear halt request (port will remain halted until reset) */ in q6v5proc_halt_axi_port()
835 ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); in q6v5_mpss_init_image()
838 dev_err(qproc->dev, "failed to allocate mdt buffer\n"); in q6v5_mpss_init_image()
839 return -ENOMEM; in q6v5_mpss_init_image()
849 dev_err(qproc->dev, in q6v5_mpss_init_image()
851 ret = -EAGAIN; in q6v5_mpss_init_image()
855 writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG); in q6v5_mpss_init_image()
856 writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); in q6v5_mpss_init_image()
859 if (ret == -ETIMEDOUT) in q6v5_mpss_init_image()
860 dev_err(qproc->dev, "MPSS header authentication timed out\n"); in q6v5_mpss_init_image()
862 dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret); in q6v5_mpss_init_image()
868 dev_warn(qproc->dev, in q6v5_mpss_init_image()
872 dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs); in q6v5_mpss_init_image()
880 if (phdr->p_type != PT_LOAD) in q6v5_phdr_valid()
883 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) in q6v5_phdr_valid()
886 if (!phdr->p_memsz) in q6v5_phdr_valid()
898 qcom_q6v5_prepare(&qproc->q6v5); in q6v5_mba_load()
900 ret = q6v5_pds_enable(qproc, qproc->active_pds, qproc->active_pd_count); in q6v5_mba_load()
902 dev_err(qproc->dev, "failed to enable active power domains\n"); in q6v5_mba_load()
906 ret = q6v5_pds_enable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); in q6v5_mba_load()
908 dev_err(qproc->dev, "failed to enable proxy power domains\n"); in q6v5_mba_load()
912 ret = q6v5_regulator_enable(qproc, qproc->fallback_proxy_regs, in q6v5_mba_load()
913 qproc->fallback_proxy_reg_count); in q6v5_mba_load()
915 dev_err(qproc->dev, "failed to enable fallback proxy supplies\n"); in q6v5_mba_load()
919 ret = q6v5_regulator_enable(qproc, qproc->proxy_regs, in q6v5_mba_load()
920 qproc->proxy_reg_count); in q6v5_mba_load()
922 dev_err(qproc->dev, "failed to enable proxy supplies\n"); in q6v5_mba_load()
926 ret = q6v5_clk_enable(qproc->dev, qproc->proxy_clks, in q6v5_mba_load()
927 qproc->proxy_clk_count); in q6v5_mba_load()
929 dev_err(qproc->dev, "failed to enable proxy clocks\n"); in q6v5_mba_load()
933 ret = q6v5_regulator_enable(qproc, qproc->active_regs, in q6v5_mba_load()
934 qproc->active_reg_count); in q6v5_mba_load()
936 dev_err(qproc->dev, "failed to enable supplies\n"); in q6v5_mba_load()
940 ret = q6v5_clk_enable(qproc->dev, qproc->reset_clks, in q6v5_mba_load()
941 qproc->reset_clk_count); in q6v5_mba_load()
943 dev_err(qproc->dev, "failed to enable reset clocks\n"); in q6v5_mba_load()
949 dev_err(qproc->dev, "failed to deassert mss restart\n"); in q6v5_mba_load()
953 ret = q6v5_clk_enable(qproc->dev, qproc->active_clks, in q6v5_mba_load()
954 qproc->active_clk_count); in q6v5_mba_load()
956 dev_err(qproc->dev, "failed to enable clocks\n"); in q6v5_mba_load()
964 ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, false, true, in q6v5_mba_load()
965 qproc->mpss_phys, qproc->mpss_size); in q6v5_mba_load()
967 dev_err(qproc->dev, "assigning Q6 access to mpss memory failed: %d\n", ret); in q6v5_mba_load()
972 ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, false, true, in q6v5_mba_load()
973 qproc->mba_phys, qproc->mba_size); in q6v5_mba_load()
975 dev_err(qproc->dev, in q6v5_mba_load()
980 writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); in q6v5_mba_load()
981 if (qproc->dp_size) { in q6v5_mba_load()
982 writel(qproc->mba_phys + SZ_1M, qproc->rmb_base + RMB_PMI_CODE_START_REG); in q6v5_mba_load()
983 writel(qproc->dp_size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); in q6v5_mba_load()
991 if (ret == -ETIMEDOUT) { in q6v5_mba_load()
992 dev_err(qproc->dev, "MBA boot timed out\n"); in q6v5_mba_load()
996 dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret); in q6v5_mba_load()
997 ret = -EINVAL; in q6v5_mba_load()
1001 qproc->dump_mba_loaded = true; in q6v5_mba_load()
1005 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); in q6v5_mba_load()
1006 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); in q6v5_mba_load()
1007 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); in q6v5_mba_load()
1010 xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, in q6v5_mba_load()
1011 false, qproc->mba_phys, in q6v5_mba_load()
1012 qproc->mba_size); in q6v5_mba_load()
1014 dev_err(qproc->dev, in q6v5_mba_load()
1021 q6v5_clk_disable(qproc->dev, qproc->active_clks, in q6v5_mba_load()
1022 qproc->active_clk_count); in q6v5_mba_load()
1026 q6v5_clk_disable(qproc->dev, qproc->reset_clks, in q6v5_mba_load()
1027 qproc->reset_clk_count); in q6v5_mba_load()
1029 q6v5_regulator_disable(qproc, qproc->active_regs, in q6v5_mba_load()
1030 qproc->active_reg_count); in q6v5_mba_load()
1032 q6v5_clk_disable(qproc->dev, qproc->proxy_clks, in q6v5_mba_load()
1033 qproc->proxy_clk_count); in q6v5_mba_load()
1035 q6v5_regulator_disable(qproc, qproc->proxy_regs, in q6v5_mba_load()
1036 qproc->proxy_reg_count); in q6v5_mba_load()
1038 q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs, in q6v5_mba_load()
1039 qproc->fallback_proxy_reg_count); in q6v5_mba_load()
1041 q6v5_pds_disable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); in q6v5_mba_load()
1043 q6v5_pds_disable(qproc, qproc->active_pds, qproc->active_pd_count); in q6v5_mba_load()
1045 qcom_q6v5_unprepare(&qproc->q6v5); in q6v5_mba_load()
1055 qproc->dump_mba_loaded = false; in q6v5_mba_reclaim()
1056 qproc->dp_size = 0; in q6v5_mba_reclaim()
1058 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); in q6v5_mba_reclaim()
1059 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); in q6v5_mba_reclaim()
1060 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); in q6v5_mba_reclaim()
1061 if (qproc->version == MSS_MSM8996) { in q6v5_mba_reclaim()
1065 val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5_mba_reclaim()
1068 writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG); in q6v5_mba_reclaim()
1073 q6v5_clk_disable(qproc->dev, qproc->reset_clks, in q6v5_mba_reclaim()
1074 qproc->reset_clk_count); in q6v5_mba_reclaim()
1075 q6v5_clk_disable(qproc->dev, qproc->active_clks, in q6v5_mba_reclaim()
1076 qproc->active_clk_count); in q6v5_mba_reclaim()
1077 q6v5_regulator_disable(qproc, qproc->active_regs, in q6v5_mba_reclaim()
1078 qproc->active_reg_count); in q6v5_mba_reclaim()
1079 q6v5_pds_disable(qproc, qproc->active_pds, qproc->active_pd_count); in q6v5_mba_reclaim()
1084 ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, false, in q6v5_mba_reclaim()
1085 qproc->mba_phys, in q6v5_mba_reclaim()
1086 qproc->mba_size); in q6v5_mba_reclaim()
1089 ret = qcom_q6v5_unprepare(&qproc->q6v5); in q6v5_mba_reclaim()
1091 q6v5_pds_disable(qproc, qproc->proxy_pds, in q6v5_mba_reclaim()
1092 qproc->proxy_pd_count); in q6v5_mba_reclaim()
1093 q6v5_clk_disable(qproc->dev, qproc->proxy_clks, in q6v5_mba_reclaim()
1094 qproc->proxy_clk_count); in q6v5_mba_reclaim()
1095 q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs, in q6v5_mba_reclaim()
1096 qproc->fallback_proxy_reg_count); in q6v5_mba_reclaim()
1097 q6v5_regulator_disable(qproc, qproc->proxy_regs, in q6v5_mba_reclaim()
1098 qproc->proxy_reg_count); in q6v5_mba_reclaim()
1104 struct q6v5 *qproc = rproc->priv; in q6v5_reload_mba()
1108 ret = request_firmware(&fw, rproc->firmware, qproc->dev); in q6v5_reload_mba()
1140 fw_name_len = strlen(qproc->hexagon_mdt_image); in q6v5_mpss_load()
1142 return -EINVAL; in q6v5_mpss_load()
1144 fw_name = kstrdup(qproc->hexagon_mdt_image, GFP_KERNEL); in q6v5_mpss_load()
1146 return -ENOMEM; in q6v5_mpss_load()
1148 ret = request_firmware(&fw, fw_name, qproc->dev); in q6v5_mpss_load()
1150 dev_err(qproc->dev, "unable to load %s\n", fw_name); in q6v5_mpss_load()
1155 writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); in q6v5_mpss_load()
1161 ehdr = (struct elf32_hdr *)fw->data; in q6v5_mpss_load()
1164 for (i = 0; i < ehdr->e_phnum; i++) { in q6v5_mpss_load()
1170 if (phdr->p_flags & QCOM_MDT_RELOCATABLE) in q6v5_mpss_load()
1173 if (phdr->p_paddr < min_addr) in q6v5_mpss_load()
1174 min_addr = phdr->p_paddr; in q6v5_mpss_load()
1176 if (phdr->p_paddr + phdr->p_memsz > max_addr) in q6v5_mpss_load()
1177 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); in q6v5_mpss_load()
1184 q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, true, false, in q6v5_mpss_load()
1185 qproc->mpss_phys, qproc->mpss_size); in q6v5_mpss_load()
1188 ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, true, true, in q6v5_mpss_load()
1189 qproc->mpss_phys, qproc->mpss_size); in q6v5_mpss_load()
1191 dev_err(qproc->dev, in q6v5_mpss_load()
1193 ret = -EAGAIN; in q6v5_mpss_load()
1197 mpss_reloc = relocate ? min_addr : qproc->mpss_phys; in q6v5_mpss_load()
1198 qproc->mpss_reloc = mpss_reloc; in q6v5_mpss_load()
1200 for (i = 0; i < ehdr->e_phnum; i++) { in q6v5_mpss_load()
1206 offset = phdr->p_paddr - mpss_reloc; in q6v5_mpss_load()
1207 if (offset < 0 || offset + phdr->p_memsz > qproc->mpss_size) { in q6v5_mpss_load()
1208 dev_err(qproc->dev, "segment outside memory range\n"); in q6v5_mpss_load()
1209 ret = -EINVAL; in q6v5_mpss_load()
1213 if (phdr->p_filesz > phdr->p_memsz) { in q6v5_mpss_load()
1214 dev_err(qproc->dev, in q6v5_mpss_load()
1217 ret = -EINVAL; in q6v5_mpss_load()
1221 ptr = memremap(qproc->mpss_phys + offset, phdr->p_memsz, MEMREMAP_WC); in q6v5_mpss_load()
1223 dev_err(qproc->dev, in q6v5_mpss_load()
1224 "unable to map memory region: %pa+%zx-%x\n", in q6v5_mpss_load()
1225 &qproc->mpss_phys, offset, phdr->p_memsz); in q6v5_mpss_load()
1229 if (phdr->p_filesz && phdr->p_offset < fw->size) { in q6v5_mpss_load()
1230 /* Firmware is large enough to be non-split */ in q6v5_mpss_load()
1231 if (phdr->p_offset + phdr->p_filesz > fw->size) { in q6v5_mpss_load()
1232 dev_err(qproc->dev, in q6v5_mpss_load()
1235 ret = -EINVAL; in q6v5_mpss_load()
1240 memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz); in q6v5_mpss_load()
1241 } else if (phdr->p_filesz) { in q6v5_mpss_load()
1243 sprintf(fw_name + fw_name_len - 3, "b%02d", i); in q6v5_mpss_load()
1244 ret = request_firmware_into_buf(&seg_fw, fw_name, qproc->dev, in q6v5_mpss_load()
1245 ptr, phdr->p_filesz); in q6v5_mpss_load()
1247 dev_err(qproc->dev, "failed to load %s\n", fw_name); in q6v5_mpss_load()
1252 if (seg_fw->size != phdr->p_filesz) { in q6v5_mpss_load()
1253 dev_err(qproc->dev, in q6v5_mpss_load()
1256 ret = -EINVAL; in q6v5_mpss_load()
1265 if (phdr->p_memsz > phdr->p_filesz) { in q6v5_mpss_load()
1266 memset(ptr + phdr->p_filesz, 0, in q6v5_mpss_load()
1267 phdr->p_memsz - phdr->p_filesz); in q6v5_mpss_load()
1270 size += phdr->p_memsz; in q6v5_mpss_load()
1272 code_length = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); in q6v5_mpss_load()
1274 boot_addr = relocate ? qproc->mpss_phys : min_addr; in q6v5_mpss_load()
1275 writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG); in q6v5_mpss_load()
1276 writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG); in q6v5_mpss_load()
1278 writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); in q6v5_mpss_load()
1280 ret = readl(qproc->rmb_base + RMB_MBA_STATUS_REG); in q6v5_mpss_load()
1282 dev_err(qproc->dev, "MPSS authentication failed: %d\n", in q6v5_mpss_load()
1289 ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, false, true, in q6v5_mpss_load()
1290 qproc->mpss_phys, qproc->mpss_size); in q6v5_mpss_load()
1292 dev_err(qproc->dev, in q6v5_mpss_load()
1294 ret = -EAGAIN; in q6v5_mpss_load()
1299 if (ret == -ETIMEDOUT) in q6v5_mpss_load()
1300 dev_err(qproc->dev, "MPSS authentication timed out\n"); in q6v5_mpss_load()
1302 dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret); in q6v5_mpss_load()
1304 qcom_pil_info_store("modem", qproc->mpss_phys, qproc->mpss_size); in q6v5_mpss_load()
1319 struct q6v5 *qproc = rproc->priv; in qcom_q6v5_dump_segment()
1320 int offset = segment->da - qproc->mpss_reloc; in qcom_q6v5_dump_segment()
1324 if (!qproc->dump_mba_loaded) { in qcom_q6v5_dump_segment()
1327 /* Reset ownership back to Linux to copy segments */ in qcom_q6v5_dump_segment()
1328 ret = q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, in qcom_q6v5_dump_segment()
1330 qproc->mpss_phys, in qcom_q6v5_dump_segment()
1331 qproc->mpss_size); in qcom_q6v5_dump_segment()
1336 ptr = memremap(qproc->mpss_phys + offset + cp_offset, size, MEMREMAP_WC); in qcom_q6v5_dump_segment()
1345 qproc->current_dump_size += size; in qcom_q6v5_dump_segment()
1348 if (qproc->current_dump_size == qproc->total_dump_size) { in qcom_q6v5_dump_segment()
1349 if (qproc->dump_mba_loaded) { in qcom_q6v5_dump_segment()
1350 /* Try to reset ownership back to Q6 */ in qcom_q6v5_dump_segment()
1351 q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, in qcom_q6v5_dump_segment()
1353 qproc->mpss_phys, in qcom_q6v5_dump_segment()
1354 qproc->mpss_size); in qcom_q6v5_dump_segment()
1362 struct q6v5 *qproc = (struct q6v5 *)rproc->priv; in q6v5_start()
1370 dev_info(qproc->dev, "MBA booted with%s debug policy, loading mpss\n", in q6v5_start()
1371 qproc->dp_size ? "" : "out"); in q6v5_start()
1377 ret = qcom_q6v5_wait_for_start(&qproc->q6v5, msecs_to_jiffies(5000)); in q6v5_start()
1378 if (ret == -ETIMEDOUT) { in q6v5_start()
1379 dev_err(qproc->dev, "start timed out\n"); in q6v5_start()
1383 xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, in q6v5_start()
1384 false, qproc->mba_phys, in q6v5_start()
1385 qproc->mba_size); in q6v5_start()
1387 dev_err(qproc->dev, in q6v5_start()
1390 /* Reset Dump Segment Mask */ in q6v5_start()
1391 qproc->current_dump_size = 0; in q6v5_start()
1404 struct q6v5 *qproc = (struct q6v5 *)rproc->priv; in q6v5_stop()
1407 ret = qcom_q6v5_request_stop(&qproc->q6v5, qproc->sysmon); in q6v5_stop()
1408 if (ret == -ETIMEDOUT) in q6v5_stop()
1409 dev_err(qproc->dev, "timed out on wait\n"); in q6v5_stop()
1423 struct q6v5 *qproc = rproc->priv; in qcom_q6v5_register_dump_segments()
1427 ret = request_firmware(&fw, qproc->hexagon_mdt_image, qproc->dev); in qcom_q6v5_register_dump_segments()
1429 dev_err(qproc->dev, "unable to load %s\n", in qcom_q6v5_register_dump_segments()
1430 qproc->hexagon_mdt_image); in qcom_q6v5_register_dump_segments()
1436 ehdr = (struct elf32_hdr *)fw->data; in qcom_q6v5_register_dump_segments()
1438 qproc->total_dump_size = 0; in qcom_q6v5_register_dump_segments()
1440 for (i = 0; i < ehdr->e_phnum; i++) { in qcom_q6v5_register_dump_segments()
1446 ret = rproc_coredump_add_custom_segment(rproc, phdr->p_paddr, in qcom_q6v5_register_dump_segments()
1447 phdr->p_memsz, in qcom_q6v5_register_dump_segments()
1453 qproc->total_dump_size += phdr->p_memsz; in qcom_q6v5_register_dump_segments()
1471 q6v5_clk_disable(qproc->dev, qproc->proxy_clks, in qcom_msa_handover()
1472 qproc->proxy_clk_count); in qcom_msa_handover()
1473 q6v5_regulator_disable(qproc, qproc->proxy_regs, in qcom_msa_handover()
1474 qproc->proxy_reg_count); in qcom_msa_handover()
1475 q6v5_regulator_disable(qproc, qproc->fallback_proxy_regs, in qcom_msa_handover()
1476 qproc->fallback_proxy_reg_count); in qcom_msa_handover()
1477 q6v5_pds_disable(qproc, qproc->proxy_pds, qproc->proxy_pd_count); in qcom_msa_handover()
1487 qproc->reg_base = devm_ioremap_resource(&pdev->dev, res); in q6v5_init_mem()
1488 if (IS_ERR(qproc->reg_base)) in q6v5_init_mem()
1489 return PTR_ERR(qproc->reg_base); in q6v5_init_mem()
1492 qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res); in q6v5_init_mem()
1493 if (IS_ERR(qproc->rmb_base)) in q6v5_init_mem()
1494 return PTR_ERR(qproc->rmb_base); in q6v5_init_mem()
1496 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, in q6v5_init_mem()
1497 "qcom,halt-regs", 3, 0, &args); in q6v5_init_mem()
1499 dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); in q6v5_init_mem()
1500 return -EINVAL; in q6v5_init_mem()
1503 qproc->halt_map = syscon_node_to_regmap(args.np); in q6v5_init_mem()
1505 if (IS_ERR(qproc->halt_map)) in q6v5_init_mem()
1506 return PTR_ERR(qproc->halt_map); in q6v5_init_mem()
1508 qproc->halt_q6 = args.args[0]; in q6v5_init_mem()
1509 qproc->halt_modem = args.args[1]; in q6v5_init_mem()
1510 qproc->halt_nc = args.args[2]; in q6v5_init_mem()
1512 if (qproc->has_spare_reg) { in q6v5_init_mem()
1513 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, in q6v5_init_mem()
1514 "qcom,spare-regs", in q6v5_init_mem()
1517 dev_err(&pdev->dev, "failed to parse spare-regs\n"); in q6v5_init_mem()
1518 return -EINVAL; in q6v5_init_mem()
1521 qproc->conn_map = syscon_node_to_regmap(args.np); in q6v5_init_mem()
1523 if (IS_ERR(qproc->conn_map)) in q6v5_init_mem()
1524 return PTR_ERR(qproc->conn_map); in q6v5_init_mem()
1526 qproc->conn_box = args.args[0]; in q6v5_init_mem()
1545 if (rc != -EPROBE_DEFER) in q6v5_init_clocks()
1571 ret = PTR_ERR(devs[i]) ? : -ENODATA; in q6v5_pds_attach()
1579 for (i--; i >= 0; i--) in q6v5_pds_attach()
1596 qproc->mss_restart = devm_reset_control_get_exclusive(qproc->dev, in q6v5_init_reset()
1598 if (IS_ERR(qproc->mss_restart)) { in q6v5_init_reset()
1599 dev_err(qproc->dev, "failed to acquire mss restart\n"); in q6v5_init_reset()
1600 return PTR_ERR(qproc->mss_restart); in q6v5_init_reset()
1603 if (qproc->has_alt_reset || qproc->has_spare_reg) { in q6v5_init_reset()
1604 qproc->pdc_reset = devm_reset_control_get_exclusive(qproc->dev, in q6v5_init_reset()
1606 if (IS_ERR(qproc->pdc_reset)) { in q6v5_init_reset()
1607 dev_err(qproc->dev, "failed to acquire pdc reset\n"); in q6v5_init_reset()
1608 return PTR_ERR(qproc->pdc_reset); in q6v5_init_reset()
1623 * In the absence of mba/mpss sub-child, extract the mba and mpss in q6v5_alloc_memory_region()
1624 * reserved memory regions from device's memory-region property. in q6v5_alloc_memory_region()
1626 child = of_get_child_by_name(qproc->dev->of_node, "mba"); in q6v5_alloc_memory_region()
1628 node = of_parse_phandle(qproc->dev->of_node, in q6v5_alloc_memory_region()
1629 "memory-region", 0); in q6v5_alloc_memory_region()
1631 node = of_parse_phandle(child, "memory-region", 0); in q6v5_alloc_memory_region()
1635 dev_err(qproc->dev, "unable to resolve mba region\n"); in q6v5_alloc_memory_region()
1640 qproc->mba_phys = r.start; in q6v5_alloc_memory_region()
1641 qproc->mba_size = resource_size(&r); in q6v5_alloc_memory_region()
1644 node = of_parse_phandle(qproc->dev->of_node, in q6v5_alloc_memory_region()
1645 "memory-region", 1); in q6v5_alloc_memory_region()
1647 child = of_get_child_by_name(qproc->dev->of_node, "mpss"); in q6v5_alloc_memory_region()
1648 node = of_parse_phandle(child, "memory-region", 0); in q6v5_alloc_memory_region()
1653 dev_err(qproc->dev, "unable to resolve mpss region\n"); in q6v5_alloc_memory_region()
1658 qproc->mpss_phys = qproc->mpss_reloc = r.start; in q6v5_alloc_memory_region()
1659 qproc->mpss_size = resource_size(&r); in q6v5_alloc_memory_region()
1672 desc = of_device_get_match_data(&pdev->dev); in q6v5_probe()
1674 return -EINVAL; in q6v5_probe()
1676 if (desc->need_mem_protection && !qcom_scm_is_available()) in q6v5_probe()
1677 return -EPROBE_DEFER; in q6v5_probe()
1679 mba_image = desc->hexagon_mba_image; in q6v5_probe()
1680 ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", in q6v5_probe()
1682 if (ret < 0 && ret != -EINVAL) { in q6v5_probe()
1683 dev_err(&pdev->dev, "unable to read mba firmware-name\n"); in q6v5_probe()
1687 rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops, in q6v5_probe()
1690 dev_err(&pdev->dev, "failed to allocate rproc\n"); in q6v5_probe()
1691 return -ENOMEM; in q6v5_probe()
1694 rproc->auto_boot = false; in q6v5_probe()
1697 qproc = (struct q6v5 *)rproc->priv; in q6v5_probe()
1698 qproc->dev = &pdev->dev; in q6v5_probe()
1699 qproc->rproc = rproc; in q6v5_probe()
1700 qproc->hexagon_mdt_image = "modem.mdt"; in q6v5_probe()
1701 ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", in q6v5_probe()
1702 1, &qproc->hexagon_mdt_image); in q6v5_probe()
1703 if (ret < 0 && ret != -EINVAL) { in q6v5_probe()
1704 dev_err(&pdev->dev, "unable to read mpss firmware-name\n"); in q6v5_probe()
1710 qproc->has_spare_reg = desc->has_spare_reg; in q6v5_probe()
1719 ret = q6v5_init_clocks(&pdev->dev, qproc->proxy_clks, in q6v5_probe()
1720 desc->proxy_clk_names); in q6v5_probe()
1722 dev_err(&pdev->dev, "Failed to get proxy clocks.\n"); in q6v5_probe()
1725 qproc->proxy_clk_count = ret; in q6v5_probe()
1727 ret = q6v5_init_clocks(&pdev->dev, qproc->reset_clks, in q6v5_probe()
1728 desc->reset_clk_names); in q6v5_probe()
1730 dev_err(&pdev->dev, "Failed to get reset clocks.\n"); in q6v5_probe()
1733 qproc->reset_clk_count = ret; in q6v5_probe()
1735 ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks, in q6v5_probe()
1736 desc->active_clk_names); in q6v5_probe()
1738 dev_err(&pdev->dev, "Failed to get active clocks.\n"); in q6v5_probe()
1741 qproc->active_clk_count = ret; in q6v5_probe()
1743 ret = q6v5_regulator_init(&pdev->dev, qproc->proxy_regs, in q6v5_probe()
1744 desc->proxy_supply); in q6v5_probe()
1746 dev_err(&pdev->dev, "Failed to get proxy regulators.\n"); in q6v5_probe()
1749 qproc->proxy_reg_count = ret; in q6v5_probe()
1751 ret = q6v5_regulator_init(&pdev->dev, qproc->active_regs, in q6v5_probe()
1752 desc->active_supply); in q6v5_probe()
1754 dev_err(&pdev->dev, "Failed to get active regulators.\n"); in q6v5_probe()
1757 qproc->active_reg_count = ret; in q6v5_probe()
1759 ret = q6v5_pds_attach(&pdev->dev, qproc->active_pds, in q6v5_probe()
1760 desc->active_pd_names); in q6v5_probe()
1762 dev_err(&pdev->dev, "Failed to attach active power domains\n"); in q6v5_probe()
1765 qproc->active_pd_count = ret; in q6v5_probe()
1767 ret = q6v5_pds_attach(&pdev->dev, qproc->proxy_pds, in q6v5_probe()
1768 desc->proxy_pd_names); in q6v5_probe()
1770 if (ret == -ENODATA && desc->fallback_proxy_supply) { in q6v5_probe()
1771 ret = q6v5_regulator_init(&pdev->dev, in q6v5_probe()
1772 qproc->fallback_proxy_regs, in q6v5_probe()
1773 desc->fallback_proxy_supply); in q6v5_probe()
1775 dev_err(&pdev->dev, "Failed to get fallback proxy regulators.\n"); in q6v5_probe()
1778 qproc->fallback_proxy_reg_count = ret; in q6v5_probe()
1780 dev_err(&pdev->dev, "Failed to init power domains\n"); in q6v5_probe()
1783 qproc->proxy_pd_count = ret; in q6v5_probe()
1786 qproc->has_alt_reset = desc->has_alt_reset; in q6v5_probe()
1791 qproc->version = desc->version; in q6v5_probe()
1792 qproc->need_mem_protection = desc->need_mem_protection; in q6v5_probe()
1793 qproc->has_mba_logs = desc->has_mba_logs; in q6v5_probe()
1795 ret = qcom_q6v5_init(&qproc->q6v5, pdev, rproc, MPSS_CRASH_REASON_SMEM, in q6v5_probe()
1800 qproc->mpss_perm = BIT(QCOM_SCM_VMID_HLOS); in q6v5_probe()
1801 qproc->mba_perm = BIT(QCOM_SCM_VMID_HLOS); in q6v5_probe()
1802 qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss"); in q6v5_probe()
1803 qcom_add_smd_subdev(rproc, &qproc->smd_subdev); in q6v5_probe()
1804 qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); in q6v5_probe()
1805 qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12); in q6v5_probe()
1806 if (IS_ERR(qproc->sysmon)) { in q6v5_probe()
1807 ret = PTR_ERR(qproc->sysmon); in q6v5_probe()
1818 qcom_remove_sysmon_subdev(qproc->sysmon); in q6v5_probe()
1820 qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev); in q6v5_probe()
1821 qcom_remove_smd_subdev(rproc, &qproc->smd_subdev); in q6v5_probe()
1822 qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); in q6v5_probe()
1824 q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count); in q6v5_probe()
1826 q6v5_pds_detach(qproc, qproc->active_pds, qproc->active_pd_count); in q6v5_probe()
1836 struct rproc *rproc = qproc->rproc; in q6v5_remove()
1840 qcom_remove_sysmon_subdev(qproc->sysmon); in q6v5_remove()
1841 qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev); in q6v5_remove()
1842 qcom_remove_smd_subdev(rproc, &qproc->smd_subdev); in q6v5_remove()
1843 qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); in q6v5_remove()
1845 q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count); in q6v5_remove()
1846 q6v5_pds_detach(qproc, qproc->active_pds, qproc->active_pd_count); in q6v5_remove()
2075 { .compatible = "qcom,q6v5-pil", .data = &msm8916_mss},
2076 { .compatible = "qcom,msm8916-mss-pil", .data = &msm8916_mss},
2077 { .compatible = "qcom,msm8974-mss-pil", .data = &msm8974_mss},
2078 { .compatible = "qcom,msm8996-mss-pil", .data = &msm8996_mss},
2079 { .compatible = "qcom,msm8998-mss-pil", .data = &msm8998_mss},
2080 { .compatible = "qcom,sc7180-mss-pil", .data = &sc7180_mss},
2081 { .compatible = "qcom,sdm845-mss-pil", .data = &sdm845_mss},
2090 .name = "qcom-q6v5-mss",
2096 MODULE_DESCRIPTION("Qualcomm Self-authenticating modem remoteproc driver");