remoteproc/mediatek: read IPI buffer offset from FW
authorTzung-Bi Shih <tzungbi@google.com>
Wed, 2 Dec 2020 04:46:09 +0000 (12:46 +0800)
committerBjorn Andersson <bjorn.andersson@linaro.org>
Thu, 10 Dec 2020 19:32:10 +0000 (13:32 -0600)
Reads the IPI buffer offset from the FW binary.  The information resides
in addr of .ipi_buffer section.

Moves scp_ipi_init() to rproc_ops::parse_fw() phase.  The IPI buffer can
be initialized only if the offset is clear.

To backward compatible to MT8183 SCP, specify the offset in the board
specific mtk_scp_of_data.  Reads the default offset if the firmware
doesn't have it.

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Tzung-Bi Shih <tzungbi@google.com>
Link: https://lore.kernel.org/r/20201202044609.2501913-1-tzungbi@google.com
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
drivers/remoteproc/mtk_common.h
drivers/remoteproc/mtk_scp.c

index fb022ff..988edb4 100644 (file)
@@ -78,6 +78,8 @@ struct mtk_scp_of_data {
 
        u32 host_to_scp_reg;
        u32 host_to_scp_int_bit;
+
+       size_t ipi_buf_offset;
 };
 
 struct mtk_scp {
index 5e5705f..e0c2356 100644 (file)
@@ -21,7 +21,7 @@
 #include "remoteproc_internal.h"
 
 #define MAX_CODE_SIZE 0x500000
-#define SCP_FW_END 0x7C000
+#define SECTION_NAME_IPI_BUFFER ".ipi_buffer"
 
 /**
  * scp_get() - get a reference to SCP.
@@ -119,16 +119,29 @@ static void scp_ipi_handler(struct mtk_scp *scp)
        wake_up(&scp->ack_wq);
 }
 
-static int scp_ipi_init(struct mtk_scp *scp)
+static int scp_elf_read_ipi_buf_addr(struct mtk_scp *scp,
+                                    const struct firmware *fw,
+                                    size_t *offset);
+
+static int scp_ipi_init(struct mtk_scp *scp, const struct firmware *fw)
 {
-       size_t send_offset = SCP_FW_END - sizeof(struct mtk_share_obj);
-       size_t recv_offset = send_offset - sizeof(struct mtk_share_obj);
+       int ret;
+       size_t offset;
+
+       /* read the ipi buf addr from FW itself first */
+       ret = scp_elf_read_ipi_buf_addr(scp, fw, &offset);
+       if (ret) {
+               /* use default ipi buf addr if the FW doesn't have it */
+               offset = scp->data->ipi_buf_offset;
+               if (!offset)
+                       return ret;
+       }
+       dev_info(scp->dev, "IPI buf addr %#010zx\n", offset);
 
-       /* shared buffer initialization */
-       scp->recv_buf =
-               (struct mtk_share_obj __iomem *)(scp->sram_base + recv_offset);
-       scp->send_buf =
-               (struct mtk_share_obj __iomem *)(scp->sram_base + send_offset);
+       scp->recv_buf = (struct mtk_share_obj __iomem *)
+                       (scp->sram_base + offset);
+       scp->send_buf = (struct mtk_share_obj __iomem *)
+                       (scp->sram_base + offset + sizeof(*scp->recv_buf));
        memset_io(scp->recv_buf, 0, sizeof(*scp->recv_buf));
        memset_io(scp->send_buf, 0, sizeof(*scp->send_buf));
 
@@ -271,6 +284,32 @@ static int scp_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
        return ret;
 }
 
+static int scp_elf_read_ipi_buf_addr(struct mtk_scp *scp,
+                                    const struct firmware *fw,
+                                    size_t *offset)
+{
+       struct elf32_hdr *ehdr;
+       struct elf32_shdr *shdr, *shdr_strtab;
+       int i;
+       const u8 *elf_data = fw->data;
+       const char *strtab;
+
+       ehdr = (struct elf32_hdr *)elf_data;
+       shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+       shdr_strtab = shdr + ehdr->e_shstrndx;
+       strtab = (const char *)(elf_data + shdr_strtab->sh_offset);
+
+       for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+               if (strcmp(strtab + shdr->sh_name,
+                          SECTION_NAME_IPI_BUFFER) == 0) {
+                       *offset = shdr->sh_addr;
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
 static int mt8183_scp_before_load(struct mtk_scp *scp)
 {
        /* Clear SCP to host interrupt */
@@ -359,6 +398,23 @@ leave:
        return ret;
 }
 
+static int scp_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+       struct mtk_scp *scp = rproc->priv;
+       struct device *dev = scp->dev;
+       int ret;
+
+       ret = clk_prepare_enable(scp->clk);
+       if (ret) {
+               dev_err(dev, "failed to enable clocks\n");
+               return ret;
+       }
+
+       ret = scp_ipi_init(scp, fw);
+       clk_disable_unprepare(scp->clk);
+       return ret;
+}
+
 static int scp_start(struct rproc *rproc)
 {
        struct mtk_scp *scp = (struct mtk_scp *)rproc->priv;
@@ -462,6 +518,7 @@ static const struct rproc_ops scp_ops = {
        .stop           = scp_stop,
        .load           = scp_load,
        .da_to_va       = scp_da_to_va,
+       .parse_fw       = scp_parse_fw,
 };
 
 /**
@@ -681,19 +738,6 @@ static int scp_probe(struct platform_device *pdev)
                goto release_dev_mem;
        }
 
-       ret = clk_prepare_enable(scp->clk);
-       if (ret) {
-               dev_err(dev, "failed to enable clocks\n");
-               goto release_dev_mem;
-       }
-
-       ret = scp_ipi_init(scp);
-       clk_disable_unprepare(scp->clk);
-       if (ret) {
-               dev_err(dev, "Failed to init ipi\n");
-               goto release_dev_mem;
-       }
-
        /* register SCP initialization IPI */
        ret = scp_ipi_register(scp, SCP_IPI_INIT, scp_init_ipi_handler, scp);
        if (ret) {
@@ -761,6 +805,7 @@ static const struct mtk_scp_of_data mt8183_of_data = {
        .scp_stop = mt8183_scp_stop,
        .host_to_scp_reg = MT8183_HOST_TO_SCP,
        .host_to_scp_int_bit = MT8183_HOST_IPC_INT_BIT,
+       .ipi_buf_offset = 0x7bdb0,
 };
 
 static const struct mtk_scp_of_data mt8192_of_data = {