|
@@ -13,6 +13,10 @@
|
|
|
#include <linux/reset.h>
|
|
|
#include <linux/interconnect.h>
|
|
|
#include <soc/qcom/subsystem_restart.h>
|
|
|
+#include <linux/of_address.h>
|
|
|
+#include <linux/firmware.h>
|
|
|
+#include <linux/qcom_scm.h>
|
|
|
+#include <linux/soc/qcom/mdt_loader.h>
|
|
|
|
|
|
#include "venus_hfi.h"
|
|
|
#include "msm_vidc_core.h"
|
|
@@ -27,6 +31,8 @@
|
|
|
|
|
|
#define MIN_PAYLOAD_SIZE 3
|
|
|
|
|
|
+#define MAX_FIRMWARE_NAME_SIZE 128
|
|
|
+
|
|
|
static int __resume(struct msm_vidc_core *core);
|
|
|
static int __suspend(struct msm_vidc_core *core);
|
|
|
|
|
@@ -2246,13 +2252,112 @@ fail_alloc_queue:
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
+static int __load_fw_to_memory(struct platform_device *pdev,
|
|
|
+ const char *fw_name)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+ const struct firmware *firmware = NULL;
|
|
|
+ char firmware_name[MAX_FIRMWARE_NAME_SIZE] = { 0 };
|
|
|
+ struct device_node *node = NULL;
|
|
|
+ struct resource res = { 0 };
|
|
|
+ phys_addr_t phys = 0;
|
|
|
+ size_t res_size = 0;
|
|
|
+ ssize_t fw_size = 0;
|
|
|
+ void *virt = NULL;
|
|
|
+ int pas_id = 0;
|
|
|
+
|
|
|
+ if (!fw_name || !(*fw_name) || !pdev) {
|
|
|
+ d_vpr_e("%s: Invalid inputs\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) {
|
|
|
+ d_vpr_e("%s: Invalid fw name\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ scnprintf(firmware_name, ARRAY_SIZE(firmware_name), "%s.mdt", fw_name);
|
|
|
+
|
|
|
+ rc = of_property_read_u32(pdev->dev.of_node, "pas-id", &pas_id);
|
|
|
+ if (rc) {
|
|
|
+ d_vpr_e("%s: failed to read \"pas-id\". error %d\n",
|
|
|
+ __func__, rc);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
|
|
|
+ if (!node) {
|
|
|
+ d_vpr_e("%s: failed to read \"memory-region\"\n",
|
|
|
+ __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = of_address_to_resource(node, 0, &res);
|
|
|
+ if (rc) {
|
|
|
+ d_vpr_e("%s: failed to read \"memory-region\", error %d\n",
|
|
|
+ __func__, rc);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ phys = res.start;
|
|
|
+ res_size = (size_t)resource_size(&res);
|
|
|
+
|
|
|
+ rc = request_firmware(&firmware, firmware_name, &pdev->dev);
|
|
|
+ if (rc) {
|
|
|
+ d_vpr_e("%s: failed to request fw \"%s\", error %d\n",
|
|
|
+ __func__, rc, firmware_name);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ fw_size = qcom_mdt_get_size(firmware);
|
|
|
+ if (fw_size < 0 || res_size < (size_t)fw_size) {
|
|
|
+ rc = -EINVAL;
|
|
|
+ d_vpr_e("%s: out of bound fw image fw size: %ld, res_size: %lu",
|
|
|
+ __func__, fw_size, res_size);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ virt = memremap(phys, res_size, MEMREMAP_WC);
|
|
|
+ if (!virt) {
|
|
|
+ d_vpr_e("%s: failed to remap fw memory phys %pa[p]\n",
|
|
|
+ __func__, phys);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = qcom_mdt_load(&pdev->dev, firmware, firmware_name,
|
|
|
+ pas_id, virt, phys, res_size, NULL);
|
|
|
+ if (rc) {
|
|
|
+ d_vpr_e("%s: error %d loading fw \"%s\"\n",
|
|
|
+ __func__, rc, firmware_name);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+ rc = qcom_scm_pas_auth_and_reset(pas_id);
|
|
|
+ if (rc) {
|
|
|
+ d_vpr_e("%s: error %d authenticating fw \"%s\"\n",
|
|
|
+ __func__, rc, firmware_name);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ memunmap(virt);
|
|
|
+ release_firmware(firmware);
|
|
|
+ d_vpr_h("%s: firmware \"%s\" loaded successfully\n",
|
|
|
+ __func__, firmware_name);
|
|
|
+
|
|
|
+ return pas_id;
|
|
|
+
|
|
|
+exit:
|
|
|
+ if (virt)
|
|
|
+ memunmap(virt);
|
|
|
+ if (firmware)
|
|
|
+ release_firmware(firmware);
|
|
|
+
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static int __load_fw(struct msm_vidc_core *core)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
|
|
|
rc = __init_resources(core);
|
|
|
if (rc) {
|
|
|
- d_vpr_e("Failed to init resources: %d\n", rc);
|
|
|
+ d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc);
|
|
|
goto fail_init_res;
|
|
|
}
|
|
|
|
|
@@ -2263,11 +2368,12 @@ static int __load_fw(struct msm_vidc_core *core)
|
|
|
}
|
|
|
|
|
|
if (!core->dt->fw_cookie) {
|
|
|
- core->dt->fw_cookie = subsystem_get_with_fwname("venus",
|
|
|
- core->dt->fw_name);
|
|
|
- if (IS_ERR_OR_NULL(core->dt->fw_cookie)) {
|
|
|
- d_vpr_e("%s: firmware download failed\n", __func__);
|
|
|
- core->dt->fw_cookie = NULL;
|
|
|
+ core->dt->fw_cookie = __load_fw_to_memory(core->pdev,
|
|
|
+ core->dt->fw_name);
|
|
|
+ if (core->dt->fw_cookie <= 0) {
|
|
|
+ d_vpr_e("%s: firmware download failed %d\n",
|
|
|
+ __func__, core->dt->fw_cookie);
|
|
|
+ core->dt->fw_cookie = 0;
|
|
|
rc = -ENOMEM;
|
|
|
goto fail_load_fw;
|
|
|
}
|
|
@@ -2284,14 +2390,13 @@ static int __load_fw(struct msm_vidc_core *core)
|
|
|
* (s/w triggered) to fast (HW triggered) unless the h/w vote is
|
|
|
* present.
|
|
|
*/
|
|
|
- if (__enable_hw_power_collapse(core))
|
|
|
- d_vpr_e("%s: hardware power collapse unsuccessful\n", __func__);
|
|
|
+ __enable_hw_power_collapse(core);
|
|
|
|
|
|
return rc;
|
|
|
fail_protect_mem:
|
|
|
if (core->dt->fw_cookie)
|
|
|
- subsystem_put(core->dt->fw_cookie);
|
|
|
- core->dt->fw_cookie = NULL;
|
|
|
+ qcom_scm_pas_shutdown(core->dt->fw_cookie);
|
|
|
+ core->dt->fw_cookie = 0;
|
|
|
fail_load_fw:
|
|
|
call_venus_op(core, power_off, core);
|
|
|
fail_venus_power_on:
|
|
@@ -2309,10 +2414,12 @@ static void __unload_fw(struct msm_vidc_core *core)
|
|
|
if (core->state != MSM_VIDC_CORE_DEINIT)
|
|
|
flush_workqueue(core->pm_workq);
|
|
|
|
|
|
- subsystem_put(core->dt->fw_cookie);
|
|
|
+ qcom_scm_pas_shutdown(core->dt->fw_cookie);
|
|
|
+ core->dt->fw_cookie = 0;
|
|
|
+
|
|
|
__interface_queues_release(core);
|
|
|
call_venus_op(core, power_off, core);
|
|
|
- core->dt->fw_cookie = NULL;
|
|
|
+
|
|
|
__deinit_resources(core);
|
|
|
|
|
|
d_vpr_h("Firmware unloaded successfully\n");
|