Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,26 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_STI_HVA
tristate "STMicroelectronics HVA multi-format video encoder V4L2 driver"
depends on V4L_MEM2MEM_DRIVERS
depends on VIDEO_DEV
depends on ARCH_STI || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
help
This V4L2 driver enables HVA (Hardware Video Accelerator) multi-format
video encoder of STMicroelectronics SoC, allowing hardware encoding of
raw uncompressed formats in various compressed video bitstreams format.
To compile this driver as a module, choose M here:
the module will be called st-hva.
config VIDEO_STI_HVA_DEBUGFS
bool "Export STMicroelectronics HVA internals in debugfs"
depends on VIDEO_STI_HVA
depends on DEBUG_FS
help
Select this to see information about the internal state and the last
operation of STMicroelectronics HVA multi-format video encoder in
debugfs.
Choose N unless you know you need this.
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_VIDEO_STI_HVA) += st-hva.o
st-hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o
st-hva-$(CONFIG_VIDEO_STI_HVA_DEBUGFS) += hva-debugfs.o
@@ -0,0 +1,396 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#include <linux/debugfs.h>
#include "hva.h"
#include "hva-hw.h"
static void format_ctx(struct seq_file *s, struct hva_ctx *ctx)
{
struct hva_streaminfo *stream = &ctx->streaminfo;
struct hva_frameinfo *frame = &ctx->frameinfo;
struct hva_controls *ctrls = &ctx->ctrls;
struct hva_ctx_dbg *dbg = &ctx->dbg;
u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp;
seq_printf(s, "|-%s\n |\n", ctx->name);
seq_printf(s, " |-[%sframe info]\n",
ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default ");
seq_printf(s, " | |- pixel format=%4.4s\n"
" | |- wxh=%dx%d\n"
" | |- wxh (w/ encoder alignment constraint)=%dx%d\n"
" |\n",
(char *)&frame->pixelformat,
frame->width, frame->height,
frame->aligned_width, frame->aligned_height);
seq_printf(s, " |-[%sstream info]\n",
ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default ");
seq_printf(s, " | |- stream format=%4.4s\n"
" | |- wxh=%dx%d\n"
" | |- %s\n"
" | |- %s\n"
" |\n",
(char *)&stream->streamformat,
stream->width, stream->height,
stream->profile, stream->level);
bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
aspect = V4L2_CID_MPEG_VIDEO_ASPECT;
seq_puts(s, " |-[parameters]\n");
seq_printf(s, " | |- %s\n"
" | |- bitrate=%d bps\n"
" | |- GOP size=%d\n"
" | |- video aspect=%s\n"
" | |- framerate=%d/%d\n",
v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode],
ctrls->bitrate,
ctrls->gop_size,
v4l2_ctrl_get_menu(aspect)[ctrls->aspect],
ctrls->time_per_frame.denominator,
ctrls->time_per_frame.numerator);
entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE;
vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC;
sei_fp = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE;
if (stream->streamformat == V4L2_PIX_FMT_H264) {
seq_printf(s, " | |- %s entropy mode\n"
" | |- CPB size=%d kB\n"
" | |- DCT8x8 enable=%s\n"
" | |- qpmin=%d\n"
" | |- qpmax=%d\n"
" | |- PAR enable=%s\n"
" | |- PAR id=%s\n"
" | |- SEI frame packing enable=%s\n"
" | |- SEI frame packing type=%s\n",
v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode],
ctrls->cpb_size,
ctrls->dct8x8 ? "true" : "false",
ctrls->qpmin,
ctrls->qpmax,
ctrls->vui_sar ? "true" : "false",
v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc],
ctrls->sei_fp ? "true" : "false",
v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]);
}
if (ctx->sys_errors || ctx->encode_errors || ctx->frame_errors) {
seq_puts(s, " |\n |-[errors]\n");
seq_printf(s, " | |- system=%d\n"
" | |- encoding=%d\n"
" | |- frame=%d\n",
ctx->sys_errors,
ctx->encode_errors,
ctx->frame_errors);
}
seq_puts(s, " |\n |-[performances]\n");
seq_printf(s, " | |- frames encoded=%d\n"
" | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n"
" | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n"
" | |- avg fps (0.1Hz)=%d\n"
" | |- max reachable fps (0.1Hz)=%d\n"
" | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n"
" | |- last bitrate (kbps)=%d\n",
dbg->cnt_duration,
dbg->avg_duration,
dbg->min_duration,
dbg->max_duration,
dbg->avg_period,
dbg->min_period,
dbg->max_period,
dbg->avg_fps,
dbg->max_fps,
dbg->avg_bitrate,
dbg->min_bitrate,
dbg->max_bitrate,
dbg->last_bitrate);
}
/*
* performance debug info
*/
void hva_dbg_perf_begin(struct hva_ctx *ctx)
{
u64 div;
u32 period;
u32 bitrate;
struct hva_ctx_dbg *dbg = &ctx->dbg;
ktime_t prev = dbg->begin;
dbg->begin = ktime_get();
if (dbg->is_valid_period) {
/* encoding period */
div = (u64)ktime_us_delta(dbg->begin, prev);
do_div(div, 100);
period = (u32)div;
dbg->min_period = min(period, dbg->min_period);
dbg->max_period = max(period, dbg->max_period);
dbg->total_period += period;
dbg->cnt_period++;
/*
* minimum and maximum bitrates are based on the
* encoding period values upon a window of 32 samples
*/
dbg->window_duration += period;
dbg->cnt_window++;
if (dbg->cnt_window >= 32) {
/*
* bitrate in kbps = (size * 8 / 1000) /
* (duration / 10000)
* = size * 80 / duration
*/
if (dbg->window_duration > 0) {
div = (u64)dbg->window_stream_size * 80;
do_div(div, dbg->window_duration);
bitrate = (u32)div;
dbg->last_bitrate = bitrate;
dbg->min_bitrate = min(bitrate,
dbg->min_bitrate);
dbg->max_bitrate = max(bitrate,
dbg->max_bitrate);
}
dbg->window_stream_size = 0;
dbg->window_duration = 0;
dbg->cnt_window = 0;
}
}
/*
* filter sequences valid for performance:
* - begin/begin (no stream available) is an invalid sequence
* - begin/end is a valid sequence
*/
dbg->is_valid_period = false;
}
void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream)
{
struct device *dev = ctx_to_dev(ctx);
u64 div;
u32 duration;
u32 bytesused;
u32 timestamp;
struct hva_ctx_dbg *dbg = &ctx->dbg;
ktime_t end = ktime_get();
/* stream bytesused and timestamp in us */
bytesused = vb2_get_plane_payload(&stream->vbuf.vb2_buf, 0);
div = stream->vbuf.vb2_buf.timestamp;
do_div(div, 1000);
timestamp = (u32)div;
/* encoding duration */
div = (u64)ktime_us_delta(end, dbg->begin);
dev_dbg(dev,
"%s perf stream[%d] dts=%d encoded using %d bytes in %d us",
ctx->name,
stream->vbuf.sequence,
timestamp,
bytesused, (u32)div);
do_div(div, 100);
duration = (u32)div;
dbg->min_duration = min(duration, dbg->min_duration);
dbg->max_duration = max(duration, dbg->max_duration);
dbg->total_duration += duration;
dbg->cnt_duration++;
/*
* the average bitrate is based on the total stream size
* and the total encoding periods
*/
dbg->total_stream_size += bytesused;
dbg->window_stream_size += bytesused;
dbg->is_valid_period = true;
}
static void hva_dbg_perf_compute(struct hva_ctx *ctx)
{
u64 div;
struct hva_ctx_dbg *dbg = &ctx->dbg;
if (dbg->cnt_duration > 0) {
div = (u64)dbg->total_duration;
do_div(div, dbg->cnt_duration);
dbg->avg_duration = (u32)div;
} else {
dbg->avg_duration = 0;
}
if (dbg->total_duration > 0) {
div = (u64)dbg->cnt_duration * 100000;
do_div(div, dbg->total_duration);
dbg->max_fps = (u32)div;
} else {
dbg->max_fps = 0;
}
if (dbg->cnt_period > 0) {
div = (u64)dbg->total_period;
do_div(div, dbg->cnt_period);
dbg->avg_period = (u32)div;
} else {
dbg->avg_period = 0;
}
if (dbg->total_period > 0) {
div = (u64)dbg->cnt_period * 100000;
do_div(div, dbg->total_period);
dbg->avg_fps = (u32)div;
} else {
dbg->avg_fps = 0;
}
if (dbg->total_period > 0) {
/*
* bitrate in kbps = (video size * 8 / 1000) /
* (video duration / 10000)
* = video size * 80 / video duration
*/
div = (u64)dbg->total_stream_size * 80;
do_div(div, dbg->total_period);
dbg->avg_bitrate = (u32)div;
} else {
dbg->avg_bitrate = 0;
}
}
/*
* device debug info
*/
static int device_show(struct seq_file *s, void *data)
{
struct hva_dev *hva = s->private;
seq_printf(s, "[%s]\n", hva->v4l2_dev.name);
seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num);
return 0;
}
static int encoders_show(struct seq_file *s, void *data)
{
struct hva_dev *hva = s->private;
unsigned int i = 0;
seq_printf(s, "[encoders]\n|- %d registered encoders:\n",
hva->nb_of_encoders);
while (hva->encoders[i]) {
seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name,
(char *)&hva->encoders[i]->pixelformat,
(char *)&hva->encoders[i]->streamformat);
i++;
}
return 0;
}
static int last_show(struct seq_file *s, void *data)
{
struct hva_dev *hva = s->private;
struct hva_ctx *last_ctx = &hva->dbg.last_ctx;
if (last_ctx->flags & HVA_FLAG_STREAMINFO) {
seq_puts(s, "[last encoding]\n");
hva_dbg_perf_compute(last_ctx);
format_ctx(s, last_ctx);
} else {
seq_puts(s, "[no information recorded about last encoding]\n");
}
return 0;
}
static int regs_show(struct seq_file *s, void *data)
{
struct hva_dev *hva = s->private;
hva_hw_dump_regs(hva, s);
return 0;
}
#define hva_dbg_create_entry(name) \
debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
&name##_fops)
DEFINE_SHOW_ATTRIBUTE(device);
DEFINE_SHOW_ATTRIBUTE(encoders);
DEFINE_SHOW_ATTRIBUTE(last);
DEFINE_SHOW_ATTRIBUTE(regs);
void hva_debugfs_create(struct hva_dev *hva)
{
hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
hva_dbg_create_entry(device);
hva_dbg_create_entry(encoders);
hva_dbg_create_entry(last);
hva_dbg_create_entry(regs);
}
void hva_debugfs_remove(struct hva_dev *hva)
{
debugfs_remove_recursive(hva->dbg.debugfs_entry);
hva->dbg.debugfs_entry = NULL;
}
/*
* context (instance) debug info
*/
static int ctx_show(struct seq_file *s, void *data)
{
struct hva_ctx *ctx = s->private;
seq_printf(s, "[running encoding %d]\n", ctx->id);
hva_dbg_perf_compute(ctx);
format_ctx(s, ctx);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(ctx);
void hva_dbg_ctx_create(struct hva_ctx *ctx)
{
struct hva_dev *hva = ctx->hva_dev;
char name[4] = "";
ctx->dbg.min_duration = UINT_MAX;
ctx->dbg.min_period = UINT_MAX;
ctx->dbg.min_bitrate = UINT_MAX;
snprintf(name, sizeof(name), "%d", hva->instance_id);
ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444,
hva->dbg.debugfs_entry,
ctx, &ctx_fops);
}
void hva_dbg_ctx_remove(struct hva_ctx *ctx)
{
struct hva_dev *hva = ctx->hva_dev;
if (ctx->flags & HVA_FLAG_STREAMINFO)
/* save context before removing */
memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx));
debugfs_remove(ctx->dbg.debugfs_entry);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,584 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
#include <linux/seq_file.h>
#endif
#include "hva.h"
#include "hva-hw.h"
/* HVA register offsets */
#define HVA_HIF_REG_RST 0x0100U
#define HVA_HIF_REG_RST_ACK 0x0104U
#define HVA_HIF_REG_MIF_CFG 0x0108U
#define HVA_HIF_REG_HEC_MIF_CFG 0x010CU
#define HVA_HIF_REG_CFL 0x0110U
#define HVA_HIF_FIFO_CMD 0x0114U
#define HVA_HIF_FIFO_STS 0x0118U
#define HVA_HIF_REG_SFL 0x011CU
#define HVA_HIF_REG_IT_ACK 0x0120U
#define HVA_HIF_REG_ERR_IT_ACK 0x0124U
#define HVA_HIF_REG_LMI_ERR 0x0128U
#define HVA_HIF_REG_EMI_ERR 0x012CU
#define HVA_HIF_REG_HEC_MIF_ERR 0x0130U
#define HVA_HIF_REG_HEC_STS 0x0134U
#define HVA_HIF_REG_HVC_STS 0x0138U
#define HVA_HIF_REG_HJE_STS 0x013CU
#define HVA_HIF_REG_CNT 0x0140U
#define HVA_HIF_REG_HEC_CHKSYN_DIS 0x0144U
#define HVA_HIF_REG_CLK_GATING 0x0148U
#define HVA_HIF_REG_VERSION 0x014CU
#define HVA_HIF_REG_BSM 0x0150U
/* define value for version id register (HVA_HIF_REG_VERSION) */
#define VERSION_ID_MASK 0x0000FFFF
/* define values for BSM register (HVA_HIF_REG_BSM) */
#define BSM_CFG_VAL1 0x0003F000
#define BSM_CFG_VAL2 0x003F0000
/* define values for memory interface register (HVA_HIF_REG_MIF_CFG) */
#define MIF_CFG_VAL1 0x04460446
#define MIF_CFG_VAL2 0x04460806
#define MIF_CFG_VAL3 0x00000000
/* define value for HEC memory interface register (HVA_HIF_REG_MIF_CFG) */
#define HEC_MIF_CFG_VAL 0x000000C4
/* Bits definition for clock gating register (HVA_HIF_REG_CLK_GATING) */
#define CLK_GATING_HVC BIT(0)
#define CLK_GATING_HEC BIT(1)
#define CLK_GATING_HJE BIT(2)
/* fix hva clock rate */
#define CLK_RATE 300000000
/* fix delay for pmruntime */
#define AUTOSUSPEND_DELAY_MS 3
/*
* hw encode error values
* NO_ERROR: Success, Task OK
* H264_BITSTREAM_OVERSIZE: VECH264 Bitstream size > bitstream buffer
* H264_FRAME_SKIPPED: VECH264 Frame skipped (refers to CPB Buffer Size)
* H264_SLICE_LIMIT_SIZE: VECH264 MB > slice limit size
* H264_MAX_SLICE_NUMBER: VECH264 max slice number reached
* H264_SLICE_READY: VECH264 Slice ready
* TASK_LIST_FULL: HVA/FPC task list full
(discard latest transform command)
* UNKNOWN_COMMAND: Transform command not known by HVA/FPC
* WRONG_CODEC_OR_RESOLUTION: Wrong Codec or Resolution Selection
* NO_INT_COMPLETION: Time-out on interrupt completion
* LMI_ERR: Local Memory Interface Error
* EMI_ERR: External Memory Interface Error
* HECMI_ERR: HEC Memory Interface Error
*/
enum hva_hw_error {
NO_ERROR = 0x0,
H264_BITSTREAM_OVERSIZE = 0x2,
H264_FRAME_SKIPPED = 0x4,
H264_SLICE_LIMIT_SIZE = 0x5,
H264_MAX_SLICE_NUMBER = 0x7,
H264_SLICE_READY = 0x8,
TASK_LIST_FULL = 0xF0,
UNKNOWN_COMMAND = 0xF1,
WRONG_CODEC_OR_RESOLUTION = 0xF4,
NO_INT_COMPLETION = 0x100,
LMI_ERR = 0x101,
EMI_ERR = 0x102,
HECMI_ERR = 0x103,
};
static irqreturn_t hva_hw_its_interrupt(int irq, void *data)
{
struct hva_dev *hva = data;
/* read status registers */
hva->sts_reg = readl_relaxed(hva->regs + HVA_HIF_FIFO_STS);
hva->sfl_reg = readl_relaxed(hva->regs + HVA_HIF_REG_SFL);
/* acknowledge interruption */
writel_relaxed(0x1, hva->regs + HVA_HIF_REG_IT_ACK);
return IRQ_WAKE_THREAD;
}
static irqreturn_t hva_hw_its_irq_thread(int irq, void *arg)
{
struct hva_dev *hva = arg;
struct device *dev = hva_to_dev(hva);
u32 status = hva->sts_reg & 0xFF;
u8 ctx_id = 0;
struct hva_ctx *ctx = NULL;
dev_dbg(dev, "%s %s: status: 0x%02x fifo level: 0x%02x\n",
HVA_PREFIX, __func__, hva->sts_reg & 0xFF, hva->sfl_reg & 0xF);
/*
* status: task_id[31:16] client_id[15:8] status[7:0]
* the context identifier is retrieved from the client identifier
*/
ctx_id = (hva->sts_reg & 0xFF00) >> 8;
if (ctx_id >= HVA_MAX_INSTANCES) {
dev_err(dev, "%s %s: bad context identifier: %d\n",
HVA_PREFIX, __func__, ctx_id);
goto out;
}
ctx = hva->instances[ctx_id];
if (!ctx)
goto out;
switch (status) {
case NO_ERROR:
dev_dbg(dev, "%s %s: no error\n",
ctx->name, __func__);
ctx->hw_err = false;
break;
case H264_SLICE_READY:
dev_dbg(dev, "%s %s: h264 slice ready\n",
ctx->name, __func__);
ctx->hw_err = false;
break;
case H264_FRAME_SKIPPED:
dev_dbg(dev, "%s %s: h264 frame skipped\n",
ctx->name, __func__);
ctx->hw_err = false;
break;
case H264_BITSTREAM_OVERSIZE:
dev_err(dev, "%s %s:h264 bitstream oversize\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
case H264_SLICE_LIMIT_SIZE:
dev_err(dev, "%s %s: h264 slice limit size is reached\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
case H264_MAX_SLICE_NUMBER:
dev_err(dev, "%s %s: h264 max slice number is reached\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
case TASK_LIST_FULL:
dev_err(dev, "%s %s:task list full\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
case UNKNOWN_COMMAND:
dev_err(dev, "%s %s: command not known\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
case WRONG_CODEC_OR_RESOLUTION:
dev_err(dev, "%s %s: wrong codec or resolution\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
default:
dev_err(dev, "%s %s: status not recognized\n",
ctx->name, __func__);
ctx->hw_err = true;
break;
}
out:
complete(&hva->interrupt);
return IRQ_HANDLED;
}
static irqreturn_t hva_hw_err_interrupt(int irq, void *data)
{
struct hva_dev *hva = data;
/* read status registers */
hva->sts_reg = readl_relaxed(hva->regs + HVA_HIF_FIFO_STS);
hva->sfl_reg = readl_relaxed(hva->regs + HVA_HIF_REG_SFL);
/* read error registers */
hva->lmi_err_reg = readl_relaxed(hva->regs + HVA_HIF_REG_LMI_ERR);
hva->emi_err_reg = readl_relaxed(hva->regs + HVA_HIF_REG_EMI_ERR);
hva->hec_mif_err_reg = readl_relaxed(hva->regs +
HVA_HIF_REG_HEC_MIF_ERR);
/* acknowledge interruption */
writel_relaxed(0x1, hva->regs + HVA_HIF_REG_IT_ACK);
return IRQ_WAKE_THREAD;
}
static irqreturn_t hva_hw_err_irq_thread(int irq, void *arg)
{
struct hva_dev *hva = arg;
struct device *dev = hva_to_dev(hva);
u8 ctx_id = 0;
struct hva_ctx *ctx;
dev_dbg(dev, "%s status: 0x%02x fifo level: 0x%02x\n",
HVA_PREFIX, hva->sts_reg & 0xFF, hva->sfl_reg & 0xF);
/*
* status: task_id[31:16] client_id[15:8] status[7:0]
* the context identifier is retrieved from the client identifier
*/
ctx_id = (hva->sts_reg & 0xFF00) >> 8;
if (ctx_id >= HVA_MAX_INSTANCES) {
dev_err(dev, "%s bad context identifier: %d\n", HVA_PREFIX,
ctx_id);
goto out;
}
ctx = hva->instances[ctx_id];
if (!ctx)
goto out;
if (hva->lmi_err_reg) {
dev_err(dev, "%s local memory interface error: 0x%08x\n",
ctx->name, hva->lmi_err_reg);
ctx->hw_err = true;
}
if (hva->emi_err_reg) {
dev_err(dev, "%s external memory interface error: 0x%08x\n",
ctx->name, hva->emi_err_reg);
ctx->hw_err = true;
}
if (hva->hec_mif_err_reg) {
dev_err(dev, "%s hec memory interface error: 0x%08x\n",
ctx->name, hva->hec_mif_err_reg);
ctx->hw_err = true;
}
out:
complete(&hva->interrupt);
return IRQ_HANDLED;
}
static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva)
{
struct device *dev = hva_to_dev(hva);
unsigned long int version;
if (pm_runtime_resume_and_get(dev) < 0) {
dev_err(dev, "%s failed to get pm_runtime\n", HVA_PREFIX);
mutex_unlock(&hva->protect_mutex);
return -EFAULT;
}
version = readl_relaxed(hva->regs + HVA_HIF_REG_VERSION) &
VERSION_ID_MASK;
pm_runtime_put_autosuspend(dev);
switch (version) {
case HVA_VERSION_V400:
dev_dbg(dev, "%s IP hardware version 0x%lx\n",
HVA_PREFIX, version);
break;
default:
dev_err(dev, "%s unknown IP hardware version 0x%lx\n",
HVA_PREFIX, version);
version = HVA_VERSION_UNKNOWN;
break;
}
return version;
}
int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva)
{
struct device *dev = &pdev->dev;
struct resource *esram;
int ret;
WARN_ON(!hva);
/* get memory for registers */
hva->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hva->regs)) {
dev_err(dev, "%s failed to get regs\n", HVA_PREFIX);
return PTR_ERR(hva->regs);
}
/* get memory for esram */
esram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!esram) {
dev_err(dev, "%s failed to get esram\n", HVA_PREFIX);
return -ENODEV;
}
hva->esram_addr = esram->start;
hva->esram_size = resource_size(esram);
dev_info(dev, "%s esram reserved for address: 0x%x size:%d\n",
HVA_PREFIX, hva->esram_addr, hva->esram_size);
/* get clock resource */
hva->clk = devm_clk_get(dev, "clk_hva");
if (IS_ERR(hva->clk)) {
dev_err(dev, "%s failed to get clock\n", HVA_PREFIX);
return PTR_ERR(hva->clk);
}
ret = clk_prepare(hva->clk);
if (ret < 0) {
dev_err(dev, "%s failed to prepare clock\n", HVA_PREFIX);
hva->clk = ERR_PTR(-EINVAL);
return ret;
}
/* get status interruption resource */
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto err_clk;
hva->irq_its = ret;
ret = devm_request_threaded_irq(dev, hva->irq_its, hva_hw_its_interrupt,
hva_hw_its_irq_thread,
IRQF_ONESHOT,
"hva_its_irq", hva);
if (ret) {
dev_err(dev, "%s failed to install status IRQ 0x%x\n",
HVA_PREFIX, hva->irq_its);
goto err_clk;
}
disable_irq(hva->irq_its);
/* get error interruption resource */
ret = platform_get_irq(pdev, 1);
if (ret < 0)
goto err_clk;
hva->irq_err = ret;
ret = devm_request_threaded_irq(dev, hva->irq_err, hva_hw_err_interrupt,
hva_hw_err_irq_thread,
IRQF_ONESHOT,
"hva_err_irq", hva);
if (ret) {
dev_err(dev, "%s failed to install error IRQ 0x%x\n",
HVA_PREFIX, hva->irq_err);
goto err_clk;
}
disable_irq(hva->irq_err);
/* initialise protection mutex */
mutex_init(&hva->protect_mutex);
/* initialise completion signal */
init_completion(&hva->interrupt);
/* initialise runtime power management */
pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_suspended(dev);
pm_runtime_enable(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0) {
dev_err(dev, "%s failed to set PM\n", HVA_PREFIX);
goto err_disable;
}
/* check IP hardware version */
hva->ip_version = hva_hw_get_ip_version(hva);
if (hva->ip_version == HVA_VERSION_UNKNOWN) {
ret = -EINVAL;
goto err_pm;
}
dev_info(dev, "%s found hva device (version 0x%lx)\n", HVA_PREFIX,
hva->ip_version);
return 0;
err_pm:
pm_runtime_put(dev);
err_disable:
pm_runtime_disable(dev);
err_clk:
clk_unprepare(hva->clk);
return ret;
}
void hva_hw_remove(struct hva_dev *hva)
{
struct device *dev = hva_to_dev(hva);
disable_irq(hva->irq_its);
disable_irq(hva->irq_err);
pm_runtime_put_autosuspend(dev);
pm_runtime_disable(dev);
}
int hva_hw_runtime_suspend(struct device *dev)
{
struct hva_dev *hva = dev_get_drvdata(dev);
clk_disable_unprepare(hva->clk);
return 0;
}
int hva_hw_runtime_resume(struct device *dev)
{
struct hva_dev *hva = dev_get_drvdata(dev);
if (clk_prepare_enable(hva->clk)) {
dev_err(hva->dev, "%s failed to prepare hva clk\n",
HVA_PREFIX);
return -EINVAL;
}
if (clk_set_rate(hva->clk, CLK_RATE)) {
dev_err(dev, "%s failed to set clock frequency\n",
HVA_PREFIX);
clk_disable_unprepare(hva->clk);
return -EINVAL;
}
return 0;
}
int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
struct hva_buffer *task)
{
struct hva_dev *hva = ctx_to_hdev(ctx);
struct device *dev = hva_to_dev(hva);
u8 client_id = ctx->id;
int ret;
u32 reg = 0;
bool got_pm = false;
mutex_lock(&hva->protect_mutex);
/* enable irqs */
enable_irq(hva->irq_its);
enable_irq(hva->irq_err);
if (pm_runtime_resume_and_get(dev) < 0) {
dev_err(dev, "%s failed to get pm_runtime\n", ctx->name);
ctx->sys_errors++;
ret = -EFAULT;
goto out;
}
got_pm = true;
reg = readl_relaxed(hva->regs + HVA_HIF_REG_CLK_GATING);
switch (cmd) {
case H264_ENC:
reg |= CLK_GATING_HVC;
break;
default:
dev_dbg(dev, "%s unknown command 0x%x\n", ctx->name, cmd);
ctx->encode_errors++;
ret = -EFAULT;
goto out;
}
writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING);
dev_dbg(dev, "%s %s: write configuration registers\n", ctx->name,
__func__);
/* byte swap config */
writel_relaxed(BSM_CFG_VAL1, hva->regs + HVA_HIF_REG_BSM);
/* define Max Opcode Size and Max Message Size for LMI and EMI */
writel_relaxed(MIF_CFG_VAL3, hva->regs + HVA_HIF_REG_MIF_CFG);
writel_relaxed(HEC_MIF_CFG_VAL, hva->regs + HVA_HIF_REG_HEC_MIF_CFG);
/*
* command FIFO: task_id[31:16] client_id[15:8] command_type[7:0]
* the context identifier is provided as client identifier to the
* hardware, and is retrieved in the interrupt functions from the
* status register
*/
dev_dbg(dev, "%s %s: send task (cmd: %d, task_desc: %pad)\n",
ctx->name, __func__, cmd + (client_id << 8), &task->paddr);
writel_relaxed(cmd + (client_id << 8), hva->regs + HVA_HIF_FIFO_CMD);
writel_relaxed(task->paddr, hva->regs + HVA_HIF_FIFO_CMD);
if (!wait_for_completion_timeout(&hva->interrupt,
msecs_to_jiffies(2000))) {
dev_err(dev, "%s %s: time out on completion\n", ctx->name,
__func__);
ctx->encode_errors++;
ret = -EFAULT;
goto out;
}
/* get encoding status */
ret = ctx->hw_err ? -EFAULT : 0;
ctx->encode_errors += ctx->hw_err ? 1 : 0;
out:
disable_irq(hva->irq_its);
disable_irq(hva->irq_err);
switch (cmd) {
case H264_ENC:
reg &= ~CLK_GATING_HVC;
writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING);
break;
default:
dev_dbg(dev, "%s unknown command 0x%x\n", ctx->name, cmd);
}
if (got_pm)
pm_runtime_put_autosuspend(dev);
mutex_unlock(&hva->protect_mutex);
return ret;
}
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
#define DUMP(reg) seq_printf(s, "%-30s: 0x%08X\n",\
#reg, readl_relaxed(hva->regs + reg))
void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s)
{
struct device *dev = hva_to_dev(hva);
mutex_lock(&hva->protect_mutex);
if (pm_runtime_resume_and_get(dev) < 0) {
seq_puts(s, "Cannot wake up IP\n");
mutex_unlock(&hva->protect_mutex);
return;
}
seq_printf(s, "Registers:\nReg @ = 0x%p\n", hva->regs);
DUMP(HVA_HIF_REG_RST);
DUMP(HVA_HIF_REG_RST_ACK);
DUMP(HVA_HIF_REG_MIF_CFG);
DUMP(HVA_HIF_REG_HEC_MIF_CFG);
DUMP(HVA_HIF_REG_CFL);
DUMP(HVA_HIF_REG_SFL);
DUMP(HVA_HIF_REG_LMI_ERR);
DUMP(HVA_HIF_REG_EMI_ERR);
DUMP(HVA_HIF_REG_HEC_MIF_ERR);
DUMP(HVA_HIF_REG_HEC_STS);
DUMP(HVA_HIF_REG_HVC_STS);
DUMP(HVA_HIF_REG_HJE_STS);
DUMP(HVA_HIF_REG_CNT);
DUMP(HVA_HIF_REG_HEC_CHKSYN_DIS);
DUMP(HVA_HIF_REG_CLK_GATING);
DUMP(HVA_HIF_REG_VERSION);
pm_runtime_put_autosuspend(dev);
mutex_unlock(&hva->protect_mutex);
}
#endif
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#ifndef HVA_HW_H
#define HVA_HW_H
#include "hva-mem.h"
/* HVA Versions */
#define HVA_VERSION_UNKNOWN 0x000
#define HVA_VERSION_V400 0x400
/* HVA command types */
enum hva_hw_cmd_type {
/* RESERVED = 0x00 */
/* RESERVED = 0x01 */
H264_ENC = 0x02,
/* RESERVED = 0x03 */
/* RESERVED = 0x04 */
/* RESERVED = 0x05 */
/* RESERVED = 0x06 */
/* RESERVED = 0x07 */
REMOVE_CLIENT = 0x08,
FREEZE_CLIENT = 0x09,
START_CLIENT = 0x0A,
FREEZE_ALL = 0x0B,
START_ALL = 0x0C,
REMOVE_ALL = 0x0D
};
int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva);
void hva_hw_remove(struct hva_dev *hva);
int hva_hw_runtime_suspend(struct device *dev);
int hva_hw_runtime_resume(struct device *dev);
int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
struct hva_buffer *task);
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s);
#endif
#endif /* HVA_HW_H */
@@ -0,0 +1,62 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#include "hva.h"
#include "hva-mem.h"
int hva_mem_alloc(struct hva_ctx *ctx, u32 size, const char *name,
struct hva_buffer **buf)
{
struct device *dev = ctx_to_dev(ctx);
struct hva_buffer *b;
dma_addr_t paddr;
void *base;
b = devm_kzalloc(dev, sizeof(*b), GFP_KERNEL);
if (!b) {
ctx->sys_errors++;
return -ENOMEM;
}
base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL,
DMA_ATTR_WRITE_COMBINE);
if (!base) {
dev_err(dev, "%s %s : dma_alloc_attrs failed for %s (size=%d)\n",
ctx->name, __func__, name, size);
ctx->sys_errors++;
devm_kfree(dev, b);
return -ENOMEM;
}
b->size = size;
b->paddr = paddr;
b->vaddr = base;
b->name = name;
dev_dbg(dev,
"%s allocate %d bytes of HW memory @(virt=%p, phy=%pad): %s\n",
ctx->name, size, b->vaddr, &b->paddr, b->name);
/* return hva buffer to user */
*buf = b;
return 0;
}
void hva_mem_free(struct hva_ctx *ctx, struct hva_buffer *buf)
{
struct device *dev = ctx_to_dev(ctx);
dev_dbg(dev,
"%s free %d bytes of HW memory @(virt=%p, phy=%pad): %s\n",
ctx->name, buf->size, buf->vaddr, &buf->paddr, buf->name);
dma_free_attrs(dev, buf->size, buf->vaddr, buf->paddr,
DMA_ATTR_WRITE_COMBINE);
devm_kfree(dev, buf);
}
@@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#ifndef HVA_MEM_H
#define HVA_MEM_H
/**
* struct hva_buffer - hva buffer
*
* @name: name of requester
* @paddr: physical address (for hardware)
* @vaddr: virtual address (kernel can read/write)
* @size: size of buffer
*/
struct hva_buffer {
const char *name;
dma_addr_t paddr;
void *vaddr;
u32 size;
};
int hva_mem_alloc(struct hva_ctx *ctx,
__u32 size,
const char *name,
struct hva_buffer **buf);
void hva_mem_free(struct hva_ctx *ctx,
struct hva_buffer *buf);
#endif /* HVA_MEM_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,407 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#ifndef HVA_H
#define HVA_H
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-mem2mem.h>
#define hva_to_dev(h) (h->dev)
#define ctx_to_dev(c) (c->hva_dev->dev)
#define ctx_to_hdev(c) (c->hva_dev)
#define HVA_NAME "st-hva"
#define HVA_PREFIX "[---:----]"
extern const struct hva_enc nv12h264enc;
extern const struct hva_enc nv21h264enc;
/**
* struct hva_frameinfo - information about hva frame
*
* @pixelformat: fourcc code for uncompressed video format
* @width: width of frame
* @height: height of frame
* @aligned_width: width of frame (with encoder alignment constraint)
* @aligned_height: height of frame (with encoder alignment constraint)
* @size: maximum size in bytes required for data
*/
struct hva_frameinfo {
u32 pixelformat;
u32 width;
u32 height;
u32 aligned_width;
u32 aligned_height;
u32 size;
};
/**
* struct hva_streaminfo - information about hva stream
*
* @streamformat: fourcc code of compressed video format (H.264...)
* @width: width of stream
* @height: height of stream
* @profile: profile string
* @level: level string
*/
struct hva_streaminfo {
u32 streamformat;
u32 width;
u32 height;
u8 profile[32];
u8 level[32];
};
/**
* struct hva_controls - hva controls set
*
* @time_per_frame: time per frame in seconds
* @bitrate_mode: bitrate mode (constant bitrate or variable bitrate)
* @gop_size: groupe of picture size
* @bitrate: bitrate (in bps)
* @aspect: video aspect
* @profile: H.264 profile
* @level: H.264 level
* @entropy_mode: H.264 entropy mode (CABAC or CVLC)
* @cpb_size: coded picture buffer size (in kB)
* @dct8x8: transform mode 8x8 enable
* @qpmin: minimum quantizer
* @qpmax: maximum quantizer
* @vui_sar: pixel aspect ratio enable
* @vui_sar_idc: pixel aspect ratio identifier
* @sei_fp: sei frame packing arrangement enable
* @sei_fp_type: sei frame packing arrangement type
*/
struct hva_controls {
struct v4l2_fract time_per_frame;
enum v4l2_mpeg_video_bitrate_mode bitrate_mode;
u32 gop_size;
u32 bitrate;
enum v4l2_mpeg_video_aspect aspect;
enum v4l2_mpeg_video_h264_profile profile;
enum v4l2_mpeg_video_h264_level level;
enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
u32 cpb_size;
bool dct8x8;
u32 qpmin;
u32 qpmax;
bool vui_sar;
enum v4l2_mpeg_video_h264_vui_sar_idc vui_sar_idc;
bool sei_fp;
enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_type;
};
/**
* struct hva_frame - hva frame buffer (output)
*
* @vbuf: video buffer information for V4L2
* @list: V4L2 m2m list that the frame belongs to
* @info: frame information (width, height, format, alignment...)
* @paddr: physical address (for hardware)
* @vaddr: virtual address (kernel can read/write)
* @prepared: true if vaddr/paddr are resolved
*/
struct hva_frame {
struct vb2_v4l2_buffer vbuf;
struct list_head list;
struct hva_frameinfo info;
dma_addr_t paddr;
void *vaddr;
bool prepared;
};
/*
* to_hva_frame() - cast struct vb2_v4l2_buffer * to struct hva_frame *
*/
#define to_hva_frame(vb) \
container_of(vb, struct hva_frame, vbuf)
/**
* struct hva_stream - hva stream buffer (capture)
*
* @vbuf: video buffer information for V4L2
* @list: V4L2 m2m list that the frame belongs to
* @paddr: physical address (for hardware)
* @vaddr: virtual address (kernel can read/write)
* @prepared: true if vaddr/paddr are resolved
* @size: size of the buffer in bytes
* @bytesused: number of bytes occupied by data in the buffer
*/
struct hva_stream {
struct vb2_v4l2_buffer vbuf;
struct list_head list;
dma_addr_t paddr;
void *vaddr;
bool prepared;
unsigned int size;
unsigned int bytesused;
};
/*
* to_hva_stream() - cast struct vb2_v4l2_buffer * to struct hva_stream *
*/
#define to_hva_stream(vb) \
container_of(vb, struct hva_stream, vbuf)
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
/**
* struct hva_ctx_dbg - instance context debug info
*
* @debugfs_entry: debugfs entry
* @is_valid_period: true if the sequence is valid for performance
* @begin: start time of last HW task
* @total_duration: total HW processing durations in 0.1ms
* @cnt_duration: number of HW processings
* @min_duration: minimum HW processing duration in 0.1ms
* @max_duration: maximum HW processing duration in 0.1ms
* @avg_duration: average HW processing duration in 0.1ms
* @max_fps: maximum frames encoded per second (in 0.1Hz)
* @total_period: total encoding periods in 0.1ms
* @cnt_period: number of periods
* @min_period: minimum encoding period in 0.1ms
* @max_period: maximum encoding period in 0.1ms
* @avg_period: average encoding period in 0.1ms
* @total_stream_size: total number of encoded bytes
* @avg_fps: average frames encoded per second (in 0.1Hz)
* @window_duration: duration of the sampling window in 0.1ms
* @cnt_window: number of samples in the window
* @window_stream_size: number of encoded bytes upon the sampling window
* @last_bitrate: bitrate upon the last sampling window
* @min_bitrate: minimum bitrate in kbps
* @max_bitrate: maximum bitrate in kbps
* @avg_bitrate: average bitrate in kbps
*/
struct hva_ctx_dbg {
struct dentry *debugfs_entry;
bool is_valid_period;
ktime_t begin;
u32 total_duration;
u32 cnt_duration;
u32 min_duration;
u32 max_duration;
u32 avg_duration;
u32 max_fps;
u32 total_period;
u32 cnt_period;
u32 min_period;
u32 max_period;
u32 avg_period;
u32 total_stream_size;
u32 avg_fps;
u32 window_duration;
u32 cnt_window;
u32 window_stream_size;
u32 last_bitrate;
u32 min_bitrate;
u32 max_bitrate;
u32 avg_bitrate;
};
#endif
struct hva_dev;
struct hva_enc;
/**
* struct hva_ctx - context of hva instance
*
* @hva_dev: the device that this instance is associated with
* @fh: V4L2 file handle
* @ctrl_handler: V4L2 controls handler
* @ctrls: hva controls set
* @id: instance identifier
* @aborting: true if current job aborted
* @name: instance name (debug purpose)
* @run_work: encode work
* @lock: mutex used to lock access of this context
* @flags: validity of streaminfo and frameinfo fields
* @frame_num: frame number
* @stream_num: stream number
* @max_stream_size: maximum size in bytes required for stream data
* @colorspace: colorspace identifier
* @xfer_func: transfer function identifier
* @ycbcr_enc: Y'CbCr encoding identifier
* @quantization: quantization identifier
* @streaminfo: stream properties
* @frameinfo: frame properties
* @enc: current encoder
* @priv: private codec data for this instance, allocated
* by encoder @open time
* @hw_err: true if hardware error detected
* @encoded_frames: number of encoded frames
* @sys_errors: number of system errors (memory, resource, pm...)
* @encode_errors: number of encoding errors (hw/driver errors)
* @frame_errors: number of frame errors (format, size, header...)
* @dbg: context debug info
*/
struct hva_ctx {
struct hva_dev *hva_dev;
struct v4l2_fh fh;
struct v4l2_ctrl_handler ctrl_handler;
struct hva_controls ctrls;
u8 id;
bool aborting;
char name[100];
struct work_struct run_work;
/* mutex protecting this data structure */
struct mutex lock;
u32 flags;
u32 frame_num;
u32 stream_num;
u32 max_stream_size;
enum v4l2_colorspace colorspace;
enum v4l2_xfer_func xfer_func;
enum v4l2_ycbcr_encoding ycbcr_enc;
enum v4l2_quantization quantization;
struct hva_streaminfo streaminfo;
struct hva_frameinfo frameinfo;
struct hva_enc *enc;
void *priv;
bool hw_err;
u32 encoded_frames;
u32 sys_errors;
u32 encode_errors;
u32 frame_errors;
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
struct hva_ctx_dbg dbg;
#endif
};
#define HVA_FLAG_STREAMINFO 0x0001
#define HVA_FLAG_FRAMEINFO 0x0002
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
/**
* struct hva_dev_dbg - device debug info
*
* @debugfs_entry: debugfs entry
* @last_ctx: debug information about last running instance context
*/
struct hva_dev_dbg {
struct dentry *debugfs_entry;
struct hva_ctx last_ctx;
};
#endif
#define HVA_MAX_INSTANCES 16
#define HVA_MAX_ENCODERS 10
#define HVA_MAX_FORMATS HVA_MAX_ENCODERS
/**
* struct hva_dev - abstraction for hva entity
*
* @v4l2_dev: V4L2 device
* @vdev: video device
* @pdev: platform device
* @dev: device
* @lock: mutex used for critical sections & V4L2 ops
* serialization
* @m2m_dev: memory-to-memory V4L2 device information
* @instances: opened instances
* @nb_of_instances: number of opened instances
* @instance_id: rolling counter identifying an instance (debug purpose)
* @regs: register io memory access
* @esram_addr: esram address
* @esram_size: esram size
* @clk: hva clock
* @irq_its: status interruption
* @irq_err: error interruption
* @work_queue: work queue to handle the encode jobs
* @protect_mutex: mutex used to lock access of hardware
* @interrupt: completion interrupt
* @ip_version: IP hardware version
* @encoders: registered encoders
* @nb_of_encoders: number of registered encoders
* @pixelformats: supported uncompressed video formats
* @nb_of_pixelformats: number of supported umcompressed video formats
* @streamformats: supported compressed video formats
* @nb_of_streamformats: number of supported compressed video formats
* @sfl_reg: status fifo level register value
* @sts_reg: status register value
* @lmi_err_reg: local memory interface error register value
* @emi_err_reg: external memory interface error register value
* @hec_mif_err_reg: HEC memory interface error register value
* @dbg: device debug info
*/
struct hva_dev {
struct v4l2_device v4l2_dev;
struct video_device *vdev;
struct platform_device *pdev;
struct device *dev;
/* mutex protecting vb2_queue structure */
struct mutex lock;
struct v4l2_m2m_dev *m2m_dev;
struct hva_ctx *instances[HVA_MAX_INSTANCES];
unsigned int nb_of_instances;
unsigned int instance_id;
void __iomem *regs;
u32 esram_addr;
u32 esram_size;
struct clk *clk;
int irq_its;
int irq_err;
struct workqueue_struct *work_queue;
/* mutex protecting hardware access */
struct mutex protect_mutex;
struct completion interrupt;
unsigned long int ip_version;
const struct hva_enc *encoders[HVA_MAX_ENCODERS];
u32 nb_of_encoders;
u32 pixelformats[HVA_MAX_FORMATS];
u32 nb_of_pixelformats;
u32 streamformats[HVA_MAX_FORMATS];
u32 nb_of_streamformats;
u32 sfl_reg;
u32 sts_reg;
u32 lmi_err_reg;
u32 emi_err_reg;
u32 hec_mif_err_reg;
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
struct hva_dev_dbg dbg;
#endif
};
/**
* struct hva_enc - hva encoder
*
* @name: encoder name
* @streamformat: fourcc code for compressed video format (H.264...)
* @pixelformat: fourcc code for uncompressed video format
* @max_width: maximum width of frame for this encoder
* @max_height: maximum height of frame for this encoder
* @open: open encoder
* @close: close encoder
* @encode: encode a frame (struct hva_frame) in a stream
* (struct hva_stream)
*/
struct hva_enc {
const char *name;
u32 streamformat;
u32 pixelformat;
u32 max_width;
u32 max_height;
int (*open)(struct hva_ctx *ctx);
int (*close)(struct hva_ctx *ctx);
int (*encode)(struct hva_ctx *ctx, struct hva_frame *frame,
struct hva_stream *stream);
};
#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
void hva_debugfs_create(struct hva_dev *hva);
void hva_debugfs_remove(struct hva_dev *hva);
void hva_dbg_ctx_create(struct hva_ctx *ctx);
void hva_dbg_ctx_remove(struct hva_ctx *ctx);
void hva_dbg_perf_begin(struct hva_ctx *ctx);
void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream);
#endif
#endif /* HVA_H */