blob: a64026cf41f6d6f96f74aff659fca6e3bd587b9e [file] [log] [blame]
/*
* drivers/amlogic/media/common/ge2d/ge2dgen.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
/* Amlogic Headers */
#include <linux/amlogic/media/ge2d/ge2d.h>
static inline void _set_src1_format(struct ge2d_src1_data_s *src1_data_cfg,
struct ge2d_src1_gen_s *src1_gen_cfg,
struct ge2d_dp_gen_s *dp_gen_cfg,
unsigned int format_src,
unsigned int format_dst)
{
src1_data_cfg->format_all = format_src;
src1_data_cfg->format = (format_src >> 8) & 3;
src1_data_cfg->mode_8b_sel = (format_src >> 6) & 3;
src1_data_cfg->lut_en = (format_src >> 5) & 1;
src1_data_cfg->sep_en = (format_src >> 2) & 1;
src1_data_cfg->endian = (format_src & GE2D_ENDIAN_MASK) >>
GE2D_ENDIAN_SHIFT;
src1_data_cfg->color_map = (format_src & GE2D_COLOR_MAP_MASK) >>
GE2D_COLOR_MAP_SHIFT;
src1_gen_cfg->pic_struct = (format_src >> 3) & 3;
src1_data_cfg->x_yc_ratio = (format_src >> 1) & 1;
src1_data_cfg->y_yc_ratio = (format_src >> 0) & 1;
if (format_src & GE2D_FORMAT_DEEP_COLOR)
src1_data_cfg->deep_color = 1;
else
src1_data_cfg->deep_color = 0;
if ((format_src & GE2D_FORMAT_YUV) &&
((format_dst & GE2D_FORMAT_YUV) == 0)) {
dp_gen_cfg->use_matrix_default =
(format_src & GE2D_FORMAT_FULL_RANGE) ?
MATRIX_FULL_RANGE_YCC_TO_RGB : MATRIX_YCC_TO_RGB;
dp_gen_cfg->conv_matrix_en = 1;
} else if (((format_src & GE2D_FORMAT_YUV) == 0) &&
(format_dst & GE2D_FORMAT_YUV)) {
dp_gen_cfg->use_matrix_default =
(format_dst & GE2D_FORMAT_FULL_RANGE) ?
MATRIX_RGB_TO_FULL_RANGE_YCC : MATRIX_RGB_TO_YCC;
dp_gen_cfg->conv_matrix_en = 1;
} else
dp_gen_cfg->conv_matrix_en = 0;
}
static inline void _set_src2_format(
struct ge2d_src2_dst_data_s *src2_dst_data_cfg,
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg,
unsigned int format)
{
src2_dst_data_cfg->src2_format_all = format;
src2_dst_data_cfg->src2_format = (format >> 8) & 3;
src2_dst_data_cfg->src2_endian = (format & GE2D_ENDIAN_MASK) >>
GE2D_ENDIAN_SHIFT;
src2_dst_data_cfg->src2_color_map = (format & GE2D_COLOR_MAP_MASK) >>
GE2D_COLOR_MAP_SHIFT;
src2_dst_data_cfg->src2_mode_8b_sel = (format >> 6) & 3;
src2_dst_gen_cfg->src2_pic_struct = (format >> 3) & 3;
}
static inline void _set_dst_format(
struct ge2d_src2_dst_data_s *src2_dst_data_cfg,
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg,
struct ge2d_dp_gen_s *dp_gen_cfg,
unsigned int format_src,
unsigned int format_dst)
{
unsigned int y_yc_ratio;
src2_dst_data_cfg->dst_format_all = format_dst;
src2_dst_data_cfg->dst_format = (format_dst >> 8) & 3;
src2_dst_data_cfg->dst_endian = (format_dst & GE2D_ENDIAN_MASK) >>
GE2D_ENDIAN_SHIFT;
src2_dst_data_cfg->dst_color_map = (format_dst & GE2D_COLOR_MAP_MASK) >>
GE2D_COLOR_MAP_SHIFT;
src2_dst_data_cfg->dst_mode_8b_sel = (format_dst >> 6) & 3;
src2_dst_gen_cfg->dst_pic_struct = (format_dst >> 3) & 3;
if ((format_src & GE2D_FORMAT_YUV) &&
((format_dst & GE2D_FORMAT_YUV) == 0)) {
dp_gen_cfg->use_matrix_default =
(format_src & GE2D_FORMAT_FULL_RANGE) ?
MATRIX_FULL_RANGE_YCC_TO_RGB : MATRIX_YCC_TO_RGB;
dp_gen_cfg->conv_matrix_en = 1;
} else if (((format_src & GE2D_FORMAT_YUV) == 0) &&
(format_dst & GE2D_FORMAT_YUV)) {
dp_gen_cfg->use_matrix_default =
(format_dst & GE2D_FORMAT_FULL_RANGE) ?
MATRIX_RGB_TO_FULL_RANGE_YCC : MATRIX_RGB_TO_YCC;
dp_gen_cfg->conv_matrix_en = 1;
} else
dp_gen_cfg->conv_matrix_en = 0;
y_yc_ratio = (format_dst >> 0) & 1;
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
/* for dest is nv21 or nv12 in m6. */
if ((format_dst & GE2D_FORMAT_YUV) &&
((src2_dst_data_cfg->dst_color_map | 1) == 15)) {
src2_dst_data_cfg->dst_format = 0;
src2_dst_data_cfg->dst_mode_8b_sel = 0;
src2_dst_data_cfg->dst2_pixel_byte_width = 1;
if (y_yc_ratio == 0)
src2_dst_data_cfg->dst2_discard_mode = 0xc;
else
src2_dst_data_cfg->dst2_discard_mode = 0xf;
src2_dst_data_cfg->dst2_enable = 1;
src2_dst_data_cfg->dst2_color_map =
src2_dst_data_cfg->dst_color_map - 5;
} else
src2_dst_data_cfg->dst2_enable = 0;
/* #endif */
}
void ge2dgen_src(struct ge2d_context_s *wq,
unsigned int canvas_addr,
unsigned int format,
unsigned int phy_addr,
unsigned int stride)
{
struct ge2d_src1_data_s *src1_data_cfg = ge2d_wq_get_src_data(wq);
struct ge2d_src1_gen_s *src1_gen_cfg = ge2d_wq_get_src_gen(wq);
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
struct ge2d_src2_dst_data_s *src2_dst_data_cfg =
ge2d_wq_get_dst_data(wq);
if ((format != src1_data_cfg->format_all) ||
(canvas_addr != src1_data_cfg->canaddr) ||
(phy_addr != src1_data_cfg->phy_addr) ||
(stride != src1_data_cfg->stride)) {
src1_data_cfg->canaddr = canvas_addr;
_set_src1_format(src1_data_cfg, src1_gen_cfg, dp_gen_cfg,
format, src2_dst_data_cfg->dst_format_all);
src1_data_cfg->phy_addr = phy_addr;
src1_data_cfg->stride = stride;
wq->config.update_flag |= UPDATE_SRC_DATA;
wq->config.update_flag |= UPDATE_SRC_GEN;
wq->config.update_flag |= UPDATE_DP_GEN;
}
}
void ge2dgen_antiflicker(struct ge2d_context_s *wq, unsigned long enable)
{
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
enable = enable ? 1 : 0;
if (dp_gen_cfg->antiflick_en != enable) {
dp_gen_cfg->antiflick_en = enable;
wq->config.update_flag |= UPDATE_DP_GEN;
}
}
void ge2dgen_post_release_src1buf(struct ge2d_context_s *wq,
unsigned int buffer)
{
struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq);
ge2d_cmd_cfg->src1_buffer = buffer;
ge2d_cmd_cfg->release_flag |= RELEASE_SRC1_BUFFER;
}
void ge2dgen_post_release_src1canvas(struct ge2d_context_s *wq)
{
struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq);
ge2d_cmd_cfg->release_flag |= RELEASE_SRC1_CANVAS;
}
void ge2dgen_post_release_src2buf(struct ge2d_context_s *wq,
unsigned int buffer)
{
struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq);
ge2d_cmd_cfg->src2_buffer = buffer;
ge2d_cmd_cfg->release_flag |= RELEASE_SRC2_BUFFER;
}
void ge2dgen_post_release_src2canvas(struct ge2d_context_s *wq)
{
struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq);
ge2d_cmd_cfg->release_flag |= RELEASE_SRC2_CANVAS;
}
void ge2dgen_cb(struct ge2d_context_s *wq,
int (*cmd_cb)(unsigned int), unsigned int param)
{
struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq);
ge2d_cmd_cfg->cmd_cb = cmd_cb;
ge2d_cmd_cfg->cmd_cb_param = param;
ge2d_cmd_cfg->release_flag |= RELEASE_CB;
}
void ge2dgen_src2(struct ge2d_context_s *wq,
unsigned int canvas_addr,
unsigned int format,
unsigned int phy_addr,
unsigned int stride)
{
struct ge2d_src2_dst_data_s *src2_dst_data_cfg =
ge2d_wq_get_dst_data(wq);
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg = ge2d_wq_get_dst_gen(wq);
if ((format != src2_dst_data_cfg->src2_format_all) ||
(canvas_addr != src2_dst_data_cfg->src2_canaddr) ||
(phy_addr != src2_dst_data_cfg->src2_phyaddr) ||
(stride != src2_dst_data_cfg->src2_stride)) {
src2_dst_data_cfg->src2_canaddr = canvas_addr;
_set_src2_format(src2_dst_data_cfg, src2_dst_gen_cfg, format);
src2_dst_data_cfg->src2_phyaddr = phy_addr;
src2_dst_data_cfg->src2_stride = stride;
wq->config.update_flag |= UPDATE_DST_DATA;
wq->config.update_flag |= UPDATE_DST_GEN;
}
}
void ge2dgen_dst(struct ge2d_context_s *wq,
unsigned int canvas_addr,
unsigned int format,
unsigned int phy_addr,
unsigned int stride)
{
struct ge2d_src1_data_s *src1_data_cfg = ge2d_wq_get_src_data(wq);
struct ge2d_src2_dst_data_s *src2_dst_data_cfg =
ge2d_wq_get_dst_data(wq);
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg = ge2d_wq_get_dst_gen(wq);
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
if ((format != src2_dst_data_cfg->dst_format_all) ||
(canvas_addr != src2_dst_data_cfg->dst_canaddr) ||
(phy_addr != src2_dst_data_cfg->dst_phyaddr) ||
(stride != src2_dst_data_cfg->dst_stride)) {
src2_dst_data_cfg->dst_canaddr = canvas_addr;
_set_dst_format(src2_dst_data_cfg, src2_dst_gen_cfg, dp_gen_cfg,
src1_data_cfg->format_all, format);
src2_dst_data_cfg->dst_phyaddr = phy_addr;
src2_dst_data_cfg->dst_stride = stride;
wq->config.update_flag |= UPDATE_DST_DATA;
wq->config.update_flag |= UPDATE_DST_GEN;
wq->config.update_flag |= UPDATE_DP_GEN;
}
}
void ge2dgen_src_clip(struct ge2d_context_s *wq,
int x, int y, int w, int h)
{
struct ge2d_src1_gen_s *src1_gen_cfg = ge2d_wq_get_src_gen(wq);
/* adjust w->x_end h->y_end */
w = x + w - 1;
h = y + h - 1;
if (src1_gen_cfg->clipx_start != x ||
src1_gen_cfg->clipx_end != w ||
src1_gen_cfg->clipy_start != y ||
src1_gen_cfg->clipy_end != h) {
src1_gen_cfg->clipx_start = x;
src1_gen_cfg->clipx_end = w;
src1_gen_cfg->clipy_start = y;
src1_gen_cfg->clipy_end = h;
wq->config.update_flag |= UPDATE_SRC_GEN;
}
}
void ge2dgen_src2_clip(struct ge2d_context_s *wq,
int x, int y, int w, int h)
{
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg = ge2d_wq_get_dst_gen(wq);
/* adjust w->x_end h->y_end */
w = x + w - 1;
h = y + h - 1;
if (src2_dst_gen_cfg->src2_clipx_start != x ||
src2_dst_gen_cfg->src2_clipx_end != w ||
src2_dst_gen_cfg->src2_clipy_start != y ||
src2_dst_gen_cfg->src2_clipy_end != h) {
src2_dst_gen_cfg->src2_clipx_start = x;
src2_dst_gen_cfg->src2_clipx_end = w;
src2_dst_gen_cfg->src2_clipy_start = y;
src2_dst_gen_cfg->src2_clipy_end = h;
wq->config.update_flag |= UPDATE_DST_GEN;
}
}
void ge2dgen_src_key(struct ge2d_context_s *wq,
int en, int key, int keymask, int keymode)
{
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
if (dp_gen_cfg->src1_key_en != en ||
dp_gen_cfg->src1_key != key ||
dp_gen_cfg->src1_key_mask != keymask ||
dp_gen_cfg->src1_key_mode != keymode) {
dp_gen_cfg->src1_key_en = en & 0x1;
dp_gen_cfg->src1_key = key;
dp_gen_cfg->src1_key_mask = keymask;
dp_gen_cfg->src1_key_mode = keymode & 0x1;
dp_gen_cfg->src1_vsc_bank_length = 4;
dp_gen_cfg->src1_hsc_bank_length = 4;
wq->config.update_flag |= UPDATE_DP_GEN;
}
}
EXPORT_SYMBOL(ge2dgen_src_key);
void ge2dgent_src_gbalpha(struct ge2d_context_s *wq,
unsigned char alpha1, unsigned char alpha2)
{
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
#ifdef CONFIG_GE2D_SRC2
if ((dp_gen_cfg->src1_gb_alpha != alpha1)
|| (dp_gen_cfg->src2_gb_alpha != alpha2)) {
dp_gen_cfg->src1_gb_alpha = alpha1;
dp_gen_cfg->src2_gb_alpha = alpha2;
wq->config.update_flag |= UPDATE_DP_GEN;
}
#else
if (dp_gen_cfg->src1_gb_alpha != alpha1) {
dp_gen_cfg->src1_gb_alpha = alpha1;
wq->config.update_flag |= UPDATE_DP_GEN;
}
#endif
}
void ge2dgen_src_color(struct ge2d_context_s *wq,
unsigned int color)
{
struct ge2d_src1_data_s *src1_data_cfg = ge2d_wq_get_src_data(wq);
if (src1_data_cfg->def_color != color) {
src1_data_cfg->def_color = color;
wq->config.update_flag |= UPDATE_SRC_DATA;
}
}
void ge2dgen_rendering_dir(struct ge2d_context_s *wq,
int src_x_dir, int src_y_dir,
int dst_x_dir, int dst_y_dir,
int dst_xy_swap)
{
struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq);
ge2d_cmd_cfg->src1_x_rev = src_x_dir;
ge2d_cmd_cfg->src1_y_rev = src_y_dir;
ge2d_cmd_cfg->dst_x_rev = dst_x_dir;
ge2d_cmd_cfg->dst_y_rev = dst_y_dir;
ge2d_cmd_cfg->dst_xy_swap = dst_xy_swap;
}
void ge2dgen_dst_clip(struct ge2d_context_s *wq,
int x, int y, int w, int h, int mode)
{
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg = ge2d_wq_get_dst_gen(wq);
/* adjust w->x_end h->y_end */
w = x + w - 1;
h = y + h - 1;
if (src2_dst_gen_cfg->dst_clipx_start != x ||
src2_dst_gen_cfg->dst_clipx_end != w ||
src2_dst_gen_cfg->dst_clipy_start != y ||
src2_dst_gen_cfg->dst_clipy_end != h ||
src2_dst_gen_cfg->dst_clip_mode != mode) {
src2_dst_gen_cfg->dst_clipx_start = x;
src2_dst_gen_cfg->dst_clipx_end = w;
src2_dst_gen_cfg->dst_clipy_start = y;
src2_dst_gen_cfg->dst_clipy_end = h;
src2_dst_gen_cfg->dst_clip_mode = mode;
wq->config.update_flag |= UPDATE_DST_GEN;
}
}
void ge2dgent_src2_clip(struct ge2d_context_s *wq,
int x, int y, int w, int h)
{
struct ge2d_src2_dst_gen_s *src2_dst_gen_cfg = ge2d_wq_get_dst_gen(wq);
/* adjust w->x_end h->y_end */
w = x + w - 1;
h = y + h - 1;
if (src2_dst_gen_cfg->src2_clipx_start != x ||
src2_dst_gen_cfg->src2_clipx_end != w ||
src2_dst_gen_cfg->src2_clipy_start != y ||
src2_dst_gen_cfg->src2_clipy_end != h) {
src2_dst_gen_cfg->src2_clipx_start = x;
src2_dst_gen_cfg->src2_clipx_end = w;
src2_dst_gen_cfg->src2_clipy_start = y;
src2_dst_gen_cfg->src2_clipy_end = h;
wq->config.update_flag |= UPDATE_DST_GEN;
}
}
void ge2dgen_const_color(struct ge2d_context_s *wq,
unsigned int color)
{
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
if (dp_gen_cfg->alu_const_color != color) {
dp_gen_cfg->alu_const_color = color;
wq->config.update_flag |= UPDATE_DP_GEN;
}
}