remoteproc: qcom: q6v5: Decouple driver from MDT loader
Rather than duplicating half of the MDT loader in the validation step move the entire MDT parser into the q6v5 driver. This allows us to make the shared MDT-loader call the SCM PAS operations directly which simplifies the client code and allows for better reuse of the code. Cc: Avaneesh Kumar Dwivedi <akdwived@codeaurora.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
This commit is contained in:
parent
2bb5d90699
commit
e7fd252262
|
@ -92,7 +92,6 @@ config QCOM_Q6V5_PIL
|
||||||
depends on QCOM_SMEM
|
depends on QCOM_SMEM
|
||||||
depends on REMOTEPROC
|
depends on REMOTEPROC
|
||||||
select MFD_SYSCON
|
select MFD_SYSCON
|
||||||
select QCOM_MDT_LOADER
|
|
||||||
select QCOM_SCM
|
select QCOM_SCM
|
||||||
help
|
help
|
||||||
Say y here to support the Qualcomm Peripherial Image Loader for the
|
Say y here to support the Qualcomm Peripherial Image Loader for the
|
||||||
|
|
|
@ -37,8 +37,6 @@
|
||||||
|
|
||||||
#include <linux/qcom_scm.h>
|
#include <linux/qcom_scm.h>
|
||||||
|
|
||||||
#define MPSS_FIRMWARE_NAME "modem.mdt"
|
|
||||||
|
|
||||||
#define MPSS_CRASH_REASON_SMEM 421
|
#define MPSS_CRASH_REASON_SMEM 421
|
||||||
|
|
||||||
/* RMB Status Register Values */
|
/* RMB Status Register Values */
|
||||||
|
@ -277,6 +275,16 @@ static void q6v5_clk_disable(struct device *dev,
|
||||||
clk_disable_unprepare(clks[i]);
|
clk_disable_unprepare(clks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct resource_table *q6v5_find_rsc_table(struct rproc *rproc,
|
||||||
|
const struct firmware *fw,
|
||||||
|
int *tablesz)
|
||||||
|
{
|
||||||
|
static struct resource_table table = { .ver = 1, };
|
||||||
|
|
||||||
|
*tablesz = sizeof(table);
|
||||||
|
return &table;
|
||||||
|
}
|
||||||
|
|
||||||
static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
|
static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
|
||||||
{
|
{
|
||||||
struct q6v5 *qproc = rproc->priv;
|
struct q6v5 *qproc = rproc->priv;
|
||||||
|
@ -287,7 +295,7 @@ static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rproc_fw_ops q6v5_fw_ops = {
|
static const struct rproc_fw_ops q6v5_fw_ops = {
|
||||||
.find_rsc_table = qcom_mdt_find_rsc_table,
|
.find_rsc_table = q6v5_find_rsc_table,
|
||||||
.load = q6v5_load,
|
.load = q6v5_load,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -464,45 +472,109 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
|
||||||
return ret < 0 ? ret : 0;
|
return ret < 0 ? ret : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
|
static bool q6v5_phdr_valid(const struct elf32_phdr *phdr)
|
||||||
|
{
|
||||||
|
if (phdr->p_type != PT_LOAD)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!phdr->p_memsz)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int q6v5_mpss_load(struct q6v5 *qproc)
|
||||||
{
|
{
|
||||||
const struct elf32_phdr *phdrs;
|
const struct elf32_phdr *phdrs;
|
||||||
const struct elf32_phdr *phdr;
|
const struct elf32_phdr *phdr;
|
||||||
|
const struct firmware *seg_fw;
|
||||||
|
const struct firmware *fw;
|
||||||
struct elf32_hdr *ehdr;
|
struct elf32_hdr *ehdr;
|
||||||
|
phys_addr_t mpss_reloc;
|
||||||
phys_addr_t boot_addr;
|
phys_addr_t boot_addr;
|
||||||
phys_addr_t fw_addr;
|
phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
|
||||||
bool relocate;
|
phys_addr_t max_addr = 0;
|
||||||
|
bool relocate = false;
|
||||||
|
char seg_name[10];
|
||||||
|
size_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
void *ptr;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
|
ret = request_firmware(&fw, "modem.mdt", qproc->dev);
|
||||||
if (ret) {
|
if (ret < 0) {
|
||||||
dev_err(qproc->dev, "failed to parse mdt header\n");
|
dev_err(qproc->dev, "unable to load modem.mdt\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relocate)
|
/* Initialize the RMB validator */
|
||||||
boot_addr = qproc->mpss_phys;
|
writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
|
||||||
else
|
|
||||||
boot_addr = fw_addr;
|
ret = q6v5_mpss_init_image(qproc, fw);
|
||||||
|
if (ret)
|
||||||
|
goto release_firmware;
|
||||||
|
|
||||||
ehdr = (struct elf32_hdr *)fw->data;
|
ehdr = (struct elf32_hdr *)fw->data;
|
||||||
phdrs = (struct elf32_phdr *)(ehdr + 1);
|
phdrs = (struct elf32_phdr *)(ehdr + 1);
|
||||||
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
|
|
||||||
|
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||||
phdr = &phdrs[i];
|
phdr = &phdrs[i];
|
||||||
|
|
||||||
if (phdr->p_type != PT_LOAD)
|
if (!q6v5_phdr_valid(phdr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
|
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
|
||||||
|
relocate = true;
|
||||||
|
|
||||||
|
if (phdr->p_paddr < min_addr)
|
||||||
|
min_addr = phdr->p_paddr;
|
||||||
|
|
||||||
|
if (phdr->p_paddr + phdr->p_memsz > max_addr)
|
||||||
|
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpss_reloc = relocate ? min_addr : qproc->mpss_phys;
|
||||||
|
|
||||||
|
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||||
|
phdr = &phdrs[i];
|
||||||
|
|
||||||
|
if (!q6v5_phdr_valid(phdr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!phdr->p_memsz)
|
offset = phdr->p_paddr - mpss_reloc;
|
||||||
continue;
|
if (offset < 0 || offset + phdr->p_memsz > qproc->mpss_size) {
|
||||||
|
dev_err(qproc->dev, "segment outside memory range\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto release_firmware;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = qproc->mpss_region + offset;
|
||||||
|
|
||||||
|
if (phdr->p_filesz) {
|
||||||
|
snprintf(seg_name, sizeof(seg_name), "modem.b%02d", i);
|
||||||
|
ret = request_firmware(&seg_fw, seg_name, qproc->dev);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(qproc->dev, "failed to load %s\n", seg_name);
|
||||||
|
goto release_firmware;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ptr, seg_fw->data, seg_fw->size);
|
||||||
|
|
||||||
|
release_firmware(seg_fw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phdr->p_memsz > phdr->p_filesz) {
|
||||||
|
memset(ptr + phdr->p_filesz, 0,
|
||||||
|
phdr->p_memsz - phdr->p_filesz);
|
||||||
|
}
|
||||||
|
|
||||||
size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
|
size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
|
||||||
if (!size) {
|
if (!size) {
|
||||||
|
boot_addr = relocate ? qproc->mpss_phys : min_addr;
|
||||||
writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
|
writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
|
||||||
writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
|
writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
|
||||||
}
|
}
|
||||||
|
@ -517,44 +589,6 @@ static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
|
||||||
else if (ret < 0)
|
else if (ret < 0)
|
||||||
dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);
|
dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret);
|
||||||
|
|
||||||
return ret < 0 ? ret : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int q6v5_mpss_load(struct q6v5 *qproc)
|
|
||||||
{
|
|
||||||
const struct firmware *fw;
|
|
||||||
phys_addr_t fw_addr;
|
|
||||||
bool relocate;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(qproc->dev, "failed to parse mdt header\n");
|
|
||||||
goto release_firmware;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relocate)
|
|
||||||
qproc->mpss_reloc = fw_addr;
|
|
||||||
|
|
||||||
/* Initialize the RMB validator */
|
|
||||||
writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
|
|
||||||
|
|
||||||
ret = q6v5_mpss_init_image(qproc, fw);
|
|
||||||
if (ret)
|
|
||||||
goto release_firmware;
|
|
||||||
|
|
||||||
ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME);
|
|
||||||
if (ret)
|
|
||||||
goto release_firmware;
|
|
||||||
|
|
||||||
ret = q6v5_mpss_validate(qproc, fw);
|
|
||||||
|
|
||||||
release_firmware:
|
release_firmware:
|
||||||
release_firmware(fw);
|
release_firmware(fw);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue