From 31c1931eb90a161dc63105299b14f3f27a7e25af Mon Sep 17 00:00:00 2001 From: Cho KyongHo Date: Thu, 4 May 2017 18:37:49 +0900 Subject: [PATCH] [COMMON] g2d: Add command list completion To push a command list to H/W, G2D driver should add some required information to the command list including: - initialization of H/W for the new job - information about the layers involved with the job. - information about secure layers. The driver should also satisfies the requirment of H/W. It includes alignment restriction of the number of commands in the command list. If the number of commands are not multiple of 8, the driver appends some redundant commands to satisfy the restriction. Change-Id: Ia986f95de7df8e96907cac0cf7197f1fc3560db8 Signed-off-by: Cho KyongHo --- drivers/gpu/exynos/g2d/g2d_command.c | 82 ++++++++++++++++++++++- drivers/gpu/exynos/g2d/g2d_command.h | 2 + drivers/gpu/exynos/g2d/g2d_regs.h | 2 + drivers/gpu/exynos/g2d/g2d_task.c | 5 ++ drivers/gpu/exynos/g2d/g2d_uapi_process.c | 2 + 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/exynos/g2d/g2d_command.c b/drivers/gpu/exynos/g2d/g2d_command.c index 651790dd1c71..1155ea2b59a6 100644 --- a/drivers/gpu/exynos/g2d/g2d_command.c +++ b/drivers/gpu/exynos/g2d/g2d_command.c @@ -21,6 +21,67 @@ #include "g2d_task.h" #include "g2d_uapi.h" #include "g2d_command.h" +#include "g2d_regs.h" + +/* + * Number of registers of coefficients of conversion functions + * - 4 sets of color space conversion for sources + * - 1 set of color space conversion for destination + * - 2 sets of HDR coefficients + * - 2 matrices of EOTF + * - 2 matrices of Gamut mapping + * - 2 matrices Tone mappings + */ +#define MAX_EXTRA_REGS (9 * 5 + (65 + 9 + 33) * 2) + +enum { + TASK_REG_SOFT_RESET, + TASK_REG_LAYER_SECURE, + TASK_REG_LAYER_UPDATE, + + TASK_REG_COUNT +}; + +/* + * G2D_SECURE_LAYER_REG and G2D_LAYER_UPDATE_REG are updated in + * g2d_prepare_source() and g2d_prepare_target(). + */ +static struct g2d_reg g2d_setup_commands[TASK_REG_COUNT] = { + {G2D_SOFT_RESET_REG, 0x00000004}, /* CoreSFRClear */ + {G2D_SECURE_LAYER_REG, 0x00000000}, + {G2D_LAYER_UPDATE_REG, 0x00000000}, +}; + +void g2d_init_commands(struct g2d_task *task) +{ + memcpy(page_address(task->cmd_page), + &g2d_setup_commands, sizeof(g2d_setup_commands)); + task->cmd_count = ARRAY_SIZE(g2d_setup_commands); +} + +void g2d_complete_commands(struct g2d_task *task) +{ + struct g2d_reg *regs = page_address(task->cmd_page); + unsigned int n = 8 - ((task->cmd_count + 1) % 8); + + + /* 832 is the total number of the G2D registers */ + BUG_ON(task->cmd_count > 830); + + /* + * Number of commands should be multiple of 8. + * If it is not, then pad dummy commands with no side effect. + */ + while (n-- > 0) { + regs[task->cmd_count].offset = G2D_LAYER_UPDATE_REG; + regs[task->cmd_count].value = regs[TASK_REG_LAYER_UPDATE].value; + task->cmd_count++; + } + + regs[task->cmd_count].offset = G2D_BITBLT_START_REG; + regs[task->cmd_count].value = 1; + task->cmd_count++; +} #define NV12N_Y_SIZE(w, h) (ALIGN((w), 16) * ALIGN((h), 16) + 256) #define NV12N_CBCR_SIZE(w, h) \ @@ -587,7 +648,13 @@ int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, unsigned int i; int copied; - task->cmd_count = 0; + if (cmds->num_extra_regs > MAX_EXTRA_REGS) { + dev_err(dev, "%s: Too many coefficient reigsters %d\n", + __func__, cmds->num_extra_regs); + return -EINVAL; + } + + cmdaddr += task->cmd_count; copied = g2d_copy_commands(g2d_dev, -1, cmdaddr, cmds->target, target_command_checker, G2DSFR_DST_FIELD_COUNT); @@ -734,10 +801,19 @@ static unsigned int g2d_set_afbc_buffer(struct g2d_task *task, bool g2d_prepare_source(struct g2d_task *task, struct g2d_layer *layer, int index) { + struct g2d_reg *reg = (struct g2d_reg *)page_address(task->cmd_page); u32 colormode = layer->commands[G2DSFR_IMG_COLORMODE].value; unsigned char *offsets = IS_YUV420_82(colormode) ? src_base_reg_offset_yuv82 : src_base_reg_offset; + reg[TASK_REG_LAYER_UPDATE].value |= 1 << index; + + if ((layer->flags & G2D_LAYERFLAG_COLORFILL) != 0) + return true; + + if ((layer->flags & G2D_LAYERFLAG_SECURE) != 0) + reg[TASK_REG_LAYER_SECURE].value |= 1 << index; + task->cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) ? g2d_set_afbc_buffer(task, layer, LAYER_OFFSET(index)) : g2d_set_image_buffer(task, layer, colormode, @@ -751,8 +827,12 @@ bool g2d_prepare_source(struct g2d_task *task, bool g2d_prepare_target(struct g2d_task *task) { + struct g2d_reg *reg = (struct g2d_reg *)page_address(task->cmd_page); u32 colormode = task->target.commands[G2DSFR_IMG_COLORMODE].value; + if ((task->target.flags & G2D_LAYERFLAG_SECURE) != 0) + reg[TASK_REG_LAYER_SECURE].value |= 1 << 24; + task->cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) ? g2d_set_afbc_buffer(task, &task->target, TARGET_OFFSET) diff --git a/drivers/gpu/exynos/g2d/g2d_command.h b/drivers/gpu/exynos/g2d/g2d_command.h index 3f2f9b86cfae..5de201de83ba 100644 --- a/drivers/gpu/exynos/g2d/g2d_command.h +++ b/drivers/gpu/exynos/g2d/g2d_command.h @@ -30,6 +30,8 @@ struct g2d_fmt { u8 num_planes; }; +void g2d_init_commands(struct g2d_task *task); +void g2d_complete_commands(struct g2d_task *task); const struct g2d_fmt *g2d_find_format(u32 fmtval); int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, struct g2d_task_data *data, unsigned int num_sources); diff --git a/drivers/gpu/exynos/g2d/g2d_regs.h b/drivers/gpu/exynos/g2d/g2d_regs.h index 9f9ff6a48407..7355806e009e 100644 --- a/drivers/gpu/exynos/g2d/g2d_regs.h +++ b/drivers/gpu/exynos/g2d/g2d_regs.h @@ -20,6 +20,8 @@ #define G2D_FIFO_STAT_REG 0x010 #define G2D_VERSION_INFO_REG 0x014 #define G2D_AXI_MODE_REG 0x01c +#define G2D_SECURE_MODE_REG 0x030 +#define G2D_SECURE_LAYER_REG 0x034 #define G2D_COMP_DEBUG_ADDR_REG 0x0f0 #define G2D_COMP_DEBUG_DATA_REG 0x0f4 diff --git a/drivers/gpu/exynos/g2d/g2d_task.c b/drivers/gpu/exynos/g2d/g2d_task.c index cd1fd7a2cc95..fffb7cf13cf1 100644 --- a/drivers/gpu/exynos/g2d/g2d_task.c +++ b/drivers/gpu/exynos/g2d/g2d_task.c @@ -21,6 +21,7 @@ #include "g2d.h" #include "g2d_task.h" #include "g2d_uapi_process.h" +#include "g2d_command.h" struct g2d_task *g2d_get_active_task_from_id(struct g2d_device *g2d_dev, unsigned int id) @@ -170,6 +171,8 @@ static void g2d_schedule_task(struct g2d_task *task) unsigned long flags; int ret; + g2d_complete_commands(task); + /* * Unconditional invocation of pm_runtime_get_sync() has no side effect * in g2d_schedule(). It just increases the usage count of RPM if this @@ -259,6 +262,8 @@ struct g2d_task *g2d_get_free_task(struct g2d_device *g2d_dev) init_task_state(task); + g2d_init_commands(task); + spin_unlock_irqrestore(&g2d_dev->lock_task, flags); return task; diff --git a/drivers/gpu/exynos/g2d/g2d_uapi_process.c b/drivers/gpu/exynos/g2d/g2d_uapi_process.c index 029f32235c98..03c10f0ccb2f 100644 --- a/drivers/gpu/exynos/g2d/g2d_uapi_process.c +++ b/drivers/gpu/exynos/g2d/g2d_uapi_process.c @@ -534,6 +534,8 @@ static int g2d_get_source(struct g2d_device *g2d_dev, struct g2d_task *task, if (layer->flags & G2D_LAYERFLAG_COLORFILL) { layer->num_buffers = 0; layer->flags &= ~G2D_LAYERFLAG_ACQUIRE_FENCE; + /* g2d_prepare_source() always successes for colofill */ + g2d_prepare_source(task, layer, index); return 0; } -- 2.20.1