drivers/remoteproc/mtk_scp.c

Source file repositories/reference/linux-study-clean/drivers/remoteproc/mtk_scp.c

File Facts

System
Linux kernel
Corpus path
drivers/remoteproc/mtk_scp.c
Extension
.c
Size
44716 bytes
Lines
1647
Domain
Driver Families
Bucket
drivers/remoteproc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (filesz > memsz) {
			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
				filesz, memsz);
			ret = -EINVAL;
			break;
		}

		if (offset + filesz > fw->size) {
			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
				offset + filesz, fw->size);
			ret = -EINVAL;
			break;
		}

		/* grab the kernel address for this device address */
		ptr = (void __iomem *)rproc_da_to_va(rproc, da, memsz, NULL);
		if (!ptr) {
			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
			ret = -EINVAL;
			break;
		}

		/* put the segment where the remote processor expects it */
		scp_memcpy_aligned(ptr, elf_data + phdr->p_offset, filesz);
	}

	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_clk_get(struct mtk_scp *scp)
{
	struct device *dev = scp->dev;
	int ret = 0;

	scp->clk = devm_clk_get(dev, "main");
	if (IS_ERR(scp->clk)) {
		dev_err(dev, "Failed to get clock\n");
		ret = PTR_ERR(scp->clk);
	}

	return ret;
}

static int mt8192_scp_clk_get(struct mtk_scp *scp)
{
	return mt8183_scp_clk_get(scp);
}

static int mt8195_scp_clk_get(struct mtk_scp *scp)
{
	scp->clk = NULL;

	return 0;
}

static int mt8183_scp_before_load(struct mtk_scp *scp)
{
	/* Clear SCP to host interrupt */
	writel(MT8183_SCP_IPC_INT_BIT, scp->cluster->reg_base + MT8183_SCP_TO_HOST);

	/* Reset clocks before loading FW */
	writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_SW_SEL);
	writel(0x0, scp->cluster->reg_base + MT8183_SCP_CLK_DIV_SEL);

Annotation

Implementation Notes