From 91583b59aead65b87bba099a703a46bc81fdb507 Mon Sep 17 00:00:00 2001 From: Cho KyongHo Date: Mon, 5 Mar 2018 17:00:47 +0900 Subject: [PATCH] g2d: add support for Secure DRM of Exynos9820 Protected contents of Secure DRM are processed by G2D if post image prosessing is needed. G2D in Exynos9810 needs help of the secure world due to the lack of prevention of protected contents leak to non-secure world. G2D in Exynos9820 does not need the help of the secure world because it is guaranteed that G2D does not leak the protected contents. Change-Id: I11028c774fe8b59cd21f7c6f391ae1949fd78767 Signed-off-by: Cho KyongHo --- drivers/gpu/exynos/g2d/g2d.h | 6 +++++ drivers/gpu/exynos/g2d/g2d_command.c | 3 ++- drivers/gpu/exynos/g2d/g2d_drv.c | 33 ++++++++++++++++++++++------ drivers/gpu/exynos/g2d/g2d_regs.c | 31 ++++++++++++++++++++------ drivers/gpu/exynos/g2d/g2d_regs.h | 3 +++ drivers/gpu/exynos/g2d/g2d_task.c | 15 +++++++------ 6 files changed, 69 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/exynos/g2d/g2d.h b/drivers/gpu/exynos/g2d/g2d.h index afb69d2820ae..c7546cdd0293 100644 --- a/drivers/gpu/exynos/g2d/g2d.h +++ b/drivers/gpu/exynos/g2d/g2d.h @@ -72,8 +72,14 @@ struct g2d_dvfs_table { u32 freq; }; +/* + * Proved that G2D does not leak protected conents that it is processing. + */ +#define G2D_DEVICE_CAPS_SELF_PROTECTION 1 + struct g2d_device { unsigned long state; + unsigned long caps; struct miscdevice misc[2]; struct device *dev; diff --git a/drivers/gpu/exynos/g2d/g2d_command.c b/drivers/gpu/exynos/g2d/g2d_command.c index e4e816987aa3..d22b2cb4f949 100644 --- a/drivers/gpu/exynos/g2d/g2d_command.c +++ b/drivers/gpu/exynos/g2d/g2d_command.c @@ -130,10 +130,11 @@ static void g2d_set_hwfc_commands(struct g2d_task *task) static void g2d_set_start_commands(struct g2d_task *task) { + bool self_prot = task->g2d_dev->caps & G2D_DEVICE_CAPS_SELF_PROTECTION; struct g2d_reg *regs = page_address(task->cmd_page); unsigned int n; - if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) + if (!self_prot && IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) return; /* diff --git a/drivers/gpu/exynos/g2d/g2d_drv.c b/drivers/gpu/exynos/g2d/g2d_drv.c index d21a6ea7f781..fdf577358c13 100644 --- a/drivers/gpu/exynos/g2d/g2d_drv.c +++ b/drivers/gpu/exynos/g2d/g2d_drv.c @@ -750,8 +750,27 @@ static int g2d_parse_dt(struct g2d_device *g2d_dev) return 0; } +struct g2d_device_data { + unsigned long caps; +}; + +const struct g2d_device_data g2d_9820_data __initconst = { + .caps = G2D_DEVICE_CAPS_SELF_PROTECTION, +}; + +static const struct of_device_id of_g2d_match[] __refconst = { + { + .compatible = "samsung,exynos9810-g2d", + }, { + .compatible = "samsung,exynos9820-g2d", + .data = &g2d_9820_data, + }, + {}, +}; + static int g2d_probe(struct platform_device *pdev) { + const struct of_device_id *of_id; struct g2d_device *g2d_dev; struct resource *res; __u32 version; @@ -797,6 +816,13 @@ static int g2d_probe(struct platform_device *pdev) if (ret < 0) return ret; + of_id = of_match_node(of_g2d_match, pdev->dev.of_node); + if (of_id->data) { + const struct g2d_device_data *devdata = of_id->data; + + g2d_dev->caps = devdata->caps; + } + ret = iovmm_activate(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to activate iommu\n"); @@ -933,13 +959,6 @@ static const struct dev_pm_ops g2d_pm_ops = { SET_RUNTIME_PM_OPS(NULL, g2d_runtime_resume, g2d_runtime_suspend) }; -static const struct of_device_id of_g2d_match[] = { - { - .compatible = "samsung,exynos9810-g2d", - }, - {}, -}; - static struct platform_driver g2d_driver = { .probe = g2d_probe, .remove = g2d_remove, diff --git a/drivers/gpu/exynos/g2d/g2d_regs.c b/drivers/gpu/exynos/g2d/g2d_regs.c index 376f374ae4ce..7e3540c749d4 100644 --- a/drivers/gpu/exynos/g2d/g2d_regs.c +++ b/drivers/gpu/exynos/g2d/g2d_regs.c @@ -67,18 +67,35 @@ static void g2d_hw_push_task_by_smc(struct g2d_device *g2d_dev, void g2d_hw_push_task(struct g2d_device *g2d_dev, struct g2d_task *task) { - u32 state; + bool self_prot = g2d_dev->caps & G2D_DEVICE_CAPS_SELF_PROTECTION; + u32 state = g2d_hw_get_job_state(g2d_dev, task->job_id); - if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) { - g2d_hw_push_task_by_smc(g2d_dev, task); - return; - } - - state = g2d_hw_get_job_state(g2d_dev, task->job_id); if (state != G2D_JOB_STATE_DONE) dev_err(g2d_dev->dev, "%s: Unexpected state %#x of JOB %d\n", __func__, state, task->job_id); + if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) { + unsigned int i; + + if (!self_prot) { + g2d_hw_push_task_by_smc(g2d_dev, task); + return; + } + + state = 0; + + for (i = 0; i < task->num_source; i++) + if (task->source[i].flags & G2D_LAYERFLAG_SECURE) + state |= 1 << i; + + if ((task->target.flags & G2D_LAYERFLAG_SECURE) || state) + state |= 1 << 24; + + writel_relaxed(state, + g2d_dev->reg + + G2D_JOBn_LAYER_SECURE_REG(task->job_id)); + } + writel_relaxed(G2D_JOB_HEADER_DATA(task->priority, task->job_id), g2d_dev->reg + G2D_JOB_HEADER_REG); diff --git a/drivers/gpu/exynos/g2d/g2d_regs.h b/drivers/gpu/exynos/g2d/g2d_regs.h index 4bae0619adf0..432e2075356b 100644 --- a/drivers/gpu/exynos/g2d/g2d_regs.h +++ b/drivers/gpu/exynos/g2d/g2d_regs.h @@ -47,6 +47,9 @@ #define G2D_BITBLT_COMMAND_REG 0x104 #define G2D_LAYER_UPDATE_REG 0x108 +/* G2D Secure mode registers */ +#define G2D_JOBn_LAYER_SECURE_REG(n) (0x9004 + (n) * 8) + /* HWFC related Registers */ #define G2D_HWFC_CAPTURE_IDX_REG 0x8000 #define G2D_HWFC_ENCODING_IDX_REG 0x8004 diff --git a/drivers/gpu/exynos/g2d/g2d_task.c b/drivers/gpu/exynos/g2d/g2d_task.c index b8d217834072..53162351ddd5 100644 --- a/drivers/gpu/exynos/g2d/g2d_task.c +++ b/drivers/gpu/exynos/g2d/g2d_task.c @@ -26,23 +26,24 @@ #include "g2d_debug.h" #include "g2d_secure.h" -static void g2d_secure_enable(void) +static void g2d_secure_enable(bool self_prot) { - if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) + if (!self_prot && IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) exynos_smc(SMC_PROTECTION_SET, 0, G2D_ALWAYS_S, 1); } -static void g2d_secure_disable(void) +static void g2d_secure_disable(bool self_prot) { - if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) + if (!self_prot && IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) exynos_smc(SMC_PROTECTION_SET, 0, G2D_ALWAYS_S, 0); } static int g2d_map_cmd_data(struct g2d_task *task) { + bool self_prot = task->g2d_dev->caps & G2D_DEVICE_CAPS_SELF_PROTECTION; struct scatterlist sgl; - if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) + if (!self_prot && IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) return 0; /* mapping the command data */ @@ -117,7 +118,7 @@ static void g2d_finish_task(struct g2d_device *g2d_dev, g2d_stamp_task(task, G2D_STAMP_STATE_DONE, (int)ktime_us_delta(task->ktime_end, task->ktime_begin)); - g2d_secure_disable(); + g2d_secure_disable(g2d_dev->caps & G2D_DEVICE_CAPS_SELF_PROTECTION); clk_disable(g2d_dev->clock); @@ -165,7 +166,7 @@ void g2d_flush_all_tasks(struct g2d_device *g2d_dev) static void g2d_execute_task(struct g2d_device *g2d_dev, struct g2d_task *task) { - g2d_secure_enable(); + g2d_secure_enable(g2d_dev->caps & G2D_DEVICE_CAPS_SELF_PROTECTION); list_move_tail(&task->node, &g2d_dev->tasks_active); change_task_state_active(task); -- 2.20.1