In IPQ5332 and IPQ5424 SoCs, Q6 requires separate device-tree.

Signed-off-by: Gokul Sriram Palanisamy <[email protected]>
---
 drivers/remoteproc/qcom_q6v5_wcss_sec.c | 147 ++++++++++++++++++++++--
 1 file changed, 137 insertions(+), 10 deletions(-)

diff --git a/drivers/remoteproc/qcom_q6v5_wcss_sec.c 
b/drivers/remoteproc/qcom_q6v5_wcss_sec.c
index 30422c6c982d..e4cc7caebd7c 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss_sec.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss_sec.c
@@ -10,9 +10,12 @@
 #include <linux/io.h>
 #include <linux/mailbox_client.h>
 #include <linux/mailbox/tmelcom-qmp.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/soc/qcom/mdt_loader.h>
+#include <linux/soc/qcom/smem.h>
 
 #include "qcom_common.h"
 #include "qcom_q6v5.h"
@@ -34,6 +37,18 @@ struct wcss_sec {
        phys_addr_t mem_reloc;
        void *mem_region;
        size_t mem_size;
+
+       const char *dtb_firmware_name;
+       const struct firmware *dtb_firmware;
+       phys_addr_t dtb_mem_phys;
+       phys_addr_t dtb_mem_reloc;
+       void *dtb_mem_region;
+       size_t dtb_mem_size;
+       struct regmap *tcsr_map;
+       u32 dtb_low_offset;
+       u32 dtb_high_offset;
+       u32 machid_offset;
+
        const struct wcss_data *desc;
 
        struct mbox_client mbox_client;
@@ -46,6 +61,7 @@ struct wcss_data {
        u32 pasid;
        const char *ss_name;
        bool auto_boot;
+       const char *dtb_firmware_name;
        bool tmelcom;
 };
 
@@ -137,8 +153,45 @@ static int wcss_sec_load(struct rproc *rproc, const struct 
firmware *fw)
 {
        struct wcss_sec *wcss = rproc->priv;
        struct device *dev = wcss->dev;
+       u32 machid;
        int ret;
 
+       if (wcss->dtb_firmware_name) {
+               ret = request_firmware(&wcss->dtb_firmware, 
wcss->dtb_firmware_name, wcss->dev);
+               if (ret) {
+                       dev_err(wcss->dev, "request_firmware failed for %s: 
%d\n",
+                               wcss->dtb_firmware_name, ret);
+                       return ret;
+               }
+
+               ret = qcom_mdt_load_no_init(wcss->dev, wcss->dtb_firmware,
+                                           wcss->dtb_firmware_name, 0, 
wcss->dtb_mem_region,
+                                           wcss->dtb_mem_phys, 
wcss->dtb_mem_size,
+                                           &wcss->dtb_mem_reloc);
+               if (ret)
+                       goto release_dtb_firmware;
+
+               ret = qcom_smem_get_machid(&machid);
+               if (ret) {
+                       pr_err("machid get failed, ret = %d\n", ret);
+                       goto release_dtb_firmware;
+               }
+
+               ret = regmap_write(wcss->tcsr_map, wcss->dtb_low_offset,
+                                  wcss->dtb_mem_phys & 0xFFFFFFFF);
+               if (ret)
+                       goto release_dtb_firmware;
+
+               ret = regmap_write(wcss->tcsr_map, wcss->dtb_high_offset,
+                                  wcss->dtb_mem_phys & (0xFFFFFFFF << 31));
+               if (ret)
+                       goto release_dtb_firmware;
+
+               ret = regmap_write(wcss->tcsr_map, wcss->machid_offset, machid);
+               if (ret)
+                       goto release_dtb_firmware;
+       }
+
        if (!IS_ERR_OR_NULL(wcss->mbox_chan)) {
                wcss->metadata = qcom_mdt_read_metadata(fw, &wcss->metadata_len,
                                                        rproc->firmware, 
wcss->dev);
@@ -146,26 +199,33 @@ static int wcss_sec_load(struct rproc *rproc, const 
struct firmware *fw)
                        ret = PTR_ERR(wcss->metadata);
                        dev_err(wcss->dev, "error %d reading firmware %s 
metadata\n",
                                ret, rproc->firmware);
-                       return ret;
+                       goto release_dtb_firmware;
                }
 
                ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, 
wcss->desc->pasid,
                                            wcss->mem_region, wcss->mem_phys, 
wcss->mem_size,
                                            &wcss->mem_reloc);
-               if (ret) {
-                       kfree(wcss->metadata);
-                       return ret;
-               }
+               if (ret)
+                       goto release_metadata;
        } else {
                ret = qcom_mdt_load(dev, fw, rproc->firmware, 
wcss->desc->pasid, wcss->mem_region,
                                    wcss->mem_phys, wcss->mem_size, 
&wcss->mem_reloc);
                if (ret)
-                       return ret;
+                       goto release_dtb_firmware;
        }
 
        qcom_pil_info_store("wcss", wcss->mem_phys, wcss->mem_size);
 
        return 0;
+
+release_metadata:
+       if (!IS_ERR_OR_NULL(wcss->mbox_chan))
+               kfree(wcss->metadata);
+release_dtb_firmware:
+       if (wcss->dtb_firmware_name)
+               release_firmware(wcss->dtb_firmware);
+
+       return ret;
 }
 
 static unsigned long wcss_sec_panic(struct rproc *rproc)
@@ -282,6 +342,33 @@ static int wcss_sec_alloc_memory_region(struct wcss_sec 
*wcss)
                return -ENOMEM;
        }
 
+       if (!wcss->dtb_firmware_name)
+               return 0;
+
+       node = of_parse_phandle(dev->of_node, "memory-region", 1);
+       if (!node) {
+               dev_err(dev, "can't find dtb memory-region\n");
+               return -EINVAL;
+       }
+
+       rmem = of_reserved_mem_lookup(node);
+       of_node_put(node);
+
+       if (!rmem) {
+               dev_err(dev, "unable to resolve dtb memory-region\n");
+               return -EINVAL;
+       }
+
+       wcss->dtb_mem_phys = rmem->base;
+       wcss->dtb_mem_reloc = rmem->base;
+       wcss->dtb_mem_size = rmem->size;
+       wcss->dtb_mem_region = devm_ioremap_wc(dev, wcss->dtb_mem_phys, 
wcss->dtb_mem_size);
+       if (!wcss->dtb_mem_region) {
+               dev_err(dev, "unable to map dtb memory region: %pa+%pa\n",
+                       &rmem->base, &rmem->size);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -291,6 +378,9 @@ static int wcss_sec_probe(struct platform_device *pdev)
        struct wcss_sec *wcss;
        struct clk *sleep_clk;
        const char *fw_name = NULL;
+       const char *dtb_fw_name = NULL;
+       struct of_phandle_args args;
+       int args_cell_cnt = 3;
        const struct wcss_data *desc = of_device_get_match_data(&pdev->dev);
        int ret;
 
@@ -310,6 +400,33 @@ static int wcss_sec_probe(struct platform_device *pdev)
        wcss->dev = &pdev->dev;
        wcss->desc = desc;
 
+       if (desc->dtb_firmware_name) {
+               ret = of_property_read_string_index(pdev->dev.of_node, 
"firmware-name",
+                                                   1, &dtb_fw_name);
+               if (ret < 0)
+                       return ret;
+
+               if (dtb_fw_name)
+                       wcss->dtb_firmware_name = dtb_fw_name;
+
+               ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, 
"qcom,q6-dtb-info",
+                                                      args_cell_cnt, 0, &args);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to parse 
qcom,q6-dtb-info\n");
+                       return ret;
+               }
+
+               wcss->tcsr_map = syscon_node_to_regmap(args.np);
+               of_node_put(args.np);
+               if (IS_ERR(wcss->tcsr_map))
+                       return dev_err_probe(&pdev->dev, 
PTR_ERR(wcss->tcsr_map),
+                                            "unable to get syscon regmap\n");
+
+               wcss->dtb_low_offset = args.args[0];
+               wcss->dtb_high_offset = args.args[1];
+               wcss->machid_offset = args.args[2];
+       }
+
        ret = wcss_sec_alloc_memory_region(wcss);
        if (ret)
                return ret;
@@ -336,18 +453,26 @@ static int wcss_sec_probe(struct platform_device *pdev)
                wcss->mbox_client.knows_txdone = true;
                wcss->mbox_client.tx_block = true;
                wcss->mbox_chan = mbox_request_channel(&wcss->mbox_client, 0);
-               if (IS_ERR(wcss->mbox_chan))
-                       return dev_err_probe(wcss->dev, 
PTR_ERR(wcss->mbox_chan),
-                                            "mbox chan for IPC is missing\n");
+               if (IS_ERR(wcss->mbox_chan)) {
+                       ret = dev_err_probe(&pdev->dev, 
PTR_ERR(wcss->mbox_chan),
+                                           "mbox chan for IPC is missing\n");
+                       goto remove_subdevs;
+               }
        }
 
        ret = devm_rproc_add(&pdev->dev, rproc);
        if (ret)
-               return ret;
+               goto remove_subdevs;
 
        platform_set_drvdata(pdev, rproc);
 
        return 0;
+
+remove_subdevs:
+       qcom_remove_glink_subdev(rproc, &wcss->glink_subdev);
+       qcom_remove_ssr_subdev(rproc, &wcss->ssr_subdev);
+
+       return ret;
 }
 
 static void wcss_sec_remove(struct platform_device *pdev)
@@ -364,11 +489,13 @@ static void wcss_sec_remove(struct platform_device *pdev)
 static const struct wcss_data wcss_sec_ipq5332_res_init = {
        .pasid = MPD_WCSS_PAS_ID,
        .ss_name = "q6wcss",
+       .dtb_firmware_name = "qdsp6sw_dtb.mbn",
 };
 
 static const struct wcss_data wcss_sec_ipq5424_res_init = {
        .pasid = MPD_WCSS_PAS_ID,
        .ss_name = "q6wcss",
+       .dtb_firmware_name = "qdsp6sw_dtb.mbn",
        .tmelcom = true,
 };
 
-- 
2.34.1


Reply via email to