mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
ODROID-COMMON: slipstream Amlogic drivers
Change-Id: I96b0ed0cce029e85a12c1a04327f106b68ba7f43
This commit is contained in:
@@ -1502,6 +1502,22 @@ CONFIG_AMLOGIC_DEFENDKEY=y
|
||||
#
|
||||
# Meson SPI NOR Flash Support
|
||||
#
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4_MULTI=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_VC1=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_H264=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_H264_MULTI=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_H264_MVC=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_H265=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_VP9=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG_MULTI=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_REAL=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_AVS=m
|
||||
CONFIG_AMLOGIC_MEDIA_VDEC_AVS2=m
|
||||
CONFIG_AMLOGIC_MEDIA_VENC_H264=m
|
||||
CONFIG_AMLOGIC_MEDIA_VENC_H265=m
|
||||
CONFIG_ARM_AMBA=y
|
||||
|
||||
#
|
||||
@@ -4447,6 +4463,29 @@ CONFIG_NVMEM=y
|
||||
# CONFIG_FPGA is not set
|
||||
# CONFIG_TEE is not set
|
||||
|
||||
#
|
||||
# ARM GPU Configuration
|
||||
#
|
||||
CONFIG_MALI_MIDGARD=y
|
||||
# CONFIG_MALI_GATOR_SUPPORT is not set
|
||||
# CONFIG_MALI_MIDGARD_DVFS is not set
|
||||
# CONFIG_MALI_MIDGARD_ENABLE_TRACE is not set
|
||||
# CONFIG_MALI_DEVFREQ is not set
|
||||
# CONFIG_MALI_DMA_FENCE is not set
|
||||
CONFIG_MALI_PLATFORM_NAME="devicetree"
|
||||
CONFIG_MALI_EXPERT=y
|
||||
# CONFIG_MALI_CORESTACK is not set
|
||||
# CONFIG_MALI_PRFCNT_SET_SECONDARY is not set
|
||||
# CONFIG_MALI_DEBUG is not set
|
||||
# CONFIG_MALI_FENCE_DEBUG is not set
|
||||
# CONFIG_MALI_NO_MALI is not set
|
||||
# CONFIG_MALI_TRACE_TIMELINE is not set
|
||||
# CONFIG_MALI_SYSTEM_TRACE is not set
|
||||
# CONFIG_MALI_JOB_DUMP is not set
|
||||
# CONFIG_MALI_2MB_ALLOC is not set
|
||||
# CONFIG_MALI_PWRSOFT_765 is not set
|
||||
CONFIG_MALI_KUTF=m
|
||||
|
||||
#
|
||||
# Firmware Drivers
|
||||
#
|
||||
@@ -4721,7 +4760,7 @@ CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_GDB_SCRIPTS is not set
|
||||
CONFIG_ENABLE_WARN_DEPRECATED=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
CONFIG_FRAME_WARN=2048
|
||||
CONFIG_FRAME_WARN=0
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
# CONFIG_READABLE_ASM is not set
|
||||
# CONFIG_UNUSED_SYMBOLS is not set
|
||||
@@ -4836,6 +4875,7 @@ CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_TRACE_CLOCK=y
|
||||
CONFIG_RING_BUFFER=y
|
||||
CONFIG_EVENT_TRACING=y
|
||||
CONFIG_GPU_TRACEPOINTS=y
|
||||
CONFIG_CONTEXT_SWITCH_TRACER=y
|
||||
CONFIG_TRACING=y
|
||||
CONFIG_GENERIC_TRACER=y
|
||||
|
||||
@@ -135,5 +135,7 @@ source "drivers/amlogic/defendkey/Kconfig"
|
||||
source "drivers/amlogic/battery/Kconfig"
|
||||
|
||||
source "drivers/amlogic/spi-nor/Kconfig"
|
||||
|
||||
source "drivers/amlogic/media_modules/Kconfig"
|
||||
endmenu
|
||||
endif
|
||||
|
||||
@@ -7,14 +7,8 @@
|
||||
## Do not change.
|
||||
##########################################
|
||||
|
||||
ifndef CONFIG_KASAN
|
||||
KBUILD_CFLAGS += -Wlarger-than=28792
|
||||
KBUILD_CFLAGS += -Wstack-usage=1856 -Wno-bool-operation -Wno-maybe-uninitialized
|
||||
else
|
||||
ifeq ($(call cc-ifversion, -lt, 0500, y), y)
|
||||
$(error -----GCC VERSION TOO SMALL FOR KASAN -----)
|
||||
endif
|
||||
endif
|
||||
|
||||
# These 2 marked sentence is just for generate warning messages
|
||||
#KBUILD_CFLAGS += -Wno-error=larger-than=28792
|
||||
@@ -133,3 +127,5 @@ obj-$(CONFIG_AMLOGIC_DEBUG) += debug/
|
||||
obj-$(CONFIG_AMLOGIC_DEFENDKEY) += defendkey/
|
||||
|
||||
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
|
||||
|
||||
obj-y += media_modules/
|
||||
|
||||
101
drivers/amlogic/media_modules/Kconfig
Normal file
101
drivers/amlogic/media_modules/Kconfig
Normal file
@@ -0,0 +1,101 @@
|
||||
config AMLOGIC_MEDIA_VDEC_MPEG12
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_MPEG4
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_MPEG4_MULTI
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_VC1
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_H264
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_H264_MULTI
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_H264_MVC
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_H265
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_VP9
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_MJPEG
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_MJPEG_MULTI
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_REAL
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_AVS
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VDEC_AVS2
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VENC_H264
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_VENC_H265
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
|
||||
config AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
|
||||
tristate "Amlogic Video decoder"
|
||||
default m
|
||||
help
|
||||
Enables amlogic video decoder
|
||||
4
drivers/amlogic/media_modules/Makefile
Normal file
4
drivers/amlogic/media_modules/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
obj-y += common/
|
||||
obj-y += frame_provider/
|
||||
obj-y += frame_sink/
|
||||
obj-y += stream_input/
|
||||
2
drivers/amlogic/media_modules/common/Makefile
Normal file
2
drivers/amlogic/media_modules/common/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
obj-y += media_clock/
|
||||
obj-y += firmware/
|
||||
183
drivers/amlogic/media_modules/common/chips/chips.c
Normal file
183
drivers/amlogic/media_modules/common/chips/chips.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/chips/chips.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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/amlogic/media/utils/vformat.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
#include "../../stream_input/amports/amports_priv.h"
|
||||
#include "../../frame_provider/decoder/utils/vdec.h"
|
||||
#include "chips.h"
|
||||
#include <linux/amlogic/media/utils/log.h>
|
||||
#include <linux/amlogic/media/utils/vdec_reg.h>
|
||||
|
||||
#define VIDEO_FIRMWARE_FATHER_NAME "video"
|
||||
|
||||
/*
|
||||
*#define MESON_CPU_MAJOR_ID_M6 0x16
|
||||
*#define MESON_CPU_MAJOR_ID_M6TV 0x17
|
||||
*#define MESON_CPU_MAJOR_ID_M6TVL 0x18
|
||||
*#define MESON_CPU_MAJOR_ID_M8 0x19
|
||||
*#define MESON_CPU_MAJOR_ID_MTVD 0x1A
|
||||
*#define MESON_CPU_MAJOR_ID_M8B 0x1B
|
||||
*#define MESON_CPU_MAJOR_ID_MG9TV 0x1C
|
||||
*#define MESON_CPU_MAJOR_ID_M8M2 0x1D
|
||||
*#define MESON_CPU_MAJOR_ID_GXBB 0x1F
|
||||
*#define MESON_CPU_MAJOR_ID_GXTVBB 0x20
|
||||
*#define MESON_CPU_MAJOR_ID_GXL 0x21
|
||||
*#define MESON_CPU_MAJOR_ID_GXM 0x22
|
||||
*#define MESON_CPU_MAJOR_ID_TXL 0x23
|
||||
*/
|
||||
struct type_name {
|
||||
|
||||
int type;
|
||||
|
||||
const char *name;
|
||||
};
|
||||
static const struct type_name cpu_type_name[] = {
|
||||
{MESON_CPU_MAJOR_ID_M6, "m6"},
|
||||
{MESON_CPU_MAJOR_ID_M6TV, "m6tv"},
|
||||
{MESON_CPU_MAJOR_ID_M6TVL, "m6tvl"},
|
||||
{MESON_CPU_MAJOR_ID_M8, "m8"},
|
||||
{MESON_CPU_MAJOR_ID_MTVD, "mtvd"},
|
||||
{MESON_CPU_MAJOR_ID_M8B, "m8b"},
|
||||
{MESON_CPU_MAJOR_ID_MG9TV, "mg9tv"},
|
||||
{MESON_CPU_MAJOR_ID_M8M2, "m8"},
|
||||
{MESON_CPU_MAJOR_ID_GXBB, "gxbb"},
|
||||
{MESON_CPU_MAJOR_ID_GXTVBB, "gxtvbb"},
|
||||
{MESON_CPU_MAJOR_ID_GXL, "gxl"},
|
||||
{MESON_CPU_MAJOR_ID_GXM, "gxm"},
|
||||
{MESON_CPU_MAJOR_ID_TXL, "txl"},
|
||||
{MESON_CPU_MAJOR_ID_TXLX, "txlx"},
|
||||
{MESON_CPU_MAJOR_ID_G12A, "g12a"},
|
||||
{MESON_CPU_MAJOR_ID_G12B, "g12b"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static const char *get_type_name(const struct type_name *typename, int size,
|
||||
int type)
|
||||
{
|
||||
|
||||
const char *name = "unknown";
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
|
||||
if (type == typename[i].type)
|
||||
|
||||
name = typename[i].name;
|
||||
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *get_cpu_type_name(void)
|
||||
{
|
||||
|
||||
return get_type_name(cpu_type_name,
|
||||
sizeof(cpu_type_name) / sizeof(struct type_name),
|
||||
get_cpu_type());
|
||||
}
|
||||
EXPORT_SYMBOL(get_cpu_type_name);
|
||||
|
||||
/*
|
||||
*enum vformat_e {
|
||||
* VFORMAT_MPEG12 = 0,
|
||||
* VFORMAT_MPEG4,
|
||||
* VFORMAT_H264,
|
||||
* VFORMAT_MJPEG,
|
||||
* VFORMAT_REAL,
|
||||
* VFORMAT_JPEG,
|
||||
* VFORMAT_VC1,
|
||||
* VFORMAT_AVS,
|
||||
* VFORMAT_YUV,
|
||||
* VFORMAT_H264MVC,
|
||||
* VFORMAT_H264_4K2K,
|
||||
* VFORMAT_HEVC,
|
||||
* VFORMAT_H264_ENC,
|
||||
* VFORMAT_JPEG_ENC,
|
||||
* VFORMAT_VP9,
|
||||
* VFORMAT_AVS2,
|
||||
* VFORMAT_MAX
|
||||
*};
|
||||
*/
|
||||
static const struct type_name vformat_type_name[] = {
|
||||
{VFORMAT_MPEG12, "mpeg12"},
|
||||
{VFORMAT_MPEG4, "mpeg4"},
|
||||
{VFORMAT_H264, "h264"},
|
||||
{VFORMAT_MJPEG, "mjpeg"},
|
||||
{VFORMAT_REAL, "real"},
|
||||
{VFORMAT_JPEG, "jpeg"},
|
||||
{VFORMAT_VC1, "vc1"},
|
||||
{VFORMAT_AVS, "avs"},
|
||||
{VFORMAT_YUV, "yuv"},
|
||||
{VFORMAT_H264MVC, "h264mvc"},
|
||||
{VFORMAT_H264_4K2K, "h264_4k"},
|
||||
{VFORMAT_HEVC, "hevc"},
|
||||
{VFORMAT_H264_ENC, "h264_enc"},
|
||||
{VFORMAT_JPEG_ENC, "jpeg_enc"},
|
||||
{VFORMAT_VP9, "vp9"},
|
||||
{VFORMAT_AVS2, "avs2"},
|
||||
{VFORMAT_YUV, "yuv"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
const char *get_video_format_name(enum vformat_e type)
|
||||
{
|
||||
|
||||
return get_type_name(vformat_type_name,
|
||||
sizeof(vformat_type_name) / sizeof(struct type_name), type);
|
||||
}
|
||||
EXPORT_SYMBOL(get_video_format_name);
|
||||
|
||||
static struct chip_vdec_info_s current_chip_info;
|
||||
|
||||
struct chip_vdec_info_s *get_current_vdec_chip(void)
|
||||
{
|
||||
|
||||
return ¤t_chip_info;
|
||||
}
|
||||
EXPORT_SYMBOL(get_current_vdec_chip);
|
||||
|
||||
bool check_efuse_chip(int vformat)
|
||||
{
|
||||
unsigned int status, i = 0;
|
||||
int type[] = {15, 14, 11, 2}; /* avs2, vp9, h265, h264 */
|
||||
|
||||
status = (READ_EFUSE_REG(EFUSE_LIC2) >> 8 & 0xf);
|
||||
if (!status)
|
||||
return false;
|
||||
|
||||
do {
|
||||
if ((status & 1) && (type[i] == vformat))
|
||||
return true;
|
||||
i++;
|
||||
} while (status >>= 1);
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(check_efuse_chip);
|
||||
|
||||
40
drivers/amlogic/media_modules/common/chips/chips.h
Normal file
40
drivers/amlogic/media_modules/common/chips/chips.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/chips/chips.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCODE_MANAGER_HEADER
|
||||
#define UCODE_MANAGER_HEADER
|
||||
#include "../media_clock/clk/clk_priv.h"
|
||||
|
||||
struct chip_vdec_info_s {
|
||||
|
||||
int cpu_type;
|
||||
|
||||
struct video_firmware_s *firmware;
|
||||
|
||||
struct chip_vdec_clk_s *clk_mgr[VDEC_MAX];
|
||||
|
||||
struct clk_set_setting *clk_setting_array;
|
||||
};
|
||||
|
||||
const char *get_cpu_type_name(void);
|
||||
const char *get_video_format_name(enum vformat_e type);
|
||||
|
||||
struct chip_vdec_info_s *get_current_vdec_chip(void);
|
||||
|
||||
bool check_efuse_chip(int vformat);
|
||||
|
||||
#endif
|
||||
3
drivers/amlogic/media_modules/common/firmware/Makefile
Normal file
3
drivers/amlogic/media_modules/common/firmware/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
obj-m += firmware.o
|
||||
firmware-objs += firmware_drv.o
|
||||
firmware-objs += firmware_type.o
|
||||
32
drivers/amlogic/media_modules/common/firmware/firmware_cfg.h
Normal file
32
drivers/amlogic/media_modules/common/firmware/firmware_cfg.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/firmware/firmware_cfg.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*all firmwares in one bin.*/
|
||||
{VIDEO_MISC, VIDEO_PACKAGE, "video_ucode.bin"},
|
||||
|
||||
/* Note: if the addition of new package has the same name */
|
||||
/* as the firmware in the video_ucode.bin, the firmware */
|
||||
/* in the video_ucode.bin will be ignored yet, because the */
|
||||
/* video_ucode.bin will always be processed in the end */
|
||||
{VIDEO_ENCODE, VIDEO_PACKAGE, "h264_enc.bin"},
|
||||
|
||||
|
||||
/*firmware for a special format, to replace the format in the package.*/
|
||||
{VIDEO_DECODE, VIDEO_FW_FILE, "h265.bin"},
|
||||
{VIDEO_DECODE, VIDEO_FW_FILE, "h264.bin"},
|
||||
{VIDEO_DECODE, VIDEO_FW_FILE, "h264_multi.bin"},
|
||||
|
||||
927
drivers/amlogic/media_modules/common/firmware/firmware_drv.c
Normal file
927
drivers/amlogic/media_modules/common/firmware/firmware_drv.c
Normal file
@@ -0,0 +1,927 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/firmware/firmware.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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/amlogic/media/utils/vformat.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
#include "../../stream_input/amports/amports_priv.h"
|
||||
#include "../../frame_provider/decoder/utils/vdec.h"
|
||||
#include "firmware_priv.h"
|
||||
#include "../chips/chips.h"
|
||||
#include <linux/string.h>
|
||||
#include <linux/amlogic/media/utils/log.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/amlogic/tee.h>
|
||||
#include <linux/amlogic/major.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
/* major.minor.revision */
|
||||
#define PACK_VERS "v0.0.1"
|
||||
|
||||
#define CLASS_NAME "firmware_codec"
|
||||
#define DEV_NAME "firmware_vdec"
|
||||
#define DIR "video"
|
||||
#define FRIMWARE_SIZE (64 * 1024) /*64k*/
|
||||
#define BUFF_SIZE (1024 * 1024 * 2)
|
||||
|
||||
#define FW_LOAD_FORCE (0x1)
|
||||
#define FW_LOAD_TRY (0X2)
|
||||
|
||||
/*the first 256 bytes are signature data*/
|
||||
#define SEC_OFFSET (256)
|
||||
|
||||
#define PACK ('P' << 24 | 'A' << 16 | 'C' << 8 | 'K')
|
||||
#define CODE ('C' << 24 | 'O' << 16 | 'D' << 8 | 'E')
|
||||
|
||||
static DEFINE_MUTEX(mutex);
|
||||
|
||||
static struct ucode_file_info_s ucode_info[] = {
|
||||
#include "firmware_cfg.h"
|
||||
};
|
||||
|
||||
static const struct file_operations fw_fops = {
|
||||
.owner = THIS_MODULE
|
||||
};
|
||||
|
||||
struct fw_mgr_s *g_mgr;
|
||||
struct fw_dev_s *g_dev;
|
||||
|
||||
static u32 debug;
|
||||
static u32 detail;
|
||||
|
||||
int get_firmware_data(unsigned int format, char *buf)
|
||||
{
|
||||
int data_len, ret = -1;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_info_s *info;
|
||||
|
||||
if (tee_enabled()) {
|
||||
pr_info ("tee load firmware fomat = %d\n",(u32)format);
|
||||
ret = tee_load_video_fw((u32)format, 0);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
else
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&mutex);
|
||||
|
||||
if (list_empty(&mgr->fw_head)) {
|
||||
pr_info("the info list is empty.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(info, &mgr->fw_head, node) {
|
||||
if (format != info->format)
|
||||
continue;
|
||||
|
||||
data_len = info->data->head.data_size;
|
||||
memcpy(buf, info->data->data, data_len);
|
||||
ret = data_len;
|
||||
|
||||
break;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_firmware_data);
|
||||
|
||||
int get_data_from_name(const char *name, char *buf)
|
||||
{
|
||||
int data_len, ret = -1;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_info_s *info;
|
||||
char *fw_name = __getname();
|
||||
|
||||
if (IS_ERR_OR_NULL(fw_name))
|
||||
return -ENOMEM;
|
||||
|
||||
strcat(fw_name, name);
|
||||
strcat(fw_name, ".bin");
|
||||
|
||||
mutex_lock(&mutex);
|
||||
|
||||
if (list_empty(&mgr->fw_head)) {
|
||||
pr_info("the info list is empty.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(info, &mgr->fw_head, node) {
|
||||
if (strcmp(fw_name, info->name))
|
||||
continue;
|
||||
|
||||
data_len = info->data->head.data_size;
|
||||
memcpy(buf, info->data->data, data_len);
|
||||
ret = data_len;
|
||||
|
||||
break;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&mutex);
|
||||
|
||||
__putname(fw_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_data_from_name);
|
||||
|
||||
static int fw_probe(char *buf)
|
||||
{
|
||||
int magic = 0;
|
||||
|
||||
memcpy(&magic, buf, sizeof(int));
|
||||
return magic;
|
||||
}
|
||||
|
||||
static int request_firmware_from_sys(const char *file_name,
|
||||
char *buf, int size)
|
||||
{
|
||||
int ret = -1;
|
||||
const struct firmware *fw;
|
||||
int magic, offset = 0;
|
||||
|
||||
pr_info("Try to load %s ...\n", file_name);
|
||||
|
||||
ret = request_firmware(&fw, file_name, g_dev->dev);
|
||||
if (ret < 0) {
|
||||
pr_info("Error : %d can't load the %s.\n", ret, file_name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fw->size > size) {
|
||||
pr_info("Not enough memory size for ucode.\n");
|
||||
ret = -ENOMEM;
|
||||
goto release;
|
||||
}
|
||||
|
||||
magic = fw_probe((char *)fw->data);
|
||||
if (magic != PACK && magic != CODE) {
|
||||
if (fw->size < SEC_OFFSET) {
|
||||
pr_info("This is an invalid firmware file.\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
magic = fw_probe((char *)fw->data + SEC_OFFSET);
|
||||
if (magic != PACK) {
|
||||
pr_info("The firmware file is not packet.\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
offset = SEC_OFFSET;
|
||||
}
|
||||
|
||||
memcpy(buf, (char *)fw->data + offset, fw->size - offset);
|
||||
|
||||
pr_info("load firmware size : %zd, Name : %s.\n",
|
||||
fw->size, file_name);
|
||||
ret = fw->size;
|
||||
release:
|
||||
release_firmware(fw);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int request_decoder_firmware_on_sys(enum vformat_e format,
|
||||
const char *file_name, char *buf, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = get_data_from_name(file_name, buf);
|
||||
if (ret < 0)
|
||||
pr_info("Get firmware fail.\n");
|
||||
|
||||
if (ret > size) {
|
||||
pr_info("Not enough memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
int get_decoder_firmware_data(enum vformat_e format,
|
||||
const char *file_name, char *buf, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = request_decoder_firmware_on_sys(format, file_name, buf, size);
|
||||
if (ret < 0)
|
||||
pr_info("get_decoder_firmware_data %s for format %d failed!\n",
|
||||
file_name, format);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_decoder_firmware_data);
|
||||
|
||||
static unsigned long fw_mgr_lock(struct fw_mgr_s *mgr)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mgr->lock, flags);
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void fw_mgr_unlock(struct fw_mgr_s *mgr, unsigned long flags)
|
||||
{
|
||||
spin_unlock_irqrestore(&mgr->lock, flags);
|
||||
}
|
||||
|
||||
static void fw_add_info(struct fw_info_s *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
|
||||
flags = fw_mgr_lock(mgr);
|
||||
list_add(&info->node, &mgr->fw_head);
|
||||
fw_mgr_unlock(mgr, flags);
|
||||
}
|
||||
|
||||
static void fw_del_info(struct fw_info_s *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
|
||||
flags = fw_mgr_lock(mgr);
|
||||
list_del(&info->node);
|
||||
kfree(info);
|
||||
fw_mgr_unlock(mgr, flags);
|
||||
}
|
||||
|
||||
static void fw_info_walk(void)
|
||||
{
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_info_s *info;
|
||||
|
||||
if (list_empty(&mgr->fw_head)) {
|
||||
pr_info("the info list is empty.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(info, &mgr->fw_head, node) {
|
||||
if (IS_ERR_OR_NULL(info->data))
|
||||
continue;
|
||||
|
||||
pr_info("name : %s.\n", info->name);
|
||||
pr_info("ver : %s.\n",
|
||||
info->data->head.version);
|
||||
pr_info("crc : 0x%x.\n",
|
||||
info->data->head.checksum);
|
||||
pr_info("size : %d.\n",
|
||||
info->data->head.data_size);
|
||||
pr_info("maker: %s.\n",
|
||||
info->data->head.maker);
|
||||
pr_info("from : %s.\n", info->src_from);
|
||||
pr_info("date : %s.\n\n",
|
||||
info->data->head.date);
|
||||
}
|
||||
}
|
||||
|
||||
static void fw_files_info_walk(void)
|
||||
{
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_files_s *files;
|
||||
|
||||
if (list_empty(&mgr->files_head)) {
|
||||
pr_info("the file list is empty.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(files, &mgr->files_head, node) {
|
||||
pr_info("type : %s.\n", !files->fw_type ?
|
||||
"VIDEO_DECODE" : files->fw_type == 1 ?
|
||||
"VIDEO_ENCODE" : "VIDEO_MISC");
|
||||
pr_info("from : %s.\n", !files->file_type ?
|
||||
"VIDEO_PACKAGE" : "VIDEO_FW_FILE");
|
||||
pr_info("path : %s.\n", files->path);
|
||||
pr_info("name : %s.\n\n", files->name);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t info_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_info_s *info;
|
||||
unsigned int secs = 0;
|
||||
struct tm tm;
|
||||
|
||||
mutex_lock(&mutex);
|
||||
|
||||
if (list_empty(&mgr->fw_head)) {
|
||||
pbuf += sprintf(pbuf, "No firmware.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(info, &mgr->fw_head, node) {
|
||||
if (IS_ERR_OR_NULL(info->data))
|
||||
continue;
|
||||
|
||||
if (detail) {
|
||||
pr_info("%-5s: %s\n", "name", info->name);
|
||||
pr_info("%-5s: %s\n", "ver",
|
||||
info->data->head.version);
|
||||
pr_info("%-5s: 0x%x\n", "sum",
|
||||
info->data->head.checksum);
|
||||
pr_info("%-5s: %d\n", "size",
|
||||
info->data->head.data_size);
|
||||
pr_info("%-5s: %s\n", "maker",
|
||||
info->data->head.maker);
|
||||
pr_info("%-5s: %s\n", "from",
|
||||
info->src_from);
|
||||
pr_info("%-5s: %s\n\n", "date",
|
||||
info->data->head.date);
|
||||
continue;
|
||||
}
|
||||
|
||||
secs = info->data->head.time
|
||||
- sys_tz.tz_minuteswest * 60;
|
||||
time_to_tm(secs, 0, &tm);
|
||||
|
||||
pr_info("%s %-16s, %02d:%02d:%02d %d/%d/%ld, %s %-8s, %s %s\n",
|
||||
"fmt:", info->data->head.format,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900,
|
||||
"id:", info->data->head.commit,
|
||||
"mk:", info->data->head.maker);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&mutex);
|
||||
|
||||
return pbuf - buf;
|
||||
}
|
||||
|
||||
static ssize_t info_store(struct class *cls,
|
||||
struct class_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
if (kstrtoint(buf, 0, &detail) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int fw_info_fill(void)
|
||||
{
|
||||
int ret = 0, i, len;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_files_s *files;
|
||||
int info_size = ARRAY_SIZE(ucode_info);
|
||||
char *path = __getname();
|
||||
const char *name;
|
||||
|
||||
if (IS_ERR_OR_NULL(path))
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < info_size; i++) {
|
||||
name = ucode_info[i].name;
|
||||
if (IS_ERR_OR_NULL(name))
|
||||
break;
|
||||
|
||||
len = snprintf(path, PATH_MAX, "%s/%s", DIR,
|
||||
ucode_info[i].name);
|
||||
if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
files = kzalloc(sizeof(struct fw_files_s), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(files)) {
|
||||
__putname(path);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
files->file_type = ucode_info[i].file_type;
|
||||
files->fw_type = ucode_info[i].fw_type;
|
||||
strncpy(files->path, path, sizeof(files->path));
|
||||
strncpy(files->name, name, sizeof(files->name));
|
||||
|
||||
list_add(&files->node, &mgr->files_head);
|
||||
}
|
||||
|
||||
__putname(path);
|
||||
|
||||
if (debug)
|
||||
fw_files_info_walk();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_data_check_sum(struct firmware_s *fw)
|
||||
{
|
||||
unsigned int crc;
|
||||
|
||||
crc = crc32_le(~0U, fw->data, fw->head.data_size);
|
||||
|
||||
/*pr_info("firmware crc result : 0x%x\n", crc ^ ~0U);*/
|
||||
|
||||
return fw->head.checksum != (crc ^ ~0U) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int fw_data_filter(struct firmware_s *fw,
|
||||
struct fw_info_s *fw_info)
|
||||
{
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_info_s *info, *tmp;
|
||||
int cpu = fw_get_cpu(fw->head.cpu);
|
||||
|
||||
if (mgr->cur_cpu < cpu) {
|
||||
pr_info("the fw %s is not match.\n", fw_info->name);
|
||||
kfree(fw_info);
|
||||
kfree(fw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the encode fw need to ignoring filtering rules. */
|
||||
if (fw_info->format == FIRMWARE_MAX)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry_safe(info, tmp, &mgr->fw_head, node) {
|
||||
if (info->format != fw_info->format)
|
||||
continue;
|
||||
|
||||
if (IS_ERR_OR_NULL(info->data)) {
|
||||
fw_del_info(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* high priority of VIDEO_FW_FILE */
|
||||
if (info->file_type == VIDEO_FW_FILE) {
|
||||
pr_info("the %s need to priority proc.\n",info->name);
|
||||
kfree(fw_info);
|
||||
kfree(fw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* the cpu ver is lower and needs to be filtered */
|
||||
if (cpu < fw_get_cpu(info->data->head.cpu)) {
|
||||
pr_info("the fw %s is not match.\n",
|
||||
fw_info->name);
|
||||
kfree(fw_info);
|
||||
kfree(fw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* removes not match fw from info list */
|
||||
pr_info("the fw %s is not match.\n", info->name);
|
||||
kfree(info->data);
|
||||
fw_del_info(info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_check_pack_version(char *buf)
|
||||
{
|
||||
struct package_s *pack = NULL;
|
||||
int major, minor, rev, ver = 0;
|
||||
|
||||
pack = (struct package_s *) buf;
|
||||
sscanf(PACK_VERS, "v%x.%x.%x", &major, &minor, &rev);
|
||||
ver = (major << 24 | minor << 16 | rev);
|
||||
|
||||
pr_info("the package has %d fws totally.\n", pack->head.total);
|
||||
|
||||
major = pack->head.version >> 24;
|
||||
minor = (pack->head.version >> 16) & 0xf;
|
||||
rev = pack->head.version & 0xff;
|
||||
|
||||
if (ver < pack->head.version) {
|
||||
pr_info("the pack ver v%d.%d.%d too higher to unsupport.\n",
|
||||
major, minor, rev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ver != pack->head.version) {
|
||||
pr_info("the fw pack ver v%d.%d.%d is too lower.\n", major, minor, rev);
|
||||
pr_info("it may work abnormally so need to be update in time.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_package_parse(struct fw_files_s *files,
|
||||
char *buf, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct package_info_s *pack_info;
|
||||
struct fw_info_s *info;
|
||||
struct firmware_s *data;
|
||||
char *pack_data;
|
||||
int info_len, len;
|
||||
int try_cnt = 100;
|
||||
char *path = __getname();
|
||||
|
||||
if (IS_ERR_OR_NULL(path))
|
||||
return -ENOMEM;
|
||||
|
||||
pack_data = ((struct package_s *)buf)->data;
|
||||
pack_info = (struct package_info_s *)pack_data;
|
||||
info_len = sizeof(struct package_info_s);
|
||||
|
||||
do {
|
||||
if (!pack_info->head.length)
|
||||
break;
|
||||
|
||||
len = snprintf(path, PATH_MAX, "%s/%s", DIR,
|
||||
pack_info->head.name);
|
||||
if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(info)) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(data)) {
|
||||
kfree(info);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info->file_type = files->file_type;
|
||||
strncpy(info->src_from, files->name,
|
||||
sizeof(info->src_from));
|
||||
strncpy(info->name, pack_info->head.name,
|
||||
sizeof(info->name));
|
||||
info->format = get_fw_format(pack_info->head.format);
|
||||
|
||||
len = pack_info->head.length;
|
||||
memcpy(data, pack_info->data, len);
|
||||
|
||||
pack_data += (pack_info->head.length + info_len);
|
||||
pack_info = (struct package_info_s *)pack_data;
|
||||
|
||||
if (!fw_data_check_sum(data)) {
|
||||
pr_info("check sum fail !\n");
|
||||
kfree(data);
|
||||
kfree(info);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fw_data_filter(data, info))
|
||||
continue;
|
||||
|
||||
if (debug)
|
||||
pr_info("adds %s to the fw list.\n", info->name);
|
||||
|
||||
info->data = data;
|
||||
fw_add_info(info);
|
||||
} while (try_cnt--);
|
||||
out:
|
||||
__putname(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_code_parse(struct fw_files_s *files,
|
||||
char *buf, int size)
|
||||
{
|
||||
struct fw_info_s *info;
|
||||
|
||||
info = kzalloc(sizeof(struct fw_info_s), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(info))
|
||||
return -ENOMEM;
|
||||
|
||||
info->data = kzalloc(FRIMWARE_SIZE, GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(info->data))
|
||||
return -ENOMEM;
|
||||
|
||||
info->file_type = files->file_type;
|
||||
strncpy(info->src_from, files->name,
|
||||
sizeof(info->src_from));
|
||||
memcpy(info->data, buf, size);
|
||||
|
||||
if (!fw_data_check_sum(info->data)) {
|
||||
pr_info("check sum fail !\n");
|
||||
kfree(info->data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
pr_info("adds %s to the fw list.\n", info->name);
|
||||
|
||||
fw_add_info(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_firmware_from_sys(const char *path,
|
||||
char *buf, int size)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len = request_firmware_from_sys(path, buf, size);
|
||||
if (len < 0)
|
||||
pr_info("get data from fsys fail.\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int fw_data_binding(void)
|
||||
{
|
||||
int ret = 0, magic = 0;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_files_s *files, *tmp;
|
||||
char *buf = vmalloc(BUFF_SIZE);
|
||||
int size;
|
||||
|
||||
if (list_empty(&mgr->files_head)) {
|
||||
pr_info("the file list is empty.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(buf))
|
||||
return -ENOMEM;
|
||||
|
||||
memset(buf, 0, BUFF_SIZE);
|
||||
|
||||
list_for_each_entry_safe(files, tmp, &mgr->files_head, node) {
|
||||
size = get_firmware_from_sys(files->path, buf, BUFF_SIZE);
|
||||
magic = fw_probe(buf);
|
||||
|
||||
if (files->file_type == VIDEO_PACKAGE && magic == PACK) {
|
||||
pr_info("start to parse fw package.\n");
|
||||
|
||||
if (!fw_check_pack_version(buf))
|
||||
ret = fw_package_parse(files, buf, size);
|
||||
} else if (files->file_type == VIDEO_FW_FILE && magic == CODE) {
|
||||
pr_info("start to parse fw code.\n");
|
||||
|
||||
ret = fw_code_parse(files, buf, size);
|
||||
} else {
|
||||
list_del(&files->node);
|
||||
kfree(files);
|
||||
pr_info("invaild file type.\n");
|
||||
}
|
||||
|
||||
memset(buf, 0, BUFF_SIZE);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
fw_info_walk();
|
||||
|
||||
vfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fw_pre_load(void)
|
||||
{
|
||||
if (fw_info_fill() < 0) {
|
||||
pr_info("Get path fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fw_data_binding() < 0) {
|
||||
pr_info("Set data fail.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fw_mgr_init(void)
|
||||
{
|
||||
g_mgr = kzalloc(sizeof(struct fw_mgr_s), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(g_mgr))
|
||||
return -ENOMEM;
|
||||
|
||||
g_mgr->cur_cpu = get_cpu_type();
|
||||
INIT_LIST_HEAD(&g_mgr->files_head);
|
||||
INIT_LIST_HEAD(&g_mgr->fw_head);
|
||||
spin_lock_init(&g_mgr->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fw_ctx_clean(void)
|
||||
{
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
struct fw_files_s *files;
|
||||
struct fw_info_s *info;
|
||||
unsigned long flags;
|
||||
|
||||
flags = fw_mgr_lock(mgr);
|
||||
while (!list_empty(&mgr->files_head)) {
|
||||
files = list_entry(mgr->files_head.next,
|
||||
struct fw_files_s, node);
|
||||
list_del(&files->node);
|
||||
kfree(files);
|
||||
}
|
||||
|
||||
while (!list_empty(&mgr->fw_head)) {
|
||||
info = list_entry(mgr->fw_head.next,
|
||||
struct fw_info_s, node);
|
||||
list_del(&info->node);
|
||||
kfree(info->data);
|
||||
kfree(info);
|
||||
}
|
||||
fw_mgr_unlock(mgr, flags);
|
||||
}
|
||||
|
||||
int video_fw_reload(int mode)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fw_mgr_s *mgr = g_mgr;
|
||||
|
||||
if (tee_enabled())
|
||||
return 0;
|
||||
|
||||
mutex_lock(&mutex);
|
||||
|
||||
if (mode & FW_LOAD_FORCE) {
|
||||
fw_ctx_clean();
|
||||
|
||||
ret = fw_pre_load();
|
||||
if (ret < 0)
|
||||
pr_err("The fw reload fail.\n");
|
||||
} else if (mode & FW_LOAD_TRY) {
|
||||
if (!list_empty(&mgr->fw_head)) {
|
||||
pr_info("The fw has been loaded.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fw_pre_load();
|
||||
if (ret < 0)
|
||||
pr_err("The fw try to reload fail.\n");
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(video_fw_reload);
|
||||
|
||||
static ssize_t reload_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
|
||||
pbuf += sprintf(pbuf, "The fw reload usage.\n");
|
||||
pbuf += sprintf(pbuf, "> set 1 means that the fw is forced to update\n");
|
||||
pbuf += sprintf(pbuf, "> set 2 means that the fw is try to reload\n");
|
||||
|
||||
return pbuf - buf;
|
||||
}
|
||||
|
||||
static ssize_t reload_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int val;
|
||||
|
||||
ret = kstrtoint(buf, 0, &val);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = video_fw_reload(val);
|
||||
if (ret < 0)
|
||||
pr_err("fw reload fail.\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t debug_show(struct class *cls,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%x\n", debug);
|
||||
}
|
||||
|
||||
static ssize_t debug_store(struct class *cls,
|
||||
struct class_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
if (kstrtoint(buf, 0, &debug) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct class_attribute fw_class_attrs[] = {
|
||||
__ATTR(info, 0664, info_show, info_store),
|
||||
__ATTR(reload, 0664, reload_show, reload_store),
|
||||
__ATTR(debug, 0664, debug_show, debug_store),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static struct class fw_class = {
|
||||
.name = CLASS_NAME,
|
||||
.class_attrs = fw_class_attrs,
|
||||
};
|
||||
|
||||
static int fw_driver_init(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
g_dev = kzalloc(sizeof(struct fw_dev_s), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(g_dev))
|
||||
return -ENOMEM;
|
||||
|
||||
g_dev->dev_no = MKDEV(AMSTREAM_MAJOR, 100);
|
||||
|
||||
ret = register_chrdev_region(g_dev->dev_no, 1, DEV_NAME);
|
||||
if (ret < 0) {
|
||||
pr_info("Can't get major number %d.\n", AMSTREAM_MAJOR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
cdev_init(&g_dev->cdev, &fw_fops);
|
||||
g_dev->cdev.owner = THIS_MODULE;
|
||||
|
||||
ret = cdev_add(&g_dev->cdev, g_dev->dev_no, 1);
|
||||
if (ret) {
|
||||
pr_info("Error %d adding cdev fail.\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = class_register(&fw_class);
|
||||
if (ret < 0) {
|
||||
pr_info("Failed in creating class.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
g_dev->dev = device_create(&fw_class, NULL,
|
||||
g_dev->dev_no, NULL, DEV_NAME);
|
||||
if (IS_ERR_OR_NULL(g_dev->dev)) {
|
||||
pr_info("Create device failed.\n");
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pr_info("Registered firmware driver success.\n");
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fw_driver_exit(void)
|
||||
{
|
||||
cdev_del(&g_dev->cdev);
|
||||
device_destroy(&fw_class, g_dev->dev_no);
|
||||
class_unregister(&fw_class);
|
||||
unregister_chrdev_region(g_dev->dev_no, 1);
|
||||
kfree(g_dev);
|
||||
kfree(g_mgr);
|
||||
}
|
||||
|
||||
static int __init fw_module_init(void)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
ret = fw_driver_init();
|
||||
if (ret) {
|
||||
pr_info("Error %d firmware driver init fail.\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = fw_mgr_init();
|
||||
if (ret) {
|
||||
pr_info("Error %d firmware mgr init fail.\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = fw_pre_load();
|
||||
if (ret) {
|
||||
pr_info("Error %d firmware pre load fail.\n", ret);
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fw_module_exit(void)
|
||||
{
|
||||
fw_ctx_clean();
|
||||
fw_driver_exit();
|
||||
pr_info("Firmware driver cleaned up.\n");
|
||||
}
|
||||
|
||||
module_init(fw_module_init);
|
||||
module_exit(fw_module_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Nanxin Qin <nanxin.qin@amlogic.com>");
|
||||
117
drivers/amlogic/media_modules/common/firmware/firmware_priv.h
Normal file
117
drivers/amlogic/media_modules/common/firmware/firmware_priv.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/firmware/firmware.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VIDEO_FIRMWARE_PRIV_HEAD_
|
||||
#define __VIDEO_FIRMWARE_PRIV_HEAD_
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cdev.h>
|
||||
#include "firmware_type.h"
|
||||
|
||||
struct fw_mgr_s {
|
||||
struct list_head fw_head;
|
||||
struct list_head files_head;
|
||||
spinlock_t lock;
|
||||
int cur_cpu;
|
||||
};
|
||||
|
||||
struct fw_files_s {
|
||||
struct list_head node;
|
||||
int fw_type;
|
||||
int file_type;
|
||||
char name[32];
|
||||
char path[64];
|
||||
};
|
||||
|
||||
struct ucode_file_info_s {
|
||||
int fw_type;
|
||||
int file_type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct fw_info_s {
|
||||
struct list_head node;
|
||||
char name[32];
|
||||
char src_from[32];
|
||||
int file_type;
|
||||
unsigned int format;
|
||||
struct firmware_s *data;
|
||||
};
|
||||
|
||||
struct fw_head_s {
|
||||
int magic;
|
||||
int checksum;
|
||||
char name[32];
|
||||
char cpu[16];
|
||||
char format[32];
|
||||
char version[32];
|
||||
char maker[32];
|
||||
char date[32];
|
||||
char commit[16];
|
||||
int data_size;
|
||||
unsigned int time;
|
||||
char reserved[128];
|
||||
};
|
||||
|
||||
struct firmware_s {
|
||||
union {
|
||||
struct fw_head_s head;
|
||||
char buf[512];
|
||||
};
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct package_head_s {
|
||||
int magic;
|
||||
int size;
|
||||
int checksum;
|
||||
int total;
|
||||
int version;
|
||||
char reserved[128];
|
||||
};
|
||||
|
||||
struct package_s {
|
||||
union {
|
||||
struct package_head_s head;
|
||||
char buf[256];
|
||||
};
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct info_head_s {
|
||||
char name[32];
|
||||
char format[32];
|
||||
char cpu[32];
|
||||
int length;
|
||||
};
|
||||
|
||||
struct package_info_s {
|
||||
union {
|
||||
struct info_head_s head;
|
||||
char buf[256];
|
||||
};
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct fw_dev_s {
|
||||
struct cdev cdev;
|
||||
struct device *dev;
|
||||
dev_t dev_no;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "firmware_type.h"
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
|
||||
static const struct format_name_s format_name[] = {
|
||||
{VIDEO_DEC_MPEG12, "mpeg12"},
|
||||
{VIDEO_DEC_MPEG12_MULTI, "mpeg12_multi"},
|
||||
{VIDEO_DEC_MPEG4_3, "divx311"},
|
||||
{VIDEO_DEC_MPEG4_4, "divx4x"},
|
||||
{VIDEO_DEC_MPEG4_4_MULTI, "divx4x_multi"},
|
||||
{VIDEO_DEC_MPEG4_5, "xvid"},
|
||||
{VIDEO_DEC_MPEG4_5_MULTI, "xvid_multi"},
|
||||
{VIDEO_DEC_H263, "h263"},
|
||||
{VIDEO_DEC_H263_MULTI, "h263_multi"},
|
||||
{VIDEO_DEC_MJPEG, "mjpeg"},
|
||||
{VIDEO_DEC_MJPEG_MULTI, "mjpeg_multi"},
|
||||
{VIDEO_DEC_REAL_V8, "real_v8"},
|
||||
{VIDEO_DEC_REAL_V9, "real_v9"},
|
||||
{VIDEO_DEC_VC1, "vc1"},
|
||||
{VIDEO_DEC_VC1_G12A, "vc1_g12a"},
|
||||
{VIDEO_DEC_AVS, "avs"},
|
||||
{VIDEO_DEC_AVS_GXM, "avs_gxm"},
|
||||
{VIDEO_DEC_AVS_NOCABAC, "avs_no_cabac"},
|
||||
{VIDEO_DEC_H264, "h264"},
|
||||
{VIDEO_DEC_H264_4k2K, "h264_4k2k"},
|
||||
{VIDEO_DEC_H264_4k2K_SINGLE, "h264_4k2k_single"},
|
||||
{VIDEO_DEC_H264_MVC, "h264_mvc"},
|
||||
{VIDEO_DEC_H264_MVC_GXM, "h264_mvc_gxm"},
|
||||
{VIDEO_DEC_H264_MULTI, "h264_multi"},
|
||||
{VIDEO_DEC_H264_MULTI_MMU, "h264_multi_mmu"},
|
||||
{VIDEO_DEC_H264_MULTI_GXM, "h264_multi_gxm"},
|
||||
{VIDEO_DEC_HEVC, "hevc"},
|
||||
{VIDEO_DEC_HEVC_MMU, "hevc_mmu"},
|
||||
{VIDEO_DEC_HEVC_G12A, "hevc_g12a"},
|
||||
{VIDEO_DEC_VP9, "vp9"},
|
||||
{VIDEO_DEC_VP9_MMU, "vp9_mmu"},
|
||||
{VIDEO_DEC_VP9_G12A, "vp9_g12a"},
|
||||
{VIDEO_DEC_AVS2, "avs2"},
|
||||
{VIDEO_DEC_AVS2_MMU, "avs2_mmu"},
|
||||
{VIDEO_ENC_H264, "h264_enc"},
|
||||
{VIDEO_ENC_JPEG, "jpeg_enc"},
|
||||
{FIRMWARE_MAX, "unknown"},
|
||||
};
|
||||
|
||||
static const struct cpu_type_s cpu_type[] = {
|
||||
{MESON_CPU_MAJOR_ID_GXL, "gxl"},
|
||||
{MESON_CPU_MAJOR_ID_GXM, "gxm"},
|
||||
{MESON_CPU_MAJOR_ID_G12A, "g12a"},
|
||||
{MESON_CPU_MAJOR_ID_G12B, "g12b"},
|
||||
};
|
||||
|
||||
const char *get_fw_format_name(unsigned int format)
|
||||
{
|
||||
const char *name = "unknown";
|
||||
int i, size = ARRAY_SIZE(format_name);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (format == format_name[i].format)
|
||||
name = format_name[i].name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
EXPORT_SYMBOL(get_fw_format_name);
|
||||
|
||||
unsigned int get_fw_format(const char *name)
|
||||
{
|
||||
unsigned int format = FIRMWARE_MAX;
|
||||
int i, size = ARRAY_SIZE(format_name);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (!strcmp(name, format_name[i].name))
|
||||
format = format_name[i].format;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
EXPORT_SYMBOL(get_fw_format);
|
||||
|
||||
int fw_get_cpu(const char *name)
|
||||
{
|
||||
int type = 0;
|
||||
int i, size = ARRAY_SIZE(cpu_type);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (!strcmp(name, cpu_type[i].name))
|
||||
type = cpu_type[i].type;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
EXPORT_SYMBOL(fw_get_cpu);
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef __VIDEO_FIRMWARE_FORMAT_
|
||||
#define __VIDEO_FIRMWARE_FORMAT_
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* example: #define VIDEO_DEC_AV1 TAG('A', 'V', '1', '-')*/
|
||||
#define TAG(a, b, c, d)\
|
||||
((a << 24) | (b << 16) | (c << 8) | d)
|
||||
|
||||
/* fws define */
|
||||
#define VIDEO_DEC_MPEG12 (0)
|
||||
#define VIDEO_DEC_MPEG4_3 (1)
|
||||
#define VIDEO_DEC_MPEG4_4 (2)
|
||||
#define VIDEO_DEC_MPEG4_5 (3)
|
||||
#define VIDEO_DEC_H263 (4)
|
||||
#define VIDEO_DEC_MJPEG (5)
|
||||
#define VIDEO_DEC_MJPEG_MULTI (6)
|
||||
#define VIDEO_DEC_REAL_V8 (7)
|
||||
#define VIDEO_DEC_REAL_V9 (8)
|
||||
#define VIDEO_DEC_VC1 (9)
|
||||
#define VIDEO_DEC_AVS (10)
|
||||
#define VIDEO_DEC_H264 (11)
|
||||
#define VIDEO_DEC_H264_4k2K (12)
|
||||
#define VIDEO_DEC_H264_4k2K_SINGLE (13)
|
||||
#define VIDEO_DEC_H264_MVC (14)
|
||||
#define VIDEO_DEC_H264_MULTI (15)
|
||||
#define VIDEO_DEC_HEVC (16)
|
||||
#define VIDEO_DEC_HEVC_MMU (17)
|
||||
#define VIDEO_DEC_VP9 (18)
|
||||
#define VIDEO_DEC_VP9_MMU (19)
|
||||
#define VIDEO_ENC_H264 (20)
|
||||
#define VIDEO_ENC_JPEG (21)
|
||||
#define VIDEO_DEC_H264_MULTI_MMU (23)
|
||||
#define VIDEO_DEC_HEVC_G12A (24)
|
||||
#define VIDEO_DEC_VP9_G12A (25)
|
||||
#define VIDEO_DEC_AVS2 (26)
|
||||
#define VIDEO_DEC_AVS2_MMU (27)
|
||||
#define VIDEO_DEC_AVS_GXM (28)
|
||||
#define VIDEO_DEC_AVS_NOCABAC (29)
|
||||
#define VIDEO_DEC_H264_MULTI_GXM (30)
|
||||
#define VIDEO_DEC_H264_MVC_GXM (31)
|
||||
#define VIDEO_DEC_VC1_G12A (32)
|
||||
#define VIDEO_DEC_MPEG12_MULTI TAG('M', '1', '2', 'M')
|
||||
#define VIDEO_DEC_MPEG4_4_MULTI TAG('M', '4', '4', 'M')
|
||||
#define VIDEO_DEC_MPEG4_5_MULTI TAG('M', '4', '5', 'M')
|
||||
#define VIDEO_DEC_H263_MULTI TAG('2', '6', '3', 'M')
|
||||
|
||||
/* ... */
|
||||
#define FIRMWARE_MAX (UINT_MAX)
|
||||
|
||||
#define VIDEO_PACKAGE (0)
|
||||
#define VIDEO_FW_FILE (1)
|
||||
|
||||
#define VIDEO_DECODE (0)
|
||||
#define VIDEO_ENCODE (1)
|
||||
#define VIDEO_MISC (2)
|
||||
|
||||
#define OPTEE_VDEC_LEGENCY (0)
|
||||
#define OPTEE_VDEC (1)
|
||||
#define OPTEE_VDEC_HEVC (2)
|
||||
|
||||
struct format_name_s {
|
||||
unsigned int format;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct cpu_type_s {
|
||||
int type;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
const char *get_firmware_type_name(unsigned int format);
|
||||
unsigned int get_fw_format(const char *name);
|
||||
int fw_get_cpu(const char *name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
obj-m += media_clock.o
|
||||
media_clock-objs += ../chips/chips.o
|
||||
media_clock-objs += clk/clkg12.o
|
||||
media_clock-objs += clk/clk.o
|
||||
media_clock-objs += switch/amports_gate.o
|
||||
455
drivers/amlogic/media_modules/common/media_clock/clk/clk.c
Normal file
455
drivers/amlogic/media_modules/common/media_clock/clk/clk.c
Normal file
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/clk/clk.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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/amlogic/media/utils/vformat.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
#include "../../../stream_input/amports/amports_priv.h"
|
||||
#include "../../../frame_provider/decoder/utils/vdec.h"
|
||||
#include "../../chips/chips.h"
|
||||
#include "clk_priv.h"
|
||||
#include <linux/amlogic/media/utils/log.h>
|
||||
|
||||
#define p_vdec() (get_current_vdec_chip()->clk_mgr[VDEC_1])
|
||||
#define p_vdec2() (get_current_vdec_chip()->clk_mgr[VDEC_2])
|
||||
#define p_vdec_hcodec() (get_current_vdec_chip()->clk_mgr[VDEC_HCODEC])
|
||||
#define p_vdec_hevc() (get_current_vdec_chip()->clk_mgr[VDEC_HEVC])
|
||||
#define p_vdec_hevc_back() (get_current_vdec_chip()->clk_mgr[VDEC_HEVCB])
|
||||
|
||||
static int clock_source_wxhxfps_saved[VDEC_MAX + 1];
|
||||
|
||||
#define IF_HAVE_RUN(p, fn)\
|
||||
do {\
|
||||
if (p && p->fn)\
|
||||
p->fn();\
|
||||
} while (0)
|
||||
/*
|
||||
*#define IF_HAVE_RUN_P1_RET(p, fn, p1)\
|
||||
* do {\
|
||||
* pr_debug("%s-----%d\n", __func__, clk);\
|
||||
* if (p && p->fn)\
|
||||
* return p->fn(p1);\
|
||||
* else\
|
||||
* return -1;\
|
||||
* } while (0)
|
||||
*
|
||||
*#define IF_HAVE_RUN_RET(p, fn)\
|
||||
* do {\
|
||||
* if (p && p->fn)\
|
||||
* return p->fn();\
|
||||
* else\
|
||||
* return 0;\
|
||||
* } while (0)
|
||||
*/
|
||||
|
||||
int vdec_clock_init(void)
|
||||
{
|
||||
if (p_vdec() && p_vdec()->clock_init)
|
||||
return p_vdec()->clock_init();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clock_init);
|
||||
|
||||
/*
|
||||
*clk ==0 :
|
||||
* to be release.
|
||||
* released shared clk,
|
||||
*clk ==1 :default low clk
|
||||
*clk ==2 :default high clk
|
||||
*/
|
||||
int vdec_clock_set(int clk)
|
||||
{
|
||||
pr_debug("%s-----%d\n", __func__, clk);
|
||||
if (p_vdec() && p_vdec()->clock_set)
|
||||
return p_vdec()->clock_set(clk);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clock_set);
|
||||
|
||||
void vdec_clock_enable(void)
|
||||
{
|
||||
vdec_clock_set(1);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clock_enable);
|
||||
|
||||
void vdec_clock_hi_enable(void)
|
||||
{
|
||||
vdec_clock_set(2);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clock_hi_enable);
|
||||
|
||||
void vdec_clock_on(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec(), clock_on);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clock_on);
|
||||
|
||||
void vdec_clock_off(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec(), clock_off);
|
||||
clock_source_wxhxfps_saved[VDEC_1] = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clock_off);
|
||||
|
||||
int vdec2_clock_set(int clk)
|
||||
{
|
||||
pr_debug("%s-----%d\n", __func__, clk);
|
||||
if (p_vdec2() && p_vdec2()->clock_set)
|
||||
return p_vdec2()->clock_set(clk);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec2_clock_set);
|
||||
|
||||
void vdec2_clock_enable(void)
|
||||
{
|
||||
vdec2_clock_set(1);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec2_clock_enable);
|
||||
|
||||
void vdec2_clock_hi_enable(void)
|
||||
{
|
||||
vdec2_clock_set(2);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec2_clock_hi_enable);
|
||||
|
||||
void vdec2_clock_on(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec2(), clock_on);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec2_clock_on);
|
||||
|
||||
void vdec2_clock_off(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec2(), clock_off);
|
||||
clock_source_wxhxfps_saved[VDEC_2] = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec2_clock_off);
|
||||
|
||||
int hcodec_clock_set(int clk)
|
||||
{
|
||||
pr_debug("%s-----%d\n", __func__, clk);
|
||||
if (p_vdec_hcodec() && p_vdec_hcodec()->clock_set)
|
||||
return p_vdec_hcodec()->clock_set(clk);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(hcodec_clock_set);
|
||||
|
||||
void hcodec_clock_enable(void)
|
||||
{
|
||||
hcodec_clock_set(1);
|
||||
}
|
||||
EXPORT_SYMBOL(hcodec_clock_enable);
|
||||
|
||||
void hcodec_clock_hi_enable(void)
|
||||
{
|
||||
hcodec_clock_set(2);
|
||||
}
|
||||
EXPORT_SYMBOL(hcodec_clock_hi_enable);
|
||||
|
||||
void hcodec_clock_on(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec_hcodec(), clock_on);
|
||||
}
|
||||
EXPORT_SYMBOL(hcodec_clock_on);
|
||||
|
||||
void hcodec_clock_off(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec_hcodec(), clock_off);
|
||||
clock_source_wxhxfps_saved[VDEC_HCODEC] = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hcodec_clock_off);
|
||||
|
||||
int hevc_back_clock_init(void)
|
||||
{
|
||||
if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_init)
|
||||
return p_vdec_hevc_back()->clock_init();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_back_clock_init);
|
||||
|
||||
int hevc_back_clock_set(int clk)
|
||||
{
|
||||
pr_debug("%s-----%d\n", __func__, clk);
|
||||
if (p_vdec_hevc_back() && p_vdec_hevc_back()->clock_set)
|
||||
return p_vdec_hevc_back()->clock_set(clk);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_back_clock_set);
|
||||
|
||||
void hevc_back_clock_enable(void)
|
||||
{
|
||||
hevc_back_clock_set(1);
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_back_clock_enable);
|
||||
|
||||
void hevc_back_clock_hi_enable(void)
|
||||
{
|
||||
hevc_back_clock_set(2);
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_back_clock_hi_enable);
|
||||
|
||||
int hevc_clock_init(void)
|
||||
{
|
||||
if (p_vdec_hevc() && p_vdec_hevc()->clock_init)
|
||||
return p_vdec_hevc()->clock_init();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_clock_init);
|
||||
|
||||
int hevc_clock_set(int clk)
|
||||
{
|
||||
pr_debug("%s-----%d\n", __func__, clk);
|
||||
if (p_vdec_hevc() && p_vdec_hevc()->clock_set)
|
||||
return p_vdec_hevc()->clock_set(clk);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_clock_set);
|
||||
|
||||
void hevc_clock_enable(void)
|
||||
{
|
||||
hevc_clock_set(1);
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_clock_enable);
|
||||
|
||||
void hevc_clock_hi_enable(void)
|
||||
{
|
||||
hevc_clock_set(2);
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_clock_hi_enable);
|
||||
|
||||
void hevc_back_clock_on(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec_hevc_back(), clock_on);
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_back_clock_on);
|
||||
|
||||
void hevc_back_clock_off(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec_hevc_back(), clock_off);
|
||||
clock_source_wxhxfps_saved[VDEC_HEVCB] = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_back_clock_off);
|
||||
|
||||
void hevc_clock_on(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec_hevc(), clock_on);
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_clock_on);
|
||||
|
||||
void hevc_clock_off(void)
|
||||
{
|
||||
IF_HAVE_RUN(p_vdec_hevc(), clock_off);
|
||||
clock_source_wxhxfps_saved[VDEC_HEVC] = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hevc_clock_off);
|
||||
|
||||
int vdec_source_get(enum vdec_type_e core)
|
||||
{
|
||||
return clock_source_wxhxfps_saved[core];
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_source_get);
|
||||
|
||||
int vdec_clk_get(enum vdec_type_e core)
|
||||
{
|
||||
return get_current_vdec_chip()->clk_mgr[core]->clock_get(core);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_clk_get);
|
||||
|
||||
int get_clk_with_source(int format, int w_x_h_fps)
|
||||
{
|
||||
struct clk_set_setting *p_setting;
|
||||
int i;
|
||||
int clk = -2;
|
||||
|
||||
p_setting = get_current_vdec_chip()->clk_setting_array;
|
||||
if (!p_setting || format < 0 || format > VFORMAT_MAX) {
|
||||
pr_info("error on get_clk_with_source ,%p,%d\n",
|
||||
p_setting, format);
|
||||
return -1; /*no setting found. */
|
||||
}
|
||||
p_setting = &p_setting[format];
|
||||
for (i = 0; i < MAX_CLK_SET; i++) {
|
||||
if (p_setting->set[i].wh_X_fps > w_x_h_fps) {
|
||||
clk = p_setting->set[i].clk_Mhz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL(get_clk_with_source);
|
||||
|
||||
int vdec_source_changed_for_clk_set(int format, int width, int height, int fps)
|
||||
{
|
||||
int clk = get_clk_with_source(format, width * height * fps);
|
||||
int ret_clk;
|
||||
|
||||
if (clk < 0) {
|
||||
pr_info("can't get valid clk for source ,%d,%d,%d\n",
|
||||
width, height, fps);
|
||||
if (format >= 1920 && width >= 1080 && fps >= 30)
|
||||
clk = 2; /*default high clk */
|
||||
else
|
||||
clk = 0; /*default clk. */
|
||||
}
|
||||
if (width * height * fps == 0)
|
||||
clk = 0;
|
||||
/*
|
||||
*clk == 0
|
||||
*is used for set default clk;
|
||||
*if used supper clk.
|
||||
*changed to default min clk.
|
||||
*/
|
||||
|
||||
if (format == VFORMAT_HEVC || format == VFORMAT_VP9
|
||||
|| format == VFORMAT_AVS2) {
|
||||
ret_clk = hevc_clock_set(clk);
|
||||
clock_source_wxhxfps_saved[VDEC_HEVC] = width * height * fps;
|
||||
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) {
|
||||
ret_clk = hevc_back_clock_set(clk);
|
||||
clock_source_wxhxfps_saved[VDEC_HEVCB] = width * height * fps;
|
||||
}
|
||||
} else if (format == VFORMAT_H264_ENC || format == VFORMAT_JPEG_ENC) {
|
||||
ret_clk = hcodec_clock_set(clk);
|
||||
clock_source_wxhxfps_saved[VDEC_HCODEC] = width * height * fps;
|
||||
} else if (format == VFORMAT_H264_4K2K &&
|
||||
get_cpu_type() == MESON_CPU_MAJOR_ID_M8) {
|
||||
ret_clk = vdec2_clock_set(clk);
|
||||
clock_source_wxhxfps_saved[VDEC_2] = width * height * fps;
|
||||
ret_clk = vdec_clock_set(clk);
|
||||
clock_source_wxhxfps_saved[VDEC_1] = width * height * fps;
|
||||
} else {
|
||||
ret_clk = vdec_clock_set(clk);
|
||||
clock_source_wxhxfps_saved[VDEC_1] = width * height * fps;
|
||||
}
|
||||
return ret_clk;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_source_changed_for_clk_set);
|
||||
|
||||
static int register_vdec_clk_mgr_per_cpu(int cputype,
|
||||
enum vdec_type_e vdec_type, struct chip_vdec_clk_s *t_mgr)
|
||||
{
|
||||
|
||||
struct chip_vdec_clk_s *mgr;
|
||||
|
||||
if (cputype != get_cpu_type() || vdec_type >= VDEC_MAX) {
|
||||
/*
|
||||
*pr_info("ignore vdec clk mgr for vdec[%d] cpu=%d\n",
|
||||
*vdec_type, cputype);
|
||||
*/
|
||||
return 0; /* ignore don't needed firmare. */
|
||||
}
|
||||
mgr = kmalloc(sizeof(struct chip_vdec_clk_s), GFP_KERNEL);
|
||||
if (!mgr)
|
||||
return -ENOMEM;
|
||||
*mgr = *t_mgr;
|
||||
/*
|
||||
*pr_info("register vdec clk mgr for vdec[%d]\n", vdec_type);
|
||||
*/
|
||||
if (mgr->clock_init) {
|
||||
if (mgr->clock_init()) {
|
||||
kfree(mgr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
get_current_vdec_chip()->clk_mgr[vdec_type] = mgr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_vdec_clk_mgr(int cputype[], enum vdec_type_e vdec_type,
|
||||
struct chip_vdec_clk_s *t_mgr)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (cputype[i] > 0) {
|
||||
register_vdec_clk_mgr_per_cpu(cputype[i], vdec_type, t_mgr);
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(register_vdec_clk_mgr);
|
||||
|
||||
int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type)
|
||||
{
|
||||
kfree(get_current_vdec_chip()->clk_mgr[vdec_type]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_vdec_clk_mgr);
|
||||
|
||||
static int register_vdec_clk_setting_per_cpu(int cputype,
|
||||
struct clk_set_setting *setting, int size)
|
||||
{
|
||||
|
||||
struct clk_set_setting *p_setting;
|
||||
|
||||
if (cputype != get_cpu_type()) {
|
||||
/*
|
||||
*pr_info("ignore clk_set_setting for cpu=%d\n",
|
||||
*cputype);
|
||||
*/
|
||||
return 0; /* ignore don't needed this setting . */
|
||||
}
|
||||
p_setting = kmalloc(size, GFP_KERNEL);
|
||||
if (!p_setting)
|
||||
return -ENOMEM;
|
||||
memcpy(p_setting, setting, size);
|
||||
|
||||
pr_info("register clk_set_setting cpu[%d]\n", cputype);
|
||||
|
||||
get_current_vdec_chip()->clk_setting_array = p_setting;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_vdec_clk_setting(int cputype[],
|
||||
struct clk_set_setting *p_seting, int size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (cputype[i] > 0) {
|
||||
register_vdec_clk_setting_per_cpu(cputype[i], p_seting, size);
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(register_vdec_clk_setting);
|
||||
|
||||
int unregister_vdec_clk_setting(void)
|
||||
{
|
||||
kfree(get_current_vdec_chip()->clk_setting_array);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_vdec_clk_setting);
|
||||
|
||||
172
drivers/amlogic/media_modules/common/media_clock/clk/clk.h
Normal file
172
drivers/amlogic/media_modules/common/media_clock/clk/clk.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/clk/clk.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VDEC_CHIP_CLK_HEADER
|
||||
#define VDEC_CHIP_CLK_HEADER
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include "clk_priv.h"
|
||||
#include <linux/amlogic/media/clk/gp_pll.h>
|
||||
|
||||
#ifndef INCLUDE_FROM_ARCH_CLK_MGR
|
||||
int vdec_clock_init(void);
|
||||
int vdec_clock_set(int clk);
|
||||
int vdec2_clock_set(int clk);
|
||||
|
||||
int hcodec_clock_set(int clk);
|
||||
int hevc_clock_init(void);
|
||||
int hevc_clock_set(int clk);
|
||||
|
||||
void vdec_clock_on(void);
|
||||
void vdec_clock_off(void);
|
||||
void vdec2_clock_on(void);
|
||||
|
||||
void vdec2_clock_off(void);
|
||||
void hcodec_clock_on(void);
|
||||
void hcodec_clock_off(void);
|
||||
void hevc_clock_on(void);
|
||||
void hevc_clock_off(void);
|
||||
|
||||
int hevc_back_clock_init(void);
|
||||
void hevc_back_clock_on(void);
|
||||
void hevc_back_clock_off(void);
|
||||
int hevc_back_clock_set(int clk);
|
||||
void hevc_back_clock_enable(void);
|
||||
void hevc_back_clock_hi_enable(void);
|
||||
|
||||
int vdec_source_get(enum vdec_type_e core);
|
||||
int vdec_clk_get(enum vdec_type_e core);
|
||||
|
||||
int vdec_source_changed_for_clk_set(int format, int width, int height, int fps);
|
||||
int get_clk_with_source(int format, int w_x_h_fps);
|
||||
|
||||
void vdec_clock_enable(void);
|
||||
void vdec_clock_hi_enable(void);
|
||||
void hcodec_clock_enable(void);
|
||||
void hcodec_clock_hi_enable(void);
|
||||
void hevc_clock_enable(void);
|
||||
void hevc_clock_hi_enable(void);
|
||||
void vdec2_clock_enable(void);
|
||||
void vdec2_clock_hi_enable(void);
|
||||
void set_clock_gate(struct gate_switch_node *nodes, int num);
|
||||
|
||||
#endif
|
||||
int register_vdec_clk_mgr(int cputype[],
|
||||
enum vdec_type_e vdec_type, struct chip_vdec_clk_s *t_mgr);
|
||||
|
||||
int unregister_vdec_clk_mgr(enum vdec_type_e vdec_type);
|
||||
|
||||
int register_vdec_clk_setting(int cputype[],
|
||||
struct clk_set_setting *p_seting, int size);
|
||||
|
||||
int unregister_vdec_clk_setting(void);
|
||||
|
||||
#ifdef INCLUDE_FROM_ARCH_CLK_MGR
|
||||
static struct chip_vdec_clk_s vdec_clk_mgr __initdata = {
|
||||
.clock_init = vdec_clock_init,
|
||||
.clock_set = vdec_clock_set,
|
||||
.clock_on = vdec_clock_on,
|
||||
.clock_off = vdec_clock_off,
|
||||
.clock_get = vdec_clock_get,
|
||||
};
|
||||
|
||||
#ifdef VDEC_HAS_VDEC2
|
||||
static struct chip_vdec_clk_s vdec2_clk_mgr __initdata = {
|
||||
.clock_set = vdec2_clock_set,
|
||||
.clock_on = vdec2_clock_on,
|
||||
.clock_off = vdec2_clock_off,
|
||||
.clock_get = vdec_clock_get,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef VDEC_HAS_HEVC
|
||||
static struct chip_vdec_clk_s vdec_hevc_clk_mgr __initdata = {
|
||||
.clock_init = hevc_clock_init,
|
||||
.clock_set = hevc_clock_set,
|
||||
.clock_on = hevc_clock_on,
|
||||
.clock_off = hevc_clock_off,
|
||||
.clock_get = vdec_clock_get,
|
||||
};
|
||||
static struct chip_vdec_clk_s vdec_hevc_back_clk_mgr __initdata = {
|
||||
.clock_init = hevc_back_clock_init,
|
||||
.clock_set = hevc_back_clock_set,
|
||||
.clock_on = hevc_back_clock_on,
|
||||
.clock_off = hevc_back_clock_off,
|
||||
.clock_get = vdec_clock_get,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef VDEC_HAS_VDEC_HCODEC
|
||||
static struct chip_vdec_clk_s vdec_hcodec_clk_mgr __initdata = {
|
||||
.clock_set = hcodec_clock_set,
|
||||
.clock_on = hcodec_clock_on,
|
||||
.clock_off = hcodec_clock_off,
|
||||
.clock_get = vdec_clock_get,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init vdec_init_clk(void)
|
||||
{
|
||||
int cpus[] = CLK_FOR_CPU;
|
||||
|
||||
register_vdec_clk_mgr(cpus, VDEC_1, &vdec_clk_mgr);
|
||||
#ifdef VDEC_HAS_VDEC2
|
||||
register_vdec_clk_mgr(cpus, VDEC_2, &vdec2_clk_mgr);
|
||||
#endif
|
||||
#ifdef VDEC_HAS_HEVC
|
||||
register_vdec_clk_mgr(cpus, VDEC_HEVC, &vdec_hevc_clk_mgr);
|
||||
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A)
|
||||
register_vdec_clk_mgr(cpus, VDEC_HEVCB, &vdec_hevc_back_clk_mgr);
|
||||
#endif
|
||||
#ifdef VDEC_HAS_VDEC_HCODEC
|
||||
register_vdec_clk_mgr(cpus, VDEC_HCODEC, &vdec_hcodec_clk_mgr);
|
||||
#endif
|
||||
|
||||
#ifdef VDEC_HAS_CLK_SETTINGS
|
||||
register_vdec_clk_setting(cpus,
|
||||
clks_for_formats, sizeof(clks_for_formats));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit vdec_clk_exit(void)
|
||||
{
|
||||
unregister_vdec_clk_mgr(VDEC_1);
|
||||
#ifdef VDEC_HAS_VDEC2
|
||||
unregister_vdec_clk_mgr(VDEC_2);
|
||||
#endif
|
||||
#ifdef VDEC_HAS_HEVC
|
||||
unregister_vdec_clk_mgr(VDEC_HEVC);
|
||||
#endif
|
||||
#ifdef VDEC_HAS_VDEC_HCODEC
|
||||
unregister_vdec_clk_mgr(VDEC_HCODEC);
|
||||
#endif
|
||||
#ifdef VDEC_HAS_CLK_SETTINGS
|
||||
unregister_vdec_clk_setting();
|
||||
#endif
|
||||
pr_info("media clock exit.\n");
|
||||
}
|
||||
|
||||
#define ARCH_VDEC_CLK_INIT()\
|
||||
module_init(vdec_init_clk)
|
||||
|
||||
#define ARCH_VDEC_CLK_EXIT()\
|
||||
module_exit(vdec_clk_exit)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/clk/clk_priv.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AMPORTS_CLK_PRIV_HEADER
|
||||
#define AMPORTS_CLK_PRIV_HEADER
|
||||
|
||||
struct clk_set {
|
||||
u32 wh_X_fps; /* [x*y*fps */
|
||||
u32 clk_Mhz; /*min MHZ */
|
||||
};
|
||||
#define MAX_CLK_SET 6
|
||||
struct clk_set_setting {
|
||||
struct clk_set set[MAX_CLK_SET];
|
||||
};
|
||||
|
||||
struct chip_vdec_clk_s {
|
||||
int (*clock_get)(enum vdec_type_e core);
|
||||
int (*clock_init)(void);
|
||||
int (*clock_set)(int clk);
|
||||
void (*clock_on)(void);
|
||||
void (*clock_off)(void);
|
||||
void (*clock_prepare_switch)(void);
|
||||
};
|
||||
#endif
|
||||
1006
drivers/amlogic/media_modules/common/media_clock/clk/clkg12.c
Normal file
1006
drivers/amlogic/media_modules/common/media_clock/clk/clkg12.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/switch/amports_gate.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.
|
||||
*
|
||||
*/
|
||||
#define DEBUG
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk.h>
|
||||
#include "amports_gate.h"
|
||||
#include <linux/amlogic/media/utils/vdec_reg.h>
|
||||
#include "../../../stream_input/amports/amports_priv.h"
|
||||
#include "../../../frame_provider/decoder/utils/vdec.h"
|
||||
#include "../clk/clk.h"
|
||||
|
||||
|
||||
#define DEBUG_REF 1
|
||||
#define GATE_RESET_OK
|
||||
|
||||
#ifdef GATE_RESET_OK
|
||||
|
||||
struct gate_switch_node gates[] = {
|
||||
{
|
||||
.name = "demux",
|
||||
},
|
||||
{
|
||||
.name = "parser_top",
|
||||
},
|
||||
{
|
||||
.name = "vdec",
|
||||
},
|
||||
{
|
||||
.name = "clk_81",
|
||||
},
|
||||
{
|
||||
.name = "clk_vdec_mux",
|
||||
},
|
||||
{
|
||||
.name = "clk_hcodec_mux",
|
||||
},
|
||||
{
|
||||
.name = "clk_hevc_mux",
|
||||
},
|
||||
{
|
||||
.name = "clk_hevcb_mux",
|
||||
},
|
||||
{
|
||||
.name = "ahbarb0",
|
||||
},
|
||||
{
|
||||
.name = "asyncfifo",
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
*mesonstream {
|
||||
* compatible = "amlogic, codec, streambuf";
|
||||
* dev_name = "mesonstream";
|
||||
* status = "okay";
|
||||
* clocks = <&clkc CLKID_DOS_PARSER
|
||||
* &clkc CLKID_DEMUX
|
||||
* &clkc CLKID_DOS
|
||||
* &clkc CLKID_VDEC_MUX
|
||||
* &clkc CLKID_HCODEC_MUX
|
||||
* &clkc CLKID_HEVCF_MUX
|
||||
* &clkc CLKID_HEVC_MUX>;
|
||||
* clock-names = "parser_top",
|
||||
* "demux",
|
||||
* "vdec",
|
||||
* "clk_vdec_mux",
|
||||
* "clk_hcodec_mux",
|
||||
* "clk_hevc_mux",
|
||||
* "clk_hevcb_mux";
|
||||
*};
|
||||
*/
|
||||
|
||||
int amports_clock_gate_init(struct device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(gates) / sizeof(struct gate_switch_node); i++) {
|
||||
gates[i].clk = devm_clk_get(dev, gates[i].name);
|
||||
if (IS_ERR_OR_NULL(gates[i].clk)) {
|
||||
gates[i].clk = NULL;
|
||||
pr_info("get gate %s control failed %p\n",
|
||||
gates[i].name,
|
||||
gates[i].clk);
|
||||
} else {
|
||||
pr_info("get gate %s control ok %p\n",
|
||||
gates[i].name,
|
||||
gates[i].clk);
|
||||
}
|
||||
gates[i].ref_count = 0;
|
||||
mutex_init(&gates[i].mutex);
|
||||
}
|
||||
|
||||
set_clock_gate(gates, ARRAY_SIZE(gates));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(amports_clock_gate_init);
|
||||
|
||||
static int amports_gate_clk(struct gate_switch_node *gate_node, int enable)
|
||||
{
|
||||
mutex_lock(&gate_node->mutex);
|
||||
if (enable) {
|
||||
if (gate_node->ref_count == 0)
|
||||
clk_prepare_enable(gate_node->clk);
|
||||
|
||||
gate_node->ref_count++;
|
||||
|
||||
if (DEBUG_REF)
|
||||
pr_debug("the %-15s clock on, ref cnt: %d\n",
|
||||
gate_node->name, gate_node->ref_count);
|
||||
} else {
|
||||
gate_node->ref_count--;
|
||||
if (gate_node->ref_count == 0)
|
||||
clk_disable_unprepare(gate_node->clk);
|
||||
|
||||
if (DEBUG_REF)
|
||||
pr_debug("the %-15s clock off, ref cnt: %d\n",
|
||||
gate_node->name, gate_node->ref_count);
|
||||
}
|
||||
mutex_unlock(&gate_node->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amports_switch_gate(const char *name, int enable)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(gates) / sizeof(struct gate_switch_node); i++) {
|
||||
if (!strcmp(name, gates[i].name)) {
|
||||
|
||||
/*pr_info("openclose:%d gate %s control\n", enable,
|
||||
* gates[i].name);
|
||||
*/
|
||||
|
||||
if (gates[i].clk)
|
||||
amports_gate_clk(&gates[i], enable);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(amports_switch_gate);
|
||||
|
||||
#else
|
||||
/*
|
||||
*can used for debug.
|
||||
*on chip bringup.
|
||||
*/
|
||||
int amports_clock_gate_init(struct device *dev)
|
||||
{
|
||||
static int gate_inited;
|
||||
|
||||
if (gate_inited)
|
||||
return 0;
|
||||
/*
|
||||
*#define HHI_GCLK_MPEG0 0x1050
|
||||
*#define HHI_GCLK_MPEG1 0x1051
|
||||
*#define HHI_GCLK_MPEG2 0x1052
|
||||
*#define HHI_GCLK_OTHER 0x1054
|
||||
*#define HHI_GCLK_AO 0x1055
|
||||
*/
|
||||
WRITE_HHI_REG_BITS(HHI_GCLK_MPEG0, 1, 1, 1);/*dos*/
|
||||
WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 25, 1);/*U_parser_top()*/
|
||||
WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 0xff, 6, 8);/*aiu()*/
|
||||
WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 4, 1);/*demux()*/
|
||||
WRITE_HHI_REG_BITS(HHI_GCLK_MPEG1, 1, 2, 1);/*audio in()*/
|
||||
WRITE_HHI_REG_BITS(HHI_GCLK_MPEG2, 1, 25, 1);/*VPU Interrupt*/
|
||||
gate_inited++;
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(amports_clock_gate_init);
|
||||
|
||||
static int amports_switch_gate(struct gate_switch_node *gate_node, int enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amports_switch_gate(const char *name, int enable)
|
||||
{
|
||||
amports_switch_gate(0, 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(amports_switch_gate);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* drivers/amlogic/media/common/arch/switch/amports_gate.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AMPORT_GATE_H
|
||||
#define AMPORT_GATE_H
|
||||
#include <linux/device.h>
|
||||
|
||||
struct gate_switch_node {
|
||||
struct clk *clk;
|
||||
const char *name;
|
||||
struct mutex mutex;
|
||||
int ref_count;
|
||||
};
|
||||
|
||||
extern int amports_clock_gate_init(struct device *dev);
|
||||
extern int amports_switch_gate(const char *name, int enable);
|
||||
|
||||
#endif
|
||||
1
drivers/amlogic/media_modules/frame_provider/Makefile
Normal file
1
drivers/amlogic/media_modules/frame_provider/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-y += decoder/
|
||||
@@ -0,0 +1,12 @@
|
||||
obj-y += utils/
|
||||
obj-y += mpeg12/
|
||||
obj-y += mpeg4/
|
||||
obj-y += vc1/
|
||||
obj-y += h264/
|
||||
obj-y += h264_multi/
|
||||
obj-y += h265/
|
||||
obj-y += vp9/
|
||||
obj-y += mjpeg/
|
||||
obj-y += real/
|
||||
obj-y += avs/
|
||||
obj-y += avs2/
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS) += amvdec_avs.o
|
||||
amvdec_avs-objs += avs.o avsp_trans.o
|
||||
1887
drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c
Normal file
1887
drivers/amlogic/media_modules/frame_provider/decoder/avs/avs.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
#ifndef AVS_H_
|
||||
#define AVS_H_
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_AVSP_LONG_CABAC
|
||||
#define AVSP_LONG_CABAC
|
||||
#endif
|
||||
/*#define BITSTREAM_READ_TMP_NO_CACHE*/
|
||||
|
||||
#ifdef AVSP_LONG_CABAC
|
||||
#define MAX_CODED_FRAME_SIZE 1500000 /*!< bytes for one frame*/
|
||||
#define LOCAL_HEAP_SIZE (1024*1024*10)
|
||||
/*
|
||||
*#define MAX_CODED_FRAME_SIZE 240000
|
||||
*#define MAX_CODED_FRAME_SIZE 700000
|
||||
*/
|
||||
#define SVA_STREAM_BUF_SIZE 1024
|
||||
|
||||
extern void *es_write_addr_virt;
|
||||
extern dma_addr_t es_write_addr_phy;
|
||||
|
||||
extern void *bitstream_read_tmp;
|
||||
extern dma_addr_t bitstream_read_tmp_phy;
|
||||
extern void *avsp_heap_adr;
|
||||
|
||||
int avs_get_debug_flag(void);
|
||||
|
||||
int process_long_cabac(void);
|
||||
|
||||
/* bit [6] - skip_mode_flag
|
||||
* bit [5:4] - picture_type
|
||||
* bit [3] - picture_structure (0-Field, 1-Frame)
|
||||
* bit [2] - fixed_picture_qp
|
||||
* bit [1] - progressive_sequence
|
||||
* bit [0] - active
|
||||
*/
|
||||
#define LONG_CABAC_REQ AV_SCRATCH_K
|
||||
#define LONG_CABAC_SRC_ADDR AV_SCRATCH_H
|
||||
#define LONG_CABAC_DES_ADDR AV_SCRATCH_I
|
||||
/* bit[31:16] - vertical_size
|
||||
* bit[15:0] - horizontal_size
|
||||
*/
|
||||
#define LONG_CABAC_PIC_SIZE AV_SCRATCH_J
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
*#define PERFORMANCE_DEBUG
|
||||
*#define DUMP_DEBUG
|
||||
*/
|
||||
#define AVS_DEBUG_PRINT 0x01
|
||||
#define AVS_DEBUG_UCODE 0x02
|
||||
#define AVS_DEBUG_OLD_ERROR_HANDLE 0x10
|
||||
#define AVS_DEBUG_USE_FULL_SPEED 0x80
|
||||
#define AEC_DUMP 0x100
|
||||
#define STREAM_INFO_DUMP 0x200
|
||||
#define SLICE_INFO_DUMP 0x400
|
||||
#define MB_INFO_DUMP 0x800
|
||||
#define MB_NUM_DUMP 0x1000
|
||||
#define BLOCK_NUM_DUMP 0x2000
|
||||
#define COEFF_DUMP 0x4000
|
||||
#define ES_DUMP 0x8000
|
||||
#define DQUANT_DUMP 0x10000
|
||||
#define STREAM_INFO_DUMP_MORE 0x20000
|
||||
#define STREAM_INFO_DUMP_MORE2 0x40000
|
||||
|
||||
extern void *es_write_addr_virt;
|
||||
extern void *bitstream_read_tmp;
|
||||
extern dma_addr_t bitstream_read_tmp_phy;
|
||||
int read_bitstream(unsigned char *Buf, int size);
|
||||
int u_v(int LenInBits, char *tracestring);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_AVS2) += amvdec_avs2.o
|
||||
amvdec_avs2-objs += vavs2.o avs2_bufmgr.o
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6095
drivers/amlogic/media_modules/frame_provider/decoder/avs2/vavs2.c
Normal file
6095
drivers/amlogic/media_modules/frame_provider/decoder/avs2/vavs2.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vavs2.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VAVS2_H
|
||||
#define VAVS2_H
|
||||
|
||||
#define AVS2_10B_MMU
|
||||
#define MV_USE_FIXED_BUF
|
||||
|
||||
void adapt_coef_probs(int pic_count, int prev_kf, int cur_kf, int pre_fc,
|
||||
unsigned int *prev_prob, unsigned int *cur_prob, unsigned int *count);
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264) += amvdec_h264.o
|
||||
amvdec_h264-objs += vh264.o
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MVC) += amvdec_h264mvc.o
|
||||
amvdec_h264mvc-objs += vh264_mvc.o
|
||||
|
||||
3216
drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264.c
Normal file
3216
drivers/amlogic/media_modules/frame_provider/decoder/h264/vh264.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/h264/vh264.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VH264_H
|
||||
#define VH264_H
|
||||
|
||||
extern int query_video_status(int type, int *value);
|
||||
|
||||
/* extern s32 vh264_init(void); */
|
||||
|
||||
extern s32 vh264_release(void);
|
||||
|
||||
#endif /* VMPEG4_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H264_MULTI) += amvdec_mh264.o
|
||||
amvdec_mh264-objs += vmh264.o h264_dpb.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,860 @@
|
||||
#ifndef H264_DPB_H_
|
||||
#define H264_DPB_H_
|
||||
|
||||
#define ERROR_CHECK
|
||||
|
||||
#define OUTPUT_BUFFER_IN_C
|
||||
|
||||
#define PRINT_FLAG_ERROR 0x0
|
||||
#define PRINT_FLAG_VDEC_STATUS 0X0001
|
||||
#define PRINT_FLAG_UCODE_EVT 0x0002
|
||||
#define PRINT_FLAG_MMU_DETAIL 0x0004
|
||||
#define PRINT_FLAG_ERRORFLAG_DBG 0x0008
|
||||
#define PRINT_FLAG_DPB_DETAIL 0x0010
|
||||
#define PRINT_FLAG_DEC_DETAIL 0x0020
|
||||
#define PRINT_FLAG_VDEC_DETAIL 0x0040
|
||||
#define PRINT_FLAG_DUMP_DPB 0x0080
|
||||
#define PRINT_FRAMEBASE_DATA 0x0100
|
||||
#define PRINT_FLAG_DEBUG_POC 0x0200
|
||||
#define RRINT_FLAG_RPM 0x0400
|
||||
#define DEBUG_DISABLE_RUNREADY_RMBUF 0x0800
|
||||
#define PRINT_FLAG_DUMP_BUFSPEC 0x1000
|
||||
#define DISABLE_ERROR_HANDLE 0x10000
|
||||
#define DEBUG_DUMP_STAT 0x80000
|
||||
|
||||
|
||||
#define MVC_EXTENSION_ENABLE 0
|
||||
#define PRINTREFLIST 0
|
||||
|
||||
#define MAX_LIST_SIZE 33
|
||||
|
||||
#define FALSE 0
|
||||
|
||||
#define H264_SLICE_HEAD_DONE 0x01
|
||||
#define H264_PIC_DATA_DONE 0x02
|
||||
/*#define H264_SPS_DONE 0x03*/
|
||||
/*#define H264_PPS_DONE 0x04*/
|
||||
/*#define H264_SLICE_DATA_DONE 0x05*/
|
||||
/*#define H264_DATA_END 0x06*/
|
||||
|
||||
#define H264_CONFIG_REQUEST 0x11
|
||||
#define H264_DATA_REQUEST 0x12
|
||||
#define H264_WRRSP_REQUEST 0x13
|
||||
#define H264_WRRSP_DONE 0x14
|
||||
|
||||
#define H264_DECODE_BUFEMPTY 0x20
|
||||
#define H264_DECODE_TIMEOUT 0x21
|
||||
#define H264_SEARCH_BUFEMPTY 0x22
|
||||
#define H264_DECODE_OVER_SIZE 0x23
|
||||
|
||||
#define H264_FIND_NEXT_PIC_NAL 0x50
|
||||
#define H264_FIND_NEXT_DVEL_NAL 0x51
|
||||
#define H264_AUX_DATA_READY 0x52
|
||||
|
||||
/* 0x8x, search state*/
|
||||
#define H264_STATE_SEARCH_AFTER_SPS 0x80
|
||||
#define H264_STATE_SEARCH_AFTER_PPS 0x81
|
||||
#define H264_STATE_PARSE_SLICE_HEAD 0x82
|
||||
#define H264_STATE_SEARCH_HEAD 0x83
|
||||
/**/
|
||||
#define H264_ACTION_SEARCH_HEAD 0xf0
|
||||
#define H264_ACTION_DECODE_SLICE 0xf1
|
||||
#define H264_ACTION_CONFIG_DONE 0xf2
|
||||
#define H264_ACTION_DECODE_NEWPIC 0xf3
|
||||
#define H264_ACTION_DECODE_START 0xff
|
||||
|
||||
#define RPM_BEGIN 0x0
|
||||
#define RPM_END 0x400
|
||||
|
||||
#define val(s) (s[0]|(s[1]<<16))
|
||||
|
||||
#define FRAME_IN_DPB 24
|
||||
#define DPB_OFFSET 0x100
|
||||
#define MMCO_OFFSET 0x200
|
||||
union param {
|
||||
#if 0
|
||||
#define H_TIME_STAMP_START 0X00
|
||||
#define H_TIME_STAMP_END 0X17
|
||||
#define PTS_ZERO_0 0X18
|
||||
#define PTS_ZERO_1 0X19
|
||||
#endif
|
||||
#define FIXED_FRAME_RATE_FLAG 0X21
|
||||
|
||||
#define OFFSET_DELIMITER_LO 0x2f
|
||||
#define OFFSET_DELIMITER_HI 0x30
|
||||
|
||||
|
||||
#define SLICE_IPONLY_BREAK 0X5C
|
||||
#define PREV_MAX_REFERENCE_FRAME_NUM 0X5D
|
||||
#define EOS 0X5E
|
||||
#define FRAME_PACKING_TYPE 0X5F
|
||||
#define OLD_POC_PAR_1 0X60
|
||||
#define OLD_POC_PAR_2 0X61
|
||||
#define PREV_MBX 0X62
|
||||
#define PREV_MBY 0X63
|
||||
#define ERROR_SKIP_MB_NUM 0X64
|
||||
#define ERROR_MB_STATUS 0X65
|
||||
#define L0_PIC0_STATUS 0X66
|
||||
#define TIMEOUT_COUNTER 0X67
|
||||
#define BUFFER_SIZE 0X68
|
||||
#define BUFFER_SIZE_HI 0X69
|
||||
#define CROPPING_LEFT_RIGHT 0X6A
|
||||
#define CROPPING_TOP_BOTTOM 0X6B
|
||||
#define POC_SELECT_NEED_SWAP 0X6C
|
||||
#define POC_SELECT_SWAP 0X6D
|
||||
#define MAX_BUFFER_FRAME 0X6E
|
||||
|
||||
#define NON_CONFORMING_STREAM 0X70
|
||||
#define RECOVERY_POINT 0X71
|
||||
#define POST_CANVAS 0X72
|
||||
#define POST_CANVAS_H 0X73
|
||||
#define SKIP_PIC_COUNT 0X74
|
||||
#define TARGET_NUM_SCALING_LIST 0X75
|
||||
#define FF_POST_ONE_FRAME 0X76
|
||||
#define PREVIOUS_BIT_CNT 0X77
|
||||
#define MB_NOT_SHIFT_COUNT 0X78
|
||||
#define PIC_STATUS 0X79
|
||||
#define FRAME_COUNTER 0X7A
|
||||
#define NEW_SLICE_TYPE 0X7B
|
||||
#define NEW_PICTURE_STRUCTURE 0X7C
|
||||
#define NEW_FRAME_NUM 0X7D
|
||||
#define NEW_IDR_PIC_ID 0X7E
|
||||
#define IDR_PIC_ID 0X7F
|
||||
|
||||
/* h264 LOCAL */
|
||||
#define NAL_UNIT_TYPE 0X80
|
||||
#define NAL_REF_IDC 0X81
|
||||
#define SLICE_TYPE 0X82
|
||||
#define LOG2_MAX_FRAME_NUM 0X83
|
||||
#define FRAME_MBS_ONLY_FLAG 0X84
|
||||
#define PIC_ORDER_CNT_TYPE 0X85
|
||||
#define LOG2_MAX_PIC_ORDER_CNT_LSB 0X86
|
||||
#define PIC_ORDER_PRESENT_FLAG 0X87
|
||||
#define REDUNDANT_PIC_CNT_PRESENT_FLAG 0X88
|
||||
#define PIC_INIT_QP_MINUS26 0X89
|
||||
#define DEBLOCKING_FILTER_CONTROL_PRESENT_FLAG 0X8A
|
||||
#define NUM_SLICE_GROUPS_MINUS1 0X8B
|
||||
#define MODE_8X8_FLAGS 0X8C
|
||||
#define ENTROPY_CODING_MODE_FLAG 0X8D
|
||||
#define SLICE_QUANT 0X8E
|
||||
#define TOTAL_MB_HEIGHT 0X8F
|
||||
#define PICTURE_STRUCTURE 0X90
|
||||
#define TOP_INTRA_TYPE 0X91
|
||||
#define RV_AI_STATUS 0X92
|
||||
#define AI_READ_START 0X93
|
||||
#define AI_WRITE_START 0X94
|
||||
#define AI_CUR_BUFFER 0X95
|
||||
#define AI_DMA_BUFFER 0X96
|
||||
#define AI_READ_OFFSET 0X97
|
||||
#define AI_WRITE_OFFSET 0X98
|
||||
#define AI_WRITE_OFFSET_SAVE 0X99
|
||||
#define RV_AI_BUFF_START 0X9A
|
||||
#define I_PIC_MB_COUNT 0X9B
|
||||
#define AI_WR_DCAC_DMA_CTRL 0X9C
|
||||
#define SLICE_MB_COUNT 0X9D
|
||||
#define PICTYPE 0X9E
|
||||
#define SLICE_GROUP_MAP_TYPE 0X9F
|
||||
#define MB_TYPE 0XA0
|
||||
#define MB_AFF_ADDED_DMA 0XA1
|
||||
#define PREVIOUS_MB_TYPE 0XA2
|
||||
#define WEIGHTED_PRED_FLAG 0XA3
|
||||
#define WEIGHTED_BIPRED_IDC 0XA4
|
||||
/* bit 3:2 - PICTURE_STRUCTURE
|
||||
* bit 1 - MB_ADAPTIVE_FRAME_FIELD_FLAG
|
||||
* bit 0 - FRAME_MBS_ONLY_FLAG
|
||||
*/
|
||||
#define MBFF_INFO 0XA5
|
||||
#define TOP_INTRA_TYPE_TOP 0XA6
|
||||
|
||||
#define RV_AI_BUFF_INC 0xa7
|
||||
|
||||
#define DEFAULT_MB_INFO_LO 0xa8
|
||||
|
||||
/* 0 -- no need to read
|
||||
* 1 -- need to wait Left
|
||||
* 2 -- need to read Intra
|
||||
* 3 -- need to read back MV
|
||||
*/
|
||||
#define NEED_READ_TOP_INFO 0xa9
|
||||
/* 0 -- idle
|
||||
* 1 -- wait Left
|
||||
* 2 -- reading top Intra
|
||||
* 3 -- reading back MV
|
||||
*/
|
||||
#define READ_TOP_INFO_STATE 0xaa
|
||||
#define DCAC_MBX 0xab
|
||||
#define TOP_MB_INFO_OFFSET 0xac
|
||||
#define TOP_MB_INFO_RD_IDX 0xad
|
||||
#define TOP_MB_INFO_WR_IDX 0xae
|
||||
|
||||
#define VLD_NO_WAIT 0
|
||||
#define VLD_WAIT_BUFFER 1
|
||||
#define VLD_WAIT_HOST 2
|
||||
#define VLD_WAIT_GAP 3
|
||||
|
||||
#define VLD_WAITING 0xaf
|
||||
|
||||
#define MB_X_NUM 0xb0
|
||||
/* #define MB_WIDTH 0xb1 */
|
||||
#define MB_HEIGHT 0xb2
|
||||
#define MBX 0xb3
|
||||
#define TOTAL_MBY 0xb4
|
||||
#define INTR_MSK_SAVE 0xb5
|
||||
|
||||
/* #define has_time_stamp 0xb6 */
|
||||
#define NEED_DISABLE_PPE 0xb6
|
||||
#define IS_NEW_PICTURE 0XB7
|
||||
#define PREV_NAL_REF_IDC 0XB8
|
||||
#define PREV_NAL_UNIT_TYPE 0XB9
|
||||
#define FRAME_MB_COUNT 0XBA
|
||||
#define SLICE_GROUP_UCODE 0XBB
|
||||
#define SLICE_GROUP_CHANGE_RATE 0XBC
|
||||
#define SLICE_GROUP_CHANGE_CYCLE_LEN 0XBD
|
||||
#define DELAY_LENGTH 0XBE
|
||||
#define PICTURE_STRUCT 0XBF
|
||||
/* #define pre_picture_struct 0xc0 */
|
||||
#define DCAC_PREVIOUS_MB_TYPE 0xc1
|
||||
|
||||
#define TIME_STAMP 0XC2
|
||||
#define H_TIME_STAMP 0XC3
|
||||
#define VPTS_MAP_ADDR 0XC4
|
||||
#define H_VPTS_MAP_ADDR 0XC5
|
||||
|
||||
/*#define MAX_DPB_SIZE 0XC6*/
|
||||
#define PIC_INSERT_FLAG 0XC7
|
||||
|
||||
#define TIME_STAMP_START 0XC8
|
||||
#define TIME_STAMP_END 0XDF
|
||||
|
||||
#define OFFSET_FOR_NON_REF_PIC 0XE0
|
||||
#define OFFSET_FOR_TOP_TO_BOTTOM_FIELD 0XE2
|
||||
#define MAX_REFERENCE_FRAME_NUM 0XE4
|
||||
#define FRAME_NUM_GAP_ALLOWED 0XE5
|
||||
#define NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE 0XE6
|
||||
#define PROFILE_IDC_MMCO 0XE7
|
||||
#define LEVEL_IDC_MMCO 0XE8
|
||||
#define FRAME_SIZE_IN_MB 0XE9
|
||||
#define DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG 0XEA
|
||||
#define PPS_NUM_REF_IDX_L0_ACTIVE_MINUS1 0XEB
|
||||
#define PPS_NUM_REF_IDX_L1_ACTIVE_MINUS1 0XEC
|
||||
#define CURRENT_SPS_ID 0XED
|
||||
#define CURRENT_PPS_ID 0XEE
|
||||
/* bit 0 - sequence parameter set may change
|
||||
* bit 1 - picture parameter set may change
|
||||
* bit 2 - new dpb just inited
|
||||
* bit 3 - IDR picture not decoded yet
|
||||
* bit 5:4 - 0: mb level code loaded 1: picture
|
||||
* level code loaded 2: slice level code loaded
|
||||
*/
|
||||
#define DECODE_STATUS 0XEF
|
||||
#define FIRST_MB_IN_SLICE 0XF0
|
||||
#define PREV_MB_WIDTH 0XF1
|
||||
#define PREV_FRAME_SIZE_IN_MB 0XF2
|
||||
/*#define MAX_REFERENCE_FRAME_NUM_IN_MEM 0XF3*/
|
||||
/* bit 0 - aspect_ratio_info_present_flag
|
||||
* bit 1 - timing_info_present_flag
|
||||
* bit 2 - nal_hrd_parameters_present_flag
|
||||
* bit 3 - vcl_hrd_parameters_present_flag
|
||||
* bit 4 - pic_struct_present_flag
|
||||
* bit 5 - bitstream_restriction_flag
|
||||
*/
|
||||
#define VUI_STATUS 0XF4
|
||||
#define ASPECT_RATIO_IDC 0XF5
|
||||
#define ASPECT_RATIO_SAR_WIDTH 0XF6
|
||||
#define ASPECT_RATIO_SAR_HEIGHT 0XF7
|
||||
#define NUM_UNITS_IN_TICK 0XF8
|
||||
#define TIME_SCALE 0XFA
|
||||
#define CURRENT_PIC_INFO 0XFC
|
||||
#define DPB_BUFFER_INFO 0XFD
|
||||
#define REFERENCE_POOL_INFO 0XFE
|
||||
#define REFERENCE_LIST_INFO 0XFF
|
||||
struct{
|
||||
unsigned short data[RPM_END-RPM_BEGIN];
|
||||
} l;
|
||||
struct{
|
||||
unsigned short dump[DPB_OFFSET];
|
||||
unsigned short dpb_base[FRAME_IN_DPB<<3];
|
||||
|
||||
unsigned short dpb_max_buffer_frame;
|
||||
unsigned short actual_dpb_size;
|
||||
|
||||
unsigned short colocated_buf_status;
|
||||
|
||||
unsigned short num_forward_short_term_reference_pic;
|
||||
unsigned short num_short_term_reference_pic;
|
||||
unsigned short num_reference_pic;
|
||||
|
||||
unsigned short current_dpb_index;
|
||||
unsigned short current_decoded_frame_num;
|
||||
unsigned short current_reference_frame_num;
|
||||
|
||||
unsigned short l0_size;
|
||||
unsigned short l1_size;
|
||||
|
||||
/* [6:5] : nal_ref_idc */
|
||||
/* [4:0] : nal_unit_type */
|
||||
unsigned short NAL_info_mmco;
|
||||
|
||||
/* [1:0] : 00 - top field, 01 - bottom field,
|
||||
* 10 - frame, 11 - mbaff frame
|
||||
*/
|
||||
unsigned short picture_structure_mmco;
|
||||
|
||||
unsigned short frame_num;
|
||||
unsigned short pic_order_cnt_lsb;
|
||||
|
||||
unsigned short num_ref_idx_l0_active_minus1;
|
||||
unsigned short num_ref_idx_l1_active_minus1;
|
||||
|
||||
unsigned short PrevPicOrderCntLsb;
|
||||
unsigned short PreviousFrameNum;
|
||||
|
||||
/* 32 bits variables */
|
||||
unsigned short delta_pic_order_cnt_bottom[2];
|
||||
unsigned short delta_pic_order_cnt_0[2];
|
||||
unsigned short delta_pic_order_cnt_1[2];
|
||||
|
||||
unsigned short PrevPicOrderCntMsb[2];
|
||||
unsigned short PrevFrameNumOffset[2];
|
||||
|
||||
unsigned short frame_pic_order_cnt[2];
|
||||
unsigned short top_field_pic_order_cnt[2];
|
||||
unsigned short bottom_field_pic_order_cnt[2];
|
||||
|
||||
unsigned short colocated_mv_addr_start[2];
|
||||
unsigned short colocated_mv_addr_end[2];
|
||||
unsigned short colocated_mv_wr_addr[2];
|
||||
} dpb;
|
||||
struct {
|
||||
unsigned short dump[MMCO_OFFSET];
|
||||
|
||||
/* array base address for offset_for_ref_frame */
|
||||
unsigned short offset_for_ref_frame_base[128];
|
||||
|
||||
/* 0 - Index in DPB
|
||||
* 1 - Picture Flag
|
||||
* [ 2] : 0 - short term reference,
|
||||
* 1 - long term reference
|
||||
* [ 1] : bottom field
|
||||
* [ 0] : top field
|
||||
* 2 - Picture Number (short term or long term) low 16 bits
|
||||
* 3 - Picture Number (short term or long term) high 16 bits
|
||||
*/
|
||||
unsigned short reference_base[128];
|
||||
|
||||
/* command and parameter, until command is 3 */
|
||||
unsigned short l0_reorder_cmd[66];
|
||||
unsigned short l1_reorder_cmd[66];
|
||||
|
||||
/* command and parameter, until command is 0 */
|
||||
unsigned short mmco_cmd[44];
|
||||
|
||||
unsigned short l0_base[40];
|
||||
unsigned short l1_base[40];
|
||||
} mmco;
|
||||
struct {
|
||||
/* from ucode lmem, do not change this struct */
|
||||
} p;
|
||||
};
|
||||
|
||||
|
||||
struct StorablePicture;
|
||||
struct VideoParameters;
|
||||
struct DecodedPictureBuffer;
|
||||
|
||||
/* New enum for field processing */
|
||||
enum PictureStructure {
|
||||
FRAME,
|
||||
TOP_FIELD,
|
||||
BOTTOM_FIELD
|
||||
};
|
||||
|
||||
#define I_Slice 2
|
||||
#define P_Slice 5
|
||||
#define B_Slice 6
|
||||
#define P_Slice_0 0
|
||||
#define B_Slice_1 1
|
||||
#define I_Slice_7 7
|
||||
|
||||
enum SliceType {
|
||||
P_SLICE = 0,
|
||||
B_SLICE = 1,
|
||||
I_SLICE = 2,
|
||||
SP_SLICE = 3,
|
||||
SI_SLICE = 4,
|
||||
NUM_SLICE_TYPES = 5
|
||||
};
|
||||
|
||||
enum ProfileIDC {
|
||||
FREXT_CAVLC444 = 44, /*!< YUV 4:4:4/14 "CAVLC 4:4:4"*/
|
||||
BASELINE = 66, /*!< YUV 4:2:0/8 "Baseline"*/
|
||||
MAIN = 77, /*!< YUV 4:2:0/8 "Main"*/
|
||||
EXTENDED = 88, /*!< YUV 4:2:0/8 "Extended"*/
|
||||
FREXT_HP = 100, /*!< YUV 4:2:0/8 "High"*/
|
||||
FREXT_Hi10P = 110, /*!< YUV 4:2:0/10 "High 10"*/
|
||||
FREXT_Hi422 = 122, /*!< YUV 4:2:2/10 "High 4:2:2"*/
|
||||
FREXT_Hi444 = 244, /*!< YUV 4:4:4/14 "High 4:4:4"*/
|
||||
MVC_HIGH = 118, /*!< YUV 4:2:0/8 "Multiview High"*/
|
||||
STEREO_HIGH = 128 /*!< YUV 4:2:0/8 "Stereo High"*/
|
||||
};
|
||||
|
||||
struct SPSParameters {
|
||||
unsigned int profile_idc;
|
||||
int pic_order_cnt_type;
|
||||
int log2_max_pic_order_cnt_lsb_minus4;
|
||||
int num_ref_frames_in_pic_order_cnt_cycle;
|
||||
short offset_for_ref_frame[128];
|
||||
short offset_for_non_ref_pic;
|
||||
short offset_for_top_to_bottom_field;
|
||||
|
||||
/**/
|
||||
int frame_mbs_only_flag;
|
||||
int num_ref_frames;
|
||||
int max_dpb_size;
|
||||
|
||||
int log2_max_frame_num_minus4;
|
||||
};
|
||||
|
||||
#define DEC_REF_PIC_MARKING_BUFFER_NUM_MAX 45
|
||||
struct DecRefPicMarking_s {
|
||||
int memory_management_control_operation;
|
||||
int difference_of_pic_nums_minus1;
|
||||
int long_term_pic_num;
|
||||
int long_term_frame_idx;
|
||||
int max_long_term_frame_idx_plus1;
|
||||
struct DecRefPicMarking_s *Next;
|
||||
};
|
||||
|
||||
#define REORDERING_COMMAND_MAX_SIZE 33
|
||||
struct Slice {
|
||||
int first_mb_in_slice;
|
||||
int mode_8x8_flags;
|
||||
int picture_structure_mmco;
|
||||
|
||||
int frame_num;
|
||||
int idr_flag;
|
||||
int toppoc;
|
||||
int bottompoc;
|
||||
int framepoc;
|
||||
int pic_order_cnt_lsb;
|
||||
int PicOrderCntMsb;
|
||||
unsigned char field_pic_flag;
|
||||
unsigned char bottom_field_flag;
|
||||
int ThisPOC;
|
||||
int nal_reference_idc;
|
||||
int AbsFrameNum;
|
||||
int delta_pic_order_cnt_bottom;
|
||||
int delta_pic_order_cnt[2];
|
||||
|
||||
/**/
|
||||
char listXsize[6];
|
||||
struct StorablePicture *listX[6][MAX_LIST_SIZE * 2];
|
||||
|
||||
/**/
|
||||
enum PictureStructure structure;
|
||||
int long_term_reference_flag;
|
||||
int no_output_of_prior_pics_flag;
|
||||
int adaptive_ref_pic_buffering_flag;
|
||||
|
||||
struct VideoParameters *p_Vid;
|
||||
struct DecodedPictureBuffer *p_Dpb;
|
||||
int num_ref_idx_active[2]; /* number of available list references */
|
||||
|
||||
/*modification*/
|
||||
int slice_type; /* slice type */
|
||||
int ref_pic_list_reordering_flag[2];
|
||||
int modification_of_pic_nums_idc[2][REORDERING_COMMAND_MAX_SIZE];
|
||||
int abs_diff_pic_num_minus1[2][REORDERING_COMMAND_MAX_SIZE];
|
||||
int long_term_pic_idx[2][REORDERING_COMMAND_MAX_SIZE];
|
||||
/**/
|
||||
unsigned char dec_ref_pic_marking_buffer_valid;
|
||||
struct DecRefPicMarking_s
|
||||
dec_ref_pic_marking_buffer[DEC_REF_PIC_MARKING_BUFFER_NUM_MAX];
|
||||
};
|
||||
|
||||
struct OldSliceParams {
|
||||
unsigned int field_pic_flag;
|
||||
unsigned int frame_num;
|
||||
int nal_ref_idc;
|
||||
unsigned int pic_oder_cnt_lsb;
|
||||
int delta_pic_oder_cnt_bottom;
|
||||
int delta_pic_order_cnt[2];
|
||||
unsigned char bottom_field_flag;
|
||||
unsigned char idr_flag;
|
||||
int idr_pic_id;
|
||||
int pps_id;
|
||||
#if (MVC_EXTENSION_ENABLE)
|
||||
int view_id;
|
||||
int inter_view_flag;
|
||||
int anchor_pic_flag;
|
||||
#endif
|
||||
int layer_id;
|
||||
};
|
||||
|
||||
struct VideoParameters {
|
||||
int PrevPicOrderCntMsb;
|
||||
int PrevPicOrderCntLsb;
|
||||
unsigned char last_has_mmco_5;
|
||||
unsigned char last_pic_bottom_field;
|
||||
int ThisPOC;
|
||||
int PreviousFrameNum;
|
||||
int FrameNumOffset;
|
||||
int PreviousFrameNumOffset;
|
||||
int max_frame_num;
|
||||
unsigned int pre_frame_num;
|
||||
int ExpectedDeltaPerPicOrderCntCycle;
|
||||
int PicOrderCntCycleCnt;
|
||||
int FrameNumInPicOrderCntCycle;
|
||||
int ExpectedPicOrderCnt;
|
||||
|
||||
/**/
|
||||
struct SPSParameters *active_sps;
|
||||
struct Slice **ppSliceList;
|
||||
int iSliceNumOfCurrPic;
|
||||
int conceal_mode;
|
||||
int earlier_missing_poc;
|
||||
int pocs_in_dpb[100];
|
||||
|
||||
struct OldSliceParams old_slice;
|
||||
/**/
|
||||
struct StorablePicture *dec_picture;
|
||||
struct StorablePicture *no_reference_picture;
|
||||
|
||||
/*modification*/
|
||||
int non_conforming_stream;
|
||||
int recovery_point;
|
||||
};
|
||||
|
||||
static inline int imin(int a, int b)
|
||||
{
|
||||
return ((a) < (b)) ? (a) : (b);
|
||||
}
|
||||
|
||||
static inline int imax(int a, int b)
|
||||
{
|
||||
return ((a) > (b)) ? (a) : (b);
|
||||
}
|
||||
|
||||
#define MAX_PIC_BUF_NUM 128
|
||||
#define MAX_NUM_SLICES 50
|
||||
|
||||
struct StorablePicture {
|
||||
/**/
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int y_canvas_index;
|
||||
int u_canvas_index;
|
||||
int v_canvas_index;
|
||||
/**/
|
||||
int index;
|
||||
unsigned char is_used;
|
||||
|
||||
enum PictureStructure structure;
|
||||
|
||||
int poc;
|
||||
int top_poc;
|
||||
int bottom_poc;
|
||||
int frame_poc;
|
||||
unsigned int frame_num;
|
||||
unsigned int recovery_frame;
|
||||
|
||||
int pic_num;
|
||||
int buf_spec_num;
|
||||
int buf_spec_is_alloced;
|
||||
int colocated_buf_index;
|
||||
int long_term_pic_num;
|
||||
int long_term_frame_idx;
|
||||
|
||||
unsigned char is_long_term;
|
||||
int used_for_reference;
|
||||
int is_output;
|
||||
#if 1
|
||||
/* rain */
|
||||
int pre_output;
|
||||
#endif
|
||||
int non_existing;
|
||||
int separate_colour_plane_flag;
|
||||
|
||||
short max_slice_id;
|
||||
|
||||
int size_x, size_y, size_x_cr, size_y_cr;
|
||||
int size_x_m1, size_y_m1, size_x_cr_m1, size_y_cr_m1;
|
||||
int coded_frame;
|
||||
int mb_aff_frame_flag;
|
||||
unsigned int PicWidthInMbs;
|
||||
unsigned int PicSizeInMbs;
|
||||
int iLumaPadY, iLumaPadX;
|
||||
int iChromaPadY, iChromaPadX;
|
||||
|
||||
/* for mb aff, if frame for referencing the top field */
|
||||
struct StorablePicture *top_field;
|
||||
/* for mb aff, if frame for referencing the bottom field */
|
||||
struct StorablePicture *bottom_field;
|
||||
/* for mb aff, if field for referencing the combined frame */
|
||||
struct StorablePicture *frame;
|
||||
|
||||
int slice_type;
|
||||
int idr_flag;
|
||||
int no_output_of_prior_pics_flag;
|
||||
int long_term_reference_flag;
|
||||
int adaptive_ref_pic_buffering_flag;
|
||||
|
||||
int chroma_format_idc;
|
||||
int frame_mbs_only_flag;
|
||||
int frame_cropping_flag;
|
||||
int frame_crop_left_offset;
|
||||
int frame_crop_right_offset;
|
||||
int frame_crop_top_offset;
|
||||
int frame_crop_bottom_offset;
|
||||
int qp;
|
||||
int chroma_qp_offset[2];
|
||||
int slice_qp_delta;
|
||||
/* stores the memory management control operations */
|
||||
struct DecRefPicMarking_s *dec_ref_pic_marking_buffer;
|
||||
|
||||
/* picture error concealment */
|
||||
/*indicates if this is a concealed picture */
|
||||
int concealed_pic;
|
||||
|
||||
/* variables for tone mapping */
|
||||
int seiHasTone_mapping;
|
||||
int tone_mapping_model_id;
|
||||
int tonemapped_bit_depth;
|
||||
/* imgpel* tone_mapping_lut; tone mapping look up table */
|
||||
|
||||
int proc_flag;
|
||||
#if (MVC_EXTENSION_ENABLE)
|
||||
int view_id;
|
||||
int inter_view_flag;
|
||||
int anchor_pic_flag;
|
||||
#endif
|
||||
int iLumaStride;
|
||||
int iChromaStride;
|
||||
int iLumaExpandedHeight;
|
||||
int iChromaExpandedHeight;
|
||||
/* imgpel **cur_imgY; for more efficient get_block_luma */
|
||||
int no_ref;
|
||||
int iCodingType;
|
||||
|
||||
char listXsize[MAX_NUM_SLICES][2];
|
||||
struct StorablePicture **listX[MAX_NUM_SLICES][2];
|
||||
int layer_id;
|
||||
|
||||
int offset_delimiter_lo;
|
||||
int offset_delimiter_hi;
|
||||
|
||||
u32 pts;
|
||||
u64 pts64;
|
||||
unsigned char data_flag;
|
||||
};
|
||||
|
||||
struct FrameStore {
|
||||
/* rain */
|
||||
int buf_spec_num;
|
||||
/* rain */
|
||||
int colocated_buf_index;
|
||||
|
||||
/* 0=empty; 1=top; 2=bottom; 3=both fields (or frame) */
|
||||
int is_used;
|
||||
/* 0=not used for ref; 1=top used; 2=bottom used;
|
||||
* 3=both fields (or frame) used
|
||||
*/
|
||||
int is_reference;
|
||||
/* 0=not used for ref; 1=top used; 2=bottom used;
|
||||
* 3=both fields (or frame) used
|
||||
*/
|
||||
int is_long_term;
|
||||
/* original marking by nal_ref_idc: 0=not used for ref; 1=top used;
|
||||
* 2=bottom used; 3=both fields (or frame) used
|
||||
*/
|
||||
int is_orig_reference;
|
||||
|
||||
int is_non_existent;
|
||||
|
||||
unsigned int frame_num;
|
||||
unsigned int recovery_frame;
|
||||
|
||||
int frame_num_wrap;
|
||||
int long_term_frame_idx;
|
||||
int is_output;
|
||||
#if 1
|
||||
/* rain */
|
||||
int pre_output;
|
||||
/* index in gFrameStore */
|
||||
int index;
|
||||
#define I_FLAG 0x01
|
||||
#define IDR_FLAG 0x02
|
||||
#define ERROR_FLAG 0x10
|
||||
#define NULL_FLAG 0x20
|
||||
#define MAYBE_ERROR_FLAG 0x40
|
||||
#define NODISP_FLAG 0x80
|
||||
unsigned char data_flag;
|
||||
#endif
|
||||
int poc;
|
||||
|
||||
/* picture error concealment */
|
||||
int concealment_reference;
|
||||
|
||||
struct StorablePicture *frame;
|
||||
struct StorablePicture *top_field;
|
||||
struct StorablePicture *bottom_field;
|
||||
|
||||
#if (MVC_EXTENSION_ENABLE)
|
||||
int view_id;
|
||||
int inter_view_flag[2];
|
||||
int anchor_pic_flag[2];
|
||||
#endif
|
||||
int layer_id;
|
||||
|
||||
u32 pts;
|
||||
u64 pts64;
|
||||
};
|
||||
|
||||
|
||||
/* #define DPB_SIZE_MAX 16 */
|
||||
#define DPB_SIZE_MAX 32
|
||||
struct DecodedPictureBuffer {
|
||||
struct VideoParameters *p_Vid;
|
||||
/* InputParameters *p_Inp; ??? */
|
||||
struct FrameStore *fs[DPB_SIZE_MAX];
|
||||
struct FrameStore *fs_ref[DPB_SIZE_MAX];
|
||||
struct FrameStore *fs_ltref[DPB_SIZE_MAX];
|
||||
/* inter-layer reference (for multi-layered codecs) */
|
||||
struct FrameStore *fs_ilref[DPB_SIZE_MAX];
|
||||
/**/
|
||||
struct FrameStore *fs_list0[DPB_SIZE_MAX];
|
||||
struct FrameStore *fs_list1[DPB_SIZE_MAX];
|
||||
struct FrameStore *fs_listlt[DPB_SIZE_MAX];
|
||||
|
||||
/**/
|
||||
unsigned int size;
|
||||
unsigned int used_size;
|
||||
unsigned int ref_frames_in_buffer;
|
||||
unsigned int ltref_frames_in_buffer;
|
||||
int last_output_poc;
|
||||
#if (MVC_EXTENSION_ENABLE)
|
||||
int last_output_view_id;
|
||||
#endif
|
||||
int max_long_term_pic_idx;
|
||||
|
||||
|
||||
int init_done;
|
||||
int first_pic_done; /*by rain*/
|
||||
int num_ref_frames;
|
||||
|
||||
struct FrameStore *last_picture;
|
||||
unsigned int used_size_il;
|
||||
int layer_id;
|
||||
|
||||
/* DPB related function; */
|
||||
};
|
||||
|
||||
struct h264_dpb_stru {
|
||||
struct vdec_s *vdec;
|
||||
int decoder_index;
|
||||
|
||||
union param dpb_param;
|
||||
|
||||
int decode_idx;
|
||||
int buf_num;
|
||||
int curr_POC;
|
||||
int reorder_pic_num;
|
||||
u8 fast_output_enable;
|
||||
/*poc_even_flag:
|
||||
0, init; 1, odd; 2, even*/
|
||||
u8 poc_even_odd_flag;
|
||||
u32 decode_pic_count;
|
||||
/**/
|
||||
unsigned int max_reference_size;
|
||||
|
||||
unsigned int colocated_buf_map;
|
||||
unsigned int colocated_buf_count;
|
||||
unsigned int colocated_mv_addr_start;
|
||||
unsigned int colocated_mv_addr_end;
|
||||
unsigned int colocated_buf_size;
|
||||
|
||||
struct DecodedPictureBuffer mDPB;
|
||||
struct Slice mSlice;
|
||||
struct VideoParameters mVideo;
|
||||
struct SPSParameters mSPS;
|
||||
|
||||
struct StorablePicture m_PIC[MAX_PIC_BUF_NUM];
|
||||
struct FrameStore mFrameStore[DPB_SIZE_MAX];
|
||||
|
||||
/*vui*/
|
||||
unsigned int vui_status;
|
||||
unsigned int num_units_in_tick;
|
||||
unsigned int time_scale;
|
||||
unsigned int fixed_frame_rate_flag;
|
||||
unsigned int aspect_ratio_idc;
|
||||
unsigned int aspect_ratio_sar_width;
|
||||
unsigned int aspect_ratio_sar_height;
|
||||
|
||||
unsigned int dec_dpb_status;
|
||||
unsigned char buf_alloc_fail;
|
||||
unsigned int dpb_error_flag;
|
||||
};
|
||||
|
||||
|
||||
extern unsigned int h264_debug_flag;
|
||||
extern unsigned int h264_debug_mask;
|
||||
|
||||
int dpb_print(int indext, int debug_flag, const char *fmt, ...);
|
||||
|
||||
int dpb_print_cont(int index, int debug_flag, const char *fmt, ...);
|
||||
|
||||
unsigned char dpb_is_debug(int index, int debug_flag);
|
||||
|
||||
int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame);
|
||||
|
||||
int release_buf_spec_num(struct vdec_s *vdec, int buf_spec_num);
|
||||
|
||||
void set_frame_output_flag(struct h264_dpb_stru *p_H264_Dpb, int index);
|
||||
|
||||
int is_there_unused_frame_from_dpb(struct DecodedPictureBuffer *p_Dpb);
|
||||
|
||||
int h264_slice_header_process(struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
void dpb_init_global(struct h264_dpb_stru *p_H264_Dpb,
|
||||
int id, int actual_dpb_size, int max_reference_size);
|
||||
|
||||
void init_colocate_buf(struct h264_dpb_stru *p_H264_Dpb, int count);
|
||||
|
||||
int release_colocate_buf(struct h264_dpb_stru *p_H264_Dpb, int index);
|
||||
|
||||
int get_free_buf_idx(struct vdec_s *vdec);
|
||||
|
||||
int store_picture_in_dpb(struct h264_dpb_stru *p_H264_Dpb,
|
||||
struct StorablePicture *p, unsigned char data_flag);
|
||||
|
||||
int release_picture(struct h264_dpb_stru *p_H264_Dpb,
|
||||
struct StorablePicture *pic);
|
||||
|
||||
void remove_dpb_pictures(struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
void bufmgr_post(struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
void bufmgr_force_recover(struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
int get_long_term_flag_by_buf_spec_num(struct h264_dpb_stru *p_H264_Dpb,
|
||||
int buf_spec_num);
|
||||
|
||||
void bufmgr_h264_remove_unused_frame(struct h264_dpb_stru *p_H264_Dpb,
|
||||
u8 force_flag);
|
||||
|
||||
void flush_dpb(struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
void print_pic_info(int decindex, const char *info,
|
||||
struct StorablePicture *pic,
|
||||
int slice_type);
|
||||
void dump_dpb(struct DecodedPictureBuffer *p_Dpb, u8 force);
|
||||
|
||||
void dump_pic(struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
enum PictureStructure get_cur_slice_picture_struct(
|
||||
struct h264_dpb_stru *p_H264_Dpb);
|
||||
|
||||
int dpb_check_ref_list_error(
|
||||
struct h264_dpb_stru *p_H264_Dpb);
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_H265) += amvdec_h265.o
|
||||
amvdec_h265-objs += vh265.o
|
||||
10905
drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c
Normal file
10905
drivers/amlogic/media_modules/frame_provider/decoder/h265/vh265.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vh265.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VH265_H
|
||||
#define VH265_H
|
||||
|
||||
extern u32 get_blackout_policy(void);
|
||||
|
||||
extern s32 vh265_init(void);
|
||||
|
||||
extern s32 vh265_release(void);
|
||||
|
||||
#endif /* VMPEG4_H */
|
||||
@@ -0,0 +1,5 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG) += amvdec_mjpeg.o
|
||||
amvdec_mjpeg-objs += vmjpeg.o
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MJPEG_MULTI) += amvdec_mmjpeg.o
|
||||
amvdec_mmjpeg-objs += vmjpeg_multi.o
|
||||
@@ -0,0 +1,956 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vmjpeg.c
|
||||
*
|
||||
* Copyright (C) 2015 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/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/amlogic/media/frame_sync/ptsserv.h>
|
||||
#include <linux/amlogic/media/utils/amstream.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 <linux/amlogic/media/utils/vdec_reg.h>
|
||||
#include "../../../stream_input/amports/amports_priv.h"
|
||||
#include <linux/amlogic/media/registers/register.h>
|
||||
#include "../utils/decoder_mmu_box.h"
|
||||
#include "../utils/decoder_bmmu_box.h"
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
||||
#include <linux/amlogic/media/codec_mm/configs.h>
|
||||
|
||||
#ifdef CONFIG_AM_VDEC_MJPEG_LOG
|
||||
#define AMLOG
|
||||
#define LOG_LEVEL_VAR amlog_level_vmjpeg
|
||||
#define LOG_MASK_VAR amlog_mask_vmjpeg
|
||||
#define LOG_LEVEL_ERROR 0
|
||||
#define LOG_LEVEL_INFO 1
|
||||
#define LOG_LEVEL_DESC "0:ERROR, 1:INFO"
|
||||
#endif
|
||||
#include <linux/amlogic/media/utils/amlog.h>
|
||||
MODULE_AMLOG(LOG_LEVEL_ERROR, 0, LOG_LEVEL_DESC, LOG_DEFAULT_MASK_DESC);
|
||||
|
||||
#include "../utils/amvdec.h"
|
||||
#include "../utils/firmware.h"
|
||||
|
||||
#define DRIVER_NAME "amvdec_mjpeg"
|
||||
#define MODULE_NAME "amvdec_mjpeg"
|
||||
|
||||
/* protocol register usage
|
||||
* AV_SCRATCH_0 - AV_SCRATCH_1 : initial display buffer fifo
|
||||
* AV_SCRATCH_2 - AV_SCRATCH_3 : decoder settings
|
||||
* AV_SCRATCH_4 - AV_SCRATCH_7 : display buffer spec
|
||||
* AV_SCRATCH_8 - AV_SCRATCH_9 : amrisc/host display buffer management
|
||||
* AV_SCRATCH_a : time stamp
|
||||
*/
|
||||
|
||||
#define MREG_DECODE_PARAM AV_SCRATCH_2 /* bit 0-3: pico_addr_mode */
|
||||
/* bit 15-4: reference height */
|
||||
#define MREG_TO_AMRISC AV_SCRATCH_8
|
||||
#define MREG_FROM_AMRISC AV_SCRATCH_9
|
||||
#define MREG_FRAME_OFFSET AV_SCRATCH_A
|
||||
|
||||
#define PICINFO_BUF_IDX_MASK 0x0007
|
||||
#define PICINFO_AVI1 0x0080
|
||||
#define PICINFO_INTERLACE 0x0020
|
||||
#define PICINFO_INTERLACE_AVI1_BOT 0x0010
|
||||
#define PICINFO_INTERLACE_FIRST 0x0010
|
||||
|
||||
#define VF_POOL_SIZE 16
|
||||
#define DECODE_BUFFER_NUM_MAX 4
|
||||
#define MAX_BMMU_BUFFER_NUM DECODE_BUFFER_NUM_MAX
|
||||
#define PUT_INTERVAL (HZ/100)
|
||||
|
||||
#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
|
||||
/* #define NV21 */
|
||||
#endif
|
||||
static DEFINE_MUTEX(vmjpeg_mutex);
|
||||
|
||||
static struct dec_sysinfo vmjpeg_amstream_dec_info;
|
||||
|
||||
static struct vframe_s *vmjpeg_vf_peek(void *);
|
||||
static struct vframe_s *vmjpeg_vf_get(void *);
|
||||
static void vmjpeg_vf_put(struct vframe_s *, void *);
|
||||
static int vmjpeg_vf_states(struct vframe_states *states, void *);
|
||||
static int vmjpeg_event_cb(int type, void *data, void *private_data);
|
||||
|
||||
static int vmjpeg_prot_init(void);
|
||||
static void vmjpeg_local_init(void);
|
||||
|
||||
static const char vmjpeg_dec_id[] = "vmjpeg-dev";
|
||||
static struct vdec_info *gvs;
|
||||
static struct work_struct set_clk_work;
|
||||
|
||||
#define PROVIDER_NAME "decoder.mjpeg"
|
||||
static const struct vframe_operations_s vmjpeg_vf_provider = {
|
||||
.peek = vmjpeg_vf_peek,
|
||||
.get = vmjpeg_vf_get,
|
||||
.put = vmjpeg_vf_put,
|
||||
.event_cb = vmjpeg_event_cb,
|
||||
.vf_states = vmjpeg_vf_states,
|
||||
};
|
||||
static void *mm_blk_handle;
|
||||
static struct vframe_provider_s vmjpeg_vf_prov;
|
||||
|
||||
static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
|
||||
static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
|
||||
static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE);
|
||||
|
||||
static struct vframe_s vfpool[VF_POOL_SIZE];
|
||||
static s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
|
||||
|
||||
static u32 frame_width, frame_height, frame_dur;
|
||||
static u32 saved_resolution;
|
||||
static struct timer_list recycle_timer;
|
||||
static u32 stat;
|
||||
static u32 buf_size = 32 * 1024 * 1024;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
static bool is_reset;
|
||||
|
||||
static inline u32 index2canvas0(u32 index)
|
||||
{
|
||||
const u32 canvas_tab[4] = {
|
||||
#ifdef NV21
|
||||
0x010100, 0x030302, 0x050504, 0x070706
|
||||
#else
|
||||
0x020100, 0x050403, 0x080706, 0x0b0a09
|
||||
#endif
|
||||
};
|
||||
|
||||
return canvas_tab[index];
|
||||
}
|
||||
|
||||
static inline u32 index2canvas1(u32 index)
|
||||
{
|
||||
const u32 canvas_tab[4] = {
|
||||
#ifdef NV21
|
||||
0x0d0d0c, 0x0f0f0e, 0x171716, 0x191918
|
||||
#else
|
||||
0x0e0d0c, 0x181716, 0x222120, 0x252423
|
||||
#endif
|
||||
};
|
||||
|
||||
return canvas_tab[index];
|
||||
}
|
||||
|
||||
static void set_frame_info(struct vframe_s *vf)
|
||||
{
|
||||
vf->width = frame_width;
|
||||
vf->height = frame_height;
|
||||
vf->duration = frame_dur;
|
||||
vf->ratio_control = 0;
|
||||
vf->duration_pulldown = 0;
|
||||
vf->flag = 0;
|
||||
}
|
||||
|
||||
static irqreturn_t vmjpeg_isr(int irq, void *dev_id)
|
||||
{
|
||||
u32 reg, offset, pts, pts_valid = 0;
|
||||
struct vframe_s *vf = NULL;
|
||||
u64 pts_us64;
|
||||
|
||||
WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
|
||||
|
||||
reg = READ_VREG(MREG_FROM_AMRISC);
|
||||
|
||||
if (reg & PICINFO_BUF_IDX_MASK) {
|
||||
offset = READ_VREG(MREG_FRAME_OFFSET);
|
||||
|
||||
if (pts_lookup_offset_us64
|
||||
(PTS_TYPE_VIDEO, offset, &pts, 0, &pts_us64) == 0)
|
||||
pts_valid = 1;
|
||||
|
||||
if ((reg & PICINFO_INTERLACE) == 0) {
|
||||
u32 index = ((reg & PICINFO_BUF_IDX_MASK) - 1) & 3;
|
||||
|
||||
if (index >= DECODE_BUFFER_NUM_MAX) {
|
||||
pr_err("fatal error, invalid buffer index.");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (kfifo_get(&newframe_q, &vf) == 0) {
|
||||
pr_info(
|
||||
"fatal error, no available buffer slot.");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
set_frame_info(vf);
|
||||
vf->signal_type = 0;
|
||||
vf->index = index;
|
||||
#ifdef NV21
|
||||
vf->type =
|
||||
VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD |
|
||||
VIDTYPE_VIU_NV21;
|
||||
#else
|
||||
vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
|
||||
#endif
|
||||
vf->canvas0Addr = vf->canvas1Addr =
|
||||
index2canvas0(index);
|
||||
vf->pts = (pts_valid) ? pts : 0;
|
||||
vf->pts_us64 = (pts_valid) ? pts_us64 : 0;
|
||||
vf->orientation = 0;
|
||||
vf->type_original = vf->type;
|
||||
vfbuf_use[index]++;
|
||||
vf->mem_handle =
|
||||
decoder_bmmu_box_get_mem_handle(
|
||||
mm_blk_handle,
|
||||
index);
|
||||
|
||||
gvs->frame_dur = frame_dur;
|
||||
vdec_count_info(gvs, 0, offset);
|
||||
|
||||
kfifo_put(&display_q, (const struct vframe_s *)vf);
|
||||
|
||||
vf_notify_receiver(PROVIDER_NAME,
|
||||
VFRAME_EVENT_PROVIDER_VFRAME_READY,
|
||||
NULL);
|
||||
|
||||
} else {
|
||||
u32 index = ((reg & PICINFO_BUF_IDX_MASK) - 1) & 3;
|
||||
|
||||
if (index >= DECODE_BUFFER_NUM_MAX) {
|
||||
pr_info("fatal error, invalid buffer index.");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (kfifo_get(&newframe_q, &vf) == 0) {
|
||||
pr_info
|
||||
("fatal error, no available buffer slot.");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
set_frame_info(vf);
|
||||
vf->signal_type = 0;
|
||||
vf->index = index;
|
||||
#if 0
|
||||
if (reg & PICINFO_AVI1) {
|
||||
/* AVI1 format */
|
||||
if (reg & PICINFO_INTERLACE_AVI1_BOT) {
|
||||
vf->type =
|
||||
VIDTYPE_INTERLACE_BOTTOM |
|
||||
VIDTYPE_INTERLACE_FIRST;
|
||||
} else
|
||||
vf->type = VIDTYPE_INTERLACE_TOP;
|
||||
} else {
|
||||
if (reg & PICINFO_INTERLACE_FIRST) {
|
||||
vf->type =
|
||||
VIDTYPE_INTERLACE_TOP |
|
||||
VIDTYPE_INTERLACE_FIRST;
|
||||
} else
|
||||
vf->type = VIDTYPE_INTERLACE_BOTTOM;
|
||||
}
|
||||
|
||||
vf->type |= VIDTYPE_VIU_FIELD;
|
||||
#ifdef NV21
|
||||
vf->type |= VIDTYPE_VIU_NV21;
|
||||
#endif
|
||||
vf->duration >>= 1;
|
||||
vf->canvas0Addr = vf->canvas1Addr =
|
||||
index2canvas0(index);
|
||||
vf->orientation = 0;
|
||||
if ((vf->type & VIDTYPE_INTERLACE_FIRST) &&
|
||||
(pts_valid))
|
||||
vf->pts = pts;
|
||||
else
|
||||
vf->pts = 0;
|
||||
|
||||
vfbuf_use[index]++;
|
||||
|
||||
kfifo_put(&display_q, (const struct vframe_s *)vf);
|
||||
#else
|
||||
/* send whole frame by weaving top & bottom field */
|
||||
#ifdef NV21
|
||||
vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_NV21;
|
||||
#else
|
||||
vf->type = VIDTYPE_PROGRESSIVE;
|
||||
#endif
|
||||
vf->canvas0Addr = index2canvas0(index);
|
||||
vf->canvas1Addr = index2canvas1(index);
|
||||
vf->orientation = 0;
|
||||
if (pts_valid) {
|
||||
vf->pts = pts;
|
||||
vf->pts_us64 = pts_us64;
|
||||
} else {
|
||||
vf->pts = 0;
|
||||
vf->pts_us64 = 0;
|
||||
}
|
||||
vf->type_original = vf->type;
|
||||
vfbuf_use[index]++;
|
||||
vf->mem_handle =
|
||||
decoder_bmmu_box_get_mem_handle(
|
||||
mm_blk_handle,
|
||||
index);
|
||||
|
||||
gvs->frame_dur = frame_dur;
|
||||
vdec_count_info(gvs, 0, offset);
|
||||
|
||||
kfifo_put(&display_q, (const struct vframe_s *)vf);
|
||||
|
||||
vf_notify_receiver(PROVIDER_NAME,
|
||||
VFRAME_EVENT_PROVIDER_VFRAME_READY,
|
||||
NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
WRITE_VREG(MREG_FROM_AMRISC, 0);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct vframe_s *vmjpeg_vf_peek(void *op_arg)
|
||||
{
|
||||
struct vframe_s *vf;
|
||||
|
||||
if (kfifo_peek(&display_q, &vf))
|
||||
return vf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct vframe_s *vmjpeg_vf_get(void *op_arg)
|
||||
{
|
||||
struct vframe_s *vf;
|
||||
|
||||
if (kfifo_get(&display_q, &vf))
|
||||
return vf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vmjpeg_vf_put(struct vframe_s *vf, void *op_arg)
|
||||
{
|
||||
kfifo_put(&recycle_q, (const struct vframe_s *)vf);
|
||||
}
|
||||
|
||||
static int vmjpeg_event_cb(int type, void *data, void *private_data)
|
||||
{
|
||||
if (type & VFRAME_EVENT_RECEIVER_RESET) {
|
||||
unsigned long flags;
|
||||
|
||||
amvdec_stop();
|
||||
#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
|
||||
vf_light_unreg_provider(&vmjpeg_vf_prov);
|
||||
#endif
|
||||
spin_lock_irqsave(&lock, flags);
|
||||
vmjpeg_local_init();
|
||||
vmjpeg_prot_init();
|
||||
spin_unlock_irqrestore(&lock, flags);
|
||||
#ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
|
||||
vf_reg_provider(&vmjpeg_vf_prov);
|
||||
#endif
|
||||
amvdec_start();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmjpeg_vf_states(struct vframe_states *states, void *op_arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&lock, flags);
|
||||
|
||||
states->vf_pool_size = VF_POOL_SIZE;
|
||||
states->buf_free_num = kfifo_len(&newframe_q);
|
||||
states->buf_avail_num = kfifo_len(&display_q);
|
||||
states->buf_recycle_num = kfifo_len(&recycle_q);
|
||||
|
||||
spin_unlock_irqrestore(&lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void mjpeg_set_clk(struct work_struct *work)
|
||||
{
|
||||
if (frame_dur > 0 && saved_resolution !=
|
||||
frame_width * frame_height * (96000 / frame_dur)) {
|
||||
int fps = 96000 / frame_dur;
|
||||
|
||||
saved_resolution = frame_width * frame_height * fps;
|
||||
vdec_source_changed(VFORMAT_MJPEG,
|
||||
frame_width, frame_height, fps);
|
||||
}
|
||||
}
|
||||
|
||||
static void vmjpeg_put_timer_func(unsigned long arg)
|
||||
{
|
||||
struct timer_list *timer = (struct timer_list *)arg;
|
||||
|
||||
while (!kfifo_is_empty(&recycle_q) &&
|
||||
(READ_VREG(MREG_TO_AMRISC) == 0)) {
|
||||
struct vframe_s *vf;
|
||||
|
||||
if (kfifo_get(&recycle_q, &vf)) {
|
||||
if ((vf->index >= 0)
|
||||
&& (vf->index < DECODE_BUFFER_NUM_MAX)
|
||||
&& (--vfbuf_use[vf->index] == 0)) {
|
||||
WRITE_VREG(MREG_TO_AMRISC, vf->index + 1);
|
||||
vf->index = DECODE_BUFFER_NUM_MAX;
|
||||
}
|
||||
|
||||
kfifo_put(&newframe_q, (const struct vframe_s *)vf);
|
||||
}
|
||||
}
|
||||
|
||||
schedule_work(&set_clk_work);
|
||||
|
||||
timer->expires = jiffies + PUT_INTERVAL;
|
||||
|
||||
add_timer(timer);
|
||||
}
|
||||
|
||||
int vmjpeg_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
|
||||
{
|
||||
vstatus->frame_width = frame_width;
|
||||
vstatus->frame_height = frame_height;
|
||||
if (0 != frame_dur)
|
||||
vstatus->frame_rate = 96000 / frame_dur;
|
||||
else
|
||||
vstatus->frame_rate = 96000;
|
||||
vstatus->error_count = 0;
|
||||
vstatus->status = stat;
|
||||
vstatus->bit_rate = gvs->bit_rate;
|
||||
vstatus->frame_dur = frame_dur;
|
||||
vstatus->frame_data = gvs->frame_data;
|
||||
vstatus->total_data = gvs->total_data;
|
||||
vstatus->frame_count = gvs->frame_count;
|
||||
vstatus->error_frame_count = gvs->error_frame_count;
|
||||
vstatus->drop_frame_count = gvs->drop_frame_count;
|
||||
vstatus->total_data = gvs->total_data;
|
||||
vstatus->samp_cnt = gvs->samp_cnt;
|
||||
vstatus->offset = gvs->offset;
|
||||
snprintf(vstatus->vdec_name, sizeof(vstatus->vdec_name),
|
||||
"%s", DRIVER_NAME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vmjpeg_set_isreset(struct vdec_s *vdec, int isreset)
|
||||
{
|
||||
is_reset = isreset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
static int vmjpeg_canvas_init(void)
|
||||
{
|
||||
int i, ret;
|
||||
u32 canvas_width, canvas_height;
|
||||
u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
|
||||
unsigned long buf_start;
|
||||
|
||||
if (buf_size <= 0x00400000) {
|
||||
/* SD only */
|
||||
canvas_width = 768;
|
||||
canvas_height = 576;
|
||||
decbuf_y_size = 0x80000;
|
||||
decbuf_uv_size = 0x20000;
|
||||
decbuf_size = 0x100000;
|
||||
} else {
|
||||
/* HD & SD */
|
||||
canvas_width = 1920;
|
||||
canvas_height = 1088;
|
||||
decbuf_y_size = 0x200000;
|
||||
decbuf_uv_size = 0x80000;
|
||||
decbuf_size = 0x300000;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_BMMU_BUFFER_NUM; i++) {
|
||||
|
||||
ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, i,
|
||||
decbuf_size, DRIVER_NAME, &buf_start);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
#ifdef NV21
|
||||
canvas_config(index2canvas0(i) & 0xff,
|
||||
buf_start,
|
||||
canvas_width, canvas_height,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config((index2canvas0(i) >> 8) & 0xff,
|
||||
buf_start +
|
||||
decbuf_y_size, canvas_width,
|
||||
canvas_height / 2, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config(index2canvas1(i) & 0xff,
|
||||
buf_start +
|
||||
decbuf_size / 2, canvas_width,
|
||||
canvas_height, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config((index2canvas1(i) >> 8) & 0xff,
|
||||
buf_start +
|
||||
decbuf_y_size + decbuf_uv_size / 2,
|
||||
canvas_width, canvas_height / 2,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
#else
|
||||
canvas_config(index2canvas0(i) & 0xff,
|
||||
buf_start,
|
||||
canvas_width, canvas_height,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config((index2canvas0(i) >> 8) & 0xff,
|
||||
buf_start +
|
||||
decbuf_y_size, canvas_width / 2,
|
||||
canvas_height / 2, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config((index2canvas0(i) >> 16) & 0xff,
|
||||
buf_start +
|
||||
decbuf_y_size + decbuf_uv_size,
|
||||
canvas_width / 2, canvas_height / 2,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config(index2canvas1(i) & 0xff,
|
||||
buf_start +
|
||||
decbuf_size / 2, canvas_width,
|
||||
canvas_height, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config((index2canvas1(i) >> 8) & 0xff,
|
||||
buf_start +
|
||||
decbuf_y_size + decbuf_uv_size / 2,
|
||||
canvas_width / 2, canvas_height / 2,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config((index2canvas1(i) >> 16) & 0xff,
|
||||
buf_start +
|
||||
decbuf_y_size + decbuf_uv_size +
|
||||
decbuf_uv_size / 2, canvas_width / 2,
|
||||
canvas_height / 2, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
#endif
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_scaler(void)
|
||||
{
|
||||
/* 4 point triangle */
|
||||
const unsigned int filt_coef[] = {
|
||||
0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
|
||||
0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
|
||||
0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
|
||||
0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
|
||||
0x18382808, 0x18382808, 0x17372909, 0x17372909,
|
||||
0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
|
||||
0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
|
||||
0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
|
||||
0x10303010
|
||||
};
|
||||
int i;
|
||||
|
||||
/* pscale enable, PSCALE cbus bmem enable */
|
||||
WRITE_VREG(PSCALE_CTRL, 0xc000);
|
||||
|
||||
/* write filter coefs */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 0);
|
||||
for (i = 0; i < 33; i++) {
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, filt_coef[i]);
|
||||
}
|
||||
|
||||
/* Y horizontal initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 37 * 2);
|
||||
/* [35]: buf repeat pix0,
|
||||
* [34:29] => buf receive num,
|
||||
* [28:16] => buf blk x,
|
||||
* [15:0] => buf phase
|
||||
*/
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* C horizontal initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 41 * 2);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* Y vertical initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 39 * 2);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* C vertical initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 43 * 2);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* Y horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 36 * 2 + 1);
|
||||
/* [19:0] => Y horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
/* C horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 40 * 2 + 1);
|
||||
/* [19:0] => C horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
|
||||
/* Y vertical phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 38 * 2 + 1);
|
||||
/* [19:0] => Y vertical phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
/* C vertical phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 42 * 2 + 1);
|
||||
/* [19:0] => C horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
|
||||
/* reset pscaler */
|
||||
#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
|
||||
WRITE_VREG(DOS_SW_RESET0, (1 << 10));
|
||||
WRITE_VREG(DOS_SW_RESET0, 0);
|
||||
#else
|
||||
WRITE_RESET_REG(RESET2_REGISTER, RESET_PSCALE);
|
||||
#endif
|
||||
READ_RESET_REG(RESET2_REGISTER);
|
||||
READ_RESET_REG(RESET2_REGISTER);
|
||||
READ_RESET_REG(RESET2_REGISTER);
|
||||
|
||||
WRITE_VREG(PSCALE_RST, 0x7);
|
||||
WRITE_VREG(PSCALE_RST, 0x0);
|
||||
}
|
||||
|
||||
static int vmjpeg_prot_init(void)
|
||||
{
|
||||
int r;
|
||||
#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
|
||||
WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
|
||||
WRITE_VREG(DOS_SW_RESET0, 0);
|
||||
#else
|
||||
WRITE_RESET_REG(RESET0_REGISTER, RESET_IQIDCT | RESET_MC);
|
||||
#endif
|
||||
|
||||
r = vmjpeg_canvas_init();
|
||||
|
||||
WRITE_VREG(AV_SCRATCH_0, 12);
|
||||
WRITE_VREG(AV_SCRATCH_1, 0x031a);
|
||||
#ifdef NV21
|
||||
WRITE_VREG(AV_SCRATCH_4, 0x010100);
|
||||
WRITE_VREG(AV_SCRATCH_5, 0x030302);
|
||||
WRITE_VREG(AV_SCRATCH_6, 0x050504);
|
||||
WRITE_VREG(AV_SCRATCH_7, 0x070706);
|
||||
#else
|
||||
WRITE_VREG(AV_SCRATCH_4, 0x020100);
|
||||
WRITE_VREG(AV_SCRATCH_5, 0x050403);
|
||||
WRITE_VREG(AV_SCRATCH_6, 0x080706);
|
||||
WRITE_VREG(AV_SCRATCH_7, 0x0b0a09);
|
||||
#endif
|
||||
init_scaler();
|
||||
|
||||
/* clear buffer IN/OUT registers */
|
||||
WRITE_VREG(MREG_TO_AMRISC, 0);
|
||||
WRITE_VREG(MREG_FROM_AMRISC, 0);
|
||||
|
||||
WRITE_VREG(MCPU_INTR_MSK, 0xffff);
|
||||
WRITE_VREG(MREG_DECODE_PARAM, (frame_height << 4) | 0x8000);
|
||||
|
||||
/* clear mailbox interrupt */
|
||||
WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
|
||||
/* enable mailbox interrupt */
|
||||
WRITE_VREG(ASSIST_MBOX1_MASK, 1);
|
||||
/* set interrupt mapping for vld */
|
||||
WRITE_VREG(ASSIST_AMR1_INT8, 8);
|
||||
#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
|
||||
#ifdef NV21
|
||||
SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
|
||||
#else
|
||||
CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
|
||||
#endif
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vmjpeg_vdec_info_init(void)
|
||||
{
|
||||
gvs = kzalloc(sizeof(struct vdec_info), GFP_KERNEL);
|
||||
if (NULL == gvs) {
|
||||
pr_info("the struct of vdec status malloc failed.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmjpeg_local_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
frame_width = vmjpeg_amstream_dec_info.width;
|
||||
frame_height = vmjpeg_amstream_dec_info.height;
|
||||
frame_dur = vmjpeg_amstream_dec_info.rate;
|
||||
saved_resolution = 0;
|
||||
amlog_level(LOG_LEVEL_INFO, "mjpegdec: w(%d), h(%d), dur(%d)\n",
|
||||
frame_width, frame_height, frame_dur);
|
||||
|
||||
for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
|
||||
vfbuf_use[i] = 0;
|
||||
|
||||
INIT_KFIFO(display_q);
|
||||
INIT_KFIFO(recycle_q);
|
||||
INIT_KFIFO(newframe_q);
|
||||
|
||||
for (i = 0; i < VF_POOL_SIZE; i++) {
|
||||
const struct vframe_s *vf = &vfpool[i];
|
||||
|
||||
vfpool[i].index = DECODE_BUFFER_NUM_MAX;
|
||||
kfifo_put(&newframe_q, vf);
|
||||
}
|
||||
if (mm_blk_handle) {
|
||||
decoder_bmmu_box_free(mm_blk_handle);
|
||||
mm_blk_handle = NULL;
|
||||
}
|
||||
|
||||
mm_blk_handle = decoder_bmmu_box_alloc_box(
|
||||
DRIVER_NAME,
|
||||
0,
|
||||
MAX_BMMU_BUFFER_NUM,
|
||||
4 + PAGE_SHIFT,
|
||||
CODEC_MM_FLAGS_CMA_CLEAR |
|
||||
CODEC_MM_FLAGS_FOR_VDECODER);
|
||||
}
|
||||
|
||||
static s32 vmjpeg_init(void)
|
||||
{
|
||||
int ret = -1, size = -1;
|
||||
char *buf = vmalloc(0x1000 * 16);
|
||||
|
||||
if (IS_ERR_OR_NULL(buf))
|
||||
return -ENOMEM;
|
||||
|
||||
init_timer(&recycle_timer);
|
||||
|
||||
stat |= STAT_TIMER_INIT;
|
||||
|
||||
amvdec_enable();
|
||||
|
||||
vmjpeg_local_init();
|
||||
|
||||
size = get_firmware_data(VIDEO_DEC_MJPEG, buf);
|
||||
if (size < 0) {
|
||||
amvdec_disable();
|
||||
pr_err("get firmware fail.");
|
||||
vfree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size == 1)
|
||||
pr_info ("tee load ok");
|
||||
else if (amvdec_loadmc_ex(VFORMAT_MJPEG, NULL, buf) < 0) {
|
||||
amvdec_disable();
|
||||
vfree(buf);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
vfree(buf);
|
||||
|
||||
stat |= STAT_MC_LOAD;
|
||||
|
||||
/* enable AMRISC side protocol */
|
||||
ret = vmjpeg_prot_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = vdec_request_irq(VDEC_IRQ_1, vmjpeg_isr,
|
||||
"vmjpeg-irq", (void *)vmjpeg_dec_id);
|
||||
|
||||
if (ret) {
|
||||
amvdec_disable();
|
||||
|
||||
amlog_level(LOG_LEVEL_ERROR, "vmjpeg irq register error.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
stat |= STAT_ISR_REG;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
|
||||
vf_provider_init(&vmjpeg_vf_prov, PROVIDER_NAME, &vmjpeg_vf_provider,
|
||||
NULL);
|
||||
vf_reg_provider(&vmjpeg_vf_prov);
|
||||
vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_START, NULL);
|
||||
#else
|
||||
vf_provider_init(&vmjpeg_vf_prov, PROVIDER_NAME, &vmjpeg_vf_provider,
|
||||
NULL);
|
||||
vf_reg_provider(&vmjpeg_vf_prov);
|
||||
#endif
|
||||
|
||||
if (!is_reset)
|
||||
vf_notify_receiver(PROVIDER_NAME,
|
||||
VFRAME_EVENT_PROVIDER_FR_HINT,
|
||||
(void *)
|
||||
((unsigned long)vmjpeg_amstream_dec_info.rate));
|
||||
|
||||
stat |= STAT_VF_HOOK;
|
||||
|
||||
recycle_timer.data = (ulong)&recycle_timer;
|
||||
recycle_timer.function = vmjpeg_put_timer_func;
|
||||
recycle_timer.expires = jiffies + PUT_INTERVAL;
|
||||
|
||||
add_timer(&recycle_timer);
|
||||
|
||||
stat |= STAT_TIMER_ARM;
|
||||
|
||||
amvdec_start();
|
||||
|
||||
stat |= STAT_VDEC_RUN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amvdec_mjpeg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
|
||||
|
||||
mutex_lock(&vmjpeg_mutex);
|
||||
|
||||
amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg probe start.\n");
|
||||
|
||||
INIT_WORK(&set_clk_work, mjpeg_set_clk);
|
||||
|
||||
if (pdata == NULL) {
|
||||
amlog_level(LOG_LEVEL_ERROR,
|
||||
"amvdec_mjpeg memory resource undefined.\n");
|
||||
mutex_unlock(&vmjpeg_mutex);
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (pdata->sys_info)
|
||||
vmjpeg_amstream_dec_info = *pdata->sys_info;
|
||||
|
||||
pdata->dec_status = vmjpeg_dec_status;
|
||||
pdata->set_isreset = vmjpeg_set_isreset;
|
||||
is_reset = 0;
|
||||
vmjpeg_vdec_info_init();
|
||||
|
||||
if (vmjpeg_init() < 0) {
|
||||
amlog_level(LOG_LEVEL_ERROR, "amvdec_mjpeg init failed.\n");
|
||||
mutex_unlock(&vmjpeg_mutex);
|
||||
kfree(gvs);
|
||||
gvs = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_unlock(&vmjpeg_mutex);
|
||||
|
||||
amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg probe end.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amvdec_mjpeg_remove(struct platform_device *pdev)
|
||||
{
|
||||
mutex_lock(&vmjpeg_mutex);
|
||||
|
||||
cancel_work_sync(&set_clk_work);
|
||||
|
||||
if (stat & STAT_VDEC_RUN) {
|
||||
amvdec_stop();
|
||||
stat &= ~STAT_VDEC_RUN;
|
||||
}
|
||||
|
||||
if (stat & STAT_ISR_REG) {
|
||||
vdec_free_irq(VDEC_IRQ_1, (void *)vmjpeg_dec_id);
|
||||
stat &= ~STAT_ISR_REG;
|
||||
}
|
||||
|
||||
if (stat & STAT_TIMER_ARM) {
|
||||
del_timer_sync(&recycle_timer);
|
||||
stat &= ~STAT_TIMER_ARM;
|
||||
}
|
||||
|
||||
if (stat & STAT_VF_HOOK) {
|
||||
if (!is_reset)
|
||||
vf_notify_receiver(PROVIDER_NAME,
|
||||
VFRAME_EVENT_PROVIDER_FR_END_HINT,
|
||||
NULL);
|
||||
|
||||
vf_unreg_provider(&vmjpeg_vf_prov);
|
||||
stat &= ~STAT_VF_HOOK;
|
||||
}
|
||||
|
||||
amvdec_disable();
|
||||
|
||||
mutex_unlock(&vmjpeg_mutex);
|
||||
|
||||
kfree(gvs);
|
||||
gvs = NULL;
|
||||
|
||||
if (mm_blk_handle) {
|
||||
decoder_bmmu_box_free(mm_blk_handle);
|
||||
mm_blk_handle = NULL;
|
||||
}
|
||||
|
||||
amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg remove.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
|
||||
static struct platform_driver amvdec_mjpeg_driver = {
|
||||
.probe = amvdec_mjpeg_probe,
|
||||
.remove = amvdec_mjpeg_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = amvdec_suspend,
|
||||
.resume = amvdec_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
}
|
||||
};
|
||||
|
||||
static struct codec_profile_t amvdec_mjpeg_profile = {
|
||||
.name = "mjpeg",
|
||||
.profile = ""
|
||||
};
|
||||
static struct mconfig mjpeg_configs[] = {
|
||||
MC_PU32("stat", &stat),
|
||||
};
|
||||
static struct mconfig_node mjpeg_node;
|
||||
|
||||
static int __init amvdec_mjpeg_driver_init_module(void)
|
||||
{
|
||||
amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg module init\n");
|
||||
|
||||
if (platform_driver_register(&amvdec_mjpeg_driver)) {
|
||||
amlog_level(LOG_LEVEL_ERROR,
|
||||
"failed to register amvdec_mjpeg driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
vcodec_profile_register(&amvdec_mjpeg_profile);
|
||||
INIT_REG_NODE_CONFIGS("media.decoder", &mjpeg_node,
|
||||
"mjpeg", mjpeg_configs, CONFIG_FOR_RW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit amvdec_mjpeg_driver_remove_module(void)
|
||||
{
|
||||
amlog_level(LOG_LEVEL_INFO, "amvdec_mjpeg module remove.\n");
|
||||
|
||||
platform_driver_unregister(&amvdec_mjpeg_driver);
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
|
||||
module_param(stat, uint, 0664);
|
||||
MODULE_PARM_DESC(stat, "\n amvdec_mjpeg stat\n");
|
||||
|
||||
module_init(amvdec_mjpeg_driver_init_module);
|
||||
module_exit(amvdec_mjpeg_driver_remove_module);
|
||||
|
||||
MODULE_DESCRIPTION("AMLOGIC MJMPEG Video Decoder Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
|
||||
@@ -0,0 +1,932 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vmjpeg.c
|
||||
*
|
||||
* Copyright (C) 2015 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/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/amlogic/media/frame_sync/ptsserv.h>
|
||||
#include <linux/amlogic/media/utils/amstream.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 <linux/amlogic/tee.h>
|
||||
|
||||
#include <linux/amlogic/media/utils/vdec_reg.h>
|
||||
#include <linux/amlogic/media/registers/register.h>
|
||||
#include "../../../stream_input/amports/amports_priv.h"
|
||||
|
||||
#include "../utils/vdec_input.h"
|
||||
#include "../utils/vdec.h"
|
||||
#include "../utils/amvdec.h"
|
||||
#include "../utils/decoder_mmu_box.h"
|
||||
#include "../utils/decoder_bmmu_box.h"
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
||||
#include <linux/amlogic/media/codec_mm/configs.h>
|
||||
#include "../utils/firmware.h"
|
||||
|
||||
#define MEM_NAME "codec_mmjpeg"
|
||||
|
||||
#define DRIVER_NAME "ammvdec_mjpeg"
|
||||
#define MODULE_NAME "ammvdec_mjpeg"
|
||||
#define CHECK_INTERVAL (HZ/100)
|
||||
|
||||
/* protocol register usage
|
||||
* AV_SCRATCH_4 : decode buffer spec
|
||||
* AV_SCRATCH_5 : decode buffer index
|
||||
*/
|
||||
|
||||
#define MREG_DECODE_PARAM AV_SCRATCH_2 /* bit 0-3: pico_addr_mode */
|
||||
/* bit 15-4: reference height */
|
||||
#define MREG_TO_AMRISC AV_SCRATCH_8
|
||||
#define MREG_FROM_AMRISC AV_SCRATCH_9
|
||||
#define MREG_FRAME_OFFSET AV_SCRATCH_A
|
||||
#define DEC_STATUS_REG AV_SCRATCH_J
|
||||
|
||||
#define PICINFO_BUF_IDX_MASK 0x0007
|
||||
#define PICINFO_AVI1 0x0080
|
||||
#define PICINFO_INTERLACE 0x0020
|
||||
#define PICINFO_INTERLACE_AVI1_BOT 0x0010
|
||||
#define PICINFO_INTERLACE_FIRST 0x0010
|
||||
|
||||
#define VF_POOL_SIZE 16
|
||||
#define DECODE_BUFFER_NUM_MAX 4
|
||||
#define MAX_BMMU_BUFFER_NUM DECODE_BUFFER_NUM_MAX
|
||||
|
||||
#define DEFAULT_MEM_SIZE (32*SZ_1M)
|
||||
static int debug_enable;
|
||||
#define DECODE_ID(hw) (hw_to_vdec(hw)->id)
|
||||
|
||||
static struct vframe_s *vmjpeg_vf_peek(void *);
|
||||
static struct vframe_s *vmjpeg_vf_get(void *);
|
||||
static void vmjpeg_vf_put(struct vframe_s *, void *);
|
||||
static int vmjpeg_vf_states(struct vframe_states *states, void *);
|
||||
static int vmjpeg_event_cb(int type, void *data, void *private_data);
|
||||
static void vmjpeg_work(struct work_struct *work);
|
||||
static int pre_decode_buf_level = 0x800;
|
||||
|
||||
static const char vmjpeg_dec_id[] = "vmmjpeg-dev";
|
||||
|
||||
#define PROVIDER_NAME "vdec.mjpeg"
|
||||
static const struct vframe_operations_s vf_provider_ops = {
|
||||
.peek = vmjpeg_vf_peek,
|
||||
.get = vmjpeg_vf_get,
|
||||
.put = vmjpeg_vf_put,
|
||||
.event_cb = vmjpeg_event_cb,
|
||||
.vf_states = vmjpeg_vf_states,
|
||||
};
|
||||
|
||||
#define DEC_RESULT_NONE 0
|
||||
#define DEC_RESULT_DONE 1
|
||||
#define DEC_RESULT_AGAIN 2
|
||||
#define DEC_RESULT_FORCE_EXIT 3
|
||||
#define DEC_RESULT_EOS 4
|
||||
#define DEC_DECODE_TIMEOUT 0x21
|
||||
|
||||
|
||||
struct buffer_spec_s {
|
||||
unsigned int y_addr;
|
||||
unsigned int u_addr;
|
||||
unsigned int v_addr;
|
||||
|
||||
int y_canvas_index;
|
||||
int u_canvas_index;
|
||||
int v_canvas_index;
|
||||
|
||||
struct canvas_config_s canvas_config[3];
|
||||
unsigned long cma_alloc_addr;
|
||||
int cma_alloc_count;
|
||||
unsigned int buf_adr;
|
||||
};
|
||||
|
||||
#define spec2canvas(x) \
|
||||
(((x)->v_canvas_index << 16) | \
|
||||
((x)->u_canvas_index << 8) | \
|
||||
((x)->y_canvas_index << 0))
|
||||
|
||||
struct vdec_mjpeg_hw_s {
|
||||
spinlock_t lock;
|
||||
struct mutex vmjpeg_mutex;
|
||||
|
||||
struct platform_device *platform_dev;
|
||||
DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE);
|
||||
DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE);
|
||||
|
||||
struct vframe_s vfpool[VF_POOL_SIZE];
|
||||
struct buffer_spec_s buffer_spec[DECODE_BUFFER_NUM_MAX];
|
||||
s32 vfbuf_use[DECODE_BUFFER_NUM_MAX];
|
||||
|
||||
u32 frame_width;
|
||||
u32 frame_height;
|
||||
u32 frame_dur;
|
||||
u32 saved_resolution;
|
||||
u8 init_flag;
|
||||
u32 stat;
|
||||
u32 dec_result;
|
||||
unsigned long buf_start;
|
||||
u32 buf_size;
|
||||
void *mm_blk_handle;
|
||||
struct dec_sysinfo vmjpeg_amstream_dec_info;
|
||||
|
||||
struct vframe_chunk_s *chunk;
|
||||
struct work_struct work;
|
||||
void (*vdec_cb)(struct vdec_s *, void *);
|
||||
void *vdec_cb_arg;
|
||||
struct firmware_s *fw;
|
||||
struct timer_list check_timer;
|
||||
unsigned decode_timeout_count;
|
||||
u8 eos;
|
||||
u32 frame_num, put_num;
|
||||
};
|
||||
|
||||
static void set_frame_info(struct vdec_mjpeg_hw_s *hw, struct vframe_s *vf)
|
||||
{
|
||||
vf->width = hw->frame_width;
|
||||
vf->height = hw->frame_height;
|
||||
vf->duration = hw->frame_dur;
|
||||
vf->ratio_control = 0;
|
||||
vf->duration_pulldown = 0;
|
||||
vf->flag = 0;
|
||||
|
||||
vf->canvas0Addr = vf->canvas1Addr = -1;
|
||||
vf->plane_num = 3;
|
||||
|
||||
vf->canvas0_config[0] = hw->buffer_spec[vf->index].canvas_config[0];
|
||||
vf->canvas0_config[1] = hw->buffer_spec[vf->index].canvas_config[1];
|
||||
vf->canvas0_config[2] = hw->buffer_spec[vf->index].canvas_config[2];
|
||||
|
||||
vf->canvas1_config[0] = hw->buffer_spec[vf->index].canvas_config[0];
|
||||
vf->canvas1_config[1] = hw->buffer_spec[vf->index].canvas_config[1];
|
||||
vf->canvas1_config[2] = hw->buffer_spec[vf->index].canvas_config[2];
|
||||
}
|
||||
|
||||
static irqreturn_t vmjpeg_isr(struct vdec_s *vdec, int irq)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)(vdec->private);
|
||||
u32 reg;
|
||||
struct vframe_s *vf = NULL;
|
||||
u32 index, offset = 0, pts;
|
||||
u64 pts_us64;
|
||||
|
||||
if (debug_enable & 0x1)
|
||||
pr_info("%s: %d\n", __func__, __LINE__);
|
||||
|
||||
WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
|
||||
|
||||
if (!hw)
|
||||
return IRQ_HANDLED;
|
||||
if (hw->eos)
|
||||
return IRQ_HANDLED;
|
||||
reg = READ_VREG(MREG_FROM_AMRISC);
|
||||
index = READ_VREG(AV_SCRATCH_5);
|
||||
|
||||
if (index >= DECODE_BUFFER_NUM_MAX) {
|
||||
pr_err("fatal error, invalid buffer index.");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (kfifo_get(&hw->newframe_q, &vf) == 0) {
|
||||
pr_info(
|
||||
"fatal error, no available buffer slot.");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
vf->index = index;
|
||||
set_frame_info(hw, vf);
|
||||
|
||||
vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD;
|
||||
/* vf->pts = (pts_valid) ? pts : 0; */
|
||||
/* vf->pts_us64 = (pts_valid) ? pts_us64 : 0; */
|
||||
|
||||
if (hw->chunk) {
|
||||
vf->pts = hw->chunk->pts;
|
||||
vf->pts_us64 = hw->chunk->pts64;
|
||||
} else {
|
||||
offset = READ_VREG(MREG_FRAME_OFFSET);
|
||||
if (pts_lookup_offset_us64
|
||||
(PTS_TYPE_VIDEO, offset, &pts, 3000,
|
||||
&pts_us64) == 0) {
|
||||
vf->pts = pts;
|
||||
vf->pts_us64 = pts_us64;
|
||||
} else {
|
||||
vf->pts = 0;
|
||||
vf->pts_us64 = 0;
|
||||
}
|
||||
}
|
||||
vf->orientation = 0;
|
||||
hw->vfbuf_use[index]++;
|
||||
|
||||
kfifo_put(&hw->display_q, (const struct vframe_s *)vf);
|
||||
|
||||
hw->frame_num++;
|
||||
vf_notify_receiver(vdec->vf_provider_name,
|
||||
VFRAME_EVENT_PROVIDER_VFRAME_READY,
|
||||
NULL);
|
||||
|
||||
hw->dec_result = DEC_RESULT_DONE;
|
||||
|
||||
schedule_work(&hw->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct vframe_s *vmjpeg_vf_peek(void *op_arg)
|
||||
{
|
||||
struct vframe_s *vf;
|
||||
struct vdec_s *vdec = op_arg;
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
if (!hw)
|
||||
return NULL;
|
||||
|
||||
if (kfifo_peek(&hw->display_q, &vf))
|
||||
return vf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct vframe_s *vmjpeg_vf_get(void *op_arg)
|
||||
{
|
||||
struct vframe_s *vf;
|
||||
struct vdec_s *vdec = op_arg;
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
if (!hw)
|
||||
return NULL;
|
||||
|
||||
if (kfifo_get(&hw->display_q, &vf))
|
||||
return vf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void vmjpeg_vf_put(struct vframe_s *vf, void *op_arg)
|
||||
{
|
||||
struct vdec_s *vdec = op_arg;
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
hw->vfbuf_use[vf->index]--;
|
||||
kfifo_put(&hw->newframe_q, (const struct vframe_s *)vf);
|
||||
hw->put_num++;
|
||||
}
|
||||
|
||||
static int vmjpeg_event_cb(int type, void *data, void *private_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmjpeg_vf_states(struct vframe_states *states, void *op_arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct vdec_s *vdec = op_arg;
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
spin_lock_irqsave(&hw->lock, flags);
|
||||
|
||||
states->vf_pool_size = VF_POOL_SIZE;
|
||||
states->buf_free_num = kfifo_len(&hw->newframe_q);
|
||||
states->buf_avail_num = kfifo_len(&hw->display_q);
|
||||
states->buf_recycle_num = 0;
|
||||
|
||||
spin_unlock_irqrestore(&hw->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmjpeg_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
vstatus->frame_width = hw->frame_width;
|
||||
vstatus->frame_height = hw->frame_height;
|
||||
if (0 != hw->frame_dur)
|
||||
vstatus->frame_rate = 96000 / hw->frame_dur;
|
||||
else
|
||||
vstatus->frame_rate = 96000;
|
||||
vstatus->error_count = 0;
|
||||
vstatus->status = hw->stat;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
static void vmjpeg_canvas_init(struct vdec_s *vdec)
|
||||
{
|
||||
int i, ret;
|
||||
u32 canvas_width, canvas_height;
|
||||
u32 decbuf_size, decbuf_y_size, decbuf_uv_size;
|
||||
unsigned long buf_start, addr;
|
||||
struct vdec_mjpeg_hw_s *hw =
|
||||
(struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
canvas_width = 1920;
|
||||
canvas_height = 1088;
|
||||
decbuf_y_size = 0x200000;
|
||||
decbuf_uv_size = 0x80000;
|
||||
decbuf_size = 0x300000;
|
||||
|
||||
for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
|
||||
int canvas;
|
||||
|
||||
canvas = vdec->get_canvas(i, 3);
|
||||
|
||||
ret = decoder_bmmu_box_alloc_buf_phy(hw->mm_blk_handle, i,
|
||||
decbuf_size, DRIVER_NAME, &buf_start);
|
||||
if (ret < 0) {
|
||||
pr_err("CMA alloc failed! size 0x%d idx %d\n",
|
||||
decbuf_size, i);
|
||||
return;
|
||||
}
|
||||
|
||||
hw->buffer_spec[i].buf_adr = buf_start;
|
||||
addr = hw->buffer_spec[i].buf_adr;
|
||||
|
||||
hw->buffer_spec[i].y_addr = addr;
|
||||
addr += decbuf_y_size;
|
||||
hw->buffer_spec[i].u_addr = addr;
|
||||
addr += decbuf_uv_size;
|
||||
hw->buffer_spec[i].v_addr = addr;
|
||||
|
||||
hw->buffer_spec[i].y_canvas_index = canvas_y(canvas);
|
||||
hw->buffer_spec[i].u_canvas_index = canvas_u(canvas);
|
||||
hw->buffer_spec[i].v_canvas_index = canvas_v(canvas);
|
||||
|
||||
canvas_config(hw->buffer_spec[i].y_canvas_index,
|
||||
hw->buffer_spec[i].y_addr,
|
||||
canvas_width,
|
||||
canvas_height,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
hw->buffer_spec[i].canvas_config[0].phy_addr =
|
||||
hw->buffer_spec[i].y_addr;
|
||||
hw->buffer_spec[i].canvas_config[0].width =
|
||||
canvas_width;
|
||||
hw->buffer_spec[i].canvas_config[0].height =
|
||||
canvas_height;
|
||||
hw->buffer_spec[i].canvas_config[0].block_mode =
|
||||
CANVAS_BLKMODE_LINEAR;
|
||||
|
||||
canvas_config(hw->buffer_spec[i].u_canvas_index,
|
||||
hw->buffer_spec[i].u_addr,
|
||||
canvas_width / 2,
|
||||
canvas_height / 2,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
hw->buffer_spec[i].canvas_config[1].phy_addr =
|
||||
hw->buffer_spec[i].u_addr;
|
||||
hw->buffer_spec[i].canvas_config[1].width =
|
||||
canvas_width / 2;
|
||||
hw->buffer_spec[i].canvas_config[1].height =
|
||||
canvas_height / 2;
|
||||
hw->buffer_spec[i].canvas_config[1].block_mode =
|
||||
CANVAS_BLKMODE_LINEAR;
|
||||
|
||||
canvas_config(hw->buffer_spec[i].v_canvas_index,
|
||||
hw->buffer_spec[i].v_addr,
|
||||
canvas_width / 2,
|
||||
canvas_height / 2,
|
||||
CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
hw->buffer_spec[i].canvas_config[2].phy_addr =
|
||||
hw->buffer_spec[i].v_addr;
|
||||
hw->buffer_spec[i].canvas_config[2].width =
|
||||
canvas_width / 2;
|
||||
hw->buffer_spec[i].canvas_config[2].height =
|
||||
canvas_height / 2;
|
||||
hw->buffer_spec[i].canvas_config[2].block_mode =
|
||||
CANVAS_BLKMODE_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_scaler(void)
|
||||
{
|
||||
/* 4 point triangle */
|
||||
const unsigned int filt_coef[] = {
|
||||
0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
|
||||
0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
|
||||
0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
|
||||
0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
|
||||
0x18382808, 0x18382808, 0x17372909, 0x17372909,
|
||||
0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
|
||||
0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
|
||||
0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
|
||||
0x10303010
|
||||
};
|
||||
int i;
|
||||
|
||||
/* pscale enable, PSCALE cbus bmem enable */
|
||||
WRITE_VREG(PSCALE_CTRL, 0xc000);
|
||||
|
||||
/* write filter coefs */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 0);
|
||||
for (i = 0; i < 33; i++) {
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, filt_coef[i]);
|
||||
}
|
||||
|
||||
/* Y horizontal initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 37 * 2);
|
||||
/* [35]: buf repeat pix0,
|
||||
* [34:29] => buf receive num,
|
||||
* [28:16] => buf blk x,
|
||||
* [15:0] => buf phase
|
||||
*/
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* C horizontal initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 41 * 2);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* Y vertical initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 39 * 2);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* C vertical initial info */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 43 * 2);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x0008);
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x60000000);
|
||||
|
||||
/* Y horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 36 * 2 + 1);
|
||||
/* [19:0] => Y horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
/* C horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 40 * 2 + 1);
|
||||
/* [19:0] => C horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
|
||||
/* Y vertical phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 38 * 2 + 1);
|
||||
/* [19:0] => Y vertical phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
/* C vertical phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_ADDR, 42 * 2 + 1);
|
||||
/* [19:0] => C horizontal phase step */
|
||||
WRITE_VREG(PSCALE_BMEM_DAT, 0x10000);
|
||||
|
||||
/* reset pscaler */
|
||||
#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
|
||||
WRITE_VREG(DOS_SW_RESET0, (1 << 10));
|
||||
WRITE_VREG(DOS_SW_RESET0, 0);
|
||||
#else
|
||||
WRITE_RESET_REG(RESET2_REGISTER, RESET_PSCALE);
|
||||
#endif
|
||||
READ_RESET_REG(RESET2_REGISTER);
|
||||
READ_RESET_REG(RESET2_REGISTER);
|
||||
READ_RESET_REG(RESET2_REGISTER);
|
||||
|
||||
WRITE_VREG(PSCALE_RST, 0x7);
|
||||
WRITE_VREG(PSCALE_RST, 0x0);
|
||||
}
|
||||
|
||||
static void timeout_process(struct vdec_mjpeg_hw_s *hw)
|
||||
{
|
||||
amvdec_stop();
|
||||
pr_info("%s decoder timeout\n", __func__);
|
||||
hw->dec_result = DEC_RESULT_DONE;
|
||||
|
||||
vdec_schedule_work(&hw->work);
|
||||
}
|
||||
|
||||
static void check_timer_func(unsigned long arg)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw = (struct vdec_mjpeg_hw_s *)arg;
|
||||
struct vdec_s *vdec = hw_to_vdec(hw);
|
||||
if ((debug_enable & 0x2) != 0) {
|
||||
pr_info("%s: status:nstatus=%d:%d\n",
|
||||
__func__, vdec->status, vdec->next_status);
|
||||
pr_info("%s: %d,buftl=%x:%x:%x:%x\n",
|
||||
__func__, __LINE__,
|
||||
READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL),
|
||||
READ_PARSER_REG(PARSER_VIDEO_WP),
|
||||
READ_VREG(VLD_MEM_VIFIFO_LEVEL),
|
||||
READ_VREG(VLD_MEM_VIFIFO_WP));
|
||||
}
|
||||
if ((debug_enable & 0x100) != 0) {
|
||||
hw->dec_result = DEC_RESULT_DONE;
|
||||
vdec_schedule_work(&hw->work);
|
||||
pr_info("vdec %d is forced to be disconnected\n",
|
||||
debug_enable & 0xff);
|
||||
debug_enable = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (input_stream_based(vdec)
|
||||
&& READ_VREG(VLD_MEM_VIFIFO_LEVEL) <= 0x80) {
|
||||
if (hw->decode_timeout_count > 0)
|
||||
hw->decode_timeout_count--;
|
||||
if (hw->decode_timeout_count == 0)
|
||||
timeout_process(hw);
|
||||
}
|
||||
|
||||
if (READ_VREG(DEC_STATUS_REG) == DEC_DECODE_TIMEOUT) {
|
||||
pr_info("ucode DEC_DECODE_TIMEOUT\n");
|
||||
if (hw->decode_timeout_count > 0)
|
||||
hw->decode_timeout_count--;
|
||||
if (hw->decode_timeout_count == 0)
|
||||
timeout_process(hw);
|
||||
WRITE_VREG(DEC_STATUS_REG, 0);
|
||||
}
|
||||
|
||||
if (vdec->next_status == VDEC_STATUS_DISCONNECTED) {
|
||||
hw->dec_result = DEC_RESULT_FORCE_EXIT;
|
||||
vdec_schedule_work(&hw->work);
|
||||
pr_info("vdec requested to be disconnected\n");
|
||||
return;
|
||||
}
|
||||
mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
|
||||
}
|
||||
static void vmjpeg_hw_ctx_restore(struct vdec_s *vdec, int index)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw =
|
||||
(struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
WRITE_VREG(DOS_SW_RESET0, (1 << 7) | (1 << 6));
|
||||
WRITE_VREG(DOS_SW_RESET0, 0);
|
||||
|
||||
vmjpeg_canvas_init(vdec);
|
||||
|
||||
/* find next decode buffer index */
|
||||
WRITE_VREG(AV_SCRATCH_4, spec2canvas(&hw->buffer_spec[index]));
|
||||
WRITE_VREG(AV_SCRATCH_5, index);
|
||||
|
||||
init_scaler();
|
||||
|
||||
/* clear buffer IN/OUT registers */
|
||||
WRITE_VREG(MREG_TO_AMRISC, 0);
|
||||
WRITE_VREG(MREG_FROM_AMRISC, 0);
|
||||
|
||||
WRITE_VREG(MCPU_INTR_MSK, 0xffff);
|
||||
WRITE_VREG(MREG_DECODE_PARAM, (hw->frame_height << 4) | 0x8000);
|
||||
|
||||
/* clear mailbox interrupt */
|
||||
WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1);
|
||||
/* enable mailbox interrupt */
|
||||
WRITE_VREG(ASSIST_MBOX1_MASK, 1);
|
||||
/* set interrupt mapping for vld */
|
||||
WRITE_VREG(ASSIST_AMR1_INT8, 8);
|
||||
#if 1/*MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6*/
|
||||
CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 17);
|
||||
#endif
|
||||
}
|
||||
|
||||
static s32 vmjpeg_init(struct vdec_s *vdec)
|
||||
{
|
||||
int i;
|
||||
int size = -1, fw_size = 0x1000 * 16;
|
||||
struct firmware_s *fw = NULL;
|
||||
struct vdec_mjpeg_hw_s *hw =
|
||||
(struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
|
||||
fw = vmalloc(sizeof(struct firmware_s) + fw_size);
|
||||
if (IS_ERR_OR_NULL(fw))
|
||||
return -ENOMEM;
|
||||
if (tee_enabled()) {
|
||||
size = 1;
|
||||
pr_debug (" tee load\n");
|
||||
} else
|
||||
size = get_firmware_data(VIDEO_DEC_MJPEG_MULTI, fw->data);
|
||||
if (size < 0) {
|
||||
pr_err("get firmware fail.");
|
||||
vfree(fw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fw->len = size;
|
||||
hw->fw = fw;
|
||||
|
||||
hw->frame_width = hw->vmjpeg_amstream_dec_info.width;
|
||||
hw->frame_height = hw->vmjpeg_amstream_dec_info.height;
|
||||
hw->frame_dur = hw->vmjpeg_amstream_dec_info.rate;
|
||||
hw->saved_resolution = 0;
|
||||
hw->eos = 0;
|
||||
hw->init_flag = 0;
|
||||
hw->frame_num = 0;
|
||||
hw->put_num = 0;
|
||||
for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++)
|
||||
hw->vfbuf_use[i] = 0;
|
||||
|
||||
INIT_KFIFO(hw->display_q);
|
||||
INIT_KFIFO(hw->newframe_q);
|
||||
|
||||
for (i = 0; i < VF_POOL_SIZE; i++) {
|
||||
const struct vframe_s *vf = &hw->vfpool[i];
|
||||
|
||||
hw->vfpool[i].index = -1;
|
||||
kfifo_put(&hw->newframe_q, vf);
|
||||
}
|
||||
|
||||
if (hw->mm_blk_handle) {
|
||||
decoder_bmmu_box_free(hw->mm_blk_handle);
|
||||
hw->mm_blk_handle = NULL;
|
||||
}
|
||||
|
||||
hw->mm_blk_handle = decoder_bmmu_box_alloc_box(
|
||||
DRIVER_NAME,
|
||||
0,
|
||||
MAX_BMMU_BUFFER_NUM,
|
||||
4 + PAGE_SHIFT,
|
||||
CODEC_MM_FLAGS_CMA_CLEAR |
|
||||
CODEC_MM_FLAGS_FOR_VDECODER);
|
||||
|
||||
init_timer(&hw->check_timer);
|
||||
|
||||
hw->check_timer.data = (unsigned long)hw;
|
||||
hw->check_timer.function = check_timer_func;
|
||||
hw->check_timer.expires = jiffies + CHECK_INTERVAL;
|
||||
/*add_timer(&hw->check_timer);*/
|
||||
hw->stat |= STAT_TIMER_ARM;
|
||||
|
||||
INIT_WORK(&hw->work, vmjpeg_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw =
|
||||
(struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
if (hw->eos)
|
||||
return 0;
|
||||
if (vdec_stream_based(vdec) && (hw->init_flag == 0)
|
||||
&& pre_decode_buf_level != 0) {
|
||||
u32 rp, wp, level;
|
||||
|
||||
rp = READ_PARSER_REG(PARSER_VIDEO_RP);
|
||||
wp = READ_PARSER_REG(PARSER_VIDEO_WP);
|
||||
if (wp < rp)
|
||||
level = vdec->input.size + wp - rp;
|
||||
else
|
||||
level = wp - rp;
|
||||
|
||||
if (level < pre_decode_buf_level)
|
||||
return 0;
|
||||
}
|
||||
return CORE_MASK_VDEC_1 | CORE_MASK_HEVC;
|
||||
}
|
||||
|
||||
static void run(struct vdec_s *vdec, unsigned long mask,
|
||||
void (*callback)(struct vdec_s *, void *), void *arg)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw =
|
||||
(struct vdec_mjpeg_hw_s *)vdec->private;
|
||||
int i,ret = -1;
|
||||
|
||||
hw->vdec_cb_arg = arg;
|
||||
hw->vdec_cb = callback;
|
||||
|
||||
for (i = 0; i < DECODE_BUFFER_NUM_MAX; i++) {
|
||||
if (hw->vfbuf_use[i] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == DECODE_BUFFER_NUM_MAX) {
|
||||
hw->dec_result = DEC_RESULT_AGAIN;
|
||||
schedule_work(&hw->work);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = vdec_prepare_input(vdec, &hw->chunk);
|
||||
if (ret < 0) {
|
||||
if (debug_enable & 0x1) {
|
||||
pr_info("%s: %d,r=%d,buftl=%x:%x:%x\n",
|
||||
__func__, __LINE__, ret,
|
||||
READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL),
|
||||
READ_PARSER_REG(PARSER_VIDEO_WP),
|
||||
READ_VREG(VLD_MEM_VIFIFO_WP));
|
||||
}
|
||||
hw->dec_result = DEC_RESULT_AGAIN;
|
||||
schedule_work(&hw->work);
|
||||
return;
|
||||
}
|
||||
|
||||
hw->dec_result = DEC_RESULT_NONE;
|
||||
|
||||
if (amvdec_vdec_loadmc_ex(vdec, "vmmjpeg_mc",hw->fw->data) < 0) {
|
||||
pr_err("%s: Error amvdec_loadmc fail\n", __func__);
|
||||
return;
|
||||
}
|
||||
/* if (amvdec_vdec_loadmc_buf_ex(vdec, hw->fw->data, hw->fw->len) < 0) {
|
||||
pr_err("%s: Error amvdec_loadmc fail\n", __func__);
|
||||
return;
|
||||
}*/
|
||||
|
||||
vmjpeg_hw_ctx_restore(vdec, i);
|
||||
#if 0
|
||||
vdec_enable_input(vdec);
|
||||
mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
|
||||
#endif
|
||||
amvdec_start();
|
||||
vdec_enable_input(vdec);
|
||||
mod_timer(&hw->check_timer, jiffies + CHECK_INTERVAL);
|
||||
hw->decode_timeout_count = 2;
|
||||
hw->init_flag = 1;
|
||||
if (debug_enable&0x1) {
|
||||
|
||||
pr_info("%s (0x%x 0x%x 0x%x) vldcrl 0x%x bitcnt 0x%x powerctl 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
__func__,
|
||||
READ_VREG(VLD_MEM_VIFIFO_LEVEL),
|
||||
READ_VREG(VLD_MEM_VIFIFO_WP),
|
||||
READ_VREG(VLD_MEM_VIFIFO_RP),
|
||||
READ_VREG(VLD_DECODE_CONTROL),
|
||||
READ_VREG(VIFF_BIT_CNT),
|
||||
READ_VREG(POWER_CTL_VLD),
|
||||
READ_VREG(VLD_MEM_VIFIFO_START_PTR),
|
||||
READ_VREG(VLD_MEM_VIFIFO_CURR_PTR),
|
||||
READ_VREG(VLD_MEM_VIFIFO_CONTROL),
|
||||
READ_VREG(VLD_MEM_VIFIFO_BUF_CNTL),
|
||||
READ_VREG(VLD_MEM_VIFIFO_END_PTR));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void vmjpeg_work(struct work_struct *work)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw = container_of(work,
|
||||
struct vdec_mjpeg_hw_s, work);
|
||||
if (debug_enable & 0x2)
|
||||
pr_info("%s: result=%d,len=%d:%d\n",
|
||||
__func__, hw->dec_result,
|
||||
kfifo_len(&hw->newframe_q),
|
||||
kfifo_len(&hw->display_q));
|
||||
if (hw->dec_result == DEC_RESULT_DONE)
|
||||
vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
|
||||
else if (hw->dec_result == DEC_RESULT_AGAIN) {
|
||||
/*
|
||||
stream base: stream buf empty or timeout
|
||||
frame base: vdec_prepare_input fail
|
||||
*/
|
||||
if (!vdec_has_more_input(hw_to_vdec(hw))) {
|
||||
hw->dec_result = DEC_RESULT_EOS;
|
||||
vdec_schedule_work(&hw->work);
|
||||
/*pr_info("%s: return\n",
|
||||
__func__);*/
|
||||
return;
|
||||
}
|
||||
} else if (hw->dec_result == DEC_RESULT_FORCE_EXIT) {
|
||||
pr_info("%s: force exit\n",
|
||||
__func__);
|
||||
} else if (hw->dec_result == DEC_RESULT_EOS) {
|
||||
/*pr_info("%s: end of stream\n",
|
||||
__func__);*/
|
||||
if (READ_VREG(VLD_MEM_VIFIFO_LEVEL) < 0x100)
|
||||
hw->eos = 1;
|
||||
vdec_vframe_dirty(hw_to_vdec(hw), hw->chunk);
|
||||
}
|
||||
amvdec_stop();
|
||||
/* mark itself has all HW resource released and input released */
|
||||
vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_CONNECTED);
|
||||
vdec_core_finish_run(hw_to_vdec(hw), CORE_MASK_VDEC_1
|
||||
| CORE_MASK_HEVC);
|
||||
del_timer_sync(&hw->check_timer);
|
||||
hw->stat &= ~STAT_TIMER_ARM;
|
||||
|
||||
if (hw->vdec_cb)
|
||||
hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg);
|
||||
}
|
||||
|
||||
static int amvdec_mjpeg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data;
|
||||
struct vdec_mjpeg_hw_s *hw = NULL;
|
||||
|
||||
if (pdata == NULL) {
|
||||
pr_info("amvdec_mjpeg memory resource undefined.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
hw = (struct vdec_mjpeg_hw_s *)devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct vdec_mjpeg_hw_s), GFP_KERNEL);
|
||||
if (hw == NULL) {
|
||||
pr_info("\nammvdec_mjpeg device data allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pdata->private = hw;
|
||||
pdata->dec_status = vmjpeg_dec_status;
|
||||
|
||||
pdata->run = run;
|
||||
pdata->run_ready = run_ready;
|
||||
pdata->irq_handler = vmjpeg_isr;
|
||||
|
||||
|
||||
if (pdata->use_vfm_path)
|
||||
snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
|
||||
VFM_DEC_PROVIDER_NAME);
|
||||
else
|
||||
snprintf(pdata->vf_provider_name, VDEC_PROVIDER_NAME_SIZE,
|
||||
PROVIDER_NAME ".%02x", pdev->id & 0xff);
|
||||
|
||||
vf_provider_init(&pdata->vframe_provider, pdata->vf_provider_name,
|
||||
&vf_provider_ops, pdata);
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
hw->platform_dev = pdev;
|
||||
|
||||
if (pdata->sys_info)
|
||||
hw->vmjpeg_amstream_dec_info = *pdata->sys_info;
|
||||
|
||||
if (vmjpeg_init(pdata) < 0) {
|
||||
pr_info("amvdec_mjpeg init failed.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vdec_core_request(pdata, CORE_MASK_VDEC_1 | CORE_MASK_HEVC
|
||||
| CORE_MASK_COMBINE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amvdec_mjpeg_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vdec_mjpeg_hw_s *hw =
|
||||
(struct vdec_mjpeg_hw_s *)
|
||||
(((struct vdec_s *)(platform_get_drvdata(pdev)))->private);
|
||||
|
||||
|
||||
if (hw->stat & STAT_TIMER_ARM) {
|
||||
del_timer_sync(&hw->check_timer);
|
||||
hw->stat &= ~STAT_TIMER_ARM;
|
||||
}
|
||||
cancel_work_sync(&hw->work);
|
||||
if (hw->mm_blk_handle) {
|
||||
decoder_bmmu_box_free(hw->mm_blk_handle);
|
||||
hw->mm_blk_handle = NULL;
|
||||
}
|
||||
|
||||
vfree(hw->fw);
|
||||
hw->fw = NULL;
|
||||
|
||||
vdec_core_release(hw_to_vdec(hw), CORE_MASK_VDEC_1 | CORE_MASK_HEVC);
|
||||
vdec_set_status(hw_to_vdec(hw), VDEC_STATUS_DISCONNECTED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
|
||||
static struct platform_driver amvdec_mjpeg_driver = {
|
||||
.probe = amvdec_mjpeg_probe,
|
||||
.remove = amvdec_mjpeg_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = amvdec_suspend,
|
||||
.resume = amvdec_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
}
|
||||
};
|
||||
|
||||
static struct codec_profile_t amvdec_mjpeg_profile = {
|
||||
.name = "mmjpeg",
|
||||
.profile = ""
|
||||
};
|
||||
|
||||
static int __init amvdec_mjpeg_driver_init_module(void)
|
||||
{
|
||||
if (platform_driver_register(&amvdec_mjpeg_driver)) {
|
||||
pr_err("failed to register amvdec_mjpeg driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
vcodec_profile_register(&amvdec_mjpeg_profile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit amvdec_mjpeg_driver_remove_module(void)
|
||||
{
|
||||
platform_driver_unregister(&amvdec_mjpeg_driver);
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
module_param(debug_enable, uint, 0664);
|
||||
MODULE_PARM_DESC(debug_enable, "\n debug enable\n");
|
||||
module_param(pre_decode_buf_level, int, 0664);
|
||||
MODULE_PARM_DESC(pre_decode_buf_level,
|
||||
"\n ammvdec_h264 pre_decode_buf_level\n");
|
||||
module_init(amvdec_mjpeg_driver_init_module);
|
||||
module_exit(amvdec_mjpeg_driver_remove_module);
|
||||
|
||||
MODULE_DESCRIPTION("AMLOGIC MJMPEG Video Decoder Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>");
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG12) += amvdec_mpeg12.o
|
||||
amvdec_mpeg12-objs += vmpeg12.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vmpeg12.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VMPEG12_H
|
||||
#define VMPEG12_H
|
||||
|
||||
/* /#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
|
||||
/* TODO: move to register headers */
|
||||
#define VPP_VD1_POSTBLEND (1 << 10)
|
||||
/* /#endif */
|
||||
|
||||
#endif /* VMPEG12_H */
|
||||
@@ -0,0 +1,5 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4) += amvdec_mpeg4.o
|
||||
amvdec_mpeg4-objs += vmpeg4.o
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_MPEG4_MULTI) += amvdec_mmpeg4.o
|
||||
amvdec_mmpeg4-objs += vmpeg4_multi.o
|
||||
1257
drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c
Normal file
1257
drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vmpeg4.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VMPEG4_H
|
||||
#define VMPEG4_H
|
||||
|
||||
/* /#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
|
||||
/* TODO: move to register headers */
|
||||
#define VPP_VD1_POSTBLEND (1 << 10)
|
||||
/* /#endif */
|
||||
|
||||
#endif /* VMPEG4_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_REAL) += amvdec_real.o
|
||||
amvdec_real-objs += vreal.o
|
||||
1040
drivers/amlogic/media_modules/frame_provider/decoder/real/vreal.c
Normal file
1040
drivers/amlogic/media_modules/frame_provider/decoder/real/vreal.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vreal.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VREAL_H
|
||||
#define VREAL_H
|
||||
|
||||
#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
|
||||
/* TODO: move to register headers */
|
||||
#define VPP_VD1_POSTBLEND (1 << 10)
|
||||
#endif
|
||||
|
||||
#endif /* VREAL_H */
|
||||
@@ -0,0 +1,4 @@
|
||||
obj-m += decoder_common.o
|
||||
decoder_common-objs += utils.o vdec.o vdec_input.o amvdec.o
|
||||
decoder_common-objs += decoder_mmu_box.o decoder_bmmu_box.o
|
||||
decoder_common-objs += config_parser.o secprot.o vdec_profile.o
|
||||
1107
drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c
Normal file
1107
drivers/amlogic/media_modules/frame_provider/decoder/utils/amvdec.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/amvdec.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AMVDEC_H
|
||||
#define AMVDEC_H
|
||||
#include <linux/amlogic/media/utils/amports_config.h>
|
||||
#include <linux/amlogic/media/utils/vformat.h>
|
||||
#include "vdec.h"
|
||||
|
||||
#define UCODE_ALIGN 8
|
||||
#define UCODE_ALIGN_MASK 7UL
|
||||
|
||||
struct amvdec_dec_reg_s {
|
||||
unsigned long mem_start;
|
||||
unsigned long mem_end;
|
||||
struct device *cma_dev;
|
||||
struct dec_sysinfo *dec_sysinfo;
|
||||
}; /*amvdec_dec_reg_t */
|
||||
|
||||
struct vdec_s;
|
||||
|
||||
extern void amvdec_start(void);
|
||||
extern void amvdec_stop(void);
|
||||
extern void amvdec_enable(void);
|
||||
extern void amvdec_disable(void);
|
||||
s32 amvdec_loadmc_ex(enum vformat_e type, const char *name, char *def);
|
||||
s32 amvdec_vdec_loadmc_ex(struct vdec_s *vdec, const char *name, char *def);
|
||||
|
||||
extern void amvdec2_start(void);
|
||||
extern void amvdec2_stop(void);
|
||||
extern void amvdec2_enable(void);
|
||||
extern void amvdec2_disable(void);
|
||||
s32 amvdec2_loadmc_ex(enum vformat_e type, const char *name, char *def);
|
||||
|
||||
extern void amhevc_start(void);
|
||||
extern void amhevc_stop(void);
|
||||
extern void amhevc_enable(void);
|
||||
extern void amhevc_disable(void);
|
||||
s32 amhevc_loadmc_ex(enum vformat_e type, const char *name, char *def);
|
||||
s32 amhevc_vdec_loadmc_ex(struct vdec_s *vdec, const char *name, char *def);
|
||||
s32 amvdec_vdec_loadmc_buf_ex(struct vdec_s *vdec, char *buf, int size);
|
||||
|
||||
extern void amhcodec_start(void);
|
||||
extern void amhcodec_stop(void);
|
||||
s32 amhcodec_loadmc(const u32 *p);
|
||||
s32 amhcodec_loadmc_ex(enum vformat_e type, const char *name, char *def);
|
||||
|
||||
extern int amvdev_pause(void);
|
||||
extern int amvdev_resume(void);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int amvdec_suspend(struct platform_device *dev, pm_message_t event);
|
||||
extern int amvdec_resume(struct platform_device *dec);
|
||||
extern int amhevc_suspend(struct platform_device *dev, pm_message_t event);
|
||||
extern int amhevc_resume(struct platform_device *dec);
|
||||
|
||||
#endif
|
||||
|
||||
int amvdec_init(void);
|
||||
void amvdec_exit(void);
|
||||
|
||||
#if 1 /* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
|
||||
#define AMVDEC_CLK_GATE_ON(a)
|
||||
#define AMVDEC_CLK_GATE_OFF(a)
|
||||
#else
|
||||
#define AMVDEC_CLK_GATE_ON(a) CLK_GATE_ON(a)
|
||||
#define AMVDEC_CLK_GATE_OFF(a) CLK_GATE_OFF(a)
|
||||
#endif
|
||||
|
||||
/* TODO: move to register headers */
|
||||
#define RESET_VCPU (1<<7)
|
||||
#define RESET_CCPU (1<<8)
|
||||
|
||||
#endif /* AMVDEC_H */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/config_parser.c
|
||||
*
|
||||
* Copyright (C) 2015 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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "config_parser.h"
|
||||
/*
|
||||
*sample config:
|
||||
*configs: width:1920;height:1080;
|
||||
*need:width
|
||||
*ok: return 0;
|
||||
**val = value;
|
||||
*/
|
||||
int get_config_int(const char *configs, const char *need, int *val)
|
||||
{
|
||||
const char *str;
|
||||
int ret;
|
||||
int lval = 0;
|
||||
*val = 0;
|
||||
|
||||
if (!configs || !need)
|
||||
return -1;
|
||||
str = strstr(configs, need);
|
||||
if (str != NULL) {
|
||||
if (str > configs && str[-1] != ';') {
|
||||
/*
|
||||
* if not the first config val.
|
||||
* make sure before is ';'
|
||||
* to recognize:
|
||||
* ;crop_width:100
|
||||
* ;width:100
|
||||
*/
|
||||
return -2;
|
||||
}
|
||||
str += strlen(need);
|
||||
if (str[0] != ':' || str[1] == '\0')
|
||||
return -3;
|
||||
ret = sscanf(str, ":%d", &lval);
|
||||
if (ret == 1) {
|
||||
*val = lval;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -4;
|
||||
}
|
||||
EXPORT_SYMBOL(get_config_int);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/config_parser.c
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
#ifndef CONFIG_PARSER_HHH_
|
||||
#define CONFIG_PARSER_HHH_
|
||||
int get_config_int(const char *configs, const char *need, int *val);
|
||||
|
||||
#endif/*CONFIG_PARSER_HHH_*/
|
||||
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/decoder/decoder_bmmu_box.c
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
#define DEBUG
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm_scatter.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/amlogic/media/video_sink/video_keeper.h>
|
||||
#include "decoder_bmmu_box.h"
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
||||
|
||||
struct decoder_bmmu_box {
|
||||
int max_mm_num;
|
||||
const char *name;
|
||||
int channel_id;
|
||||
struct mutex mutex;
|
||||
struct list_head list;
|
||||
int total_size;
|
||||
int change_size_on_need_smaller;
|
||||
int align2n; /*can overwite on idx alloc */
|
||||
int mem_flags; /*can overwite on idx alloc */
|
||||
struct codec_mm_s *mm_list[1];
|
||||
};
|
||||
|
||||
struct decoder_bmmu_box_mgr {
|
||||
int num;
|
||||
struct mutex mutex;
|
||||
struct list_head box_list;
|
||||
};
|
||||
static struct decoder_bmmu_box_mgr global_blk_mgr;
|
||||
static struct decoder_bmmu_box_mgr *get_decoder_bmmu_box_mgr(void)
|
||||
{
|
||||
return &global_blk_mgr;
|
||||
}
|
||||
|
||||
static int decoder_bmmu_box_mgr_add_box(struct decoder_bmmu_box *box)
|
||||
{
|
||||
struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
|
||||
|
||||
mutex_lock(&mgr->mutex);
|
||||
list_add_tail(&box->list, &mgr->box_list);
|
||||
mutex_unlock(&mgr->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decoder_bmmu_box_mgr_del_box(struct decoder_bmmu_box *box)
|
||||
{
|
||||
struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
|
||||
|
||||
mutex_lock(&mgr->mutex);
|
||||
list_del(&box->list);
|
||||
mutex_unlock(&mgr->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *decoder_bmmu_box_alloc_box(const char *name,
|
||||
int channel_id, int max_num,
|
||||
int aligned, int mem_flags)
|
||||
/*min_size_M:wait alloc this size*/
|
||||
{
|
||||
struct decoder_bmmu_box *box;
|
||||
int size;
|
||||
int tvp_flags;
|
||||
tvp_flags = (mem_flags & CODEC_MM_FLAGS_TVP) ?
|
||||
CODEC_MM_FLAGS_TVP : 0;
|
||||
|
||||
pr_debug("decoder_bmmu_box_alloc_box, tvp_flags = %x\n", tvp_flags);
|
||||
|
||||
size = sizeof(struct decoder_bmmu_box) + sizeof(struct codec_mm_s *) *
|
||||
max_num;
|
||||
box = kmalloc(size, GFP_KERNEL);
|
||||
if (!box) {
|
||||
pr_err("can't alloc decoder buffers box!!!\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(box, 0, size);
|
||||
box->max_mm_num = max_num;
|
||||
box->name = name;
|
||||
box->channel_id = channel_id;
|
||||
box->align2n = aligned;
|
||||
box->mem_flags = mem_flags | tvp_flags;
|
||||
mutex_init(&box->mutex);
|
||||
INIT_LIST_HEAD(&box->list);
|
||||
decoder_bmmu_box_mgr_add_box(box);
|
||||
return (void *)box;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_alloc_box);
|
||||
|
||||
int decoder_bmmu_box_alloc_idx(void *handle, int idx, int size, int aligned_2n,
|
||||
int mem_flags)
|
||||
/*align& flags if -1 user box default.*/
|
||||
{
|
||||
struct decoder_bmmu_box *box = handle;
|
||||
struct codec_mm_s *mm;
|
||||
int align = aligned_2n;
|
||||
int memflags = mem_flags;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_mm_num) {
|
||||
pr_err("can't alloc mmu box(%p),idx:%d\n",
|
||||
box, idx);
|
||||
return -1;
|
||||
}
|
||||
if (align == -1)
|
||||
align = box->align2n;
|
||||
if (memflags == -1)
|
||||
memflags = box->mem_flags;
|
||||
|
||||
mutex_lock(&box->mutex);
|
||||
mm = box->mm_list[idx];
|
||||
if (mm) {
|
||||
int invalid = 0;
|
||||
|
||||
if (mm->page_count * PAGE_SIZE < size) {
|
||||
/*size is small. */
|
||||
invalid = 1;
|
||||
} else if (box->change_size_on_need_smaller &&
|
||||
(mm->buffer_size > (size << 1))) {
|
||||
/*size is too large. */
|
||||
invalid = 2;
|
||||
} else if (mm->phy_addr & ((1 << align) - 1)) {
|
||||
/*addr is not align */
|
||||
invalid = 4;
|
||||
}
|
||||
if (invalid) {
|
||||
box->total_size -= mm->buffer_size;
|
||||
codec_mm_release(mm, box->name);
|
||||
box->mm_list[idx] = NULL;
|
||||
mm = NULL;
|
||||
}
|
||||
}
|
||||
if (!mm) {
|
||||
mm = codec_mm_alloc(box->name, size, align, memflags);
|
||||
if (mm) {
|
||||
box->mm_list[idx] = mm;
|
||||
box->total_size += mm->buffer_size;
|
||||
mm->ins_id = box->channel_id;
|
||||
mm->ins_buffer_id = idx;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&box->mutex);
|
||||
return mm ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
int decoder_bmmu_box_free_idx(void *handle, int idx)
|
||||
{
|
||||
struct decoder_bmmu_box *box = handle;
|
||||
struct codec_mm_s *mm;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_mm_num) {
|
||||
pr_err("can't free idx of box(%p),idx:%d in (%d-%d)\n",
|
||||
box, idx, 0,
|
||||
box->max_mm_num - 1);
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&box->mutex);
|
||||
mm = box->mm_list[idx];
|
||||
if (mm) {
|
||||
box->total_size -= mm->buffer_size;
|
||||
codec_mm_release(mm, box->name);
|
||||
box->mm_list[idx] = NULL;
|
||||
mm = NULL;
|
||||
}
|
||||
mutex_unlock(&box->mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_free_idx);
|
||||
|
||||
int decoder_bmmu_box_free(void *handle)
|
||||
{
|
||||
struct decoder_bmmu_box *box = handle;
|
||||
struct codec_mm_s *mm;
|
||||
int i;
|
||||
|
||||
if (!box) {
|
||||
pr_err("can't free box of NULL box!\n");
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&box->mutex);
|
||||
for (i = 0; i < box->max_mm_num; i++) {
|
||||
mm = box->mm_list[i];
|
||||
if (mm) {
|
||||
codec_mm_release(mm, box->name);
|
||||
box->mm_list[i] = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&box->mutex);
|
||||
decoder_bmmu_box_mgr_del_box(box);
|
||||
kfree(box);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_free);
|
||||
|
||||
void *decoder_bmmu_box_get_mem_handle(void *box_handle, int idx)
|
||||
{
|
||||
struct decoder_bmmu_box *box = box_handle;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_mm_num)
|
||||
return NULL;
|
||||
return box->mm_list[idx];
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_get_mem_handle);
|
||||
|
||||
int decoder_bmmu_box_get_mem_size(void *box_handle, int idx)
|
||||
{
|
||||
struct decoder_bmmu_box *box = box_handle;
|
||||
int size = 0;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_mm_num)
|
||||
return 0;
|
||||
mutex_lock(&box->mutex);
|
||||
if (box->mm_list[idx] != NULL)
|
||||
size = box->mm_list[idx]->buffer_size;
|
||||
mutex_unlock(&box->mutex);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
unsigned long decoder_bmmu_box_get_phy_addr(void *box_handle, int idx)
|
||||
{
|
||||
struct decoder_bmmu_box *box = box_handle;
|
||||
struct codec_mm_s *mm;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_mm_num)
|
||||
return 0;
|
||||
mm = box->mm_list[idx];
|
||||
if (!mm)
|
||||
return 0;
|
||||
return mm->phy_addr;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_get_phy_addr);
|
||||
|
||||
void *decoder_bmmu_box_get_virt_addr(void *box_handle, int idx)
|
||||
{
|
||||
struct decoder_bmmu_box *box = box_handle;
|
||||
struct codec_mm_s *mm;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_mm_num)
|
||||
return NULL;
|
||||
mm = box->mm_list[idx];
|
||||
if (!mm)
|
||||
return 0;
|
||||
return codec_mm_phys_to_virt(mm->phy_addr);
|
||||
}
|
||||
|
||||
/*flags: &0x1 for wait,*/
|
||||
int decoder_bmmu_box_check_and_wait_size(int size, int flags)
|
||||
{
|
||||
if ((flags & BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER) &&
|
||||
codec_mm_get_free_size() < size) {
|
||||
pr_err("CMA force free keep,for size = %d\n", size);
|
||||
/*need free others?
|
||||
*/
|
||||
try_free_keep_video(1);
|
||||
}
|
||||
|
||||
return codec_mm_enough_for_size(size,
|
||||
flags & BMMU_ALLOC_FLAGS_WAIT);
|
||||
}
|
||||
|
||||
int decoder_bmmu_box_alloc_idx_wait(
|
||||
void *handle, int idx,
|
||||
int size, int aligned_2n,
|
||||
int mem_flags,
|
||||
int wait_flags)
|
||||
{
|
||||
int have_space;
|
||||
int ret = -1;
|
||||
|
||||
if (decoder_bmmu_box_get_mem_size(handle, idx) >= size)
|
||||
return 0;/*have alloced memery before.*/
|
||||
have_space = decoder_bmmu_box_check_and_wait_size(
|
||||
size,
|
||||
wait_flags);
|
||||
if (have_space) {
|
||||
ret = decoder_bmmu_box_alloc_idx(handle,
|
||||
idx, size, aligned_2n, mem_flags);
|
||||
} else {
|
||||
try_free_keep_video(1);
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_alloc_idx_wait);
|
||||
|
||||
int decoder_bmmu_box_alloc_buf_phy(
|
||||
void *handle, int idx,
|
||||
int size, unsigned char *driver_name,
|
||||
unsigned long *buf_phy_addr)
|
||||
{
|
||||
if (!decoder_bmmu_box_check_and_wait_size(
|
||||
size,
|
||||
1)) {
|
||||
pr_info("%s not enough buf for buf_idx = %d\n",
|
||||
driver_name, idx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!decoder_bmmu_box_alloc_idx_wait(
|
||||
handle,
|
||||
idx,
|
||||
size,
|
||||
-1,
|
||||
-1,
|
||||
BMMU_ALLOC_FLAGS_WAITCLEAR
|
||||
)) {
|
||||
*buf_phy_addr =
|
||||
decoder_bmmu_box_get_phy_addr(
|
||||
handle,
|
||||
idx);
|
||||
/*
|
||||
*pr_info("%s malloc buf_idx = %d addr = %ld size = %d\n",
|
||||
* driver_name, idx, *buf_phy_addr, size);
|
||||
*/
|
||||
} else {
|
||||
pr_info("%s malloc failed %d\n", driver_name, idx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_alloc_buf_phy);
|
||||
|
||||
static int decoder_bmmu_box_dump(struct decoder_bmmu_box *box, void *buf,
|
||||
int size)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
char sbuf[512];
|
||||
int tsize = 0;
|
||||
int s;
|
||||
int i;
|
||||
if (!buf) {
|
||||
pbuf = sbuf;
|
||||
size = 100000;
|
||||
}
|
||||
#define BUFPRINT(args...) \
|
||||
do {\
|
||||
s = snprintf(pbuf, size - tsize, args);\
|
||||
tsize += s;\
|
||||
pbuf += s; \
|
||||
} while (0)
|
||||
|
||||
for (i = 0; i < box->max_mm_num; i++) {
|
||||
struct codec_mm_s *mm = box->mm_list[i];
|
||||
if (buf && (size - tsize) < 256) {
|
||||
BUFPRINT("\n\t**NOT END**\n");
|
||||
break;
|
||||
}
|
||||
if (mm) {
|
||||
BUFPRINT("code mem[%d]:%p, addr=%p, size=%d,from=%d\n",
|
||||
i,
|
||||
(void *)mm,
|
||||
(void *)mm->phy_addr,
|
||||
mm->buffer_size,
|
||||
mm->from_flags);
|
||||
if (!buf) {
|
||||
pr_info("%s", sbuf);
|
||||
pbuf = sbuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef BUFPRINT
|
||||
|
||||
return tsize;
|
||||
}
|
||||
|
||||
static int decoder_bmmu_box_dump_all(void *buf, int size)
|
||||
{
|
||||
struct decoder_bmmu_box_mgr *mgr = get_decoder_bmmu_box_mgr();
|
||||
char *pbuf = buf;
|
||||
char sbuf[512];
|
||||
int tsize = 0;
|
||||
int s;
|
||||
int i;
|
||||
struct list_head *head, *list;
|
||||
if (!buf) {
|
||||
pbuf = sbuf;
|
||||
size = 100000;
|
||||
}
|
||||
#define BUFPRINT(args...) \
|
||||
do {\
|
||||
s = snprintf(pbuf, size - tsize, args);\
|
||||
tsize += s;\
|
||||
pbuf += s; \
|
||||
} while (0)
|
||||
|
||||
mutex_lock(&mgr->mutex);
|
||||
head = &mgr->box_list;
|
||||
list = head->next;
|
||||
i = 0;
|
||||
while (list != head) {
|
||||
struct decoder_bmmu_box *box;
|
||||
|
||||
box = list_entry(list, struct decoder_bmmu_box, list);
|
||||
BUFPRINT("box[%d]: %s, %splayer_id:%d, max_num:%d, size:%d\n",
|
||||
i, box->name,
|
||||
(box->mem_flags & CODEC_MM_FLAGS_TVP) ?
|
||||
"TVP mode " : "",
|
||||
box->channel_id,
|
||||
box->max_mm_num,
|
||||
box->total_size);
|
||||
if (buf) {
|
||||
s = decoder_bmmu_box_dump(box, pbuf, size - tsize);
|
||||
if (s > 0) {
|
||||
tsize += s;
|
||||
pbuf += s;
|
||||
}
|
||||
} else {
|
||||
pr_info("%s", sbuf);
|
||||
pbuf = sbuf;
|
||||
tsize += decoder_bmmu_box_dump(box, NULL, 0);
|
||||
}
|
||||
list = list->next;
|
||||
i++;
|
||||
}
|
||||
mutex_unlock(&mgr->mutex);
|
||||
|
||||
#undef BUFPRINT
|
||||
if (!buf)
|
||||
pr_info("%s", sbuf);
|
||||
return tsize;
|
||||
}
|
||||
|
||||
static ssize_t box_dump_show(struct class *class, struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
|
||||
ret = decoder_bmmu_box_dump_all(buf, PAGE_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t box_debug_show(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t size = 0;
|
||||
size += sprintf(buf, "box debug help:\n");
|
||||
size += sprintf(buf + size, "echo n > debug\n");
|
||||
size += sprintf(buf + size, "n==0: clear all debugs)\n");
|
||||
size += sprintf(buf + size,
|
||||
"n=1: dump all box\n");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t box_debug_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
unsigned val;
|
||||
ssize_t ret;
|
||||
val = -1;
|
||||
ret = sscanf(buf, "%d", &val);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
switch (val) {
|
||||
case 1:
|
||||
decoder_bmmu_box_dump_all(NULL , 0);
|
||||
break;
|
||||
default:
|
||||
pr_err("unknow cmd! %d\n", val);
|
||||
}
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct class_attribute decoder_bmmu_box_class_attrs[] = {
|
||||
__ATTR_RO(box_dump),
|
||||
__ATTR(debug, S_IRUGO | S_IWUSR | S_IWGRP,
|
||||
box_debug_show, box_debug_store),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static struct class decoder_bmmu_box_class = {
|
||||
.name = "decoder_bmmu_box",
|
||||
.class_attrs = decoder_bmmu_box_class_attrs,
|
||||
};
|
||||
|
||||
int decoder_bmmu_box_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
memset(&global_blk_mgr, 0, sizeof(global_blk_mgr));
|
||||
INIT_LIST_HEAD(&global_blk_mgr.box_list);
|
||||
mutex_init(&global_blk_mgr.mutex);
|
||||
r = class_register(&decoder_bmmu_box_class);
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_bmmu_box_init);
|
||||
|
||||
void decoder_bmmu_box_exit(void)
|
||||
{
|
||||
class_unregister(&decoder_bmmu_box_class);
|
||||
pr_info("dec bmmu box exit.\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int __init decoder_bmmu_box_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
memset(&global_blk_mgr, 0, sizeof(global_blk_mgr));
|
||||
INIT_LIST_HEAD(&global_blk_mgr.box_list);
|
||||
mutex_init(&global_blk_mgr.mutex);
|
||||
r = class_register(&decoder_bmmu_box_class);
|
||||
return r;
|
||||
}
|
||||
|
||||
module_init(decoder_bmmu_box_init);
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/decoder/decoder_bmmu_box.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DECODER_BLOCK_BUFFER_BOX
|
||||
#define DECODER_BLOCK_BUFFER_BOX
|
||||
|
||||
void *decoder_bmmu_box_alloc_box(const char *name,
|
||||
int channel_id,
|
||||
int max_num,
|
||||
int aligned,
|
||||
int mem_flags);
|
||||
|
||||
int decoder_bmmu_box_alloc_idx(
|
||||
void *handle, int idx, int size,
|
||||
int aligned_2n, int mem_flags);
|
||||
|
||||
int decoder_bmmu_box_free_idx(void *handle, int idx);
|
||||
int decoder_bmmu_box_free(void *handle);
|
||||
void *decoder_bmmu_box_get_mem_handle(
|
||||
void *box_handle, int idx);
|
||||
|
||||
unsigned long decoder_bmmu_box_get_phy_addr(
|
||||
void *box_handle, int idx);
|
||||
|
||||
void *decoder_bmmu_box_get_virt_addr(
|
||||
void *box_handle, int idx);
|
||||
|
||||
/*flags: &0x1 for wait,*/
|
||||
int decoder_bmmu_box_check_and_wait_size(
|
||||
int size, int flags);
|
||||
|
||||
int decoder_bmmu_box_alloc_buf_phy(
|
||||
void *handle, int idx,
|
||||
int size, unsigned char *driver_name,
|
||||
unsigned long *buf_phy_addr);
|
||||
|
||||
#define BMMU_ALLOC_FLAGS_WAIT (1 << 0)
|
||||
#define BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER (1 << 1)
|
||||
#define BMMU_ALLOC_FLAGS_WAITCLEAR \
|
||||
(BMMU_ALLOC_FLAGS_WAIT |\
|
||||
BMMU_ALLOC_FLAGS_CAN_CLEAR_KEEPER)
|
||||
|
||||
int decoder_bmmu_box_alloc_idx_wait(
|
||||
void *handle, int idx,
|
||||
int size, int aligned_2n,
|
||||
int mem_flags,
|
||||
int wait_flags);
|
||||
|
||||
int decoder_bmmu_box_init(void);
|
||||
void decoder_bmmu_box_exit(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/decoder_mmu_box.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/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm_scatter.h>
|
||||
#include <linux/platform_device.h>
|
||||
struct decoder_mmu_box {
|
||||
int max_sc_num;
|
||||
const char *name;
|
||||
int channel_id;
|
||||
int tvp_mode;
|
||||
struct mutex mutex;
|
||||
struct list_head list;
|
||||
struct codec_mm_scatter *sc_list[1];
|
||||
};
|
||||
#define MAX_KEEP_FRAME 4
|
||||
#define START_KEEP_ID 0x9
|
||||
#define MAX_KEEP_ID (INT_MAX - 1)
|
||||
struct decoder_mmu_box_mgr {
|
||||
int num;
|
||||
struct mutex mutex;
|
||||
struct codec_mm_scatter *keep_sc[MAX_KEEP_FRAME];
|
||||
int keep_id[MAX_KEEP_FRAME];
|
||||
int next_id;/*id for keep & free.*/
|
||||
struct list_head box_list;
|
||||
};
|
||||
static struct decoder_mmu_box_mgr global_mgr;
|
||||
static struct decoder_mmu_box_mgr *get_decoder_mmu_box_mgr(void)
|
||||
{
|
||||
return &global_mgr;
|
||||
}
|
||||
|
||||
static int decoder_mmu_box_mgr_add_box(struct decoder_mmu_box *box)
|
||||
{
|
||||
struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
|
||||
|
||||
mutex_lock(&mgr->mutex);
|
||||
list_add_tail(&box->list, &mgr->box_list);
|
||||
mutex_unlock(&mgr->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decoder_mmu_box_mgr_del_box(struct decoder_mmu_box *box)
|
||||
{
|
||||
struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
|
||||
|
||||
mutex_lock(&mgr->mutex);
|
||||
list_del(&box->list);
|
||||
mutex_unlock(&mgr->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *decoder_mmu_box_alloc_box(const char *name,
|
||||
int channel_id,
|
||||
int max_num,
|
||||
int min_size_M,
|
||||
int mem_flags)
|
||||
/*min_size_M:wait alloc this size*/
|
||||
{
|
||||
struct decoder_mmu_box *box;
|
||||
int size;
|
||||
|
||||
pr_debug("decoder_mmu_box_alloc_box, mem_flags = 0x%x\n", mem_flags);
|
||||
|
||||
size = sizeof(struct decoder_mmu_box) +
|
||||
sizeof(struct codec_mm_scatter *) *
|
||||
max_num;
|
||||
box = kmalloc(size, GFP_KERNEL);
|
||||
if (!box) {
|
||||
pr_err("can't alloc decoder buffers box!!!\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(box, 0, size);
|
||||
box->max_sc_num = max_num;
|
||||
box->name = name;
|
||||
box->channel_id = channel_id;
|
||||
box->tvp_mode = mem_flags;
|
||||
|
||||
mutex_init(&box->mutex);
|
||||
INIT_LIST_HEAD(&box->list);
|
||||
decoder_mmu_box_mgr_add_box(box);
|
||||
codec_mm_scatter_mgt_delay_free_swith(1, 2000,
|
||||
min_size_M, box->tvp_mode);
|
||||
return (void *)box;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_alloc_box);
|
||||
|
||||
int decoder_mmu_box_alloc_idx(
|
||||
void *handle, int idx, int num_pages,
|
||||
unsigned int *mmu_index_adr)
|
||||
{
|
||||
struct decoder_mmu_box *box = handle;
|
||||
struct codec_mm_scatter *sc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_sc_num) {
|
||||
pr_err("can't alloc mmu box(%p),idx:%d\n",
|
||||
box, idx);
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&box->mutex);
|
||||
sc = box->sc_list[idx];
|
||||
if (sc) {
|
||||
if (sc->page_max_cnt >= num_pages)
|
||||
ret = codec_mm_scatter_alloc_want_pages(sc,
|
||||
num_pages);
|
||||
else {
|
||||
codec_mm_scatter_dec_owner_user(sc, 0);
|
||||
box->sc_list[idx] = NULL;
|
||||
sc = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
if (!sc) {
|
||||
sc = codec_mm_scatter_alloc(num_pages + 64, num_pages,
|
||||
box->tvp_mode);
|
||||
if (!sc) {
|
||||
mutex_unlock(&box->mutex);
|
||||
pr_err("alloc mmu failed, need pages=%d\n",
|
||||
num_pages);
|
||||
return -1;
|
||||
}
|
||||
box->sc_list[idx] = sc;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_pages; i++)
|
||||
mmu_index_adr[i] = PAGE_INDEX(sc->pages_list[i]);
|
||||
mmu_index_adr[num_pages] = 0;
|
||||
|
||||
mutex_unlock(&box->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_alloc_idx);
|
||||
|
||||
int decoder_mmu_box_free_idx_tail(
|
||||
void *handle, int idx,
|
||||
int start_release_index)
|
||||
{
|
||||
struct decoder_mmu_box *box = handle;
|
||||
struct codec_mm_scatter *sc;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_sc_num) {
|
||||
pr_err("can't free tail mmu box(%p),idx:%d in (%d-%d)\n",
|
||||
box, idx, 0,
|
||||
box->max_sc_num - 1);
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&box->mutex);
|
||||
sc = box->sc_list[idx];
|
||||
if (sc && start_release_index < sc->page_cnt)
|
||||
codec_mm_scatter_free_tail_pages_fast(sc,
|
||||
start_release_index);
|
||||
mutex_unlock(&box->mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_free_idx_tail);
|
||||
|
||||
int decoder_mmu_box_free_idx(void *handle, int idx)
|
||||
{
|
||||
struct decoder_mmu_box *box = handle;
|
||||
struct codec_mm_scatter *sc;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_sc_num) {
|
||||
pr_err("can't free idx of box(%p),idx:%d in (%d-%d)\n",
|
||||
box, idx, 0,
|
||||
box->max_sc_num - 1);
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&box->mutex);
|
||||
sc = box->sc_list[idx];
|
||||
if (sc && sc->page_cnt > 0) {
|
||||
codec_mm_scatter_dec_owner_user(sc, 0);
|
||||
box->sc_list[idx] = NULL;
|
||||
} mutex_unlock(&box->mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_free_idx);
|
||||
|
||||
int decoder_mmu_box_free(void *handle)
|
||||
{
|
||||
struct decoder_mmu_box *box = handle;
|
||||
struct codec_mm_scatter *sc;
|
||||
int i;
|
||||
|
||||
if (!box) {
|
||||
pr_err("can't free box of NULL box!\n");
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&box->mutex);
|
||||
for (i = 0; i < box->max_sc_num; i++) {
|
||||
sc = box->sc_list[i];
|
||||
if (sc) {
|
||||
codec_mm_scatter_dec_owner_user(sc, 200);
|
||||
box->sc_list[i] = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&box->mutex);
|
||||
decoder_mmu_box_mgr_del_box(box);
|
||||
codec_mm_scatter_mgt_delay_free_swith(0, 2000, 0, box->tvp_mode);
|
||||
kfree(box);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_free);
|
||||
|
||||
void *decoder_mmu_box_get_mem_handle(void *box_handle, int idx)
|
||||
{
|
||||
struct decoder_mmu_box *box = box_handle;
|
||||
|
||||
if (!box || idx < 0 || idx >= box->max_sc_num)
|
||||
return NULL;
|
||||
return box->sc_list[idx];
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_get_mem_handle);
|
||||
|
||||
static int decoder_mmu_box_dump(struct decoder_mmu_box *box,
|
||||
void *buf, int size)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
char sbuf[512];
|
||||
int tsize = 0;
|
||||
int s;
|
||||
int i;
|
||||
|
||||
if (!buf) {
|
||||
pbuf = sbuf;
|
||||
size = 100000;
|
||||
}
|
||||
#define BUFPRINT(args...) \
|
||||
do {\
|
||||
s = snprintf(pbuf, size - tsize, args);\
|
||||
tsize += s;\
|
||||
pbuf += s; \
|
||||
} while (0)
|
||||
|
||||
for (i = 0; i < box->max_sc_num; i++) {
|
||||
struct codec_mm_scatter *sc = box->sc_list[i];
|
||||
|
||||
if (sc) {
|
||||
BUFPRINT("sc mem[%d]:%p, size=%d\n",
|
||||
i, sc,
|
||||
sc->page_cnt << PAGE_SHIFT);
|
||||
}
|
||||
}
|
||||
#undef BUFPRINT
|
||||
if (!buf)
|
||||
pr_info("%s", sbuf);
|
||||
|
||||
return tsize;
|
||||
}
|
||||
|
||||
static int decoder_mmu_box_dump_all(void *buf, int size)
|
||||
{
|
||||
struct decoder_mmu_box_mgr *mgr = get_decoder_mmu_box_mgr();
|
||||
char *pbuf = buf;
|
||||
char sbuf[512];
|
||||
int tsize = 0;
|
||||
int s;
|
||||
int i;
|
||||
struct list_head *head, *list;
|
||||
|
||||
if (!pbuf) {
|
||||
pbuf = sbuf;
|
||||
size = 100000;
|
||||
}
|
||||
|
||||
#define BUFPRINT(args...) \
|
||||
do {\
|
||||
s = snprintf(pbuf, size - tsize, args);\
|
||||
tsize += s;\
|
||||
pbuf += s; \
|
||||
} while (0)
|
||||
|
||||
mutex_lock(&mgr->mutex);
|
||||
head = &mgr->box_list;
|
||||
list = head->next;
|
||||
i = 0;
|
||||
while (list != head) {
|
||||
struct decoder_mmu_box *box;
|
||||
box = list_entry(list, struct decoder_mmu_box,
|
||||
list);
|
||||
BUFPRINT("box[%d]: %s, %splayer_id:%d, max_num:%d\n",
|
||||
i,
|
||||
box->name,
|
||||
box->tvp_mode ? "TVP mode " : "",
|
||||
box->channel_id,
|
||||
box->max_sc_num);
|
||||
if (buf) {
|
||||
s += decoder_mmu_box_dump(box, pbuf, size - tsize);
|
||||
if (s > 0) {
|
||||
tsize += s;
|
||||
pbuf += s;
|
||||
}
|
||||
} else {
|
||||
pr_info("%s", sbuf);
|
||||
pbuf = sbuf;
|
||||
tsize += decoder_mmu_box_dump(box, NULL, 0);
|
||||
}
|
||||
list = list->next;
|
||||
i++;
|
||||
}
|
||||
mutex_unlock(&mgr->mutex);
|
||||
|
||||
|
||||
#undef BUFPRINT
|
||||
if (!buf)
|
||||
pr_info("%s", sbuf);
|
||||
return tsize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ssize_t
|
||||
box_dump_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
|
||||
ret = decoder_mmu_box_dump_all(buf, PAGE_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct class_attribute decoder_mmu_box_class_attrs[] = {
|
||||
__ATTR_RO(box_dump),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static struct class decoder_mmu_box_class = {
|
||||
.name = "decoder_mmu_box",
|
||||
.class_attrs = decoder_mmu_box_class_attrs,
|
||||
};
|
||||
|
||||
int decoder_mmu_box_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
memset(&global_mgr, 0, sizeof(global_mgr));
|
||||
INIT_LIST_HEAD(&global_mgr.box_list);
|
||||
mutex_init(&global_mgr.mutex);
|
||||
global_mgr.next_id = START_KEEP_ID;
|
||||
r = class_register(&decoder_mmu_box_class);
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(decoder_mmu_box_init);
|
||||
|
||||
void decoder_mmu_box_exit(void)
|
||||
{
|
||||
class_unregister(&decoder_mmu_box_class);
|
||||
pr_info("dec mmu box exit.\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int __init decoder_mmu_box_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
memset(&global_mgr, 0, sizeof(global_mgr));
|
||||
INIT_LIST_HEAD(&global_mgr.box_list);
|
||||
mutex_init(&global_mgr.mutex);
|
||||
global_mgr.next_id = START_KEEP_ID;
|
||||
r = class_register(&decoder_mmu_box_class);
|
||||
return r;
|
||||
}
|
||||
|
||||
module_init(decoder_mmu_box_init);
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/decoder_mmu_box.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DECODER_BUFFER_BOX
|
||||
#define DECODER_BUFFER_BOX
|
||||
|
||||
void *decoder_mmu_box_alloc_box(const char *name,
|
||||
int channel_id,
|
||||
int max_num,
|
||||
int min_size_M,
|
||||
int mem_flags);
|
||||
|
||||
int decoder_mmu_box_alloc_idx(
|
||||
void *handle, int idx, int num_pages,
|
||||
unsigned int *mmu_index_adr);
|
||||
|
||||
int decoder_mmu_box_free_idx_tail(void *handle, int idx,
|
||||
int start_release_index);
|
||||
|
||||
int decoder_mmu_box_free_idx(void *handle, int idx);
|
||||
|
||||
int decoder_mmu_box_free(void *handle);
|
||||
|
||||
int decoder_mmu_box_move_keep_idx(void *box_handle,
|
||||
int keep_idx);
|
||||
int decoder_mmu_box_free_keep(int keep_id);
|
||||
int decoder_mmu_box_free_all_keep(void);
|
||||
void *decoder_mmu_box_get_mem_handle(void *box_handle, int idx);
|
||||
int decoder_mmu_box_init(void);
|
||||
void decoder_mmu_box_exit(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef __VIDEO_FIRMWARE_HEADER_
|
||||
#define __VIDEO_FIRMWARE_HEADER_
|
||||
|
||||
#include "../../../common/firmware/firmware_type.h"
|
||||
#include <linux/amlogic/media/utils/vformat.h>
|
||||
|
||||
#define FW_LOAD_FORCE (0x1)
|
||||
#define FW_LOAD_TRY (0X2)
|
||||
|
||||
struct firmware_s {
|
||||
unsigned int len;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
extern int get_decoder_firmware_data(enum vformat_e type,
|
||||
const char *file_name, char *buf, int size);
|
||||
extern int get_data_from_name(const char *name, char *buf);
|
||||
extern int get_firmware_data(unsigned int foramt, char *buf);
|
||||
extern int video_fw_reload(int mode);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/arch/secprot.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 "secprot.h"
|
||||
|
||||
int tee_config_device_secure(int dev_id, int secure)
|
||||
{
|
||||
int ret = 0;
|
||||
register unsigned x0 asm("x0");
|
||||
register unsigned x1 asm("x1");
|
||||
register unsigned x2 asm("x2");
|
||||
|
||||
x0 = OPTEE_SMC_CONFIG_DEVICE_SECURE;
|
||||
x1 = dev_id;
|
||||
x2 = secure;
|
||||
|
||||
asm volatile(
|
||||
__asmeq("%0", "x0")
|
||||
__asmeq("%1", "x0")
|
||||
__asmeq("%2", "x1")
|
||||
__asmeq("%3", "x2")
|
||||
"smc #0\n"
|
||||
: "=r"(x0)
|
||||
: "r"(x0), "r"(x1), "r"(x2));
|
||||
ret = x0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/arch/secprot.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SECPROT_H_
|
||||
#define __SECPROT_H_
|
||||
|
||||
#define DMC_DEV_TYPE_NON_SECURE 0
|
||||
#define DMC_DEV_TYPE_SECURE 1
|
||||
|
||||
#define DMC_DEV_ID_GPU 1
|
||||
#define DMC_DEV_ID_HEVC 4
|
||||
#define DMC_DEV_ID_PARSER 7
|
||||
#define DMC_DEV_ID_VPU 8
|
||||
#define DMC_DEV_ID_VDEC 13
|
||||
#define DMC_DEV_ID_HCODEC 14
|
||||
#define DMC_DEV_ID_GE2D 15
|
||||
|
||||
#define OPTEE_SMC_CONFIG_DEVICE_SECURE 0xb200000e
|
||||
|
||||
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
|
||||
|
||||
extern int tee_config_device_secure(int dev_id, int secure);
|
||||
|
||||
#endif /* __SECPROT_H_ */
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/utils.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/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/sched/rt.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "vdec.h"
|
||||
#include "vdec_input.h"
|
||||
#include <linux/amlogic/media/utils/vdec_reg.h>
|
||||
#include "amvdec.h"
|
||||
#include "decoder_mmu_box.h"
|
||||
#include "decoder_bmmu_box.h"
|
||||
#include "vdec_profile.h"
|
||||
|
||||
static int __init decoder_common_init(void)
|
||||
{
|
||||
/*vdec init.*/
|
||||
vdec_module_init();
|
||||
|
||||
/*amvdec init.*/
|
||||
amvdec_init();
|
||||
|
||||
/*mmu box init.*/
|
||||
decoder_mmu_box_init();/*exit?*/
|
||||
decoder_bmmu_box_init();
|
||||
|
||||
vdec_profile_init_debugfs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit decoder_common_exit(void)
|
||||
{
|
||||
/*vdec exit.*/
|
||||
vdec_module_exit();
|
||||
|
||||
/*amvdec exit.*/
|
||||
amvdec_exit();
|
||||
|
||||
decoder_mmu_box_exit();
|
||||
decoder_bmmu_box_exit();
|
||||
|
||||
vdec_profile_exit_debugfs();
|
||||
}
|
||||
|
||||
module_init(decoder_common_init);
|
||||
module_exit(decoder_common_exit);
|
||||
3861
drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c
Normal file
3861
drivers/amlogic/media_modules/frame_provider/decoder/utils/vdec.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/vdec.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VDEC_H
|
||||
#define VDEC_H
|
||||
#include <linux/amlogic/media/utils/amports_config.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/irqreturn.h>
|
||||
|
||||
#include <linux/amlogic/media/utils/amstream.h>
|
||||
#include <linux/amlogic/media/vfm/vframe.h>
|
||||
#include <linux/amlogic/media/vfm/vframe_provider.h>
|
||||
#include <linux/amlogic/media/vfm/vframe_receiver.h>
|
||||
|
||||
/*#define CONFIG_AM_VDEC_DV*/
|
||||
|
||||
#include "vdec_input.h"
|
||||
|
||||
s32 vdec_dev_register(void);
|
||||
s32 vdec_dev_unregister(void);
|
||||
|
||||
int vdec_source_changed(int format, int width, int height, int fps);
|
||||
int vdec2_source_changed(int format, int width, int height, int fps);
|
||||
int hevc_source_changed(int format, int width, int height, int fps);
|
||||
struct device *get_vdec_device(void);
|
||||
int vdec_module_init(void);
|
||||
void vdec_module_exit(void);
|
||||
|
||||
#define VDEC_DEBUG_SUPPORT
|
||||
|
||||
#define DEC_FLAG_HEVC_WORKAROUND 0x01
|
||||
|
||||
#define VDEC_FIFO_ALIGN 8
|
||||
|
||||
enum vdec_type_e {
|
||||
VDEC_1 = 0,
|
||||
VDEC_HCODEC,
|
||||
VDEC_2,
|
||||
VDEC_HEVC,
|
||||
VDEC_HEVCB,
|
||||
VDEC_MAX
|
||||
};
|
||||
|
||||
#define CORE_MASK_VDEC_1 (1 << VDEC_1)
|
||||
#define CORE_MASK_HCODEC (1 << VDEC_HCODEC)
|
||||
#define CORE_MASK_VDEC_2 (1 << VDEC_2)
|
||||
#define CORE_MASK_HEVC (1 << VDEC_HEVC)
|
||||
#define CORE_MASK_HEVC_FRONT (1 << VDEC_HEVC)
|
||||
#define CORE_MASK_HEVC_BACK (1 << VDEC_HEVCB)
|
||||
#define CORE_MASK_COMBINE (1UL << 31)
|
||||
|
||||
extern void vdec2_power_mode(int level);
|
||||
extern void vdec_poweron(enum vdec_type_e core);
|
||||
extern void vdec_poweroff(enum vdec_type_e core);
|
||||
extern bool vdec_on(enum vdec_type_e core);
|
||||
extern void vdec_power_reset(void);
|
||||
|
||||
/*irq num as same as .dts*/
|
||||
|
||||
/*
|
||||
* interrupts = <0 3 1
|
||||
* 0 23 1
|
||||
* 0 32 1
|
||||
* 0 43 1
|
||||
* 0 44 1
|
||||
* 0 45 1>;
|
||||
* interrupt-names = "vsync",
|
||||
* "demux",
|
||||
* "parser",
|
||||
* "mailbox_0",
|
||||
* "mailbox_1",
|
||||
* "mailbox_2";
|
||||
*/
|
||||
enum vdec_irq_num {
|
||||
VSYNC_IRQ = 0,
|
||||
DEMUX_IRQ,
|
||||
PARSER_IRQ,
|
||||
VDEC_IRQ_0,
|
||||
VDEC_IRQ_1,
|
||||
VDEC_IRQ_2,
|
||||
VDEC_IRQ_HEVC_BACK,
|
||||
VDEC_IRQ_MAX,
|
||||
};
|
||||
|
||||
enum vdec_fr_hint_state {
|
||||
VDEC_NO_NEED_HINT = 0,
|
||||
VDEC_NEED_HINT,
|
||||
VDEC_HINTED,
|
||||
};
|
||||
extern s32 vdec_request_threaded_irq(enum vdec_irq_num num,
|
||||
irq_handler_t handler,
|
||||
irq_handler_t thread_fn,
|
||||
unsigned long irqflags,
|
||||
const char *devname, void *dev);
|
||||
extern s32 vdec_request_irq(enum vdec_irq_num num, irq_handler_t handler,
|
||||
const char *devname, void *dev);
|
||||
extern void vdec_free_irq(enum vdec_irq_num num, void *dev);
|
||||
|
||||
extern void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
|
||||
unsigned int get_vdec_clk_config_settings(void);
|
||||
void update_vdec_clk_config_settings(unsigned int config);
|
||||
//unsigned int get_mmu_mode(void);//DEBUG_TMP
|
||||
|
||||
struct vdec_s;
|
||||
enum vformat_t;
|
||||
|
||||
/* stream based with single instance decoder driver */
|
||||
#define VDEC_TYPE_SINGLE 0
|
||||
|
||||
/* stream based with multi-instance decoder with HW resouce sharing */
|
||||
#define VDEC_TYPE_STREAM_PARSER 1
|
||||
|
||||
/* frame based with multi-instance decoder, input block list based */
|
||||
#define VDEC_TYPE_FRAME_BLOCK 2
|
||||
|
||||
/* frame based with multi-instance decoder, single circular input block */
|
||||
#define VDEC_TYPE_FRAME_CIRCULAR 3
|
||||
|
||||
/* decoder status: uninitialized */
|
||||
#define VDEC_STATUS_UNINITIALIZED 0
|
||||
|
||||
/* decoder status: before the decoder can start consuming data */
|
||||
#define VDEC_STATUS_DISCONNECTED 1
|
||||
|
||||
/* decoder status: decoder should become disconnected once it's not active */
|
||||
#define VDEC_STATUS_CONNECTED 2
|
||||
|
||||
/* decoder status: decoder owns HW resource and is running */
|
||||
#define VDEC_STATUS_ACTIVE 3
|
||||
|
||||
#define VDEC_PROVIDER_NAME_SIZE 16
|
||||
#define VDEC_RECEIVER_NAME_SIZE 16
|
||||
#define VDEC_MAP_NAME_SIZE 45
|
||||
|
||||
#define VDEC_FLAG_OTHER_INPUT_CONTEXT 0x0
|
||||
#define VDEC_FLAG_SELF_INPUT_CONTEXT 0x01
|
||||
|
||||
#define VDEC_NEED_MORE_DATA_RUN 0x01
|
||||
#define VDEC_NEED_MORE_DATA_DIRTY 0x02
|
||||
#define VDEC_NEED_MORE_DATA 0x04
|
||||
|
||||
struct vdec_s {
|
||||
u32 magic;
|
||||
struct list_head list;
|
||||
unsigned long core_mask;
|
||||
unsigned long active_mask;
|
||||
unsigned long sched_mask;
|
||||
int id;
|
||||
|
||||
struct vdec_s *master;
|
||||
struct vdec_s *slave;
|
||||
struct stream_port_s *port;
|
||||
int status;
|
||||
int next_status;
|
||||
int type;
|
||||
int port_flag;
|
||||
int format;
|
||||
u32 pts;
|
||||
u64 pts64;
|
||||
bool pts_valid;
|
||||
int flag;
|
||||
int sched;
|
||||
int need_more_data;
|
||||
|
||||
struct completion inactive_done;
|
||||
|
||||
/* config (temp) */
|
||||
unsigned long mem_start;
|
||||
unsigned long mem_end;
|
||||
|
||||
void *mm_blk_handle;
|
||||
|
||||
struct device *cma_dev;
|
||||
struct platform_device *dev;
|
||||
struct dec_sysinfo sys_info_store;
|
||||
struct dec_sysinfo *sys_info;
|
||||
|
||||
/* input */
|
||||
struct vdec_input_s input;
|
||||
|
||||
/* mc cache */
|
||||
u32 mc[4096 * 4];
|
||||
bool mc_loaded;
|
||||
|
||||
/* frame provider/receiver interface */
|
||||
char vf_provider_name[VDEC_PROVIDER_NAME_SIZE];
|
||||
struct vframe_provider_s vframe_provider;
|
||||
char *vf_receiver_name;
|
||||
char vfm_map_id[VDEC_MAP_NAME_SIZE];
|
||||
char vfm_map_chain[VDEC_MAP_NAME_SIZE];
|
||||
int vf_receiver_inst;
|
||||
enum FRAME_BASE_VIDEO_PATH frame_base_video_path;
|
||||
enum vdec_fr_hint_state fr_hint_state;
|
||||
bool use_vfm_path;
|
||||
char config[PAGE_SIZE];
|
||||
int config_len;
|
||||
bool is_reset;
|
||||
bool dolby_meta_with_el;
|
||||
|
||||
/* canvas */
|
||||
int (*get_canvas)(unsigned int index, unsigned int base);
|
||||
|
||||
int (*dec_status)(struct vdec_s *vdec, struct vdec_info *vstatus);
|
||||
int (*set_trickmode)(struct vdec_s *vdec, unsigned long trickmode);
|
||||
int (*set_isreset)(struct vdec_s *vdec, int isreset);
|
||||
|
||||
unsigned long (*run_ready)(struct vdec_s *vdec, unsigned long mask);
|
||||
void (*run)(struct vdec_s *vdec, unsigned long mask,
|
||||
void (*callback)(struct vdec_s *, void *), void *);
|
||||
void (*reset)(struct vdec_s *vdec);
|
||||
void (*dump_state)(struct vdec_s *vdec);
|
||||
irqreturn_t (*irq_handler)(struct vdec_s *vdec, int irq);
|
||||
irqreturn_t (*threaded_irq_handler)(struct vdec_s *vdec, int irq);
|
||||
|
||||
int (*user_data_read)(struct vdec_s *vdec,
|
||||
struct userdata_param_t *puserdata_para);
|
||||
void (*reset_userdata_fifo)(struct vdec_s *vdec, int bInit);
|
||||
|
||||
/* private */
|
||||
void *private; /* decoder per instance specific data */
|
||||
#ifdef VDEC_DEBUG_SUPPORT
|
||||
u64 profile_start_clk[VDEC_MAX];
|
||||
u64 total_clk[VDEC_MAX];
|
||||
u32 check_count[VDEC_MAX];
|
||||
u32 not_run_ready_count[VDEC_MAX];
|
||||
u32 input_underrun_count[VDEC_MAX];
|
||||
u32 run_count[VDEC_MAX];
|
||||
u64 run_clk[VDEC_MAX];
|
||||
u64 start_run_clk[VDEC_MAX];
|
||||
#endif
|
||||
atomic_t inirq_thread_flag;
|
||||
atomic_t inirq_flag;
|
||||
};
|
||||
|
||||
/* common decoder vframe provider name to use default vfm path */
|
||||
#define VFM_DEC_PROVIDER_NAME "decoder"
|
||||
#define VFM_DEC_DVBL_PROVIDER_NAME "dvbldec"
|
||||
#define VFM_DEC_DVEL_PROVIDER_NAME "dveldec"
|
||||
|
||||
#define hw_to_vdec(hw) ((struct vdec_s *) \
|
||||
(platform_get_drvdata(hw->platform_dev)))
|
||||
|
||||
#define canvas_y(canvas) ((canvas) & 0xff)
|
||||
#define canvas_u(canvas) (((canvas) >> 8) & 0xff)
|
||||
#define canvas_v(canvas) (((canvas) >> 16) & 0xff)
|
||||
#define canvas_y2(canvas) (((canvas) >> 16) & 0xff)
|
||||
#define canvas_u2(canvas) (((canvas) >> 24) & 0xff)
|
||||
|
||||
#define vdec_frame_based(vdec) \
|
||||
(((vdec)->type == VDEC_TYPE_FRAME_BLOCK) || \
|
||||
((vdec)->type == VDEC_TYPE_FRAME_CIRCULAR))
|
||||
#define vdec_stream_based(vdec) \
|
||||
(((vdec)->type == VDEC_TYPE_STREAM_PARSER) || \
|
||||
((vdec)->type == VDEC_TYPE_SINGLE))
|
||||
#define vdec_single(vdec) \
|
||||
((vdec)->type == VDEC_TYPE_SINGLE)
|
||||
#define vdec_dual(vdec) \
|
||||
(((vdec)->port->type & PORT_TYPE_DUALDEC) ||\
|
||||
(vdec_get_debug_flags() & 0x100))
|
||||
#define vdec_secure(vdec) \
|
||||
(((vdec)->port_flag & PORT_FLAG_DRM))
|
||||
|
||||
/* construct vdec strcture */
|
||||
extern struct vdec_s *vdec_create(struct stream_port_s *port,
|
||||
struct vdec_s *master);
|
||||
|
||||
/* set video format */
|
||||
extern int vdec_set_format(struct vdec_s *vdec, int format);
|
||||
|
||||
/* set PTS */
|
||||
extern int vdec_set_pts(struct vdec_s *vdec, u32 pts);
|
||||
|
||||
extern int vdec_set_pts64(struct vdec_s *vdec, u64 pts64);
|
||||
|
||||
/* set vfm map when use frame base decoder */
|
||||
extern int vdec_set_video_path(struct vdec_s *vdec, int video_path);
|
||||
|
||||
/* set receive id when receive is ionvideo or amlvideo */
|
||||
extern int vdec_set_receive_id(struct vdec_s *vdec, int receive_id);
|
||||
|
||||
/* add frame data to input chain */
|
||||
extern int vdec_write_vframe(struct vdec_s *vdec, const char *buf,
|
||||
size_t count);
|
||||
|
||||
/* mark the vframe_chunk as consumed */
|
||||
extern void vdec_vframe_dirty(struct vdec_s *vdec,
|
||||
struct vframe_chunk_s *chunk);
|
||||
|
||||
/* prepare decoder input */
|
||||
extern int vdec_prepare_input(struct vdec_s *vdec, struct vframe_chunk_s **p);
|
||||
|
||||
/* clean decoder input */
|
||||
extern void vdec_clean_input(struct vdec_s *vdec);
|
||||
|
||||
/* sync decoder input */
|
||||
extern int vdec_sync_input(struct vdec_s *vdec);
|
||||
|
||||
/* enable decoder input */
|
||||
extern void vdec_enable_input(struct vdec_s *vdec);
|
||||
|
||||
/* set decoder input prepare level */
|
||||
extern void vdec_set_prepare_level(struct vdec_s *vdec, int level);
|
||||
|
||||
/* set vdec input */
|
||||
extern int vdec_set_input_buffer(struct vdec_s *vdec, u32 start, u32 size);
|
||||
|
||||
/* check if decoder can get more input */
|
||||
extern bool vdec_has_more_input(struct vdec_s *vdec);
|
||||
|
||||
/* allocate input chain
|
||||
* register vdec_device
|
||||
* create output, vfm or create ionvideo output
|
||||
* insert vdec to vdec_manager for scheduling
|
||||
*/
|
||||
extern int vdec_connect(struct vdec_s *vdec);
|
||||
|
||||
/* remove vdec from vdec_manager scheduling
|
||||
* release input chain
|
||||
* disconnect video output from ionvideo
|
||||
*/
|
||||
extern int vdec_disconnect(struct vdec_s *vdec);
|
||||
|
||||
/* release vdec structure */
|
||||
extern int vdec_destroy(struct vdec_s *vdec);
|
||||
|
||||
/* reset vdec */
|
||||
extern int vdec_reset(struct vdec_s *vdec);
|
||||
|
||||
extern void vdec_set_status(struct vdec_s *vdec, int status);
|
||||
|
||||
extern void vdec_set_next_status(struct vdec_s *vdec, int status);
|
||||
|
||||
extern int vdec_set_decinfo(struct vdec_s *vdec, struct dec_sysinfo *p);
|
||||
|
||||
extern int vdec_init(struct vdec_s *vdec, int is_4k);
|
||||
|
||||
extern void vdec_release(struct vdec_s *vdec);
|
||||
|
||||
extern int vdec_status(struct vdec_s *vdec, struct vdec_info *vstatus);
|
||||
|
||||
extern int vdec_set_trickmode(struct vdec_s *vdec, unsigned long trickmode);
|
||||
|
||||
extern int vdec_set_isreset(struct vdec_s *vdec, int isreset);
|
||||
|
||||
extern int vdec_set_dv_metawithel(struct vdec_s *vdec, int isdvmetawithel);
|
||||
|
||||
extern void vdec_set_no_powerdown(int flag);
|
||||
|
||||
extern int vdec_is_support_4k(void);
|
||||
extern void vdec_set_flag(struct vdec_s *vdec, u32 flag);
|
||||
|
||||
extern void vdec_set_eos(struct vdec_s *vdec, bool eos);
|
||||
|
||||
extern void vdec_set_next_sched(struct vdec_s *vdec, struct vdec_s *next_vdec);
|
||||
|
||||
extern const char *vdec_status_str(struct vdec_s *vdec);
|
||||
|
||||
extern const char *vdec_type_str(struct vdec_s *vdec);
|
||||
|
||||
extern const char *vdec_device_name_str(struct vdec_s *vdec);
|
||||
|
||||
extern void vdec_schedule_work(struct work_struct *work);
|
||||
|
||||
extern void vdec_count_info(struct vdec_info *vs, unsigned int err,
|
||||
unsigned int offset);
|
||||
|
||||
extern bool vdec_need_more_data(struct vdec_s *vdec);
|
||||
|
||||
extern void hevc_reset_core(struct vdec_s *vdec);
|
||||
|
||||
extern void vdec_set_suspend_clk(int mode, int hevc);
|
||||
|
||||
extern unsigned long vdec_ready_to_run(struct vdec_s *vdec, unsigned long mask);
|
||||
|
||||
extern void vdec_prepare_run(struct vdec_s *vdec, unsigned long mask);
|
||||
|
||||
extern int vdec_core_request(struct vdec_s *vdec, unsigned long mask);
|
||||
|
||||
extern int vdec_core_release(struct vdec_s *vdec, unsigned long mask);
|
||||
|
||||
extern const bool vdec_core_with_input(unsigned long mask);
|
||||
|
||||
extern void vdec_core_finish_run(struct vdec_s *vdec, unsigned long mask);
|
||||
|
||||
#ifdef VDEC_DEBUG_SUPPORT
|
||||
extern void vdec_set_step_mode(void);
|
||||
#endif
|
||||
|
||||
int vdec_read_user_data(struct vdec_s *vdec,
|
||||
struct userdata_param_t *p_userdata_param);
|
||||
|
||||
int vdec_wakeup_userdata_poll(struct vdec_s *vdec);
|
||||
|
||||
void vdec_reset_userdata_fifo(struct vdec_s *vdec, int bInit);
|
||||
|
||||
#ifdef VDEC_DEBUG_SUPPORT
|
||||
extern void vdec_set_step_mode(void);
|
||||
#endif
|
||||
int vdec_get_debug_flags(void);
|
||||
|
||||
unsigned char is_mult_inc(unsigned int);
|
||||
|
||||
#endif /* VDEC_H */
|
||||
@@ -0,0 +1,940 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/vdec_input.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/uaccess.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
||||
|
||||
#include "../../../stream_input/amports/amports_priv.h"
|
||||
#include "vdec.h"
|
||||
#include "vdec_input.h"
|
||||
|
||||
#define VFRAME_BLOCK_SIZE (512 * SZ_1K)/*512 for 1080p default init.*/
|
||||
#define VFRAME_BLOCK_SIZE_4K (2 * SZ_1M) /*2M for 4K default.*/
|
||||
#define VFRAME_BLOCK_SIZE_MAX (4 * SZ_1M)
|
||||
|
||||
#define VFRAME_BLOCK_PAGEALIGN 4
|
||||
#define VFRAME_BLOCK_MIN_LEVEL (2 * SZ_1M)
|
||||
#define VFRAME_BLOCK_MAX_LEVEL (8 * SZ_1M)
|
||||
#define VFRAME_BLOCK_MAX_TOTAL_SIZE (16 * SZ_1M)
|
||||
|
||||
/*
|
||||
2s for OMX
|
||||
*/
|
||||
#define MAX_FRAME_DURATION_S 2
|
||||
|
||||
|
||||
#define VFRAME_BLOCK_HOLE (SZ_64K)
|
||||
|
||||
#define MIN_FRAME_PADDING_SIZE ((u32)(L1_CACHE_BYTES))
|
||||
|
||||
#define EXTRA_PADDING_SIZE (16 * SZ_1K) /*HEVC_PADDING_SIZE*/
|
||||
|
||||
#define MEM_NAME "VFRAME_INPUT"
|
||||
static int vdec_input_get_duration_u64(struct vdec_input_s *input);
|
||||
static struct vframe_block_list_s *
|
||||
vdec_input_alloc_new_block(struct vdec_input_s *input);
|
||||
|
||||
static int vframe_chunk_fill(struct vdec_input_s *input,
|
||||
struct vframe_chunk_s *chunk, const char *buf,
|
||||
size_t count, struct vframe_block_list_s *block)
|
||||
{
|
||||
u8 *p = (u8 *)block->start_virt + block->wp;
|
||||
int total_size = count + chunk->pading_size;
|
||||
if (block->type == VDEC_TYPE_FRAME_BLOCK) {
|
||||
if (copy_from_user(p, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
p += count;
|
||||
|
||||
memset(p, 0, chunk->pading_size);
|
||||
|
||||
dma_sync_single_for_device(get_vdec_device(),
|
||||
block->start + block->wp,
|
||||
total_size, DMA_TO_DEVICE);
|
||||
|
||||
} else if (block->type == VDEC_TYPE_FRAME_CIRCULAR) {
|
||||
size_t len = min((size_t)(block->size - block->wp), count);
|
||||
u32 wp;
|
||||
|
||||
if (copy_from_user(p, buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
dma_sync_single_for_device(get_vdec_device(),
|
||||
block->start + block->wp,
|
||||
len, DMA_TO_DEVICE);
|
||||
|
||||
p += len;
|
||||
|
||||
if (count > len) {
|
||||
p = (u8 *)block->start_virt;
|
||||
if (copy_from_user(p, buf, count - len))
|
||||
return -EFAULT;
|
||||
|
||||
dma_sync_single_for_device(get_vdec_device(),
|
||||
block->start,
|
||||
count-len, DMA_TO_DEVICE);
|
||||
|
||||
p += count - len;
|
||||
}
|
||||
|
||||
wp = block->wp + count;
|
||||
if (wp >= block->size)
|
||||
wp -= block->size;
|
||||
|
||||
len = min(block->size - wp, chunk->pading_size);
|
||||
|
||||
memset(p, 0, len);
|
||||
|
||||
dma_sync_single_for_device(get_vdec_device(),
|
||||
block->start + wp,
|
||||
len, DMA_TO_DEVICE);
|
||||
|
||||
if (chunk->pading_size > len) {
|
||||
p = (u8 *)block->start_virt;
|
||||
|
||||
memset(p, 0, count - len);
|
||||
|
||||
dma_sync_single_for_device(get_vdec_device(),
|
||||
block->start,
|
||||
chunk->pading_size - len, DMA_TO_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 vframe_block_space(struct vframe_block_list_s *block)
|
||||
{
|
||||
if (block->type == VDEC_TYPE_FRAME_BLOCK) {
|
||||
return block->size - block->wp;
|
||||
} else {
|
||||
return (block->rp >= block->wp) ?
|
||||
(block->rp - block->wp) :
|
||||
(block->rp - block->wp + block->size);
|
||||
}
|
||||
}
|
||||
|
||||
static void vframe_block_add_chunk(struct vframe_block_list_s *block,
|
||||
struct vframe_chunk_s *chunk)
|
||||
{
|
||||
block->wp += chunk->size + chunk->pading_size;
|
||||
if (block->wp >= block->size)
|
||||
block->wp -= block->size;
|
||||
block->data_size += chunk->size;
|
||||
block->chunk_count++;
|
||||
chunk->block = block;
|
||||
block->input->wr_block = block;
|
||||
chunk->sequence = block->input->sequence;
|
||||
block->input->sequence++;
|
||||
}
|
||||
|
||||
static void vframe_block_free_block(struct vframe_block_list_s *block)
|
||||
{
|
||||
if (block->addr) {
|
||||
codec_mm_free_for_dma(MEM_NAME, block->addr);
|
||||
}
|
||||
/*
|
||||
*pr_err("free block %d, size=%d\n", block->id, block->size);
|
||||
*/
|
||||
kfree(block);
|
||||
}
|
||||
|
||||
static int vframe_block_init_alloc_storage(struct vdec_input_s *input,
|
||||
struct vframe_block_list_s *block)
|
||||
{
|
||||
int alloc_size = input->default_block_size;
|
||||
block->magic = 0x4b434c42;
|
||||
block->input = input;
|
||||
block->type = input->type;
|
||||
|
||||
/*
|
||||
* todo: for different type use different size
|
||||
*/
|
||||
alloc_size = PAGE_ALIGN(alloc_size);
|
||||
block->addr = codec_mm_alloc_for_dma_ex(
|
||||
MEM_NAME,
|
||||
alloc_size/PAGE_SIZE,
|
||||
VFRAME_BLOCK_PAGEALIGN,
|
||||
CODEC_MM_FLAGS_DMA_CPU | CODEC_MM_FLAGS_FOR_VDECODER,
|
||||
input->id,
|
||||
block->id);
|
||||
|
||||
if (!block->addr) {
|
||||
pr_err("Input block allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
block->start_virt = (void *)codec_mm_phys_to_virt(block->addr);
|
||||
block->start = block->addr;
|
||||
block->size = alloc_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vdec_input_init(struct vdec_input_s *input, struct vdec_s *vdec)
|
||||
{
|
||||
INIT_LIST_HEAD(&input->vframe_block_list);
|
||||
INIT_LIST_HEAD(&input->vframe_block_free_list);
|
||||
INIT_LIST_HEAD(&input->vframe_chunk_list);
|
||||
spin_lock_init(&input->lock);
|
||||
input->id = vdec->id;
|
||||
input->block_nums = 0;
|
||||
input->vdec = vdec;
|
||||
input->block_id_seq = 0;
|
||||
input->size = 0;
|
||||
input->default_block_size = VFRAME_BLOCK_SIZE;
|
||||
}
|
||||
int vdec_input_prepare_bufs(struct vdec_input_s *input,
|
||||
int frame_width, int frame_height)
|
||||
{
|
||||
struct vframe_block_list_s *block;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (input->size > 0)
|
||||
return 0;
|
||||
if (frame_width * frame_height >= 1920 * 1088) {
|
||||
/*have add data before. ignore prepare buffers.*/
|
||||
input->default_block_size = VFRAME_BLOCK_SIZE_4K;
|
||||
}
|
||||
/*prepared 3 buffers for smooth start.*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
block = vdec_input_alloc_new_block(input);
|
||||
if (!block)
|
||||
break;
|
||||
flags = vdec_input_lock(input);
|
||||
list_move_tail(&block->list,
|
||||
&input->vframe_block_free_list);
|
||||
input->wr_block = NULL;
|
||||
vdec_input_unlock(input, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdec_input_dump_block_locked(
|
||||
struct vframe_block_list_s *block,
|
||||
char *buf, int size)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
char sbuf[512];
|
||||
int tsize = 0;
|
||||
int s;
|
||||
if (!pbuf) {
|
||||
pbuf = sbuf;
|
||||
size = 512;
|
||||
}
|
||||
#define BUFPRINT(args...) \
|
||||
do {\
|
||||
s = snprintf(pbuf, size - tsize, args);\
|
||||
tsize += s;\
|
||||
pbuf += s; \
|
||||
} while (0)
|
||||
|
||||
BUFPRINT("\tblock:[%d:%p]-addr=%p,vstart=%p,type=%d\n",
|
||||
block->id,
|
||||
block,
|
||||
(void *)block->addr,
|
||||
(void *)block->start_virt,
|
||||
block->type);
|
||||
BUFPRINT("\t-blocksize=%d,data=%d,wp=%d,rp=%d,chunk_count=%d\n",
|
||||
block->size,
|
||||
block->data_size,
|
||||
block->wp,
|
||||
block->rp,
|
||||
block->chunk_count);
|
||||
/*
|
||||
BUFPRINT("\tlist=%p,next=%p,prev=%p\n",
|
||||
&block->list,
|
||||
block->list.next,
|
||||
block->list.prev);
|
||||
*/
|
||||
#undef BUFPRINT
|
||||
if (!buf)
|
||||
pr_info("%s", sbuf);
|
||||
return tsize;
|
||||
}
|
||||
|
||||
int vdec_input_dump_blocks(struct vdec_input_s *input,
|
||||
char *bufs, int size)
|
||||
{
|
||||
struct list_head *p, *tmp;
|
||||
unsigned long flags;
|
||||
char *lbuf = bufs;
|
||||
char sbuf[256];
|
||||
int s = 0;
|
||||
|
||||
if (size <= 0)
|
||||
return 0;
|
||||
if (!bufs)
|
||||
lbuf = sbuf;
|
||||
s += snprintf(lbuf + s, size - s,
|
||||
"blocks:vdec-%d id:%d,bufsize=%d,dsize=%d,frames:%d,dur:%dms\n",
|
||||
input->id,
|
||||
input->block_nums,
|
||||
input->size,
|
||||
input->data_size,
|
||||
input->have_frame_num,
|
||||
vdec_input_get_duration_u64(input)/1000);
|
||||
if (bufs)
|
||||
lbuf += s;
|
||||
else {
|
||||
pr_info("%s", sbuf);
|
||||
lbuf = NULL;
|
||||
}
|
||||
|
||||
flags = vdec_input_lock(input);
|
||||
/* dump input blocks */
|
||||
list_for_each_safe(p, tmp, &input->vframe_block_list) {
|
||||
struct vframe_block_list_s *block = list_entry(
|
||||
p, struct vframe_block_list_s, list);
|
||||
if (bufs != NULL) {
|
||||
lbuf = bufs + s;
|
||||
if (size - s < 128)
|
||||
break;
|
||||
}
|
||||
s += vdec_input_dump_block_locked(block, lbuf, size - s);
|
||||
}
|
||||
list_for_each_safe(p, tmp, &input->vframe_block_free_list) {
|
||||
struct vframe_block_list_s *block = list_entry(
|
||||
p, struct vframe_block_list_s, list);
|
||||
if (bufs != NULL) {
|
||||
lbuf = bufs + s;
|
||||
if (size - s < 128)
|
||||
break;
|
||||
}
|
||||
s += vdec_input_dump_block_locked(block, lbuf, size - s);
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int vdec_input_dump_chunk_locked(
|
||||
struct vframe_chunk_s *chunk,
|
||||
char *buf, int size)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
char sbuf[512];
|
||||
int tsize = 0;
|
||||
int s;
|
||||
if (!pbuf) {
|
||||
pbuf = sbuf;
|
||||
size = 512;
|
||||
}
|
||||
#define BUFPRINT(args...) \
|
||||
do {\
|
||||
s = snprintf(pbuf, size - tsize, args);\
|
||||
tsize += s;\
|
||||
pbuf += s; \
|
||||
} while (0)
|
||||
|
||||
BUFPRINT(
|
||||
"\t[%lld:%p]-off=%d,size:%d,p:%d,\tpts64=%lld,addr=%p\n",
|
||||
chunk->sequence,
|
||||
chunk->block,
|
||||
chunk->offset,
|
||||
chunk->size,
|
||||
chunk->pading_size,
|
||||
chunk->pts64,
|
||||
(void *)(chunk->block->addr + chunk->offset));
|
||||
/*
|
||||
BUFPRINT("\tlist=%p,next=%p,prev=%p\n",
|
||||
&chunk->list,
|
||||
chunk->list.next,
|
||||
chunk->list.prev);
|
||||
*/
|
||||
#undef BUFPRINT
|
||||
if (!buf)
|
||||
pr_info("%s", sbuf);
|
||||
return tsize;
|
||||
}
|
||||
|
||||
int vdec_input_dump_chunks(struct vdec_input_s *input,
|
||||
char *bufs, int size)
|
||||
{
|
||||
|
||||
struct list_head *p, *tmp;
|
||||
unsigned long flags;
|
||||
char *lbuf = bufs;
|
||||
char sbuf[256];
|
||||
int s = 0;
|
||||
if (size <= 0)
|
||||
return 0;
|
||||
if (!bufs)
|
||||
lbuf = sbuf;
|
||||
snprintf(lbuf + s, size - s,
|
||||
"blocks:vdec-%d id:%d,bufsize=%d,dsize=%d,frames:%d,maxframe:%d\n",
|
||||
input->id,
|
||||
input->block_nums,
|
||||
input->size,
|
||||
input->data_size,
|
||||
input->have_frame_num,
|
||||
input->frame_max_size);
|
||||
if (bufs)
|
||||
lbuf += s;
|
||||
if (!bufs) {
|
||||
pr_info("%s", sbuf);
|
||||
lbuf = NULL;
|
||||
}
|
||||
flags = vdec_input_lock(input);
|
||||
/*dump chunks list infos.*/
|
||||
list_for_each_safe(p, tmp, &input->vframe_chunk_list) {
|
||||
struct vframe_chunk_s *chunk = list_entry(
|
||||
p, struct vframe_chunk_s, list);
|
||||
if (bufs != NULL)
|
||||
lbuf = bufs + s;
|
||||
s += vdec_input_dump_chunk_locked(chunk, lbuf, size - s);
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vdec_input_set_buffer(struct vdec_input_s *input, u32 start, u32 size)
|
||||
{
|
||||
if (input_frame_based(input))
|
||||
return -EINVAL;
|
||||
|
||||
input->start = start;
|
||||
input->size = size;
|
||||
input->swap_rp = start;
|
||||
|
||||
if (vdec_secure(input->vdec))
|
||||
input->swap_page_phys = codec_mm_alloc_for_dma("SWAP",
|
||||
1, 0, CODEC_MM_FLAGS_TVP);
|
||||
else {
|
||||
input->swap_page = alloc_page(GFP_KERNEL);
|
||||
if (input->swap_page) {
|
||||
input->swap_page_phys =
|
||||
page_to_phys(input->swap_page);
|
||||
}
|
||||
}
|
||||
|
||||
if (input->swap_page_phys == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_set_buffer);
|
||||
|
||||
void vdec_input_set_type(struct vdec_input_s *input, int type, int target)
|
||||
{
|
||||
input->type = type;
|
||||
input->target = target;
|
||||
if (type == VDEC_TYPE_FRAME_CIRCULAR) {
|
||||
/*alway used max block.*/
|
||||
input->default_block_size = VFRAME_BLOCK_SIZE_MAX;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_set_type);
|
||||
|
||||
int vdec_input_get_status(struct vdec_input_s *input,
|
||||
struct vdec_input_status_s *status)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (input->vdec == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
flags = vdec_input_lock(input);
|
||||
|
||||
if (list_empty(&input->vframe_block_list)) {
|
||||
status->size = VFRAME_BLOCK_SIZE;
|
||||
status->data_len = 0;
|
||||
status->free_len = VFRAME_BLOCK_SIZE;
|
||||
status->read_pointer = 0;
|
||||
} else {
|
||||
int r = VFRAME_BLOCK_MAX_LEVEL - vdec_input_level(input)
|
||||
- VFRAME_BLOCK_HOLE;
|
||||
status->size = input->size;
|
||||
status->data_len = vdec_input_level(input);
|
||||
status->free_len = (r > 0) ? r : 0;
|
||||
status->read_pointer = input->total_rd_count;
|
||||
}
|
||||
|
||||
vdec_input_unlock(input, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_get_status);
|
||||
|
||||
static void vdec_input_add_block(struct vdec_input_s *input,
|
||||
struct vframe_block_list_s *block)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
flags = vdec_input_lock(input);
|
||||
block->wp = 0;
|
||||
block->id = input->block_id_seq++;
|
||||
list_add_tail(&block->list, &input->vframe_block_list);
|
||||
input->size += block->size;
|
||||
input->block_nums++;
|
||||
input->wr_block = block;
|
||||
vdec_input_unlock(input, flags);
|
||||
}
|
||||
|
||||
static inline void vdec_input_del_block_locked(struct vdec_input_s *input,
|
||||
struct vframe_block_list_s *block)
|
||||
{
|
||||
list_del(&block->list);
|
||||
input->size -= block->size;
|
||||
input->block_nums--;
|
||||
}
|
||||
|
||||
int vdec_input_level(struct vdec_input_s *input)
|
||||
{
|
||||
return input->total_wr_count - input->total_rd_count;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_level);
|
||||
|
||||
static struct vframe_block_list_s *
|
||||
vdec_input_alloc_new_block(struct vdec_input_s *input)
|
||||
{
|
||||
struct vframe_block_list_s *block;
|
||||
block = kzalloc(sizeof(struct vframe_block_list_s),
|
||||
GFP_KERNEL);
|
||||
if (block == NULL) {
|
||||
input->no_mem_err_cnt++;
|
||||
pr_err("vframe_block structure allocation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vframe_block_init_alloc_storage(input,
|
||||
block) != 0) {
|
||||
kfree(block);
|
||||
pr_err("vframe_block storage allocation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&block->list);
|
||||
|
||||
vdec_input_add_block(input, block);
|
||||
|
||||
/*
|
||||
*pr_info("vdec-%d:new block id=%d, total_blocks:%d, size=%d\n",
|
||||
* input->id,
|
||||
* block->id,
|
||||
* input->block_nums,
|
||||
* block->size);
|
||||
*/
|
||||
if (0 && input->size > VFRAME_BLOCK_MAX_LEVEL * 2) {
|
||||
/*
|
||||
used
|
||||
*/
|
||||
pr_info(
|
||||
"input[%d] reach max: size:%d, blocks:%d",
|
||||
input->id,
|
||||
input->size,
|
||||
input->block_nums);
|
||||
pr_info("level:%d, wr:%lld,rd:%lld\n",
|
||||
vdec_input_level(input),
|
||||
input->total_wr_count,
|
||||
input->total_rd_count);
|
||||
vdec_input_dump_blocks(input, NULL, 0);
|
||||
}
|
||||
return block;
|
||||
}
|
||||
static int vdec_input_get_duration_u64(struct vdec_input_s *input)
|
||||
{
|
||||
int duration = (input->last_inpts_u64 - input->last_comsumed_pts_u64);
|
||||
if (input->last_in_nopts_cnt > 0 &&
|
||||
input->last_comsumed_pts_u64 > 0 &&
|
||||
input->last_duration > 0) {
|
||||
duration += (input->last_in_nopts_cnt -
|
||||
input->last_comsumed_no_pts_cnt) *
|
||||
input->last_duration;
|
||||
}
|
||||
if (duration > 1000 * 1000000)/*> 1000S,I think jumped.*/
|
||||
duration = 0;
|
||||
if (duration <= 0 && input->last_duration > 0) {
|
||||
/*..*/
|
||||
duration = input->last_duration * input->have_frame_num;
|
||||
}
|
||||
if (duration < 0)
|
||||
duration = 0;
|
||||
return duration;
|
||||
}
|
||||
/*
|
||||
ret >= 13: have enough buffer, blocked add more buffers
|
||||
*/
|
||||
static int vdec_input_have_blocks_enough(struct vdec_input_s *input)
|
||||
{
|
||||
int ret = 0;
|
||||
if (vdec_input_level(input) > VFRAME_BLOCK_MIN_LEVEL)
|
||||
ret += 1;
|
||||
if (vdec_input_level(input) >= VFRAME_BLOCK_MAX_LEVEL)
|
||||
ret += 2;
|
||||
if (vdec_input_get_duration_u64(input) > MAX_FRAME_DURATION_S)
|
||||
ret += 4;
|
||||
if (input->have_frame_num > 30)
|
||||
ret += 8;
|
||||
else
|
||||
ret -= 8;/*not enough frames.*/
|
||||
if (input->size >= VFRAME_BLOCK_MAX_TOTAL_SIZE)
|
||||
ret += 100;/*always bloced add more buffers.*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
static int vdec_input_get_free_block(
|
||||
struct vdec_input_s *input,
|
||||
int size,/*frame size + pading*/
|
||||
struct vframe_block_list_s **block_ret)
|
||||
{
|
||||
struct vframe_block_list_s *to_freeblock = NULL;
|
||||
struct vframe_block_list_s *block = NULL;
|
||||
unsigned long flags;
|
||||
flags = vdec_input_lock(input);
|
||||
/*get from free list.*/
|
||||
if (!list_empty(&input->vframe_block_free_list)) {
|
||||
block = list_entry(input->vframe_block_free_list.next,
|
||||
struct vframe_block_list_s, list);
|
||||
if (block->size < (size)) {
|
||||
vdec_input_del_block_locked(input, block);
|
||||
to_freeblock = block;
|
||||
block = NULL;
|
||||
} else {
|
||||
list_move_tail(&block->list,
|
||||
&input->vframe_block_list);
|
||||
input->wr_block = block;/*swith to new block*/
|
||||
}
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
if (to_freeblock) {
|
||||
/*free the small block.*/
|
||||
vframe_block_free_block(to_freeblock);
|
||||
}
|
||||
if (block) {
|
||||
*block_ret = block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vdec_input_have_blocks_enough(input) > 13) {
|
||||
/*buf fulled */
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (input->no_mem_err_cnt > 3) {
|
||||
/*alloced failed more times.
|
||||
*/
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (input->default_block_size <=
|
||||
size * 2) {
|
||||
int def_size = input->default_block_size;
|
||||
do {
|
||||
def_size *= 2;
|
||||
} while ((def_size <= 2 * size) &&
|
||||
(def_size <= VFRAME_BLOCK_SIZE_MAX));
|
||||
if (def_size < size)
|
||||
def_size = ALIGN(size + 64, (1 << 17));
|
||||
/*128k aligned,same as codec_mm*/
|
||||
input->default_block_size = def_size;
|
||||
}
|
||||
block = vdec_input_alloc_new_block(input);
|
||||
if (!block) {
|
||||
input->no_mem_err_cnt++;
|
||||
return -EAGAIN;
|
||||
}
|
||||
input->no_mem_err_cnt = 0;
|
||||
*block_ret = block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct vframe_chunk_s *chunk;
|
||||
struct vdec_s *vdec = input->vdec;
|
||||
struct vframe_block_list_s *block;
|
||||
int need_pading_size = MIN_FRAME_PADDING_SIZE;
|
||||
|
||||
#if 0
|
||||
if (add_count == 0) {
|
||||
add_count++;
|
||||
memcpy(sps, buf, 30);
|
||||
return 30;
|
||||
} else if (add_count == 1) {
|
||||
add_count++;
|
||||
memcpy(pps, buf, 8);
|
||||
return 8;
|
||||
}
|
||||
add_count++;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
pr_info("vdec_input_add_frame add %p, count=%d\n", buf, (int)count);
|
||||
|
||||
if (count >= 8) {
|
||||
pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7]);
|
||||
}
|
||||
if (count >= 16) {
|
||||
pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[8], buf[9], buf[10], buf[11],
|
||||
buf[12], buf[13], buf[14], buf[15]);
|
||||
}
|
||||
if (count >= 24) {
|
||||
pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[16], buf[17], buf[18], buf[19],
|
||||
buf[20], buf[21], buf[22], buf[23]);
|
||||
}
|
||||
if (count >= 32) {
|
||||
pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[24], buf[25], buf[26], buf[27],
|
||||
buf[28], buf[29], buf[30], buf[31]);
|
||||
}
|
||||
#endif
|
||||
if (input_stream_based(input))
|
||||
return -EINVAL;
|
||||
if (count < PAGE_SIZE) {
|
||||
need_pading_size = PAGE_ALIGN(count + need_pading_size) -
|
||||
count;
|
||||
} else {
|
||||
/*to 64 bytes aligned;*/
|
||||
if (count & 0x3f)
|
||||
need_pading_size += 64 - (count & 0x3f);
|
||||
}
|
||||
block = input->wr_block;
|
||||
if (block &&
|
||||
(vframe_block_space(block) > (count + need_pading_size))) {
|
||||
/*this block have enough buffers.
|
||||
do nothings.
|
||||
*/
|
||||
} else if (block && (block->type == VDEC_TYPE_FRAME_CIRCULAR)) {
|
||||
/*in circular module.
|
||||
only one block,.*/
|
||||
return -EAGAIN;
|
||||
} else if (block != NULL) {
|
||||
/*have block but not enough space.
|
||||
recycle the no enough blocks.*/
|
||||
flags = vdec_input_lock(input);
|
||||
if (input->wr_block == block &&
|
||||
block->chunk_count == 0) {
|
||||
block->rp = 0;
|
||||
block->wp = 0;
|
||||
/*block no data move to freelist*/
|
||||
list_move_tail(&block->list,
|
||||
&input->vframe_block_free_list);
|
||||
input->wr_block = NULL;
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
block = NULL;
|
||||
}
|
||||
if (!block) {/*try new block.*/
|
||||
int ret = vdec_input_get_free_block(input,
|
||||
count + need_pading_size + EXTRA_PADDING_SIZE,
|
||||
&block);
|
||||
if (ret < 0)/*no enough block now.*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
chunk = kzalloc(sizeof(struct vframe_chunk_s), GFP_KERNEL);
|
||||
|
||||
if (!chunk) {
|
||||
pr_err("vframe_chunk structure allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chunk->magic = 0x4b554843;
|
||||
if (vdec->pts_valid) {
|
||||
chunk->pts = vdec->pts;
|
||||
chunk->pts64 = vdec->pts64;
|
||||
}
|
||||
if (vdec->pts_valid &&
|
||||
input->last_inpts_u64 > 0 &&
|
||||
input->last_in_nopts_cnt == 0) {
|
||||
int d = (int)(chunk->pts64 - input->last_inpts_u64);
|
||||
if (d > 0 && (d < input->last_duration))
|
||||
input->last_duration = d;
|
||||
/* alwasy: used the smallest duration;
|
||||
if 60fps->30 fps.
|
||||
maybe have warning value.
|
||||
*/
|
||||
}
|
||||
chunk->pts_valid = vdec->pts_valid;
|
||||
vdec->pts_valid = false;
|
||||
chunk->offset = block->wp;
|
||||
chunk->size = count;
|
||||
chunk->pading_size = need_pading_size;
|
||||
INIT_LIST_HEAD(&chunk->list);
|
||||
|
||||
if (vframe_chunk_fill(input, chunk, buf, count, block)) {
|
||||
pr_err("vframe_chunk_fill failed\n");
|
||||
kfree(chunk);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
flags = vdec_input_lock(input);
|
||||
|
||||
vframe_block_add_chunk(block, chunk);
|
||||
|
||||
list_add_tail(&chunk->list, &input->vframe_chunk_list);
|
||||
input->data_size += chunk->size;
|
||||
input->have_frame_num++;
|
||||
if (chunk->pts_valid) {
|
||||
input->last_inpts_u64 = chunk->pts64;
|
||||
input->last_in_nopts_cnt = 0;
|
||||
} else {
|
||||
/*nopts*/
|
||||
input->last_in_nopts_cnt++;
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
if (chunk->size > input->frame_max_size)
|
||||
input->frame_max_size = chunk->size;
|
||||
input->total_wr_count += count;
|
||||
|
||||
#if 0
|
||||
if (add_count == 2)
|
||||
input->total_wr_count += 38;
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_add_frame);
|
||||
|
||||
struct vframe_chunk_s *vdec_input_next_chunk(struct vdec_input_s *input)
|
||||
{
|
||||
struct vframe_chunk_s *chunk = NULL;
|
||||
unsigned long flags;
|
||||
flags = vdec_input_lock(input);
|
||||
if (!list_empty(&input->vframe_chunk_list)) {
|
||||
chunk = list_first_entry(&input->vframe_chunk_list,
|
||||
struct vframe_chunk_s, list);
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
return chunk;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_next_chunk);
|
||||
|
||||
struct vframe_chunk_s *vdec_input_next_input_chunk(
|
||||
struct vdec_input_s *input)
|
||||
{
|
||||
struct vframe_chunk_s *chunk = NULL;
|
||||
struct list_head *p;
|
||||
unsigned long flags;
|
||||
flags = vdec_input_lock(input);
|
||||
|
||||
list_for_each(p, &input->vframe_chunk_list) {
|
||||
struct vframe_chunk_s *c = list_entry(
|
||||
p, struct vframe_chunk_s, list);
|
||||
if ((c->flag & VFRAME_CHUNK_FLAG_CONSUMED) == 0) {
|
||||
chunk = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vdec_input_unlock(input, flags);
|
||||
return chunk;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_next_input_chunk);
|
||||
|
||||
void vdec_input_release_chunk(struct vdec_input_s *input,
|
||||
struct vframe_chunk_s *chunk)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct vframe_block_list_s *block = chunk->block;
|
||||
struct vframe_block_list_s *tofreeblock = NULL;
|
||||
flags = vdec_input_lock(input);
|
||||
|
||||
list_del(&chunk->list);
|
||||
input->have_frame_num--;
|
||||
if (chunk->pts_valid) {
|
||||
input->last_comsumed_no_pts_cnt = 0;
|
||||
input->last_comsumed_pts_u64 = chunk->pts64;
|
||||
} else
|
||||
input->last_comsumed_no_pts_cnt++;
|
||||
block->rp += chunk->size;
|
||||
if (block->rp >= block->size)
|
||||
block->rp -= block->size;
|
||||
block->data_size -= chunk->size;
|
||||
block->chunk_count--;
|
||||
input->data_size -= chunk->size;
|
||||
input->total_rd_count += chunk->size;
|
||||
if (block->chunk_count == 0 &&
|
||||
input->wr_block != block) {/*don't free used block*/
|
||||
if (block->size < input->default_block_size) {
|
||||
vdec_input_del_block_locked(input, block);
|
||||
tofreeblock = block;
|
||||
} else {
|
||||
block->rp = 0;
|
||||
block->wp = 0;
|
||||
list_move_tail(&block->list,
|
||||
&input->vframe_block_free_list);
|
||||
}
|
||||
}
|
||||
|
||||
vdec_input_unlock(input, flags);
|
||||
if (tofreeblock)
|
||||
vframe_block_free_block(tofreeblock);
|
||||
kfree(chunk);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_release_chunk);
|
||||
|
||||
unsigned long vdec_input_lock(struct vdec_input_s *input)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&input->lock, flags);
|
||||
|
||||
return flags;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_lock);
|
||||
|
||||
void vdec_input_unlock(struct vdec_input_s *input, unsigned long flags)
|
||||
{
|
||||
spin_unlock_irqrestore(&input->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_unlock);
|
||||
|
||||
void vdec_input_release(struct vdec_input_s *input)
|
||||
{
|
||||
struct list_head *p, *tmp;
|
||||
|
||||
/* release chunk data */
|
||||
list_for_each_safe(p, tmp, &input->vframe_chunk_list) {
|
||||
struct vframe_chunk_s *chunk = list_entry(
|
||||
p, struct vframe_chunk_s, list);
|
||||
vdec_input_release_chunk(input, chunk);
|
||||
}
|
||||
list_for_each_safe(p, tmp, &input->vframe_block_list) {
|
||||
/*should never here.*/
|
||||
list_move_tail(p, &input->vframe_block_free_list);
|
||||
}
|
||||
/* release input blocks */
|
||||
list_for_each_safe(p, tmp, &input->vframe_block_free_list) {
|
||||
struct vframe_block_list_s *block = list_entry(
|
||||
p, struct vframe_block_list_s, list);
|
||||
vdec_input_del_block_locked(input, block);
|
||||
vframe_block_free_block(block);
|
||||
}
|
||||
|
||||
/* release swap pages */
|
||||
if (input->swap_page_phys) {
|
||||
if (vdec_secure(input->vdec))
|
||||
codec_mm_free_for_dma("SWAP", input->swap_page_phys);
|
||||
else
|
||||
__free_page(input->swap_page);
|
||||
input->swap_page = NULL;
|
||||
input->swap_page_phys = 0;
|
||||
}
|
||||
input->swap_valid = false;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_input_release);
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* drivers/amlogic/media/frame_provider/decoder/utils/vdec_input.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VDEC_INPUT_H
|
||||
#define VDEC_INPUT_H
|
||||
|
||||
struct vdec_s;
|
||||
struct vdec_input_s;
|
||||
|
||||
struct vframe_block_list_s {
|
||||
u32 magic;
|
||||
int id;
|
||||
struct list_head list;
|
||||
ulong start;
|
||||
void *start_virt;
|
||||
ulong addr;
|
||||
int type;
|
||||
u32 size;
|
||||
u32 wp;
|
||||
u32 rp;
|
||||
int data_size;
|
||||
int chunk_count;
|
||||
struct vdec_input_s *input;
|
||||
};
|
||||
|
||||
#define VFRAME_CHUNK_FLAG_CONSUMED 0x0001
|
||||
|
||||
struct vframe_chunk_s {
|
||||
u32 magic;
|
||||
struct list_head list;
|
||||
int flag;
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 pts;
|
||||
u32 pading_size;
|
||||
u64 pts64;
|
||||
bool pts_valid;
|
||||
u64 sequence;
|
||||
struct vframe_block_list_s *block;
|
||||
};
|
||||
|
||||
#define VDEC_INPUT_TARGET_VLD 0
|
||||
#define VDEC_INPUT_TARGET_HEVC 1
|
||||
|
||||
struct vdec_input_s {
|
||||
struct list_head vframe_block_list;
|
||||
struct list_head vframe_chunk_list;
|
||||
struct list_head vframe_block_free_list;
|
||||
struct vframe_block_list_s *wr_block;
|
||||
int have_free_blocks;
|
||||
int no_mem_err_cnt;/*when alloc no mem cnt++*/
|
||||
int block_nums;
|
||||
int block_id_seq;
|
||||
int id;
|
||||
spinlock_t lock;
|
||||
int type;
|
||||
int target;
|
||||
struct vdec_s *vdec;
|
||||
bool swap_valid;
|
||||
bool swap_needed;
|
||||
bool eos;
|
||||
struct page *swap_page;
|
||||
unsigned long swap_page_phys;
|
||||
u64 total_wr_count;
|
||||
u64 total_rd_count;
|
||||
u64 streaming_rp;
|
||||
u32 swap_rp;
|
||||
bool last_swap_slave;
|
||||
int dirty_count;
|
||||
u64 sequence;
|
||||
unsigned start;
|
||||
unsigned size;
|
||||
int default_block_size;
|
||||
int data_size;
|
||||
int frame_max_size;
|
||||
int prepare_level;
|
||||
/*for check frame delay.*/
|
||||
u64 last_inpts_u64;
|
||||
u64 last_comsumed_pts_u64;
|
||||
int last_in_nopts_cnt;
|
||||
int last_comsumed_no_pts_cnt;
|
||||
int last_duration;
|
||||
/*for check frame delay.*/
|
||||
int have_frame_num;
|
||||
int stream_cookie; /* wrap count for vld_mem and
|
||||
HEVC_SHIFT_BYTE_COUNT for hevc */
|
||||
};
|
||||
|
||||
struct vdec_input_status_s {
|
||||
int size;
|
||||
int data_len;
|
||||
int free_len;
|
||||
int read_pointer;
|
||||
};
|
||||
|
||||
#define input_frame_based(input) \
|
||||
(((input)->type == VDEC_TYPE_FRAME_BLOCK) || \
|
||||
((input)->type == VDEC_TYPE_FRAME_CIRCULAR))
|
||||
#define input_stream_based(input) \
|
||||
(((input)->type == VDEC_TYPE_STREAM_PARSER) || \
|
||||
((input)->type == VDEC_TYPE_SINGLE))
|
||||
|
||||
/* Initialize vdec_input structure */
|
||||
extern void vdec_input_init(struct vdec_input_s *input, struct vdec_s *vdec);
|
||||
extern int vdec_input_prepare_bufs(struct vdec_input_s *input,
|
||||
int frame_width, int frame_height);
|
||||
|
||||
/* Get available input data size */
|
||||
extern int vdec_input_level(struct vdec_input_s *input);
|
||||
|
||||
/* Set input type and target */
|
||||
extern void vdec_input_set_type(struct vdec_input_s *input, int type,
|
||||
int target);
|
||||
|
||||
/* Set stream buffer information for stream based input */
|
||||
extern int vdec_input_set_buffer(struct vdec_input_s *input, u32 start,
|
||||
u32 size);
|
||||
|
||||
/* Add enqueue video data into decoder's input */
|
||||
extern int vdec_input_add_frame(struct vdec_input_s *input, const char *buf,
|
||||
size_t count);
|
||||
|
||||
/* Peek next frame data from decoder's input */
|
||||
extern struct vframe_chunk_s *vdec_input_next_chunk(
|
||||
struct vdec_input_s *input);
|
||||
|
||||
/* Peek next frame data from decoder's input, not marked as consumed */
|
||||
extern struct vframe_chunk_s *vdec_input_next_input_chunk(
|
||||
struct vdec_input_s *input);
|
||||
|
||||
/* Consume next frame data from decoder's input */
|
||||
extern void vdec_input_release_chunk(struct vdec_input_s *input,
|
||||
struct vframe_chunk_s *chunk);
|
||||
|
||||
/* Get decoder input buffer status */
|
||||
extern int vdec_input_get_status(struct vdec_input_s *input,
|
||||
struct vdec_input_status_s *status);
|
||||
|
||||
extern unsigned long vdec_input_lock(struct vdec_input_s *input);
|
||||
|
||||
extern void vdec_input_unlock(struct vdec_input_s *input, unsigned long lock);
|
||||
|
||||
/* release all resource for decoder's input */
|
||||
extern void vdec_input_release(struct vdec_input_s *input);
|
||||
int vdec_input_dump_chunks(struct vdec_input_s *input,
|
||||
char *bufs, int size);
|
||||
int vdec_input_dump_blocks(struct vdec_input_s *input,
|
||||
char *bufs, int size);
|
||||
|
||||
#endif /* VDEC_INPUT_H */
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vdec_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/mutex.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <linux/amlogic/media/utils/vdec_reg.h>
|
||||
#include "vdec_profile.h"
|
||||
#include "vdec.h"
|
||||
|
||||
#define ISA_TIMERE 0x2662
|
||||
#define ISA_TIMERE_HI 0x2663
|
||||
|
||||
#define PROFILE_REC_SIZE 40
|
||||
|
||||
static DEFINE_MUTEX(vdec_profile_mutex);
|
||||
static int rec_wp;
|
||||
static bool rec_wrapped;
|
||||
|
||||
struct dentry *root, *event;
|
||||
|
||||
struct vdec_profile_rec_s {
|
||||
struct vdec_s *vdec;
|
||||
u64 timestamp;
|
||||
int event;
|
||||
int para1;
|
||||
int para2;
|
||||
};
|
||||
|
||||
static struct vdec_profile_rec_s recs[PROFILE_REC_SIZE];
|
||||
static const char *event_name[VDEC_PROFILE_MAX_EVENT] = {
|
||||
"run",
|
||||
"cb",
|
||||
"save_input",
|
||||
"check run ready",
|
||||
"run ready",
|
||||
"disconnect",
|
||||
"dec_work",
|
||||
"info"
|
||||
};
|
||||
|
||||
#if 0 /* get time from hardware. */
|
||||
static u64 get_us_time_hw(void)
|
||||
{
|
||||
u32 lo, hi1, hi2;
|
||||
int offset = 0;
|
||||
|
||||
/* txlx, g12a isa register base is 0x3c00 */
|
||||
if (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXLX)
|
||||
offset = 0x1600;
|
||||
|
||||
do {
|
||||
hi1 = READ_MPEG_REG(ISA_TIMERE_HI + offset);
|
||||
lo = READ_MPEG_REG(ISA_TIMERE + offset);
|
||||
hi2 = READ_MPEG_REG(ISA_TIMERE_HI + offset);
|
||||
} while (hi1 != hi2);
|
||||
|
||||
return (((u64)hi1) << 32) | lo;
|
||||
}
|
||||
#endif
|
||||
|
||||
static u64 get_us_time_system(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
|
||||
return div64_u64(timeval_to_ns(&tv), 1000);
|
||||
}
|
||||
|
||||
void vdec_profile_more(struct vdec_s *vdec, int event, int para1, int para2)
|
||||
{
|
||||
mutex_lock(&vdec_profile_mutex);
|
||||
|
||||
recs[rec_wp].vdec = vdec;
|
||||
recs[rec_wp].timestamp = get_us_time_system();
|
||||
recs[rec_wp].event = event;
|
||||
recs[rec_wp].para1 = para1;
|
||||
recs[rec_wp].para2 = para2;
|
||||
|
||||
rec_wp++;
|
||||
if (rec_wp == PROFILE_REC_SIZE) {
|
||||
rec_wrapped = true;
|
||||
rec_wp = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&vdec_profile_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_profile_more);
|
||||
|
||||
void vdec_profile(struct vdec_s *vdec, int event)
|
||||
{
|
||||
vdec_profile_more(vdec, event, 0 , 0);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_profile);
|
||||
|
||||
void vdec_profile_flush(struct vdec_s *vdec)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&vdec_profile_mutex);
|
||||
|
||||
for (i = 0; i < PROFILE_REC_SIZE; i++) {
|
||||
if (recs[i].vdec == vdec)
|
||||
recs[i].vdec = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&vdec_profile_mutex);
|
||||
}
|
||||
|
||||
static const char *event_str(int event)
|
||||
{
|
||||
if (event < VDEC_PROFILE_MAX_EVENT)
|
||||
return event_name[event];
|
||||
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static int vdec_profile_dbg_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i, end;
|
||||
u64 base_timestamp;
|
||||
|
||||
mutex_lock(&vdec_profile_mutex);
|
||||
|
||||
if (rec_wrapped) {
|
||||
i = rec_wp;
|
||||
end = rec_wp;
|
||||
} else {
|
||||
i = 0;
|
||||
end = rec_wp;
|
||||
}
|
||||
|
||||
base_timestamp = recs[i].timestamp;
|
||||
while (1) {
|
||||
if ((!rec_wrapped) && (i == end))
|
||||
break;
|
||||
|
||||
if (recs[i].vdec) {
|
||||
seq_printf(m, "[%s:%d] \t%016llu us : %s (%d,%d)\n",
|
||||
vdec_device_name_str(recs[i].vdec),
|
||||
recs[i].vdec->id,
|
||||
recs[i].timestamp - base_timestamp,
|
||||
event_str(recs[i].event),
|
||||
recs[i].para1,
|
||||
recs[i].para2
|
||||
);
|
||||
} else {
|
||||
seq_printf(m, "[%s:%d] \t%016llu us : %s (%d,%d)\n",
|
||||
"N/A",
|
||||
0,
|
||||
recs[i].timestamp - base_timestamp,
|
||||
event_str(recs[i].event),
|
||||
recs[i].para1,
|
||||
recs[i].para2
|
||||
);
|
||||
}
|
||||
if (++i == PROFILE_REC_SIZE)
|
||||
i = 0;
|
||||
|
||||
if (rec_wrapped && (i == end))
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&vdec_profile_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdec_profile_dbg_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, vdec_profile_dbg_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations event_dbg_fops = {
|
||||
.open = vdec_profile_dbg_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
#if 0 /*DEBUG_TMP*/
|
||||
static int __init vdec_profile_init_debugfs(void)
|
||||
{
|
||||
struct dentry *root, *event;
|
||||
|
||||
root = debugfs_create_dir("vdec_profile", NULL);
|
||||
if (IS_ERR(root) || !root)
|
||||
goto err;
|
||||
|
||||
event = debugfs_create_file("event", 0400, root, NULL,
|
||||
&event_dbg_fops);
|
||||
if (!event)
|
||||
goto err_1;
|
||||
|
||||
mutex_init(&vdec_profile_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_1:
|
||||
debugfs_remove(root);
|
||||
err:
|
||||
pr_err("Can not create debugfs for vdec_profile\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int vdec_profile_init_debugfs(void)
|
||||
{
|
||||
struct dentry *root, *event;
|
||||
|
||||
root = debugfs_create_dir("vdec_profile", NULL);
|
||||
if (IS_ERR(root) || !root)
|
||||
goto err;
|
||||
|
||||
event = debugfs_create_file("event", 0400, root, NULL,
|
||||
&event_dbg_fops);
|
||||
if (!event)
|
||||
goto err_1;
|
||||
|
||||
mutex_init(&vdec_profile_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_1:
|
||||
debugfs_remove(root);
|
||||
err:
|
||||
pr_err("Can not create debugfs for vdec_profile\n");
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_profile_init_debugfs);
|
||||
|
||||
void vdec_profile_exit_debugfs(void)
|
||||
{
|
||||
debugfs_remove(event);
|
||||
debugfs_remove(root);
|
||||
}
|
||||
EXPORT_SYMBOL(vdec_profile_exit_debugfs);
|
||||
|
||||
/*module_init(vdec_profile_init_debugfs);*/
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vdec_profile.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VDEC_PROFILE_H
|
||||
#define VDEC_PROFILE_H
|
||||
|
||||
struct vdec_s;
|
||||
|
||||
#define VDEC_PROFILE_EVENT_RUN 0
|
||||
#define VDEC_PROFILE_EVENT_CB 1
|
||||
#define VDEC_PROFILE_EVENT_SAVE_INPUT 2
|
||||
#define VDEC_PROFILE_EVENT_CHK_RUN_READY 3
|
||||
#define VDEC_PROFILE_EVENT_RUN_READY 4
|
||||
#define VDEC_PROFILE_EVENT_DISCONNECT 5
|
||||
#define VDEC_PROFILE_EVENT_DEC_WORK 6
|
||||
#define VDEC_PROFILE_EVENT_INFO 7
|
||||
#define VDEC_PROFILE_MAX_EVENT 8
|
||||
|
||||
extern void vdec_profile(struct vdec_s *vdec, int event);
|
||||
extern void vdec_profile_more(struct vdec_s *vdec, int event, int para1, int para2);
|
||||
extern void vdec_profile_flush(struct vdec_s *vdec);
|
||||
|
||||
int vdec_profile_init_debugfs(void);
|
||||
void vdec_profile_exit_debugfs(void);
|
||||
|
||||
#endif /* VDEC_PROFILE_H */
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vdec_trace.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM vdec
|
||||
|
||||
#if !defined(_VDEC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _VDEC_TRACE_H
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
struct vdec_s;
|
||||
|
||||
/* single lifecycle events */
|
||||
DECLARE_EVENT_CLASS(vdec_event_class,
|
||||
TP_PROTO(struct vdec_s *vdec),
|
||||
TP_ARGS(vdec),
|
||||
TP_STRUCT__entry(
|
||||
__field(struct vdec_s *, vdec)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->vdec = vdec;
|
||||
),
|
||||
TP_printk("[%p]", __entry->vdec)
|
||||
);
|
||||
|
||||
#define DEFINE_VDEC_EVENT(name) \
|
||||
DEFINE_EVENT(vdec_event_class, name, \
|
||||
TP_PROTO(struct vdec_s *vdec), \
|
||||
TP_ARGS(vdec))
|
||||
|
||||
DEFINE_VDEC_EVENT(vdec_create);
|
||||
DEFINE_VDEC_EVENT(vdec_connect);
|
||||
DEFINE_VDEC_EVENT(vdec_disconnect);
|
||||
DEFINE_VDEC_EVENT(vdec_destroy);
|
||||
DEFINE_VDEC_EVENT(vdec_reset);
|
||||
DEFINE_VDEC_EVENT(vdec_release);
|
||||
|
||||
/* set format event */
|
||||
#define format_name(format) \
|
||||
__print_symbolic(format, \
|
||||
{0, "MPEG"}, \
|
||||
{1, "MPEG4"}, \
|
||||
{2, "H264"}, \
|
||||
{3, "MJPEG"}, \
|
||||
{4, "REAL"}, \
|
||||
{5, "JPEG"}, \
|
||||
{6, "VC1"}, \
|
||||
{7, "AVS"}, \
|
||||
{8, "YUV"}, \
|
||||
{9, "H264MVC"}, \
|
||||
{10, "H264_4K2K"}, \
|
||||
{11, "H265"}, \
|
||||
{12, "ENC_AVC"}, \
|
||||
{13, "ENC_JPEG"}, \
|
||||
{14, "VP9"})
|
||||
|
||||
TRACE_EVENT(vdec_set_format,
|
||||
TP_PROTO(struct vdec_s *vdec, int format),
|
||||
TP_ARGS(vdec, format),
|
||||
TP_STRUCT__entry(
|
||||
__field(struct vdec_s *, vdec)
|
||||
__field(int, format)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->vdec = vdec;
|
||||
__entry->format = format;
|
||||
),
|
||||
TP_printk("[%p]:%s", __entry->vdec,
|
||||
format_name(__entry->format))
|
||||
);
|
||||
|
||||
/* status events */
|
||||
#define status_name(status) \
|
||||
__print_symbolic(status, \
|
||||
{0, "UNINITIALIZED"}, \
|
||||
{1, "DISCONNECTED"}, \
|
||||
{2, "CONNECTED"}, \
|
||||
{3, "ACTIVE"})
|
||||
|
||||
DECLARE_EVENT_CLASS(vdec_status_class,
|
||||
TP_PROTO(struct vdec_s *vdec, int state),
|
||||
TP_ARGS(vdec, state),
|
||||
TP_STRUCT__entry(
|
||||
__field(struct vdec_s *, vdec)
|
||||
__field(int, state)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->vdec = vdec;
|
||||
__entry->state = state;
|
||||
),
|
||||
TP_printk("[%p]:%s", __entry->vdec, status_name(__entry->state))
|
||||
);
|
||||
|
||||
#define DEFINE_STATUS_EVENT(name) \
|
||||
DEFINE_EVENT(vdec_status_class, name, \
|
||||
TP_PROTO(struct vdec_s *vdec, int status), \
|
||||
TP_ARGS(vdec, status))
|
||||
|
||||
DEFINE_STATUS_EVENT(vdec_set_status);
|
||||
DEFINE_STATUS_EVENT(vdec_set_next_status);
|
||||
|
||||
/* set pts events */
|
||||
DECLARE_EVENT_CLASS(vdec_pts_class,
|
||||
TP_PROTO(struct vdec_s *vdec, u64 pts),
|
||||
TP_ARGS(vdec, pts),
|
||||
TP_STRUCT__entry(
|
||||
__field(struct vdec_s *, vdec)
|
||||
__field(u64, pts)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->vdec = vdec;
|
||||
__entry->pts = pts;
|
||||
),
|
||||
TP_printk("[%p]%llu", __entry->vdec, __entry->pts)
|
||||
);
|
||||
|
||||
#define DEFINE_PTS_EVENT(name) \
|
||||
DEFINE_EVENT(vdec_pts_class, name, \
|
||||
TP_PROTO(struct vdec_s *vdec, u64 pts), \
|
||||
TP_ARGS(vdec, pts))
|
||||
|
||||
DEFINE_PTS_EVENT(vdec_set_pts);
|
||||
DEFINE_PTS_EVENT(vdec_set_pts64);
|
||||
|
||||
#endif /* _VDEC_TRACE_H */
|
||||
|
||||
/*
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#define TRACE_INCLUDE_FILE vdec_trace
|
||||
#include <trace/define_trace.h>
|
||||
*/
|
||||
/**/ //DEBUG_TMP
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_VC1) += amvdec_vc1.o
|
||||
amvdec_vc1-objs += vvc1.o
|
||||
1255
drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c
Normal file
1255
drivers/amlogic/media_modules/frame_provider/decoder/vc1/vvc1.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VDEC_VP9) += amvdec_vp9.o
|
||||
amvdec_vp9-objs += vvp9.o
|
||||
9755
drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c
Normal file
9755
drivers/amlogic/media_modules/frame_provider/decoder/vp9/vvp9.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/vvp9.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VVP9_H
|
||||
#define VVP9_H
|
||||
#define VP9_10B_MMU
|
||||
void adapt_coef_probs(int pic_count, int prev_kf, int cur_kf, int pre_fc,
|
||||
unsigned int *prev_prob, unsigned int *cur_prob, unsigned int *count);
|
||||
#endif
|
||||
1
drivers/amlogic/media_modules/frame_sink/Makefile
Normal file
1
drivers/amlogic/media_modules/frame_sink/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-y += encoder/
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H264) += h264/
|
||||
obj-$(CONFIG_AMLOGIC_MEDIA_VENC_H265) += h265/
|
||||
@@ -0,0 +1 @@
|
||||
obj-m += encoder.o
|
||||
4275
drivers/amlogic/media_modules/frame_sink/encoder/h264/encoder.c
Normal file
4275
drivers/amlogic/media_modules/frame_sink/encoder/h264/encoder.c
Normal file
File diff suppressed because it is too large
Load Diff
468
drivers/amlogic/media_modules/frame_sink/encoder/h264/encoder.h
Normal file
468
drivers/amlogic/media_modules/frame_sink/encoder/h264/encoder.h
Normal file
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* drivers/amlogic/amports/encoder.h
|
||||
*
|
||||
* Copyright (C) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __H264_H__
|
||||
#define __H264_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
|
||||
#include <linux/amlogic/media/ge2d/ge2d.h>
|
||||
#endif
|
||||
|
||||
#define AMVENC_DEVINFO_M8 "AML-M8"
|
||||
#define AMVENC_DEVINFO_G9 "AML-G9"
|
||||
#define AMVENC_DEVINFO_GXBB "AML-GXBB"
|
||||
#define AMVENC_DEVINFO_GXTVBB "AML-GXTVBB"
|
||||
#define AMVENC_DEVINFO_GXL "AML-GXL"
|
||||
|
||||
#define HCODEC_IRQ_MBOX_CLR HCODEC_ASSIST_MBOX2_CLR_REG
|
||||
#define HCODEC_IRQ_MBOX_MASK HCODEC_ASSIST_MBOX2_MASK
|
||||
|
||||
/* M8: 2550/10 = 255M GX: 2000/10 = 200M */
|
||||
#define HDEC_L0() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(2 << 25) | (1 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
/* M8: 2550/8 = 319M GX: 2000/8 = 250M */
|
||||
#define HDEC_L1() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(0 << 25) | (1 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
/* M8: 2550/7 = 364M GX: 2000/7 = 285M */
|
||||
#define HDEC_L2() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(3 << 25) | (0 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
/* M8: 2550/6 = 425M GX: 2000/6 = 333M */
|
||||
#define HDEC_L3() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(1 << 25) | (1 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
/* M8: 2550/5 = 510M GX: 2000/5 = 400M */
|
||||
#define HDEC_L4() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(2 << 25) | (0 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
/* M8: 2550/4 = 638M GX: 2000/4 = 500M */
|
||||
#define HDEC_L5() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(0 << 25) | (0 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
/* M8: 2550/3 = 850M GX: 2000/3 = 667M */
|
||||
#define HDEC_L6() WRITE_HHI_REG(HHI_VDEC_CLK_CNTL, \
|
||||
(1 << 25) | (0 << 16) | (1 << 24) | \
|
||||
(0xffff & READ_HHI_REG(HHI_VDEC_CLK_CNTL)))
|
||||
|
||||
#define hvdec_clock_enable(level) \
|
||||
do { \
|
||||
if (level == 0) \
|
||||
HDEC_L0(); \
|
||||
else if (level == 1) \
|
||||
HDEC_L1(); \
|
||||
else if (level == 2) \
|
||||
HDEC_L2(); \
|
||||
else if (level == 3) \
|
||||
HDEC_L3(); \
|
||||
else if (level == 4) \
|
||||
HDEC_L4(); \
|
||||
else if (level == 5) \
|
||||
HDEC_L5(); \
|
||||
else if (level == 6) \
|
||||
HDEC_L6(); \
|
||||
WRITE_VREG_BITS(DOS_GCLK_EN0, 0x7fff, 12, 15); \
|
||||
} while (0)
|
||||
|
||||
#define hvdec_clock_disable() \
|
||||
do { \
|
||||
WRITE_VREG_BITS(DOS_GCLK_EN0, 0, 12, 15); \
|
||||
WRITE_HHI_REG_BITS(HHI_VDEC_CLK_CNTL, 0, 24, 1); \
|
||||
} while (0)
|
||||
|
||||
#define LOG_ALL 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_DEBUG 2
|
||||
#define LOG_ERROR 3
|
||||
|
||||
#define enc_pr(level, x...) \
|
||||
do { \
|
||||
if (level >= encode_print_level) \
|
||||
printk(x); \
|
||||
} while (0)
|
||||
|
||||
#define AMVENC_AVC_IOC_MAGIC 'E'
|
||||
|
||||
#define AMVENC_AVC_IOC_GET_DEVINFO _IOW(AMVENC_AVC_IOC_MAGIC, 0xf0, u32)
|
||||
#define AMVENC_AVC_IOC_MAX_INSTANCE _IOW(AMVENC_AVC_IOC_MAGIC, 0xf1, u32)
|
||||
|
||||
#define AMVENC_AVC_IOC_GET_ADDR _IOW(AMVENC_AVC_IOC_MAGIC, 0x00, u32)
|
||||
#define AMVENC_AVC_IOC_INPUT_UPDATE _IOW(AMVENC_AVC_IOC_MAGIC, 0x01, u32)
|
||||
#define AMVENC_AVC_IOC_NEW_CMD _IOW(AMVENC_AVC_IOC_MAGIC, 0x02, u32)
|
||||
#define AMVENC_AVC_IOC_GET_STAGE _IOW(AMVENC_AVC_IOC_MAGIC, 0x03, u32)
|
||||
#define AMVENC_AVC_IOC_GET_OUTPUT_SIZE _IOW(AMVENC_AVC_IOC_MAGIC, 0x04, u32)
|
||||
#define AMVENC_AVC_IOC_CONFIG_INIT _IOW(AMVENC_AVC_IOC_MAGIC, 0x05, u32)
|
||||
#define AMVENC_AVC_IOC_FLUSH_CACHE _IOW(AMVENC_AVC_IOC_MAGIC, 0x06, u32)
|
||||
#define AMVENC_AVC_IOC_FLUSH_DMA _IOW(AMVENC_AVC_IOC_MAGIC, 0x07, u32)
|
||||
#define AMVENC_AVC_IOC_GET_BUFFINFO _IOW(AMVENC_AVC_IOC_MAGIC, 0x08, u32)
|
||||
#define AMVENC_AVC_IOC_SUBMIT _IOW(AMVENC_AVC_IOC_MAGIC, 0x09, u32)
|
||||
#define AMVENC_AVC_IOC_READ_CANVAS _IOW(AMVENC_AVC_IOC_MAGIC, 0x0a, u32)
|
||||
|
||||
|
||||
#define IE_PIPPELINE_BLOCK_SHIFT 0
|
||||
#define IE_PIPPELINE_BLOCK_MASK 0x1f
|
||||
#define ME_PIXEL_MODE_SHIFT 5
|
||||
#define ME_PIXEL_MODE_MASK 0x3
|
||||
|
||||
enum amvenc_mem_type_e {
|
||||
LOCAL_BUFF = 0,
|
||||
CANVAS_BUFF,
|
||||
PHYSICAL_BUFF,
|
||||
MAX_BUFF_TYPE
|
||||
};
|
||||
|
||||
enum amvenc_frame_fmt_e {
|
||||
FMT_YUV422_SINGLE = 0,
|
||||
FMT_YUV444_SINGLE,
|
||||
FMT_NV21,
|
||||
FMT_NV12,
|
||||
FMT_YUV420,
|
||||
FMT_YUV444_PLANE,
|
||||
FMT_RGB888,
|
||||
FMT_RGB888_PLANE,
|
||||
FMT_RGB565,
|
||||
FMT_RGBA8888,
|
||||
FMT_YUV422_12BIT,
|
||||
FMT_YUV444_10BIT,
|
||||
FMT_YUV422_10BIT,
|
||||
MAX_FRAME_FMT
|
||||
};
|
||||
|
||||
#define MAX_ENCODE_REQUEST 8 /* 64 */
|
||||
|
||||
#define MAX_ENCODE_INSTANCE 8 /* 64 */
|
||||
|
||||
#define ENCODE_PROCESS_QUEUE_START 0
|
||||
#define ENCODE_PROCESS_QUEUE_STOP 1
|
||||
|
||||
#define AMVENC_FLUSH_FLAG_INPUT 0x1
|
||||
#define AMVENC_FLUSH_FLAG_OUTPUT 0x2
|
||||
#define AMVENC_FLUSH_FLAG_REFERENCE 0x4
|
||||
#define AMVENC_FLUSH_FLAG_INTRA_INFO 0x8
|
||||
#define AMVENC_FLUSH_FLAG_INTER_INFO 0x10
|
||||
#define AMVENC_FLUSH_FLAG_QP 0x20
|
||||
#define AMVENC_FLUSH_FLAG_DUMP 0x40
|
||||
#define AMVENC_FLUSH_FLAG_CBR 0x80
|
||||
|
||||
#define ENCODER_BUFFER_INPUT 0
|
||||
#define ENCODER_BUFFER_REF0 1
|
||||
#define ENCODER_BUFFER_REF1 2
|
||||
#define ENCODER_BUFFER_OUTPUT 3
|
||||
#define ENCODER_BUFFER_INTER_INFO 4
|
||||
#define ENCODER_BUFFER_INTRA_INFO 5
|
||||
#define ENCODER_BUFFER_QP 6
|
||||
#define ENCODER_BUFFER_DUMP 7
|
||||
#define ENCODER_BUFFER_CBR 8
|
||||
|
||||
struct encode_wq_s;
|
||||
|
||||
struct encode_request_s {
|
||||
u32 quant;
|
||||
u32 cmd;
|
||||
u32 ucode_mode;
|
||||
|
||||
u32 src;
|
||||
|
||||
u32 framesize;
|
||||
|
||||
u32 me_weight;
|
||||
u32 i4_weight;
|
||||
u32 i16_weight;
|
||||
|
||||
u32 crop_top;
|
||||
u32 crop_bottom;
|
||||
u32 crop_left;
|
||||
u32 crop_right;
|
||||
u32 src_w;
|
||||
u32 src_h;
|
||||
u32 scale_enable;
|
||||
|
||||
u32 nr_mode;
|
||||
u32 flush_flag;
|
||||
u32 timeout;
|
||||
enum amvenc_mem_type_e type;
|
||||
enum amvenc_frame_fmt_e fmt;
|
||||
struct encode_wq_s *parent;
|
||||
};
|
||||
|
||||
struct encode_queue_item_s {
|
||||
struct list_head list;
|
||||
struct encode_request_s request;
|
||||
};
|
||||
|
||||
struct Buff_s {
|
||||
u32 buf_start;
|
||||
u32 buf_size;
|
||||
bool used;
|
||||
};
|
||||
|
||||
struct BuffInfo_s {
|
||||
u32 lev_id;
|
||||
u32 min_buffsize;
|
||||
u32 max_width;
|
||||
u32 max_height;
|
||||
struct Buff_s dct;
|
||||
struct Buff_s dec0_y;
|
||||
struct Buff_s dec0_uv;
|
||||
struct Buff_s dec1_y;
|
||||
struct Buff_s dec1_uv;
|
||||
struct Buff_s assit;
|
||||
struct Buff_s bitstream;
|
||||
struct Buff_s scale_buff;
|
||||
struct Buff_s dump_info;
|
||||
struct Buff_s cbr_info;
|
||||
};
|
||||
|
||||
struct encode_meminfo_s {
|
||||
u32 buf_start;
|
||||
u32 buf_size;
|
||||
|
||||
u32 BitstreamStart;
|
||||
u32 BitstreamEnd;
|
||||
|
||||
/*input buffer define*/
|
||||
u32 dct_buff_start_addr;
|
||||
u32 dct_buff_end_addr;
|
||||
|
||||
/*microcode assitant buffer*/
|
||||
u32 assit_buffer_offset;
|
||||
|
||||
u32 scaler_buff_start_addr;
|
||||
|
||||
u32 dump_info_ddr_start_addr;
|
||||
u32 dump_info_ddr_size;
|
||||
|
||||
u32 cbr_info_ddr_start_addr;
|
||||
u32 cbr_info_ddr_size;
|
||||
|
||||
s32 dblk_buf_canvas;
|
||||
s32 ref_buf_canvas;
|
||||
struct BuffInfo_s bufspec;
|
||||
#ifdef CONFIG_CMA
|
||||
struct page *venc_pages;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct encode_picinfo_s {
|
||||
u32 encoder_width;
|
||||
u32 encoder_height;
|
||||
|
||||
u32 rows_per_slice;
|
||||
|
||||
u32 idr_pic_id; /* need reset as 0 for IDR */
|
||||
u32 frame_number; /* need plus each frame */
|
||||
/* need reset as 0 for IDR and plus 2 for NON-IDR */
|
||||
u32 pic_order_cnt_lsb;
|
||||
|
||||
u32 log2_max_pic_order_cnt_lsb;
|
||||
u32 log2_max_frame_num;
|
||||
u32 init_qppicture;
|
||||
};
|
||||
|
||||
struct encode_cbr_s {
|
||||
u16 block_w;
|
||||
u16 block_h;
|
||||
u16 long_th;
|
||||
u8 start_tbl_id;
|
||||
u8 short_shift;
|
||||
u8 long_mb_num;
|
||||
};
|
||||
|
||||
struct encode_wq_s {
|
||||
struct list_head list;
|
||||
|
||||
/* dev info */
|
||||
u32 ucode_index;
|
||||
u32 hw_status;
|
||||
u32 output_size;
|
||||
|
||||
u32 sps_size;
|
||||
u32 pps_size;
|
||||
|
||||
u32 me_weight;
|
||||
u32 i4_weight;
|
||||
u32 i16_weight;
|
||||
|
||||
u32 quant_tbl_i4[8];
|
||||
u32 quant_tbl_i16[8];
|
||||
u32 quant_tbl_me[8];
|
||||
|
||||
struct encode_meminfo_s mem;
|
||||
struct encode_picinfo_s pic;
|
||||
struct encode_request_s request;
|
||||
struct encode_cbr_s cbr_info;
|
||||
atomic_t request_ready;
|
||||
wait_queue_head_t request_complete;
|
||||
};
|
||||
|
||||
struct encode_event_s {
|
||||
wait_queue_head_t hw_complete;
|
||||
struct completion process_complete;
|
||||
spinlock_t sem_lock; /* for queue switch and create destroy queue. */
|
||||
struct completion request_in_com;
|
||||
};
|
||||
|
||||
struct encode_manager_s {
|
||||
struct list_head wq;
|
||||
struct list_head process_queue;
|
||||
struct list_head free_queue;
|
||||
|
||||
u32 encode_hw_status;
|
||||
u32 process_queue_state;
|
||||
s32 irq_num;
|
||||
u32 wq_count;
|
||||
u32 ucode_index;
|
||||
u32 max_instance;
|
||||
#ifdef CONFIG_AMLOGIC_MEDIA_GE2D
|
||||
struct ge2d_context_s *context;
|
||||
#endif
|
||||
bool irq_requested;
|
||||
bool need_reset;
|
||||
bool process_irq;
|
||||
bool inited; /* power on encode */
|
||||
bool remove_flag; /* remove wq; */
|
||||
bool uninit_flag; /* power off encode */
|
||||
bool use_reserve;
|
||||
|
||||
#ifdef CONFIG_CMA
|
||||
bool check_cma;
|
||||
ulong cma_pool_size;
|
||||
#endif
|
||||
struct platform_device *this_pdev;
|
||||
struct Buff_s *reserve_buff;
|
||||
struct encode_wq_s *current_wq;
|
||||
struct encode_wq_s *last_wq;
|
||||
struct encode_queue_item_s *current_item;
|
||||
struct task_struct *encode_thread;
|
||||
struct Buff_s reserve_mem;
|
||||
struct encode_event_s event;
|
||||
struct tasklet_struct encode_tasklet;
|
||||
};
|
||||
|
||||
extern s32 encode_wq_add_request(struct encode_wq_s *wq);
|
||||
extern struct encode_wq_s *create_encode_work_queue(void);
|
||||
extern s32 destroy_encode_work_queue(struct encode_wq_s *encode_work_queue);
|
||||
|
||||
/********************************************
|
||||
* AV Scratch Register Re-Define
|
||||
****************************************** *
|
||||
*/
|
||||
#define ENCODER_STATUS HCODEC_HENC_SCRATCH_0
|
||||
#define MEM_OFFSET_REG HCODEC_HENC_SCRATCH_1
|
||||
#define DEBUG_REG HCODEC_HENC_SCRATCH_2
|
||||
#define IDR_PIC_ID HCODEC_HENC_SCRATCH_5
|
||||
#define FRAME_NUMBER HCODEC_HENC_SCRATCH_6
|
||||
#define PIC_ORDER_CNT_LSB HCODEC_HENC_SCRATCH_7
|
||||
#define LOG2_MAX_PIC_ORDER_CNT_LSB HCODEC_HENC_SCRATCH_8
|
||||
#define LOG2_MAX_FRAME_NUM HCODEC_HENC_SCRATCH_9
|
||||
#define ANC0_BUFFER_ID HCODEC_HENC_SCRATCH_A
|
||||
#define QPPICTURE HCODEC_HENC_SCRATCH_B
|
||||
|
||||
#define IE_ME_MB_TYPE HCODEC_HENC_SCRATCH_D
|
||||
|
||||
/* bit 0-4, IE_PIPPELINE_BLOCK
|
||||
* bit 5 me half pixel in m8
|
||||
* disable i4x4 in gxbb
|
||||
* bit 6 me step2 sub pixel in m8
|
||||
* disable i16x16 in gxbb
|
||||
*/
|
||||
#define IE_ME_MODE HCODEC_HENC_SCRATCH_E
|
||||
#define IE_REF_SEL HCODEC_HENC_SCRATCH_F
|
||||
|
||||
/* [31:0] NUM_ROWS_PER_SLICE_P */
|
||||
/* [15:0] NUM_ROWS_PER_SLICE_I */
|
||||
#define FIXED_SLICE_CFG HCODEC_HENC_SCRATCH_L
|
||||
|
||||
/* For GX */
|
||||
#define INFO_DUMP_START_ADDR HCODEC_HENC_SCRATCH_I
|
||||
|
||||
/* For CBR */
|
||||
#define H264_ENC_CBR_TABLE_ADDR HCODEC_HENC_SCRATCH_3
|
||||
#define H264_ENC_CBR_MB_SIZE_ADDR HCODEC_HENC_SCRATCH_4
|
||||
/* Bytes(Float) * 256 */
|
||||
#define H264_ENC_CBR_CTL HCODEC_HENC_SCRATCH_G
|
||||
/* [31:28] : init qp table idx */
|
||||
/* [27:24] : short_term adjust shift */
|
||||
/* [23:16] : Long_term MB_Number between adjust, */
|
||||
/* [15:0] Long_term adjust threshold(Bytes) */
|
||||
#define H264_ENC_CBR_TARGET_SIZE HCODEC_HENC_SCRATCH_H
|
||||
/* Bytes(Float) * 256 */
|
||||
#define H264_ENC_CBR_PREV_BYTES HCODEC_HENC_SCRATCH_J
|
||||
#define H264_ENC_CBR_REGION_SIZE HCODEC_HENC_SCRATCH_J
|
||||
|
||||
/* --------------------------------------------------- */
|
||||
/* ENCODER_STATUS define */
|
||||
/* --------------------------------------------------- */
|
||||
#define ENCODER_IDLE 0
|
||||
#define ENCODER_SEQUENCE 1
|
||||
#define ENCODER_PICTURE 2
|
||||
#define ENCODER_IDR 3
|
||||
#define ENCODER_NON_IDR 4
|
||||
#define ENCODER_MB_HEADER 5
|
||||
#define ENCODER_MB_DATA 6
|
||||
|
||||
#define ENCODER_SEQUENCE_DONE 7
|
||||
#define ENCODER_PICTURE_DONE 8
|
||||
#define ENCODER_IDR_DONE 9
|
||||
#define ENCODER_NON_IDR_DONE 10
|
||||
#define ENCODER_MB_HEADER_DONE 11
|
||||
#define ENCODER_MB_DATA_DONE 12
|
||||
|
||||
#define ENCODER_NON_IDR_INTRA 13
|
||||
#define ENCODER_NON_IDR_INTER 14
|
||||
|
||||
#define ENCODER_ERROR 0xff
|
||||
|
||||
/********************************************
|
||||
* defines for H.264 mb_type
|
||||
*******************************************
|
||||
*/
|
||||
#define HENC_MB_Type_PBSKIP 0x0
|
||||
#define HENC_MB_Type_PSKIP 0x0
|
||||
#define HENC_MB_Type_BSKIP_DIRECT 0x0
|
||||
#define HENC_MB_Type_P16x16 0x1
|
||||
#define HENC_MB_Type_P16x8 0x2
|
||||
#define HENC_MB_Type_P8x16 0x3
|
||||
#define HENC_MB_Type_SMB8x8 0x4
|
||||
#define HENC_MB_Type_SMB8x4 0x5
|
||||
#define HENC_MB_Type_SMB4x8 0x6
|
||||
#define HENC_MB_Type_SMB4x4 0x7
|
||||
#define HENC_MB_Type_P8x8 0x8
|
||||
#define HENC_MB_Type_I4MB 0x9
|
||||
#define HENC_MB_Type_I16MB 0xa
|
||||
#define HENC_MB_Type_IBLOCK 0xb
|
||||
#define HENC_MB_Type_SI4MB 0xc
|
||||
#define HENC_MB_Type_I8MB 0xd
|
||||
#define HENC_MB_Type_IPCM 0xe
|
||||
#define HENC_MB_Type_AUTO 0xf
|
||||
|
||||
#define HENC_MB_CBP_AUTO 0xff
|
||||
#define HENC_SKIP_RUN_AUTO 0xffff
|
||||
|
||||
|
||||
extern bool amvenc_avc_on(void);
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
obj-m += vpu.o
|
||||
665
drivers/amlogic/media_modules/frame_sink/encoder/h265/vmm.h
Normal file
665
drivers/amlogic/media_modules/frame_sink/encoder/h265/vmm.h
Normal file
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
* vmm.h
|
||||
*
|
||||
* memory allocator for VPU
|
||||
*
|
||||
* Copyright (C) 2006 - 2013 CHIPS&MEDIA INC.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CNM_VIDEO_MEMORY_MANAGEMENT_H__
|
||||
#define __CNM_VIDEO_MEMORY_MANAGEMENT_H__
|
||||
|
||||
#define VMEM_PAGE_SIZE (16 * 1024)
|
||||
#define MAKE_KEY(_a, _b) (((vmem_key_t)_a) << 32 | _b)
|
||||
#define KEY_TO_VALUE(_key) (_key >> 32)
|
||||
|
||||
#define VMEM_P_ALLOC(_x) vmalloc(_x)
|
||||
#define VMEM_P_FREE(_x) vfree(_x)
|
||||
|
||||
#define VMEM_ASSERT \
|
||||
pr_info("VMEM_ASSERT at %s:%d\n", __FILE__, __LINE__)
|
||||
|
||||
|
||||
#define VMEM_HEIGHT(_tree) (_tree == NULL ? -1 : _tree->height)
|
||||
|
||||
#define MAX(_a, _b) (_a >= _b ? _a : _b)
|
||||
|
||||
struct avl_node_t;
|
||||
#define vmem_key_t unsigned long long
|
||||
|
||||
struct vmem_info_t {
|
||||
ulong total_pages;
|
||||
ulong alloc_pages;
|
||||
ulong free_pages;
|
||||
ulong page_size;
|
||||
};
|
||||
|
||||
struct page_t {
|
||||
s32 pageno;
|
||||
ulong addr;
|
||||
s32 used;
|
||||
s32 alloc_pages;
|
||||
s32 first_pageno;
|
||||
};
|
||||
|
||||
struct avl_node_t {
|
||||
vmem_key_t key;
|
||||
s32 height;
|
||||
struct page_t *page;
|
||||
struct avl_node_t *left;
|
||||
struct avl_node_t *right;
|
||||
};
|
||||
|
||||
struct video_mm_t {
|
||||
struct avl_node_t *free_tree;
|
||||
struct avl_node_t *alloc_tree;
|
||||
struct page_t *page_list;
|
||||
s32 num_pages;
|
||||
ulong base_addr;
|
||||
ulong mem_size;
|
||||
s32 free_page_count;
|
||||
s32 alloc_page_count;
|
||||
};
|
||||
|
||||
enum rotation_dir_t {
|
||||
LEFT,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
struct avl_node_data_t {
|
||||
s32 key;
|
||||
struct page_t *page;
|
||||
};
|
||||
|
||||
static struct avl_node_t *make_avl_node(
|
||||
vmem_key_t key,
|
||||
struct page_t *page)
|
||||
{
|
||||
struct avl_node_t *node =
|
||||
(struct avl_node_t *)VMEM_P_ALLOC(sizeof(struct avl_node_t));
|
||||
node->key = key;
|
||||
node->page = page;
|
||||
node->height = 0;
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
static s32 get_balance_factor(struct avl_node_t *tree)
|
||||
{
|
||||
s32 factor = 0;
|
||||
|
||||
if (tree)
|
||||
factor = VMEM_HEIGHT(tree->right) - VMEM_HEIGHT(tree->left);
|
||||
return factor;
|
||||
}
|
||||
|
||||
/*
|
||||
* Left Rotation
|
||||
*
|
||||
* A B
|
||||
* \ / \
|
||||
* B => A C
|
||||
* / \ \
|
||||
* D C D
|
||||
*
|
||||
*/
|
||||
static struct avl_node_t *rotation_left(struct avl_node_t *tree)
|
||||
{
|
||||
struct avl_node_t *rchild;
|
||||
struct avl_node_t *lchild;
|
||||
|
||||
if (tree == NULL)
|
||||
return NULL;
|
||||
|
||||
rchild = tree->right;
|
||||
if (rchild == NULL)
|
||||
return tree;
|
||||
|
||||
lchild = rchild->left;
|
||||
rchild->left = tree;
|
||||
tree->right = lchild;
|
||||
|
||||
tree->height =
|
||||
MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1;
|
||||
rchild->height =
|
||||
MAX(VMEM_HEIGHT(rchild->left), VMEM_HEIGHT(rchild->right)) + 1;
|
||||
return rchild;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reft Rotation
|
||||
*
|
||||
* A B
|
||||
* \ / \
|
||||
* B => D A
|
||||
* / \ /
|
||||
* D C C
|
||||
*
|
||||
*/
|
||||
static struct avl_node_t *rotation_right(struct avl_node_t *tree)
|
||||
{
|
||||
struct avl_node_t *rchild;
|
||||
struct avl_node_t *lchild;
|
||||
|
||||
if (tree == NULL)
|
||||
return NULL;
|
||||
|
||||
lchild = tree->left;
|
||||
if (lchild == NULL)
|
||||
return NULL;
|
||||
|
||||
rchild = lchild->right;
|
||||
lchild->right = tree;
|
||||
tree->left = rchild;
|
||||
|
||||
tree->height =
|
||||
MAX(VMEM_HEIGHT(tree->left),
|
||||
VMEM_HEIGHT(tree->right)) + 1;
|
||||
lchild->height =
|
||||
MAX(VMEM_HEIGHT(lchild->left),
|
||||
VMEM_HEIGHT(lchild->right)) + 1;
|
||||
return lchild;
|
||||
}
|
||||
|
||||
static struct avl_node_t *do_balance(struct avl_node_t *tree)
|
||||
{
|
||||
s32 bfactor = 0, child_bfactor;
|
||||
|
||||
bfactor = get_balance_factor(tree);
|
||||
if (bfactor >= 2) {
|
||||
child_bfactor = get_balance_factor(tree->right);
|
||||
if (child_bfactor == 1 || child_bfactor == 0) {
|
||||
tree = rotation_left(tree);
|
||||
} else if (child_bfactor == -1) {
|
||||
tree->right = rotation_right(tree->right);
|
||||
tree = rotation_left(tree);
|
||||
} else {
|
||||
pr_info(
|
||||
"invalid balancing factor: %d\n",
|
||||
child_bfactor);
|
||||
VMEM_ASSERT;
|
||||
return NULL;
|
||||
}
|
||||
} else if (bfactor <= -2) {
|
||||
child_bfactor = get_balance_factor(tree->left);
|
||||
if (child_bfactor == -1 || child_bfactor == 0) {
|
||||
tree = rotation_right(tree);
|
||||
} else if (child_bfactor == 1) {
|
||||
tree->left = rotation_left(tree->left);
|
||||
tree = rotation_right(tree);
|
||||
} else {
|
||||
pr_info(
|
||||
"invalid balancing factor: %d\n",
|
||||
child_bfactor);
|
||||
VMEM_ASSERT;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
static struct avl_node_t *unlink_end_node(
|
||||
struct avl_node_t *tree,
|
||||
s32 dir,
|
||||
struct avl_node_t **found_node)
|
||||
{
|
||||
struct avl_node_t *node;
|
||||
*found_node = NULL;
|
||||
|
||||
if (tree == NULL)
|
||||
return NULL;
|
||||
|
||||
if (dir == LEFT) {
|
||||
if (tree->left == NULL) {
|
||||
*found_node = tree;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (tree->right == NULL) {
|
||||
*found_node = tree;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == LEFT) {
|
||||
node = tree->left;
|
||||
tree->left = unlink_end_node(tree->left, LEFT, found_node);
|
||||
if (tree->left == NULL) {
|
||||
tree->left = (*found_node)->right;
|
||||
(*found_node)->left = NULL;
|
||||
(*found_node)->right = NULL;
|
||||
}
|
||||
} else {
|
||||
node = tree->right;
|
||||
tree->right = unlink_end_node(tree->right, RIGHT, found_node);
|
||||
if (tree->right == NULL) {
|
||||
tree->right = (*found_node)->left;
|
||||
(*found_node)->left = NULL;
|
||||
(*found_node)->right = NULL;
|
||||
}
|
||||
}
|
||||
tree->height =
|
||||
MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1;
|
||||
return do_balance(tree);
|
||||
}
|
||||
|
||||
|
||||
static struct avl_node_t *avltree_insert(
|
||||
struct avl_node_t *tree,
|
||||
vmem_key_t key,
|
||||
struct page_t *page)
|
||||
{
|
||||
if (tree == NULL) {
|
||||
tree = make_avl_node(key, page);
|
||||
} else {
|
||||
if (key >= tree->key)
|
||||
tree->right =
|
||||
avltree_insert(tree->right, key, page);
|
||||
else
|
||||
tree->left =
|
||||
avltree_insert(tree->left, key, page);
|
||||
}
|
||||
tree = do_balance(tree);
|
||||
tree->height =
|
||||
MAX(VMEM_HEIGHT(tree->left), VMEM_HEIGHT(tree->right)) + 1;
|
||||
return tree;
|
||||
}
|
||||
|
||||
static struct avl_node_t *do_unlink(struct avl_node_t *tree)
|
||||
{
|
||||
struct avl_node_t *node;
|
||||
struct avl_node_t *end_node;
|
||||
|
||||
node = unlink_end_node(tree->right, LEFT, &end_node);
|
||||
if (node) {
|
||||
tree->right = node;
|
||||
} else {
|
||||
node =
|
||||
unlink_end_node(tree->left, RIGHT, &end_node);
|
||||
if (node)
|
||||
tree->left = node;
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
node = tree->right ? tree->right : tree->left;
|
||||
end_node = node;
|
||||
}
|
||||
|
||||
if (end_node) {
|
||||
end_node->left =
|
||||
(tree->left != end_node) ?
|
||||
tree->left : end_node->left;
|
||||
end_node->right =
|
||||
(tree->right != end_node) ?
|
||||
tree->right : end_node->right;
|
||||
end_node->height =
|
||||
MAX(VMEM_HEIGHT(end_node->left),
|
||||
VMEM_HEIGHT(end_node->right)) + 1;
|
||||
}
|
||||
tree = end_node;
|
||||
return tree;
|
||||
}
|
||||
|
||||
static struct avl_node_t *avltree_remove(
|
||||
struct avl_node_t *tree,
|
||||
struct avl_node_t **found_node,
|
||||
vmem_key_t key)
|
||||
{
|
||||
*found_node = NULL;
|
||||
if (tree == NULL) {
|
||||
pr_info("failed to find key %d\n", (s32)key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (key == tree->key) {
|
||||
*found_node = tree;
|
||||
tree = do_unlink(tree);
|
||||
} else if (key > tree->key) {
|
||||
tree->right =
|
||||
avltree_remove(tree->right, found_node, key);
|
||||
} else {
|
||||
tree->left =
|
||||
avltree_remove(tree->left, found_node, key);
|
||||
}
|
||||
|
||||
if (tree)
|
||||
tree->height =
|
||||
MAX(VMEM_HEIGHT(tree->left),
|
||||
VMEM_HEIGHT(tree->right)) + 1;
|
||||
|
||||
tree = do_balance(tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
void avltree_free(struct avl_node_t *tree)
|
||||
{
|
||||
if (tree == NULL)
|
||||
return;
|
||||
if (tree->left == NULL && tree->right == NULL) {
|
||||
VMEM_P_FREE(tree);
|
||||
return;
|
||||
}
|
||||
|
||||
avltree_free(tree->left);
|
||||
tree->left = NULL;
|
||||
avltree_free(tree->right);
|
||||
tree->right = NULL;
|
||||
VMEM_P_FREE(tree);
|
||||
}
|
||||
|
||||
static struct avl_node_t *remove_approx_value(
|
||||
struct avl_node_t *tree,
|
||||
struct avl_node_t **found,
|
||||
vmem_key_t key)
|
||||
{
|
||||
*found = NULL;
|
||||
if (tree == NULL)
|
||||
return NULL;
|
||||
|
||||
if (key == tree->key) {
|
||||
*found = tree;
|
||||
tree = do_unlink(tree);
|
||||
} else if (key > tree->key) {
|
||||
tree->right = remove_approx_value(tree->right, found, key);
|
||||
} else {
|
||||
tree->left = remove_approx_value(tree->left, found, key);
|
||||
if (*found == NULL) {
|
||||
*found = tree;
|
||||
tree = do_unlink(tree);
|
||||
}
|
||||
}
|
||||
if (tree)
|
||||
tree->height =
|
||||
MAX(VMEM_HEIGHT(tree->left),
|
||||
VMEM_HEIGHT(tree->right)) + 1;
|
||||
tree = do_balance(tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
static void set_blocks_free(
|
||||
struct video_mm_t *mm,
|
||||
s32 pageno,
|
||||
s32 npages)
|
||||
{
|
||||
s32 last_pageno = pageno + npages - 1;
|
||||
s32 i;
|
||||
struct page_t *page;
|
||||
struct page_t *last_page;
|
||||
|
||||
if (npages == 0)
|
||||
VMEM_ASSERT;
|
||||
|
||||
if (last_pageno >= mm->num_pages) {
|
||||
pr_info(
|
||||
"set_blocks_free: invalid last page number: %d\n",
|
||||
last_pageno);
|
||||
VMEM_ASSERT;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = pageno; i <= last_pageno; i++) {
|
||||
mm->page_list[i].used = 0;
|
||||
mm->page_list[i].alloc_pages = 0;
|
||||
mm->page_list[i].first_pageno = -1;
|
||||
}
|
||||
|
||||
page = &mm->page_list[pageno];
|
||||
page->alloc_pages = npages;
|
||||
last_page = &mm->page_list[last_pageno];
|
||||
last_page->first_pageno = pageno;
|
||||
mm->free_tree =
|
||||
avltree_insert(mm->free_tree, MAKE_KEY(npages, pageno), page);
|
||||
}
|
||||
|
||||
static void set_blocks_alloc(
|
||||
struct video_mm_t *mm,
|
||||
s32 pageno,
|
||||
s32 npages)
|
||||
{
|
||||
s32 last_pageno = pageno + npages - 1;
|
||||
s32 i;
|
||||
struct page_t *page;
|
||||
struct page_t *last_page;
|
||||
|
||||
if (last_pageno >= mm->num_pages) {
|
||||
pr_info(
|
||||
"set_blocks_free: invalid last page number: %d\n",
|
||||
last_pageno);
|
||||
VMEM_ASSERT;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = pageno; i <= last_pageno; i++) {
|
||||
mm->page_list[i].used = 1;
|
||||
mm->page_list[i].alloc_pages = 0;
|
||||
mm->page_list[i].first_pageno = -1;
|
||||
}
|
||||
|
||||
page = &mm->page_list[pageno];
|
||||
page->alloc_pages = npages;
|
||||
last_page = &mm->page_list[last_pageno];
|
||||
last_page->first_pageno = pageno;
|
||||
mm->alloc_tree =
|
||||
avltree_insert(mm->alloc_tree, MAKE_KEY(page->addr, 0), page);
|
||||
}
|
||||
|
||||
|
||||
s32 vmem_init(struct video_mm_t *mm, ulong addr, ulong size)
|
||||
{
|
||||
s32 i;
|
||||
|
||||
if (mm == NULL)
|
||||
return -1;
|
||||
|
||||
mm->base_addr = (addr + (VMEM_PAGE_SIZE - 1))
|
||||
& ~(VMEM_PAGE_SIZE - 1);
|
||||
mm->mem_size = size & ~VMEM_PAGE_SIZE;
|
||||
mm->num_pages = mm->mem_size / VMEM_PAGE_SIZE;
|
||||
mm->free_tree = NULL;
|
||||
mm->alloc_tree = NULL;
|
||||
mm->free_page_count = mm->num_pages;
|
||||
mm->alloc_page_count = 0;
|
||||
mm->page_list =
|
||||
(struct page_t *)VMEM_P_ALLOC(
|
||||
mm->num_pages * sizeof(struct page_t));
|
||||
if (mm->page_list == NULL) {
|
||||
pr_err("%s:%d failed to kmalloc(%ld)\n",
|
||||
__func__, __LINE__,
|
||||
mm->num_pages * sizeof(struct page_t));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < mm->num_pages; i++) {
|
||||
mm->page_list[i].pageno = i;
|
||||
mm->page_list[i].addr =
|
||||
mm->base_addr + i * VMEM_PAGE_SIZE;
|
||||
mm->page_list[i].alloc_pages = 0;
|
||||
mm->page_list[i].used = 0;
|
||||
mm->page_list[i].first_pageno = -1;
|
||||
}
|
||||
set_blocks_free(mm, 0, mm->num_pages);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 vmem_exit(struct video_mm_t *mm)
|
||||
{
|
||||
if (mm == NULL) {
|
||||
pr_info("vmem_exit: invalid handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mm->free_tree)
|
||||
avltree_free(mm->free_tree);
|
||||
if (mm->alloc_tree)
|
||||
avltree_free(mm->alloc_tree);
|
||||
|
||||
if (mm->page_list) {
|
||||
VMEM_P_FREE(mm->page_list);
|
||||
mm->page_list = NULL;
|
||||
}
|
||||
|
||||
mm->base_addr = 0;
|
||||
mm->mem_size = 0;
|
||||
mm->num_pages = 0;
|
||||
mm->page_list = NULL;
|
||||
mm->free_tree = NULL;
|
||||
mm->alloc_tree = NULL;
|
||||
mm->free_page_count = 0;
|
||||
mm->alloc_page_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong vmem_alloc(struct video_mm_t *mm, s32 size, ulong pid)
|
||||
{
|
||||
struct avl_node_t *node;
|
||||
struct page_t *free_page;
|
||||
s32 npages, free_size;
|
||||
s32 alloc_pageno;
|
||||
ulong ptr;
|
||||
|
||||
if (mm == NULL) {
|
||||
pr_info("vmem_alloc: invalid handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
return -1;
|
||||
|
||||
npages = (size + VMEM_PAGE_SIZE - 1) / VMEM_PAGE_SIZE;
|
||||
mm->free_tree = remove_approx_value(mm->free_tree,
|
||||
&node, MAKE_KEY(npages, 0));
|
||||
|
||||
if (node == NULL)
|
||||
return -1;
|
||||
|
||||
free_page = node->page;
|
||||
free_size = KEY_TO_VALUE(node->key);
|
||||
alloc_pageno = free_page->pageno;
|
||||
set_blocks_alloc(mm, alloc_pageno, npages);
|
||||
if (npages != free_size) {
|
||||
s32 free_pageno = alloc_pageno + npages;
|
||||
|
||||
set_blocks_free(mm, free_pageno, (free_size-npages));
|
||||
}
|
||||
VMEM_P_FREE(node);
|
||||
|
||||
ptr = mm->page_list[alloc_pageno].addr;
|
||||
mm->alloc_page_count += npages;
|
||||
mm->free_page_count -= npages;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
s32 vmem_free(struct video_mm_t *mm, ulong ptr, ulong pid)
|
||||
{
|
||||
ulong addr;
|
||||
struct avl_node_t *found;
|
||||
struct page_t *page;
|
||||
s32 pageno, prev_free_pageno, next_free_pageno;
|
||||
s32 prev_size, next_size;
|
||||
s32 merge_page_no, merge_page_size, free_page_size;
|
||||
|
||||
if (mm == NULL) {
|
||||
pr_info("vmem_free: invalid handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr = ptr;
|
||||
mm->alloc_tree = avltree_remove(mm->alloc_tree, &found,
|
||||
MAKE_KEY(addr, 0));
|
||||
|
||||
if (found == NULL) {
|
||||
pr_info("vmem_free: 0x%08x not found\n", (s32)addr);
|
||||
VMEM_ASSERT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find previous free block */
|
||||
page = found->page;
|
||||
pageno = page->pageno;
|
||||
free_page_size = page->alloc_pages;
|
||||
prev_free_pageno = pageno - 1;
|
||||
prev_size = -1;
|
||||
if (prev_free_pageno >= 0) {
|
||||
if (mm->page_list[prev_free_pageno].used == 0) {
|
||||
prev_free_pageno =
|
||||
mm->page_list[prev_free_pageno].first_pageno;
|
||||
prev_size =
|
||||
mm->page_list[prev_free_pageno].alloc_pages;
|
||||
}
|
||||
}
|
||||
|
||||
/* find next free block */
|
||||
next_free_pageno = pageno + page->alloc_pages;
|
||||
next_free_pageno =
|
||||
(next_free_pageno == mm->num_pages) ? -1 : next_free_pageno;
|
||||
next_size = -1;
|
||||
if (next_free_pageno >= 0) {
|
||||
if (mm->page_list[next_free_pageno].used == 0) {
|
||||
next_size =
|
||||
mm->page_list[next_free_pageno].alloc_pages;
|
||||
}
|
||||
}
|
||||
VMEM_P_FREE(found);
|
||||
|
||||
/* merge */
|
||||
merge_page_no = page->pageno;
|
||||
merge_page_size = page->alloc_pages;
|
||||
if (prev_size >= 0) {
|
||||
mm->free_tree = avltree_remove(mm->free_tree, &found,
|
||||
MAKE_KEY(prev_size, prev_free_pageno));
|
||||
if (found == NULL) {
|
||||
VMEM_ASSERT;
|
||||
return -1;
|
||||
}
|
||||
merge_page_no = found->page->pageno;
|
||||
merge_page_size += found->page->alloc_pages;
|
||||
VMEM_P_FREE(found);
|
||||
}
|
||||
if (next_size >= 0) {
|
||||
mm->free_tree = avltree_remove(mm->free_tree, &found,
|
||||
MAKE_KEY(next_size, next_free_pageno));
|
||||
if (found == NULL) {
|
||||
VMEM_ASSERT;
|
||||
return -1;
|
||||
}
|
||||
merge_page_size += found->page->alloc_pages;
|
||||
VMEM_P_FREE(found);
|
||||
}
|
||||
page->alloc_pages = 0;
|
||||
page->first_pageno = -1;
|
||||
set_blocks_free(mm, merge_page_no, merge_page_size);
|
||||
mm->alloc_page_count -= free_page_size;
|
||||
mm->free_page_count += free_page_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 vmem_get_info(struct video_mm_t *mm, struct vmem_info_t *info)
|
||||
{
|
||||
if (mm == NULL) {
|
||||
pr_info("vmem_get_info: invalid handle\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (info == NULL)
|
||||
return -1;
|
||||
|
||||
info->total_pages = mm->num_pages;
|
||||
info->alloc_pages = mm->alloc_page_count;
|
||||
info->free_pages = mm->free_page_count;
|
||||
info->page_size = VMEM_PAGE_SIZE;
|
||||
return 0;
|
||||
}
|
||||
#endif /* __CNM_VIDEO_MEMORY_MANAGEMENT_H__ */
|
||||
2040
drivers/amlogic/media_modules/frame_sink/encoder/h265/vpu.c
Normal file
2040
drivers/amlogic/media_modules/frame_sink/encoder/h265/vpu.c
Normal file
File diff suppressed because it is too large
Load Diff
306
drivers/amlogic/media_modules/frame_sink/encoder/h265/vpu.h
Normal file
306
drivers/amlogic/media_modules/frame_sink/encoder/h265/vpu.h
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* vpu.h
|
||||
*
|
||||
* linux device driver for VPU.
|
||||
*
|
||||
* Copyright (C) 2006 - 2013 CHIPS&MEDIA INC.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VPU_DRV_H__
|
||||
#define __VPU_DRV_H__
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#define MAX_INST_HANDLE_SIZE (32*1024)
|
||||
#define MAX_NUM_INSTANCE 4
|
||||
#define MAX_NUM_VPU_CORE 1
|
||||
|
||||
#define W4_CMD_INIT_VPU (0x0001)
|
||||
#define W4_CMD_SLEEP_VPU (0x0400)
|
||||
#define W4_CMD_WAKEUP_VPU (0x0800)
|
||||
|
||||
/* GXM: 2000/10 = 200M */
|
||||
#define HevcEnc_L0() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(3 << 25) | (1 << 16) | (3 << 9) | (1 << 0))
|
||||
/* GXM: 2000/8 = 250M */
|
||||
#define HevcEnc_L1() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(1 << 25) | (1 << 16) | (1 << 9) | (1 << 0))
|
||||
/* GXM: 2000/7 = 285M */
|
||||
#define HevcEnc_L2() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(4 << 25) | (0 << 16) | (4 << 9) | (0 << 0))
|
||||
/*GXM: 2000/6 = 333M */
|
||||
#define HevcEnc_L3() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(2 << 25) | (1 << 16) | (2 << 9) | (1 << 0))
|
||||
/* GXM: 2000/5 = 400M */
|
||||
#define HevcEnc_L4() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(3 << 25) | (0 << 16) | (3 << 9) | (0 << 0))
|
||||
/* GXM: 2000/4 = 500M */
|
||||
#define HevcEnc_L5() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(1 << 25) | (0 << 16) | (1 << 9) | (0 << 0))
|
||||
/* GXM: 2000/3 = 667M */
|
||||
#define HevcEnc_L6() WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
(2 << 25) | (0 << 16) | (2 << 9) | (0 << 0))
|
||||
|
||||
#define HevcEnc_clock_enable(level) \
|
||||
do { \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
READ_HHI_REG(HHI_WAVE420L_CLK_CNTL) \
|
||||
& (~(1 << 8)) & (~(1 << 24))); \
|
||||
if (level == 0) \
|
||||
HevcEnc_L0(); \
|
||||
else if (level == 1) \
|
||||
HevcEnc_L1(); \
|
||||
else if (level == 2) \
|
||||
HevcEnc_L2(); \
|
||||
else if (level == 3) \
|
||||
HevcEnc_L3(); \
|
||||
else if (level == 4) \
|
||||
HevcEnc_L4(); \
|
||||
else if (level == 5) \
|
||||
HevcEnc_L5(); \
|
||||
else if (level == 6) \
|
||||
HevcEnc_L6(); \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
READ_HHI_REG(HHI_WAVE420L_CLK_CNTL) \
|
||||
| (1 << 8) | (1 << 24)); \
|
||||
} while (0)
|
||||
|
||||
#define HevcEnc_clock_disable() \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL, \
|
||||
READ_HHI_REG(HHI_WAVE420L_CLK_CNTL) \
|
||||
& (~(1 << 8)) & (~(1 << 24)))
|
||||
|
||||
/* ACLK 667MHZ */
|
||||
#define HevcEnc_MoreClock_enable() \
|
||||
do { \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
|
||||
READ_HHI_REG(HHI_WAVE420L_CLK_CNTL2) \
|
||||
& (~(1 << 8))); \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
|
||||
(2 << 9) | (0 << 0)); \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
|
||||
READ_HHI_REG(HHI_WAVE420L_CLK_CNTL2) \
|
||||
| (1 << 8)); \
|
||||
} while (0)
|
||||
|
||||
#define HevcEnc_MoreClock_disable() \
|
||||
WRITE_HHI_REG(HHI_WAVE420L_CLK_CNTL2, \
|
||||
READ_HHI_REG(HHI_WAVE420L_CLK_CNTL2) \
|
||||
& (~(1 << 8)))
|
||||
|
||||
struct compat_vpudrv_buffer_t {
|
||||
u32 size;
|
||||
u32 cached;
|
||||
compat_ulong_t phys_addr;
|
||||
compat_ulong_t base; /* kernel logical address in use kernel */
|
||||
compat_ulong_t virt_addr; /* virtual user space address */
|
||||
};
|
||||
|
||||
struct vpudrv_buffer_t {
|
||||
u32 size;
|
||||
u32 cached;
|
||||
ulong phys_addr;
|
||||
ulong base; /* kernel logical address in use kernel */
|
||||
ulong virt_addr; /* virtual user space address */
|
||||
};
|
||||
|
||||
struct vpu_bit_firmware_info_t {
|
||||
u32 size; /* size of this structure*/
|
||||
u32 core_idx;
|
||||
u32 reg_base_offset;
|
||||
u16 bit_code[512];
|
||||
};
|
||||
|
||||
struct vpudrv_inst_info_t {
|
||||
u32 core_idx;
|
||||
u32 inst_idx;
|
||||
s32 inst_open_count; /* for output only*/
|
||||
};
|
||||
|
||||
struct vpudrv_intr_info_t {
|
||||
u32 timeout;
|
||||
s32 intr_reason;
|
||||
};
|
||||
|
||||
struct vpu_drv_context_t {
|
||||
struct fasync_struct *async_queue;
|
||||
ulong interrupt_reason;
|
||||
u32 open_count; /*!<< device reference count. Not instance count */
|
||||
};
|
||||
|
||||
/* To track the allocated memory buffer */
|
||||
struct vpudrv_buffer_pool_t {
|
||||
struct list_head list;
|
||||
struct vpudrv_buffer_t vb;
|
||||
struct file *filp;
|
||||
};
|
||||
|
||||
/* To track the instance index and buffer in instance pool */
|
||||
struct vpudrv_instanace_list_t {
|
||||
struct list_head list;
|
||||
ulong inst_idx;
|
||||
ulong core_idx;
|
||||
struct file *filp;
|
||||
};
|
||||
|
||||
struct vpudrv_instance_pool_t {
|
||||
u8 codecInstPool[MAX_NUM_INSTANCE][MAX_INST_HANDLE_SIZE];
|
||||
};
|
||||
|
||||
#define VPUDRV_BUF_LEN struct vpudrv_buffer_t
|
||||
#define VPUDRV_BUF_LEN32 struct compat_vpudrv_buffer_t
|
||||
#define VPUDRV_INST_LEN struct vpudrv_inst_info_t
|
||||
|
||||
#define VDI_MAGIC 'V'
|
||||
#define VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY \
|
||||
_IOW(VDI_MAGIC, 0, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_FREE_PHYSICALMEMORY \
|
||||
_IOW(VDI_MAGIC, 1, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_WAIT_INTERRUPT \
|
||||
_IOW(VDI_MAGIC, 2, struct vpudrv_intr_info_t)
|
||||
|
||||
#define VDI_IOCTL_SET_CLOCK_GATE \
|
||||
_IOW(VDI_MAGIC, 3, u32)
|
||||
|
||||
#define VDI_IOCTL_RESET \
|
||||
_IOW(VDI_MAGIC, 4, u32)
|
||||
|
||||
#define VDI_IOCTL_GET_INSTANCE_POOL \
|
||||
_IOW(VDI_MAGIC, 5, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_GET_COMMON_MEMORY \
|
||||
_IOW(VDI_MAGIC, 6, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO \
|
||||
_IOW(VDI_MAGIC, 8, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_OPEN_INSTANCE \
|
||||
_IOW(VDI_MAGIC, 9, VPUDRV_INST_LEN)
|
||||
|
||||
#define VDI_IOCTL_CLOSE_INSTANCE \
|
||||
_IOW(VDI_MAGIC, 10, VPUDRV_INST_LEN)
|
||||
|
||||
#define VDI_IOCTL_GET_INSTANCE_NUM \
|
||||
_IOW(VDI_MAGIC, 11, VPUDRV_INST_LEN)
|
||||
|
||||
#define VDI_IOCTL_GET_REGISTER_INFO \
|
||||
_IOW(VDI_MAGIC, 12, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_FLUSH_BUFFER \
|
||||
_IOW(VDI_MAGIC, 13, VPUDRV_BUF_LEN)
|
||||
|
||||
#define VDI_IOCTL_ALLOCATE_PHYSICAL_MEMORY32 \
|
||||
_IOW(VDI_MAGIC, 0, VPUDRV_BUF_LEN32)
|
||||
|
||||
#define VDI_IOCTL_FREE_PHYSICALMEMORY32 \
|
||||
_IOW(VDI_MAGIC, 1, VPUDRV_BUF_LEN32)
|
||||
|
||||
#define VDI_IOCTL_GET_INSTANCE_POOL32 \
|
||||
_IOW(VDI_MAGIC, 5, VPUDRV_BUF_LEN32)
|
||||
|
||||
#define VDI_IOCTL_GET_COMMON_MEMORY32 \
|
||||
_IOW(VDI_MAGIC, 6, VPUDRV_BUF_LEN32)
|
||||
|
||||
#define VDI_IOCTL_GET_RESERVED_VIDEO_MEMORY_INFO32 \
|
||||
_IOW(VDI_MAGIC, 8, VPUDRV_BUF_LEN32)
|
||||
|
||||
#define VDI_IOCTL_GET_REGISTER_INFO32 \
|
||||
_IOW(VDI_MAGIC, 12, VPUDRV_BUF_LEN32)
|
||||
|
||||
#define VDI_IOCTL_FLUSH_BUFFER32 \
|
||||
_IOW(VDI_MAGIC, 13, VPUDRV_BUF_LEN32)
|
||||
|
||||
enum {
|
||||
W4_INT_INIT_VPU = 0,
|
||||
W4_INT_DEC_PIC_HDR = 1,
|
||||
W4_INT_SET_PARAM = 1,
|
||||
W4_INT_ENC_INIT_SEQ = 1,
|
||||
W4_INT_FINI_SEQ = 2,
|
||||
W4_INT_DEC_PIC = 3,
|
||||
W4_INT_ENC_PIC = 3,
|
||||
W4_INT_SET_FRAMEBUF = 4,
|
||||
W4_INT_FLUSH_DEC = 5,
|
||||
W4_INT_ENC_SLICE_INT = 7,
|
||||
W4_INT_GET_FW_VERSION = 8,
|
||||
W4_INT_QUERY_DEC = 9,
|
||||
W4_INT_SLEEP_VPU = 10,
|
||||
W4_INT_WAKEUP_VPU = 11,
|
||||
W4_INT_CHANGE_INT = 12,
|
||||
W4_INT_CREATE_INSTANCE = 14,
|
||||
W4_INT_BSBUF_EMPTY = 15,
|
||||
/*!<< Bitstream buffer empty[dec]/full[enc] */
|
||||
};
|
||||
|
||||
/* WAVE4 registers */
|
||||
#define VPU_REG_BASE_ADDR 0xc8810000
|
||||
#define VPU_REG_SIZE (0x4000 * MAX_NUM_VPU_CORE)
|
||||
|
||||
#define W4_REG_BASE 0x0000
|
||||
#define W4_VPU_BUSY_STATUS (W4_REG_BASE + 0x0070)
|
||||
#define W4_VPU_INT_REASON_CLEAR (W4_REG_BASE + 0x0034)
|
||||
#define W4_VPU_VINT_CLEAR (W4_REG_BASE + 0x003C)
|
||||
#define W4_VPU_VPU_INT_STS (W4_REG_BASE + 0x0044)
|
||||
#define W4_VPU_INT_REASON (W4_REG_BASE + 0x004c)
|
||||
|
||||
#define W4_RET_SUCCESS (W4_REG_BASE + 0x0110)
|
||||
#define W4_RET_FAIL_REASON (W4_REG_BASE + 0x0114)
|
||||
|
||||
/* WAVE4 INIT, WAKEUP */
|
||||
#define W4_PO_CONF (W4_REG_BASE + 0x0000)
|
||||
#define W4_VCPU_CUR_PC (W4_REG_BASE + 0x0004)
|
||||
|
||||
#define W4_VPU_VINT_ENABLE (W4_REG_BASE + 0x0048)
|
||||
|
||||
#define W4_VPU_RESET_REQ (W4_REG_BASE + 0x0050)
|
||||
#define W4_VPU_RESET_STATUS (W4_REG_BASE + 0x0054)
|
||||
|
||||
#define W4_VPU_REMAP_CTRL (W4_REG_BASE + 0x0060)
|
||||
#define W4_VPU_REMAP_VADDR (W4_REG_BASE + 0x0064)
|
||||
#define W4_VPU_REMAP_PADDR (W4_REG_BASE + 0x0068)
|
||||
#define W4_VPU_REMAP_CORE_START (W4_REG_BASE + 0x006C)
|
||||
#define W4_VPU_BUSY_STATUS (W4_REG_BASE + 0x0070)
|
||||
|
||||
#define W4_HW_OPTION (W4_REG_BASE + 0x0124)
|
||||
#define W4_CODE_SIZE (W4_REG_BASE + 0x011C)
|
||||
/* Note: W4_INIT_CODE_BASE_ADDR should be aligned to 4KB */
|
||||
#define W4_ADDR_CODE_BASE (W4_REG_BASE + 0x0118)
|
||||
#define W4_CODE_PARAM (W4_REG_BASE + 0x0120)
|
||||
#define W4_INIT_VPU_TIME_OUT_CNT (W4_REG_BASE + 0x0134)
|
||||
|
||||
/* WAVE4 Wave4BitIssueCommand */
|
||||
#define W4_CORE_INDEX (W4_REG_BASE + 0x0104)
|
||||
#define W4_INST_INDEX (W4_REG_BASE + 0x0108)
|
||||
#define W4_COMMAND (W4_REG_BASE + 0x0100)
|
||||
#define W4_VPU_HOST_INT_REQ (W4_REG_BASE + 0x0038)
|
||||
|
||||
#define W4_BS_RD_PTR (W4_REG_BASE + 0x0130)
|
||||
#define W4_BS_WR_PTR (W4_REG_BASE + 0x0134)
|
||||
#define W4_RET_ENC_PIC_BYTE (W4_REG_BASE + 0x01C8)
|
||||
|
||||
#define W4_REMAP_CODE_INDEX 0
|
||||
|
||||
#define ReadVpuRegister(addr) \
|
||||
readl((void __iomem *)(s_vpu_register.virt_addr \
|
||||
+ s_bit_firmware_info[core].reg_base_offset + addr))
|
||||
|
||||
#define WriteVpuRegister(addr, val) \
|
||||
writel((u32)val, (void __iomem *)(s_vpu_register.virt_addr \
|
||||
+ s_bit_firmware_info[core].reg_base_offset + addr))
|
||||
|
||||
#define WriteVpu(addr, val) writel((u32)val, (void __iomem *)addr)
|
||||
#endif
|
||||
17
drivers/amlogic/media_modules/stream_input/Makefile
Normal file
17
drivers/amlogic/media_modules/stream_input/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
obj-m += stream_input.o
|
||||
|
||||
stream_input-objs += amports/amstream.o
|
||||
stream_input-objs += amports/amstream_profile.o
|
||||
stream_input-objs += amports/adec.o
|
||||
stream_input-objs += parser/thread_rw.o
|
||||
stream_input-objs += parser/streambuf.o
|
||||
stream_input-objs += parser/esparser.o
|
||||
stream_input-objs += parser/tsdemux.o
|
||||
stream_input-objs += parser/psparser.o
|
||||
stream_input-objs += parser/rmparser.o
|
||||
|
||||
obj-y += parser/hw_demux/
|
||||
obj-y += tv_frontend/
|
||||
# obj-y += box-frontend/avl6211/
|
||||
# obj-y += box-frontend/atbm8881/
|
||||
# obj-y += box-frontend/avl68xx/
|
||||
@@ -0,0 +1,2 @@
|
||||
obj-y += amports.o
|
||||
amports-objs += amstream.o amstream_profile.o adec.o
|
||||
393
drivers/amlogic/media_modules/stream_input/amports/adec.c
Normal file
393
drivers/amlogic/media_modules/stream_input/amports/adec.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* drivers/amlogic/media/stream_input/amports/adec.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/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uio_driver.h>
|
||||
#include <linux/amlogic/media/utils/aformat.h>
|
||||
#include <linux/amlogic/media/frame_sync/ptsserv.h>
|
||||
#include <linux/amlogic/media/registers/register.h>
|
||||
#include <linux/amlogic/media/codec_mm/configs.h>
|
||||
#include "../parser/streambuf.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include "amports_priv.h"
|
||||
|
||||
#define INFO_VALID ((astream_dev) && (astream_dev->format))
|
||||
|
||||
struct astream_device_s {
|
||||
char *name;
|
||||
char *format;
|
||||
s32 channum;
|
||||
s32 samplerate;
|
||||
s32 datawidth;
|
||||
int offset;
|
||||
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
static char *astream_format[] = {
|
||||
"amadec_mpeg",
|
||||
"amadec_pcm_s16le",
|
||||
"amadec_aac",
|
||||
"amadec_ac3",
|
||||
"amadec_alaw",
|
||||
"amadec_mulaw",
|
||||
"amadec_dts",
|
||||
"amadec_pcm_s16be",
|
||||
"amadec_flac",
|
||||
"amadec_cook",
|
||||
"amadec_pcm_u8",
|
||||
"amadec_adpcm",
|
||||
"amadec_amr",
|
||||
"amadec_raac",
|
||||
"amadec_wma",
|
||||
"amadec_wmapro",
|
||||
"amadec_pcm_bluray",
|
||||
"amadec_alac",
|
||||
"amadec_vorbis",
|
||||
"amadec_aac_latm",
|
||||
"amadec_ape",
|
||||
"amadec_eac3",
|
||||
"amadec_pcm_widi",
|
||||
"amadec_dra",
|
||||
"amadec_sipr",
|
||||
"amadec_truehd",
|
||||
"amadec_mpeg1",
|
||||
"amadec_mpeg2",
|
||||
"amadec_wmavoi",
|
||||
"amadec_wmalossless",
|
||||
"amadec_pcm_s24le",
|
||||
"adec_max"
|
||||
};
|
||||
|
||||
static const char *na_string = "NA";
|
||||
static struct astream_device_s *astream_dev;
|
||||
|
||||
static ssize_t format_show(struct class *class, struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
if (INFO_VALID && astream_dev->format)
|
||||
return sprintf(buf, "%s\n", astream_dev->format);
|
||||
else
|
||||
return sprintf(buf, "%s\n", na_string);
|
||||
}
|
||||
|
||||
static ssize_t channum_show(struct class *class, struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
if (INFO_VALID)
|
||||
return sprintf(buf, "%u\n", astream_dev->channum);
|
||||
else
|
||||
return sprintf(buf, "%s\n", na_string);
|
||||
}
|
||||
|
||||
static ssize_t samplerate_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
if (INFO_VALID)
|
||||
return sprintf(buf, "%u\n", astream_dev->samplerate);
|
||||
else
|
||||
return sprintf(buf, "%s\n", na_string);
|
||||
}
|
||||
|
||||
static ssize_t datawidth_show(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
if (INFO_VALID)
|
||||
return sprintf(buf, "%u\n", astream_dev->datawidth);
|
||||
else
|
||||
return sprintf(buf, "%s\n", na_string);
|
||||
}
|
||||
|
||||
static ssize_t pts_show(struct class *class, struct class_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
u32 pts;
|
||||
u32 pts_margin = 0;
|
||||
|
||||
if (astream_dev->samplerate <= 12000)
|
||||
pts_margin = 512;
|
||||
|
||||
if (INFO_VALID && (pts_lookup(PTS_TYPE_AUDIO, &pts, pts_margin) >= 0))
|
||||
return sprintf(buf, "0x%x\n", pts);
|
||||
else
|
||||
return sprintf(buf, "%s\n", na_string);
|
||||
}
|
||||
|
||||
static ssize_t addr_offset_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", astream_dev->offset);
|
||||
}
|
||||
|
||||
static struct class_attribute astream_class_attrs[] = {
|
||||
__ATTR_RO(format),
|
||||
__ATTR_RO(samplerate),
|
||||
__ATTR_RO(channum),
|
||||
__ATTR_RO(datawidth),
|
||||
__ATTR_RO(pts),
|
||||
__ATTR_RO(addr_offset),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static struct class astream_class = {
|
||||
.name = "astream",
|
||||
.class_attrs = astream_class_attrs,
|
||||
};
|
||||
|
||||
#if 1
|
||||
#define IO_CBUS_PHY_BASE 0xc1100000
|
||||
#define CBUS_REG_OFFSET(reg) ((reg) << 2)
|
||||
#define IO_SECBUS_PHY_BASE 0xda000000
|
||||
|
||||
static struct uio_info astream_uio_info = {
|
||||
.name = "astream_uio",
|
||||
.version = "0.1",
|
||||
.irq = UIO_IRQ_NONE,
|
||||
|
||||
.mem = {
|
||||
[0] = {
|
||||
.name = "AIFIFO",
|
||||
.memtype = UIO_MEM_PHYS,
|
||||
.addr =
|
||||
(IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL))
|
||||
&(PAGE_MASK),
|
||||
.size = PAGE_SIZE,
|
||||
},
|
||||
[1] = {
|
||||
.memtype = UIO_MEM_PHYS,
|
||||
.addr =
|
||||
(IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(VCOP_CTRL_REG)),
|
||||
.size = PAGE_SIZE,
|
||||
},
|
||||
[2] = {
|
||||
.name = "SECBUS",
|
||||
.memtype = UIO_MEM_PHYS,
|
||||
.addr = (IO_SECBUS_PHY_BASE),
|
||||
.size = PAGE_SIZE,
|
||||
},
|
||||
[3] = {
|
||||
.name = "CBUS",
|
||||
.memtype = UIO_MEM_PHYS,
|
||||
.addr =
|
||||
(IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(ASSIST_HW_REV))
|
||||
&(PAGE_MASK),
|
||||
.size = PAGE_SIZE,
|
||||
},
|
||||
[4] = {
|
||||
.name = "CBUS-START",
|
||||
.memtype = UIO_MEM_PHYS,
|
||||
.addr = (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(0x1000)),
|
||||
.size = PAGE_SIZE * 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static void astream_release(struct device *dev)
|
||||
{
|
||||
kfree(astream_dev);
|
||||
|
||||
astream_dev = NULL;
|
||||
}
|
||||
|
||||
s32 adec_init(struct stream_port_s *port)
|
||||
{
|
||||
enum aformat_e af;
|
||||
|
||||
if (!astream_dev)
|
||||
return -ENODEV;
|
||||
|
||||
af = port->aformat;
|
||||
|
||||
astream_dev->channum = port->achanl;
|
||||
astream_dev->samplerate = port->asamprate;
|
||||
astream_dev->datawidth = port->adatawidth;
|
||||
|
||||
/*wmb();don't need it...*/
|
||||
if (af <= ARRAY_SIZE(astream_format))
|
||||
astream_dev->format = astream_format[af];
|
||||
else
|
||||
astream_dev->format = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 adec_release(enum aformat_e vf)
|
||||
{
|
||||
pr_info("adec_release\n");
|
||||
|
||||
if (!astream_dev)
|
||||
return -ENODEV;
|
||||
|
||||
astream_dev->format = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amstream_adec_show_fun(const char *trigger, int id, char *sbuf, int size)
|
||||
{
|
||||
int ret = -1;
|
||||
void *buf, *getbuf = NULL;
|
||||
if (size < PAGE_SIZE) {
|
||||
void *getbuf = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!getbuf)
|
||||
return -ENOMEM;
|
||||
buf = getbuf;
|
||||
} else {
|
||||
buf = sbuf;
|
||||
}
|
||||
switch (trigger[0]) {
|
||||
case 'f':
|
||||
ret = format_show(NULL, NULL, buf);
|
||||
break;
|
||||
case 's':
|
||||
ret = samplerate_show(NULL, NULL, buf);
|
||||
break;
|
||||
case 'c':
|
||||
ret = channum_show(NULL, NULL, buf);
|
||||
break;
|
||||
case 'd':
|
||||
ret = datawidth_show(NULL, NULL, buf);
|
||||
break;
|
||||
case 'p':
|
||||
ret = pts_show(NULL, NULL, buf);
|
||||
break;
|
||||
default:
|
||||
ret = -1;
|
||||
}
|
||||
if (ret > 0 && getbuf != NULL) {
|
||||
int ret = min_t(int, ret, size);
|
||||
strncpy(sbuf, buf, ret);
|
||||
}
|
||||
if (getbuf != NULL)
|
||||
free_page((unsigned long)getbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mconfig adec_configs[] = {
|
||||
MC_FUN("format", &amstream_adec_show_fun, NULL),
|
||||
MC_FUN("samplerate", &amstream_adec_show_fun, NULL),
|
||||
MC_FUN("channum", &amstream_adec_show_fun, NULL),
|
||||
MC_FUN("datawidth", &amstream_adec_show_fun, NULL),
|
||||
MC_FUN("pts", &amstream_adec_show_fun, NULL),
|
||||
};
|
||||
static struct mconfig_node adec_node;
|
||||
|
||||
|
||||
s32 astream_dev_register(void)
|
||||
{
|
||||
s32 r;
|
||||
struct device_node *node;
|
||||
unsigned int cbus_base = 0xffd00000;
|
||||
|
||||
r = class_register(&astream_class);
|
||||
if (r) {
|
||||
pr_info("astream class create fail.\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
astream_dev = kzalloc(sizeof(struct astream_device_s), GFP_KERNEL);
|
||||
|
||||
if (!astream_dev) {
|
||||
pr_info("astream device create fail.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_3;
|
||||
}
|
||||
|
||||
astream_dev->dev.class = &astream_class;
|
||||
astream_dev->dev.release = astream_release;
|
||||
astream_dev->offset = 0;
|
||||
dev_set_name(&astream_dev->dev, "astream-dev");
|
||||
|
||||
dev_set_drvdata(&astream_dev->dev, astream_dev);
|
||||
|
||||
r = device_register(&astream_dev->dev);
|
||||
if (r) {
|
||||
pr_info("astream device register fail.\n");
|
||||
goto err_2;
|
||||
}
|
||||
|
||||
if (MESON_CPU_MAJOR_ID_TXL < get_cpu_type()) {
|
||||
node = of_find_node_by_path("/codec_io/io_cbus_base");
|
||||
if (!node) {
|
||||
pr_info("No io_cbus_base node found.");
|
||||
goto err_1;
|
||||
}
|
||||
|
||||
r = of_property_read_u32_index(node, "reg", 1, &cbus_base);
|
||||
if (r) {
|
||||
pr_info("No find node.\n");
|
||||
goto err_1;
|
||||
}
|
||||
|
||||
/*need to offset -0x100 in txlx.*/
|
||||
astream_dev->offset = -0x100;
|
||||
|
||||
/*need to offset -0x180 in g12a.*/
|
||||
if (MESON_CPU_MAJOR_ID_G12A <= get_cpu_type())
|
||||
astream_dev->offset = -0x180;
|
||||
|
||||
astream_uio_info.mem[0].addr =
|
||||
(cbus_base + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL +
|
||||
astream_dev->offset)) & (PAGE_MASK);
|
||||
|
||||
astream_uio_info.mem[3].addr =
|
||||
(cbus_base + CBUS_REG_OFFSET(ASSIST_HW_REV +
|
||||
0x100)) & (PAGE_MASK);
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (uio_register_device(&astream_dev->dev, &astream_uio_info)) {
|
||||
pr_info("astream UIO device register fail.\n");
|
||||
r = -ENODEV;
|
||||
goto err_1;
|
||||
}
|
||||
#endif
|
||||
INIT_REG_NODE_CONFIGS("media", &adec_node,
|
||||
"adec", adec_configs, CONFIG_FOR_R);
|
||||
return 0;
|
||||
|
||||
err_1:
|
||||
device_unregister(&astream_dev->dev);
|
||||
|
||||
err_2:
|
||||
kfree(astream_dev);
|
||||
astream_dev = NULL;
|
||||
|
||||
err_3:
|
||||
class_unregister(&astream_class);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void astream_dev_unregister(void)
|
||||
{
|
||||
if (astream_dev) {
|
||||
#if 1
|
||||
uio_unregister_device(&astream_uio_info);
|
||||
#endif
|
||||
|
||||
device_unregister(&astream_dev->dev);
|
||||
|
||||
class_unregister(&astream_class);
|
||||
}
|
||||
}
|
||||
32
drivers/amlogic/media_modules/stream_input/amports/adec.h
Normal file
32
drivers/amlogic/media_modules/stream_input/amports/adec.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* drivers/amlogic/media/stream_input/amports/adec.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ADEC_H
|
||||
#define ADEC_H
|
||||
|
||||
#include "../parser/streambuf.h"
|
||||
#include <linux/amlogic/media/utils/aformat.h>
|
||||
|
||||
extern s32 adec_init(struct stream_port_s *port);
|
||||
|
||||
extern s32 adec_release(enum aformat_e af);
|
||||
|
||||
extern s32 astream_dev_register(void);
|
||||
|
||||
extern s32 astream_dev_unregister(void);
|
||||
|
||||
#endif /* ADEC_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* drivers/amlogic/media/stream_input/amports/amports_priv.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AMPORTS_PRIV_HEAD_HH
|
||||
#define AMPORTS_PRIV_HEAD_HH
|
||||
#include "../parser/streambuf.h"
|
||||
#include "../../common/media_clock/switch/amports_gate.h"
|
||||
#include <linux/amlogic/media/vfm/vframe.h>
|
||||
#include <linux/amlogic/media/registers/register.h>
|
||||
#include <linux/amlogic/media/utils/log.h>
|
||||
|
||||
struct port_priv_s {
|
||||
struct vdec_s *vdec;
|
||||
struct stream_port_s *port;
|
||||
};
|
||||
|
||||
struct stream_buf_s *get_buf_by_type(u32 type);
|
||||
|
||||
/*video.c provide*/
|
||||
extern u32 trickmode_i;
|
||||
struct amvideocap_req;
|
||||
extern u32 set_blackout_policy(int policy);
|
||||
extern u32 get_blackout_policy(void);
|
||||
int calculation_stream_ext_delayed_ms(u8 type);
|
||||
int ext_get_cur_video_frame(struct vframe_s **vf, int *canvas_index);
|
||||
int ext_put_video_frame(struct vframe_s *vf);
|
||||
int ext_register_end_frame_callback(struct amvideocap_req *req);
|
||||
int amstream_request_firmware_from_sys(const char *file_name,
|
||||
char *buf, int size);
|
||||
void set_vsync_pts_inc_mode(int inc);
|
||||
|
||||
void set_real_audio_info(void *arg);
|
||||
#define dbg() pr_info("on %s,line %d\n", __func__, __LINE__);
|
||||
|
||||
struct device *amports_get_dma_device(void);
|
||||
struct device *get_codec_cma_device(void);
|
||||
|
||||
#endif
|
||||
3927
drivers/amlogic/media_modules/stream_input/amports/amstream.c
Normal file
3927
drivers/amlogic/media_modules/stream_input/amports/amstream.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 "amports_priv.h"
|
||||
|
||||
static const struct codec_profile_t *vcodec_profile[SUPPORT_VDEC_NUM] = { 0 };
|
||||
|
||||
static int vcodec_profile_idx;
|
||||
|
||||
ssize_t vcodec_profile_read(char *buf)
|
||||
{
|
||||
char *pbuf = buf;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < vcodec_profile_idx; i++) {
|
||||
pbuf += sprintf(pbuf, "%s:%s;\n", vcodec_profile[i]->name,
|
||||
vcodec_profile[i]->profile);
|
||||
}
|
||||
|
||||
return pbuf - buf;
|
||||
}
|
||||
|
||||
int vcodec_profile_register(const struct codec_profile_t *vdec_profile)
|
||||
{
|
||||
if (vcodec_profile_idx < SUPPORT_VDEC_NUM) {
|
||||
vcodec_profile[vcodec_profile_idx] = vdec_profile;
|
||||
vcodec_profile_idx++;
|
||||
pr_debug("regist %s codec profile\n", vdec_profile->name);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vcodec_profile_register);
|
||||
|
||||
939
drivers/amlogic/media_modules/stream_input/parser/esparser.c
Normal file
939
drivers/amlogic/media_modules/stream_input/parser/esparser.c
Normal file
@@ -0,0 +1,939 @@
|
||||
/*
|
||||
* drivers/amlogic/media/stream_input/parser/esparser.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/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/amlogic/media/frame_sync/ptsserv.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
/* #include <mach/am_regs.h> */
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "../../frame_provider/decoder/utils/vdec.h"
|
||||
#include <linux/amlogic/media/utils/vdec_reg.h>
|
||||
#include "streambuf_reg.h"
|
||||
#include "streambuf.h"
|
||||
#include "esparser.h"
|
||||
#include "../amports/amports_priv.h"
|
||||
#include "thread_rw.h"
|
||||
|
||||
#include <linux/amlogic/media/codec_mm/codec_mm.h>
|
||||
|
||||
|
||||
|
||||
#define SAVE_SCR 0
|
||||
|
||||
#define ES_START_CODE_PATTERN 0x00000100
|
||||
#define ES_START_CODE_MASK 0xffffff00
|
||||
#define SEARCH_PATTERN_LEN 512
|
||||
#define ES_PARSER_POP READ_PARSER_REG(PFIFO_DATA)
|
||||
|
||||
#define PARSER_WRITE (ES_WRITE | ES_PARSER_START)
|
||||
#define PARSER_VIDEO (ES_TYPE_VIDEO)
|
||||
#define PARSER_AUDIO (ES_TYPE_AUDIO)
|
||||
#define PARSER_SUBPIC (ES_TYPE_SUBTITLE)
|
||||
#define PARSER_PASSTHROUGH (ES_PASSTHROUGH | ES_PARSER_START)
|
||||
#define PARSER_AUTOSEARCH (ES_SEARCH | ES_PARSER_START)
|
||||
#define PARSER_DISCARD (ES_DISCARD | ES_PARSER_START)
|
||||
#define PARSER_BUSY (ES_PARSER_BUSY)
|
||||
|
||||
static unsigned char *search_pattern;
|
||||
static dma_addr_t search_pattern_map;
|
||||
static u32 audio_real_wp;
|
||||
static u32 audio_buf_start;
|
||||
static u32 audio_buf_end;
|
||||
|
||||
static const char esparser_id[] = "esparser-id";
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(wq);
|
||||
|
||||
|
||||
static u32 search_done;
|
||||
static u32 video_data_parsed;
|
||||
static u32 audio_data_parsed;
|
||||
static atomic_t esparser_use_count = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(esparser_mutex);
|
||||
|
||||
static inline u32 get_buf_wp(u32 type)
|
||||
{
|
||||
if (type == BUF_TYPE_AUDIO)
|
||||
return audio_real_wp;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static inline u32 get_buf_start(u32 type)
|
||||
{
|
||||
if (type == BUF_TYPE_AUDIO)
|
||||
return audio_buf_start;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static inline u32 get_buf_end(u32 type)
|
||||
{
|
||||
if (type == BUF_TYPE_AUDIO)
|
||||
return audio_buf_end;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
static void set_buf_wp(u32 type, u32 wp)
|
||||
{
|
||||
if (type == BUF_TYPE_AUDIO) {
|
||||
audio_real_wp = wp;
|
||||
WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP, wp/* & 0xffffff00*/);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static irqreturn_t esparser_isr(int irq, void *dev_id)
|
||||
{
|
||||
u32 int_status = READ_PARSER_REG(PARSER_INT_STATUS);
|
||||
|
||||
WRITE_PARSER_REG(PARSER_INT_STATUS, int_status);
|
||||
|
||||
if (int_status & PARSER_INTSTAT_SC_FOUND) {
|
||||
WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
|
||||
WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
|
||||
search_done = 1;
|
||||
wake_up_interruptible(&wq);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline u32 buf_wp(u32 type)
|
||||
{
|
||||
u32 wp;
|
||||
|
||||
if ((READ_PARSER_REG(PARSER_ES_CONTROL) & ES_VID_MAN_RD_PTR) == 0) {
|
||||
wp =
|
||||
#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
|
||||
(type == BUF_TYPE_HEVC) ? READ_VREG(HEVC_STREAM_WR_PTR) :
|
||||
#endif
|
||||
(type == BUF_TYPE_VIDEO) ? READ_VREG(VLD_MEM_VIFIFO_WP) :
|
||||
(type == BUF_TYPE_AUDIO) ?
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) :
|
||||
READ_PARSER_REG(PARSER_SUB_START_PTR);
|
||||
} else {
|
||||
wp =
|
||||
#if 1/* MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
|
||||
(type == BUF_TYPE_HEVC) ? READ_PARSER_REG(PARSER_VIDEO_WP) :
|
||||
#endif
|
||||
(type == BUF_TYPE_VIDEO) ? READ_PARSER_REG(PARSER_VIDEO_WP) :
|
||||
(type == BUF_TYPE_AUDIO) ?
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_MAN_WP) :
|
||||
READ_PARSER_REG(PARSER_SUB_START_PTR);
|
||||
}
|
||||
|
||||
return wp;
|
||||
}
|
||||
|
||||
static ssize_t _esparser_write(const char __user *buf,
|
||||
size_t count, u32 type, int isphybuf)
|
||||
{
|
||||
size_t r = count;
|
||||
const char __user *p = buf;
|
||||
|
||||
u32 len = 0;
|
||||
u32 parser_type;
|
||||
int ret;
|
||||
u32 wp;
|
||||
dma_addr_t dma_addr = 0;
|
||||
|
||||
if (type == BUF_TYPE_HEVC)
|
||||
parser_type = PARSER_VIDEO;
|
||||
else if (type == BUF_TYPE_VIDEO)
|
||||
parser_type = PARSER_VIDEO;
|
||||
else if (type == BUF_TYPE_AUDIO)
|
||||
parser_type = PARSER_AUDIO;
|
||||
else
|
||||
parser_type = PARSER_SUBPIC;
|
||||
|
||||
wp = buf_wp(type);
|
||||
|
||||
if (r > 0) {
|
||||
if (isphybuf)
|
||||
len = count;
|
||||
else {
|
||||
len = min_t(size_t, r, (size_t) FETCHBUF_SIZE);
|
||||
|
||||
if (copy_from_user(fetchbuf, p, len))
|
||||
return -EFAULT;
|
||||
dma_addr = dma_map_single(
|
||||
amports_get_dma_device(), fetchbuf,
|
||||
FETCHBUF_SIZE, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(amports_get_dma_device(),
|
||||
(dma_addr_t) dma_addr))
|
||||
return -EFAULT;
|
||||
|
||||
}
|
||||
|
||||
/* wmb(); don't need */
|
||||
/* reset the Write and read pointer to zero again */
|
||||
WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
|
||||
WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
|
||||
|
||||
WRITE_PARSER_REG_BITS(PARSER_CONTROL, len, ES_PACK_SIZE_BIT,
|
||||
ES_PACK_SIZE_WID);
|
||||
WRITE_PARSER_REG_BITS(PARSER_CONTROL,
|
||||
parser_type | PARSER_WRITE |
|
||||
PARSER_AUTOSEARCH, ES_CTRL_BIT,
|
||||
ES_CTRL_WID);
|
||||
|
||||
if (isphybuf) {
|
||||
u32 buf_32 = (unsigned long)buf & 0xffffffff;
|
||||
WRITE_PARSER_REG(PARSER_FETCH_ADDR, buf_32);
|
||||
} else {
|
||||
WRITE_PARSER_REG(PARSER_FETCH_ADDR, dma_addr);
|
||||
dma_unmap_single(amports_get_dma_device(), dma_addr,
|
||||
FETCHBUF_SIZE, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
search_done = 0;
|
||||
if (!(isphybuf & TYPE_PATTERN)) {
|
||||
WRITE_PARSER_REG(PARSER_FETCH_CMD,
|
||||
(7 << FETCH_ENDIAN) | len);
|
||||
WRITE_PARSER_REG(PARSER_FETCH_ADDR, search_pattern_map);
|
||||
WRITE_PARSER_REG(PARSER_FETCH_CMD,
|
||||
(7 << FETCH_ENDIAN) | SEARCH_PATTERN_LEN);
|
||||
} else {
|
||||
WRITE_PARSER_REG(PARSER_FETCH_CMD,
|
||||
(7 << FETCH_ENDIAN) | (len + 512));
|
||||
}
|
||||
ret = wait_event_interruptible_timeout(wq, search_done != 0,
|
||||
HZ / 5);
|
||||
if (ret == 0) {
|
||||
WRITE_PARSER_REG(PARSER_FETCH_CMD, 0);
|
||||
|
||||
if (wp == buf_wp(type)) {
|
||||
/*no data fetched */
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
pr_info("W Timeout, but fetch ok,");
|
||||
pr_info("type %d len=%d,wpdiff=%d, isphy %x\n",
|
||||
type, len, wp - buf_wp(type), isphybuf);
|
||||
}
|
||||
} else if (ret < 0)
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
if ((type == BUF_TYPE_VIDEO)
|
||||
|| (has_hevc_vdec() && (type == BUF_TYPE_HEVC)))
|
||||
video_data_parsed += len;
|
||||
else if (type == BUF_TYPE_AUDIO)
|
||||
audio_data_parsed += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t _esparser_write_s(const char __user *buf,
|
||||
size_t count, u32 type)
|
||||
{
|
||||
size_t r = count;
|
||||
const char __user *p = buf;
|
||||
u32 len = 0;
|
||||
int ret;
|
||||
u32 wp, buf_start, buf_end;
|
||||
dma_addr_t buf_wp_map;
|
||||
|
||||
if (type != BUF_TYPE_AUDIO)
|
||||
BUG();
|
||||
wp = get_buf_wp(type);
|
||||
buf_end = get_buf_end(type) + 8;
|
||||
buf_start = get_buf_start(type);
|
||||
/*pr_info("write wp 0x%x, count %d, start 0x%x, end 0x%x\n",
|
||||
* wp, (u32)count, buf_start, buf_end);*/
|
||||
if (wp + count > buf_end) {
|
||||
ret = copy_from_user(codec_mm_phys_to_virt(wp),
|
||||
p, buf_end - wp);
|
||||
if (ret > 0) {
|
||||
len += buf_end - wp - ret;
|
||||
buf_wp_map = dma_map_single(amports_get_dma_device(),
|
||||
codec_mm_phys_to_virt(wp), len, DMA_TO_DEVICE);
|
||||
wp += len;
|
||||
pr_info("copy from user not finished\n");
|
||||
dma_unmap_single(NULL, buf_wp_map, len, DMA_TO_DEVICE);
|
||||
set_buf_wp(type, wp);
|
||||
goto end_write;
|
||||
} else if (ret == 0) {
|
||||
len += buf_end - wp;
|
||||
buf_wp_map = dma_map_single(amports_get_dma_device(),
|
||||
codec_mm_phys_to_virt(wp), len, DMA_TO_DEVICE);
|
||||
wp = buf_start;
|
||||
r = count - len;
|
||||
dma_unmap_single(NULL, buf_wp_map, len, DMA_TO_DEVICE);
|
||||
set_buf_wp(type, wp);
|
||||
} else {
|
||||
pr_info("copy from user failed 1\n");
|
||||
pr_info("w wp 0x%x, count %d, start 0x%x end 0x%x\n",
|
||||
wp, (u32)count, buf_start, buf_end);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
ret = copy_from_user(codec_mm_phys_to_virt(wp), p + len, r);
|
||||
if (ret >= 0) {
|
||||
len += r - ret;
|
||||
buf_wp_map = dma_map_single(amports_get_dma_device(),
|
||||
codec_mm_phys_to_virt(wp), r - ret, DMA_TO_DEVICE);
|
||||
|
||||
if (ret > 0)
|
||||
pr_info("copy from user not finished 2\n");
|
||||
wp += r - ret;
|
||||
dma_unmap_single(NULL, buf_wp_map, r - ret, DMA_TO_DEVICE);
|
||||
set_buf_wp(type, wp);
|
||||
} else {
|
||||
pr_info("copy from user failed 2\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
end_write:
|
||||
if (type == BUF_TYPE_AUDIO)
|
||||
audio_data_parsed += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
s32 es_vpts_checkin_us64(struct stream_buf_s *buf, u64 us64)
|
||||
{
|
||||
u32 passed;
|
||||
|
||||
if (buf->write_thread)
|
||||
passed = threadrw_dataoffset(buf);
|
||||
else
|
||||
passed = video_data_parsed;
|
||||
return pts_checkin_offset_us64(PTS_TYPE_VIDEO, passed, us64);
|
||||
|
||||
}
|
||||
|
||||
s32 es_apts_checkin_us64(struct stream_buf_s *buf, u64 us64)
|
||||
{
|
||||
u32 passed;
|
||||
|
||||
if (buf->write_thread)
|
||||
passed = threadrw_dataoffset(buf);
|
||||
else
|
||||
passed = audio_data_parsed;
|
||||
return pts_checkin_offset_us64(PTS_TYPE_AUDIO, passed, us64);
|
||||
}
|
||||
|
||||
s32 es_vpts_checkin(struct stream_buf_s *buf, u32 pts)
|
||||
{
|
||||
#if 0
|
||||
if (buf->first_tstamp == INVALID_PTS) {
|
||||
buf->flag |= BUF_FLAG_FIRST_TSTAMP;
|
||||
buf->first_tstamp = pts;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
u32 passed = video_data_parsed + threadrw_buffer_level(buf);
|
||||
|
||||
return pts_checkin_offset(PTS_TYPE_VIDEO, passed, pts);
|
||||
|
||||
}
|
||||
|
||||
s32 es_apts_checkin(struct stream_buf_s *buf, u32 pts)
|
||||
{
|
||||
#if 0
|
||||
if (buf->first_tstamp == INVALID_PTS) {
|
||||
buf->flag |= BUF_FLAG_FIRST_TSTAMP;
|
||||
buf->first_tstamp = pts;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
u32 passed = audio_data_parsed + threadrw_buffer_level(buf);
|
||||
|
||||
return pts_checkin_offset(PTS_TYPE_AUDIO, passed, pts);
|
||||
}
|
||||
|
||||
s32 esparser_init(struct stream_buf_s *buf, struct vdec_s *vdec)
|
||||
{
|
||||
s32 r = 0;
|
||||
u32 pts_type;
|
||||
u32 parser_sub_start_ptr;
|
||||
u32 parser_sub_end_ptr;
|
||||
u32 parser_sub_rp;
|
||||
bool first_use = false;
|
||||
/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON8 */
|
||||
if (has_hevc_vdec() && (buf->type == BUF_TYPE_HEVC))
|
||||
pts_type = PTS_TYPE_HEVC;
|
||||
else
|
||||
/* #endif */
|
||||
if (buf->type == BUF_TYPE_VIDEO)
|
||||
pts_type = PTS_TYPE_VIDEO;
|
||||
else if (buf->type == BUF_TYPE_AUDIO)
|
||||
pts_type = PTS_TYPE_AUDIO;
|
||||
else if (buf->type == BUF_TYPE_SUBTITLE)
|
||||
pts_type = PTS_TYPE_MAX;
|
||||
else
|
||||
return -EINVAL;
|
||||
mutex_lock(&esparser_mutex);
|
||||
parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
|
||||
parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
|
||||
parser_sub_rp = READ_PARSER_REG(PARSER_SUB_RP);
|
||||
|
||||
buf->flag |= BUF_FLAG_PARSER;
|
||||
|
||||
if (atomic_add_return(1, &esparser_use_count) == 1) {
|
||||
first_use = true;
|
||||
|
||||
if (fetchbuf == 0) {
|
||||
pr_info("%s: no fetchbuf\n", __func__);
|
||||
r = -ENOMEM;
|
||||
goto Err_1;
|
||||
}
|
||||
|
||||
if (search_pattern == NULL) {
|
||||
search_pattern = kcalloc(1,
|
||||
SEARCH_PATTERN_LEN,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (search_pattern == NULL) {
|
||||
pr_err("%s: no search_pattern\n", __func__);
|
||||
r = -ENOMEM;
|
||||
goto Err_1;
|
||||
}
|
||||
|
||||
/* build a fake start code to get parser interrupt */
|
||||
search_pattern[0] = 0x00;
|
||||
search_pattern[1] = 0x00;
|
||||
search_pattern[2] = 0x01;
|
||||
search_pattern[3] = 0xff;
|
||||
|
||||
search_pattern_map = dma_map_single(
|
||||
amports_get_dma_device(),
|
||||
search_pattern,
|
||||
SEARCH_PATTERN_LEN,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
/* reset PARSER with first esparser_init() call */
|
||||
WRITE_RESET_REG(RESET1_REGISTER, RESET_PARSER);
|
||||
|
||||
/* TS data path */
|
||||
#ifndef CONFIG_AM_DVB
|
||||
WRITE_DEMUX_REG(FEC_INPUT_CONTROL, 0);
|
||||
#else
|
||||
tsdemux_set_reset_flag();
|
||||
#endif
|
||||
CLEAR_DEMUX_REG_MASK(TS_HIU_CTL, 1 << USE_HI_BSF_INTERFACE);
|
||||
CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_2, 1 << USE_HI_BSF_INTERFACE);
|
||||
CLEAR_DEMUX_REG_MASK(TS_HIU_CTL_3, 1 << USE_HI_BSF_INTERFACE);
|
||||
|
||||
CLEAR_DEMUX_REG_MASK(TS_FILE_CONFIG, (1 << TS_HIU_ENABLE));
|
||||
|
||||
WRITE_PARSER_REG(PARSER_CONFIG,
|
||||
(10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
|
||||
(1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
|
||||
(16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
|
||||
|
||||
WRITE_PARSER_REG(PFIFO_RD_PTR, 0);
|
||||
WRITE_PARSER_REG(PFIFO_WR_PTR, 0);
|
||||
|
||||
WRITE_PARSER_REG(PARSER_SEARCH_PATTERN, ES_START_CODE_PATTERN);
|
||||
WRITE_PARSER_REG(PARSER_SEARCH_MASK, ES_START_CODE_MASK);
|
||||
|
||||
WRITE_PARSER_REG(PARSER_CONFIG,
|
||||
(10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
|
||||
(1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
|
||||
PS_CFG_STARTCODE_WID_24 |
|
||||
PS_CFG_PFIFO_ACCESS_WID_8 |
|
||||
/* single byte pop */
|
||||
(16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
|
||||
|
||||
WRITE_PARSER_REG(PARSER_CONTROL, PARSER_AUTOSEARCH);
|
||||
|
||||
}
|
||||
|
||||
/* hook stream buffer with PARSER */
|
||||
if (has_hevc_vdec() && (pts_type == PTS_TYPE_HEVC)) {
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_START_PTR, vdec->input.start);
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_END_PTR, vdec->input.start
|
||||
+ vdec->input.size - 8);
|
||||
|
||||
if (vdec_single(vdec)) {
|
||||
CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL,
|
||||
ES_VID_MAN_RD_PTR);
|
||||
|
||||
/* set vififo_vbuf_rp_sel=>hevc */
|
||||
WRITE_VREG(DOS_GEN_CTRL0, 3 << 1);
|
||||
|
||||
/* set use_parser_vbuf_wp */
|
||||
SET_VREG_MASK(HEVC_STREAM_CONTROL,
|
||||
(1 << 3) | (0 << 4));
|
||||
/* set stream_fetch_enable */
|
||||
SET_VREG_MASK(HEVC_STREAM_CONTROL, 1);
|
||||
|
||||
/* set stream_buffer_hole with 256 bytes */
|
||||
SET_VREG_MASK(HEVC_STREAM_FIFO_CTL, (1 << 29));
|
||||
} else {
|
||||
SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
|
||||
ES_VID_MAN_RD_PTR);
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_WP, vdec->input.start);
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_RP, vdec->input.start);
|
||||
}
|
||||
video_data_parsed = 0;
|
||||
} else if (pts_type == PTS_TYPE_VIDEO) {
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_START_PTR,
|
||||
vdec->input.start);
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_END_PTR,
|
||||
vdec->input.start + vdec->input.size - 8);
|
||||
if (vdec_single(vdec)) {
|
||||
CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL,
|
||||
ES_VID_MAN_RD_PTR);
|
||||
|
||||
WRITE_VREG(VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
|
||||
CLEAR_VREG_MASK(VLD_MEM_VIFIFO_BUF_CNTL,
|
||||
MEM_BUFCTRL_INIT);
|
||||
|
||||
if (has_hevc_vdec()) {
|
||||
/* set vififo_vbuf_rp_sel=>vdec */
|
||||
WRITE_VREG(DOS_GEN_CTRL0, 0);
|
||||
}
|
||||
} else {
|
||||
SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
|
||||
ES_VID_MAN_RD_PTR);
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_WP,
|
||||
vdec->input.start);
|
||||
WRITE_PARSER_REG(PARSER_VIDEO_RP,
|
||||
vdec->input.start);
|
||||
}
|
||||
video_data_parsed = 0;
|
||||
} else if (pts_type == PTS_TYPE_AUDIO) {
|
||||
/* set wp as buffer start */
|
||||
SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
|
||||
MEM_BUFCTRL_MANUAL);
|
||||
WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_RP,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
WRITE_AIU_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3);
|
||||
SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
|
||||
MEM_BUFCTRL_INIT);
|
||||
CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL,
|
||||
MEM_BUFCTRL_INIT);
|
||||
WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
audio_data_parsed = 0;
|
||||
audio_buf_start =
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR);
|
||||
audio_real_wp = audio_buf_start;
|
||||
audio_buf_end = READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR);
|
||||
} else if (buf->type == BUF_TYPE_SUBTITLE) {
|
||||
WRITE_PARSER_REG(PARSER_SUB_START_PTR,
|
||||
parser_sub_start_ptr);
|
||||
WRITE_PARSER_REG(PARSER_SUB_END_PTR,
|
||||
parser_sub_end_ptr);
|
||||
WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_rp);
|
||||
SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
|
||||
(7 << ES_SUB_WR_ENDIAN_BIT) |
|
||||
ES_SUB_MAN_RD_PTR);
|
||||
}
|
||||
|
||||
if (pts_type < PTS_TYPE_MAX) {
|
||||
r = pts_start(pts_type);
|
||||
|
||||
if (r < 0) {
|
||||
pr_info("esparser_init: pts_start failed\n");
|
||||
goto Err_1;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (buf->flag & BUF_FLAG_FIRST_TSTAMP) {
|
||||
if (buf->type == BUF_TYPE_VIDEO)
|
||||
es_vpts_checkin(buf, buf->first_tstamp);
|
||||
else if (buf->type == BUF_TYPE_AUDIO)
|
||||
es_apts_checkin(buf, buf->first_tstamp);
|
||||
|
||||
buf->flag &= ~BUF_FLAG_FIRST_TSTAMP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (first_use) {
|
||||
/*TODO irq */
|
||||
r = vdec_request_irq(PARSER_IRQ, esparser_isr,
|
||||
"parser", (void *)esparser_id);
|
||||
|
||||
if (r) {
|
||||
pr_info("esparser_init: irq register failed.\n");
|
||||
goto Err_2;
|
||||
}
|
||||
|
||||
WRITE_PARSER_REG(PARSER_INT_STATUS, 0xffff);
|
||||
WRITE_PARSER_REG(PARSER_INT_ENABLE,
|
||||
PARSER_INTSTAT_SC_FOUND <<
|
||||
PARSER_INT_HOST_EN_BIT);
|
||||
}
|
||||
mutex_unlock(&esparser_mutex);
|
||||
if (!(vdec_get_debug_flags() & 1) &&
|
||||
!codec_mm_video_tvp_enabled()) {
|
||||
int block_size = (buf->type == BUF_TYPE_AUDIO) ?
|
||||
PAGE_SIZE : PAGE_SIZE << 4;
|
||||
int buf_num = (buf->type == BUF_TYPE_AUDIO) ?
|
||||
20 : (2 * SZ_1M)/(PAGE_SIZE << 4);
|
||||
if (!(buf->type == BUF_TYPE_SUBTITLE))
|
||||
buf->write_thread = threadrw_alloc(buf_num,
|
||||
block_size,
|
||||
esparser_write_ex,
|
||||
(buf->type == BUF_TYPE_AUDIO) ? 1 : 0);
|
||||
/*manul mode for audio*/
|
||||
}
|
||||
return 0;
|
||||
|
||||
Err_2:
|
||||
pts_stop(pts_type);
|
||||
|
||||
Err_1:
|
||||
atomic_dec(&esparser_use_count);
|
||||
buf->flag &= ~BUF_FLAG_PARSER;
|
||||
mutex_unlock(&esparser_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
void esparser_audio_reset_s(struct stream_buf_s *buf)
|
||||
{
|
||||
ulong flags;
|
||||
DEFINE_SPINLOCK(lock);
|
||||
|
||||
spin_lock_irqsave(&lock, flags);
|
||||
|
||||
SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL);
|
||||
WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_RP,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
WRITE_AIU_REG_BITS(AIU_MEM_AIFIFO_CONTROL, 7, 3, 3);
|
||||
SET_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
|
||||
CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
|
||||
WRITE_AIU_REG(AIU_MEM_AIFIFO_MAN_WP,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
|
||||
buf->flag |= BUF_FLAG_PARSER;
|
||||
|
||||
audio_data_parsed = 0;
|
||||
audio_real_wp = READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR);
|
||||
audio_buf_start = READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR);
|
||||
audio_buf_end = READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR);
|
||||
spin_unlock_irqrestore(&lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void esparser_audio_reset(struct stream_buf_s *buf)
|
||||
{
|
||||
ulong flags;
|
||||
DEFINE_SPINLOCK(lock);
|
||||
|
||||
spin_lock_irqsave(&lock, flags);
|
||||
|
||||
WRITE_PARSER_REG(PARSER_AUDIO_WP,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
WRITE_PARSER_REG(PARSER_AUDIO_RP,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
|
||||
WRITE_PARSER_REG(PARSER_AUDIO_START_PTR,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_START_PTR));
|
||||
WRITE_PARSER_REG(PARSER_AUDIO_END_PTR,
|
||||
READ_AIU_REG(AIU_MEM_AIFIFO_END_PTR));
|
||||
CLEAR_PARSER_REG_MASK(PARSER_ES_CONTROL, ES_AUD_MAN_RD_PTR);
|
||||
|
||||
WRITE_AIU_REG(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
|
||||
CLEAR_AIU_REG_MASK(AIU_MEM_AIFIFO_BUF_CNTL, MEM_BUFCTRL_INIT);
|
||||
|
||||
buf->flag |= BUF_FLAG_PARSER;
|
||||
|
||||
audio_data_parsed = 0;
|
||||
audio_real_wp = 0;
|
||||
audio_buf_start = 0;
|
||||
audio_buf_end = 0;
|
||||
spin_unlock_irqrestore(&lock, flags);
|
||||
|
||||
}
|
||||
|
||||
void esparser_release(struct stream_buf_s *buf)
|
||||
{
|
||||
u32 pts_type;
|
||||
|
||||
/* check if esparser_init() is ever called */
|
||||
if ((buf->flag & BUF_FLAG_PARSER) == 0)
|
||||
return;
|
||||
|
||||
if (atomic_read(&esparser_use_count) == 0) {
|
||||
pr_info
|
||||
("[%s:%d]###warning, esparser has been released already\n",
|
||||
__func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
if (buf->write_thread)
|
||||
threadrw_release(buf);
|
||||
if (atomic_dec_and_test(&esparser_use_count)) {
|
||||
WRITE_PARSER_REG(PARSER_INT_ENABLE, 0);
|
||||
/*TODO irq */
|
||||
|
||||
vdec_free_irq(PARSER_IRQ, (void *)esparser_id);
|
||||
|
||||
if (search_pattern) {
|
||||
dma_unmap_single(amports_get_dma_device(),
|
||||
search_pattern_map,
|
||||
SEARCH_PATTERN_LEN, DMA_TO_DEVICE);
|
||||
kfree(search_pattern);
|
||||
search_pattern = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_hevc_vdec() && (buf->type == BUF_TYPE_HEVC))
|
||||
pts_type = PTS_TYPE_VIDEO;
|
||||
else if (buf->type == BUF_TYPE_VIDEO)
|
||||
pts_type = PTS_TYPE_VIDEO;
|
||||
else if (buf->type == BUF_TYPE_AUDIO)
|
||||
pts_type = PTS_TYPE_AUDIO;
|
||||
else if (buf->type == BUF_TYPE_SUBTITLE) {
|
||||
buf->flag &= ~BUF_FLAG_PARSER;
|
||||
return;
|
||||
} else
|
||||
return;
|
||||
|
||||
buf->flag &= ~BUF_FLAG_PARSER;
|
||||
pts_stop(pts_type);
|
||||
}
|
||||
|
||||
ssize_t drm_write(struct file *file, struct stream_buf_s *stbuf,
|
||||
const char __user *buf, size_t count)
|
||||
{
|
||||
s32 r;
|
||||
u32 len;
|
||||
u32 realcount, totalcount;
|
||||
u32 re_count = count;
|
||||
u32 havewritebytes = 0;
|
||||
u32 leftcount = 0;
|
||||
|
||||
struct drm_info tmpmm;
|
||||
struct drm_info *drm = &tmpmm;
|
||||
u32 res = 0;
|
||||
int isphybuf = 0;
|
||||
unsigned long realbuf;
|
||||
|
||||
if (buf == NULL || count == 0)
|
||||
return -EINVAL;
|
||||
if (stbuf->write_thread) {
|
||||
r = threadrw_flush_buffers(stbuf);
|
||||
if (r < 0)
|
||||
pr_info("Warning. drm flush threadrw failed[%d]\n", r);
|
||||
}
|
||||
res = copy_from_user(drm, buf, sizeof(struct drm_info));
|
||||
if (res) {
|
||||
pr_info("drm kmalloc failed res[%d]\n", res);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if ((drm->drm_flag & TYPE_DRMINFO) && (drm->drm_hasesdata == 0)) {
|
||||
/* buf only has drminfo not have esdata; */
|
||||
realbuf = drm->drm_phy;
|
||||
realcount = drm->drm_pktsize;
|
||||
isphybuf = drm->drm_flag;
|
||||
/* DRM_PRNT("drm_get_rawdata
|
||||
*onlydrminfo drm->drm_hasesdata[0x%x]
|
||||
* stbuf->type %d buf[0x%x]\n",
|
||||
*drm->drm_hasesdata,stbuf->type,buf);
|
||||
*/
|
||||
} else if (drm->drm_hasesdata == 1) { /* buf is drminfo+es; */
|
||||
realcount = drm->drm_pktsize;
|
||||
realbuf = (unsigned long)buf + sizeof(struct drm_info);
|
||||
isphybuf = 0;
|
||||
/* DRM_PRNT("drm_get_rawdata
|
||||
* drminfo+es drm->drm_hasesdata[0x%x]
|
||||
* stbuf->type %d\n",drm->drm_hasesdata,stbuf->type);
|
||||
*/
|
||||
} else { /* buf is hwhead; */
|
||||
realcount = count;
|
||||
isphybuf = 0;
|
||||
realbuf = (unsigned long)buf;
|
||||
/* DRM_PRNT("drm_get_rawdata
|
||||
* drm->drm_hasesdata[0x%x]
|
||||
* len[%d] count[%d] realcout[%d]\n",
|
||||
* drm->drm_hasesdata,len,count,realcount);
|
||||
*/
|
||||
}
|
||||
|
||||
len = realcount;
|
||||
count = realcount;
|
||||
totalcount = realcount;
|
||||
|
||||
while (len > 0) {
|
||||
if (stbuf->type != BUF_TYPE_SUBTITLE
|
||||
&& stbuf_space(stbuf) < count) {
|
||||
/*should not write partial data in drm mode*/
|
||||
stbuf_wait_space(stbuf, count);
|
||||
if (stbuf_space(stbuf) < count)
|
||||
return -EAGAIN;
|
||||
}
|
||||
len = min_t(u32, len, count);
|
||||
|
||||
mutex_lock(&esparser_mutex);
|
||||
|
||||
if (stbuf->type != BUF_TYPE_AUDIO)
|
||||
r = _esparser_write((const char __user *)realbuf, len,
|
||||
stbuf->type, isphybuf);
|
||||
else
|
||||
r = _esparser_write_s((const char __user *)realbuf, len,
|
||||
stbuf->type);
|
||||
if (r < 0) {
|
||||
pr_info("drm_write _esparser_write failed [%d]\n", r);
|
||||
return r;
|
||||
}
|
||||
havewritebytes += r;
|
||||
leftcount = totalcount - havewritebytes;
|
||||
if (havewritebytes == totalcount) {
|
||||
|
||||
mutex_unlock(&esparser_mutex);
|
||||
break; /* write ok; */
|
||||
} else if ((len > 0) && (havewritebytes < totalcount)) {
|
||||
DRM_PRNT
|
||||
("d writebytes[%d] want[%d] total[%d] real[%d]\n",
|
||||
havewritebytes, len, totalcount, realcount);
|
||||
len = len - r; /* write again; */
|
||||
realbuf = realbuf + r;
|
||||
} else {
|
||||
pr_info
|
||||
("e writebytes[%d] want[%d] total[%d] real[%d]\n",
|
||||
havewritebytes, len, totalcount, realcount);
|
||||
}
|
||||
mutex_unlock(&esparser_mutex);
|
||||
}
|
||||
|
||||
return re_count;
|
||||
}
|
||||
/*
|
||||
*flags:
|
||||
*1:phy
|
||||
*2:noblock
|
||||
*/
|
||||
ssize_t esparser_write_ex(struct file *file,
|
||||
struct stream_buf_s *stbuf,
|
||||
const char __user *buf, size_t count,
|
||||
int flags)
|
||||
{
|
||||
|
||||
s32 r;
|
||||
u32 len = count;
|
||||
|
||||
if (buf == NULL || count == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*subtitle have no level to check, */
|
||||
if (stbuf->type != BUF_TYPE_SUBTITLE && stbuf_space(stbuf) < count) {
|
||||
if ((flags & 2) || ((file != NULL) &&
|
||||
(file->f_flags & O_NONBLOCK))) {
|
||||
len = stbuf_space(stbuf);
|
||||
|
||||
if (len < 256) /* <1k.do eagain, */
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
len = min(stbuf_canusesize(stbuf) / 8, len);
|
||||
|
||||
if (stbuf_space(stbuf) < len) {
|
||||
r = stbuf_wait_space(stbuf, len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stbuf->last_write_jiffies64 = jiffies_64;
|
||||
|
||||
len = min_t(u32, len, count);
|
||||
|
||||
mutex_lock(&esparser_mutex);
|
||||
|
||||
if (stbuf->type == BUF_TYPE_AUDIO)
|
||||
r = _esparser_write_s(buf, len, stbuf->type);
|
||||
else
|
||||
r = _esparser_write(buf, len, stbuf->type, flags & 1);
|
||||
|
||||
mutex_unlock(&esparser_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
ssize_t esparser_write(struct file *file,
|
||||
struct stream_buf_s *stbuf,
|
||||
const char __user *buf, size_t count)
|
||||
{
|
||||
if (stbuf->write_thread) {
|
||||
ssize_t ret;
|
||||
|
||||
ret = threadrw_write(file, stbuf, buf, count);
|
||||
if (ret == -EAGAIN) {
|
||||
u32 a, b;
|
||||
int vdelay, adelay;
|
||||
|
||||
if ((stbuf->type != BUF_TYPE_VIDEO) &&
|
||||
(stbuf->type != BUF_TYPE_HEVC))
|
||||
return ret;
|
||||
if (stbuf->buf_size > (SZ_1M * 30) ||
|
||||
(threadrw_buffer_size(stbuf) > SZ_1M * 10) ||
|
||||
!threadrw_support_more_buffers(stbuf))
|
||||
return ret;
|
||||
/*only chang buffer for video.*/
|
||||
vdelay = calculation_stream_delayed_ms(
|
||||
PTS_TYPE_VIDEO, &a, &b);
|
||||
adelay = calculation_stream_delayed_ms(
|
||||
PTS_TYPE_AUDIO, &a, &b);
|
||||
if ((vdelay > 100 && vdelay < 2000) && /*vdelay valid.*/
|
||||
((vdelay < 500) ||/*video delay is short!*/
|
||||
(adelay > 0 && adelay < 1000))/*audio is low.*/
|
||||
) {
|
||||
/*on buffer fulled.
|
||||
*if delay is less than 100ms we think errors,
|
||||
*And we add more buffer on delay < 2s.
|
||||
*/
|
||||
int new_size = 2 * 1024 * 1024;
|
||||
|
||||
threadrw_alloc_more_buffer_size(
|
||||
stbuf, new_size);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return esparser_write_ex(file, stbuf, buf, count, 0);
|
||||
}
|
||||
|
||||
|
||||
void esparser_sub_reset(void)
|
||||
{
|
||||
ulong flags;
|
||||
DEFINE_SPINLOCK(lock);
|
||||
u32 parser_sub_start_ptr;
|
||||
u32 parser_sub_end_ptr;
|
||||
|
||||
spin_lock_irqsave(&lock, flags);
|
||||
|
||||
parser_sub_start_ptr = READ_PARSER_REG(PARSER_SUB_START_PTR);
|
||||
parser_sub_end_ptr = READ_PARSER_REG(PARSER_SUB_END_PTR);
|
||||
|
||||
WRITE_PARSER_REG(PARSER_SUB_START_PTR, parser_sub_start_ptr);
|
||||
WRITE_PARSER_REG(PARSER_SUB_END_PTR, parser_sub_end_ptr);
|
||||
WRITE_PARSER_REG(PARSER_SUB_RP, parser_sub_start_ptr);
|
||||
WRITE_PARSER_REG(PARSER_SUB_WP, parser_sub_start_ptr);
|
||||
SET_PARSER_REG_MASK(PARSER_ES_CONTROL,
|
||||
(7 << ES_SUB_WR_ENDIAN_BIT) | ES_SUB_MAN_RD_PTR);
|
||||
|
||||
spin_unlock_irqrestore(&lock, flags);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user