Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions drivers/media/platform/qcom/iris/iris_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ struct iris_core {
/* encoder and decoder have overlapping caps, so two different arrays are required */
struct platform_inst_fw_cap inst_fw_caps_dec[INST_FW_CAP_MAX];
struct platform_inst_fw_cap inst_fw_caps_enc[INST_FW_CAP_MAX];
bool use_tz;
struct video_firmware {
struct platform_device *pdev;
struct iommu_domain *iommu_domain;
size_t mapped_mem_size;
} fw;
};

int iris_core_init(struct iris_core *core);
Expand Down
191 changes: 172 additions & 19 deletions drivers/media/platform/qcom/iris/iris_firmware.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

#include <linux/firmware.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/iommu.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/soc/qcom/mdt_loader.h>

Expand Down Expand Up @@ -93,6 +95,45 @@ static const struct firmware *iris_detect_firmware(struct iris_core *core,
return firmware;
}

#define WRAPPER_TZ_BASE_OFFS 0x000C0000

#define WRAPPER_TZ_XTSS_SW_RESET (WRAPPER_TZ_BASE_OFFS + 0x1000)
#define WRAPPER_XTSS_SW_RESET_BIT BIT(0)

#define WRAPPER_CPA_START_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1020)
#define WRAPPER_CPA_END_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1024)
#define WRAPPER_FW_START_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1028)
#define WRAPPER_FW_END_ADDR (WRAPPER_TZ_BASE_OFFS + 0x102C)
#define WRAPPER_NONPIX_START_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1030)
#define WRAPPER_NONPIX_END_ADDR (WRAPPER_TZ_BASE_OFFS + 0x1034)

#define IRIS_FW_START_ADDR 0x0

static void iris_reset_cpu_no_tz(struct iris_core *core)
{
u32 fw_size = core->fw.mapped_mem_size;

writel(0, core->reg_base + WRAPPER_FW_START_ADDR);
writel(fw_size, core->reg_base + WRAPPER_FW_END_ADDR);
writel(0, core->reg_base + WRAPPER_CPA_START_ADDR);
writel(fw_size, core->reg_base + WRAPPER_CPA_END_ADDR);
writel(fw_size, core->reg_base + WRAPPER_NONPIX_START_ADDR);
writel(fw_size, core->reg_base + WRAPPER_NONPIX_END_ADDR);

/* Bring XTSS out of reset */
writel(0, core->reg_base + WRAPPER_TZ_XTSS_SW_RESET);
}

static int iris_set_hw_state_no_tz(struct iris_core *core, bool resume)
{
if (resume)
iris_reset_cpu_no_tz(core);
else
writel(WRAPPER_XTSS_SW_RESET_BIT, core->reg_base + WRAPPER_TZ_XTSS_SW_RESET);

return 0;
}

static int iris_load_fw_to_memory(struct iris_core *core)
{
const struct firmware *firmware = NULL;
Expand Down Expand Up @@ -130,10 +171,29 @@ static int iris_load_fw_to_memory(struct iris_core *core)
goto err_release_fw;
}

ret = qcom_mdt_load(dev, firmware, fw_name,
IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL);
if (core->use_tz)
ret = qcom_mdt_load(dev, firmware, fw_name,
IRIS_PAS_ID, mem_virt, mem_phys, res_size, NULL);
else
ret = qcom_mdt_load_no_init(dev, firmware, fw_name,
mem_virt, mem_phys, res_size, NULL);

/* Unmap memory on our side before we give firmware access to it */
memunmap(mem_virt);
if (ret)
goto err_release_fw;

if (core->fw.iommu_domain) {
ret = iommu_map(core->fw.iommu_domain, IRIS_FW_START_ADDR, mem_phys, res_size,
IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL);
if (ret) {
dev_err(core->dev, "failed to map firmware in IOMMU: %d\n", ret);
goto err_release_fw;
}

core->fw.mapped_mem_size = res_size;
}

err_release_fw:
release_firmware(firmware);

Expand All @@ -151,34 +211,127 @@ int iris_fw_load(struct iris_core *core)
return ret;
}

ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID);
if (ret) {
dev_err(core->dev, "auth and reset failed: %d\n", ret);
return ret;
}

for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) {
cp_config = &core->iris_platform_data->tz_cp_config_data[i];
ret = qcom_scm_mem_protect_video_var(cp_config->cp_start,
cp_config->cp_size,
cp_config->cp_nonpixel_start,
cp_config->cp_nonpixel_size);
if (ret) {
dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret);
qcom_scm_pas_shutdown(IRIS_PAS_ID);
if (core->use_tz) {
ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID);
if (ret) {
dev_err(core->dev, "auth and reset failed: %d\n", ret);
return ret;
}

for (i = 0; i < core->iris_platform_data->tz_cp_config_data_size; i++) {
cp_config = &core->iris_platform_data->tz_cp_config_data[i];
ret = qcom_scm_mem_protect_video_var(cp_config->cp_start,
cp_config->cp_size,
cp_config->cp_nonpixel_start,
cp_config->cp_nonpixel_size);
if (ret) {
dev_err(core->dev,
"qcom_scm_mem_protect_video_var failed: %d\n", ret);
qcom_scm_pas_shutdown(IRIS_PAS_ID);
return ret;
}
}
} else {
iris_reset_cpu_no_tz(core);
}

return 0;
}

int iris_fw_unload(struct iris_core *core)
{
return qcom_scm_pas_shutdown(IRIS_PAS_ID);
int ret;

if (core->use_tz)
ret = qcom_scm_pas_shutdown(IRIS_PAS_ID);
else
ret = iris_set_hw_state_no_tz(core, false);

if (core->fw.mapped_mem_size) {
size_t unmapped = iommu_unmap(core->fw.iommu_domain, IRIS_FW_START_ADDR,
core->fw.mapped_mem_size);

if (unmapped != core->fw.mapped_mem_size)
dev_err(core->dev, "failed to unmap firmware in IOMMU\n");

core->fw.mapped_mem_size = 0;
}

return ret;
}

int iris_set_hw_state(struct iris_core *core, bool resume)
{
return qcom_scm_set_remote_state(resume, 0);
if (core->use_tz)
return qcom_scm_set_remote_state(resume, 0);
else
return iris_set_hw_state_no_tz(core, resume);
}

int iris_fw_init(struct iris_core *core)
{
struct iommu_domain *iommu_domain;
struct platform_device_info info;
struct platform_device *pdev;
struct device_node *np;
int ret;

np = of_get_child_by_name(core->dev->of_node, "video-firmware");
if (!np) {
core->use_tz = true;
return 0;
}

memset(&info, 0, sizeof(info));
info.parent = core->dev;
info.fwnode = &np->fwnode;
info.name = np->name;
info.dma_mask = DMA_BIT_MASK(32);

pdev = platform_device_register_full(&info);
if (IS_ERR(pdev)) {
of_node_put(np);
return PTR_ERR(pdev);
}

ret = of_dma_configure(&pdev->dev, np, true);
of_node_put(np);
if (ret) {
dev_err(&pdev->dev, "failed to configure dma: %d\n", ret);
goto err_unregister;
}

iommu_domain = iommu_paging_domain_alloc(&pdev->dev);
if (IS_ERR(iommu_domain)) {
dev_err(&pdev->dev, "failed to allocate iommu domain: %pe\n", iommu_domain);
ret = PTR_ERR(iommu_domain);
goto err_unregister;
}

ret = iommu_attach_device(iommu_domain, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "could not attach device to IOMMU: %d\n", ret);
goto err_iommu_free;
}

core->fw.pdev = pdev;
core->fw.iommu_domain = iommu_domain;

return 0;

err_iommu_free:
iommu_domain_free(iommu_domain);
err_unregister:
platform_device_unregister(pdev);
return ret;
}

void iris_fw_deinit(struct iris_core *core)
{
if (!core->fw.iommu_domain)
return;

iommu_detach_device(core->fw.iommu_domain, &core->fw.pdev->dev);
iommu_domain_free(core->fw.iommu_domain);
platform_device_unregister(core->fw.pdev);
}
3 changes: 3 additions & 0 deletions drivers/media/platform/qcom/iris/iris_firmware.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ int iris_fw_load(struct iris_core *core);
int iris_fw_unload(struct iris_core *core);
int iris_set_hw_state(struct iris_core *core, bool resume);

int iris_fw_init(struct iris_core *core);
void iris_fw_deinit(struct iris_core *core);

#endif
7 changes: 7 additions & 0 deletions drivers/media/platform/qcom/iris/iris_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "iris_core.h"
#include "iris_ctrls.h"
#include "iris_firmware.h"
#include "iris_vidc.h"

static int iris_init_icc(struct iris_core *core)
Expand Down Expand Up @@ -207,6 +208,8 @@ static void iris_remove(struct platform_device *pdev)

v4l2_device_unregister(&core->v4l2_dev);

iris_fw_deinit(core);

mutex_destroy(&core->lock);
}

Expand Down Expand Up @@ -271,6 +274,10 @@ static int iris_probe(struct platform_device *pdev)
if (ret)
return ret;

ret = iris_fw_init(core);
if (ret)
return ret;

ret = v4l2_device_register(dev, &core->v4l2_dev);
if (ret)
return ret;
Expand Down