diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-26 12:18:36 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-26 12:18:36 -0800 |
commit | f3a2439f20d918930cc4ae8f76fe1c1afd26958f (patch) | |
tree | b74738bccf65a4d50dd908859537fd39ca13c922 /drivers/remoteproc/qcom_q6v5_adsp.c | |
parent | cc38a46de76e15d20bea5768e99af17b65a9caeb (diff) | |
parent | 7c855ef7137a67bcff0e039691b969428dd8ef6a (diff) | |
download | linux-f3a2439f20d918930cc4ae8f76fe1c1afd26958f.tar.gz linux-f3a2439f20d918930cc4ae8f76fe1c1afd26958f.tar.bz2 linux-f3a2439f20d918930cc4ae8f76fe1c1afd26958f.zip |
Merge tag 'rproc-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux
Pull remoteproc updates from Bjorn Andersson:
- Support for PRU clients to acquire a control reference to the PRU
instances is introduced, and the PRU now allows specifying
firmware-name in Devicetree. sysfs is requested to be read-only when
the remoteproc instance is consumed by another kernel driver
- Support for the C7xv DSP on AM62A SoC is introduced
- The Devicetree binding for the Qualcomm PAS devices are split up in
multiple files, to better account for the differences in resources
between them. A number of missing Devicetree bindings are added, and
the Qualcomm WCNSS binding is converted to YAML
- A few cleanups are introduced for the Mediatek SCP driver. And a
sanity check of the firmware image is introduced in the Mediatek
driver
- For Qualcomm SC7280 ADSP support is added, MSM8953 gains ADSP and
modem support, SM6115 and SM8550 gains ADSP, CDSP and modem support,
and support for pronto v3 support (used on e.g. MSM8953) is added
- The Qualcomm modem remoteproc driver is modified to use a no-map
reserved-memory region for it's authentication metadata, in order to
avoid fatal security violations caused by accesses from Linux during
the authentication process
- Support for separate loading of a Devicetree blob is added to the PAS
driver, and support for the PAS driver to carve out DSM memory for
the modem is added as well
- The Qualcomm ADSP remoteproc driver gains support for mapping memory
into specific range using the IOMMU. The sysmon driver is
transitioned to strlcpy()
* tag 'rproc-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux: (69 commits)
dt-bindings: mailbox: qcom,apcs-kpss-global: drop mbox-names from example
dt-bindings: remoteproc: qcom,glink-edge: correct label description
dt-bindings: remoteproc: qcom,glink-rpm-edge: convert to DT schema
dt-bindings: remoteproc: qcom,sm8550-pas: correct power domains
remoteproc: qcom_q6v5_pas: enable sm8550 adsp & cdsp autoboot
dt-bindings: remoteproc: qcom: Add sm6115 pas yaml file
remoteproc: qcom: pas: Add sm6115 remoteprocs
remoteproc: qcom: pas: Adjust the phys addr wrt the mem region
remoteproc: qcom: fix sparse warnings
remoteproc: qcom: replace kstrdup with kstrndup
remoteproc: mediatek: Check the SCP image format
remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers
Revert "remoteproc: qcom_q6v5_mss: map/unmap metadata region before/after use"
dt-bindings: remoteproc: qcom,sc7280-mss-pil: Update memory-region
dt-bindings: remoteproc: qcom,sc7180-mss-pil: Update memory-region
dt-bindings: remoteproc: qcom,msm8996-mss-pil: Update memory region
dt-bindings: remoteproc: qcom,q6v5: Move MSM8996 to schema
remoteproc: qcom_q6v5_pas: add sm8550 adsp, cdsp & mpss compatible & data
remoteproc: qcom_q6v5_pas: add support for assigning memory to firmware
remoteproc: qcom_q6v5_pas: add support for dtb co-firmware loading
...
Diffstat (limited to 'drivers/remoteproc/qcom_q6v5_adsp.c')
-rw-r--r-- | drivers/remoteproc/qcom_q6v5_adsp.c | 125 |
1 files changed, 121 insertions, 4 deletions
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 4c9a1b99cd51..08d8dad22ca7 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -9,6 +9,7 @@ #include <linux/firmware.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iommu.h> #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/mfd/syscon.h> @@ -48,12 +49,18 @@ #define LPASS_PWR_ON_REG 0x10 #define LPASS_HALTREQ_REG 0x0 +#define SID_MASK_DEFAULT 0xF + #define QDSP6SS_XO_CBCR 0x38 #define QDSP6SS_CORE_CBCR 0x20 #define QDSP6SS_SLEEP_CBCR 0x3c #define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3 +#define LPASS_BOOT_CORE_START BIT(0) +#define LPASS_BOOT_CMD_START BIT(0) +#define LPASS_EFUSE_Q6SS_EVB_SEL 0x0 + struct adsp_pil_data { int crash_reason_smem; const char *firmware_name; @@ -62,6 +69,7 @@ struct adsp_pil_data { const char *sysmon_name; int ssctl_id; bool is_wpss; + bool has_iommu; bool auto_boot; const char **clk_ids; @@ -82,6 +90,7 @@ struct qcom_adsp { struct clk_bulk_data *clks; void __iomem *qdsp6ss_base; + void __iomem *lpass_efuse; struct reset_control *pdc_sync_reset; struct reset_control *restart; @@ -99,6 +108,7 @@ struct qcom_adsp { phys_addr_t mem_reloc; void *mem_region; size_t mem_size; + bool has_iommu; struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX]; size_t proxy_pd_count; @@ -325,6 +335,48 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) return 0; } +static void adsp_unmap_carveout(struct rproc *rproc) +{ + struct qcom_adsp *adsp = rproc->priv; + + if (adsp->has_iommu) + iommu_unmap(rproc->domain, adsp->mem_phys, adsp->mem_size); +} + +static int adsp_map_carveout(struct rproc *rproc) +{ + struct qcom_adsp *adsp = rproc->priv; + struct of_phandle_args args; + long long sid; + unsigned long iova; + int ret; + + if (!adsp->has_iommu) + return 0; + + if (!rproc->domain) + return -EINVAL; + + ret = of_parse_phandle_with_args(adsp->dev->of_node, "iommus", "#iommu-cells", 0, &args); + if (ret < 0) + return ret; + + sid = args.args[0] & SID_MASK_DEFAULT; + + /* Add SID configuration for ADSP Firmware to SMMU */ + iova = adsp->mem_phys | (sid << 32); + + ret = iommu_map(rproc->domain, iova, adsp->mem_phys, + adsp->mem_size, IOMMU_READ | IOMMU_WRITE, + GFP_KERNEL); + if (ret) { + dev_err(adsp->dev, "Unable to map ADSP Physical Memory\n"); + return ret; + } + + return 0; +} + static int adsp_start(struct rproc *rproc) { struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; @@ -335,9 +387,15 @@ static int adsp_start(struct rproc *rproc) if (ret) return ret; + ret = adsp_map_carveout(rproc); + if (ret) { + dev_err(adsp->dev, "ADSP smmu mapping failed\n"); + goto disable_irqs; + } + ret = clk_prepare_enable(adsp->xo); if (ret) - goto disable_irqs; + goto adsp_smmu_unmap; ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); @@ -362,11 +420,14 @@ static int adsp_start(struct rproc *rproc) /* Program boot address */ writel(adsp->mem_phys >> 4, adsp->qdsp6ss_base + RST_EVB_REG); + if (adsp->lpass_efuse) + writel(LPASS_EFUSE_Q6SS_EVB_SEL, adsp->lpass_efuse); + /* De-assert QDSP6 stop core. QDSP6 will execute after out of reset */ - writel(0x1, adsp->qdsp6ss_base + CORE_START_REG); + writel(LPASS_BOOT_CORE_START, adsp->qdsp6ss_base + CORE_START_REG); /* Trigger boot FSM to start QDSP6 */ - writel(0x1, adsp->qdsp6ss_base + BOOT_CMD_REG); + writel(LPASS_BOOT_CMD_START, adsp->qdsp6ss_base + BOOT_CMD_REG); /* Wait for core to come out of reset */ ret = readl_poll_timeout(adsp->qdsp6ss_base + BOOT_STATUS_REG, @@ -390,6 +451,8 @@ disable_power_domain: qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); disable_xo_clk: clk_disable_unprepare(adsp->xo); +adsp_smmu_unmap: + adsp_unmap_carveout(rproc); disable_irqs: qcom_q6v5_unprepare(&adsp->q6v5); @@ -418,6 +481,8 @@ static int adsp_stop(struct rproc *rproc) if (ret) dev_err(adsp->dev, "failed to shutdown: %d\n", ret); + adsp_unmap_carveout(rproc); + handover = qcom_q6v5_unprepare(&adsp->q6v5); if (handover) qcom_adsp_pil_handover(&adsp->q6v5); @@ -437,6 +502,27 @@ static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iom return adsp->mem_region + offset; } +static int adsp_parse_firmware(struct rproc *rproc, const struct firmware *fw) +{ + struct qcom_adsp *adsp = rproc->priv; + int ret; + + ret = qcom_register_dump_segments(rproc, fw); + if (ret) { + dev_err(&rproc->dev, "Error in registering dump segments\n"); + return ret; + } + + if (adsp->has_iommu) { + ret = rproc_elf_load_rsc_table(rproc, fw); + if (ret) { + dev_err(&rproc->dev, "Error in loading resource table\n"); + return ret; + } + } + return 0; +} + static unsigned long adsp_panic(struct rproc *rproc) { struct qcom_adsp *adsp = rproc->priv; @@ -448,7 +534,7 @@ static const struct rproc_ops adsp_ops = { .start = adsp_start, .stop = adsp_stop, .da_to_va = adsp_da_to_va, - .parse_fw = qcom_register_dump_segments, + .parse_fw = adsp_parse_firmware, .load = adsp_load, .panic = adsp_panic, }; @@ -507,6 +593,7 @@ static int adsp_init_reset(struct qcom_adsp *adsp) static int adsp_init_mmio(struct qcom_adsp *adsp, struct platform_device *pdev) { + struct resource *efuse_region; struct device_node *syscon; int ret; @@ -516,6 +603,17 @@ static int adsp_init_mmio(struct qcom_adsp *adsp, return PTR_ERR(adsp->qdsp6ss_base); } + efuse_region = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!efuse_region) { + adsp->lpass_efuse = NULL; + dev_dbg(adsp->dev, "failed to get efuse memory region\n"); + } else { + adsp->lpass_efuse = devm_ioremap_resource(&pdev->dev, efuse_region); + if (IS_ERR(adsp->lpass_efuse)) { + dev_err(adsp->dev, "failed to map efuse registers\n"); + return PTR_ERR(adsp->lpass_efuse); + } + } syscon = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0); if (!syscon) { dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); @@ -595,12 +693,15 @@ static int adsp_probe(struct platform_device *pdev) } rproc->auto_boot = desc->auto_boot; + rproc->has_iommu = desc->has_iommu; rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); adsp = (struct qcom_adsp *)rproc->priv; adsp->dev = &pdev->dev; adsp->rproc = rproc; adsp->info_name = desc->sysmon_name; + adsp->has_iommu = desc->has_iommu; + platform_set_drvdata(pdev, adsp); if (desc->is_wpss) @@ -696,6 +797,21 @@ static const struct adsp_pil_data adsp_resource_init = { }, }; +static const struct adsp_pil_data adsp_sc7280_resource_init = { + .crash_reason_smem = 423, + .firmware_name = "adsp.pbn", + .load_state = "adsp", + .ssr_name = "lpass", + .sysmon_name = "adsp", + .ssctl_id = 0x14, + .has_iommu = true, + .auto_boot = true, + .clk_ids = (const char*[]) { + "gcc_cfg_noc_lpass", NULL + }, + .num_clks = 1, +}; + static const struct adsp_pil_data cdsp_resource_init = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", @@ -734,6 +850,7 @@ static const struct adsp_pil_data wpss_resource_init = { static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,qcs404-cdsp-pil", .data = &cdsp_resource_init }, + { .compatible = "qcom,sc7280-adsp-pil", .data = &adsp_sc7280_resource_init }, { .compatible = "qcom,sc7280-wpss-pil", .data = &wpss_resource_init }, { .compatible = "qcom,sdm845-adsp-pil", .data = &adsp_resource_init }, { }, |