Commit 29814986 authored by Neil Armstrong's avatar Neil Armstrong Committed by Bjorn Andersson

remoteproc: qcom_q6v5_pas: add support for dtb co-firmware loading

Starting from the SM8550 SoC, starting the aDSP, cDSP and MPSS will
require loading a separate "Devicetree" firmware.

In order to satisfy the load & authentication order required by the SM8550
SoC, the following is implemented:
- "Devicetree" firmware request & load in dedicated memory
- Q6V5 prepare
- Power Domain & Clocks enable
- "Devicetree" firmware authentication
- Main firmware load in dedicated memory
- Main firmware authentication
- Q6V5 startup
- "Devicetree" firmware metadata release
- Main metadata release

When booting older platforms, the "Devicetree" steps would be
bypassed and the load & authentication order would still be valid.
Signed-off-by: default avatarNeil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20221114-narmstrong-sm8550-upstream-remoteproc-v4-3-54154c08c0b7@linaro.org
parent 084258d6
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
struct adsp_data { struct adsp_data {
int crash_reason_smem; int crash_reason_smem;
const char *firmware_name; const char *firmware_name;
const char *dtb_firmware_name;
int pas_id; int pas_id;
int dtb_pas_id;
unsigned int minidump_id; unsigned int minidump_id;
bool auto_boot; bool auto_boot;
bool decrypt_shutdown; bool decrypt_shutdown;
...@@ -64,19 +66,28 @@ struct qcom_adsp { ...@@ -64,19 +66,28 @@ struct qcom_adsp {
int proxy_pd_count; int proxy_pd_count;
const char *dtb_firmware_name;
int pas_id; int pas_id;
int dtb_pas_id;
unsigned int minidump_id; unsigned int minidump_id;
int crash_reason_smem; int crash_reason_smem;
bool decrypt_shutdown; bool decrypt_shutdown;
const char *info_name; const char *info_name;
const struct firmware *firmware;
const struct firmware *dtb_firmware;
struct completion start_done; struct completion start_done;
struct completion stop_done; struct completion stop_done;
phys_addr_t mem_phys; phys_addr_t mem_phys;
phys_addr_t dtb_mem_phys;
phys_addr_t mem_reloc; phys_addr_t mem_reloc;
phys_addr_t dtb_mem_reloc;
void *mem_region; void *mem_region;
void *dtb_mem_region;
size_t mem_size; size_t mem_size;
size_t dtb_mem_size;
struct qcom_rproc_glink glink_subdev; struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev; struct qcom_rproc_subdev smd_subdev;
...@@ -84,6 +95,7 @@ struct qcom_adsp { ...@@ -84,6 +95,7 @@ struct qcom_adsp {
struct qcom_sysmon *sysmon; struct qcom_sysmon *sysmon;
struct qcom_scm_pas_metadata pas_metadata; struct qcom_scm_pas_metadata pas_metadata;
struct qcom_scm_pas_metadata dtb_pas_metadata;
}; };
static void adsp_minidump(struct rproc *rproc) static void adsp_minidump(struct rproc *rproc)
...@@ -158,6 +170,8 @@ static int adsp_unprepare(struct rproc *rproc) ...@@ -158,6 +170,8 @@ static int adsp_unprepare(struct rproc *rproc)
* here. * here.
*/ */
qcom_scm_pas_metadata_release(&adsp->pas_metadata); qcom_scm_pas_metadata_release(&adsp->pas_metadata);
if (adsp->dtb_pas_id)
qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
return 0; return 0;
} }
...@@ -167,20 +181,40 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw) ...@@ -167,20 +181,40 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
int ret; int ret;
ret = qcom_mdt_pas_init(adsp->dev, fw, rproc->firmware, adsp->pas_id, /* Store firmware handle to be used in adsp_start() */
adsp->mem_phys, &adsp->pas_metadata); adsp->firmware = fw;
if (ret)
return ret;
ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, adsp->pas_id, if (adsp->dtb_pas_id) {
adsp->mem_region, adsp->mem_phys, adsp->mem_size, ret = request_firmware(&adsp->dtb_firmware, adsp->dtb_firmware_name, adsp->dev);
&adsp->mem_reloc); if (ret) {
if (ret) dev_err(adsp->dev, "request_firmware failed for %s: %d\n",
return ret; adsp->dtb_firmware_name, ret);
return ret;
}
qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size); ret = qcom_mdt_pas_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name,
adsp->dtb_pas_id, adsp->dtb_mem_phys,
&adsp->dtb_pas_metadata);
if (ret)
goto release_dtb_firmware;
ret = qcom_mdt_load_no_init(adsp->dev, adsp->dtb_firmware, adsp->dtb_firmware_name,
adsp->dtb_pas_id, adsp->dtb_mem_region,
adsp->dtb_mem_phys, adsp->dtb_mem_size,
&adsp->dtb_mem_reloc);
if (ret)
goto release_dtb_metadata;
}
return 0; return 0;
release_dtb_metadata:
qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
release_dtb_firmware:
release_firmware(adsp->dtb_firmware);
return ret;
} }
static int adsp_start(struct rproc *rproc) static int adsp_start(struct rproc *rproc)
...@@ -216,24 +250,55 @@ static int adsp_start(struct rproc *rproc) ...@@ -216,24 +250,55 @@ static int adsp_start(struct rproc *rproc)
goto disable_cx_supply; goto disable_cx_supply;
} }
if (adsp->dtb_pas_id) {
ret = qcom_scm_pas_auth_and_reset(adsp->dtb_pas_id);
if (ret) {
dev_err(adsp->dev,
"failed to authenticate dtb image and release reset\n");
goto disable_px_supply;
}
}
ret = qcom_mdt_pas_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
adsp->mem_phys, &adsp->pas_metadata);
if (ret)
goto disable_px_supply;
ret = qcom_mdt_load_no_init(adsp->dev, adsp->firmware, rproc->firmware, adsp->pas_id,
adsp->mem_region, adsp->mem_phys, adsp->mem_size,
&adsp->mem_reloc);
if (ret)
goto release_pas_metadata;
qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size);
ret = qcom_scm_pas_auth_and_reset(adsp->pas_id); ret = qcom_scm_pas_auth_and_reset(adsp->pas_id);
if (ret) { if (ret) {
dev_err(adsp->dev, dev_err(adsp->dev,
"failed to authenticate image and release reset\n"); "failed to authenticate image and release reset\n");
goto disable_px_supply; goto release_pas_metadata;
} }
ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000)); ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) { if (ret == -ETIMEDOUT) {
dev_err(adsp->dev, "start timed out\n"); dev_err(adsp->dev, "start timed out\n");
qcom_scm_pas_shutdown(adsp->pas_id); qcom_scm_pas_shutdown(adsp->pas_id);
goto disable_px_supply; goto release_pas_metadata;
} }
qcom_scm_pas_metadata_release(&adsp->pas_metadata); qcom_scm_pas_metadata_release(&adsp->pas_metadata);
if (adsp->dtb_pas_id)
qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
/* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
adsp->firmware = NULL;
return 0; return 0;
release_pas_metadata:
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
if (adsp->dtb_pas_id)
qcom_scm_pas_metadata_release(&adsp->dtb_pas_metadata);
disable_px_supply: disable_px_supply:
if (adsp->px_supply) if (adsp->px_supply)
regulator_disable(adsp->px_supply); regulator_disable(adsp->px_supply);
...@@ -249,6 +314,9 @@ static int adsp_start(struct rproc *rproc) ...@@ -249,6 +314,9 @@ static int adsp_start(struct rproc *rproc)
disable_irqs: disable_irqs:
qcom_q6v5_unprepare(&adsp->q6v5); qcom_q6v5_unprepare(&adsp->q6v5);
/* Remove pointer to the loaded firmware, only valid in adsp_load() & adsp_start() */
adsp->firmware = NULL;
return ret; return ret;
} }
...@@ -282,6 +350,12 @@ static int adsp_stop(struct rproc *rproc) ...@@ -282,6 +350,12 @@ static int adsp_stop(struct rproc *rproc)
if (ret) if (ret)
dev_err(adsp->dev, "failed to shutdown: %d\n", ret); dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
if (adsp->dtb_pas_id) {
ret = qcom_scm_pas_shutdown(adsp->dtb_pas_id);
if (ret)
dev_err(adsp->dev, "failed to shutdown dtb: %d\n", ret);
}
handover = qcom_q6v5_unprepare(&adsp->q6v5); handover = qcom_q6v5_unprepare(&adsp->q6v5);
if (handover) if (handover)
qcom_pas_handover(&adsp->q6v5); qcom_pas_handover(&adsp->q6v5);
...@@ -458,6 +532,28 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp) ...@@ -458,6 +532,28 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
return -EBUSY; return -EBUSY;
} }
if (!adsp->dtb_pas_id)
return 0;
node = of_parse_phandle(adsp->dev->of_node, "memory-region", 1);
if (!node) {
dev_err(adsp->dev, "no dtb memory-region specified\n");
return -EINVAL;
}
ret = of_address_to_resource(node, 0, &r);
if (ret)
return ret;
adsp->dtb_mem_phys = adsp->dtb_mem_reloc = r.start;
adsp->dtb_mem_size = resource_size(&r);
adsp->dtb_mem_region = devm_ioremap_wc(adsp->dev, adsp->dtb_mem_phys, adsp->dtb_mem_size);
if (!adsp->dtb_mem_region) {
dev_err(adsp->dev, "unable to map dtb memory region: %pa+%zx\n",
&r.start, adsp->dtb_mem_size);
return -EBUSY;
}
return 0; return 0;
} }
...@@ -466,7 +562,7 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -466,7 +562,7 @@ static int adsp_probe(struct platform_device *pdev)
const struct adsp_data *desc; const struct adsp_data *desc;
struct qcom_adsp *adsp; struct qcom_adsp *adsp;
struct rproc *rproc; struct rproc *rproc;
const char *fw_name; const char *fw_name, *dtb_fw_name = NULL;
const struct rproc_ops *ops = &adsp_ops; const struct rproc_ops *ops = &adsp_ops;
int ret; int ret;
...@@ -483,6 +579,14 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -483,6 +579,14 @@ static int adsp_probe(struct platform_device *pdev)
if (ret < 0 && ret != -EINVAL) if (ret < 0 && ret != -EINVAL)
return ret; return ret;
if (desc->dtb_firmware_name) {
dtb_fw_name = desc->dtb_firmware_name;
ret = of_property_read_string_index(pdev->dev.of_node, "firmware-name", 1,
&dtb_fw_name);
if (ret < 0 && ret != -EINVAL)
return ret;
}
if (desc->minidump_id) if (desc->minidump_id)
ops = &adsp_minidump_ops; ops = &adsp_minidump_ops;
...@@ -503,6 +607,10 @@ static int adsp_probe(struct platform_device *pdev) ...@@ -503,6 +607,10 @@ static int adsp_probe(struct platform_device *pdev)
adsp->pas_id = desc->pas_id; adsp->pas_id = desc->pas_id;
adsp->info_name = desc->sysmon_name; adsp->info_name = desc->sysmon_name;
adsp->decrypt_shutdown = desc->decrypt_shutdown; adsp->decrypt_shutdown = desc->decrypt_shutdown;
if (dtb_fw_name) {
adsp->dtb_firmware_name = dtb_fw_name;
adsp->dtb_pas_id = desc->dtb_pas_id;
}
platform_set_drvdata(pdev, adsp); platform_set_drvdata(pdev, adsp);
ret = device_init_wakeup(adsp->dev, true); ret = device_init_wakeup(adsp->dev, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment