[RESEND PATCH v2] remoteproc/mediatek: read IPI buffer offset from FW
Tzung-Bi Shih
tzungbi at google.com
Fri Nov 27 04:29:41 EST 2020
Reads the IPI buffer offset from the FW binary. The information resides
in addr of .ipi_buffer section.
Moves scp_ipi_init() to scp_load() phase. The IPI buffer can be
initialized only if the offset is clear.
Signed-off-by: Tzung-Bi Shih <tzungbi at google.com>
---
The patch bases on https://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git/log/?h=for-next
The first 2 patches in the series
https://patchwork.kernel.org/project/linux-remoteproc/cover/20201116084413.3312631-1-tzungbi@google.com/
have been merged to remoteproc for-next branch.
Follow up the discussion in
https://patchwork.kernel.org/project/linux-remoteproc/patch/20201116084413.3312631-4-tzungbi@google.com/#23784483
The patch breaks MTK SCP when working with legacy SCP firmware. We're
aware of it and will upgrade the devices' kernel and SCP firmware
carefully. Other than that, AFAICT, no other devices in the wild are
using this driver.
drivers/remoteproc/mtk_scp.c | 73 ++++++++++++++++++++++++------------
1 file changed, 49 insertions(+), 24 deletions(-)
diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
index 7e0f1e1a335b..4467ed646bb1 100644
--- a/drivers/remoteproc/mtk_scp.c
+++ b/drivers/remoteproc/mtk_scp.c
@@ -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,24 @@ 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;
+
+ ret = scp_elf_read_ipi_buf_addr(scp, fw, &offset);
+ if (ret)
+ 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 +279,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 */
@@ -350,11 +384,15 @@ static int scp_load(struct rproc *rproc, const struct firmware *fw)
ret = scp->data->scp_before_load(scp);
if (ret < 0)
- return ret;
+ goto leave;
ret = scp_elf_load_segments(rproc, fw);
- clk_disable_unprepare(scp->clk);
+ if (ret)
+ goto leave;
+ ret = scp_ipi_init(scp, fw);
+leave:
+ clk_disable_unprepare(scp->clk);
return ret;
}
@@ -680,19 +718,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) {
--
2.29.2.454.gaff20da3a2-goog
More information about the Linux-mediatek
mailing list