v2d: add new composer device. [1/1]

PD#SWPL-183637

Problem:
add new composer device

Solution:
add new composer device

Verify:
SC2

Change-Id: I4f70a9c195c2ca2ffd4e311f4f2250618343baf8
Signed-off-by: zhenteng.tian <zhenteng.tian@amlogic.com>
This commit is contained in:
zhenteng.tian
2024-11-29 18:45:32 +08:00
committed by gerrit autosubmit
parent 9f5cb6fdd6
commit e007cda856
20 changed files with 4743 additions and 0 deletions
+6
View File
@@ -1823,6 +1823,12 @@
status = "okay";
};
v2d {
compatible = "amlogic, v2d";
dev_name = "v2d";
status = "okay";
};
video_composer {
compatible = "amlogic, video_composer";
dev_name = "video_composer";
+1
View File
@@ -206,6 +206,7 @@ CONFIG_AMLOGIC_VIDEO_PP_COMMON=y
CONFIG_AMLOGIC_VIDEO_TUNNEL=y
CONFIG_AMLOGIC_VIDEOQUEUE=y
CONFIG_AMLOGIC_DI_PROCESS=y
CONFIG_AMLOGIC_MEDIA_V2D=y
CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM=y
CONFIG_AMLOGIC_MEDIA_FRC=y
CONFIG_AMLOGIC_MEDIA_GDC=y
@@ -1823,6 +1823,12 @@
status = "okay";
};
v2d {
compatible = "amlogic, v2d";
dev_name = "v2d";
status = "okay";
};
video_composer {
compatible = "amlogic, video_composer";
dev_name = "video_composer";
+1
View File
@@ -238,6 +238,7 @@ CONFIG_AMLOGIC_VIDEO_DISPLAY=y
CONFIG_AMLOGIC_VIDEO_PP_COMMON=y
CONFIG_AMLOGIC_VIDEO_TUNNEL=y
CONFIG_AMLOGIC_VIDEOQUEUE=y
CONFIG_AMLOGIC_MEDIA_V2D=y
CONFIG_AMLOGIC_DI_PROCESS=y
CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM=y
CONFIG_AMLOGIC_MEDIA_FRC=y
+8
View File
@@ -660,6 +660,14 @@ ddk_module(
"video_processor/di_process/di_process.c",
],
},
"CONFIG_AMLOGIC_MEDIA_V2D": {
True: [
"video_processor/v2d/v2d.c",
"video_processor/v2d/v2d_dewarp_composer.c",
"video_processor/v2d/v2d_ge2d_composer.c",
"video_processor/v2d/v2d_vicp_composer.c",
],
},
"CONFIG_AMLOGIC_VIDEO_DISPLAY": {
True: [
"video_processor/videodisplay/videodisplay_util.c",
+1
View File
@@ -120,6 +120,7 @@ static int __init media_main_init(void)
call_sub_init(amlogic_codec_mm_dma_buf_init);
call_sub_init(amprime_sl_init);
call_sub_init(di_process_module_init);
call_sub_init(v2d_module_init);
pr_debug("### %s() end\n", __func__);
return 0;
}
+9
View File
@@ -765,4 +765,13 @@ static inline int di_process_module_init(void)
}
#endif
#ifdef CONFIG_AMLOGIC_MEDIA_V2D
int v2d_module_init(void);
#else
static inline int v2d_module_init(void)
{
return 0;
}
#endif
#endif
+1
View File
@@ -28,6 +28,7 @@ source "$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/videoqueue/Kconfig"
source "$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/common/Kconfig"
source "$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/di_process/Kconfig"
source "$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/videodisplay/Kconfig"
source "$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/v2d/Kconfig"
endif
endmenu
+1
View File
@@ -11,3 +11,4 @@ include $(srctree)/$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/videoqueu
include $(srctree)/$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/common/Makefile
include $(srctree)/$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/di_process/Makefile
include $(srctree)/$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/videodisplay/Makefile
include $(srctree)/$(COMMON_DRIVERS_DIR)/drivers/media/video_processor/v2d/Makefile
+16
View File
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
#
# Amlogic v2d device configuration
#
menu "Amlogic v2d support"
config AMLOGIC_MEDIA_V2D
tristate "Amlogic v2d device support"
default y
help
Select to enable "Amlogic v2d device support.
endmenu
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
asflags-y += -mfloat-abi=softfp -mfpu=neon
$(MEDIA_MODULE_NAME)-$(CONFIG_AMLOGIC_MEDIA_V2D) += video_processor/v2d/v2d.o
$(MEDIA_MODULE_NAME)-$(CONFIG_AMLOGIC_MEDIA_V2D) += video_processor/v2d/v2d_ge2d_composer.o
$(MEDIA_MODULE_NAME)-$(CONFIG_AMLOGIC_MEDIA_V2D) += video_processor/v2d/v2d_dewarp_composer.o
$(MEDIA_MODULE_NAME)-$(CONFIG_AMLOGIC_MEDIA_V2D) += video_processor/v2d/v2d_vicp_composer.o
File diff suppressed because it is too large Load Diff
+286
View File
@@ -0,0 +1,286 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#ifndef V2D_H
#define V2D_H
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/delay.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/kfifo.h>
#include <linux/amlogic/media/video_sink/v4lvideo_ext.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/amlogic/media/ge2d/ge2d.h>
#include <linux/amlogic/media/video_sink/video.h>
#include "v2d_ge2d_composer.h"
#include "v2d_dewarp_composer.h"
#include "v2d_vicp_composer.h"
#define MAX_LAYER_COUNT 9
#define V2D_POOL_SIZE 16
#define BUFFER_LEN 4
#define V2D_SET_ENABLE_MODE 1
#define V2D_SET_DISABLE_MODE 0
#define PRINT_ERROR 0X0
#define PRINT_QUEUE_STATUS 0X01
#define PRINT_FENCE 0X02
#define PRINT_PERFORMANCE 0X04
#define PRINT_AXIS 0X08
#define PRINT_INDEX_DISP 0X10
#define PRINT_PATTERN 0X20
#define PRINT_OTHER 0X040
#define PRINT_DEWARP 0X0100
#define PRINT_VICP 0x0200
#define WAIT_READY_Q_TIMEOUT 100
#define WAIT_DISPLAY_Q_TIMEOUT 100
#define MAX_RECEIVE_WAIT_TIME 15 /*15ms*/
#define V2D_IOC_MAGIC 'R'
#define V2D_IOCTL_SET_FRAMES _IOW(V2D_IOC_MAGIC, 0x00, struct frames_info_t)
#define V2D_IOCTL_SET_ENABLE _IOW(V2D_IOC_MAGIC, 0x01, int)
#define V2D_IOCTL_SET_FENCE _IOW(V2D_IOC_MAGIC, 0x02, struct release_info_t)
struct frame_info_t {
s32 fd;
s32 fence_fd;
s32 buffer_w;
s32 buffer_h;
s32 align_w;
s32 align_h;
s32 dst_x;
s32 dst_y;
s32 dst_w;
s32 dst_h;
s32 crop_x;
s32 crop_y;
s32 crop_w;
s32 crop_h;
s32 zorder;
s32 buffer_format;
s32 transform;
s32 alpha;
s32 reserved[10];
};
struct frames_info_t {
s32 frame_count;
struct frame_info_t input_buffer[MAX_LAYER_COUNT];
struct frame_info_t out_buffer;
s32 reserved[4];
};
struct release_info_t {
s32 release_fd;
s32 release_fence_fd;
};
enum v2d_buffer_status {
UNINITIAL = 0,
INIT_SIZE_SUCCESS,
INIT_BUFFER_SUCCESS,
INIT_BUFFER_ERROR,
};
struct input_crop_s {
u32 left;
u32 top;
u32 width;
u32 height;
};
struct input_axis_s {
int left;
int top;
int width;
int height;
};
struct output_axis {
u32 min_left;
u32 min_top;
u32 max_right;
u32 max_bottom;
};
enum v2d_transform_t {
/* flip source image horizontally */
V2D_TRANSFORM_FLIP_H = 1,
/* flip source image vertically */
V2D_TRANSFORM_FLIP_V = 2,
/* rotate source image 90 degrees clock-wise */
V2D_TRANSFORM_ROT_90 = 4,
/* rotate source image 180 degrees */
V2D_TRANSFORM_ROT_180 = 3,
/* rotate source image 270 degrees clock-wise */
V2D_TRANSFORM_ROT_270 = 7,
/* flip source image horizontally, the rotate 90 degrees clock-wise */
V2D_TRANSFORM_FLIP_H_ROT_90 = V2D_TRANSFORM_FLIP_H | V2D_TRANSFORM_ROT_90,
/* flip source image vertically, the rotate 90 degrees clock-wise */
V2D_TRANSFORM_FLIP_V_ROT_90 = V2D_TRANSFORM_FLIP_V | V2D_TRANSFORM_ROT_90,
};
enum buffer_format_t {
NV21 = 0,
YUV444 = 1,
};
enum output_buf_mode_t {
BUFFER_MODE_UNINIT = 0,
BUFFER_MODE_GE2D,
BUFFER_MODE_DEWARP,
BUFFER_MODE_VICP,
};
struct received_frames_t {
int index;
atomic_t on_use;
struct input_crop_s crop_info[MAX_LAYER_COUNT];
struct input_axis_s axis_info[MAX_LAYER_COUNT];
struct output_axis output_axis;
struct frames_info_t frames_info;
struct file *input_file[MAX_LAYER_COUNT];
struct file *input_fence[MAX_LAYER_COUNT];
unsigned long phy_addr[MAX_LAYER_COUNT];
bool is_tvp;
size_t usage;
};
struct dst_buf_t {
int index;
struct composer_info_t composer_info;
enum output_buf_mode_t buf_used;
bool dirty;
ulong phy_addr;
u32 buf_w;
u32 buf_h;
u32 buf_size;
bool is_tvp;
u32 dw_size;
ulong afbc_head_addr;
u32 afbc_head_size;
ulong afbc_body_addr;
u32 afbc_body_size;
ulong afbc_table_addr;
ulong afbc_table_handle;
u32 afbc_table_size;
};
struct v2d_fence_cb_t {
struct dma_fence_cb base_cb;
struct v2d_dev *dev;
struct file *buffer_file;
struct file *fence_file;
};
struct display_data_t {
struct dma_buf *output_dmabuf;
struct dst_buf_t *output_buffer;
atomic_t on_use;
};
enum composer_dev {
COMPOSER_WITH_DEFAULT = 0,
COMPOSER_WITH_GE2D,
COMPOSER_WITH_DEWARP,
COMPOSER_WITH_VICP,
COMPOSER_WITH_UNINITIAL,
};
enum v2d_work_mode {
V2D_MODE_UNINITIAL = 0,
V2D_MODE_ROTATE,
V2D_MODE_COMPOSER,
};
union composer_device_config {
struct ge2d_src_para_s ge2d_data;
struct dewarp_vf_para_s dewarp_data;
struct vicp_data_config_s vicp_data;
};
struct v2d_dev_config {
union composer_device_config composer_device_param;
unsigned long addr;
struct vframe_s *input_vf;
struct dst_buf_t *dst_buf;
struct input_axis_s frame_axis;
struct input_crop_s frame_crop;
int count;
int index;
int zorder;
bool is_tvp;
};
struct v2d_dev {
u32 index;
struct v2d_port_s *port;
enum composer_dev dev_choice;
enum v2d_work_mode work_mode;
bool status_enabled;
DECLARE_KFIFO(receive_q, struct received_frames_t *, V2D_POOL_SIZE);
DECLARE_KFIFO(free_q, struct dst_buf_t *, BUFFER_LEN);
DECLARE_KFIFO(file_free_q, struct dma_buf *, V2D_POOL_SIZE);
DECLARE_KFIFO(file_wait_q, struct dma_buf *, V2D_POOL_SIZE);
DECLARE_KFIFO(display_q, struct display_data_t *, BUFFER_LEN);
DECLARE_KFIFO(fence_wait_q, struct file *, V2D_POOL_SIZE);
DECLARE_KFIFO(fence_cb_q, struct v2d_fence_cb_t *, V2D_POOL_SIZE);
struct received_frames_t received_frames[V2D_POOL_SIZE];
struct dst_buf_t dst_buf[BUFFER_LEN];
struct v2d_fence_cb_t v2d_fence_cb[V2D_POOL_SIZE];
struct display_data_t display_data[V2D_POOL_SIZE];
struct task_struct *file_thread;
wait_queue_head_t file_wq;
struct completion file_task_done;
struct dma_buf *out_dmabuf[V2D_POOL_SIZE];
void *v2d_timeline;
u32 cur_streamline_val;
u32 buf_width;
u32 buf_height;
int (*config_param_func)(struct v2d_dev *dev,
struct frame_info_t *vframe_info_cur, struct v2d_dev_config *v2d_composer_param);
int (*process_data_func)(struct v2d_dev *dev, struct v2d_dev_config *v2d_composer_param);
enum v2d_buffer_status buffer_status;
struct ge2d_composer_para ge2d_para;
struct dewarp_composer_para dewarp_para;
u32 vinfo_w;
u32 vinfo_h;
u32 output_duration;
u32 file_thread_stopped;
bool thread_need_stop;
bool need_do_file;
u32 fget_count;
u32 fput_count;
u32 received_count;
u32 received_new_count;
u32 fence_creat_count;
u32 fence_signal_count;
u32 buffer_release_count;
u32 fence_wait_count;
u32 fence_wait_time_total;
};
struct v2d_port_s {
const char *name;
u32 index;
u32 open_count;
struct device *class_dev;
struct device *pdev;
};
#endif
@@ -0,0 +1,457 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/amlogic/media/ge2d/ge2d.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/utils/amlog.h>
#include <linux/amlogic/media/ge2d/ge2d_func.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/delay.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <api/gdc_api.h>
#include "v2d_dewarp_composer.h"
#define GDC_FIRMWARE_PATH "/vendor/lib/firmware/gdc/"
static unsigned int dewarp_com_dump_last;
int v2d_get_dewarp_format(int index, struct vframe_s *vf)
{
int format = NV12;
if (IS_ERR_OR_NULL(vf)) {
pr_info("v2d:[%d] %s: vf is NULL.\n", index, __func__);
return -1;
}
if ((vf->type & VIDTYPE_VIU_NV21) ||
(vf->type & VIDTYPE_VIU_NV12))
format = NV12;
else if (vf->type & VIDTYPE_VIU_422)
format = 0;
else if (vf->type & VIDTYPE_VIU_444)
format = YUV444_P;
else if (vf->type & VIDTYPE_RGB_444)
format = RGB444_P;
return format;
}
static int get_dewarp_rotation_value(int transform)
{
int rotate_value = 0;
if (transform == 4 || transform == 5 || transform == 6)
rotate_value = 270;
else if (transform == 3)
rotate_value = 180;
else if (transform == 7)
rotate_value = 90;
else
rotate_value = 0;
return rotate_value;
}
static int dump_dewarp_vframe(char *path, int width, int height, u32 phy_adr_y, u32 phy_adr_uv)
{
#ifdef CONFIG_AMLOGIC_ENABLE_VIDEO_PIPELINE_DUMP_DATA
int size = 0;
struct file *fp = NULL;
loff_t position = 0;
u8 *data;
if (IS_ERR_OR_NULL(path)) {
pr_info("%s: path is NULL.\n", __func__);
return -1;
}
/* open file to write */
fp = filp_open(path, O_WRONLY | O_CREAT, 0644);
if (IS_ERR(fp)) {
pr_info("%s: open file error\n", __func__);
return -1;
}
/* Write buf to file */
size = width * height;
data = codec_mm_vmap(phy_adr_y, size);
if (!data) {
pr_info("%s: vmap failed\n", __func__);
return -1;
}
/* change to KERNEL_DS address limit */
kernel_write(fp, data, size, &position);
codec_mm_unmap_phyaddr(data);
size = width * height / 2;
data = codec_mm_vmap(phy_adr_uv, size);
if (!data) {
pr_info("%s: vmap failed\n", __func__);
return -1;
}
/* change to KERNEL_DS address limit */
kernel_write(fp, data, size, &position);
codec_mm_unmap_phyaddr(data);
filp_close(fp, NULL);
return 0;
#else
return -1;
#endif
}
int v2d_load_dewarp_firmware(struct dewarp_composer_para *param)
{
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
int ret = 0;
#endif
char file_name[64];
struct firmware_rotate_s fw_param;
bool is_need_load = false;
int frame_rotation = 0;
if (IS_ERR_OR_NULL(param)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
frame_rotation = get_dewarp_rotation_value(param->vf_para->src_vf_angle);
if (param->last_fw_param.in_width != param->vf_para->src_vf_width ||
param->last_fw_param.in_height != param->vf_para->src_vf_height ||
param->last_fw_param.out_width != param->vf_para->dst_vf_width ||
param->last_fw_param.out_height != param->vf_para->dst_vf_height ||
param->last_fw_param.degree != frame_rotation) {
param->last_fw_param.format = NV12;
param->last_fw_param.in_width = param->vf_para->src_vf_width;
param->last_fw_param.in_height = param->vf_para->src_vf_height;
param->last_fw_param.out_width = param->vf_para->dst_vf_width;
param->last_fw_param.out_height = param->vf_para->dst_vf_height;
param->last_fw_param.degree = frame_rotation;
is_need_load = true;
}
if (dewarp_print) {
pr_info("v2d:[%d] need load firmware: %d.\n", param->index, is_need_load);
pr_info("v2d:[%d] src_vf, w:%d, h:%d, fromat:%d, rotation:%d.\n",
param->index,
param->vf_para->src_vf_width,
param->vf_para->src_vf_height,
param->vf_para->src_vf_format,
param->vf_para->src_vf_angle);
pr_info("v2d:[%d] src_buf, w0:%d, w1:%d.\n", param->index,
param->vf_para->src_buf_stride0, param->vf_para->src_buf_stride1);
pr_info("v2d:[%d] dst_vf, w:%d, h:%d.\n", param->index,
param->vf_para->dst_vf_width, param->vf_para->dst_vf_height);
pr_info("v2d:[%d] dst_buf, w:%d.\n", param->index,
param->vf_para->dst_buf_stride);
}
if (param->fw_load.phys_addr == 0 || is_need_load) {
v2d_unload_dewarp_firmware(param);
pr_info("v2d:[%d] start load firmware.\n", param->index);
if (dewarp_load_flag) {
memset(file_name, 0, 64);
sprintf(file_name, "%dx%d-%dx%d-%d_nv12.bin",
param->vf_para->src_vf_width,
param->vf_para->src_vf_height,
param->vf_para->dst_vf_width,
param->vf_para->dst_vf_height,
frame_rotation);
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
ret = load_firmware_by_name(file_name, &param->fw_load);
if (ret <= 0) {
pr_info("v2d:[%d] %s: load firmware failed.\n",
param->index, __func__);
return -1;
}
#else
return -1;
#endif
} else {
fw_param.format = NV12;
fw_param.in_width = param->vf_para->src_vf_width;
fw_param.in_height = param->vf_para->src_vf_height;
fw_param.out_width = param->vf_para->dst_vf_width;
fw_param.out_height = param->vf_para->dst_vf_height;
fw_param.degree = frame_rotation;
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
ret = rotation_calc_and_load_firmware(&fw_param, &param->fw_load);
if (ret <= 0) {
pr_info("v2d:[%d] %s: calc and load firmware failed.\n",
param->index, __func__);
return -1;
}
#else
return -1;
#endif
}
}
return 0;
}
int v2d_unload_dewarp_firmware(struct dewarp_composer_para *param)
{
if (IS_ERR_OR_NULL(param)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
if (param->fw_load.phys_addr != 0) {
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
release_config_firmware(&param->fw_load);
#endif
param->fw_load.phys_addr = 0;
}
return 0;
}
bool check_dewarp_status(struct vframe_s *input_vf, int count, int work_mode, int index)
{
int src_formate;
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
if (!is_aml_gdc_supported())
return false;
#endif
if (count > 1) {
pr_info("%s: dewarp not support composer.\n", __func__);
return false;
}
if (work_mode != 1)
return false;
if (!input_vf)
src_formate = NV12;
else
src_formate = v2d_get_dewarp_format(index, input_vf);
if (src_formate != NV12)
return false;
return true;
}
int v2d_init_dewarp_composer(struct dewarp_composer_para *param)
{
if (IS_ERR_OR_NULL(param)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
if (IS_ERR_OR_NULL(param->context)) {
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
param->context = create_gdc_work_queue(AML_GDC);
#else
param->context = NULL;
#endif
if (IS_ERR_OR_NULL(param->context)) {
pr_info("v2d:[%d] %s: create dewrap work_queue failed.\n",
param->index,
__func__);
return -1;
}
} else {
pr_info("v2d:[%d] %s: dewrap work queue exist.\n",
param->index, __func__);
}
return 0;
}
int v2d_uninit_dewarp_composer(struct dewarp_composer_para *param)
{
int ret = 0;
if (IS_ERR_OR_NULL(param)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
v2d_unload_dewarp_firmware(param);
if (!IS_ERR_OR_NULL(param->context)) {
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
ret = destroy_gdc_work_queue(param->context);
#else
ret = -1;
#endif
if (ret != 0) {
pr_info("v2d:[%d] %s: destroy dewarp work queue failed.\n",
param->index,
__func__);
return -1;
}
pr_info("v2d:[%d] %s: destroy dewarp work queue success.\n",
param->index, __func__);
} else {
pr_info("v2d:[%d] %s: dewarp work queue not create.\n",
param->index,
__func__);
}
param->context = NULL;
return 0;
}
int v2d_config_dewarp_vframe(struct dewarp_vf_para_s *vframe_para,
struct dewarp_common_para *common_para)
{
struct vframe_s *vf = NULL;
struct vframe_s *src_vf = common_para->input_para.vframe;
int call_index = common_para->input_para.call_index;
struct pic_s *pic_info_in = &common_para->input_para.pic_info;
struct pic_s *pic_info_out = &common_para->output_para.pic_info;
if (IS_ERR_OR_NULL(vframe_para)) {
pr_info("v2d:[%d] %s: vframe_para is null.\n", call_index, __func__);
return -1;
}
if (src_vf) {
if (src_vf->canvas0_config[0].phy_addr == 0) {
if ((src_vf->flag & VFRAME_FLAG_DOUBLE_FRAM) &&
src_vf->vf_ext) {
vf = src_vf->vf_ext;
} else {
pr_info("v2d:[%d] %s: vf no yuv data.\n", call_index, __func__);
return -1;
}
} else {
vf = src_vf;
}
vframe_para->src_vf_width = vf->width;
vframe_para->src_vf_height = vf->height;
vframe_para->src_vf_format = v2d_get_dewarp_format(call_index, vf);
vframe_para->src_vf_plane_count = 2;
vframe_para->src_buf_addr0 = vf->canvas0_config[0].phy_addr;
vframe_para->src_buf_stride0 = vf->canvas0_config[0].width;
vframe_para->src_buf_addr1 = vf->canvas0_config[1].phy_addr;
vframe_para->src_buf_stride1 = vf->canvas0_config[1].width;
vframe_para->src_vf_angle = common_para->input_para.transform;
vframe_para->src_endian = vf->canvas0_config[0].endian;
if (vf->type & VIDTYPE_VIU_NV12)
vframe_para->uvswap_enable = 1;
vframe_para->dst_vf_width = pic_info_out->align_w;
vframe_para->dst_vf_height = pic_info_out->align_h;
vframe_para->dst_vf_plane_count = 2;
vframe_para->dst_buf_addr = pic_info_out->addr[0];
vframe_para->dst_buf_stride = pic_info_out->align_w;
vframe_para->dst_endian = 0;
vframe_para->is_tvp = pic_info_in->is_tvp;
} else {
if (pic_info_in->format == 1) {
vframe_para->src_vf_format = YUV444_P;
vframe_para->src_buf_stride0 = pic_info_in->align_w * 3;
} else {
vframe_para->src_vf_format = NV12;
vframe_para->src_buf_stride0 = pic_info_in->align_w;
}
vframe_para->src_vf_width = pic_info_in->width;
vframe_para->src_vf_height = pic_info_in->height;
vframe_para->src_vf_plane_count = 2;
vframe_para->src_buf_addr0 = pic_info_in->addr[0];
vframe_para->src_buf_addr1 = pic_info_in->addr[0]
+ vframe_para->src_buf_stride0 * pic_info_in->align_h;
vframe_para->src_buf_stride1 = vframe_para->src_buf_stride0;
vframe_para->src_vf_angle = common_para->input_para.transform;
vframe_para->src_endian = 0;
vframe_para->dst_vf_width = pic_info_out->align_w;
vframe_para->dst_vf_height = pic_info_out->align_h;
vframe_para->dst_vf_plane_count = 2;
vframe_para->dst_buf_addr = pic_info_out->addr[0];
vframe_para->dst_buf_stride = pic_info_out->align_w;
vframe_para->dst_endian = 0;
vframe_para->is_tvp = pic_info_in->is_tvp;
}
return 0;
}
int v2d_dewarp_data_composer(struct dewarp_composer_para *param, bool is_tvp)
{
int ret;
struct gdc_phy_setting gdc_config;
char dump_name[32];
if (IS_ERR_OR_NULL(param)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
memset(&gdc_config, 0, sizeof(struct gdc_phy_setting));
gdc_config.format = param->vf_para->src_vf_format;
gdc_config.in_width = param->vf_para->src_vf_width;
gdc_config.in_height = param->vf_para->src_vf_height;
/*16-byte alignment*/
gdc_config.in_y_stride = AXI_WORD_ALIGN(param->vf_para->src_buf_stride0);
/*16-byte alignment*/
gdc_config.in_c_stride = AXI_WORD_ALIGN(param->vf_para->src_buf_stride1);
gdc_config.in_plane_num = param->vf_para->src_vf_plane_count;
gdc_config.out_width = param->vf_para->dst_vf_width;
gdc_config.out_height = param->vf_para->dst_vf_height;
/*16-byte alignment*/
gdc_config.out_y_stride = AXI_WORD_ALIGN(param->vf_para->dst_buf_stride);
/*16-byte alignment*/
gdc_config.out_c_stride = AXI_WORD_ALIGN(param->vf_para->dst_buf_stride);
gdc_config.out_plane_num = param->vf_para->dst_vf_plane_count;
gdc_config.in_paddr[0] = param->vf_para->src_buf_addr0;
gdc_config.in_paddr[1] = param->vf_para->src_buf_addr1;
gdc_config.out_paddr[0] = param->vf_para->dst_buf_addr;
gdc_config.out_paddr[1] = param->vf_para->dst_buf_addr
+ AXI_WORD_ALIGN(gdc_config.out_width)
* AXI_WORD_ALIGN(gdc_config.out_height);
gdc_config.config_paddr = param->fw_load.phys_addr;
gdc_config.config_size = param->fw_load.size_32bit; /* in 32bit */
gdc_config.uvswap_enable = param->vf_para->uvswap_enable;
if (param->vf_para->is_tvp)
gdc_config.use_sec_mem = 1; /* secure mem access */
else
gdc_config.use_sec_mem = 0;
if (param->vf_para->src_endian != 0)
gdc_config.in_endian = GDC_ENDIAN_BIG_8BYTES;
else
gdc_config.in_endian = GDC_ENDIAN_LITTLE;
if (param->vf_para->dst_endian != 0)
gdc_config.out_endian = GDC_ENDIAN_BIG_8BYTES;
else
gdc_config.out_endian = GDC_ENDIAN_LITTLE;
#ifdef CONFIG_AMLOGIC_MEDIA_GDC
ret = gdc_process_phys(param->context, &gdc_config);
#else
ret = -1;
#endif
if (ret < 0) {
pr_info("v2d:[%d] %s: dewrap process failed.\n", param->index, __func__);
} else {
if (dewarp_com_dump != dewarp_com_dump_last) {
sprintf(dump_name, "/data/src_%d.yuv", dewarp_com_dump);
dump_dewarp_vframe(dump_name,
param->vf_para->src_vf_width,
param->vf_para->src_vf_height,
param->vf_para->src_buf_addr0,
param->vf_para->src_buf_addr1);
sprintf(dump_name, "/data/dst_%d.yuv", dewarp_com_dump);
dump_dewarp_vframe(dump_name,
param->vf_para->dst_vf_width,
param->vf_para->dst_vf_height,
gdc_config.out_paddr[0],
gdc_config.out_paddr[1]);
dewarp_com_dump_last = dewarp_com_dump;
}
}
return ret;
}
@@ -0,0 +1,85 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#ifndef VFRAME_DEWARP_COMPOSER_H
#define VFRAME_DEWARP_COMPOSER_H
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/gdc/gdc.h>
struct dewarp_vf_para_s {
int src_vf_format;
int src_vf_width;
int src_vf_height;
int src_vf_plane_count;
int src_vf_angle;
ulong src_buf_addr0;
int src_buf_stride0;
ulong src_buf_addr1;
int src_buf_stride1;
int src_endian;
int dst_vf_format;
int dst_vf_width;
int dst_vf_height;
int dst_vf_plane_count;
ulong dst_buf_addr;
int dst_buf_stride;
int dst_endian;
bool is_tvp;
bool uvswap_enable;
};
struct pic_s {
int format;
u32 width;
u32 height;
ulong addr[2];
u32 align_w;
u32 align_h;
int plane_count;
bool is_tvp;
};
struct composer_input_para {
int call_index;
struct vframe_s *vframe;
struct pic_s pic_info;
int transform;
};
struct composer_output_para {
struct pic_s pic_info;
};
struct dewarp_common_para {
struct composer_input_para input_para;
struct composer_output_para output_para;
};
struct dewarp_composer_para {
int index;
struct gdc_context_s *context;
struct firmware_load_s fw_load;
struct dewarp_vf_para_s *vf_para;
struct firmware_rotate_s last_fw_param;
};
extern u32 dewarp_load_flag;
extern int dewarp_com_dump;
extern int dewarp_print;
int v2d_get_dewarp_format(int index, struct vframe_s *vf);
int v2d_load_dewarp_firmware(struct dewarp_composer_para *param);
int v2d_unload_dewarp_firmware(struct dewarp_composer_para *param);
bool check_dewarp_status(struct vframe_s *input_vf, int count, int work_mode, int index);
int v2d_init_dewarp_composer(struct dewarp_composer_para *param);
int v2d_uninit_dewarp_composer(struct dewarp_composer_para *param);
int v2d_config_dewarp_vframe(struct dewarp_vf_para_s *vframe_para,
struct dewarp_common_para *common_para);
int v2d_dewarp_data_composer(struct dewarp_composer_para *param, bool is_tvp);
#endif
@@ -0,0 +1,949 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/amlogic/media/ge2d/ge2d.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/utils/amlog.h>
#include <linux/amlogic/media/ge2d/ge2d_func.h>
/* media module used media/registers/cpu_version.h since kernel 5.4 */
#include <linux/amlogic/media/registers/cpu_version.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/delay.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "v2d_ge2d_composer.h"
#define WIDTH_8K 7680
#define HEIGHT_8K 7680
#define IS_DI_PSTLINK(di_flag) ((di_flag) & DI_FLAG_DI_PSTVPPLINK)
#ifdef CONFIG_AMLOGIC_ENABLE_VIDEO_PIPELINE_DUMP_DATA
static int dump_src_count;
static int dump_before_dst_count;
static int dump_dst_count;
static int dump_black_count;
#endif
#ifndef CONFIG_AMLOGIC_MEDIA_GE2D
void stretchblt_noalpha(struct ge2d_context_s *wq,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h)
{
}
int destroy_ge2d_work_queue(struct ge2d_context_s *ge2d_work_queue)
{
return 0;
}
void fillrect(struct ge2d_context_s *wq,
int x, int y, int w, int h, unsigned int color)
{
}
#endif
#ifndef CONFIG_AMLOGIC_UVM_CORE
struct vframe_s *dmabuf_get_vframe(struct dma_buf *dmabuf)
{
return NULL;
}
#endif
static int get_source_type(struct ge2d_src_para_s *src_data)
{
enum videocom_source_type ret;
int interlace_mode;
interlace_mode = src_data->type & VIDTYPE_TYPEMASK;
if (src_data->source_type == VFRAME_SOURCE_TYPE_HDMI ||
src_data->source_type == VFRAME_SOURCE_TYPE_CVBS) {
if ((src_data->bitdepth & BITDEPTH_Y10) &&
(!(src_data->type & VIDTYPE_COMPRESS)) &&
(get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL))
ret = VDIN_10BIT_NORMAL;
else
ret = VDIN_8BIT_NORMAL;
} else {
if ((src_data->bitdepth & BITDEPTH_Y10) &&
(!(src_data->type & VIDTYPE_COMPRESS)) &&
(get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)) {
if (interlace_mode == VIDTYPE_INTERLACE_TOP)
ret = DECODER_10BIT_TOP;
else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM)
ret = DECODER_10BIT_BOTTOM;
else
ret = DECODER_10BIT_NORMAL;
} else {
if (interlace_mode == VIDTYPE_INTERLACE_TOP)
ret = DECODER_8BIT_TOP;
else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM)
ret = DECODER_8BIT_BOTTOM;
else
ret = DECODER_8BIT_NORMAL;
}
}
return ret;
}
static int get_input_format(struct ge2d_src_para_s *src_data)
{
int format = GE2D_FORMAT_M24_YUV420;
enum videocom_source_type source_type;
source_type = get_source_type(src_data);
switch (source_type) {
case DECODER_8BIT_NORMAL:
if (src_data->type & VIDTYPE_VIU_422)
format = GE2D_FORMAT_S16_YUV422;
else if (src_data->type & VIDTYPE_VIU_NV21)
format = GE2D_FORMAT_M24_NV21;
else if (src_data->type & VIDTYPE_VIU_NV12)
format = GE2D_FORMAT_M24_NV12;
else if (src_data->type & VIDTYPE_VIU_444)
format = GE2D_FORMAT_S24_YUV444;
else
format = GE2D_FORMAT_M24_YUV420;
break;
case DECODER_8BIT_BOTTOM:
if (src_data->type & VIDTYPE_VIU_422)
format = GE2D_FORMAT_S16_YUV422
| (GE2D_FORMAT_S16_YUV422B & (3 << 3));
else if (src_data->type & VIDTYPE_VIU_NV21)
format = GE2D_FORMAT_M24_NV21
| (GE2D_FORMAT_M24_NV21B & (3 << 3));
else if (src_data->type & VIDTYPE_VIU_NV12)
format = GE2D_FORMAT_M24_NV12
| (GE2D_FORMAT_M24_NV12B & (3 << 3));
else if (src_data->type & VIDTYPE_VIU_444)
format = GE2D_FORMAT_S24_YUV444
| (GE2D_FORMAT_S24_YUV444B & (3 << 3));
else
format = GE2D_FORMAT_M24_YUV420
| (GE2D_FMT_M24_YUV420B & (3 << 3));
break;
case DECODER_8BIT_TOP:
if (src_data->type & VIDTYPE_VIU_422)
format = GE2D_FORMAT_S16_YUV422
| (GE2D_FORMAT_S16_YUV422T & (3 << 3));
else if (src_data->type & VIDTYPE_VIU_NV21)
format = GE2D_FORMAT_M24_NV21
| (GE2D_FORMAT_M24_NV21T & (3 << 3));
else if (src_data->type & VIDTYPE_VIU_NV12)
format = GE2D_FORMAT_M24_NV12
| (GE2D_FORMAT_M24_NV12T & (3 << 3));
else if (src_data->type & VIDTYPE_VIU_444)
format = GE2D_FORMAT_S24_YUV444
| (GE2D_FORMAT_S24_YUV444T & (3 << 3));
else
format = GE2D_FORMAT_M24_YUV420
| (GE2D_FMT_M24_YUV420T & (3 << 3));
break;
case DECODER_10BIT_NORMAL:
if (src_data->type & VIDTYPE_VIU_422) {
if (src_data->bitdepth & FULL_PACK_422_MODE)
format = GE2D_FORMAT_S16_10BIT_YUV422;
else
format = GE2D_FORMAT_S16_12BIT_YUV422;
}
break;
case DECODER_10BIT_BOTTOM:
if (src_data->type & VIDTYPE_VIU_422) {
if (src_data->bitdepth & FULL_PACK_422_MODE)
format = GE2D_FORMAT_S16_10BIT_YUV422
| (GE2D_FORMAT_S16_10BIT_YUV422B
& (3 << 3));
else
format = GE2D_FORMAT_S16_12BIT_YUV422
| (GE2D_FORMAT_S16_12BIT_YUV422B
& (3 << 3));
}
break;
case DECODER_10BIT_TOP:
if (src_data->type & VIDTYPE_VIU_422) {
if (src_data->bitdepth & FULL_PACK_422_MODE)
format = GE2D_FORMAT_S16_10BIT_YUV422
| (GE2D_FORMAT_S16_10BIT_YUV422T
& (3 << 3));
else
format = GE2D_FORMAT_S16_12BIT_YUV422
| (GE2D_FORMAT_S16_12BIT_YUV422T
& (3 << 3));
}
break;
case VDIN_8BIT_NORMAL:
if (src_data->type & VIDTYPE_VIU_422) {
format = GE2D_FORMAT_S16_YUV422;
} else if (src_data->type & VIDTYPE_VIU_NV21) {
format = GE2D_FORMAT_M24_NV21;
} else if (src_data->type & VIDTYPE_VIU_NV12) {
format = GE2D_FORMAT_M24_NV12;
} else if (src_data->type & VIDTYPE_VIU_444) {
format = GE2D_FORMAT_S24_YUV444;
} else if (src_data->type & VIDTYPE_RGB_444) {
format = GE2D_FORMAT_S24_RGB;
if (src_data->is_vframe)
format &= (~GE2D_LITTLE_ENDIAN);
} else {
format = GE2D_FORMAT_M24_YUV420;
}
break;
case VDIN_10BIT_NORMAL:
if (src_data->type & VIDTYPE_VIU_422) {
if (src_data->bitdepth & FULL_PACK_422_MODE)
format = GE2D_FORMAT_S16_10BIT_YUV422;
else
format = GE2D_FORMAT_S16_12BIT_YUV422;
} else if (src_data->type & VIDTYPE_VIU_444) {
format = GE2D_FORMAT_S24_10BIT_YUV444;
} else if (src_data->type & VIDTYPE_RGB_444) {
format = GE2D_FORMAT_S24_10BIT_RGB888;
if (!src_data->is_vframe)
format |= GE2D_LITTLE_ENDIAN;
}
break;
default:
format = GE2D_FORMAT_M24_YUV420;
}
return format;
}
static enum ge2d_angle_type config_ge2d_rotation(int vf_transform)
{
int ge2d_angle = 0;
if (vf_transform == 1)
ge2d_angle = GE2D_ANGLE_TYPE_FLIP_H;
else if (vf_transform == 2)
ge2d_angle = GE2D_ANGLE_TYPE_FLIP_V;
else if (vf_transform == 4 || vf_transform == 5 || vf_transform == 6)
ge2d_angle = GE2D_ANGLE_TYPE_ROT_90;
else if (vf_transform == 3)
ge2d_angle = GE2D_ANGLE_TYPE_ROT_180;
else if (vf_transform == 7)
ge2d_angle = GE2D_ANGLE_TYPE_ROT_270;
else if (vf_transform != 0)
VIDEOCOM_INFO("%s: not support transform=%d\n", __func__, vf_transform);
return ge2d_angle;
}
static int alloc_src_canvas(struct ge2d_composer_para *ge2d_comp_para)
{
const char *keep_owner = "ge2d_composer";
if (ge2d_comp_para->canvas_scr[0] < 0)
ge2d_comp_para->canvas_scr[0] =
canvas_pool_map_alloc_canvas(keep_owner);
if (ge2d_comp_para->canvas_scr[1] < 0)
ge2d_comp_para->canvas_scr[1] =
canvas_pool_map_alloc_canvas(keep_owner);
if (ge2d_comp_para->canvas_scr[2] < 0)
ge2d_comp_para->canvas_scr[2] =
canvas_pool_map_alloc_canvas(keep_owner);
if (ge2d_comp_para->canvas_scr[0] < 0 ||
ge2d_comp_para->canvas_scr[1] < 0 ||
ge2d_comp_para->canvas_scr[2] < 0) {
VIDEOCOM_INFO("%s failed\n", __func__);
return -1;
}
return 0;
}
static int free_src_canvas(struct ge2d_composer_para *ge2d_comp_para)
{
if (ge2d_comp_para->canvas_scr[0] >= 0) {
canvas_pool_map_free_canvas(ge2d_comp_para->canvas_scr[0]);
ge2d_comp_para->canvas_scr[0] = -1;
}
if (ge2d_comp_para->canvas_scr[1] >= 0) {
canvas_pool_map_free_canvas(ge2d_comp_para->canvas_scr[1]);
ge2d_comp_para->canvas_scr[1] = -1;
}
if (ge2d_comp_para->canvas_scr[2] >= 0) {
canvas_pool_map_free_canvas(ge2d_comp_para->canvas_scr[2]);
ge2d_comp_para->canvas_scr[2] = -1;
}
if (ge2d_comp_para->canvas_scr[0] >= 0 ||
ge2d_comp_para->canvas_scr[1] >= 0 ||
ge2d_comp_para->canvas_scr[2] >= 0) {
VIDEOCOM_INFO("%s failed!\n", __func__);
return -1;
}
return 0;
}
int v2d_init_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para)
{
const char *keep_owner = "ge2d_dest_comp";
ge2d_comp_para->context = create_ge2d_work_queue();
if (IS_ERR_OR_NULL(ge2d_comp_para->context)) {
VIDEOCOM_INFO("creat ge2d work failed\n");
return -1;
}
if (ge2d_comp_para->plane_num > 0) {
if (ge2d_comp_para->canvas_dst[0] < 0)
ge2d_comp_para->canvas_dst[0] =
canvas_pool_map_alloc_canvas(keep_owner);
if (ge2d_comp_para->canvas_dst[0] < 0) {
VIDEOCOM_ERR("ge2d init dst canvas_0 failed!\n");
return -1;
}
}
if (ge2d_comp_para->plane_num > 1) {
if (ge2d_comp_para->canvas_dst[1] < 0)
ge2d_comp_para->canvas_dst[1] =
canvas_pool_map_alloc_canvas(keep_owner);
if (ge2d_comp_para->canvas_dst[1] < 0) {
VIDEOCOM_ERR("ge2d init dst canvas_1 failed!\n");
return -1;
}
}
if (ge2d_comp_para->plane_num > 2) {
if (ge2d_comp_para->canvas_dst[2] < 0)
ge2d_comp_para->canvas_dst[2] =
canvas_pool_map_alloc_canvas(keep_owner);
if (ge2d_comp_para->canvas_dst[2] < 0) {
VIDEOCOM_ERR("ge2d init dst canvas_2 failed!\n");
return -1;
}
}
return 0;
}
int v2d_uninit_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para)
{
destroy_ge2d_work_queue(ge2d_comp_para->context);
ge2d_comp_para->context = NULL;
if (free_src_canvas(ge2d_comp_para) < 0) {
VIDEOCOM_ERR("free src canvas failed!\n");
return -1;
}
if (ge2d_comp_para->canvas_dst[0] >= 0) {
canvas_pool_map_free_canvas(ge2d_comp_para->canvas_dst[0]);
ge2d_comp_para->canvas_dst[0] = -1;
}
if (ge2d_comp_para->canvas_dst[1] >= 0) {
canvas_pool_map_free_canvas(ge2d_comp_para->canvas_dst[1]);
ge2d_comp_para->canvas_dst[1] = -1;
}
if (ge2d_comp_para->canvas_dst[2] >= 0) {
canvas_pool_map_free_canvas(ge2d_comp_para->canvas_dst[2]);
ge2d_comp_para->canvas_dst[2] = -1;
}
if (ge2d_comp_para->canvas_dst[0] >= 0 ||
ge2d_comp_para->canvas_dst[1] >= 0 ||
ge2d_comp_para->canvas_dst[2] >= 0) {
VIDEOCOM_ERR("free dst canvas failed!\n");
return -1;
}
return 0;
}
#ifdef CONFIG_AMLOGIC_ENABLE_VIDEO_PIPELINE_DUMP_DATA
static int copy_phybuf_to_file(struct canvas_config_s *config,
struct file *fp, loff_t pos)
{
u32 span = SZ_1M;
u8 *p;
int remain_size = 0;
ssize_t ret;
ulong phys;
if (IS_ERR_OR_NULL(config))
return -1;
phys = config->phy_addr;
remain_size = config->width * config->height;
while (remain_size > 0) {
if (remain_size < span)
span = remain_size;
p = codec_mm_vmap(phys, PAGE_ALIGN(span));
if (!p) {
VIDEOCOM_ERR("vmap failed\n");
return -1;
}
codec_mm_dma_flush(p, span, DMA_FROM_DEVICE);
ret = kernel_write(fp, (char *)p, span, &pos);
if (ret <= 0)
VIDEOCOM_ERR("vfs write failed!\n");
phys += span;
codec_mm_unmap_phyaddr(p);
remain_size -= span;
VIDEOCOM_INFO("pos: %lld, phys: %lx, remain_size: %d\n",
pos, phys, remain_size);
}
return 0;
}
#endif
static bool dump_data(struct dump_param *para, enum buffer_data type)
{
#ifdef CONFIG_AMLOGIC_ENABLE_VIDEO_PIPELINE_DUMP_DATA
bool ret = false;
struct file *filp_dst = NULL;
char dst_path[64] = {'\0'};
struct canvas_config_s *dump_config;
int result = 0;
int offset = 0;
offset = 0;
if (type == BLACK_BUFFER)
sprintf(dst_path, "/data/temp/black_%d", dump_black_count++);
else if (type == SCR_BUFFER)
sprintf(dst_path, "/data/temp/scr_%d", dump_src_count++);
else if (type == DST_EMPTY_BUFFER)
sprintf(dst_path,
"/data/temp/before_dst_%d",
dump_before_dst_count++);
else if (type == DST_BUFFER_DATA)
sprintf(dst_path, "/data/temp/dst_%d", dump_dst_count++);
filp_dst = filp_open(dst_path, O_RDWR | O_CREAT, 0666);
if (IS_ERR(filp_dst)) {
VIDEOCOM_ERR("open %s failed\n", dst_path);
ret = false;
} else {
dump_config = &para->canvas0_config[0];
result = copy_phybuf_to_file(dump_config, filp_dst, 0);
if (result < 0) {
VIDEOCOM_ERR("write %s failed\n", dst_path);
ret = false;
goto end;
}
if (para->plane_num >= 2) {
offset = dump_config->width *
dump_config->height;
dump_config = &para->canvas0_config[1];
result =
copy_phybuf_to_file(dump_config,
filp_dst, offset);
if (result < 0) {
VIDEOCOM_ERR("#1 write %s failed\n",
dst_path);
ret = false;
goto end;
}
}
if (para->plane_num >= 3) {
offset += dump_config->width *
dump_config->height;
dump_config = &para->canvas0_config[2];
result =
copy_phybuf_to_file(dump_config,
filp_dst, offset);
if (result < 0) {
VIDEOCOM_ERR("#2 write %s failed\n",
dst_path);
ret = false;
goto end;
}
}
filp_close(filp_dst, NULL);
ret = true;
}
end:
return ret;
#else
return false;
#endif
}
int v2d_fill_vframe_black(struct ge2d_composer_para *ge2d_comp_para)
{
struct canvas_config_s dst_canvas0_config[3];
struct config_para_ex_s ge2d_config;
u32 dst_plane_num;
struct dump_param para;
bool ret = false;
int temp = 0;
int canvas_index = 0;
memset(dst_canvas0_config, 0, sizeof(dst_canvas0_config));
memset(&ge2d_config, 0, sizeof(struct config_para_ex_s));
if (ge2d_comp_para->format == GE2D_FORMAT_S24_YUV444) {
dst_canvas0_config[0].phy_addr = ge2d_comp_para->phy_addr[0];
dst_canvas0_config[0].width = ge2d_comp_para->buffer_w * 3;
dst_canvas0_config[0].height = ge2d_comp_para->buffer_h;
dst_canvas0_config[0].block_mode = 0;
dst_canvas0_config[0].endian = 0;
} else if (ge2d_comp_para->format == GE2D_FORMAT_M24_NV21) {
dst_canvas0_config[0].phy_addr = ge2d_comp_para->phy_addr[0];
dst_canvas0_config[0].width = ge2d_comp_para->buffer_w;
dst_canvas0_config[0].height = ge2d_comp_para->buffer_h;
dst_canvas0_config[0].block_mode = 0;
dst_canvas0_config[0].endian = 0;
dst_canvas0_config[1].phy_addr = ge2d_comp_para->phy_addr[0]
+ ge2d_comp_para->buffer_w * ge2d_comp_para->buffer_h;
dst_canvas0_config[1].width = ge2d_comp_para->buffer_w;
dst_canvas0_config[1].height = ge2d_comp_para->buffer_h >> 1;
dst_canvas0_config[1].block_mode = 0;
dst_canvas0_config[1].endian = 0;
}
dst_plane_num = ge2d_comp_para->plane_num;
if (ge2d_comp_para->canvas0_addr == (u32)-1) {
canvas_config_config(ge2d_comp_para->canvas_dst[0],
&dst_canvas0_config[0]);
if (dst_plane_num == 2) {
canvas_config_config(ge2d_comp_para->canvas_dst[1],
&dst_canvas0_config[1]);
} else if (dst_plane_num == 3) {
canvas_config_config(ge2d_comp_para->canvas_dst[2],
&dst_canvas0_config[2]);
}
canvas_index = ge2d_comp_para->canvas_dst[0]
| (ge2d_comp_para->canvas_dst[1] << 8)
| (ge2d_comp_para->canvas_dst[2] << 16);
} else {
canvas_index = ge2d_comp_para->canvas0_addr;
}
ge2d_config.src_para.canvas_index = canvas_index;
ge2d_config.alu_const_color = 0;/*0x000000ff;*/
ge2d_config.bitmask_en = 0;
ge2d_config.src1_gb_alpha = 0;/*0xff;*/
ge2d_config.dst_xy_swap = 0;
ge2d_config.src_key.key_enable = 0;
ge2d_config.src_key.key_mask = 0;
ge2d_config.src_key.key_mode = 0;
ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config.src_para.format = ge2d_comp_para->format;
ge2d_config.src_para.fill_color_en = 0;
ge2d_config.src_para.fill_mode = 0;
ge2d_config.src_para.x_rev = 0;
ge2d_config.src_para.y_rev = 0;
ge2d_config.src_para.color = 0;
ge2d_config.src_para.top = 0;
ge2d_config.src_para.left = 0;
ge2d_config.src_para.width = ge2d_comp_para->buffer_w;
ge2d_config.src_para.height = ge2d_comp_para->buffer_h;
ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config.dst_para.canvas_index = canvas_index;
ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config.dst_para.fill_color_en = 0;
ge2d_config.dst_para.fill_mode = 0;
ge2d_config.dst_para.x_rev = 0;
ge2d_config.dst_para.y_rev = 0;
ge2d_config.dst_para.color = 0;
ge2d_config.dst_para.top = 0;
ge2d_config.dst_para.left = 0;
ge2d_config.dst_para.format = ge2d_comp_para->format;
if (ge2d_comp_para->format == GE2D_FORMAT_M24_NV21)
ge2d_config.dst_para.format |= GE2D_LITTLE_ENDIAN;
ge2d_config.dst_para.width = ge2d_comp_para->buffer_w;
ge2d_config.dst_para.height = ge2d_comp_para->buffer_h;
ge2d_config.mem_sec = ge2d_comp_para->is_tvp;
temp = ge2d_context_config_ex(ge2d_comp_para->context, &ge2d_config);
if (temp < 0) {
VIDEOCOM_ERR("++ge2d configing error.\n");
return -1;
}
fillrect(ge2d_comp_para->context, 0, 0,
ge2d_comp_para->buffer_w,
ge2d_comp_para->buffer_h,
0x008080ff);
if (ge2d_com_debug & 2) {
para.canvas0_config[0] = dst_canvas0_config[0];
para.canvas0_config[1] = dst_canvas0_config[1];
para.canvas0_config[2] = dst_canvas0_config[2];
para.plane_num = dst_plane_num;
ret = dump_data(&para, BLACK_BUFFER);
if (ret)
VIDEOCOM_INFO("dump black buffer successful.\n");
}
return 0;
}
int v2d_config_ge2d_data(struct vframe_s *src_vf, unsigned long addr, int buf_w, int buf_h,
int data_w, int data_h, int crop_x, int crop_y, int crop_w, int crop_h,
struct ge2d_src_para_s *data)
{
struct vframe_s *vf = NULL;
int vf_height;
if (IS_ERR_OR_NULL(data)) {
pr_info("%s: invalid param.\n", __func__);
return -1;
}
if (src_vf) {
if (src_vf->canvas0_config[0].phy_addr == 0) {
if ((src_vf->flag & VFRAME_FLAG_DOUBLE_FRAM) && src_vf->vf_ext) {
vf = src_vf->vf_ext;
} else {
VIDEOCOM_ERR("%s: vf no yuv data, composer fail\n", __func__);
return -1;
}
} else {
vf = src_vf;
}
if (vf && vf->di_flag && IS_DI_PSTLINK(vf->di_flag))
vf_height = vf->height >> 1;
else
vf_height = vf->height;
data->canvas0Addr = vf->canvas0Addr;
data->canvas1Addr = vf->canvas1Addr;
data->canvas0_config[0] = vf->canvas0_config[0];
data->canvas0_config[1] = vf->canvas0_config[1];
data->canvas0_config[2] = vf->canvas0_config[2];
data->canvas1_config[0] = vf->canvas1_config[0];
data->canvas1_config[1] = vf->canvas1_config[1];
data->canvas1_config[2] = vf->canvas1_config[2];
data->bitdepth = vf->bitdepth;
data->source_type = vf->source_type;
data->type = vf->type;
data->plane_num = vf->plane_num;
if (vf->type & VIDTYPE_COMPRESS) {
if ((crop_w > WIDTH_8K || crop_w < 0) ||
(crop_h > HEIGHT_8K || crop_h < 0)) {
data->width = vf->width;
data->height = vf_height;
} else {
if (crop_w > vf->compWidth)
crop_w = vf->compWidth;
if (crop_h > vf->compHeight)
crop_h = vf->compHeight;
data->position_x = crop_x * vf->width / vf->compWidth;
data->position_y = crop_y * vf->width / vf->compWidth;
data->width =
crop_w * vf->width / vf->compWidth;
data->height =
crop_h * vf->width / vf->compWidth * vf_height / vf->height;
}
} else {
if ((crop_w > WIDTH_8K || crop_w < 0) ||
(crop_h > HEIGHT_8K || crop_h < 0)) {
data->width = vf->width;
data->height = vf_height;
} else {
data->position_x = crop_x;
data->position_y = crop_y;
data->width = crop_w;
data->height = crop_h;
if (vf && vf->di_flag && IS_DI_PSTLINK(vf->di_flag)) {
data->position_y >>= 1;
data->height >>= 1;
}
}
}
if (ge2d_com_debug & 1) {
VIDEOCOM_INFO("scr:vf->canvas0_config[0]: paddr=%lu width=%d height=%d\n",
vf->canvas0_config[0].phy_addr,
vf->canvas0_config[0].width,
vf->canvas0_config[0].height);
VIDEOCOM_INFO("scr:vf->canvas0_config[1]: paddr=%lu width=%d height=%d\n",
vf->canvas0_config[1].phy_addr,
vf->canvas0_config[1].width,
vf->canvas0_config[1].height);
VIDEOCOM_INFO("scr:vf->width=%d vf->height=%d vf->ComW=%d vf->ComH=%d\n",
vf->width,
vf->height,
vf->compWidth,
vf->compHeight);
VIDEOCOM_INFO("scr:crop %d %d %d %d\n", crop_x, crop_y, crop_w, crop_h);
VIDEOCOM_INFO("scr:data %d %d %d %d\n",
data->position_x, data->position_y, data->width, data->height);
}
if (vf->flag & VFRAME_FLAG_VIDEO_LINEAR)
data->is_vframe = false;
else
data->is_vframe = true;
} else {
data->canvas0Addr = -1;
data->canvas1Addr = -1;
data->canvas0_config[0].phy_addr = addr;
VIDEOCOM_INFO("buffer_w(%d), data_w(%d)\n", buf_w, data_w);
if (buf_w > data_w) {
if (data->is_yuv444)
data->canvas0_config[0].width = buf_w * 3;
else
data->canvas0_config[0].width = buf_w;
} else {
if (data->is_yuv444)
data->canvas0_config[0].width = data_w * 3;
else
data->canvas0_config[0].width = data_w;
}
VIDEOCOM_INFO("buffer_h(%d), data_h(%d)\n", buf_h, data_h);
if (buf_h > data_h)
data->canvas0_config[0].height = buf_h;
else
data->canvas0_config[0].height = data_h;
data->canvas0_config[0].block_mode = CANVAS_BLKMODE_LINEAR;
data->canvas0_config[0].endian = 0;
data->canvas0_config[1].phy_addr =
(u32)(addr + (data->canvas0_config[0].width)
* (data->canvas0_config[0].height));
data->canvas0_config[1].width =
data->canvas0_config[0].width;
data->canvas0_config[1].height =
data->canvas0_config[0].height / 2;
data->canvas0_config[1].block_mode =
CANVAS_BLKMODE_LINEAR;
data->canvas0_config[1].endian = 0;
data->bitdepth = BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8;
data->source_type = 0;
if (data->is_yuv444) {
data->type = VIDTYPE_VIU_SINGLE_PLANE
| VIDTYPE_VIU_FIELD
| VIDTYPE_VIU_444;
data->plane_num = 1;
} else {
data->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | VIDTYPE_VIU_NV21;
data->plane_num = 2;
}
VIDEOCOM_INFO("crop %d %d %d %d\n", crop_x, crop_y, crop_w, crop_h);
data->position_x = crop_x;
data->position_y = crop_y;
data->is_vframe = false;
if (crop_w <= 0 || crop_h <= 0) {
data->width = buf_w;
data->height = buf_h;
} else {
data->width = crop_w;
data->height = crop_h;
}
}
return 0;
}
int v2d_ge2d_data_composer(struct ge2d_src_para_s *scr_data,
struct ge2d_composer_para *ge2d_comp_para)
{
int ret;
struct canvas_config_s dst_canvas0_config[3];
struct config_para_ex_s ge2d_config;
u32 dst_plane_num;
int src_canvas_id, dst_canvas_id;
int input_x, input_y, input_width, input_height;
int position_left, position_top;
int position_width, position_height;
struct dump_param para;
enum ge2d_angle_type ge2d_angle;
bool result = false;
memset(&ge2d_config, 0, sizeof(struct config_para_ex_s));
memset(dst_canvas0_config, 0, sizeof(dst_canvas0_config));
if (ge2d_comp_para->format == GE2D_FORMAT_S24_YUV444) {
dst_canvas0_config[0].phy_addr = ge2d_comp_para->phy_addr[0];
dst_canvas0_config[0].width = ge2d_comp_para->buffer_w * 3;
dst_canvas0_config[0].height = ge2d_comp_para->buffer_h;
dst_canvas0_config[0].block_mode = 0;
dst_canvas0_config[0].endian = 0;
} else if (ge2d_comp_para->format == GE2D_FORMAT_M24_NV21) {
dst_canvas0_config[0].phy_addr = ge2d_comp_para->phy_addr[0];
dst_canvas0_config[0].width = ge2d_comp_para->buffer_w;
dst_canvas0_config[0].height = ge2d_comp_para->buffer_h;
dst_canvas0_config[0].block_mode = 0;
dst_canvas0_config[0].endian = 0;
dst_canvas0_config[1].phy_addr = ge2d_comp_para->phy_addr[0]
+ ge2d_comp_para->buffer_w * ge2d_comp_para->buffer_h;
dst_canvas0_config[1].width = ge2d_comp_para->buffer_w;
dst_canvas0_config[1].height = ge2d_comp_para->buffer_h >> 1;
dst_canvas0_config[1].block_mode = 0;
dst_canvas0_config[1].endian = 0;
}
dst_plane_num = ge2d_comp_para->plane_num;
if (scr_data->canvas0Addr == (u32)-1) {
ret = alloc_src_canvas(ge2d_comp_para);
if (ret < 0) {
VIDEOCOM_ERR("alloc src canvas failed!\n");
return -1;
}
canvas_config_config(ge2d_comp_para->canvas_scr[0],
&scr_data->canvas0_config[0]);
if (scr_data->plane_num == 2) {
canvas_config_config(ge2d_comp_para->canvas_scr[1],
&scr_data->canvas0_config[1]);
} else if (scr_data->plane_num == 3) {
canvas_config_config(ge2d_comp_para->canvas_scr[2],
&scr_data->canvas0_config[2]);
}
src_canvas_id = ge2d_comp_para->canvas_scr[0]
| (ge2d_comp_para->canvas_scr[1] << 8)
| (ge2d_comp_para->canvas_scr[2] << 16);
} else {
src_canvas_id = scr_data->canvas0Addr;
}
if (ge2d_comp_para->canvas0_addr == (u32)-1) {
canvas_config_config(ge2d_comp_para->canvas_dst[0],
&dst_canvas0_config[0]);
if (dst_plane_num == 2) {
canvas_config_config(ge2d_comp_para->canvas_dst[1],
&dst_canvas0_config[1]);
} else if (dst_plane_num == 3) {
canvas_config_config(ge2d_comp_para->canvas_dst[2],
&dst_canvas0_config[2]);
}
dst_canvas_id = ge2d_comp_para->canvas_dst[0]
| (ge2d_comp_para->canvas_dst[1] << 8)
| (ge2d_comp_para->canvas_dst[2] << 16);
} else {
dst_canvas_id = ge2d_comp_para->canvas0_addr;
}
input_width = scr_data->width;
input_height = scr_data->height;
input_x = scr_data->position_x;
input_y = scr_data->position_y;
if (scr_data->type & VIDTYPE_INTERLACE)
input_height = scr_data->height >> 1;
else
input_height = scr_data->height;
ge2d_config.alu_const_color = 0;
ge2d_config.bitmask_en = 0;
ge2d_config.src1_gb_alpha = 0;
ge2d_config.dst_xy_swap = 0;
ge2d_config.src_key.key_enable = 0;
ge2d_config.src_key.key_mask = 0;
ge2d_config.src_key.key_mode = 0;
ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config.src_para.format = get_input_format(scr_data);
if (!scr_data->is_vframe)
ge2d_config.src_para.format |= GE2D_LITTLE_ENDIAN;
ge2d_config.src_para.fill_color_en = 0;
ge2d_config.src_para.fill_mode = 0;
ge2d_config.src_para.x_rev = 0;
ge2d_config.src_para.y_rev = 0;
ge2d_config.src_para.color = 0xffffffff;
ge2d_config.src_para.top = input_y;
ge2d_config.src_para.left = input_x;
ge2d_config.src_para.width = input_width;
ge2d_config.src_para.height = input_height;
ge2d_config.src_para.canvas_index = src_canvas_id;
ge2d_config.src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config.dst_para.fill_color_en = 0;
ge2d_config.dst_para.fill_mode = 0;
ge2d_config.dst_para.x_rev = 0;
ge2d_config.dst_para.y_rev = 0;
ge2d_config.dst_xy_swap = 0;
ge2d_angle = config_ge2d_rotation(ge2d_comp_para->angle);
if (ge2d_angle == GE2D_ANGLE_TYPE_ROT_90) {
ge2d_config.dst_xy_swap = 1;
ge2d_config.dst_para.x_rev = 1;
} else if (ge2d_angle == GE2D_ANGLE_TYPE_ROT_180) {
ge2d_config.dst_para.x_rev = 1;
ge2d_config.dst_para.y_rev = 1;
} else if (ge2d_angle == GE2D_ANGLE_TYPE_ROT_270) {
ge2d_config.dst_xy_swap = 1;
ge2d_config.dst_para.y_rev = 1;
} else if (ge2d_angle == GE2D_ANGLE_TYPE_FLIP_H) {
ge2d_config.dst_xy_swap = 0;
ge2d_config.dst_para.x_rev = 1;
ge2d_config.dst_para.y_rev = 0;
} else if (ge2d_angle == GE2D_ANGLE_TYPE_FLIP_V) {
ge2d_config.dst_xy_swap = 0;
ge2d_config.dst_para.x_rev = 0;
ge2d_config.dst_para.y_rev = 1;
}
ge2d_config.dst_para.canvas_index = dst_canvas_id;
ge2d_config.dst_para.color = 0;
ge2d_config.dst_para.top = 0;
ge2d_config.dst_para.left = 0;
ge2d_config.dst_para.format = ge2d_comp_para->format;
if (ge2d_comp_para->format == GE2D_FORMAT_M24_NV21)
ge2d_config.dst_para.format |= GE2D_LITTLE_ENDIAN;
ge2d_config.dst_para.width = ge2d_comp_para->buffer_w;
ge2d_config.dst_para.height = ge2d_comp_para->buffer_h;
ge2d_config.mem_sec = ge2d_comp_para->is_tvp;
ret = ge2d_context_config_ex(ge2d_comp_para->context, &ge2d_config);
if (ret < 0) {
VIDEOCOM_ERR("++ge2d configing error.\n");
return -1;
}
if (ge2d_com_debug & 4) {
para.canvas0_config[0] = scr_data->canvas0_config[0];
para.canvas0_config[1] = scr_data->canvas0_config[1];
para.canvas0_config[2] = scr_data->canvas0_config[2];
VIDEOCOM_INFO("canvas0:%d %d canvas1:%d %d canvas2:%d %d.\n",
scr_data->canvas0_config[0].width, scr_data->canvas0_config[0].height,
scr_data->canvas0_config[1].width, scr_data->canvas0_config[1].height,
scr_data->canvas0_config[2].width, scr_data->canvas0_config[2].height);
para.plane_num = scr_data->plane_num;
result = dump_data(&para, SCR_BUFFER);
if (result)
VIDEOCOM_INFO("dump scr buffer successful.\n");
}
if (ge2d_com_debug & 8) {
para.canvas0_config[0] = dst_canvas0_config[0];
para.canvas0_config[1] = dst_canvas0_config[1];
para.canvas0_config[2] = dst_canvas0_config[2];
para.plane_num = dst_plane_num;
result = dump_data(&para, DST_EMPTY_BUFFER);
if (result)
VIDEOCOM_INFO("dump dst empty buffer successful.\n");
}
position_left = ge2d_comp_para->position_left;
position_top = ge2d_comp_para->position_top;
position_width = ge2d_comp_para->position_width;
position_height = ge2d_comp_para->position_height;
stretchblt_noalpha(ge2d_comp_para->context,
input_x,
input_y,
input_width,
input_height,
position_left,
position_top,
position_width,
position_height);
if (ge2d_com_debug & 1)
VIDEOCOM_INFO("scr %0x,dst: %0x!,%d, %d, %d, %d\n",
ge2d_config.src_para.format,
ge2d_config.dst_para.format,
position_left,
position_top,
position_width,
position_height);
if (ge2d_com_debug & 16) {
para.canvas0_config[0] = dst_canvas0_config[0];
para.canvas0_config[1] = dst_canvas0_config[1];
para.canvas0_config[2] = dst_canvas0_config[2];
para.plane_num = dst_plane_num;
result = dump_data(&para, DST_BUFFER_DATA);
if (result)
VIDEOCOM_INFO("dump dst data successful.\n");
}
return 0;
}
@@ -0,0 +1,106 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#ifndef VFRAME_GE2D_COMPOSER_H
#define VFRAME_GE2D_COMPOSER_H
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/vfm/vframe.h>
//#include "video_composer.h"
#define VIDEOCOM_INFO(fmt, args...) \
pr_info("video_composer: info:" fmt "", ## args)
#define VIDEOCOM_DBG(fmt, args...) \
pr_debug("video_composer: dbg:" fmt "", ## args)
#define VIDEOCOM_WARN(fmt, args...) \
pr_warn("video_composer: warn:" fmt "", ## args)
#define VIDEOCOM_ERR(fmt, args...) \
pr_err("video_composer: err:" fmt "", ## args)
enum ge2d_angle_type {
GE2D_ANGLE_TYPE_ROT_90 = 1,
GE2D_ANGLE_TYPE_ROT_180,
GE2D_ANGLE_TYPE_ROT_270,
GE2D_ANGLE_TYPE_FLIP_H,
GE2D_ANGLE_TYPE_FLIP_V,
GE2D_ANGLE_TYPE_MAX,
};
enum videocom_source_type {
DECODER_8BIT_NORMAL = 0,
DECODER_8BIT_BOTTOM,
DECODER_8BIT_TOP,
DECODER_10BIT_NORMAL,
DECODER_10BIT_BOTTOM,
DECODER_10BIT_TOP,
VDIN_8BIT_NORMAL,
VDIN_10BIT_NORMAL,
};
struct ge2d_composer_para {
int count;
int format;
int position_left;
int position_top;
int position_width;
int position_height;
int buffer_w;
int buffer_h;
int plane_num;
int canvas_scr[3];
int canvas_dst[3];
ulong phy_addr[3];
u32 canvas0_addr;
struct ge2d_context_s *context;
int angle;
bool is_tvp;
};
struct ge2d_src_para_s {
u32 canvas0Addr;
u32 canvas1Addr;
u32 plane_num;
u32 type;
u32 position_x;
u32 position_y;
u32 width;
u32 height;
u32 bitdepth;
struct canvas_config_s canvas0_config[3];
struct canvas_config_s canvas1_config[3];
enum vframe_source_type_e source_type;
bool is_vframe;
bool is_yuv444;
};
struct dump_param {
u32 plane_num;
struct canvas_config_s canvas0_config[3];
};
enum buffer_data {
BLACK_BUFFER = 0,
SCR_BUFFER,
DST_EMPTY_BUFFER,
DST_BUFFER_DATA,
OTHER_BUFFER,
};
extern int ge2d_com_debug;
int v2d_init_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para);
int v2d_uninit_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para);
int v2d_fill_vframe_black(struct ge2d_composer_para *ge2d_comp_para);
int v2d_config_ge2d_data(struct vframe_s *src_vf, unsigned long addr, int buf_w, int buf_h,
int data_w, int data_h, int crop_x, int crop_y, int crop_w, int crop_h,
struct ge2d_src_para_s *data);
int v2d_ge2d_data_composer(struct ge2d_src_para_s *src_para,
struct ge2d_composer_para *ge2d_comp_para);
#endif
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/utils/amlog.h>
#include <linux/amlogic/media/vicp/vicp.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/delay.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "v2d_vicp_composer.h"
bool check_vicp_status(void)
{
int cpu_type = 0;
cpu_type = get_cpu_type();
if (cpu_type == MESON_CPU_MAJOR_ID_S5 ||
cpu_type == MESON_CPU_MAJOR_ID_T3X ||
cpu_type == MESON_CPU_MAJOR_ID_S6)
return true;
else
return false;
}
enum vicp_rotation_mode_e map_rotationmode_from_v2d_to_vicp(int v2d_rotation)
{
enum vicp_rotation_mode_e rotation = VICP_ROTATION_MAX;
if (v2d_rotation == 1)
rotation = VICP_ROTATION_MIRROR_H;
else if (v2d_rotation == 2)
rotation = VICP_ROTATION_MIRROR_V;
else if (v2d_rotation == 3)
rotation = VICP_ROTATION_180;
else if (v2d_rotation == 4)
rotation = VICP_ROTATION_90;
else if (v2d_rotation == 7)
rotation = VICP_ROTATION_270;
else
rotation = VICP_ROTATION_0;
return rotation;
}
int v2d_config_vicp_input_data(struct vframe_s *vf, ulong addr, int width, int height,
int stride_w, int stride_y, int endian, int color_fmt, int color_depth,
struct input_data_param_s *input_data)
{
if (IS_ERR_OR_NULL(input_data)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
memset(input_data, 0, sizeof(struct input_data_param_s));
if (vf) {
input_data->is_vframe = true;
input_data->data_vf = vf;
} else {
input_data->is_vframe = false;
if (stride_w > width)
input_data->data_dma.buf_stride_w = stride_w;
else
input_data->data_dma.buf_stride_w = width;
if (stride_y > height)
input_data->data_dma.buf_stride_h = stride_y;
else
input_data->data_dma.buf_stride_h = height;
input_data->data_dma.buf_addr = addr;
input_data->data_dma.data_width = width;
input_data->data_dma.data_height = height;
input_data->data_dma.color_format = color_fmt;
input_data->data_dma.color_depth = color_depth;
input_data->data_dma.plane_count = 2;
input_data->data_dma.endian = endian;
input_data->data_dma.need_swap_cbcr = 0;
}
return 0;
}
int v2d_config_vicp_output_data(int fbc_out_en, int mif_out_en, ulong *phy_addr, int stride,
int width, int height, int endian, enum vicp_color_format_e cfmt_mif, int cdep_mif,
enum vicp_color_format_e cfmt_fbc, int cdep_fbc, int init_ctrl, int pip_mode,
int out_sig_fmt, struct output_data_param_s *output_data)
{
if (IS_ERR_OR_NULL(output_data)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
memset(output_data, 0, sizeof(struct output_data_param_s));
output_data->width = width;
output_data->height = height;
output_data->phy_addr[0] = phy_addr[0];
output_data->stride[0] = stride;
output_data->mif_out_en = mif_out_en;
output_data->endian = endian;
output_data->need_swap_cbcr = 1;
output_data->out_sig_fmt = out_sig_fmt;
if (mif_out_en) {
output_data->mif_color_fmt = cfmt_mif;
output_data->mif_color_dep = cdep_mif;
}
output_data->fbc_out_en = fbc_out_en;
if (fbc_out_en) {
output_data->fbc_color_fmt = cfmt_fbc;
output_data->fbc_color_dep = cdep_fbc;
output_data->phy_addr[1] = phy_addr[1];
output_data->phy_addr[2] = phy_addr[2];
output_data->fbc_init_ctrl = init_ctrl;
output_data->fbc_pip_mode = pip_mode;
}
return 0;
}
int v2d_vicp_data_composer(struct vicp_data_config_s *data_config)
{
int ret = 0;
if (IS_ERR_OR_NULL(data_config)) {
pr_info("%s: NULL param, please check.\n", __func__);
return -1;
}
#ifdef CONFIG_AMLOGIC_MEDIA_VICP
ret = vicp_process(data_config);
#endif
if (ret < 0)
pr_info("%s: vicp_process failed.\n", __func__);
return ret;
}
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#ifndef V2D_VICP_COMPOSER_H
#define V2D_VICP_COMPOSER_H
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vicp/vicp.h>
bool check_vicp_status(void);
enum vicp_rotation_mode_e map_rotationmode_from_v2d_to_vicp(int v2d_rotation);
int v2d_config_vicp_input_data(struct vframe_s *vf, ulong addr, int width, int height,
int stride_w, int stride_y, int endian, int color_fmt, int color_depth,
struct input_data_param_s *input_data);
int v2d_config_vicp_output_data(int fbc_out_en, int mif_out_en, ulong *phy_addr, int stride,
int width, int height, int endian, enum vicp_color_format_e cfmt_mif, int cdep_mif,
enum vicp_color_format_e cfmt_fbc, int cdep_fbc, int init_ctrl, int pip_mode,
int out_sig_fmt, struct output_data_param_s *output_data);
int v2d_vicp_data_composer(struct vicp_data_config_s *data_config);
#ifdef CONFIG_AMLOGIC_MEDIA_VICP
int vicp_process(struct vicp_data_config_s *data_config);
#endif
#endif
+1
View File
@@ -50,4 +50,5 @@
#define DI_PROCESS_MAJOR (32 + (AML_BASE))
#define AML_DHP_MAJOR (33 + (AML_BASE))
#define VIDEODISPLAY_MAJOR (34 + (AML_BASE))
#define V2D_MAJOR (35 + (AML_BASE))
#endif