blob: 10c9a90e9db893ed92eaeedeb05304da04c9b176 [file] [log] [blame]
/*
* drivers/amlogic/media/video_processor/video_dev/amlvideo2.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.
*
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/random.h>
#include <linux/version.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
#include <linux/freezer.h>
#include <linux/platform_device.h>
#include <media/videobuf-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <linux/types.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
#include "common/vfp-queue.h"
#include <linux/amlogic/media/ge2d/ge2d.h>
#include <linux/amlogic/media/frame_sync/timestamp.h>
#include <linux/kernel.h>
#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
#include <linux/amlogic/media/vout/vinfo.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/v4l_util/videobuf-res.h>
#include <linux/of_reserved_mem.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include <linux/dma-contiguous.h>
#include "amlvideo2.h"
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
/* #include <mach/mod_gate.h> */
/* #endif */
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/semaphore.h>
#include <linux/sched/rt.h>
#define AVMLVIDEO2_MODULE_NAME "amlvideo2"
#define AMLVIDEO2_RES_CANVAS 0xc0
#define AMLVIDEO2_1_RES_CANVAS 0xcc
#define MULTI_NODE
/* #define USE_SEMA_QBUF */
/* #define USE_VDIN_PTS */
#define MULTI_NODE
#ifdef MULTI_NODE
#define MAX_SUB_DEV_NODE 2
#else
#define MAX_SUB_DEV_NODE 1
#endif
/* Wake up at about 30 fps */
#define WAKE_NUMERATOR 30
#define WAKE_DENOMINATOR 1001
#define AMLVIDEO2_MAJOR_VERSION 0
#define AMLVIDEO2_MINOR_VERSION 7
#define AMLVIDEO2_RELEASE 1
#define AMLVIDEO2_VERSION \
KERNEL_VERSION(\
AMLVIDEO2_MAJOR_VERSION, AMLVIDEO2_MINOR_VERSION,\
AMLVIDEO2_RELEASE)
#define MAGIC_SG_MEM 0x17890714
#define MAGIC_DC_MEM 0x0733ac61
#define MAGIC_VMAL_MEM 0x18221223
#define MAGIC_RE_MEM 0x123039dc
#ifdef MULTI_NODE
#define DEVICE_NAME0 "amlvideo2.0"
#define DEVICE_NAME1 "amlvideo2.1"
#else
#define RECEIVER_NAME "amlvideo2.0"
#define DEVICE_NAME "amlvideo2.0"
#endif
#define AMLVIDEO2_RES0_CANVAS_INDEX AMLVIDEO2_RES_CANVAS
#define AMLVIDEO2_RES1_CANVAS_INDEX AMLVIDEO2_1_RES_CANVAS
#define DUR2PTS(x) ((x) - ((x) >> 4))
#define DUR2PTS_RM(x) ((x) & 0xf)
#define CMA_ALLOC_SIZE 24
#define CANVAS_WIDTH_ALIGN 32
MODULE_DESCRIPTION(
"pass a frame of amlogic video2 codec device to user in style of v4l2");
MODULE_AUTHOR("amlogic-sh");
MODULE_LICENSE("GPL");
static unsigned int video_nr = 11;
/* module_param(video_nr, uint, 0644); */
/* MODULE_PARM_DESC(video_nr, "videoX start number, 10 is defaut"); */
static unsigned int debug;
/* module_param(debug, uint, 0644); */
/* MODULE_PARM_DESC(debug, "activates debug info"); */
#define DEF_FRAMERATE 30
static unsigned int mirror_value;
static unsigned int vid_limit = 32;
module_param(vid_limit, uint, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
static unsigned int amlvideo2_dbg_en;
module_param(amlvideo2_dbg_en, uint, 0664);
MODULE_PARM_DESC(amlvideo2_dbg_en, "enable/disable amlvideo2 debug information");
static unsigned int amlvideo2_scaledown1 = 2;
module_param(amlvideo2_scaledown1, uint, 0664);
MODULE_PARM_DESC(amlvideo2_scaledown1, "amlvideo2_scaledown1");
static unsigned int amlvideo2_scaledown2 = 2;
module_param(amlvideo2_scaledown2, uint, 0664);
MODULE_PARM_DESC(amlvideo2_scaledown2, "amlvideo2_scaledown2");
static struct v4l2_fract amlvideo2_frmintervals_active = {
.numerator = 1, .denominator = DEF_FRAMERATE, };
/* supported controls */
static struct v4l2_queryctrl amlvideo2_node_qctrl[] = {{
.id = V4L2_CID_ROTATE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Rotate",
.minimum = 0, .maximum = 270, .step = 90, .default_value = 0, .flags =
V4L2_CTRL_FLAG_SLIDER, } };
static struct v4l2_frmivalenum amlvideo2_frmivalenum[] = {{
.index = 0, .pixel_format = V4L2_PIX_FMT_NV21, .width = 1920, .height =
1080, .type = V4L2_FRMIVAL_TYPE_DISCRETE, {.discrete = {
.numerator = 1, .denominator = 30, } } }, {
.index = 1, .pixel_format = V4L2_PIX_FMT_NV21, .width = 1600, .height =
1200, .type = V4L2_FRMIVAL_TYPE_DISCRETE, {.discrete = {
.numerator = 1, .denominator = 5, } } }, };
#define dpr_err(dev, level, fmt, arg...) \
v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
/* ------------------------------------------------------------------
* Basic structures
* ------------------------------------------------------------------
*/
enum aml_provider_type_e {
AML_PROVIDE_NONE = 0,
AML_PROVIDE_VDIN0 = 1,
AML_PROVIDE_VDIN1 = 2,
AML_PROVIDE_DECODE = 3,
AML_PROVIDE_PPMGR = 4,
AML_PROVIDE_MAX = 5
};
enum aml_receiver_type_e {
AML_RECEIVER_NONE = 0,
AML_RECEIVER_PPMGR,
AML_RECEIVER_DI,
AML_RECEIVER_MAX
};
enum aml_screen_mode_e {
AML_SCREEN_MODE_RATIO = 0,
AML_SCREEN_MODE_FULL,
AML_SCREEN_MODE_ADAPTIVE,
AML_SCREEN_MODE_MAX
};
struct amlvideo2_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
int depth;
};
static struct amlvideo2_fmt formats[] = {
{.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.depth = 16, },
{.name = "RGB888 (24)",
.fourcc = V4L2_PIX_FMT_RGB24, /* 24 RGB-8-8-8 */
.depth = 24, },
{.name = "BGR888 (24)",
.fourcc = V4L2_PIX_FMT_BGR24, /* 24 BGR-8-8-8 */
.depth = 24, },
{.name = "RGBA888 (32)",
.fourcc = V4L2_PIX_FMT_RGB32, /* 32 RGBA-8-8-8 */
.depth = 32, },
{.name = "12 Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12, },
{.name = "12 Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV21,
.depth = 12, },
{.name = "YUV420P",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12, },
{.name = "YVU420P",
.fourcc = V4L2_PIX_FMT_YVU420,
.depth = 12, }
#if 0
{
.name = "RGBA8888 (32)",
.fourcc = V4L2_PIX_FMT_RGB32, /* 24 RGBA-8-8-8-8 */
.depth = 32,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.depth = 16,
},
{
.name = "BGR888 (24)",
.fourcc = V4L2_PIX_FMT_BGR24, /* 24 BGR-8-8-8 */
.depth = 24,
},
{
.name = "YUV420P",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12,
},
#endif
};
static struct amlvideo2_fmt *get_format(struct v4l2_format *f)
{
struct amlvideo2_fmt *fmt;
unsigned int k;
for (k = 0; k < ARRAY_SIZE(formats); k++) {
fmt = &formats[k];
if (fmt->fourcc == f->fmt.pix.pixelformat)
break;
}
if (k == ARRAY_SIZE(formats))
return NULL;
return &formats[k];
}
/* buffer for one video frame */
struct amlvideo2_frame_info {
int x;
int y;
int w;
int h;
};
struct amlvideo2_latency_info {
int total_latency;
int total_latency_out;
long long cur_time;
long long cur_time_out;
int frame_num;
int frame_num_out;
struct timeval test_time;
};
struct amlvideo2_node_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
struct amlvideo2_fmt *fmt;
int canvas_id;
struct amlvideo2_frame_info axis;
};
struct amlvideo2_node_dmaqueue {
struct list_head active;
/* thread for generating video stream*/
struct task_struct *kthread;
wait_queue_head_t wq;
unsigned char task_running;
#ifdef USE_SEMA_QBUF
struct completion qbuf_comp;
#endif
};
struct amlvideo2_device {
struct mutex mutex;
struct v4l2_device v4l2_dev;
struct platform_device *pdev;
struct amlvideo2_node *node[MAX_SUB_DEV_NODE];
int node_num;
resource_size_t buffer_start;
unsigned int buffer_size;
struct page *cma_pages;
struct resource memobj;
int cma_mode;
int node_id;
bool use_reserve;
};
struct crop_info_s {
int source_top_crop;
int source_left_crop;
int source_width_crop;
int source_height_crop;
int capture_crop_enable;
};
struct screen_display_info_s {
struct vdisplay_info_s display_info;
enum aml_screen_mode_e mode;
};
struct amlvideo2_fh;
struct amlvideo2_node {
spinlock_t slock;
struct mutex mutex;
int vid;
int users;
struct amlvideo2_device *vid_dev;
/* various device info */
struct video_device *vfd;
struct amlvideo2_node_dmaqueue vidq;
/* Control 'registers' */
int qctl_regs[ARRAY_SIZE(amlvideo2_node_qctrl)];
struct videobuf_res_privdata res;
struct vframe_receiver_s recv;
struct vframe_receiver_s *sub_recv;
struct vframe_provider_s *provider;
enum aml_provider_type_e p_type;
enum aml_receiver_type_e r_type;
int provide_ready;
struct amlvideo2_fh *fh;
unsigned int input; /* 0:mirrocast; 1:hdmiin */
enum tvin_port_e porttype;
unsigned int start_vdin_flag;
struct ge2d_context_s *context;
struct vdin_v4l2_ops_s vops;
int vdin_device_num;
struct vdisplay_info_s display_info;
struct crop_info_s crop_info;
enum aml_screen_mode_e mode;
bool has_amvideo_node;
struct vframe_provider_s amlvideo2_vf_prov;
int amlvideo2_pool_size;
struct vfq_s q_ready;
struct vframe_s *amlvideo2_pool_ready;
bool video_blocking;
struct timeval thread_ts1;
struct timeval thread_ts2;
int frameInv_adjust;
int frameInv;
struct vframe_s *tmp_vf;
int frame_inittime;
struct amlvideo2_latency_info latency_info;
bool pflag;
struct completion plug_sema;
bool field_flag;
bool field_condition_flag;
bool ge2d_multi_process_flag;
};
struct amlvideo2_fh {
struct amlvideo2_node *node;
/* video capture */
struct amlvideo2_fmt *fmt;
unsigned int width, height;
unsigned int src_width, src_height;
bool set_format_flag;
struct videobuf_queue vb_vidq;
bool vb_vidq_init;
unsigned int is_streamed_on;
suseconds_t frm_save_time_us; /* us */
unsigned int f_flags;
enum v4l2_buf_type type;
};
struct amlvideo2_output {
int canvas_id;
void *vbuf;
int width;
int height;
u32 v4l2_format;
int angle;
struct screen_display_info_s info;
struct amlvideo2_frame_info *frame;
};
static struct v4l2_frmsize_discrete amlvideo2_prev_resolution[] = {{160, 120}, {
320, 240}, {640, 480}, {1280, 720}, };
static struct v4l2_frmsize_discrete amlvideo2_pic_resolution[] = {{1280, 960} };
static unsigned int print_cvs_idx;
module_param(print_cvs_idx, uint, 0644);
MODULE_PARM_DESC(print_cvs_idx, "print canvas index\n");
int get_amlvideo2_canvas_index(struct amlvideo2_output *output,
int start_canvas)
{
int canvas = start_canvas;
int v4l2_format = output->v4l2_format;
void *buf = (void *)output->vbuf;
int width = output->width;
int height = output->height;
int canvas_height = height;
switch (v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_VYUY:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf, width * 2, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_YUV444:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB24:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf, width * 3, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_RGB32:
canvas = start_canvas;
canvas_config(canvas, (unsigned long)buf, width * 4, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
canvas_config(start_canvas, (unsigned long)buf, width, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas_config(start_canvas + 1, (unsigned long)(buf + width * height),
width, canvas_height / 2,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas = start_canvas | ((start_canvas + 1) << 8);
break;
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
canvas_config(start_canvas, (unsigned long)buf, width, canvas_height,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas_config(start_canvas + 1, (unsigned long)(buf + width * height),
width / 2, canvas_height / 2,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
canvas_config(start_canvas + 2,
(unsigned long)(buf + width * height * 5 / 4),
width / 2, canvas_height / 2,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
if (v4l2_format == V4L2_PIX_FMT_YUV420) {
canvas = start_canvas | ((start_canvas + 1) << 8)
| ((start_canvas + 2) << 16);
} else {
canvas = start_canvas | ((start_canvas + 2) << 8)
| ((start_canvas + 1) << 16);
}
break;
default:
break;
}
if (print_cvs_idx == 1) {
pr_err("v4l2_format=%x, canvas=%x\n", v4l2_format, canvas);
print_cvs_idx = 0;
}
return canvas;
}
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
int convert_canvas_index(struct amlvideo2_output *output, int start_canvas)
{
int canvas = start_canvas;
int v4l2_format = output->v4l2_format;
switch (v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_VYUY:
canvas = start_canvas;
break;
case V4L2_PIX_FMT_YUV444:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_RGB32:
canvas = start_canvas;
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
canvas = start_canvas | ((start_canvas + 1) << 8);
break;
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
if (v4l2_format == V4L2_PIX_FMT_YUV420) {
canvas = start_canvas | ((start_canvas + 1) << 8)
| ((start_canvas + 2) << 16);
} else {
canvas = start_canvas | ((start_canvas + 2) << 8)
| ((start_canvas + 1) << 16);
}
break;
default:
break;
}
return canvas;
}
/* #endif */
static unsigned int print_ifmt;
module_param(print_ifmt, uint, 0644);
MODULE_PARM_DESC(print_ifmt, "print input format\n");
static int get_input_format(struct vframe_s *vf)
{
int format = GE2D_FORMAT_M24_NV21;
if (vf->type & VIDTYPE_VIU_422) {
if (vf->type & VIDTYPE_INTERLACE_BOTTOM) {
format = GE2D_FORMAT_S16_YUV422
| (GE2D_FORMAT_S16_YUV422B & (3 << 3));
} else if (vf->type & VIDTYPE_INTERLACE_TOP) {
format = GE2D_FORMAT_S16_YUV422
| (GE2D_FORMAT_S16_YUV422T & (3 << 3));
} else {
format = GE2D_FORMAT_S16_YUV422;
}
} else if (vf->type & VIDTYPE_VIU_NV21) {
if (vf->type & VIDTYPE_INTERLACE_BOTTOM) {
format = GE2D_FORMAT_M24_NV21
| (GE2D_FORMAT_M24_NV21B & (3 << 3));
} else if (vf->type & VIDTYPE_INTERLACE_TOP) {
format = GE2D_FORMAT_M24_NV21
| (GE2D_FORMAT_M24_NV21T & (3 << 3));
} else {
format = GE2D_FORMAT_M24_NV21;
}
} else {
if (vf->type & VIDTYPE_INTERLACE_BOTTOM) {
format = GE2D_FORMAT_M24_YUV420
| (GE2D_FMT_M24_YUV420B & (3 << 3));
} else if (vf->type & VIDTYPE_INTERLACE_TOP) {
format = GE2D_FORMAT_M24_YUV420
| (GE2D_FORMAT_M24_YUV420T & (3 << 3));
} else {
format = GE2D_FORMAT_M24_YUV420;
}
}
if (print_ifmt == 1) {
pr_err(
"vf->type=%x, format=%x, w*h=%dx%d, canvas0=%x, canvas1=%x\n",
vf->type, format, vf->width, vf->height, vf->canvas0Addr,
vf->canvas1Addr);
pr_err(
"vf->type=%x, VIDTYPE_INTERLACE_BOTTOM=%x, VIDTYPE_INTERLACE_TOP=%x\n",
vf->type, VIDTYPE_INTERLACE_BOTTOM, VIDTYPE_INTERLACE_TOP);
print_ifmt = 0;
}
return format;
}
static int get_input_format_no_interlace(struct vframe_s *vf)
{
int format = GE2D_FORMAT_M24_NV21;
if (vf->type & VIDTYPE_VIU_422)
format = GE2D_FORMAT_S16_YUV422;
else if (vf->type & VIDTYPE_VIU_NV21)
format = GE2D_FORMAT_M24_NV21;
else
format = GE2D_FORMAT_M24_YUV420;
if (print_ifmt == 1) {
pr_err(
"vf->type=%x, format=%x, w*h=%dx%d, canvas0=%x, canvas1=%x\n",
vf->type, format, vf->width, vf->height, vf->canvas0Addr,
vf->canvas1Addr);
pr_err(
"vf->type=%x, VIDTYPE_INTERLACE_BOTTOM=%x, VIDTYPE_INTERLACE_TOP=%x\n",
vf->type, VIDTYPE_INTERLACE_BOTTOM, VIDTYPE_INTERLACE_TOP);
print_ifmt = 0;
}
return format;
}
static int get_interlace_input_format(struct vframe_s *vf,
struct amlvideo2_output *output)
{
int format = GE2D_FORMAT_M24_NV21;
if (vf->type & VIDTYPE_VIU_422) {
format = GE2D_FORMAT_S16_YUV422;
if (vf->height >= output->height << 2) {
format = GE2D_FORMAT_S16_YUV422
| (GE2D_FORMAT_S16_YUV422T & (3 << 3));
}
} else if (vf->type & VIDTYPE_VIU_NV21) {
format = GE2D_FORMAT_M24_NV21;
if (vf->height >= output->height << 2) {
format = GE2D_FORMAT_M24_NV21
| (GE2D_FORMAT_M24_NV21T & (3 << 3));
}
} else {
format = GE2D_FORMAT_M24_YUV420;
if (vf->height >= output->height << 2) {
format = GE2D_FORMAT_M24_YUV420
| (GE2D_FORMAT_M24_YUV420T & (3 << 3));
}
}
if (print_ifmt == 1) {
pr_err(
"vf->type=%x, format=%x, w*h=%dx%d, canvas0=%x, canvas1=%x\n",
vf->type, format, vf->width, vf->height, vf->canvas0Addr,
vf->canvas1Addr);
print_ifmt = 0;
}
return format;
}
static inline int get_top_input_format(struct vframe_s *vf)
{
int format = GE2D_FORMAT_M24_NV21;
if (vf->type & VIDTYPE_VIU_422)
format = GE2D_FORMAT_S16_YUV422 |
(GE2D_FORMAT_S16_YUV422T & (3 << 3));
else if (vf->type & VIDTYPE_VIU_NV21)
format = GE2D_FORMAT_M24_NV21 |
(GE2D_FORMAT_M24_NV21T & (3 << 3));
else
format = GE2D_FORMAT_M24_YUV420 |
(GE2D_FORMAT_M24_YUV420T & (3 << 3));
if (print_ifmt == 1) {
pr_err(
"vf->type=%x, format=%x, w*h=%dx%d, canvas0=%x, canvas1=%x\n",
vf->type, format, vf->width, vf->height, vf->canvas0Addr,
vf->canvas1Addr);
print_ifmt = 0;
}
return format;
}
static inline int get_bottom_input_format(struct vframe_s *vf)
{
int format = GE2D_FORMAT_M24_NV21;
if (vf->type & VIDTYPE_VIU_422)
format = GE2D_FORMAT_S16_YUV422 |
(GE2D_FORMAT_S16_YUV422B & (3 << 3));
else if (vf->type & VIDTYPE_VIU_NV21)
format = GE2D_FORMAT_M24_NV21 |
(GE2D_FORMAT_M24_NV21B & (3 << 3));
else
format =
GE2D_FORMAT_M24_YUV420 |
(GE2D_FMT_M24_YUV420B & (3 << 3));
if (print_ifmt == 1) {
pr_err(
"vf->type=%x, format=%x, w*h=%dx%d, canvas0=%x, canvas1=%x\n",
vf->type, format, vf->width, vf->height, vf->canvas0Addr,
vf->canvas1Addr);
print_ifmt = 0;
}
return format;
}
static unsigned int print_ofmt;
module_param(print_ofmt, uint, 0644);
MODULE_PARM_DESC(print_ofmt, "print output format\n");
static int get_output_format(int v4l2_format)
{
int format = GE2D_FORMAT_S24_YUV444;
switch (v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
format = GE2D_FORMAT_S16_RGB_565;
break;
case V4L2_PIX_FMT_YUV444:
format = GE2D_FORMAT_S24_YUV444;
break;
case V4L2_PIX_FMT_VYUY:
format = GE2D_FORMAT_S16_YUV422;
break;
case V4L2_PIX_FMT_BGR24:
format = GE2D_FORMAT_S24_RGB;
break;
case V4L2_PIX_FMT_RGB24:
format = GE2D_FORMAT_S24_BGR;
break;
case V4L2_PIX_FMT_RGB32:
format = GE2D_FORMAT_S32_ABGR;
break;
case V4L2_PIX_FMT_NV12:
format = GE2D_FORMAT_M24_NV12;
break;
case V4L2_PIX_FMT_NV21:
format = GE2D_FORMAT_M24_NV21;
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
format = GE2D_FORMAT_S8_Y;
break;
default:
break;
}
if (print_ofmt == 1) {
pr_err("outputformat, v4l2_format=%x, format=%x\n", v4l2_format,
format);
print_ofmt = 0;
}
return format;
}
static void src_axis_adjust(int *src_top, int *src_left,
int *src_w, int *src_h,
struct amlvideo2_output *output)
{
*src_top = output->info.display_info.frame_vd_start_lines_;
*src_left = output->info.display_info.frame_hd_start_lines_;
*src_w = output->info.display_info.frame_hd_end_lines_ -
output->info.display_info.frame_hd_start_lines_ + 1;
*src_h = output->info.display_info.frame_vd_end_lines_ -
output->info.display_info.frame_vd_start_lines_ + 1;
}
static void output_axis_adjust(int src_w, int src_h, int *dst_w, int *dst_h,
int angle, struct amlvideo2_output *output)
{
int w = 0, h = 0, disp_w = 0, disp_h = 0;
int post_blend_w = 0, post_blend_h = 0, window_w = 0, window_h = 0;
disp_w = *dst_w;
disp_h = *dst_h;
if ((src_w == 0) || (src_h == 0)) {
pr_err("src width or height is zero");
return;
}
if (output != NULL) {
if (output->info.mode == AML_SCREEN_MODE_RATIO) {
if (angle % 180 != 0) {
h = min_t(int, (int)src_w, disp_h);
w = src_h * h / src_w;
if (w > disp_w) {
h = (h * disp_w) / w;
w = disp_w;
}
} else {
if ((src_w < disp_w) && (src_h < disp_h)) {
w = src_w;
h = src_h;
} else if ((src_w * disp_h) >
(disp_w * src_h)) {
w = disp_w;
h = disp_w * src_h / src_w;
} else {
h = disp_h;
w = disp_h * src_w / src_h;
}
}
*dst_w = w;
*dst_h = h;
} else if (output->info.mode == AML_SCREEN_MODE_FULL) {
h = disp_h;
w = disp_w;
*dst_w = w;
*dst_h = h;
} else if (output->info.mode == AML_SCREEN_MODE_ADAPTIVE) {
post_blend_w =
output->info.display_info.screen_vd_h_end_ -
output->info.display_info.screen_vd_h_start_ + 1;
post_blend_h =
output->info.display_info.screen_vd_v_end_ -
output->info.display_info.screen_vd_v_start_ + 1;
window_w = output->info.display_info.display_hsc_endp -
output->info.display_info.display_hsc_startp + 1;
window_h = output->info.display_info.display_vsc_endp -
output->info.display_info.display_vsc_startp + 1;
*dst_w = (window_w * disp_w) / post_blend_w;
*dst_h = (window_h * disp_h) / post_blend_h;
}
} else {
if (angle % 180 != 0) {
h = min_t(int, (int)src_w, disp_h);
w = src_h * h / src_w;
if (w > disp_w) {
h = (h * disp_w) / w;
w = disp_w;
}
} else {
if ((src_w < disp_w) && (src_h < disp_h)) {
w = src_w;
h = src_h;
} else if ((src_w * disp_h) >
(disp_w * src_h)) {
w = disp_w;
h = disp_w * src_h / src_w;
} else {
h = disp_h;
w = disp_h * src_w / src_h;
}
}
*dst_w = w;
*dst_h = h;
}
}
int amlvideo2_ge2d_interlace_two_canvasAddr_process(
struct vframe_s *vf, struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config, struct amlvideo2_output *output,
struct amlvideo2_node *node)
{
int src_top, src_left, src_width, src_height;
int dst_top, dst_left, dst_width, dst_height;
struct canvas_s cs0, cs1, cs2, cd;
int current_mirror;
int cur_angle = 0;
int output_canvas = vf->canvas0Addr;
/* ============================ */
/* top field */
/* ============================ */
src_top = 0;
src_left = 0;
src_width = vf->width;
/* src_height = vf->height/2; */
src_height = vf->height;
if (amlvideo2_dbg_en & 4) {
pr_info("vf->width = %d, vf->height = %d\n",
vf->width, vf->height);
pr_info("vf->type = %x, vf->src_canvas = %x\n",
vf->type, vf->canvas0Addr);
pr_info("crop_enable = %d\n",
node->crop_info.capture_crop_enable);
pr_info("crop_top = %d, crop_left = %d\n",
node->crop_info.source_top_crop,
node->crop_info.source_left_crop);
pr_info("crop_width = %d, crop_height = %d\n\n",
node->crop_info.source_width_crop,
node->crop_info.source_height_crop);
}
if (node->crop_info.capture_crop_enable == 1) {
if ((node->crop_info.source_top_crop > 0) &&
(node->crop_info.source_top_crop < vf->height))
src_top = node->crop_info.source_top_crop;
else
src_top = 0;
if ((node->crop_info.source_left_crop > 0) &&
(node->crop_info.source_left_crop < vf->width))
src_left = node->crop_info.source_left_crop;
else
src_left = 0;
if ((node->crop_info.source_width_crop > 0) &&
(node->crop_info.source_width_crop <
(vf->width - src_left)))
src_width = node->crop_info.source_width_crop;
else
src_width = vf->width - src_left;
if (node->crop_info.source_height_crop > 0 &&
(node->crop_info.source_height_crop <
(vf->height - src_top)))
src_height = node->crop_info.source_height_crop;
else
src_height = vf->height - src_top;
} else {
if (node->has_amvideo_node) {
src_axis_adjust(&src_top, &src_left,
&src_width, &src_height, output);
}
if (amlvideo2_dbg_en & 4) {
pr_info("src_width = %d, src_left = %d\n",
src_width, src_left);
pr_info("src_height = %d, src_top = %d\n",
src_height, src_top);
}
if (((src_width + src_left) > vf->width) ||
((src_height + src_top) > vf->height) ||
(src_top < 0) || (src_left < 0) ||
(src_width <= 0) || (src_height <= 0)) {
pr_info("amlvideo2:parameters is not match\n");
src_width = vf->width;
src_height = vf->height;
src_top = 0;
src_left = 0;
}
src_top = src_top & 0xfffffffe;
src_left = src_left & 0xfffffffe;
src_width = src_width & 0xfffffffe;
src_height = src_height & 0xfffffffe;
}
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = output->angle;
if (current_mirror == 1)
cur_angle = (360 - cur_angle % 360);
else
cur_angle = cur_angle % 360;
if (node->porttype == TVIN_PORT_VIU1) {
if (src_width < src_height)
cur_angle = (cur_angle + 90) % 360;
}
if ((node->crop_info.capture_crop_enable == 0) &&
((node->porttype != TVIN_PORT_VIU1_VIDEO) &&
(node->porttype != TVIN_PORT_VIU1_WB0_VD1))) {
output_axis_adjust(
src_width, src_height,
&dst_width, &dst_height,
cur_angle, output);
}
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
node->crop_info.source_top_crop = dst_top;
node->crop_info.source_left_crop = dst_left;
node->crop_info.source_width_crop = dst_width;
node->crop_info.source_height_crop = dst_height;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
if ((dst_left != output->frame->x) || (dst_top != output->frame->y)
|| (dst_width != output->frame->w)
|| (dst_height != output->frame->h)) {
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->src_planes[0].addr = cd.addr;
ge2d_config->src_planes[0].w = cd.width;
ge2d_config->src_planes[0].h = cd.height;
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = output_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_output_format(
output->v4l2_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 = 0;
ge2d_config->src_para.top = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = output->width;
ge2d_config->src_para.height = output->height;
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -2;
}
if (amlvideo2_dbg_en & 4) {
pr_info("output_width = %d , output_height = %d\n",
output->width, output->height);
pr_info("dst_format = %x\n",
ge2d_config->dst_para.format);
}
fillrect(
context,
0,
0,
output->width,
output->height,
(ge2d_config->dst_para.format & GE2D_FORMAT_YUV) ?
0x008080ff : 0);
output->frame->x = dst_left;
output->frame->y = dst_top;
output->frame->w = dst_width;
output->frame->h = dst_height;
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
}
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas0Addr & 0xff, &cs0);
canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas0Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_input_format(vf);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height / 2;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
if ((output->v4l2_format != V4L2_PIX_FMT_YUV420) && (output->v4l2_format
!= V4L2_PIX_FMT_YVU420))
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = (get_output_format(output->v4l2_format)
| GE2D_LITTLE_ENDIAN)
| (GE2D_FORMAT_M24_YUV420T & (3 << 3));
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.width = output->width;
ge2d_config->dst_para.height = output->height / 2;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
if (amlvideo2_dbg_en & 4) {
pr_info("src0_addr = %lx, w = %d, h = %d\n",
cs0.addr, cs0.width, cs0.height);
pr_info("src1_addr = %lx, w = %d, h = %d\n",
cs1.addr, cs1.width, cs1.height);
pr_info("src2_addr = %lx, w = %d, h = %d\n",
cs2.addr, cs2.width, cs2.height);
pr_info("output: w = %d, h = %d, output_canvas = %x\n\n",
output->width, output->height, output_canvas);
pr_info("%s:node->id = %d ,src_left = %d ,src_top = %d\n",
__func__, node->vid, src_left, src_top);
pr_info("src_width=%d ,src_height=%d ,output->frame->x=%d\n",
src_width, src_height, output->frame->x);
pr_info("output->frame->y=%d ,frame->w=%d ,frame->h=%d\n",
output->frame->y, output->frame->w, output->frame->h);
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width, src_height / 2,
output->frame->x, output->frame->y / 2,
output->frame->w, output->frame->h / 2);
/* for cr of yuv420p or yuv420sp. */
if ((output->v4l2_format == V4L2_PIX_FMT_YUV420) || (output->v4l2_format
== V4L2_PIX_FMT_YVU420)) {
/* for cb. */
canvas_read((output_canvas >> 8) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 8) & 0xff;
ge2d_config->dst_para.format =
(GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN)
| (GE2D_FORMAT_M24_YUV420T & (3 << 3));
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 4;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 4, output->frame->w / 2,
output->frame->h / 4);
}
/* for cb of yuv420p or yuv420sp. */
if (output->v4l2_format == V4L2_PIX_FMT_YUV420 || output->v4l2_format
== V4L2_PIX_FMT_YVU420) {
canvas_read((output_canvas >> 16) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 16) & 0xff;
ge2d_config->dst_para.format =
(GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN)
| (GE2D_FORMAT_M24_YUV420T & (3 << 3));
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 4;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 4, output->frame->w / 2,
output->frame->h / 4);
}
/* ============================ */
/* bottom field */
/* ============================ */
output_canvas = vf->canvas1Addr;
src_top = 0;
src_left = 0;
src_width = vf->width;
src_height = vf->height;
if (node->crop_info.capture_crop_enable == 1) {
if ((node->crop_info.source_top_crop > 0) &&
(node->crop_info.source_top_crop < vf->height))
src_top = node->crop_info.source_top_crop;
else
src_top = 0;
if ((node->crop_info.source_left_crop > 0) &&
(node->crop_info.source_left_crop < vf->width))
src_left = node->crop_info.source_left_crop;
else
src_left = 0;
if ((node->crop_info.source_width_crop > 0) &&
(node->crop_info.source_width_crop <
(vf->width - src_left)))
src_width = node->crop_info.source_width_crop;
else
src_width = vf->width - src_left;
if (node->crop_info.source_height_crop > 0 &&
(node->crop_info.source_height_crop <
(vf->height - src_top)))
src_height = node->crop_info.source_height_crop;
else
src_height = vf->height - src_top;
} else {
if (node->has_amvideo_node) {
src_axis_adjust(&src_top, &src_left,
&src_width, &src_height, output);
}
src_top = src_top & 0xfffffffe;
src_left = src_left & 0xfffffffe;
src_width = src_width & 0xfffffffe;
src_height = src_height & 0xfffffffe;
}
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = output->angle;
if (current_mirror == 1)
cur_angle = (360 - cur_angle % 360);
else
cur_angle = cur_angle % 360;
if (src_width < src_height)
cur_angle = (cur_angle + 90) % 360;
if ((node->crop_info.capture_crop_enable == 0) &&
((node->porttype != TVIN_PORT_VIU1_VIDEO) &&
(node->porttype != TVIN_PORT_VIU1_WB0_VD1))) {
output_axis_adjust(
src_width, src_height,
&dst_width, &dst_height,
cur_angle, output);
}
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
if ((dst_left != output->frame->x) || (dst_top != output->frame->y)
|| (dst_width != output->frame->w)
|| (dst_height != output->frame->h)) {
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->src_planes[0].addr = cd.addr;
ge2d_config->src_planes[0].w = cd.width;
ge2d_config->src_planes[0].h = cd.height;
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = output_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_output_format(
output->v4l2_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 = 0;
ge2d_config->src_para.top = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = output->width;
ge2d_config->src_para.height = output->height;
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -2;
}
fillrect(
context,
0,
0,
output->width,
output->height,
(ge2d_config->dst_para.format & GE2D_FORMAT_YUV) ?
0x008080ff : 0);
output->frame->x = dst_left;
output->frame->y = dst_top;
output->frame->w = dst_width;
output->frame->h = dst_height;
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
}
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas1Addr & 0xff, &cs0);
canvas_read((vf->canvas1Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas1Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas1Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_input_format(vf);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height / 2;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
if ((output->v4l2_format != V4L2_PIX_FMT_YUV420) && (output->v4l2_format
!= V4L2_PIX_FMT_YVU420))
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = (get_output_format(output->v4l2_format)
| GE2D_LITTLE_ENDIAN)
| (GE2D_FORMAT_M24_YUV420B & (3 << 3));
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.width = output->width;
ge2d_config->dst_para.height = output->height / 2;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width, src_height / 2,
output->frame->x, output->frame->y / 2,
output->frame->w, output->frame->h / 2);
/* for cr of yuv420p or yuv420sp. */
if ((output->v4l2_format == V4L2_PIX_FMT_YUV420) || (output->v4l2_format
== V4L2_PIX_FMT_YVU420)) {
/* for cb. */
canvas_read((output_canvas >> 8) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 8) & 0xff;
ge2d_config->dst_para.format =
(GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN)
| (GE2D_FORMAT_M24_YUV420B & (3 << 3));
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 4;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 4, output->frame->w / 2,
output->frame->h / 4);
}
/* for cb of yuv420p or yuv420sp. */
if (output->v4l2_format == V4L2_PIX_FMT_YUV420 || output->v4l2_format
== V4L2_PIX_FMT_YVU420) {
canvas_read((output_canvas >> 16) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 16) & 0xff;
ge2d_config->dst_para.format =
(GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN)
| (GE2D_FORMAT_M24_YUV420B & (3 << 3));
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 4;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 4, output->frame->w / 2,
output->frame->h / 4);
}
return output_canvas;
}
int amlvideo2_ge2d_interlace_vdindata_process(
struct vframe_s *vf, struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config, struct amlvideo2_output *output,
struct amlvideo2_node *node)
{
int src_top, src_left, src_width, src_height;
int dst_top, dst_left, dst_width, dst_height;
struct canvas_s cs0, cs1, cs2, cd;
int current_mirror;
int cur_angle = 0;
int output_canvas = output->canvas_id;
src_top = 0;
src_left = 0;
src_width = vf->width;
src_height = vf->height;
if (amlvideo2_dbg_en & 4) {
pr_info("vf->width = %d, vf->height = %d\n",
vf->width, vf->height);
pr_info("vf->type = %x, vf->src_canvas = %x\n",
vf->type, vf->canvas0Addr);
pr_info("crop_enable = %d\n",
node->crop_info.capture_crop_enable);
pr_info("crop_top = %d, crop_left = %d\n",
node->crop_info.source_top_crop,
node->crop_info.source_left_crop);
pr_info("crop_width = %d, crop_height = %d\n\n",
node->crop_info.source_width_crop,
node->crop_info.source_height_crop);
}
if (node->crop_info.capture_crop_enable == 1) {
if ((node->crop_info.source_top_crop > 0) &&
(node->crop_info.source_top_crop < vf->height))
src_top = node->crop_info.source_top_crop;
else
src_top = 0;
if ((node->crop_info.source_left_crop > 0) &&
(node->crop_info.source_left_crop < vf->width))
src_left = node->crop_info.source_left_crop;
else
src_left = 0;
if ((node->crop_info.source_width_crop > 0) &&
(node->crop_info.source_width_crop <
(vf->width - src_left)))
src_width = node->crop_info.source_width_crop;
else
src_width = vf->width - src_left;
if (node->crop_info.source_height_crop > 0 &&
(node->crop_info.source_height_crop <
(vf->height - src_top)))
src_height = node->crop_info.source_height_crop;
else
src_height = vf->height - src_top;
} else {
if (node->has_amvideo_node) {
src_axis_adjust(&src_top, &src_left,
&src_width, &src_height, output);
}
if (amlvideo2_dbg_en & 4) {
pr_info("src_width = %d, src_left = %d\n",
src_width, src_left);
pr_info("src_height = %d, src_top = %d\n",
src_height, src_top);
}
if (((src_width + src_left) > vf->width) ||
((src_height + src_top) > vf->height) ||
(src_top < 0) || (src_left < 0) ||
(src_width <= 0) || (src_height <= 0)) {
pr_info("amlvideo2:parameters is not match\n");
src_width = vf->width;
src_height = vf->height;
src_top = 0;
src_left = 0;
}
src_top = src_top & 0xfffffffe;
src_left = src_left & 0xfffffffe;
src_width = src_width & 0xfffffffe;
src_height = src_height & 0xfffffffe;
}
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = output->angle;
if (current_mirror == 1)
cur_angle = (360 - cur_angle % 360);
else
cur_angle = cur_angle % 360;
if (node->porttype == TVIN_PORT_VIU1) {
if (src_width < src_height)
cur_angle = (cur_angle + 90) % 360;
}
if ((node->crop_info.capture_crop_enable == 0) &&
((node->porttype != TVIN_PORT_VIU1_VIDEO) &&
(node->porttype != TVIN_PORT_VIU1_WB0_VD1))) {
output_axis_adjust(
src_width, src_height,
&dst_width, &dst_height,
cur_angle, output);
}
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
node->crop_info.source_top_crop = dst_top;
node->crop_info.source_left_crop = dst_left;
node->crop_info.source_width_crop = dst_width;
node->crop_info.source_height_crop = dst_height;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
if ((dst_left != output->frame->x) || (dst_top != output->frame->y)
|| (dst_width != output->frame->w)
|| (dst_height != output->frame->h)) {
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->src_planes[0].addr = cd.addr;
ge2d_config->src_planes[0].w = cd.width;
ge2d_config->src_planes[0].h = cd.height;
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = output_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_output_format(
output->v4l2_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 = 0;
ge2d_config->src_para.top = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = output->width;
ge2d_config->src_para.height = output->height;
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -2;
}
if (amlvideo2_dbg_en & 4) {
pr_info("output_width = %d , output_height = %d\n",
output->width, output->height);
pr_info("dst_format = %x\n",
ge2d_config->dst_para.format);
}
fillrect(
context,
0,
0,
output->width,
output->height,
(ge2d_config->dst_para.format & GE2D_FORMAT_YUV) ?
0x008080ff : 0);
output->frame->x = dst_left;
output->frame->y = dst_top;
output->frame->w = dst_width;
output->frame->h = dst_height;
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
}
src_height = src_height / 2;
src_top = src_top / 2;
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas0Addr & 0xff, &cs0);
canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas0Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_interlace_input_format(vf, output);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height/2;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
if ((output->v4l2_format != V4L2_PIX_FMT_YUV420) && (output->v4l2_format
!= V4L2_PIX_FMT_YVU420))
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
if (amlvideo2_dbg_en & 4) {
pr_info("src0_addr = %lx, w = %d, h = %d\n",
cs0.addr, cs0.width, cs0.height);
pr_info("src1_addr = %lx, w = %d, h = %d\n",
cs1.addr, cs1.width, cs1.height);
pr_info("src2_addr = %lx, w = %d, h = %d\n",
cs2.addr, cs2.width, cs2.height);
pr_info("output: w = %d, h = %d, output_canvas = %x\n\n",
output->width, output->height, output_canvas);
pr_info("%s:node->id = %d ,src_left = %d ,src_top = %d\n",
__func__, node->vid, src_left, src_top);
pr_info("src_width=%d ,src_height=%d ,output->frame->x=%d\n",
src_width, src_height, output->frame->x);
pr_info("output->frame->y=%d ,frame->w=%d ,frame->h=%d\n",
output->frame->y, output->frame->w, output->frame->h);
}
stretchblt_noalpha(
context, src_left, src_top, src_width, src_height,
output->frame->x, output->frame->y, output->frame->w,
output->frame->h);
/* for cr of yuv420p or yuv420sp. */
if ((output->v4l2_format == V4L2_PIX_FMT_YUV420) || (output->v4l2_format
== V4L2_PIX_FMT_YVU420)) {
/* for cb. */
canvas_read((output_canvas >> 8) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 8) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top, src_width, src_height,
output->frame->x / 2, output->frame->y / 2,
output->frame->w / 2, output->frame->h / 2);
}
/* for cb of yuv420p or yuv420sp. */
if (output->v4l2_format == V4L2_PIX_FMT_YUV420 || output->v4l2_format
== V4L2_PIX_FMT_YVU420) {
canvas_read((output_canvas >> 16) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 16) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top, src_width, src_height,
output->frame->x / 2, output->frame->y / 2,
output->frame->w / 2, output->frame->h / 2);
}
return output_canvas;
}
int amlvideo2_ge2d_interlace_one_canvasAddr_process(
struct vframe_s *vf, struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config, struct amlvideo2_output *output,
struct amlvideo2_node *node)
{
int src_top, src_left, src_width, src_height;
int dst_top, dst_left, dst_width, dst_height;
struct canvas_s cs0, cs1, cs2, cd;
int current_mirror;
int cur_angle = 0;
int output_canvas = output->canvas_id;
src_top = 0;
src_left = 0;
src_width = vf->width;
/* src_height = vf->height/2; */
src_height = vf->height;
if (amlvideo2_dbg_en & 4) {
pr_info("vf->width = %d, vf->height = %d\n",
vf->width, vf->height);
pr_info("vf->type = %x, vf->src_canvas = %x\n",
vf->type, vf->canvas0Addr);
pr_info("crop_enable = %d\n",
node->crop_info.capture_crop_enable);
pr_info("crop_top = %d, crop_left = %d\n",
node->crop_info.source_top_crop,
node->crop_info.source_left_crop);
pr_info("crop_width = %d, crop_height = %d\n\n",
node->crop_info.source_width_crop,
node->crop_info.source_height_crop);
}
if (node->crop_info.capture_crop_enable == 1) {
if ((node->crop_info.source_top_crop > 0) &&
(node->crop_info.source_top_crop < vf->height))
src_top = node->crop_info.source_top_crop;
else
src_top = 0;
if ((node->crop_info.source_left_crop > 0) &&
(node->crop_info.source_left_crop < vf->width))
src_left = node->crop_info.source_left_crop;
else
src_left = 0;
if ((node->crop_info.source_width_crop > 0) &&
(node->crop_info.source_width_crop <
(vf->width - src_left)))
src_width = node->crop_info.source_width_crop;
else
src_width = vf->width - src_left;
if (node->crop_info.source_height_crop > 0 &&
(node->crop_info.source_height_crop <
(vf->height - src_top)))
src_height = node->crop_info.source_height_crop;
else
src_height = vf->height - src_top;
} else {
if (node->has_amvideo_node) {
src_axis_adjust(&src_top, &src_left,
&src_width, &src_height, output);
}
if (amlvideo2_dbg_en & 4) {
pr_info("src_width = %d, src_left = %d\n",
src_width, src_left);
pr_info("src_height = %d, src_top = %d\n",
src_height, src_top);
}
if (((src_width + src_left) > vf->width) ||
((src_height + src_top) > vf->height) ||
(src_top < 0) || (src_left < 0) ||
(src_width <= 0) || (src_height <= 0)) {
pr_info("amlvideo2:parameters is not match\n");
src_width = vf->width;
src_height = vf->height;
src_top = 0;
src_left = 0;
}
src_top = src_top & 0xfffffffe;
src_left = src_left & 0xfffffffe;
src_width = src_width & 0xfffffffe;
src_height = src_height & 0xfffffffe;
}
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = output->angle;
if (current_mirror == 1)
cur_angle = (360 - cur_angle % 360);
else
cur_angle = cur_angle % 360;
if (node->porttype == TVIN_PORT_VIU1) {
if (src_width < src_height)
cur_angle = (cur_angle + 90) % 360;
}
if ((node->crop_info.capture_crop_enable == 0) &&
((node->porttype != TVIN_PORT_VIU1_VIDEO) &&
(node->porttype != TVIN_PORT_VIU1_WB0_VD1))) {
output_axis_adjust(
src_width, src_height,
&dst_width, &dst_height,
cur_angle, output);
}
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
node->crop_info.source_top_crop = dst_top;
node->crop_info.source_left_crop = dst_left;
node->crop_info.source_width_crop = dst_width;
node->crop_info.source_height_crop = dst_height;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
if ((dst_left != output->frame->x) || (dst_top != output->frame->y)
|| (dst_width != output->frame->w)
|| (dst_height != output->frame->h)) {
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->src_planes[0].addr = cd.addr;
ge2d_config->src_planes[0].w = cd.width;
ge2d_config->src_planes[0].h = cd.height;
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = output_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_output_format(
output->v4l2_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 = 0;
ge2d_config->src_para.top = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = output->width;
ge2d_config->src_para.height = output->height;
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -2;
}
if (amlvideo2_dbg_en & 4) {
pr_info("output_width = %d , output_height = %d\n",
output->width, output->height);
pr_info("dst_format = %x\n",
ge2d_config->dst_para.format);
}
fillrect(
context,
0,
0,
output->width,
output->height,
(ge2d_config->dst_para.format & GE2D_FORMAT_YUV) ?
0x008080ff : 0);
output->frame->x = dst_left;
output->frame->y = dst_top;
output->frame->w = dst_width;
output->frame->h = dst_height;
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
}
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas0Addr & 0xff, &cs0);
canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas0Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_input_format_no_interlace(vf);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height / 2;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
if ((output->v4l2_format != V4L2_PIX_FMT_YUV420) && (output->v4l2_format
!= V4L2_PIX_FMT_YVU420))
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
if (amlvideo2_dbg_en & 4) {
pr_info("src0_addr = %lx, w = %d, h = %d\n",
cs0.addr, cs0.width, cs0.height);
pr_info("src1_addr = %lx, w = %d, h = %d\n",
cs1.addr, cs1.width, cs1.height);
pr_info("src2_addr = %lx, w = %d, h = %d\n",
cs2.addr, cs2.width, cs2.height);
pr_info("output: w = %d, h = %d, output_canvas = %x\n\n",
output->width, output->height, output_canvas);
pr_info("%s:node->id = %d ,src_left = %d ,src_top = %d\n",
__func__, node->vid, src_left, src_top);
pr_info("src_width=%d ,src_height=%d ,output->frame->x=%d\n",
src_width, src_height, output->frame->x);
pr_info("output->frame->y=%d ,frame->w=%d ,frame->h=%d\n",
output->frame->y, output->frame->w, output->frame->h);
}
stretchblt_noalpha(
context, src_left, src_top / 2, src_width, src_height / 2,
output->frame->x, output->frame->y, output->frame->w,
output->frame->h);
/* for cr of yuv420p or yuv420sp. */
if ((output->v4l2_format == V4L2_PIX_FMT_YUV420) || (output->v4l2_format
== V4L2_PIX_FMT_YVU420)) {
/* for cb. */
canvas_read((output_canvas >> 8) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 8) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 2, output->frame->w / 2,
output->frame->h / 2);
}
/* for cb of yuv420p or yuv420sp. */
if (output->v4l2_format == V4L2_PIX_FMT_YUV420 || output->v4l2_format
== V4L2_PIX_FMT_YVU420) {
canvas_read((output_canvas >> 16) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 16) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 2, output->frame->w / 2,
output->frame->h / 2);
}
return output_canvas;
}
int amlvideo2_ge2d_interlace_dtv_process(
struct vframe_s *vf, struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config, struct amlvideo2_output *output,
struct amlvideo2_node *node)
{
int src_top, src_left, src_width, src_height;
int dst_top, dst_left, dst_width, dst_height;
struct canvas_s cs0, cs1, cs2, cd;
int current_mirror;
int cur_angle = 0;
int output_canvas = output->canvas_id;
src_top = 0;
src_left = 0;
src_width = vf->width;
/* src_height = vf->height/2; */
src_height = vf->height;
if (amlvideo2_dbg_en & 4) {
pr_info("vf->width = %d, vf->height = %d\n",
vf->width, vf->height);
pr_info("vf->type = %x, vf->src_canvas = %x\n",
vf->type, vf->canvas0Addr);
pr_info("crop_enable = %d\n",
node->crop_info.capture_crop_enable);
pr_info("crop_top = %d, crop_left = %d\n",
node->crop_info.source_top_crop,
node->crop_info.source_left_crop);
pr_info("crop_width = %d, crop_height = %d\n\n",
node->crop_info.source_width_crop,
node->crop_info.source_height_crop);
}
if (node->crop_info.capture_crop_enable == 1) {
if ((node->crop_info.source_top_crop > 0) &&
(node->crop_info.source_top_crop < vf->height))
src_top = node->crop_info.source_top_crop;
else
src_top = 0;
if ((node->crop_info.source_left_crop > 0) &&
(node->crop_info.source_left_crop < vf->width))
src_left = node->crop_info.source_left_crop;
else
src_left = 0;
if ((node->crop_info.source_width_crop > 0) &&
(node->crop_info.source_width_crop <
(vf->width - src_left)))
src_width = node->crop_info.source_width_crop;
else
src_width = vf->width - src_left;
if (node->crop_info.source_height_crop > 0 &&
(node->crop_info.source_height_crop <
(vf->height - src_top)))
src_height = node->crop_info.source_height_crop;
else
src_height = vf->height - src_top;
} else {
if (node->has_amvideo_node) {
src_axis_adjust(&src_top, &src_left,
&src_width, &src_height, output);
}
if (amlvideo2_dbg_en & 4) {
pr_info("src_width = %d, src_left = %d\n",
src_width, src_left);
pr_info("src_height = %d, src_top = %d\n",
src_height, src_top);
}
if (((src_width + src_left) > vf->width) ||
((src_height + src_top) > vf->height) ||
(src_top < 0) || (src_left < 0) ||
(src_width <= 0) || (src_height <= 0)) {
pr_info("amlvideo2:parameters is not match\n");
src_width = vf->width;
src_height = vf->height;
src_top = 0;
src_left = 0;
}
src_top = src_top & 0xfffffffe;
src_left = src_left & 0xfffffffe;
src_width = src_width & 0xfffffffe;
src_height = src_height & 0xfffffffe;
}
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = output->angle;
if (current_mirror == 1)
cur_angle = (360 - cur_angle % 360);
else
cur_angle = cur_angle % 360;
if (node->porttype == TVIN_PORT_VIU1) {
if (src_width < src_height)
cur_angle = (cur_angle + 90) % 360;
}
if ((node->crop_info.capture_crop_enable == 0) &&
((node->porttype != TVIN_PORT_VIU1_VIDEO) &&
(node->porttype != TVIN_PORT_VIU1_WB0_VD1))) {
output_axis_adjust(
src_width, src_height,
&dst_width, &dst_height,
cur_angle, output);
}
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
node->crop_info.source_top_crop = dst_top;
node->crop_info.source_left_crop = dst_left;
node->crop_info.source_width_crop = dst_width;
node->crop_info.source_height_crop = dst_height;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
if ((dst_left != output->frame->x) || (dst_top != output->frame->y)
|| (dst_width != output->frame->w)
|| (dst_height != output->frame->h)) {
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->src_planes[0].addr = cd.addr;
ge2d_config->src_planes[0].w = cd.width;
ge2d_config->src_planes[0].h = cd.height;
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = output_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_output_format(
output->v4l2_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 = 0;
ge2d_config->src_para.top = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = output->width;
ge2d_config->src_para.height = output->height;
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -2;
}
if (amlvideo2_dbg_en & 4) {
pr_info("output_width = %d , output_height = %d\n",
output->width, output->height);
pr_info("dst_format = %x\n",
ge2d_config->dst_para.format);
}
fillrect(
context,
0,
0,
output->width,
output->height,
(ge2d_config->dst_para.format & GE2D_FORMAT_YUV) ?
0x008080ff : 0);
output->frame->x = dst_left;
output->frame->y = dst_top;
output->frame->w = dst_width;
output->frame->h = dst_height;
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
}
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas0Addr & 0xff, &cs0);
canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas0Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_interlace_input_format(vf, output);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
if ((output->v4l2_format != V4L2_PIX_FMT_YUV420) && (output->v4l2_format
!= V4L2_PIX_FMT_YVU420))
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
if (amlvideo2_dbg_en & 4) {
pr_info("src0_addr = %lx, w = %d, h = %d\n",
cs0.addr, cs0.width, cs0.height);
pr_info("src1_addr = %lx, w = %d, h = %d\n",
cs1.addr, cs1.width, cs1.height);
pr_info("src2_addr = %lx, w = %d, h = %d\n",
cs2.addr, cs2.width, cs2.height);
pr_info("output: w = %d, h = %d, output_canvas = %x\n\n",
output->width, output->height, output_canvas);
pr_info("%s:node->id = %d ,src_left = %d ,src_top = %d\n",
__func__, node->vid, src_left, src_top);
pr_info("src_width=%d ,src_height=%d ,output->frame->x=%d\n",
src_width, src_height, output->frame->x);
pr_info("output->frame->y=%d ,frame->w=%d ,frame->h=%d\n",
output->frame->y, output->frame->w, output->frame->h);
}
stretchblt_noalpha(
context, src_left, src_top, src_width, src_height,
output->frame->x, output->frame->y, output->frame->w,
output->frame->h);
/* for cr of yuv420p or yuv420sp. */
if ((output->v4l2_format == V4L2_PIX_FMT_YUV420) || (output->v4l2_format
== V4L2_PIX_FMT_YVU420)) {
/* for cb. */
canvas_read((output_canvas >> 8) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 8) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 2, output->frame->w / 2,
output->frame->h / 2);
}
/* for cb of yuv420p or yuv420sp. */
if (output->v4l2_format == V4L2_PIX_FMT_YUV420 || output->v4l2_format
== V4L2_PIX_FMT_YVU420) {
canvas_read((output_canvas >> 16) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 16) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context, src_left, src_top / 2, src_width,
src_height / 2, output->frame->x / 2,
output->frame->y / 2, output->frame->w / 2,
output->frame->h / 2);
}
return output_canvas;
}
int amlvideo2_ge2d_multi_pre_process(struct vframe_s *vf,
struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config,
struct amlvideo2_output *output,
struct amlvideo2_node *node)
{
int src_top, src_left, src_width, src_height;
int dst_top, dst_left, dst_width, dst_height;
struct canvas_s cs0, cs1, cs2, cd;
int current_mirror;
int cur_angle = 0;
int output_canvas = output->canvas_id;
int temp_canvas = AMLVIDEO2_1_RES_CANVAS + 8;
unsigned long temp_start = node->vid_dev->buffer_start +
(CMA_ALLOC_SIZE * SZ_1M);
int temp_w = vf->width/4;
int temp_h = vf->height/4;
u32 h_scale_coef_type =
context->config.h_scale_coef_type;
u32 v_scale_coef_type =
context->config.v_scale_coef_type;
temp_w = (temp_w + 31) & (~31);
temp_h = (temp_h + 1) & (~1);
if (amlvideo2_dbg_en & 4) {
pr_info("vf->width = %d, vf->height = %d\n",
vf->width, vf->height);
}
if (amlvideo2_scaledown1 == 0) {
context->config.h_scale_coef_type = FILTER_TYPE_BICUBIC;
context->config.v_scale_coef_type = FILTER_TYPE_BICUBIC;
} else if (amlvideo2_scaledown1 == 1) {
context->config.h_scale_coef_type = FILTER_TYPE_BILINEAR;
context->config.v_scale_coef_type = FILTER_TYPE_BILINEAR;
} else if (amlvideo2_scaledown1 == 2) {
context->config.h_scale_coef_type = FILTER_TYPE_TRIANGLE;
context->config.v_scale_coef_type = FILTER_TYPE_TRIANGLE;
} else {
context->config.h_scale_coef_type = FILTER_TYPE_BICUBIC;
context->config.v_scale_coef_type = FILTER_TYPE_BICUBIC;
}
canvas_config(temp_canvas,
(unsigned long)temp_start,
temp_w, temp_h,
CANVAS_ADDR_NOWRAP,
CANVAS_BLKMODE_LINEAR);
src_top = 4;
src_left = 4;
src_width = vf->width;
src_height = vf->height;
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = 0;
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
node->crop_info.source_top_crop = dst_top;
node->crop_info.source_left_crop = dst_left;
node->crop_info.source_width_crop = dst_width;
node->crop_info.source_height_crop = dst_height;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas0Addr & 0xff, &cs0);
canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas0Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_input_format(vf);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = temp_canvas & 0xff;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = GE2D_FORMAT_S8_Y | GE2D_LITTLE_ENDIAN;
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.width = temp_w;
ge2d_config->dst_para.height = temp_h;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context, src_left, src_top, src_width - src_left,
src_height - src_top, 0, 0, temp_w,
temp_h);
if (amlvideo2_scaledown2 == 0) {
context->config.h_scale_coef_type = FILTER_TYPE_BICUBIC;
context->config.v_scale_coef_type = FILTER_TYPE_BICUBIC;
} else if (amlvideo2_scaledown2 == 1) {
context->config.h_scale_coef_type = FILTER_TYPE_BILINEAR;
context->config.v_scale_coef_type = FILTER_TYPE_BILINEAR;
} else if (amlvideo2_scaledown2 == 2) {
context->config.h_scale_coef_type = FILTER_TYPE_TRIANGLE;
context->config.v_scale_coef_type = FILTER_TYPE_TRIANGLE;
}
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(temp_canvas & 0xff, &cs0);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = temp_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = GE2D_FORMAT_S8_Y | 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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = temp_w;
ge2d_config->src_para.height = temp_h;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = GE2D_FORMAT_S8_Y | GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context, 0, 0, temp_w, temp_h,
0, 0, output->width, output->height);
context->config.h_scale_coef_type =
h_scale_coef_type;
context->config.v_scale_coef_type =
v_scale_coef_type;
return output_canvas;
}
int amlvideo2_ge2d_pre_process(struct vframe_s *vf,
struct ge2d_context_s *context,
struct config_para_ex_s *ge2d_config,
struct amlvideo2_output *output,
struct amlvideo2_node *node)
{
int src_top, src_left, src_width, src_height;
int dst_top, dst_left, dst_width, dst_height;
struct canvas_s cs0, cs1, cs2, cd;
int current_mirror;
int cur_angle = 0;
int output_canvas = output->canvas_id;
src_top = 0;
src_left = 0;
src_width = vf->width;
src_height = vf->height;
if (amlvideo2_dbg_en & 4) {
pr_info("vf->width = %d, vf->height = %d\n",
vf->width, vf->height);
pr_info("vf->type = %x, vf->src_canvas = %x\n",
vf->type, vf->canvas0Addr);
pr_info("crop_enable = %d\n",
node->crop_info.capture_crop_enable);
pr_info("crop_top = %d, crop_left = %d\n",
node->crop_info.source_top_crop,
node->crop_info.source_left_crop);
pr_info("crop_width = %d, crop_height = %d\n\n",
node->crop_info.source_width_crop,
node->crop_info.source_height_crop);
}
if (node->crop_info.capture_crop_enable == 1) {
if ((node->crop_info.source_top_crop > 0) &&
(node->crop_info.source_top_crop < vf->height))
src_top = node->crop_info.source_top_crop;
else
src_top = 0;
if ((node->crop_info.source_left_crop > 0) &&
(node->crop_info.source_left_crop < vf->width))
src_left = node->crop_info.source_left_crop;
else
src_left = 0;
if ((node->crop_info.source_width_crop > 0) &&
(node->crop_info.source_width_crop <
(vf->width - src_left)))
src_width = node->crop_info.source_width_crop;
else
src_width = vf->width - src_left;
if (node->crop_info.source_height_crop > 0 &&
(node->crop_info.source_height_crop <
(vf->height - src_top)))
src_height = node->crop_info.source_height_crop;
else
src_height = vf->height - src_top;
} else {
if (node->has_amvideo_node) {
src_axis_adjust(&src_top, &src_left,
&src_width, &src_height, output);
}
if (amlvideo2_dbg_en & 4) {
pr_info("src_width = %d, src_left = %d\n",
src_width, src_left);
pr_info("src_height = %d, src_top = %d\n",
src_height, src_top);
}
if (((src_width + src_left) > vf->width) ||
((src_height + src_top) > vf->height) ||
(src_top < 0) || (src_left < 0) ||
(src_width <= 0) || (src_height <= 0)) {
pr_info("amlvideo2:parameters is not match\n");
src_width = vf->width;
src_height = vf->height;
src_top = 0;
src_left = 0;
}
src_top = src_top & 0xfffffffe;
src_left = src_left & 0xfffffffe;
src_width = src_width & 0xfffffffe;
src_height = src_height & 0xfffffffe;
}
dst_top = 0;
dst_left = 0;
dst_width = output->width;
dst_height = output->height;
current_mirror = mirror_value;
cur_angle = output->angle;
if (current_mirror == 1)
cur_angle = (360 - cur_angle % 360);
else
cur_angle = cur_angle % 360;
if (node->porttype == TVIN_PORT_VIU1) {
if (src_width < src_height)
cur_angle = (cur_angle + 90) % 360;
}
if ((node->crop_info.capture_crop_enable == 0) &&
((node->porttype != TVIN_PORT_VIU1_VIDEO) &&
(node->porttype != TVIN_PORT_VIU1_WB0_VD1))) {
output_axis_adjust(
src_width, src_height,
&dst_width, &dst_height,
cur_angle, output);
}
dst_width = dst_width & 0xfffffffe;
dst_height = dst_height & 0xfffffffe;
dst_top = (output->height - dst_height) / 2;
dst_left = (output->width - dst_width) / 2;
dst_top = dst_top & 0xfffffffe;
dst_left = dst_left & 0xfffffffe;
node->crop_info.source_top_crop = dst_top;
node->crop_info.source_left_crop = dst_left;
node->crop_info.source_width_crop = dst_width;
node->crop_info.source_height_crop = dst_height;
/* data operating. */
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
if ((dst_left != output->frame->x) || (dst_top != output->frame->y)
|| (dst_width != output->frame->w)
|| (dst_height != output->frame->h)) {
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->src_planes[0].addr = cd.addr;
ge2d_config->src_planes[0].w = cd.width;
ge2d_config->src_planes[0].h = cd.height;
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = output_canvas;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_output_format(
output->v4l2_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 = 0;
ge2d_config->src_para.top = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = output->width;
ge2d_config->src_para.height = output->height;
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -2;
}
if (amlvideo2_dbg_en & 4) {
pr_info("output_width = %d , output_height = %d\n",
output->width, output->height);
pr_info("dst_format = %x\n",
ge2d_config->dst_para.format);
}
fillrect(
context,
0,
0,
output->width,
output->height,
(ge2d_config->dst_para.format & GE2D_FORMAT_YUV) ?
0x008080ff : 0);
output->frame->x = dst_left;
output->frame->y = dst_top;
output->frame->w = dst_width;
output->frame->h = dst_height;
memset(ge2d_config, 0, sizeof(struct config_para_ex_s));
}
ge2d_config->alu_const_color = 0;
ge2d_config->bitmask_en = 0;
ge2d_config->src1_gb_alpha = 0;/* 0xff; */
ge2d_config->dst_xy_swap = 0;
canvas_read(vf->canvas0Addr & 0xff, &cs0);
canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
ge2d_config->src_planes[0].addr = cs0.addr;
ge2d_config->src_planes[0].w = cs0.width;
ge2d_config->src_planes[0].h = cs0.height;
ge2d_config->src_planes[1].addr = cs1.addr;
ge2d_config->src_planes[1].w = cs1.width;
ge2d_config->src_planes[1].h = cs1.height;
ge2d_config->src_planes[2].addr = cs2.addr;
ge2d_config->src_planes[2].w = cs2.width;
ge2d_config->src_planes[2].h = cs2.height;
canvas_read(output_canvas & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
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.canvas_index = vf->canvas0Addr;
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->src_para.format = get_input_format(vf);
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 = 0;
ge2d_config->src_para.left = 0;
ge2d_config->src_para.width = vf->width;
ge2d_config->src_para.height = vf->height;
/* pr_err("vf_width is %d ,
* vf_height is %d\n",vf->width ,vf->height);
*/
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.canvas_index = output_canvas & 0xff;
if ((output->v4l2_format != V4L2_PIX_FMT_YUV420) && (output->v4l2_format
!= V4L2_PIX_FMT_YVU420))
ge2d_config->dst_para.canvas_index = output_canvas;
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
ge2d_config->dst_para.format = get_output_format(
output->v4l2_format)|GE2D_LITTLE_ENDIAN;
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.width = output->width;
ge2d_config->dst_para.height = output->height;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
if (amlvideo2_dbg_en & 4) {
pr_info("src0_addr = %lx, w = %d, h = %d\n",
cs0.addr, cs0.width, cs0.height);
pr_info("src1_addr = %lx, w = %d, h = %d\n",
cs1.addr, cs1.width, cs1.height);
pr_info("src2_addr = %lx, w = %d, h = %d\n",
cs2.addr, cs2.width, cs2.height);
pr_info("output: w = %d, h = %d, output_canvas = %x\n\n",
output->width, output->height, output_canvas);
pr_info("%s:node->id = %d ,src_left = %d ,src_top = %d\n",
__func__, node->vid, src_left, src_top);
pr_info("src_width=%d ,src_height=%d ,output->frame->x=%d\n",
src_width, src_height, output->frame->x);
pr_info("output->frame->y=%d ,frame->w=%d ,frame->h=%d\n",
output->frame->y, output->frame->w, output->frame->h);
}
stretchblt_noalpha(context, src_left, src_top, src_width, src_height,
output->frame->x, output->frame->y, output->frame->w,
output->frame->h);
/* for cr of yuv420p or yuv420sp. */
if ((output->v4l2_format == V4L2_PIX_FMT_YUV420) || (output->v4l2_format
== V4L2_PIX_FMT_YVU420)) {
/* for cb. */
canvas_read((output_canvas >> 8) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 8) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(
context, src_left, src_top, src_width, src_height,
output->frame->x / 2, output->frame->y / 2,
output->frame->w / 2, output->frame->h / 2);
}
/* for cb of yuv420p or yuv420sp. */
if (output->v4l2_format == V4L2_PIX_FMT_YUV420 || output->v4l2_format
== V4L2_PIX_FMT_YVU420) {
canvas_read((output_canvas >> 16) & 0xff, &cd);
ge2d_config->dst_planes[0].addr = cd.addr;
ge2d_config->dst_planes[0].w = cd.width;
ge2d_config->dst_planes[0].h = cd.height;
ge2d_config->dst_para.canvas_index =
(output_canvas >> 16) & 0xff;
ge2d_config->dst_para.format =
GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN;
ge2d_config->dst_para.width = output->width / 2;
ge2d_config->dst_para.height = output->height / 2;
ge2d_config->dst_xy_swap = 0;
if (current_mirror == 1) {
ge2d_config->dst_para.x_rev = 1;
ge2d_config->dst_para.y_rev = 0;
} else if (current_mirror == 2) {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 1;
} else {
ge2d_config->dst_para.x_rev = 0;
ge2d_config->dst_para.y_rev = 0;
}
if (cur_angle == 90) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.x_rev ^= 1;
} else if (cur_angle == 180) {
ge2d_config->dst_para.x_rev ^= 1;
ge2d_config->dst_para.y_rev ^= 1;
} else if (cur_angle == 270) {
ge2d_config->dst_xy_swap = 1;
ge2d_config->dst_para.y_rev ^= 1;
}
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
pr_err("++ge2d configing error.\n");
return -1;
}
stretchblt_noalpha(context,
src_left, src_top, src_width, src_height,
output->frame->x / 2, output->frame->y / 2,
output->frame->w / 2, output->frame->h / 2);
}
return output_canvas;
}
static int amlvideo2_fillbuff(struct amlvideo2_fh *fh,
struct amlvideo2_node_buffer *buf,
struct vframe_s *vf)
{
struct config_para_ex_s ge2d_config;
struct amlvideo2_output output;
struct amlvideo2_node *node = fh->node;
void *vbuf = NULL;
int src_canvas = -1;
int ge2d_proc = 0;
vbuf = (void *)videobuf_to_res(&buf->vb);
dpr_err(node->vid_dev, 1, "%s\n", __func__);
if ((!vbuf) || (!vf))
return -1;
/* memset(&ge2d_config,0,sizeof(struct config_para_ex_s)); */
memset(&output, 0, sizeof(struct amlvideo2_output));
output.v4l2_format = fh->fmt->fourcc;
output.vbuf = vbuf;
output.width = buf->vb.width;
output.height = buf->vb.height;
output.canvas_id = buf->canvas_id;
output.angle = node->qctl_regs[0];
output.frame = &buf->axis;
output.info.mode = node->mode;
memcpy(&output.info.display_info, &(node->display_info),
sizeof(struct vdisplay_info_s));
if (output.canvas_id == 0) {
output.canvas_id = get_amlvideo2_canvas_index(
&output, (node->vid == 0) ?
(AMLVIDEO2_RES0_CANVAS_INDEX + buf->vb.i * 3) :
(AMLVIDEO2_RES1_CANVAS_INDEX + buf->vb.i * 3));
buf->canvas_id = output.canvas_id;
}
switch (output.v4l2_format) {
case V4L2_PIX_FMT_RGB565X:
case V4L2_PIX_FMT_YUV444:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
ge2d_proc = 1;
break;
default:
break;
}
src_canvas = vf->canvas0Addr;
if (ge2d_proc) {
if ((vf->type & VIDTYPE_INTERLACE_BOTTOM) || (vf->type
& VIDTYPE_INTERLACE_TOP)) {
if (vf->canvas0Addr == vf->canvas1Addr) {
if ((node->p_type == AML_PROVIDE_VDIN0) &&
(node->porttype == TVIN_PORT_VIU1)) {
src_canvas =
amlvideo2_ge2d_interlace_vdindata_process(
vf, node->context, &ge2d_config,
&output, node);
} else if ((vf->type & VIDTYPE_VIU_NV21) &&
(node->p_type == AML_PROVIDE_DECODE)) {
src_canvas =
amlvideo2_ge2d_interlace_dtv_process(
vf, node->context, &ge2d_config,
&output, node);
} else {
src_canvas =
amlvideo2_ge2d_interlace_one_canvasAddr_process(
vf, node->context, &ge2d_config,
&output, node);
}
} else {
src_canvas =
amlvideo2_ge2d_interlace_two_canvasAddr_process(
vf, node->context, &ge2d_config,
&output, node);
}
} else {
if (node->ge2d_multi_process_flag)
src_canvas = amlvideo2_ge2d_multi_pre_process(
vf, node->context,
&ge2d_config, &output, node);
else
src_canvas = amlvideo2_ge2d_pre_process(
vf, node->context,
&ge2d_config, &output, node);
}
}
buf->vb.state = VIDEOBUF_DONE;
/* do_gettimeofday(&buf->vb.ts); */
return 0;
}
static unsigned int print_ivals;
module_param(print_ivals, uint, 0644);
MODULE_PARM_DESC(print_ivals, "print current intervals!!");
#define TEST_LATENCY
#ifdef TEST_LATENCY
static unsigned int print_latecny;
module_param(print_latecny, uint, 0644);
MODULE_PARM_DESC(print_latecny, "print current latency!!");
#endif
/* ------------------------------------------------------------------
* queue operations
* ------------------------------------------------------------------
*/
void vf_inqueue(struct vframe_s *vf, struct amlvideo2_node *node)
{
struct vframe_receiver_s *vfp;
const char *name = node->recv.name;
if (vf == NULL)
return;
vfp = vf_get_receiver(name);
if (vfp == NULL) {
vf_put(vf, name);
return;
}
vfq_push(&node->q_ready, vf);
vf_notify_receiver(
name,
VFRAME_EVENT_PROVIDER_VFRAME_READY,
NULL);
}
static int amlvideo2_thread_tick(struct amlvideo2_fh *fh)
{
struct amlvideo2_node_buffer *buf = NULL;
struct amlvideo2_node *node = fh->node;
struct amlvideo2_node_dmaqueue *dma_q = &node->vidq;
unsigned int diff = 0;
bool no_frame = false;
struct vframe_s *vf = NULL;
unsigned long flags = 0;
int active_duration = 0;
int i_ret = 0;
dpr_err(node->vid_dev, 1, "Thread tick\n");
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("Enter amlvideo2.0 thread tick\n");
else
pr_info("Enter amlvideo2.1 thread tick\n");
}
if (kthread_should_stop()) {
if (amlvideo2_dbg_en & 2)
pr_info("amlvideo2 thread stop\n");
return 0;
}
i_ret = wait_event_interruptible_timeout(
dma_q->wq,
((vf_peek(node->recv.name) != NULL)
&& (node->provide_ready)) || (node->vidq.task_running == 0),
msecs_to_jiffies(5000));
if (i_ret == 0 || node->vidq.task_running == 0) {
if (node->pflag)
complete(&node->plug_sema);
return 0;
}
if ((node->r_type != AML_RECEIVER_NONE) &&
vfq_full(&node->q_ready)) {
if (amlvideo2_dbg_en & 2)
pr_info("q_ready full ,receiver is none\n");
return -1;
}
if ((node->video_blocking) && (node->amlvideo2_pool_ready != NULL)) {
vfq_init(&node->q_ready,
node->amlvideo2_pool_size,
(struct vframe_s **)&(node->amlvideo2_pool_ready[0]));
node->video_blocking = false;
node->tmp_vf = NULL;
pr_err("video blocking need to reset@!!!!!\n");
return 0;
}
if (!fh->is_streamed_on) {
dpr_err(node->vid_dev, 1, "dev doesn't stream on\n");
if (node->r_type != AML_RECEIVER_NONE) {
if (node->tmp_vf) {
vf_inqueue(node->tmp_vf, node);
node->tmp_vf = NULL;
}
} else {
node->tmp_vf = NULL;
}
while (vf_peek(node->recv.name) &&
(!vfq_full(&node->q_ready))) {
if (amlvideo2_dbg_en & 2)
pr_info("while 1.\n");
vf = vf_get(node->recv.name);
vf_inqueue(vf, node);
if (vf) {
fh->src_width = vf->width;
fh->src_height = vf->height;
}
}
return 0;
}
if (!node->provide_ready) {
if (amlvideo2_dbg_en & 2)
pr_info("provide is not ready .\n");
dpr_err(node->vid_dev, 1, "provide is not ready\n");
if (node->pflag)
complete(&node->plug_sema);
return -1;
}
if (node->pflag) {
complete(&node->plug_sema);
return 0;
}
if (amlvideo2_dbg_en & 2)
pr_info("start spin_lock_irqsave.\n");
spin_lock_irqsave(&node->slock, flags);
if (list_empty(&dma_q->active)) {
if (amlvideo2_dbg_en & 2)
pr_info("No active queue to serve .\n");
dpr_err(node->vid_dev, 1, "No active queue to serve\n");
while (vf_peek(node->recv.name) &&
(!vfq_full(&node->q_ready))) {
if (amlvideo2_dbg_en & 2)
pr_info("while 2.\n");
vf = vf_get(node->recv.name);
vf_inqueue(vf, node);
}
goto unlock;
}
if (amlvideo2_dbg_en & 2)
pr_info(" spin_lock_irqsave 1 .\n");
buf = list_entry(
dma_q->active.next,
struct amlvideo2_node_buffer,
vb.queue);
if (amlvideo2_dbg_en & 2)
pr_info("ready videobuf to fill data .\n");
if (vf_peek(node->recv.name) == NULL) {
no_frame = true;
} else {
/* drop the frame to get the last one */
if (!vfq_full(&node->q_ready)) {
vf = vf_get(node->recv.name);
if ((vf != NULL) && ((vf->type & VIDTYPE_TYPEMASK)
== VIDTYPE_INTERLACE_TOP) &&
(node->field_flag)) {
node->field_flag = false;
node->field_condition_flag = true;
}
while ((vf_peek(node->recv.name) != NULL)
&& (!node->field_condition_flag)) {
if (amlvideo2_dbg_en & 2)
pr_info("while 3.\n");
vf_inqueue(vf, node);
if (!vfq_full(&node->q_ready)) {
vf = vf_get(node->recv.name);
if ((vf != NULL) &&
((vf->type & VIDTYPE_TYPEMASK)
== VIDTYPE_INTERLACE_TOP) &&
(node->field_flag)) {
node->field_flag = false;
break;
}
} else
break;
}
if (vf != NULL) {
if (((vf->type & VIDTYPE_TYPEMASK)
== VIDTYPE_INTERLACE_BOTTOM) &&
(vf->canvas0Addr == vf->canvas1Addr)) {
vf_inqueue(vf, node);
no_frame = true;
vf = NULL;
node->field_flag = true;
}
}
}
node->field_condition_flag = false;
}
#ifdef USE_VDIN_PTS
if (no_frame)
goto unlock;
if (node->frame_inittime == 1) {
if (node->tmp_vf) {
vf_inqueue(node->tmp_vf, node);
node->tmp_vf = NULL;
}
node->frameInv_adjust = 0;
node->frameInv = 0;
node->thread_ts1.tv_sec = vf->pts_us64 & 0xFFFFFFFF;
node->thread_ts1.tv_usec = vf->pts;
node->frame_inittime = 0;
} else {
diff = (vf->pts_us64 & 0xFFFFFFFF) - node->thread_ts1.tv_sec;
diff = diff*1000000 + vf->pts - node->thread_ts1.tv_usec;
if (diff < (int) fh->frm_save_time_us) {
vf_inqueue(vf, node);
goto unlock;
}
}
#else
if (node->frame_inittime == 1) {
if (node->tmp_vf) {
vf_inqueue(node->tmp_vf, node);
node->tmp_vf = NULL;
}
if (no_frame)
goto unlock;
node->frameInv_adjust = 0;
node->frameInv = 0;
do_gettimeofday(&node->thread_ts1);
node->frame_inittime = 0;
} else {
do_gettimeofday(&node->thread_ts2);
/* thread_ts2.tv_sec = vf->pts_us64& 0xFFFFFFFF; */
/* thread_ts2.tv_usec = vf->pts; */
diff = node->thread_ts2.tv_sec - node->thread_ts1.tv_sec;
diff = diff * 1000000 + node->thread_ts2.tv_usec -
node->thread_ts1.tv_usec;
node->frameInv += diff;
memcpy(&node->thread_ts1, &node->thread_ts2,
sizeof(struct timeval));
active_duration = node->frameInv - node->frameInv_adjust;
/* Fill buffer */
if (active_duration + 5000 > (int)fh->frm_save_time_us) {
/* ||(active_duration > (int)fh->frm_save_time_us) */
if (vf) {
if (node->tmp_vf != NULL)
vf_inqueue(node->tmp_vf, node);
node->tmp_vf = NULL;
} else if (node->tmp_vf) {
vf = node->tmp_vf;
node->tmp_vf = NULL;
} else {
goto unlock;
}
} else {
if (vf) {
if (node->tmp_vf != NULL)
vf_inqueue(node->tmp_vf, node);
node->tmp_vf = vf;
}
goto unlock;
}
}
while (active_duration >= (int)fh->frm_save_time_us) {
if (amlvideo2_dbg_en & 2)
pr_info("while 4.\n");
active_duration -= fh->frm_save_time_us;
}
if ((active_duration + 5000) > fh->frm_save_time_us)
node->frameInv_adjust = fh->frm_save_time_us - active_duration;
else
node->frameInv_adjust = -active_duration;
node->frameInv = 0;
#endif
if (amlvideo2_dbg_en & 2)
pr_info(" spin_lock_irqsave 2 .\n");
buf->vb.state = VIDEOBUF_ACTIVE;
list_del(&buf->vb.queue);
spin_unlock_irqrestore(&node->slock, flags);
if (amlvideo2_dbg_en & 2)
pr_info("finish spin_lock_irqsave.\n");
/* test latency */
#ifdef TEST_LATENCY
if (print_latecny) {
int timeNow64, timePts;
do_gettimeofday(&node->latency_info.test_time);
timeNow64 = ((node->latency_info.test_time.tv_sec &
0xFFFFFFFF) * 1000 * 1000)
+ (node->latency_info.test_time.tv_usec);
/* timePts = ((vf->pts_us64
* & 0xFFFFFFFF)*1000*1000) + (vf->pts);
*/
timePts = ((node->thread_ts2.tv_sec & 0xFFFFFFFF) * 1000 * 1000)
+ (node->thread_ts2.tv_usec);
/* pr_err("amlvideo2 in num:%d delay:%d\n",
* timePts, (timeNow64 - timePts)/1000);
*/
if (node->latency_info.cur_time ==
node->latency_info.test_time.tv_sec) {
node->latency_info.total_latency +=
(int)((timeNow64 - timePts) / 1000);
node->latency_info.frame_num++;
} else {
node->latency_info.total_latency +=
(int)((timeNow64 - timePts) / 1000);
node->latency_info.frame_num++;
pr_err("amvideo2 in latency:%d frame_num:%d\n",
node->latency_info.total_latency /
node->latency_info.frame_num,
node->latency_info.frame_num);
node->latency_info.total_latency = 0;
node->latency_info.frame_num = 0;
node->latency_info.cur_time =
node->latency_info.test_time.tv_sec;
}
}
#endif
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 fillbuff start .\n");
else
pr_info("node1 fillbuff start .\n");
}
amlvideo2_fillbuff(fh, buf, vf);
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 fillbuff end .\n");
else
pr_info("node1 fillbuff end .\n");
}
#ifdef USE_VDIN_PTS
buf->vb.ts.tv_sec = vf->pts_us64 & 0xFFFFFFFF;
buf->vb.ts.tv_usec = vf->pts;
node->thread_ts1.tv_sec = vf->pts_us64 & 0xFFFFFFFF;
node->thread_ts1.tv_usec = vf->pts;
#else
buf->vb.ts.tv_sec = node->thread_ts2.tv_sec & 0xFFFFFFFF;
buf->vb.ts.tv_usec = node->thread_ts2.tv_usec;
#endif
vf_inqueue(vf, node);
while ((vf_peek(node->recv.name) != NULL) &&
(!vfq_full(&node->q_ready))) {
if (amlvideo2_dbg_en & 2)
pr_info("while 5.\n");
vf = vf_get(node->recv.name);
vf_inqueue(vf, node);
}
dpr_err(node->vid_dev, 1, "filled buffer %p\n", buf);
/*wait up vb done buffer workqueue*/
if (waitqueue_active(&buf->vb.done))
wake_up(&buf->vb.done);
if (node->pflag) {
complete(&node->plug_sema);
return 0;
}
if (amlvideo2_dbg_en & 2)
pr_info("filled buffer %p\n", buf);
/* test latency */
#ifdef TEST_LATENCY
if (print_latecny) {
int timeNow64_out, timePts_out;
do_gettimeofday(&node->latency_info.test_time);
timeNow64_out = ((node->latency_info.test_time.tv_sec &
0xFFFFFFFF) * 1000 * 1000)
+ (node->latency_info.test_time.tv_usec);
timePts_out = ((buf->vb.ts.tv_sec & 0xFFFFFFFF) * 1000 * 1000)
+ (buf->vb.ts.tv_usec);
/* pr_err("amlvideo2 out num:%d delay:%d\n",
* timePts_out, (timeNow64_out - timePts_out)/1000);
*/
if (node->latency_info.cur_time_out ==
node->latency_info.test_time.tv_sec) {
node->latency_info.total_latency_out +=
(timeNow64_out - timePts_out) / 1000;
node->latency_info.frame_num_out++;
} else {
node->latency_info.total_latency_out +=
(timeNow64_out - timePts_out) / 1000;
node->latency_info.frame_num_out++;
pr_err("amvideo2 out latency:%d frame_num_out:%d\n",
node->latency_info.total_latency_out /
node->latency_info.frame_num_out,
node->latency_info.frame_num_out);
node->latency_info.total_latency_out = 0;
node->latency_info.frame_num_out = 0;
node->latency_info.cur_time_out =
node->latency_info.test_time.tv_sec;
}
}
#endif
dpr_err(node->vid_dev, 2, "[%p/%d] wakeup\n", buf, buf->vb.i);
return 0;
unlock: spin_unlock_irqrestore(&node->slock, flags);
if (amlvideo2_dbg_en & 2)
pr_info("unlock finish\n");
if (node->pflag)
complete(&node->plug_sema);
return 0;
}
static void amlvideo2_sleep(struct amlvideo2_fh *fh)
{
/* struct amlvideo2_node *node = fh->node; */
/* struct amlvideo2_node_dmaqueue *dma_q = &node->vidq; */
/* DECLARE_WAITQUEUE(wait, current); */
/* dpr_err(node->vid_dev, 1, "%s dma_q=0x%08lx\n", __func__, */
/* (unsigned long)dma_q); */
/* add_wait_queue(&dma_q->wq, &wait); */
/* if (kthread_should_stop()) */
/* goto stop_task; */
/* Calculate time to wake up */
/* timeout = msecs_to_jiffies(frames_to_ms(1)); */
if (amlvideo2_thread_tick(fh) < 0)
schedule_timeout_interruptible(1);
/* stop_task: */
/* remove_wait_queue(&dma_q->wq, &wait); */
try_to_freeze();
}
static int amlvideo2_thread(void *data)
{
struct amlvideo2_fh *fh = data;
struct amlvideo2_node *node = fh->node;
struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
int ret = 0;
sched_setscheduler(current, SCHED_FIFO, &param);
allow_signal(SIGTERM);
if (amlvideo2_dbg_en) {
if (node->vid == 0)
pr_info("start amlvideo2.0 thread.\n");
else
pr_info("start amlvideo2.1 thread.\n");
}
dpr_err(node->vid_dev, 1, "thread started\n");
set_freezable();
while (1) {
if (kthread_should_stop()) {
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 kthread stop 1.\n");
else
pr_info("node1 kthread stop 1.\n");
}
break;
}
#ifdef USE_SEMA_QBUF
ret = wake_up_interruptible(&node->vidq.qbuf_comp);
#endif
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 task_running = %d\n",
node->vidq.task_running);
else
pr_info("node1 task_running = %d\n",
node->vidq.task_running);
}
if (!node->vidq.task_running) {
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 here break.\n");
else
pr_info("node1 here break.\n");
}
break;
}
amlvideo2_sleep(fh);
if (kthread_should_stop()) {
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("node0 kthread stop 2.\n");
else
pr_info("node1 kthread stop 2.\n");
}
break;
}
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("amlvideo2.0_thread while 1 .\n");
else
pr_info("amlvideo2.1_thread while 1 .\n");
}
}
while (!kthread_should_stop()) {
if (amlvideo2_dbg_en & 2) {
if (node->vid == 0)
pr_info("amlvideo2.0_thread while 2 .\n");
else
pr_info("amlvideo2.1_thread while 2 .\n");
}
usleep_range(9000, 10000);
}
/*msleep(10);*/
node->tmp_vf = NULL;
if (amlvideo2_dbg_en) {
if (node->vid == 0)
pr_info("amlvideo2.0 thread exit.\n");
else
pr_info("amlvideo2.1 thread exit.\n");
}
dpr_err(node->vid_dev, 1, "thread: exit\n");
return ret;
}
static int amlvideo2_start_thread(struct amlvideo2_fh *fh)
{
struct amlvideo2_node *node = fh->node;
struct amlvideo2_node_dmaqueue *dma_q = &node->vidq;
#ifdef USE_SEMA_QBUF
init_completion(&dma_q->qbuf_comp);
#endif
dpr_err(node->vid_dev, 1, "%s\n", __func__);
if (amlvideo2_dbg_en & 1)
pr_info("begin amlvideo2_start_thread\n");
mutex_lock(&node->mutex);
if (dma_q->task_running) {
mutex_unlock(&node->mutex);
return 0;
}
fh->src_width = 0;
fh->src_height = 0;
node->tmp_vf = NULL;
dma_q->task_running = 1;
#ifdef MULTI_NODE
dma_q->kthread =
kthread_run(amlvideo2_thread, fh,
(node->vid == 0)?"amlvideo2.0":"amlvideo2.1");
#else
dma_q->kthread = kthread_run(amlvideo2_thread, fh, "amlvideo2.0");
#endif
if (IS_ERR(dma_q->kthread)) {
v4l2_err(&node->vid_dev->v4l2_dev, "kernel_thread() failed\n");
dma_q->task_running = 0;
dma_q->kthread = NULL;
mutex_unlock(&node->mutex);
pr_info("start thread error.....\n");
return PTR_ERR(dma_q->kthread);
}
mutex_unlock(&node->mutex);
if (amlvideo2_dbg_en & 1)
pr_info("success create amlvideo2 thread .\n");
/* Wakes thread */
/* wake_up_interruptible(&dma_q->wq); */
dpr_err(node->vid_dev, 1, "returning from %s\n", __func__);
return 0;
}
static void amlvideo2_stop_thread(struct amlvideo2_node_dmaqueue *dma_q)
{
int ret = 0;
struct amlvideo2_node *node =
container_of(dma_q, struct amlvideo2_node, vidq);
dpr_err(node->vid_dev, 1, "%s\n", __func__);
if (amlvideo2_dbg_en & 1) {
if (node->vid == 0)
pr_info("begin to stop amlvideo2.0 thread\n");
else
pr_info("begin to stop amlvideo2.1 thread\n");
}
mutex_lock(&node->mutex);
/* shutdown control thread */
if (!IS_ERR(dma_q->kthread)) {
dma_q->task_running = 0;
send_sig(SIGTERM, dma_q->kthread, 1);
#ifdef USE_SEMA_QBUF
complete(&dma_q->qbuf_comp);
#endif
complete(&node->plug_sema);
wake_up_interruptible(&dma_q->wq);
if (amlvideo2_dbg_en & 1) {
if (node->vid == 0)
pr_info("ready to stop amlvideo2.0 thread\n");
else
pr_info("ready to stop amlvideo2.1 thread\n");
}
ret = kthread_stop(dma_q->kthread);
if (ret < 0)
pr_info("%s, ret = %d .\n", __func__, ret);
dma_q->kthread = NULL;
}
mutex_unlock(&node->mutex);
if (amlvideo2_dbg_en & 1) {
if (node->vid == 0)
pr_info("finish stop amlvideo2.0 thread\n");
else
pr_info("finish stop amlvideo2.1 thread\n");
}
}
enum aml_provider_type_e get_provider_type(const char *name)
{
enum aml_provider_type_e type = AML_PROVIDE_NONE;
if (!name)
return type;
if (strncasecmp(name, "vdin0", 5) == 0)
type = AML_PROVIDE_VDIN0;
else if (strncasecmp(name, "vdin1", 5) == 0)
type = AML_PROVIDE_VDIN1;
else if (strncasecmp(name, "decoder", 7) == 0)
type = AML_PROVIDE_DECODE;
else if (strncasecmp(name, "ppmgr", 5) == 0)
type = AML_PROVIDE_PPMGR;
else
type = AML_PROVIDE_MAX;
return type;
}
enum aml_receiver_type_e get_sub_receiver_type(const char *name)
{
enum aml_receiver_type_e type = AML_RECEIVER_NONE;
if (!name)
return type;
if (strncasecmp(name, "ppmgr", 5) == 0) {
type = AML_RECEIVER_PPMGR;
if (amlvideo2_dbg_en)
pr_info("type is ppmgr");
} else if (strncasecmp(name, "deinterlace", 11) == 0) {
type = AML_RECEIVER_DI;
if (amlvideo2_dbg_en)
pr_info("type is deinterlace");
} else {
type = AML_RECEIVER_MAX;
if (amlvideo2_dbg_en)
pr_info("type is not certain\n");
}
return type;
}
/* ------------------------------------------------------------------
* provider operations
* ------------------------------------------------------------------
*/
static struct vframe_s *amlvideo2_vf_peek(void *op_arg)
{
struct amlvideo2_node *node = (struct amlvideo2_node *)op_arg;
if (node->video_blocking)
return NULL;
if (amlvideo2_dbg_en & 8)
pr_info("amlvideo2 vf peek .\n");
return vfq_peek(&node->q_ready);
}
static struct vframe_s *amlvideo2_vf_get(void *op_arg)
{
struct vframe_s *vf = NULL;
struct amlvideo2_node *node = (struct amlvideo2_node *)op_arg;
if (node->video_blocking)
return NULL;
if (amlvideo2_dbg_en & 8)
pr_info("amlvideo2 vf get .\n");
vf = vfq_pop(&node->q_ready);
return vf;
}
static void amlvideo2_vf_put(struct vframe_s *vf, void *op_arg)
{
struct amlvideo2_node *node = (struct amlvideo2_node *)op_arg;
char *name = (node->vid == 0) ? DEVICE_NAME0 : DEVICE_NAME1;
if (node->video_blocking)
return;
if (amlvideo2_dbg_en & 8)
pr_info("amlvideo2 vf put .\n");
vf_put(vf, name);
}
static int amlvideo2_event_cb(int type, void *data, void *private_data)
{
if (type & VFRAME_EVENT_RECEIVER_PUT) {
/* pr_err("video put, avail=%d\n", vfq_level(&q_ready) ); */
} else if (type & VFRAME_EVENT_RECEIVER_GET) {
/* pr_err("video get, avail=%d\n", vfq_level(&q_ready) ); */
} else if (type & VFRAME_EVENT_RECEIVER_FRAME_WAIT) {
/* up(&thread_sem); */
pr_err("receiver is waiting\n");
} else if (type & VFRAME_EVENT_RECEIVER_FRAME_WAIT) {
pr_err("frame wait\n");
}
return 0;
}
static int amlvideo2_vf_states(struct vframe_states *states, void *op_arg)
{
/* unsigned long flags; */
/* spin_lock_irqsave(&lock, flags); */
struct amlvideo2_node *node = (struct amlvideo2_node *)op_arg;
states->vf_pool_size = node->amlvideo2_pool_size;
states->buf_recycle_num = 0;
states->buf_free_num = node->amlvideo2_pool_size -
vfq_level(&node->q_ready);
states->buf_avail_num = vfq_level(&node->q_ready);
/* spin_unlock_irqrestore(&lock, flags); */
return 0;
}
static const struct vframe_operations_s amlvideo2_vf_provider = {
.peek = amlvideo2_vf_peek,
.get = amlvideo2_vf_get,
.put = amlvideo2_vf_put,
.event_cb = amlvideo2_event_cb,
.vf_states = amlvideo2_vf_states, };
/* ------------------------------------------------------------------
* Videobuf operations
* ------------------------------------------------------------------
*/
static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct videobuf_res_privdata *res = (struct videobuf_res_privdata *)vq
->priv_data;
struct amlvideo2_fh *fh = (struct amlvideo2_fh *)res->priv;
struct amlvideo2_node *node = fh->node;
int height = fh->height;
if (height % 16 != 0)
height = ((height + 15) >> 4) << 4;
*size = (fh->width * height * fh->fmt->depth) >> 3;
if (*count == 0)
*count = 32;
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
dpr_err(
node->vid_dev, 1,
"%s, count=%d, size=%d\n", __func__, *count, *size);
return 0;
}
static void free_buffer(struct videobuf_queue *vq,
struct amlvideo2_node_buffer *buf)
{
struct videobuf_res_privdata *res = (struct videobuf_res_privdata *)vq
->priv_data;
struct amlvideo2_fh *fh = (struct amlvideo2_fh *)res->priv;
struct amlvideo2_node *node = fh->node;
dpr_err(node->vid_dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
videobuf_waiton(vq, &buf->vb, 0, 0);
if (in_interrupt())
WARN_ON(1);
videobuf_res_free(vq, &buf->vb);
dpr_err(node->vid_dev, 1, "free_buffer: freed\n");
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
#define norm_maxw() 2000
#define norm_maxh() 1600
static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct videobuf_res_privdata *res = (struct videobuf_res_privdata *)vq
->priv_data;
struct amlvideo2_fh *fh = (struct amlvideo2_fh *)res->priv;
struct amlvideo2_node *node = fh->node;
struct amlvideo2_node_buffer *buf = container_of(
vb, struct amlvideo2_node_buffer, vb);
int rc;
dpr_err(node->vid_dev, 1, "%s, field=%d\n", __func__, field);
WARN_ON(fh->fmt == NULL);
if (fh->width < 16 || fh->width > norm_maxw() ||
fh->height < 16 || fh->height > norm_maxh())
return -EINVAL;
buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
return -EINVAL;
/* These properties only change when queue is idle, see s_fmt */
buf->fmt = fh->fmt;
buf->vb.width = fh->width;
buf->vb.height = fh->height;
buf->vb.field = field;
if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
rc = videobuf_iolock(vq, &buf->vb, NULL);
if (rc < 0)
goto fail;
}
buf->vb.state = VIDEOBUF_PREPARED;
return 0;
fail: free_buffer(vq, buf);
return rc;
}
static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
struct amlvideo2_node_buffer *buf = container_of(
vb, struct amlvideo2_node_buffer, vb);
struct videobuf_res_privdata *res = (struct videobuf_res_privdata *)vq
->priv_data;
struct amlvideo2_fh *fh = (struct amlvideo2_fh *)res->priv;
struct amlvideo2_node *node = fh->node;
struct amlvideo2_node_dmaqueue *vidq = &node->vidq;
dpr_err(node->vid_dev, 1, "%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &vidq->active);
}
static void buffer_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
struct amlvideo2_node_buffer *buf = container_of(
vb, struct amlvideo2_node_buffer, vb);
free_buffer(vq, buf);
}
static struct videobuf_queue_ops amlvideo2_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release, };
/* ------------------------------------------------------------------
* IOCTL vidioc handling
* ------------------------------------------------------------------
*/
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
strcpy(cap->driver, "amlvideo2");
strcpy(cap->card, "amlvideo2");
strlcpy(
cap->bus_info,
node->vid_dev->v4l2_dev.name,
sizeof(cap->bus_info));
cap->version = AMLVIDEO2_VERSION;
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE;
cap->capabilities = cap->device_caps
|V4L2_CAP_DEVICE_CAPS
|V4L2_CAP_STREAMING
| V4L2_CAP_READWRITE;
return 0;
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct amlvideo2_fmt *fmt;
if (f->index >= ARRAY_SIZE(formats))
return -EINVAL;
fmt = &formats[f->index];
strlcpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct amlvideo2_fh *fh = priv;
if (fh->set_format_flag) {
f->fmt.pix.width = fh->width;
f->fmt.pix.height = fh->height;
f->fmt.pix.field = fh->vb_vidq.field;
f->fmt.pix.pixelformat = fh->fmt->fourcc;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fh->fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
} else {
if ((fh->node->start_vdin_flag) && (fh->node->provide_ready)) {
const struct vinfo_s *vinfo;
vinfo = get_current_vinfo();
f->fmt.pix.width = vinfo->width;
f->fmt.pix.height = vinfo->height;
} else if (fh->node->provide_ready) {
f->fmt.pix.width = fh->src_width;
f->fmt.pix.height = fh->src_height;
} else {
f->fmt.pix.width = 0;
f->fmt.pix.height = 0;
}
}
return 0;
}
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
struct amlvideo2_fmt *fmt = NULL;
enum v4l2_field field;
unsigned int maxw, maxh;
fmt = get_format(f);
if (!fmt) {
dpr_err(node->vid_dev, 1, "Fourcc format (0x%08x) invalid.\n",
f->fmt.pix.pixelformat);
return -EINVAL;
}
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
field = V4L2_FIELD_INTERLACED;
} else if (field != V4L2_FIELD_INTERLACED) {
dpr_err(node->vid_dev, 1, "Field type invalid.\n");
return -EINVAL;
}
maxw = norm_maxw();
maxh = norm_maxh();
f->fmt.pix.field = field;
v4l_bound_align_image(
&f->fmt.pix.width, 16,
maxw, 2, &f->fmt.pix.height, 16,
maxh, 0, 0);
f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}
/*FIXME: This seems to be generic enough to be at videodev2 */
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
int ret = 0;
struct amlvideo2_fh *fh = priv;
struct videobuf_queue *q = &fh->vb_vidq;
f->fmt.pix.width = (f->fmt.pix.width + (CANVAS_WIDTH_ALIGN-1)) &
(~(CANVAS_WIDTH_ALIGN-1));
if ((f->fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) ||
(f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)) {
f->fmt.pix.width =
(f->fmt.pix.width + (CANVAS_WIDTH_ALIGN*2-1)) &
(~(CANVAS_WIDTH_ALIGN*2-1));
}
ret = vidioc_try_fmt_vid_cap(file, fh, f);
if (ret < 0)
return ret;
mutex_lock(&q->vb_lock);
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
dpr_err(fh->node->vid_dev, 1, "%s queue busy\n", __func__);
ret = -EBUSY;
goto out;
}
fh->fmt = get_format(f);
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
fh->set_format_flag = true;
ret = 0;
out: mutex_unlock(&q->vb_lock);
return ret;
}
/*
* Implement G/S_PARM. There is a "high quality" mode we could try
* to do someday; for now, we just do the frame rate tweak.
* V4L2_CAP_TIMEPERFRAME need to be supported furthermore.
*/
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *parms)
{
struct v4l2_captureparm *cp = &parms->parm.capture;
pr_err("vidioc_g_parm\n");
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(cp, 0, sizeof(struct v4l2_captureparm));
cp->capability = V4L2_CAP_TIMEPERFRAME;
cp->timeperframe = amlvideo2_frmintervals_active;
pr_err("g_parm,deno=%d, numerator=%d\n", cp->timeperframe.denominator,
cp->timeperframe.numerator);
return 0;
}
static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *parms)
{
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
suseconds_t def_ival = 1000000 / DEF_FRAMERATE;
suseconds_t ival; /* us */
/*save the frame period. */
if (parms->parm.capture.timeperframe.denominator == 0) {
fh->frm_save_time_us = def_ival;
amlvideo2_frmintervals_active.numerator = 1;
amlvideo2_frmintervals_active.denominator = DEF_FRAMERATE;
return -EINVAL;
}
ival = parms->parm.capture.timeperframe.numerator * 1000000
/ parms->parm.capture.timeperframe.denominator;
fh->frm_save_time_us = ival;
amlvideo2_frmintervals_active = parms->parm.capture.timeperframe;
dpr_err(
node->vid_dev, 1,
"%s,%d,type=%d\n",
__func__, __LINE__, parms->type);
dpr_err(node->vid_dev, 1, "setting framerate:%d/%d(fps)\n",
amlvideo2_frmintervals_active.denominator,
amlvideo2_frmintervals_active.numerator);
return 0;
}
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct amlvideo2_fh *fh = priv;
#ifdef USE_SEMA_QBUF
struct amlvideo2_node *node = fh->node;
struct amlvideo2_node_dmaqueue *dma_q = &node->vidq;
init_completion(&dma_q->qbuf_comp);
#endif
return videobuf_reqbufs(&fh->vb_vidq, p);
}
static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct amlvideo2_fh *fh = priv;
int ret = videobuf_querybuf(&fh->vb_vidq, p);
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
#if 1
if (ret == 0) {
struct amlvideo2_output output;
memset(&output, 0, sizeof(struct amlvideo2_output));
output.v4l2_format = fh->fmt->fourcc;
output.vbuf = NULL;
output.width = fh->width;
output.height = fh->height;
output.canvas_id = -1;
p->reserved = convert_canvas_index(
&output, fh->node->vid == 0 ?
(AMLVIDEO2_RES0_CANVAS_INDEX + p->index * 3) :
(AMLVIDEO2_RES1_CANVAS_INDEX + p->index * 3));
} else {
p->reserved = 0;
}
#endif
return ret;
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct amlvideo2_fh *fh = priv;
#ifdef USE_SEMA_QBUF
struct amlvideo2_node *node = fh->node;
struct amlvideo2_node_dmaqueue *dma_q = &node->vidq;
#endif
int ret = videobuf_qbuf(&fh->vb_vidq, p);
#ifdef USE_SEMA_QBUF
complete(&dma_q->qbuf_comp);
#endif
return ret;
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct amlvideo2_fh *fh = priv;
int ret = videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK);
return ret;
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
{
struct amlvideo2_fh *fh = priv;
return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
}
#endif
#ifdef PREVIOUS_VOUT_MODE
static enum tvin_scan_mode_e vmode2scan_mode(enum vmode_e mode)
{
enum tvin_scan_mode_e scan_mode = TVIN_SCAN_MODE_PROGRESSIVE;
//TVIN_SCAN_MODE_NULL;/* 1: progressive 2:interlaced */
switch (mode) {
case VMODE_480I:
case VMODE_480CVBS:
case VMODE_NTSC_M:
case VMODE_576I:
case VMODE_576CVBS:
case VMODE_PAL_M:
case VMODE_PAL_N:
case VMODE_1080I:
case VMODE_1080I_50HZ:
scan_mode = TVIN_SCAN_MODE_INTERLACED;
break;
case VMODE_480P:
case VMODE_576P:
case VMODE_720P:
case VMODE_1080P:
case VMODE_720P_50HZ:
case VMODE_1080P_50HZ:
case VMODE_1080P_24HZ:
case VMODE_4K2K_30HZ:
case VMODE_4K2K_25HZ:
case VMODE_4K2K_24HZ:
case VMODE_4K2K_SMPTE:
case VMODE_VGA:
case VMODE_SVGA:
case VMODE_XGA:
case VMODE_SXGA:
case VMODE_LCD:
case VMODE_4K2K_50HZ:
case VMODE_4K2K_50HZ_Y420:
case VMODE_4K2K_60HZ:
case VMODE_4K2K_60HZ_Y420:
scan_mode = TVIN_SCAN_MODE_PROGRESSIVE;
break;
default:
pr_err("unknown mode=%d\n", mode);
break;
}
/* pr_err("mode=%d, scan_mode=%d\n", mode, scan_mode); */
return scan_mode;
}
#endif
/*the counter of AMLVIDEO2*/
#define AMLVIDEO2_MAX_NODE 2
static struct amlvideo2_node *gAmlvideo2_Node[AMLVIDEO2_MAX_NODE];
static int amlvideo2_stop_tvin_service(struct amlvideo2_node *node)
{
int ret = 0;
struct vdin_v4l2_ops_s *vops = &node->vops;
if (amlvideo2_dbg_en)
pr_info("%s , %d\n", __func__, __LINE__);
if (node->r_type == AML_RECEIVER_NONE)
amlvideo2_stop_thread(&node->vidq);
if (((node->input == 0) || (node->input == 0x1000C000)) &&
(node->r_type == AML_RECEIVER_NONE)) {
if (amlvideo2_dbg_en)
pr_info("stop tvin service .\n");
if (!(vops->stop_tvin_service)) {
pr_info("stop_tvin_service func is NULL.\n");
return -1;
}
vops->stop_tvin_service(node->vdin_device_num);
}
return ret;
}
static int amlvideo2_start_tvin_service(struct amlvideo2_node *node)
{
struct amlvideo2_fh *fh = node->fh;
struct vdin_v4l2_ops_s *vops = &node->vops;
struct vdin_parm_s para;
const struct vinfo_s *vinfo;
int dst_w, dst_h;
vinfo = get_current_vinfo();
if (node->r_type != AML_RECEIVER_NONE)
goto start;
if (amlvideo2_dbg_en)
pr_info("Enter %s .\n", __func__);
memset(&para, 0, sizeof(para));
para.port = node->porttype;
para.fmt = TVIN_SIG_FMT_MAX;
para.frame_rate = vinfo->sync_duration_num/vinfo->sync_duration_den;
para.h_active = vinfo->width;
para.v_active = vinfo->height;
para.hsync_phase = 0;
para.vsync_phase = 1;
para.hs_bp = 0;
para.vs_bp = 0;
para.dfmt = TVIN_NV21;/* TVIN_YUV422; */
#ifdef PREVIOUS_VOUT_MODE
para.scan_mode = vmode2scan_mode(
vinfo->mode);/* TVIN_SCAN_MODE_PROGRESSIVE; */
#else
if (vinfo->height == vinfo->field_height)
para.scan_mode = TVIN_SCAN_MODE_PROGRESSIVE;
else
para.scan_mode = TVIN_SCAN_MODE_INTERLACED;
#endif
if (para.scan_mode == TVIN_SCAN_MODE_INTERLACED)
para.v_active = para.v_active / 2;
dst_w = fh->width;
dst_h = fh->height;
if (vinfo->width < vinfo->height) {
if ((vinfo->width <= 768) && (vinfo->height <= 1024)) {
dst_w = vinfo->width;
dst_h = vinfo->height;
} else {
dst_w = fh->height;
dst_h = fh->width;
}
output_axis_adjust(vinfo->height, vinfo->width, (int *)&dst_h,
(int *)&dst_w, 0, NULL);
} else {
if ((vinfo->height <= 768) && (vinfo->width <= 1024)) {
dst_w = vinfo->width;
dst_h = vinfo->height;
}
output_axis_adjust(vinfo->width, vinfo->height, (int *)&dst_w,
(int *)&dst_h, 0, NULL);
}
para.dest_hactive = dst_w;
para.dest_vactive = dst_h;
if (para.scan_mode == TVIN_SCAN_MODE_INTERLACED)
para.dest_vactive = para.dest_vactive / 2;
if ((para.port == TVIN_PORT_VIU1_VIDEO) ||
(para.port == TVIN_PORT_VIU1_WB0_VD1))
para.cfmt = 1;
if (amlvideo2_dbg_en) {
pr_info("node->r_type=%d, node->p_type=%d\n",
node->r_type, node->p_type);
pr_info("para.h_active: %d, para.v_active: %d,",
para.h_active, para.v_active);
pr_info("para.dest_hactive: %d, para.dest_vactive: %d,",
para.dest_hactive, para.dest_vactive);
pr_info("fh->width: %d, fh->height: %d,",
fh->width, fh->height);
pr_info("vinfo->mode: %d,para.scan_mode: %d\n",
vinfo->mode, para.scan_mode);
pr_info("node->vdin_device_num = %d .\n",
node->vdin_device_num);
}
if (!(vops->start_tvin_service)) {
pr_info("start_tvin_service is NULL.\n");
return -1;
}
vops->start_tvin_service(node->vdin_device_num, &para);
start: node->frame_inittime = 1;
/* frameInv_adjust = 0; */
/* frameInv = 0; */
/* tmp_vf = NULL; */
do_gettimeofday(&node->thread_ts1);
return 0;
}
int amlvideo2_notify_callback(struct notifier_block *block, unsigned long cmd,
void *para)
{
struct amlvideo2_node *node = NULL;
struct vframe_s *recycle_vf = NULL;
struct vframe_states states;
struct vframe_provider_s *vfp = NULL;
int i;
int index = 0;
int ret = 0;
int i_ret = 0;
for (i = 0; i < AMLVIDEO2_MAX_NODE; i++) {
if ((gAmlvideo2_Node[i] != NULL) &&
(gAmlvideo2_Node[i]->r_type == AML_RECEIVER_NONE))
index = 1;
}
if (amlvideo2_dbg_en)
pr_info("%s , index = %d\n", __func__, index);
if (index != 1) {
if (amlvideo2_dbg_en)
pr_info("index is not right, return\n");
return ret;
}
node = gAmlvideo2_Node[index];
if (node == NULL) {
if (amlvideo2_dbg_en)
pr_info("node is NULL, return\n");
return ret;
}
if (node->vid != 1) {
if (amlvideo2_dbg_en)
pr_info("node is not right, return\n");
return ret;
}
if (!(node->users)) {
if (amlvideo2_dbg_en)
pr_info("node user not work, return\n");
return ret;
}
switch (cmd) {
case VOUT_EVENT_MODE_CHANGE:
pr_info("mode changed in amlvideo2 .\n");
vfp = vf_get_provider(node->recv.name);
if ((vfp == NULL) ||
(!node->fh->is_streamed_on)) {
pr_info("driver is not ready or not need to screencap.\n");
return ret;
}
node->pflag = true;
i_ret = wait_for_completion_timeout(&node->plug_sema,
msecs_to_jiffies(150));
if (i_ret == 0)
return 0;
if (amlvideo2_dbg_en)
pr_info("finish wait plug sema .\n");
/* if local queue have vf , should give back to provider */
if (vfq_empty(&node->q_ready)) {
if (amlvideo2_dbg_en & 4)
pr_info("q_ready is empty .\n");
} else {
recycle_vf = vfq_pop(&node->q_ready);
while (recycle_vf) {
vf_put(recycle_vf, node->recv.name);
recycle_vf = vfq_pop(&node->q_ready);
}
if (amlvideo2_dbg_en & 4)
pr_info("already flush local vf .\n");
}
/*debug provider vf state*/
if (amlvideo2_dbg_en & 4) {
ret = vf_get_states(vfp, &states);
if (ret == 0) {
pr_info("vf_pool_size = %d, buf_free_num = %d .\n",
states.vf_pool_size, states.buf_free_num);
pr_info("buf_recycle_num = %d, buf_avail_num = %d .\n",
states.buf_recycle_num, states.buf_avail_num);
}
}
ret = amlvideo2_stop_tvin_service(node);
if (ret < 0) {
pr_err("stop tvin service failed.\n");
node->pflag = false;
return ret;
}
if (node->r_type == AML_RECEIVER_NONE)
amlvideo2_start_thread(node->fh);
ret = amlvideo2_start_tvin_service(node);
if (ret < 0) {
pr_err("start tvin service failed.\n");
node->pflag = false;
return ret;
}
node->pflag = false;
break;
default:
pr_info("amlvideo2 not support vout cmd\n");
break;
}
if (amlvideo2_dbg_en)
pr_info("finish amlvideo2_notify_callback. ret = %d\n", ret);
return ret;
}
static struct notifier_block amlvideo2_notifier_nb = {
.notifier_call = amlvideo2_notify_callback,
};
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
int ret;
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
struct vdin_v4l2_ops_s *vops = &node->vops;
struct vdin_parm_s para;
const struct vinfo_s *vinfo;
int dst_w, dst_h;
vinfo = get_current_vinfo();
if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (i != fh->type))
return -EINVAL;
ret = videobuf_streamon(&fh->vb_vidq);
if (ret < 0) {
pr_err("%s, videobuf_streamon() ret: %d\n", __func__, ret);
return ret;
}
memset(&node->display_info, 0, sizeof(struct vdisplay_info_s));
if (!node->start_vdin_flag) {
ret = vf_notify_receiver_by_name("amvideo",
VFRAME_EVENT_PROVIDER_QUREY_DISPLAY_INFO,
&node->display_info);
if (ret < 0) {
pr_err("notify amvideo failed.\n");
node->mode = AML_SCREEN_MODE_RATIO;
/* AML_SCREEN_MODE_RATIO; */
} else {
node->has_amvideo_node = true;
node->mode = AML_SCREEN_MODE_ADAPTIVE;
/* AML_SCREEN_MODE_ADAPTIVE; */
if (amlvideo2_dbg_en) {
pr_info("screen:h_start = %d,h_end = %d\n",
node->display_info.screen_vd_h_start_,
node->display_info.screen_vd_h_end_);
pr_info("screen:v_start = %d,v_end = %d\n",
node->display_info.screen_vd_v_start_,
node->display_info.screen_vd_v_end_);
pr_info("display:hsc_startp=%d,hsc_endp=%d\n",
node->display_info.display_hsc_startp,
node->display_info.display_hsc_endp);
pr_info("display:vsc_startp=%d,vsc_endp=%d\n",
node->display_info.display_vsc_startp,
node->display_info.display_vsc_endp);
pr_info("frame:hd_start_lines=%d,hd_end_lines=%d\n",
node->display_info.frame_hd_start_lines_,
node->display_info.frame_hd_end_lines_);
pr_info("frame:vd_start_lines=%d,vd_end_lines=%d\n",
node->display_info.frame_vd_start_lines_,
node->display_info.frame_vd_end_lines_);
}
}
}
if (amlvideo2_dbg_en) {
pr_info("amlvideo2--vidioc_streamon .\n");
pr_info("crop_enable = %d\n",
node->crop_info.capture_crop_enable);
pr_info("node->r_type=%d, node->p_type=%d\n",
node->r_type, node->p_type);
}
if ((!node->start_vdin_flag) || (node->r_type != AML_RECEIVER_NONE))
goto start;
if (node->r_type == AML_RECEIVER_NONE)
amlvideo2_start_thread(fh);
memset(&para, 0, sizeof(para));
para.port = node->porttype;
para.fmt = TVIN_SIG_FMT_MAX;
para.frame_rate = vinfo->sync_duration_num/vinfo->sync_duration_den;
para.h_active = vinfo->width;
para.v_active = vinfo->height;
para.hsync_phase = 0;
para.vsync_phase = 1;
para.hs_bp = 0;
para.vs_bp = 0;
para.dfmt = TVIN_NV21;/* TVIN_YUV422; */
#ifdef PREVIOUS_VOUT_MODE
para.scan_mode = vmode2scan_mode(
vinfo->mode);/* TVIN_SCAN_MODE_PROGRESSIVE; */
#else
if (vinfo->height == vinfo->field_height)
para.scan_mode = TVIN_SCAN_MODE_PROGRESSIVE;
else
para.scan_mode = TVIN_SCAN_MODE_INTERLACED;
#endif
if (para.scan_mode == TVIN_SCAN_MODE_INTERLACED)
para.v_active = para.v_active / 2;
dst_w = fh->width;
dst_h = fh->height;
if (vinfo->width < vinfo->height) {
if ((vinfo->width <= 768) && (vinfo->height <= 1024)) {
dst_w = vinfo->width;
dst_h = vinfo->height;
} else {
dst_w = fh->height;
dst_h = fh->width;
}
output_axis_adjust(vinfo->height, vinfo->width, (int *)&dst_h,
(int *)&dst_w, 0, NULL);
} else {
if ((vinfo->height <= 768) && (vinfo->width <= 1024)) {
dst_w = vinfo->width;
dst_h = vinfo->height;
}
output_axis_adjust(vinfo->width, vinfo->height, (int *)&dst_w,
(int *)&dst_h, 0, NULL);
}
para.dest_hactive = dst_w;
para.dest_vactive = dst_h;
para.reserved |= PARAM_STATE_SCREENCAP;
if (para.scan_mode == TVIN_SCAN_MODE_INTERLACED)
para.dest_vactive = para.dest_vactive / 2;
if ((para.port == TVIN_PORT_VIU1_VIDEO) ||
(para.port == TVIN_PORT_VIU1_WB0_VD1)) {
if (node->ge2d_multi_process_flag) {
para.dest_hactive = 384;
para.dest_vactive = 216;
} else
para.cfmt = 1;
}
if (amlvideo2_dbg_en) {
pr_info("para.h_active: %d, para.v_active: %d,",
para.h_active, para.v_active);
pr_info("para.dest_hactive: %d, para.dest_vactive: %d,",
para.dest_hactive, para.dest_vactive);
pr_info("fh->width: %d, fh->height: %d,",
fh->width, fh->height);
pr_info("vinfo->mode: %d,para.scan_mode: %d\n",
vinfo->mode, para.scan_mode);
pr_info("node->vdin_device_num = %d .\n",
node->vdin_device_num);
}
vops->start_tvin_service(node->vdin_device_num, &para);
start: node->frame_inittime = 1;
fh->is_streamed_on = 1;
/* frameInv_adjust = 0; */
/* frameInv = 0; */
/* tmp_vf = NULL; */
do_gettimeofday(&node->thread_ts1);
#ifdef TEST_LATENCY
node->latency_info.cur_time = node->latency_info.cur_time_out =
node->thread_ts1.tv_sec;
node->latency_info.total_latency = 0;
node->latency_info.total_latency_out = 0;
#endif
return 0;
}
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
int ret;
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
struct vdin_v4l2_ops_s *vops = &node->vops;
if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || (i != fh->type))
return -EINVAL;
ret = videobuf_streamoff(&fh->vb_vidq);
if (ret < 0)
pr_err("videobuf stream off failed\n");
if (amlvideo2_dbg_en) {
pr_info("%s , %d\n", __func__, __LINE__);
pr_info("start_vdin_flag = %d\n", node->start_vdin_flag);
pr_info("node->r_type = %d, node->vid = %d\n",
node->r_type, node->vid);
pr_info("vdin_device_num = %d\n", node->vdin_device_num);
}
if ((node->start_vdin_flag) ||
(node->r_type == AML_RECEIVER_NONE)) {
if (amlvideo2_dbg_en)
pr_info("stop tvin service .\n");
vops->stop_tvin_service(node->vdin_device_num);
}
if (node->r_type == AML_RECEIVER_NONE)
amlvideo2_stop_thread(&node->vidq);
node->start_vdin_flag = 0;
fh->is_streamed_on = 0;
return ret;
}
static int vidioc_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
int ret = 0, i = 0;
struct amlvideo2_fmt *fmt = NULL;
struct v4l2_frmsize_discrete *frmsize = NULL;
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (formats[i].fourcc == fsize->pixel_format) {
fmt = &formats[i];
break;
}
}
if (fmt == NULL)
return -EINVAL;
if ((fmt->fourcc == V4L2_PIX_FMT_NV21)
|| (fmt->fourcc == V4L2_PIX_FMT_NV12)
|| (fmt->fourcc == V4L2_PIX_FMT_YUV420)
|| (fmt->fourcc == V4L2_PIX_FMT_YVU420)) {
if (fsize->index >= ARRAY_SIZE(amlvideo2_prev_resolution))
return -EINVAL;
frmsize = &amlvideo2_prev_resolution[fsize->index];
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = frmsize->width;
fsize->discrete.height = frmsize->height;
} else if ((fmt->fourcc == V4L2_PIX_FMT_RGB24) ||
(fmt->fourcc == V4L2_PIX_FMT_RGB32)) {
if (fsize->index >= ARRAY_SIZE(amlvideo2_pic_resolution))
return -EINVAL;
frmsize = &amlvideo2_pic_resolution[fsize->index];
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = frmsize->width;
fsize->discrete.height = frmsize->height;
}
return ret;
}
static int vidioc_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *fival)
{
unsigned int k;
if (fival->index > ARRAY_SIZE(amlvideo2_frmivalenum))
return -EINVAL;
for (k = 0; k < ARRAY_SIZE(amlvideo2_frmivalenum); k++) {
if ((fival->index == amlvideo2_frmivalenum[k].index)
&& (fival->pixel_format
== amlvideo2_frmivalenum[k].pixel_format)
&& (fival->width == amlvideo2_frmivalenum[k].width)
&& (fival->height
== amlvideo2_frmivalenum[k].height)) {
memcpy(fival, &amlvideo2_frmivalenum[k],
sizeof(struct v4l2_frmivalenum));
return 0;
}
}
return -EINVAL;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
{
return 0;
}
/* --- controls ---------------------------------------------- */
static int amlvideo2_setting(struct amlvideo2_node *node, int PROP_ID,
int value, int index)
{
int ret = 0;
switch (PROP_ID) {
case V4L2_CID_ROTATE:
if (node->qctl_regs[index] != value)
node->qctl_regs[index] = value;
break;
default:
ret = -1;
break;
}
return ret;
}
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
int i;
for (i = 0; i < ARRAY_SIZE(amlvideo2_node_qctrl); i++)
if (qc->id && qc->id == amlvideo2_node_qctrl[i].id) {
memcpy(qc, &(amlvideo2_node_qctrl[i]), sizeof(*qc));
return 0;
}
return -EINVAL;
}
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
*i = node->input;
return 0;
}
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
/*bit 28 : start tvin service flag, 1 : enable, 0 : disable*/
node->start_vdin_flag = (i >> 28);
/*bit 24 : vdin device num : 0 or 1 */
node->vdin_device_num = (i >> 24) & 1;
node->ge2d_multi_process_flag = (i >> 16) & 1;
node->porttype = (i & 0xffff);
if (amlvideo2_dbg_en) {
pr_info("porttype:%x ,start_vdin_flag = %d.\n",
node->porttype, node->start_vdin_flag);
pr_info("%s, vdin_device_num = %d\n",
__func__, node->vdin_device_num);
pr_info("%s, ge2d_multi_process_flag = %d\n",
__func__, node->ge2d_multi_process_flag);
}
return 0;
}
static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
int i;
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
for (i = 0; i < ARRAY_SIZE(amlvideo2_node_qctrl); i++)
if (ctrl->id == amlvideo2_node_qctrl[i].id) {
ctrl->value = node->qctl_regs[i];
return 0;
}
return -EINVAL;
}
static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
int i;
struct amlvideo2_fh *fh = priv;
struct amlvideo2_node *node = fh->node;
for (i = 0; i < ARRAY_SIZE(amlvideo2_node_qctrl); i++)
if (ctrl->id == amlvideo2_node_qctrl[i].id) {
if (ctrl->value < amlvideo2_node_qctrl[i].minimum
|| ctrl->value
> amlvideo2_node_qctrl[i].maximum
|| amlvideo2_setting(
node, ctrl->id, ctrl->value, i) < 0) {
return -ERANGE;
}
/* node->qctl_regs[i] = ctrl->value; */
return 0;
}
return -EINVAL;
}
static int vidioc_g_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
struct amlvideo2_node *node = video_drvdata(file);
a->c.top = node->crop_info.source_top_crop;
a->c.left = node->crop_info.source_left_crop;
a->c.width = node->crop_info.source_width_crop;
a->c.height = node->crop_info.source_height_crop;
return 0;
}
static int vidioc_s_crop(struct file *file, void *fh,
const struct v4l2_crop *a)
{
struct amlvideo2_node *node = video_drvdata(file);
if (a->c.width == 0 || a->c.height == 0) {
pr_info("disable capture crop\n");
node->crop_info.capture_crop_enable = 0;
node->crop_info.source_top_crop = 0;
node->crop_info.source_left_crop = 0;
node->crop_info.source_width_crop = 0;
node->crop_info.source_height_crop = 0;
} else {
node->crop_info.source_top_crop = a->c.top;
node->crop_info.source_left_crop = a->c.left;
node->crop_info.source_width_crop = a->c.width;
node->crop_info.source_height_crop = a->c.height;
node->crop_info.capture_crop_enable = 1;
}
return 0;
}
static int vidioc_s_output(struct file *file, void *fh,
unsigned int mode)
{
struct amlvideo2_node *node = video_drvdata(file);
if (mode > AML_SCREEN_MODE_MAX)
return -1;
node->mode = (enum aml_screen_mode_e)mode;
return 0;
}
int amlvideo2_cma_buf_init(struct amlvideo2_device *vid_dev, int node_id)
{
int flags;
if (!vid_dev->use_reserve) {
if (vid_dev->cma_mode == 0) {
vid_dev->cma_pages = dma_alloc_from_contiguous(
&(vid_dev->pdev->dev),
(CMA_ALLOC_SIZE*SZ_1M) >> PAGE_SHIFT, 0);
if (vid_dev->cma_pages) {
vid_dev->buffer_start = page_to_phys(
vid_dev->cma_pages);
vid_dev->buffer_size = (CMA_ALLOC_SIZE*SZ_1M);
} else {
pr_err("amlvideo2 alloc cma alone failed\n");
return -1;
}
} else {
flags = CODEC_MM_FLAGS_DMA |
CODEC_MM_FLAGS_CMA_CLEAR;
if (node_id == 0) {
if (vid_dev->node[node_id]->
ge2d_multi_process_flag == 1)
vid_dev->buffer_start =
codec_mm_alloc_for_dma(
"amlvideo2.0",
((CMA_ALLOC_SIZE +
4) * SZ_1M)/PAGE_SIZE,
0, flags);
else
vid_dev->buffer_start =
codec_mm_alloc_for_dma(
"amlvideo2.0",
(CMA_ALLOC_SIZE * SZ_1M)/PAGE_SIZE,
0, flags);
} else {
if (vid_dev->node[node_id]->
ge2d_multi_process_flag == 1)
vid_dev->buffer_start =
codec_mm_alloc_for_dma(
"amlvideo2.1",
((CMA_ALLOC_SIZE +
4) * SZ_1M)/PAGE_SIZE,
0, flags);
else
vid_dev->buffer_start =
codec_mm_alloc_for_dma(
"amlvideo2.1",
(CMA_ALLOC_SIZE * SZ_1M)/PAGE_SIZE,
0, flags);
}
if (!(vid_dev->buffer_start)) {
pr_err("amlvideo2 alloc cma buffer failed\n");
return -1;
}
if (vid_dev->node[node_id]->ge2d_multi_process_flag
== 1)
vid_dev->buffer_size = ((CMA_ALLOC_SIZE
+ 4)*SZ_1M);
else
vid_dev->buffer_size =
(CMA_ALLOC_SIZE * SZ_1M);
}
if (node_id == 0)
pr_info("amlvideo2.0 cma memory is %x , size is %x\n",
(unsigned int)vid_dev->buffer_start,
(unsigned int)vid_dev->buffer_size);
else
pr_info("amlvideo2.1 cma memory is %x , size is %x\n",
(unsigned int)vid_dev->buffer_start,
(unsigned int)vid_dev->buffer_size);
}
return 0;
}
int amlvideo2_cma_buf_uninit(struct amlvideo2_device *vid_dev, int node_id)
{
if (!vid_dev->use_reserve) {
if (vid_dev->cma_mode == 0) {
if (vid_dev->cma_pages) {
dma_release_from_contiguous(
&vid_dev->pdev->dev,
vid_dev->cma_pages,
(CMA_ALLOC_SIZE*SZ_1M) >> PAGE_SHIFT);
vid_dev->cma_pages = NULL;
}
} else {
if (vid_dev->buffer_start != 0) {
if (node_id == 0) {
codec_mm_free_for_dma(
"amlvideo2.0",
vid_dev->buffer_start);
} else {
codec_mm_free_for_dma(
"amlvideo2.1",
vid_dev->buffer_start);
}
vid_dev->buffer_start = 0;
vid_dev->buffer_size = 0;
if (node_id == 0)
pr_info("amlvideo2.0 cma memory release succeed\n");
else
pr_info("amlvideo2.1 cma memory release succeed\n");
}
}
}
return 0;
}
/* ------------------------------------------------------------------
* File operations for the device
* ------------------------------------------------------------------
*/
static int amlvideo2_open(struct file *file)
{
struct amlvideo2_node *node = video_drvdata(file);
struct amlvideo2_fh *fh = NULL;
struct videobuf_res_privdata *res = NULL;
struct resource *reserve = NULL;
int ret;
mutex_lock(&node->mutex);
node->users++;
if (node->users > 1) {
node->users--;
mutex_unlock(&node->mutex);
return -EBUSY;
}
#if 0
node->provider = vf_get_provider(
(node->vid == 0)?RECEIVER_NAME0:RECEIVER_NAME1);
if (node->provider == NULL) {
node->users--;
mutex_unlock(&node->mutex);
return -ENODEV;
}
node->p_type = get_provider_type(node->provider->name, node->input);
if ((node->p_type == AML_PROVIDE_NONE)
|| (node->p_type >= AML_PROVIDE_MAX)) {
node->users--;
node->provider = NULL;
mutex_unlock(&node->mutex);
return -ENODEV;
}
#endif
ret = amlvideo2_cma_buf_init(node->vid_dev, node->vid);
if (ret < 0) {
if (node->vid == 0)
pr_err("alloc amlvideo2.0 cma buffer failed.\n");
else
pr_err("alloc amlvideo2.1 cma buffer failed.\n");
node->users--;
mutex_unlock(&node->mutex);
return -ENOMEM;
}
fh = node->fh;
if (fh == NULL) {
node->users--;
/* node->provider = NULL; */
amlvideo2_cma_buf_uninit(node->vid_dev, node->vid);
mutex_unlock(&node->mutex);
return -ENOMEM;
}
if (node->vid_dev->use_reserve) {
reserve = &node->vid_dev->memobj;
if (!reserve) {
pr_err("alloc reserve buffer failed !\n");
node->users--;
amlvideo2_cma_buf_uninit(node->vid_dev, node->vid);
mutex_unlock(&node->mutex);
return -ENOMEM;
}
node->res.start = reserve->start;
node->res.end = reserve->end;
} else {
node->res.start = node->vid_dev->buffer_start;
node->res.end = node->vid_dev->buffer_start +
node->vid_dev->buffer_size;
}
mutex_unlock(&node->mutex);
node->mode = AML_SCREEN_MODE_RATIO;
file->private_data = fh;
fh->node = node;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->fmt = &formats[0];
fh->width = 1920;
fh->height = 1080;
fh->set_format_flag = false;
fh->f_flags = file->f_flags;
memset(&node->crop_info, 0, sizeof(struct crop_info_s));
fh->node->res.priv = (void *)fh;
res = &fh->node->res;
ret = videobuf_queue_res_init(&fh->vb_vidq, &amlvideo2_qops,
NULL,
&node->slock, fh->type, V4L2_FIELD_INTERLACED,
sizeof(struct amlvideo2_node_buffer), (void *)res,
NULL);
if (!ret)
fh->vb_vidq_init = 1;
#ifdef CONFIG_AMLOGIC_MEDIA_VDIN
v4l2_vdin_ops_init(&node->vops);
#endif
fh->frm_save_time_us = 1000000 / DEF_FRAMERATE;
return 0;
}
static ssize_t amlvideo2_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
struct amlvideo2_fh *fh = file->private_data;
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
file->f_flags & O_NONBLOCK);
}
return 0;
}
static unsigned int amlvideo2_poll(struct file *file,
struct poll_table_struct *wait)
{
struct amlvideo2_fh *fh = file->private_data;
struct amlvideo2_node *node = fh->node;
struct videobuf_queue *q = &fh->vb_vidq;
dpr_err(node->vid_dev, 1, "%s\n", __func__);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return POLLERR;
return videobuf_poll_stream(file, q, wait);
}
static int amlvideo2_close(struct file *file)
{
struct amlvideo2_fh *fh = file->private_data;
struct amlvideo2_node *node = fh->node;
if (fh->vb_vidq_init) {
videobuf_stop(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vidq);
}
amlvideo2_cma_buf_uninit(node->vid_dev, node->vid);
mutex_lock(&node->mutex);
if (node->r_type == AML_RECEIVER_NONE) {
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
/* switch_mod_gate_by_name("ge2d", 0); */
/* #endif */
}
node->users--;
amlvideo2_frmintervals_active.numerator = 1;
amlvideo2_frmintervals_active.denominator = DEF_FRAMERATE;
node->has_amvideo_node = false;
node->crop_info.source_top_crop = 0;
node->crop_info.source_left_crop = 0;
node->crop_info.source_width_crop = 0;
node->crop_info.source_height_crop = 0;
node->crop_info.capture_crop_enable = 0;
/* node->provider = NULL; */
node->pflag = false;
mutex_unlock(&node->mutex);
return 0;
}
static int amlvideo2_mmap(struct file *file, struct vm_area_struct *vma)
{
int ret = 0;
struct amlvideo2_fh *fh = file->private_data;
struct amlvideo2_node *node = fh->node;
dpr_err(node->vid_dev, 1,
"mmap called, vma=0x%08lx\n", (unsigned long)vma);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
dpr_err(node->vid_dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
(unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
return ret;
}
static const struct v4l2_file_operations amlvideo2_fops = {
.owner = THIS_MODULE,
.open = amlvideo2_open,
.release = amlvideo2_close,
.read = amlvideo2_read,
.poll = amlvideo2_poll,
.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = amlvideo2_mmap, };
static const struct v4l2_ioctl_ops amlvideo2_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
.vidioc_s_input = vidioc_s_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_g_crop = vidioc_g_crop,
.vidioc_s_crop = vidioc_s_crop,
.vidioc_s_output = vidioc_s_output,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
};
static struct video_device amlvideo2_template = {
.name = "amlvideo2",
.fops = &amlvideo2_fops,
.ioctl_ops = &amlvideo2_ioctl_ops,
.release = video_device_release,
.tvnorms = V4L2_STD_525_60,
/* .current_norm = V4L2_STD_NTSC_M, */
};
static int amlvideo2_receiver_event_fun(int type, void *data,
void *private_data)
{
struct amlvideo2_node *node = (struct amlvideo2_node *)private_data;
/* (struct amlvideo2_fh *)container_of(
* node, struct amlvideo2_fh, node);
*/
struct amlvideo2_fh *fh = node->fh;
struct vframe_states states;
const char *name = (node->vid == 0) ? DEVICE_NAME0 : DEVICE_NAME1;
memset(&states, 0, sizeof(struct vframe_states));
switch (type) {
case VFRAME_EVENT_PROVIDER_VFRAME_READY:
node->provide_ready = 1;
if (amlvideo2_dbg_en & 8)
pr_info("provider : node->recv.name = %s\n",
node->recv.name);
if (vf_peek(node->recv.name) != NULL)
wake_up_interruptible(&node->vidq.wq);
break;
case VFRAME_EVENT_PROVIDER_QUREY_STATE:
amlvideo2_vf_states(&states, node);
if (states.buf_avail_num > 0)
return RECEIVER_ACTIVE;
if (vf_notify_receiver(
name,
VFRAME_EVENT_PROVIDER_QUREY_STATE,
NULL)
== RECEIVER_ACTIVE) {
return RECEIVER_ACTIVE;
}
return RECEIVER_INACTIVE;
case VFRAME_EVENT_PROVIDER_START:
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
/* switch_mod_gate_by_name("ge2d", 1); */
/* #endif */
node->sub_recv = vf_get_receiver(name);
if (amlvideo2_dbg_en) {
pr_info("provider start : name = %s\n", name);
pr_info("provider start : sub_recv = %p\n",
node->sub_recv);
}
if (node->sub_recv) {
node->r_type =
get_sub_receiver_type(node->sub_recv->name);
if (amlvideo2_dbg_en) {
pr_info("%s , node->sub_recv->name=%s\n",
__func__, node->sub_recv->name);
pr_info("r_type=%d\n", node->r_type);
}
node->provider = vf_get_provider(name);
if (node->provider) {
node->p_type =
get_provider_type(node->provider->name);
if (amlvideo2_dbg_en) {
pr_info("provider=%s\n",
node->provider->name);
pr_info("node->p_type = %d .\n",
node->p_type);
}
}
fh->node = node;
vf_reg_provider(&node->amlvideo2_vf_prov);
vf_notify_receiver(name,
VFRAME_EVENT_PROVIDER_START,
NULL);
amlvideo2_start_thread(fh);
}
break;
case VFRAME_EVENT_PROVIDER_REG:
node->video_blocking = false;
vfq_init(&node->q_ready,
node->amlvideo2_pool_size,
(struct vframe_s **)&(node->amlvideo2_pool_ready[0]));
break;
case VFRAME_EVENT_PROVIDER_UNREG:
node->provide_ready = 0;
if (node->r_type != AML_RECEIVER_NONE) {
amlvideo2_stop_thread(&node->vidq);
pr_err("%s,%dstop thread\n", __func__, __LINE__);
}
if (amlvideo2_dbg_en)
pr_info("pflag = %d\n", node->pflag);
if (!node->pflag) {
if (amlvideo2_dbg_en)
pr_info("unreg amlvideo2 provider\n");
vf_unreg_provider(&node->amlvideo2_vf_prov);
}
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
/* switch_mod_gate_by_name("ge2d", 0); */
/* #endif */
break;
case VFRAME_EVENT_PROVIDER_LIGHT_UNREG:
if (amlvideo2_dbg_en)
pr_info("provider light unreg\n");
break;
case VFRAME_EVENT_PROVIDER_RESET:
if (amlvideo2_dbg_en)
pr_info("provider reset\n");
vf_notify_receiver(name,
VFRAME_EVENT_PROVIDER_RESET,
NULL);
if (node->vidq.task_running) {
node->video_blocking = true;
wake_up_interruptible(&node->vidq.wq);
}
break;
case VFRAME_EVENT_PROVIDER_FR_HINT:
case VFRAME_EVENT_PROVIDER_FR_END_HINT:
vf_notify_receiver(name, type, data);
break;
default:
break;
}
return 0;
}
static const struct vframe_receiver_op_s video_vf_receiver = {
.event_cb = amlvideo2_receiver_event_fun};
/* -----------------------------------------------------------------
* Initialization and module stuff
* -----------------------------------------------------------------
*/
static int amlvideo2_release_node(struct amlvideo2_device *vid_dev)
{
int i = 0;
struct video_device *vfd = NULL;
for (i = 0; i < vid_dev->node_num; i++) {
if (vid_dev->node[i]) {
vfd = vid_dev->node[i]->vfd;
video_device_release(vfd);
vf_unreg_receiver(&vid_dev->node[i]->recv);
if (vid_dev->node[i]->context)
destroy_ge2d_work_queue(
vid_dev->node[i]->context);
kfree(vid_dev->node[i]->fh);
kfree(vid_dev->node[i]->amlvideo2_pool_ready);
vid_dev->node[i]->fh = NULL;
kfree(vid_dev->node[i]);
vid_dev->node[i] = NULL;
}
gAmlvideo2_Node[i] = NULL;
}
return 0;
}
/* static struct resource memobj; */
static int amlvideo2_create_node(struct platform_device *pdev, int node_id)
{
int ret = 0, j = 0;
struct video_device *vfd = NULL;
struct amlvideo2_node *vid_node = NULL;
struct amlvideo2_fh *fh = NULL;
struct resource *res = NULL;
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct amlvideo2_device *vid_dev = container_of(v4l2_dev,
struct amlvideo2_device,
v4l2_dev);
pr_info("amlvideo2_create_node");
vid_dev->node_num = pdev->num_resources;
if (vid_dev->node_num > MAX_SUB_DEV_NODE)
vid_dev->node_num = MAX_SUB_DEV_NODE;
vid_dev->node[node_id] = NULL;
ret = -ENOMEM;
#if 0
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
#else
res = &vid_dev->memobj;
/*
* ret = find_reserve_block(pdev->dev.of_node->name,i);
* if(ret < 0){
* pr_err("\namlvideo2 memory resource undefined.\n");
* return -EFAULT;
* }
* res->start = (phys_addr_t)get_reserve_block_addr(ret);
* res->end = res->start +
* (phys_addr_t)get_reserve_block_size(ret)-1;
*/
#endif
if (!res)
return ret;
vid_node = kzalloc(sizeof(struct amlvideo2_node), GFP_KERNEL);
if (!vid_node)
return ret;
vid_node->res.magic = MAGIC_RE_MEM;
vid_node->res.priv = NULL;
vid_node->amlvideo2_pool_ready = NULL;
vid_node->amlvideo2_pool_size = 12;
vid_node->amlvideo2_pool_ready =
kmalloc((sizeof(struct vframe_s) *
(vid_node->amlvideo2_pool_size)),
GFP_KERNEL);
if (!vid_node->amlvideo2_pool_ready) {
pr_err("amlvideo2_pool_ready malloc failed\n");
kfree(vid_node);
return ret;
}
if (vid_node->amlvideo2_pool_ready != NULL) {
vfq_init(&vid_node->q_ready,
vid_node->amlvideo2_pool_size,
(struct vframe_s **)&(vid_node->amlvideo2_pool_ready[0]));
}
vid_node->context = create_ge2d_work_queue();
if (!vid_node->context) {
kfree(vid_node->amlvideo2_pool_ready);
kfree(vid_node);
return ret;
}
/* init video dma queues */
INIT_LIST_HEAD(&vid_node->vidq.active);
init_waitqueue_head(&vid_node->vidq.wq);
/* initialize locks */
spin_lock_init(&vid_node->slock);
mutex_init(&vid_node->mutex);
init_completion(&vid_node->plug_sema);
vfd = video_device_alloc();
if (!vfd) {
destroy_ge2d_work_queue(vid_node->context);
kfree(vid_node->amlvideo2_pool_ready);
kfree(vid_node);
return ret;
}
*vfd = amlvideo2_template;
vfd->dev_debug = debug;
vfd->v4l2_dev = v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
if (ret < 0) {
ret = -ENODEV;
video_device_release(vfd);
destroy_ge2d_work_queue(vid_node->context);
kfree(vid_node->amlvideo2_pool_ready);
kfree(vid_node);
return ret;
}
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (!fh) {
video_device_release(vfd);
destroy_ge2d_work_queue(vid_node->context);
kfree(vid_node->amlvideo2_pool_ready);
kfree(vid_node);
return ret;
}
vid_node->fh = fh;
video_set_drvdata(vfd, vid_node);
/* Set all controls to their default value. */
for (j = 0; j < ARRAY_SIZE(amlvideo2_node_qctrl); j++) {
vid_node->qctl_regs[j] =
amlvideo2_node_qctrl[j].default_value;
}
vid_node->vfd = vfd;
vid_node->vid = node_id;
vid_node->users = 0;
vid_node->vid_dev = vid_dev;
video_nr++;
#ifdef MULTI_NODE
vf_receiver_init(&vid_node->recv,
(node_id == 0) ? DEVICE_NAME0 : DEVICE_NAME1,
&video_vf_receiver, (void *)vid_node);
#else
vf_receiver_init(&vid_node->recv,
RECEIVER_NAME,
&video_vf_receiver, (void *)vid_node);
#endif
vf_reg_receiver(&vid_node->recv);
vf_provider_init(&vid_node->amlvideo2_vf_prov,
(node_id == 0) ? DEVICE_NAME0 : DEVICE_NAME1,
&amlvideo2_vf_provider,
(void *)vid_node);
vid_node->pflag = false;
vid_node->field_flag = false;
vid_node->field_condition_flag = false;
vid_node->ge2d_multi_process_flag = false;
vid_node->r_type = AML_RECEIVER_NONE;
vid_dev->node[node_id] = vid_node;
v4l2_info(&vid_dev->v4l2_dev, "V4L2 device registered as %s\n",
video_device_node_name(vfd));
gAmlvideo2_Node[node_id] = vid_node;
if (ret)
amlvideo2_release_node(vid_dev);
return ret;
}
static int amlvideo2_driver_probe(struct platform_device *pdev)
{
s32 ret;
struct amlvideo2_device *dev = NULL;
dev = kzalloc(sizeof(struct amlvideo2_device), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
memset(dev, 0, sizeof(struct amlvideo2_device));
snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s",
AVMLVIDEO2_MODULE_NAME);
pr_err("amlvideo2 probe called\n");
pdev->num_resources = MAX_SUB_DEV_NODE;
platform_set_drvdata(pdev, &(dev->v4l2_dev));
ret = of_reserved_mem_device_init(&pdev->dev);
if (ret == 0)
pr_info("amlvideo2_probe done\n");
ret = of_property_read_u32(pdev->dev.of_node,
"cma_mode", &(dev->cma_mode));
if (ret) {
pr_err("don't find match cma_mode\n");
dev->cma_mode = 1;
}
ret = of_property_read_u32(pdev->dev.of_node,
"amlvideo2_id", &(dev->node_id));
if (ret)
pr_err("don't find amlvideo2 node id.\n");
dev->pdev = pdev;
if (v4l2_device_register(&pdev->dev, &dev->v4l2_dev) < 0) {
dev_err(&pdev->dev, "v4l2_device_register failed\n");
ret = -ENODEV;
goto probe_err0;
}
mutex_init(&dev->mutex);
video_nr = 11;
ret = amlvideo2_create_node(pdev, dev->node_id);
if (ret)
goto probe_err1;
/* register vout client */
if (dev->node_id == 1)
vout_register_client(&amlvideo2_notifier_nb);
return 0;
probe_err1: v4l2_device_unregister(&dev->v4l2_dev);
probe_err0: kfree(dev);
return ret;
/* int ret = 0; */
/* struct amlvideo2_device *dev = NULL; */
/* */
/* if(of_get_property(pdev->dev.of_node, "reserve-memory", NULL)) */
/* pdev->num_resources = MAX_SUB_DEV_NODE; */
/* */
/* if (pdev->num_resources == 0) */
/* { */
/* dev_err(&pdev->dev, "probed for an unknown device\n"); */
/* return -ENODEV; */
/* } */
/* */
/* dev = kzalloc(sizeof(struct amlvideo2_device), GFP_KERNEL); */
/* */
/* if (dev == NULL) */
/* return -ENOMEM; */
/* */
/* memset(dev,0,sizeof(struct amlvideo2_device)); */
/* */
/* snprintf(dev->v4l2_dev.name,
* sizeof(dev->v4l2_dev.name),
* "%s", AVMLVIDEO2_MODULE_NAME);
*/
/* */
/* if (v4l2_device_register(&pdev->dev, &dev->v4l2_dev) < 0) { */
/* dev_err(&pdev->dev, "v4l2_device_register failed\n"); */
/* ret = -ENODEV; */
/* goto probe_err0; */
/* } */
/* */
/* mutex_init(&dev->mutex); */
/* video_nr = 11; */
/* */
/* ret = amlvideo2_create_node(pdev); */
/* if (ret) */
/* goto probe_err1; */
/* */
/* return 0; */
/* */
/* probe_err1: */
/* v4l2_device_unregister(&dev->v4l2_dev); */
/* */
/* probe_err0: */
/* kfree(dev); */
/* return ret; */
}
static int amlvideo2_mem_device_init(struct reserved_mem *rmem,
struct device *dev)
{
struct resource *res = NULL;
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct amlvideo2_device *vdevp = container_of(v4l2_dev,
struct amlvideo2_device, v4l2_dev);
res = &(vdevp->memobj);
res->start = rmem->base;
res->end = rmem->base + rmem->size - 1;
vdevp->use_reserve = 1;
pr_info("amlvideo2 mem:%lx->%lx\n", (unsigned long)res->start,
(unsigned long)res->end);
return 0;
}
static const struct reserved_mem_ops rmem_amlvideo2_ops = {
.device_init = amlvideo2_mem_device_init, };
static int __init amlvideo2_mem_setup(struct reserved_mem *rmem)
{
rmem->ops = &rmem_amlvideo2_ops;
pr_info("amlvideo2 share mem setup\n");
return 0;
}
static int amlvideo2_drv_remove(struct platform_device *pdev)
{
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct amlvideo2_device *vid_dev = container_of(v4l2_dev,
struct amlvideo2_device,
v4l2_dev);
/* unregister vout client */
video_nr = 11;
if (vid_dev->node_id == 1)
vout_unregister_client(&amlvideo2_notifier_nb);
amlvideo2_release_node(vid_dev);
v4l2_device_unregister(v4l2_dev);
platform_set_drvdata(pdev, NULL);
kfree(vid_dev);
return 0;
}
static const struct of_device_id amlvideo2_dt_match[] = {
{
.compatible = "amlogic, amlvideo2",
},
{},
};
/* general interface for a linux driver .*/
static struct platform_driver amlvideo2_drv = {
.probe = amlvideo2_driver_probe,
.remove = amlvideo2_drv_remove,
.driver = {.name = "amlvideo2", .owner = THIS_MODULE, .of_match_table =
amlvideo2_dt_match, } };
static int __init amlvideo2_init(void)
{
/* amlog_level(LOG_LEVEL_HIGH,"amlvideo2_init\n"); */
if (platform_driver_register(&amlvideo2_drv)) {
pr_err(
"Failed to register amlvideo2 driver\n");
return -ENODEV;
}
return 0;
}
static void __exit amlvideo2_exit(void)
{
platform_driver_unregister(&amlvideo2_drv);
/* amlog_level(LOG_LEVEL_HIGH,"amlvideo2 module removed.\n"); */
}
RESERVEDMEM_OF_DECLARE(amlvideo2, "amlogic, amlvideo2_memory",
amlvideo2_mem_setup);
module_init(amlvideo2_init);
module_exit(amlvideo2_exit);