blob: ea3a75df6b6eb55e152955ec50489c08084e1923 [file] [log] [blame]
/*
* drivers/amlogic/media/stream_input/amports/amstream_profile.c
*
* Copyright (C) 2016 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/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/amlogic/media/utils/amstream.h>
#include <linux/amlogic/media/utils/vformat.h>
#include "../../../common/chips/decoder_cpu_ver_info.h"
#include "vdec.h"
//static const struct codec_profile_t *vcodec_feature[SUPPORT_VDEC_NUM] = { 0 };
struct vcodec_feature {
int format;
int is_v4l;
};
static struct vcodec_feature feature[SUPPORT_VDEC_NUM];
static int vcodec_feature_idx;
static ulong last_time;
u8 buf[4096];
static const char * const format_name[] = {
"ammvdec_mpeg12",
"ammvdec_mpeg4",
"ammvdec_h264",
"ammvdec_mjpeg",
"ammvdec_real",
"ammjpegdec",
"ammvdec_vc1",
"ammvdec_avs",
"ammvdec_yuv",
"ammvdec_h264mvc",
"ammvdec_h264_4k2k",
"ammvdec_h265",
"amvenc_avc",
"jpegenc",
"ammvdec_vp9",
"ammvdec_avs2",
"ammvdec_av1",
};
static int vcodec_feature_CC(u8 *buf, int size, int vformat, int is_v4l)
{
u8 *pbuf = buf;
if (!is_v4l) {
switch (vformat) {
case VFORMAT_MPEG12:
case VFORMAT_H264:
case VFORMAT_AVS:
pbuf += snprintf(pbuf, size, " \"CC subtitle\" : \"true\"\n");
break;
default:
break;
}
}
return pbuf - buf;
}
static int vcodec_feature_report_information(u8 *buf, int size, int vformat, int is_v4l)
{
u8 *pbuf = buf;
if (!is_v4l) {
pbuf += snprintf(pbuf, size, " \"Decoder information report\" : \"true\"\n");
}
return pbuf - buf;
}
static int vcodec_feature_i_only_mode(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_MPEG12:
case VFORMAT_H264:
case VFORMAT_MPEG4:
case VFORMAT_HEVC:
case VFORMAT_AVS2:
pbuf += snprintf(pbuf, size, " \"I only mode\" : \"true\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_dolbyVison(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_H264:
case VFORMAT_HEVC:
case VFORMAT_AV1:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_S4))
pbuf += snprintf(pbuf, size, " \"DolbyVision\" : \"true\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_HDR(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_H264:
case VFORMAT_HEVC:
case VFORMAT_AV1:
case VFORMAT_AVS2:
case VFORMAT_VP9:
pbuf += snprintf(pbuf, size, " \"HDR\" : \"true\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_doublewrite(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
int tsize = 0;
int s;
switch (vformat) {
case VFORMAT_HEVC:
case VFORMAT_VP9:
case VFORMAT_AVS2:
case VFORMAT_AV1:
s = snprintf(pbuf, size - tsize, " \"DoubleWrite\" ");
tsize += s;
pbuf += s;
if ((get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T7) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T3)) {
s = snprintf(pbuf, size - tsize, "[ \"0\", \"1\", \"2\", \"3\", \"4\", \"0x10\", \"0x10000\", \"0x20000\"]\n");
tsize += s;
pbuf += s;
}
else {
s = snprintf(pbuf, size - tsize, "[ \"0\", \"1\", \"2\", \"3\", \"4\", \"8\", \"0x10\", \"0x10000\", \"0x20000\"]\n");
tsize += s;
pbuf += s;
}
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_vdec_fence(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_H264:
case VFORMAT_HEVC:
case VFORMAT_VP9:
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM)
pbuf += snprintf(pbuf, size, " \"GameMode\" : \"true\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_bitdepth(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_HEVC:
case VFORMAT_VP9:
case VFORMAT_AVS2:
case VFORMAT_AV1:
if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXBB)
pbuf += snprintf(pbuf, size, " \"BitDepth\" : \"10\"\n");
else
pbuf += snprintf(pbuf, size, " \"BitDepth\" : \"8\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_MaxResolution(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_HEVC:
case VFORMAT_VP9:
case VFORMAT_AVS2:
case VFORMAT_AV1:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D))
pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"8k\"\n");
else if (vdec_is_support_4k() &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D))
pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"4k60\"\n");
else
pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"1080p60\"\n");
break;
case VFORMAT_H264:
if (vdec_is_support_4k())
pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"4k30\"\n");
else
pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"1080p60\"\n");
break;
case VFORMAT_MPEG12:
case VFORMAT_MPEG4:
case VFORMAT_MJPEG:
case VFORMAT_VC1:
case VFORMAT_AVS:
pbuf += snprintf(pbuf, size, " \"MaximumResolution\" : \"1080p60\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_clock(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
switch (vformat) {
case VFORMAT_HEVC:
case VFORMAT_VP9:
case VFORMAT_AVS2:
case VFORMAT_AV1:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12B) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXLX2) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D))
pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"800MHZ\"\n");
else
pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"667MHZ\"\n");
break;
case VFORMAT_H264:
case VFORMAT_MPEG12:
case VFORMAT_MPEG4:
case VFORMAT_MJPEG:
case VFORMAT_VC1:
case VFORMAT_AVS:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_GXLX2) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D))
pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"800MHZ\"\n");
else
pbuf += snprintf(pbuf, size, " \"ClockFrequency\" : \"667MHZ\"\n");
break;
default:
break;
}
return pbuf - buf;
}
static int vcodec_feature_support_format(int vformat)
{
switch (vformat) {
case VFORMAT_VP9:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXL) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5))
return 1;
else
return 0;
case VFORMAT_AVS2:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5D))
return 1;
else
return 0;
case VFORMAT_AV1:
if (((get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_TM2) &&
is_cpu_tm2_revb()) ||
((get_cpu_major_id() > AM_MESON_CPU_MAJOR_ID_TM2) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_T5)))
return 1;
else
return 0;
case VFORMAT_AVS:
if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXM))
return 1;
else
return 0;
case VFORMAT_MJPEG:
case VFORMAT_VC1:
case VFORMAT_MPEG4:
case VFORMAT_MPEG12:
case VFORMAT_H264:
case VFORMAT_HEVC:
return 1;
default:
break;
}
return 0;
}
static int vcodec_feature_FCC(u8 *buf, int size, int vformat, int is_v4l)
{
u8 *pbuf = buf;
if (!is_v4l) {
switch (vformat) {
case VFORMAT_HEVC:
case VFORMAT_H264:
case VFORMAT_MPEG12:
pbuf += snprintf(pbuf, size, " \"Decoder FCC support\" : \"true\"\n");
break;
default:
break;
}
}
return pbuf - buf;
}
static int vcodec_feature_RDMA(u8 *buf, int size, int vformat)
{
u8 *pbuf = buf;
if (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T3)
pbuf += snprintf(pbuf, size, " \"Decoder RDMA support\" : \"true\"\n");
return pbuf - buf;
}
static int vcodec_feature_v4ldec_nr(u8 *buf, int size, int vformat, int is_v4l)
{
u8 *pbuf = buf;
if (is_v4l) {
pbuf += snprintf(pbuf, size, " \"V4ldec nr\" : \"true\"\n");
}
return pbuf - buf;
}
static int vcodec_feature_ge2d_wrapper(u8 *buf, int size, int vformat, int is_v4l)
{
u8 *pbuf = buf;
if (is_v4l && (get_cpu_major_id() == AM_MESON_CPU_MAJOR_ID_T7)) {
pbuf += snprintf(pbuf, size, " \"Ge2d wrapper\" : \"true\"\n");
}
return pbuf - buf;
}
int vcodec_feature_get_feature(u8 *buf, int vformat, int is_v4l)
{
u8 *pbuf = buf;
int size = PAGE_SIZE;
int tsize = 0;
int s;
s = snprintf(pbuf, size - tsize, " \"%s%s\": ", format_name[vformat], is_v4l ? "_v4l" : "");
tsize += s;
pbuf += s;
s = snprintf(pbuf, size - tsize, "{\n");
tsize += s;
pbuf += s;
s = vcodec_feature_CC(pbuf, size - tsize, vformat, is_v4l);
tsize += s;
pbuf += s;
s = vcodec_feature_report_information(pbuf, size - tsize, vformat, is_v4l);
tsize += s;
pbuf += s;
s = vcodec_feature_vdec_fence(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_i_only_mode(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_dolbyVison(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_HDR(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_doublewrite(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_bitdepth(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_MaxResolution(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_clock(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_FCC(pbuf, size - tsize, vformat, is_v4l);
tsize += s;
pbuf += s;
s = vcodec_feature_RDMA(pbuf, size - tsize, vformat);
tsize += s;
pbuf += s;
s = vcodec_feature_v4ldec_nr(pbuf, size - tsize, vformat, is_v4l);
tsize += s;
pbuf += s;
s = vcodec_feature_ge2d_wrapper(pbuf, size - tsize, vformat, is_v4l);
tsize += s;
pbuf += s;
s = snprintf(pbuf, size - tsize, " \"UcodeVersionRequest\" : \"0.3.10\"\n");
tsize += s;
pbuf += s;
s = snprintf(pbuf, size - tsize, " }\n");
tsize += s;
pbuf += s;
return pbuf - buf;
}
ssize_t vcodec_feature_read(char *buf)
{
static int read_count;
char *pbuf = buf;
if (jiffies - last_time > 5 * HZ) {
read_count = 0;
/*timeout :not continue dump,dump from first. */
}
if (vcodec_feature_idx > 0) {
if (read_count == 0)
pbuf += snprintf(pbuf, PAGE_SIZE - (pbuf - buf), "{\n");
pbuf += vcodec_feature_get_feature(pbuf, feature[read_count].format, feature[read_count].is_v4l);
read_count++;
if (read_count >= vcodec_feature_idx) {
read_count = 0;
pbuf += snprintf(pbuf, PAGE_SIZE - (pbuf - buf), "}");
}
}
last_time = jiffies;
return pbuf - buf;
}
EXPORT_SYMBOL(vcodec_feature_read);
int vcodec_feature_register(int vformat, int is_v4l)
{
if ((vcodec_feature_idx < SUPPORT_VDEC_NUM) && vcodec_feature_support_format(vformat)) {
feature[vcodec_feature_idx].format = vformat;
feature[vcodec_feature_idx].is_v4l = is_v4l;
vcodec_feature_idx++;
//pr_debug("regist %s codec profile\n", vdec_profile->name);
}
return 0;
}
EXPORT_SYMBOL(vcodec_feature_register);