| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| /* 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; |
| } |
| |
| 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; |
| |
| 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 */ |
| |
| if (ge2d_meson_dev.dst_repeat) |
| switch (format_dst & GE2D_EXT_MASK) { |
| case GE2D_DST_REPEAT_2: |
| src2_dst_data_cfg->dst_rpt = DST_RPT_2 | |
| DST_RPT_PATTERN_XX; |
| break; |
| case GE2D_DST_REPEAT_4: |
| src2_dst_data_cfg->dst_rpt = DST_RPT_4 | |
| DST_RPT_PATTERN_XX; |
| break; |
| case GE2D_DST_REPEAT_8: |
| src2_dst_data_cfg->dst_rpt = DST_RPT_8 | |
| DST_RPT_PATTERN_XX; |
| break; |
| default: |
| src2_dst_data_cfg->dst_rpt = 0; |
| break; |
| } |
| } |
| |
| static bool is_src1_addr_update(struct ge2d_src1_data_s *src1_data_cfg, |
| unsigned long *phy_addr, |
| unsigned int *stride) |
| { |
| int i; |
| int update = 0; |
| |
| for (i = 0; i < MAX_PLANE; i++) { |
| if (phy_addr[i]) { |
| if (phy_addr[i] != src1_data_cfg->phy_addr[i] || |
| stride[i] != src1_data_cfg->stride[i]) { |
| update = 1; |
| break; |
| } |
| } |
| } |
| return update; |
| } |
| |
| static bool is_src2_addr_update(struct ge2d_src2_dst_data_s *src2_dst_data_cfg, |
| unsigned long *phy_addr, |
| unsigned int *stride) |
| { |
| int i; |
| int update = 0; |
| |
| for (i = 0; i < MAX_PLANE; i++) { |
| if (phy_addr[i]) { |
| if (phy_addr[i] != src2_dst_data_cfg->src2_phyaddr[i] || |
| stride[i] != src2_dst_data_cfg->src2_stride[i]) { |
| update = 1; |
| break; |
| } |
| } |
| } |
| return update; |
| } |
| |
| static bool is_dst_addr_update(struct ge2d_src2_dst_data_s *src2_dst_data_cfg, |
| unsigned long *phy_addr, |
| unsigned int *stride) |
| { |
| int i; |
| int update = 0; |
| |
| for (i = 0; i < MAX_PLANE; i++) { |
| if (phy_addr[i]) { |
| if (phy_addr[i] != src2_dst_data_cfg->dst_phyaddr[i] || |
| stride[i] != src2_dst_data_cfg->dst_stride[i]) { |
| update = 1; |
| break; |
| } |
| } |
| } |
| return update; |
| } |
| |
| void ge2dgen_src(struct ge2d_context_s *wq, |
| unsigned int canvas_addr, |
| unsigned int format, |
| unsigned long *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); |
| int i; |
| |
| if (format != src1_data_cfg->format_all || |
| canvas_addr != src1_data_cfg->canaddr || |
| is_src1_addr_update(src1_data_cfg, phy_addr, 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); |
| for (i = 0; i < MAX_PLANE; i++) { |
| src1_data_cfg->phy_addr[i] = phy_addr[i]; |
| src1_data_cfg->stride[i] = stride[i]; |
| } |
| 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 long *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); |
| int i; |
| |
| if (format != src2_dst_data_cfg->src2_format_all || |
| canvas_addr != src2_dst_data_cfg->src2_canaddr || |
| is_src2_addr_update(src2_dst_data_cfg, phy_addr, stride)) { |
| src2_dst_data_cfg->src2_canaddr = canvas_addr; |
| |
| _set_src2_format(src2_dst_data_cfg, src2_dst_gen_cfg, format); |
| for (i = 0; i < MAX_PLANE; i++) { |
| src2_dst_data_cfg->src2_phyaddr[i] = phy_addr[i]; |
| src2_dst_data_cfg->src2_stride[i] = stride[i]; |
| } |
| 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 long *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); |
| int i; |
| |
| if (format != src2_dst_data_cfg->dst_format_all || |
| canvas_addr != src2_dst_data_cfg->dst_canaddr || |
| is_dst_addr_update(src2_dst_data_cfg, phy_addr, 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); |
| for (i = 0; i < MAX_PLANE; i++) { |
| src2_dst_data_cfg->dst_phyaddr[i] = phy_addr[i]; |
| src2_dst_data_cfg->dst_stride[i] = stride[i]; |
| } |
| 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; |
| } |
| } |