build/patch/kernel/rk322x-dev/01-linux-0012-v4l2-from-next-from-list.patch
paolo bd17d4dbd0 Many changes for rk322x target:
- Chanaged default x.org configuration to disable glamor
- Reintroduce patch to use DRM cursor plane as overlay in rk322x-current and -dev
- Updated wifi patches for kernel 5.8.10
- Bumped rk322x to u-boot v2020.07, removed reserved zones from device trees
- Updated OPTEE to v3.10, using ddrbin v1.10
- Bumped rk322x-current to kernel 5.8.y
- Imported new patches from knaerzche's LibreELEC fork for rk322x-dev (kernel 5.8.y)
- Adjusted existing patches to match changes, updated rk322x-dev kernel config file
- Add default modprobe conf file for esp8089 to force the crystal frequency to 40Mhz for rk322x targets
- Removed ssv6051 firmware packages to move to armbian-firmware repository
- Switching ssv6051-wifi.cfg to /lib/firmware for rk322x-legacy
- Removed P2P interface for esp8089 driver for rk322x-legacy
- Optimized ssv6051 performance: kernel module gains -Os flag, disabled p2p interface, enabled HW crypto for CCMP cipher
- Enabled remote control interface, IR GPIO kernel module and HDMI CEC modules
2020-09-19 15:20:16 +00:00

7852 lines
277 KiB
Diff

From 337af64a63b5d8d5a60ad8302cca0bfa4d0cc4ad Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:16 +0200
Subject: [PATCH] media: i2c: Use the new get_mbus_config pad op
Move the existing users of the g_mbus_config video operation to use the
newly introduced get_mbus_config pad operations.
All the ported drivers report a static media bus configuration and do no
support s_mbus_config so the operation implementation has not changed.
Bridge drivers needs to call the new pad operation and will receive an
-ENOICTLCMD when calling the old g_mbus_config video operation
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/i2c/adv7180.c | 7 ++++---
drivers/media/i2c/ml86v7667.c | 7 ++++---
drivers/media/i2c/mt9m001.c | 7 ++++---
drivers/media/i2c/mt9m111.c | 7 ++++---
drivers/media/i2c/ov9640.c | 7 ++++---
drivers/media/i2c/tc358743.c | 7 ++++---
drivers/media/i2c/tvp5150.c | 7 ++++---
7 files changed, 28 insertions(+), 21 deletions(-)
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 00159daa6fcd..e8744efe3cf0 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -760,8 +760,9 @@ static int adv7180_init_cfg(struct v4l2_subdev *sd,
return adv7180_set_pad_format(sd, cfg, &fmt);
}
-static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct adv7180_state *state = to_state(sd);
@@ -852,7 +853,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
- .g_mbus_config = adv7180_g_mbus_config,
.g_pixelaspect = adv7180_g_pixelaspect,
.g_tvnorms = adv7180_g_tvnorms,
.s_stream = adv7180_s_stream,
@@ -869,6 +869,7 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
.enum_mbus_code = adv7180_enum_mbus_code,
.set_fmt = adv7180_set_pad_format,
.get_fmt = adv7180_get_pad_format,
+ .get_mbus_config = adv7180_get_mbus_config,
};
static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = {
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index c444bd6a0658..ff212335326a 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -219,8 +219,9 @@ static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_DATA_ACTIVE_HIGH;
@@ -291,13 +292,13 @@ static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
.s_std = ml86v7667_s_std,
.querystd = ml86v7667_querystd,
.g_input_status = ml86v7667_g_input_status,
- .g_mbus_config = ml86v7667_g_mbus_config,
};
static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = {
.enum_mbus_code = ml86v7667_enum_mbus_code,
.get_fmt = ml86v7667_fill_fmt,
.set_fmt = ml86v7667_fill_fmt,
+ .get_mbus_config = ml86v7667_get_mbus_config,
};
static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c
index 210ea76adb53..3b0ba8ed5233 100644
--- a/drivers/media/i2c/mt9m001.c
+++ b/drivers/media/i2c/mt9m001.c
@@ -689,8 +689,9 @@ static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int mt9m001_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
/* MT9M001 has all capture_format parameters fixed */
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
@@ -703,7 +704,6 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
.s_stream = mt9m001_s_stream,
- .g_mbus_config = mt9m001_g_mbus_config,
};
static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
@@ -717,6 +717,7 @@ static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = {
.set_selection = mt9m001_set_selection,
.get_fmt = mt9m001_get_fmt,
.set_fmt = mt9m001_set_fmt,
+ .get_mbus_config = mt9m001_get_mbus_config,
};
static const struct v4l2_subdev_ops mt9m001_subdev_ops = {
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 17e8253f5748..69697386ffcd 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -1137,8 +1137,9 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
@@ -1155,7 +1156,6 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
- .g_mbus_config = mt9m111_g_mbus_config,
.s_stream = mt9m111_s_stream,
.g_frame_interval = mt9m111_g_frame_interval,
.s_frame_interval = mt9m111_s_frame_interval,
@@ -1168,6 +1168,7 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
.set_selection = mt9m111_set_selection,
.get_fmt = mt9m111_get_fmt,
.set_fmt = mt9m111_set_fmt,
+ .get_mbus_config = mt9m111_get_mbus_config,
};
static const struct v4l2_subdev_ops mt9m111_subdev_ops = {
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index 482609665305..0ef5af026d09 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -648,8 +648,9 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = {
};
/* Request bus settings on camera side */
-static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int ov9640_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
@@ -661,13 +662,13 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov9640_video_ops = {
.s_stream = ov9640_s_stream,
- .g_mbus_config = ov9640_g_mbus_config,
};
static const struct v4l2_subdev_pad_ops ov9640_pad_ops = {
.enum_mbus_code = ov9640_enum_mbus_code,
.get_selection = ov9640_get_selection,
.set_fmt = ov9640_set_fmt,
+ .get_mbus_config = ov9640_get_mbus_config,
};
static const struct v4l2_subdev_ops ov9640_subdev_ops = {
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index dbbab75f135e..a03dcab5ce61 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -1602,8 +1602,9 @@ static int tc358743_dv_timings_cap(struct v4l2_subdev *sd,
return 0;
}
-static int tc358743_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int tc358743_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct tc358743_state *state = to_state(sd);
@@ -1836,7 +1837,6 @@ static const struct v4l2_subdev_video_ops tc358743_video_ops = {
.s_dv_timings = tc358743_s_dv_timings,
.g_dv_timings = tc358743_g_dv_timings,
.query_dv_timings = tc358743_query_dv_timings,
- .g_mbus_config = tc358743_g_mbus_config,
.s_stream = tc358743_s_stream,
};
@@ -1848,6 +1848,7 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = {
.set_edid = tc358743_s_edid,
.enum_dv_timings = tc358743_enum_dv_timings,
.dv_timings_cap = tc358743_dv_timings_cap,
+ .get_mbus_config = tc358743_get_mbus_config,
};
static const struct v4l2_subdev_ops tc358743_ops = {
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 9df575238952..1c2050944b92 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1191,8 +1191,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
}
}
-static int tvp5150_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1721,7 +1722,6 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
.querystd = tvp5150_querystd,
.s_stream = tvp5150_s_stream,
.s_routing = tvp5150_s_routing,
- .g_mbus_config = tvp5150_g_mbus_config,
};
static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1739,6 +1739,7 @@ static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
.get_fmt = tvp5150_fill_fmt,
.get_selection = tvp5150_get_selection,
.set_selection = tvp5150_set_selection,
+ .get_mbus_config = tvp5150_get_mbus_config,
};
static const struct v4l2_subdev_ops tvp5150_ops = {
From 4cc9a9a8b16549358ea377485df8fe21ea9e1bff Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Tue, 21 Jul 2020 09:53:17 +0200
Subject: [PATCH] media: i2c: ov6650: Use new [get|set]_mbus_config ops
Use the new get_mbus_config and set_mbus_config pad operations in place
of the video operations currently in use.
Compared to other drivers where the same conversion has been performed,
ov6650 proved to be a bit more tricky, as the existing g_mbus_config
implementation did not report the currently applied configuration but
the set of all possible configuration options.
Adapt the driver to support the semantic of the two newly introduced
operations:
- get_mbus_config reports the current media bus configuration
- set_mbus_config applies only changes explicitly requested and updates
the provided cfg parameter to report what has actually been applied to
the hardware.
Compile-tested only.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/i2c/ov6650.c | 53 ++++++++++++++++++++++++++------------
1 file changed, 37 insertions(+), 16 deletions(-)
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 91906b94f978..48493af81198 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -921,55 +921,74 @@ static const struct v4l2_subdev_core_ops ov6650_core_ops = {
};
/* Request bus settings on camera side */
-static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int ov6650_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 comj, comf;
+ int ret;
+
+ ret = ov6650_reg_read(client, REG_COMJ, &comj);
+ if (ret)
+ return ret;
- cfg->flags = V4L2_MBUS_MASTER |
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
+ ret = ov6650_reg_read(client, REG_COMF, &comf);
+ if (ret)
+ return ret;
+
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH
+ | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH
+ : V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW
+ : V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING
+ : V4L2_MBUS_PCLK_SAMPLE_FALLING);
cfg->type = V4L2_MBUS_PARALLEL;
return 0;
}
/* Alter bus settings on camera side */
-static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
+static int ov6650_set_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
+ int ret = 0;
if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
- else
+ else if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
if (ret)
return ret;
if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
- else
+ else if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
if (ret)
return ret;
if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
- else
+ else if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
+ if (ret)
+ return ret;
- return ret;
+ /*
+ * Update the configuration to report what is actually applied to
+ * the hardware.
+ */
+ return ov6650_get_mbus_config(sd, pad, cfg);
}
static const struct v4l2_subdev_video_ops ov6650_video_ops = {
.s_stream = ov6650_s_stream,
.g_frame_interval = ov6650_g_frame_interval,
.s_frame_interval = ov6650_s_frame_interval,
- .g_mbus_config = ov6650_g_mbus_config,
- .s_mbus_config = ov6650_s_mbus_config,
};
static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
@@ -978,6 +997,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
.set_selection = ov6650_set_selection,
.get_fmt = ov6650_get_fmt,
.set_fmt = ov6650_set_fmt,
+ .get_mbus_config = ov6650_get_mbus_config,
+ .set_mbus_config = ov6650_set_mbus_config,
};
static const struct v4l2_subdev_ops ov6650_subdev_ops = {
From 9b55924aa37a4ba85f84b8c4e382efffdf2b73df Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:18 +0200
Subject: [PATCH] media: pxa_camera: Use the new set_mbus_config op
Move the PXA camera driver to use the new set_mbus_config pad operation.
For this platform the change is not only cosmetic, as the pxa driver is
currently the only driver in mainline to make use of the g_mbus_config
and s_mbus_config video operations.
The existing driver semantic is the following:
- Collect all supported mbus config flags from the remote end
- Match them with the supported PXA mbus configuration flags
- If the remote subdevice allows multiple options for for VSYNC, HSYNC
and PCLK polarity, use platform data requested settings
The semantic of the new get_mbus_config and set_mbus_config differs from
the corresponding video ops, particularly in the fact get_mbus_config
reports the current mbus configuration and not the set of supported
configuration options, with set_mbus_config always reporting the actual
mbus configuration applied to the remote subdevice.
Adapt the driver to perform the following
- Set the remote subdevice mbus configuration according to the PXA
platform data preferences.
- If the applied configuration differs from the requested one (i.e. the
remote subdevice does not allow changing one setting) make sure that
- The remote end does not claim for DATA_ACTIVE_LOW, which seems not
supported by the platform
- The bus mastering roles match
While at there remove a few checks performed on the media bus
configuration at get_format() time as they do not belong there.
Compile-tested only.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/platform/pxa_camera.c | 189 ++++++++--------------------
1 file changed, 51 insertions(+), 138 deletions(-)
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index 3c5fe737d36f..3a2cd28178da 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc(
return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
}
-static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
- unsigned int flags)
-{
- unsigned long common_flags;
- bool hsync = true, vsync = true, pclk, data, mode;
- bool mipi_lanes, mipi_clock;
-
- common_flags = cfg->flags & flags;
-
- switch (cfg->type) {
- case V4L2_MBUS_PARALLEL:
- hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_LOW);
- vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_VSYNC_ACTIVE_LOW);
- /* fall through */
- case V4L2_MBUS_BT656:
- pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING);
- data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_LOW);
- mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
- return (!hsync || !vsync || !pclk || !data || !mode) ?
- 0 : common_flags;
- case V4L2_MBUS_CSI2_DPHY:
- mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
- mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
- return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
- return 0;
-}
-
/**
* struct pxa_camera_format_xlate - match between host and sensor formats
* @code: code of a sensor provided format
@@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int test_platform_param(struct pxa_camera_dev *pcdev,
- unsigned char buswidth, unsigned long *flags)
-{
- /*
- * Platform specified synchronization and pixel clock polarities are
- * only a recommendation and are only used during probing. The PXA270
- * quick capture interface supports both.
- */
- *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
- V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING;
-
- /* If requested data width is supported by the platform, use it */
- if ((1 << (buswidth - 1)) & pcdev->width_flags)
- return 0;
-
- return -EINVAL;
-}
-
static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev,
unsigned long flags, __u32 pixfmt)
{
@@ -1598,99 +1537,78 @@ static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev)
*/
static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev)
{
+ unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc;
- unsigned long bus_flags, common_flags;
+ int mbus_config;
int ret;
- ret = test_platform_param(pcdev,
- pcdev->current_fmt->host_fmt->bits_per_sample,
- &bus_flags);
- if (ret < 0)
- return ret;
-
- ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = pxa_mbus_config_compatible(&cfg,
- bus_flags);
- if (!common_flags) {
- dev_warn(pcdev_to_dev(pcdev),
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
- cfg.flags, bus_flags);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- } else {
- common_flags = bus_flags;
+ if (!((1 << (bus_width - 1)) & pcdev->width_flags)) {
+ dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u",
+ bus_width);
+ return -EINVAL;
}
pcdev->channels = 1;
/* Make choices, based on platform preferences */
- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_HSP)
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
- }
+ mbus_config = 0;
+ if (pcdev->platform_flags & PXA_CAMERA_MASTER)
+ mbus_config |= V4L2_MBUS_MASTER;
+ else
+ mbus_config |= V4L2_MBUS_SLAVE;
- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_VSP)
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
- }
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+ else
+ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW;
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (pcdev->platform_flags & PXA_CAMERA_PCP)
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
- else
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
- }
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+ else
+ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW;
- cfg.flags = common_flags;
- ret = sensor_call(pcdev, video, s_mbus_config, &cfg);
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING;
+ else
+ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH;
+
+ cfg.flags = mbus_config;
+ ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg);
if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(pcdev_to_dev(pcdev),
- "camera s_mbus_config(0x%lx) returned %d\n",
- common_flags, ret);
+ dev_err(pcdev_to_dev(pcdev),
+ "Failed to call set_mbus_config: %d\n", ret);
return ret;
}
- pxa_camera_setup_cicr(pcdev, common_flags, pixfmt);
-
- return 0;
-}
-
-static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev,
- unsigned char buswidth)
-{
- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
- unsigned long bus_flags, common_flags;
- int ret = test_platform_param(pcdev, buswidth, &bus_flags);
-
- if (ret < 0)
- return ret;
+ /*
+ * If the requested media bus configuration has not been fully applied
+ * make sure it is supported by the platform.
+ *
+ * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering
+ * roles should match.
+ */
+ if (cfg.flags != mbus_config) {
+ unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER |
+ V4L2_MBUS_SLAVE);
+ if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER |
+ V4L2_MBUS_SLAVE))) {
+ dev_err(pcdev_to_dev(pcdev),
+ "Unsupported mbus configuration: bus mastering\n");
+ return -EINVAL;
+ }
- ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = pxa_mbus_config_compatible(&cfg,
- bus_flags);
- if (!common_flags) {
- dev_warn(pcdev_to_dev(pcdev),
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
- cfg.flags, bus_flags);
+ if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) {
+ dev_err(pcdev_to_dev(pcdev),
+ "Unsupported mbus configuration: DATA_ACTIVE_LOW\n");
return -EINVAL;
}
- } else if (ret == -ENOIOCTLCMD) {
- ret = 0;
}
- return ret;
+ pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt);
+
+ return 0;
}
static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = {
@@ -1738,11 +1656,6 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev,
return 0;
}
- /* This also checks support for the requested bits-per-sample */
- ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample);
- if (ret < 0)
- return 0;
-
switch (code.code) {
case MEDIA_BUS_FMT_UYVY8_2X8:
formats++;
From 562b1d8a78c8367d9809491277a6c60441565aa4 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:19 +0200
Subject: [PATCH] media: v4l2-subdev: Remove [s|g]_mbus_config video ops
With all sensor and platform drivers now converted to use the new
get_mbus_config and set_mbus_config pad operations, remove the
deprecated video operations g_mbus_config and s_mbus_config.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
include/media/v4l2-subdev.h | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index f7fe78a6f65a..90098fb1d770 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -402,12 +402,6 @@ struct v4l2_mbus_frame_desc {
*
* @query_dv_timings: callback for VIDIOC_QUERY_DV_TIMINGS() ioctl handler code.
*
- * @g_mbus_config: get supported mediabus configurations
- *
- * @s_mbus_config: set a certain mediabus configuration. This operation is added
- * for compatibility with soc-camera drivers and should not be used by new
- * software.
- *
* @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev
* can adjust @size to a lower value and must not write more data to the
* buffer starting at @data than the original value of @size.
@@ -435,10 +429,6 @@ struct v4l2_subdev_video_ops {
struct v4l2_dv_timings *timings);
int (*query_dv_timings)(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
- int (*g_mbus_config)(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg);
- int (*s_mbus_config)(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg);
int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf,
unsigned int *size);
};
From 1ea27db9eaddf1eb44e533e4baa49b5b3a50900f Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:20 +0200
Subject: [PATCH] media: v4l2- mediabus: Add usage note for V4L2_MBUS_*
With the removal of the legacy g_mbus_config and s_mbus_config video
operations, the sole users of V4L2_MBUS_* flags are now the newly
introduced get_mbus_config and set_mbus_config pad operations.
As the semantic of the new operations differs from the semantic of
the legacy ones, add a usage note in the v4l2-mediabus.h header to
specify how to use the flags.
Also add a TODO note to record that we intend to replace the existing
flags with fields, to prevent users from mixing conflicting values
in a single operation call.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
include/media/v4l2-mediabus.h | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 45f88f0248c4..59b1de197114 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -11,9 +11,34 @@
#include <linux/v4l2-mediabus.h>
#include <linux/bitops.h>
+/*
+ * How to use the V4L2_MBUS_* flags:
+ * Flags are defined for each of the possible states and values of a media
+ * bus configuration parameter. One and only one bit of each group of flags
+ * shall be set by the users of the v4l2_subdev_pad_ops.get_mbus_config and
+ * v4l2_subdev_pad_ops.set_mbus_config operations to ensure that no
+ * conflicting settings are specified when reporting and setting the media bus
+ * configuration with the two operations respectively. For example, it is
+ * invalid to set or clear both the V4L2_MBUS_HSYNC_ACTIVE_HIGH and the
+ * V4L2_MBUS_HSYNC_ACTIVE_LOW flag at the same time. Instead either flag
+ * V4L2_MBUS_HSYNC_ACTIVE_HIGH or flag V4L2_MBUS_HSYNC_ACTIVE_LOW shall be
+ * set. The same is true for the V4L2_MBUS_CSI2_1/2/3/4_LANE flags group: only
+ * one of these four bits shall be set.
+ *
+ * TODO: replace the existing V4L2_MBUS_* flags with structures of fields
+ * to avoid conflicting settings.
+ *
+ * In example:
+ * #define V4L2_MBUS_HSYNC_ACTIVE_HIGH BIT(2)
+ * #define V4L2_MBUS_HSYNC_ACTIVE_LOW BIT(3)
+ * will be replaced by a field whose value reports the intended active state of
+ * the signal:
+ * unsigned int v4l2_mbus_hsync_active : 1;
+ */
+
/* Parallel flags */
/*
- * Can the client run in master or in slave mode. By "Master mode" an operation
+ * The client runs in master or in slave mode. By "Master mode" an operation
* mode is meant, when the client (e.g., a camera sensor) is producing
* horizontal and vertical synchronisation. In "Slave mode" the host is
* providing these signals to the slave.
@@ -45,17 +70,17 @@
#define V4L2_MBUS_DATA_ENABLE_LOW BIT(15)
/* Serial flags */
-/* How many lanes the client can use */
+/* CSI-2 D-PHY number of data lanes. */
#define V4L2_MBUS_CSI2_1_LANE BIT(0)
#define V4L2_MBUS_CSI2_2_LANE BIT(1)
#define V4L2_MBUS_CSI2_3_LANE BIT(2)
#define V4L2_MBUS_CSI2_4_LANE BIT(3)
-/* On which channels it can send video data */
+/* CSI-2 Virtual Channel identifiers. */
#define V4L2_MBUS_CSI2_CHANNEL_0 BIT(4)
#define V4L2_MBUS_CSI2_CHANNEL_1 BIT(5)
#define V4L2_MBUS_CSI2_CHANNEL_2 BIT(6)
#define V4L2_MBUS_CSI2_CHANNEL_3 BIT(7)
-/* Does it support only continuous or also non-continuous clock mode */
+/* Clock non-continuous mode support. */
#define V4L2_MBUS_CSI2_CONTINUOUS_CLOCK BIT(8)
#define V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK BIT(9)
From 9aae063d84435edfb0212c7613f887105dd58009 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:21 +0200
Subject: [PATCH] media: staging: media: imx: Update TODO entry
Update the TODO entry that mentioned a potential use case for the now
removed g_mbus_config video operation.
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/staging/media/imx/TODO | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO
index a371cdedcdb0..9cfc1c1e78dc 100644
--- a/drivers/staging/media/imx/TODO
+++ b/drivers/staging/media/imx/TODO
@@ -10,6 +10,10 @@
driver uses the parsed DT bus config method until this issue is
resolved.
+ 2020-06: g_mbus has been removed in favour of the get_mbus_config pad
+ operation which should be used to avoid parsing the remote endpoint
+ configuration.
+
- This media driver supports inheriting V4L2 controls to the
video capture devices, from the subdevices in the capture device's
pipeline. The controls for each capture device are updated in the
From 33a781840365c6b8a2b86b1c6cb4aaa86941a5d6 Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:22 +0200
Subject: [PATCH] media: i2c: adv748x: Adjust TXA data lanes number
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When outputting SD-Core output through the TXA MIPI CSI-2 interface,
the number of enabled data lanes should be reduced in order to guarantee
that the two video formats produced by the SD-Core (480i and 576i)
generate a MIPI CSI-2 link clock frequency compatible with the MIPI D-PHY
specifications.
Limit the number of enabled data lanes to 2, which is guaranteed to
support 480i and 576i formats.
Cache the number of enabled data lanes to be able to report it through
the new get_mbus_config operation.
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/i2c/adv748x/adv748x-core.c | 31 ++++++++++++++++++------
drivers/media/i2c/adv748x/adv748x.h | 1 +
2 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c
index 23e02ff27b17..1fe7f97c6d52 100644
--- a/drivers/media/i2c/adv748x/adv748x-core.c
+++ b/drivers/media/i2c/adv748x/adv748x-core.c
@@ -241,10 +241,10 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx)
int ret = 0;
/* Enable n-lane MIPI */
- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret);
/* Set Auto DPHY Timing */
- adv748x_write_check(state, page, 0x00, 0xa0 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0xa0 | tx->active_lanes, &ret);
/* ADI Required Write */
if (tx->src == &state->hdmi.sd) {
@@ -270,7 +270,7 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx)
usleep_range(2000, 2500);
/* Power-up CSI-TX */
- adv748x_write_check(state, page, 0x00, 0x20 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0x20 | tx->active_lanes, &ret);
usleep_range(1000, 1500);
/* ADI Required Writes */
@@ -292,7 +292,7 @@ static int adv748x_power_down_tx(struct adv748x_csi2 *tx)
adv748x_write_check(state, page, 0x1e, 0x00, &ret);
/* Enable n-lane MIPI */
- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret);
/* i2c_mipi_pll_en - 1'b1 */
adv748x_write_check(state, page, 0xda, 0x01, &ret);
@@ -357,14 +357,29 @@ static int adv748x_link_setup(struct media_entity *entity,
if (state->afe.tx) {
/* AFE Requires TXA enabled, even when output to TXB */
io10 |= ADV748X_IO_10_CSI4_EN;
- if (is_txa(tx))
+ if (is_txa(tx)) {
+ /*
+ * Output from the SD-core (480i and 576i) from the TXA
+ * interface requires reducing the number of enabled
+ * data lanes in order to guarantee a valid link
+ * frequency.
+ */
+ tx->active_lanes = min(tx->num_lanes, 2U);
io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE;
- else
+ } else {
+ /* TXB has a single data lane, no need to adjust. */
io10 |= ADV748X_IO_10_CSI1_EN;
+ }
}
- if (state->hdmi.tx)
+ if (state->hdmi.tx) {
+ /*
+ * Restore the number of active lanes, in case we have gone
+ * through an AFE->TXA streaming sessions.
+ */
+ tx->active_lanes = tx->num_lanes;
io10 |= ADV748X_IO_10_CSI4_EN;
+ }
return io_clrset(state, ADV748X_IO_10, io10_mask, io10);
}
@@ -596,6 +611,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state,
}
state->txa.num_lanes = num_lanes;
+ state->txa.active_lanes = num_lanes;
adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes);
}
@@ -607,6 +623,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state,
}
state->txb.num_lanes = num_lanes;
+ state->txb.active_lanes = num_lanes;
adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes);
}
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index fccb388ce179..1061f425ece5 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -79,6 +79,7 @@ struct adv748x_csi2 {
unsigned int page;
unsigned int port;
unsigned int num_lanes;
+ unsigned int active_lanes;
struct media_pad pads[ADV748X_CSI2_NR_PADS];
struct v4l2_ctrl_handler ctrl_hdl;
From 5ccfd4f056cc53beef915bd24985449b7d20affc Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:23 +0200
Subject: [PATCH] media: i2c: adv748x: Implement get_mbus_config
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Implement the newly introduced get_mbus_config operation to report the
number of currently used data lanes on the MIPI CSI-2 interface.
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/i2c/adv748x/adv748x-csi2.c | 31 ++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 2091cda50935..99bb63d05eef 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -214,9 +214,40 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
return ret;
}
+static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+
+ if (pad != ADV748X_CSI2_SOURCE)
+ return -EINVAL;
+
+ config->type = V4L2_MBUS_CSI2_DPHY;
+ switch (tx->active_lanes) {
+ case 1:
+ config->flags = V4L2_MBUS_CSI2_1_LANE;
+ break;
+
+ case 2:
+ config->flags = V4L2_MBUS_CSI2_2_LANE;
+ break;
+
+ case 3:
+ config->flags = V4L2_MBUS_CSI2_3_LANE;
+ break;
+
+ case 4:
+ config->flags = V4L2_MBUS_CSI2_4_LANE;
+ break;
+ }
+
+ return 0;
+}
+
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
.get_fmt = adv748x_csi2_get_format,
.set_fmt = adv748x_csi2_set_format,
+ .get_mbus_config = adv748x_csi2_get_mbus_config,
};
/* -----------------------------------------------------------------------------
From a7053f425fb6140bdf72c009cab1730e9d3094af Mon Sep 17 00:00:00 2001
From: Jacopo Mondi <jacopo+renesas@jmondi.org>
Date: Fri, 17 Jul 2020 16:53:24 +0200
Subject: [PATCH] media: rcar-csi2: Negotiate data lanes number
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use the newly introduced get_mbus_config() subdevice pad operation to
retrieve the remote subdevice MIPI CSI-2 bus configuration and configure
the number of active data lanes accordingly.
In order to be able to call the remote subdevice operation cache the
index of the remote pad connected to the single CSI-2 input port.
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/platform/rcar-vin/rcar-csi2.c | 75 +++++++++++++++++++--
1 file changed, 68 insertions(+), 7 deletions(-)
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 151e6a90c5fb..fe99ae00e690 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -363,6 +363,7 @@ struct rcar_csi2 {
struct v4l2_async_notifier notifier;
struct v4l2_async_subdev asd;
struct v4l2_subdev *remote;
+ unsigned int remote_pad;
struct v4l2_mbus_framefmt mf;
@@ -408,13 +409,14 @@ static void rcsi2_exit_standby(struct rcar_csi2 *priv)
reset_control_deassert(priv->rstc);
}
-static int rcsi2_wait_phy_start(struct rcar_csi2 *priv)
+static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
+ unsigned int lanes)
{
unsigned int timeout;
/* Wait for the clock and data lanes to enter LP-11 state. */
for (timeout = 0; timeout <= 20; timeout++) {
- const u32 lane_mask = (1 << priv->lanes) - 1;
+ const u32 lane_mask = (1 << lanes) - 1;
if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) &&
(rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask)
@@ -446,7 +448,8 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
return 0;
}
-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
+static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
+ unsigned int lanes)
{
struct v4l2_subdev *source;
struct v4l2_ctrl *ctrl;
@@ -471,15 +474,64 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
* bps = link_freq * 2
*/
mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp;
- do_div(mbps, priv->lanes * 1000000);
+ do_div(mbps, lanes * 1000000);
return mbps;
}
+static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
+ unsigned int *lanes)
+{
+ struct v4l2_mbus_config mbus_config = { 0 };
+ unsigned int num_lanes = UINT_MAX;
+ int ret;
+
+ *lanes = priv->lanes;
+
+ ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config,
+ priv->remote_pad, &mbus_config);
+ if (ret == -ENOIOCTLCMD) {
+ dev_dbg(priv->dev, "No remote mbus configuration available\n");
+ return 0;
+ }
+
+ if (ret) {
+ dev_err(priv->dev, "Failed to get remote mbus configuration\n");
+ return ret;
+ }
+
+ if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) {
+ dev_err(priv->dev, "Unsupported media bus type %u\n",
+ mbus_config.type);
+ return -EINVAL;
+ }
+
+ if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE)
+ num_lanes = 1;
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE)
+ num_lanes = 2;
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE)
+ num_lanes = 3;
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE)
+ num_lanes = 4;
+
+ if (num_lanes > priv->lanes) {
+ dev_err(priv->dev,
+ "Unsupported mbus config: too many data lanes %u\n",
+ num_lanes);
+ return -EINVAL;
+ }
+
+ *lanes = num_lanes;
+
+ return 0;
+}
+
static int rcsi2_start_receiver(struct rcar_csi2 *priv)
{
const struct rcar_csi2_format *format;
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
+ unsigned int lanes;
unsigned int i;
int mbps, ret;
@@ -521,10 +573,18 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
fld |= FLD_FLD_NUM(1);
}
+ /*
+ * Get the number of active data lanes inspecting the remote mbus
+ * configuration.
+ */
+ ret = rcsi2_get_active_lanes(priv, &lanes);
+ if (ret)
+ return ret;
+
phycnt = PHYCNT_ENABLECLK;
- phycnt |= (1 << priv->lanes) - 1;
+ phycnt |= (1 << lanes) - 1;
- mbps = rcsi2_calc_mbps(priv, format->bpp);
+ mbps = rcsi2_calc_mbps(priv, format->bpp, lanes);
if (mbps < 0)
return mbps;
@@ -571,7 +631,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ);
- ret = rcsi2_wait_phy_start(priv);
+ ret = rcsi2_wait_phy_start(priv, lanes);
if (ret)
return ret;
@@ -748,6 +808,7 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
}
priv->remote = subdev;
+ priv->remote_pad = pad;
dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad);
From ed9092fbdad008ed58e0bd8079b6d6484839d811 Mon Sep 17 00:00:00 2001
From: Dinghao Liu <dinghao.liu@zju.edu.cn>
Date: Sun, 28 Jun 2020 07:55:23 +0200
Subject: [PATCH] media: venus: core: Fix runtime PM imbalance in venus_probe
pm_runtime_get_sync() increments the runtime PM usage counter even
when it returns an error code. Thus a pairing decrement is needed on
the error handling path to keep the counter balanced. For other error
paths after this call, things are the same.
Fix this by adding pm_runtime_put_noidle() after 'err_runtime_disable'
label. But in this case, the error path after pm_runtime_put_sync()
will decrease PM usage counter twice. Thus add an extra
pm_runtime_get_noresume() in this path to balance PM counter.
Signed-off-by: Dinghao Liu <dinghao.liu@zju.edu.cn>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/platform/qcom/venus/core.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 203c6538044f..b0b932bf8c02 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -287,8 +287,10 @@ static int venus_probe(struct platform_device *pdev)
goto err_core_deinit;
ret = pm_runtime_put_sync(dev);
- if (ret)
+ if (ret) {
+ pm_runtime_get_noresume(dev);
goto err_dev_unregister;
+ }
return 0;
@@ -299,6 +301,7 @@ static int venus_probe(struct platform_device *pdev)
err_venus_shutdown:
venus_shutdown(core);
err_runtime_disable:
+ pm_runtime_put_noidle(dev);
pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
hfi_destroy(core);
From 757449d0037dd11f6b783bc31b27c76c5fa636c8 Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@codeaurora.org>
Date: Wed, 29 Jul 2020 09:16:42 +0200
Subject: [PATCH] media: venus: core: Fix error handling in probe
Post a successful pm_ops->core_get, an error in probe
should exit by doing a pm_ops->core_put which seems
to be missing. So fix it.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/platform/qcom/venus/core.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index b0b932bf8c02..321ad77cb6cf 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -224,13 +224,15 @@ static int venus_probe(struct platform_device *pdev)
ret = dma_set_mask_and_coherent(dev, core->res->dma_mask);
if (ret)
- return ret;
+ goto err_core_put;
if (!dev->dma_parms) {
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
GFP_KERNEL);
- if (!dev->dma_parms)
- return -ENOMEM;
+ if (!dev->dma_parms) {
+ ret = -ENOMEM;
+ goto err_core_put;
+ }
}
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
@@ -242,11 +244,11 @@ static int venus_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"venus", core);
if (ret)
- return ret;
+ goto err_core_put;
ret = hfi_create(core, &venus_core_ops);
if (ret)
- return ret;
+ goto err_core_put;
pm_runtime_enable(dev);
@@ -305,6 +307,9 @@ static int venus_probe(struct platform_device *pdev)
pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
hfi_destroy(core);
+err_core_put:
+ if (core->pm_ops->core_put)
+ core->pm_ops->core_put(dev);
return ret;
}
From 207ffb881dd2058c1a86022671817cef37a9d273 Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@codeaurora.org>
Date: Wed, 29 Jul 2020 09:16:43 +0200
Subject: [PATCH] media: venus: core: Add support for opp tables/perf voting
Add support to add OPP tables and perf voting on the OPP powerdomain.
This is needed so venus votes on the corresponding performance state
for the OPP powerdomain along with setting the core clock rate.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/platform/qcom/venus/core.c | 2 +
drivers/media/platform/qcom/venus/core.h | 5 +
.../media/platform/qcom/venus/pm_helpers.c | 92 +++++++++++++++++--
3 files changed, 92 insertions(+), 7 deletions(-)
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 321ad77cb6cf..5fd70f8cf857 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -528,6 +528,7 @@ static const struct venus_resources sdm845_res_v2 = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" },
.vcodec_pmdomains_num = 3,
+ .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 2,
.max_load = 3110400, /* 4096x2160@90 */
.hfi_version = HFI_VERSION_4XX,
@@ -573,6 +574,7 @@ static const struct venus_resources sc7180_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
+ .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_4XX,
.vmem_id = VIDC_RESOURCE_NONE,
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 7118612673c9..b0cc544ad39f 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -62,6 +62,7 @@ struct venus_resources {
unsigned int vcodec_clks_num;
const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX];
unsigned int vcodec_pmdomains_num;
+ const char **opp_pmdomain;
unsigned int vcodec_num;
enum hfi_version hfi_version;
u32 max_load;
@@ -145,8 +146,12 @@ struct venus_core {
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
+ struct opp_table *opp_table;
+ bool has_opp_table;
struct device_link *pd_dl_venus;
struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX];
+ struct device_link *opp_dl_venus;
+ struct device *opp_pmdomain;
struct video_device *vdev_dec;
struct video_device *vdev_enc;
struct v4l2_device v4l2_dev;
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index 531e7a41658f..3127af8985cf 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -9,6 +9,7 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include <media/v4l2-mem2mem.h>
@@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core)
static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
{
- struct clk *clk = core->clks[0];
int ret;
- ret = clk_set_rate(clk, freq);
+ ret = dev_pm_opp_set_rate(core->dev, freq);
if (ret)
return ret;
@@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on)
static int vcodec_domains_get(struct device *dev)
{
+ int ret;
+ struct opp_table *opp_table;
+ struct device **opp_virt_dev;
struct venus_core *core = dev_get_drvdata(dev);
const struct venus_resources *res = core->res;
struct device *pd;
unsigned int i;
if (!res->vcodec_pmdomains_num)
- return -ENODEV;
+ goto skip_pmdomains;
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
pd = dev_pm_domain_attach_by_name(dev,
@@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev)
if (!core->pd_dl_venus)
return -ENODEV;
+skip_pmdomains:
+ if (!core->has_opp_table)
+ return 0;
+
+ /* Attach the power domain for setting performance state */
+ opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
+ if (IS_ERR(opp_table)) {
+ ret = PTR_ERR(opp_table);
+ goto opp_attach_err;
+ }
+
+ core->opp_pmdomain = *opp_virt_dev;
+ core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
+ DL_FLAG_RPM_ACTIVE |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_STATELESS);
+ if (!core->opp_dl_venus) {
+ ret = -ENODEV;
+ goto opp_dl_add_err;
+ }
+
return 0;
+
+opp_dl_add_err:
+ dev_pm_domain_detach(core->opp_pmdomain, true);
+opp_attach_err:
+ if (core->pd_dl_venus) {
+ device_link_del(core->pd_dl_venus);
+ for (i = 0; i < res->vcodec_pmdomains_num; i++) {
+ if (IS_ERR_OR_NULL(core->pmdomains[i]))
+ continue;
+ dev_pm_domain_detach(core->pmdomains[i], true);
+ }
+ }
+ return ret;
}
static void vcodec_domains_put(struct device *dev)
@@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev)
unsigned int i;
if (!res->vcodec_pmdomains_num)
- return;
+ goto skip_pmdomains;
if (core->pd_dl_venus)
device_link_del(core->pd_dl_venus);
@@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev)
continue;
dev_pm_domain_detach(core->pmdomains[i], true);
}
+
+skip_pmdomains:
+ if (!core->has_opp_table)
+ return;
+
+ if (core->opp_dl_venus)
+ device_link_del(core->opp_dl_venus);
+
+ dev_pm_domain_detach(core->opp_pmdomain, true);
}
static int core_get_v4(struct device *dev)
@@ -815,19 +861,46 @@ static int core_get_v4(struct device *dev)
if (legacy_binding)
return 0;
+ core->opp_table = dev_pm_opp_set_clkname(dev, "core");
+ if (IS_ERR(core->opp_table))
+ return PTR_ERR(core->opp_table);
+
+ if (core->res->opp_pmdomain) {
+ ret = dev_pm_opp_of_add_table(dev);
+ if (!ret) {
+ core->has_opp_table = true;
+ } else if (ret != -ENODEV) {
+ dev_err(dev, "invalid OPP table in device tree\n");
+ dev_pm_opp_put_clkname(core->opp_table);
+ return ret;
+ }
+ }
+
ret = vcodec_domains_get(dev);
- if (ret)
+ if (ret) {
+ if (core->has_opp_table)
+ dev_pm_opp_of_remove_table(dev);
+ dev_pm_opp_put_clkname(core->opp_table);
return ret;
+ }
return 0;
}
static void core_put_v4(struct device *dev)
{
+ struct venus_core *core = dev_get_drvdata(dev);
+
if (legacy_binding)
return;
vcodec_domains_put(dev);
+
+ if (core->has_opp_table)
+ dev_pm_opp_of_remove_table(dev);
+ if (core->opp_table)
+ dev_pm_opp_put_clkname(core->opp_table);
+
}
static int core_power_v4(struct device *dev, int on)
@@ -835,10 +908,15 @@ static int core_power_v4(struct device *dev, int on)
struct venus_core *core = dev_get_drvdata(dev);
int ret = 0;
- if (on == POWER_ON)
+ if (on == POWER_ON) {
ret = core_clks_enable(core);
- else
+ } else {
+ /* Drop the performance state vote */
+ if (core->opp_pmdomain)
+ dev_pm_opp_set_rate(dev, 0);
+
core_clks_disable(core);
+ }
return ret;
}
From 3bf1ba10b6ac9cfff7ecd329c38dc31213e88ce1 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Mon, 27 Jul 2020 14:05:37 -0300
Subject: [PATCH] hantro: h264: Get the correct fallback reference buffer
If the bitstream and the application are incorrectly configuring
the reference pictures, the hardware will need to fallback
to using some other reference picture.
When the post-processor is enabled, the fallback buffer
should be a shadow buffer (postproc.dec_q), and not a
CAPTURE queue buffer, since the latter is post-processed
and not really the output of the decoder core.
Fixes: 8c2d66b036c77 ("media: hantro: Support color conversion via post-processing")
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/hantro/hantro_h264.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
index 194d05848077..6dcd47bd9ed3 100644
--- a/drivers/staging/media/hantro/hantro_h264.c
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -325,7 +325,7 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx,
*/
dst_buf = hantro_get_dst_buf(ctx);
buf = &dst_buf->vb2_buf;
- dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0);
+ dma_addr = hantro_get_dec_buf_addr(ctx, buf);
}
return dma_addr;
From 28bebe4b9396ef9d2e4ae2a179abdb840ceddb03 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Mon, 27 Jul 2020 14:05:38 -0300
Subject: [PATCH] hantro: postproc: Fix motion vector space allocation
When the post-processor is enabled, the driver allocates
"shadow buffers" which are used for the decoder core,
and exposes the post-processed buffers to userspace.
For this reason, extra motion vector space has to
be allocated on the shadow buffers, which the driver
wasn't doing. Fix it.
This fix should address artifacts on high profile bitstreams.
Fixes: 8c2d66b036c77 ("media: hantro: Support color conversion via post-processing")
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/hantro/hantro_postproc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c
index 44062ffceaea..6d2a8f2a8f0b 100644
--- a/drivers/staging/media/hantro/hantro_postproc.c
+++ b/drivers/staging/media/hantro/hantro_postproc.c
@@ -118,7 +118,9 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx)
unsigned int num_buffers = cap_queue->num_buffers;
unsigned int i, buf_size;
- buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage;
+ buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage +
+ hantro_h264_mv_size(ctx->dst_fmt.width,
+ ctx->dst_fmt.height);
for (i = 0; i < num_buffers; ++i) {
struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i];
From be1ec3a445d13ab0bac45fd84edb30a11a2c0b8c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 14 Aug 2020 10:36:16 -0300
Subject: [PATCH] media: uapi: h264: Update reference lists
When dealing with with interlaced frames, reference lists must tell if
each particular reference is meant for top or bottom field. This info
is currently not provided at all in the H264 related controls.
Make reference lists hold a structure which will also hold an
enumerator type along index into DPB array. The enumerator must
be used to specify if reference is for top or bottom field.
Currently the only user of these lists is Cedrus which is just compile
fixed here. Actual usage of will come in a following commit.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
.../media/v4l/ext-ctrls-codec.rst | 44 ++++++++++++++++++-
.../staging/media/sunxi/cedrus/cedrus_h264.c | 6 +--
include/media/h264-ctrls.h | 23 +++++++---
3 files changed, 62 insertions(+), 11 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index d0d506a444b1..b9b2617c3bda 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1843,10 +1843,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - __u32
- ``slice_group_change_cycle``
-
- * - __u8
+ * - struct :c:type:`v4l2_h264_reference`
- ``ref_pic_list0[32]``
- Reference picture list after applying the per-slice modifications
- * - __u8
+ * - struct :c:type:`v4l2_h264_reference`
- ``ref_pic_list1[32]``
- Reference picture list after applying the per-slice modifications
* - __u32
@@ -1926,6 +1926,46 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
- ``chroma_offset[32][2]``
-
+``Picture Reference``
+
+.. c:type:: v4l2_h264_reference
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_h264_reference
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - enum :c:type:`v4l2_h264_field_reference`
+ - ``reference``
+ - Specifies how the picture is referenced.
+ * - __u8
+ - ``index``
+ - Index into the :c:type:`v4l2_ctrl_h264_decode_params`.dpb array.
+
+.. c:type:: v4l2_h264_field_reference
+
+.. cssclass:: longtable
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - ``V4L2_H264_TOP_FIELD_REF``
+ - 0x1
+ - The top field in field pair is used for
+ short-term reference.
+ * - ``V4L2_H264_BOTTOM_FIELD_REF``
+ - 0x2
+ - The bottom field in field pair is used for
+ short-term reference.
+ * - ``V4L2_H264_FRAME_REF``
+ - 0x3
+ - The frame (or the top/bottom fields, if it's a field pair)
+ is used for short-term reference.
+
``V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (struct)``
Specifies the decode parameters (as extracted from the bitstream)
for the associated H264 slice data. This includes the necessary
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index 54ee2aa423e2..cce527bbdf86 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -166,8 +166,8 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
struct cedrus_run *run,
- const u8 *ref_list, u8 num_ref,
- enum cedrus_h264_sram_off sram)
+ const struct v4l2_h264_reference *ref_list,
+ u8 num_ref, enum cedrus_h264_sram_off sram)
{
const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
struct vb2_queue *cap_q;
@@ -188,7 +188,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
int buf_idx;
u8 dpb_idx;
- dpb_idx = ref_list[i];
+ dpb_idx = ref_list[i].index;
dpb = &decode->dpb[dpb_idx];
if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index 080fd1293c42..5f635e8d25e2 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -19,6 +19,8 @@
*/
#define V4L2_H264_NUM_DPB_ENTRIES 16
+#define V4L2_H264_REF_LIST_LEN (2 * V4L2_H264_NUM_DPB_ENTRIES)
+
/* Our pixel format isn't stable at the moment */
#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */
@@ -140,6 +142,19 @@ struct v4l2_h264_pred_weight_table {
#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04
#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08
+enum v4l2_h264_field_reference {
+ V4L2_H264_TOP_FIELD_REF = 0x1,
+ V4L2_H264_BOTTOM_FIELD_REF = 0x2,
+ V4L2_H264_FRAME_REF = 0x3,
+};
+
+struct v4l2_h264_reference {
+ enum v4l2_h264_field_reference fields;
+
+ /* Index into v4l2_ctrl_h264_decode_params.dpb[] */
+ __u8 index;
+};
+
struct v4l2_ctrl_h264_slice_params {
/* Size in bytes, including header */
__u32 size;
@@ -178,12 +193,8 @@ struct v4l2_ctrl_h264_slice_params {
__u8 num_ref_idx_l1_active_minus1;
__u32 slice_group_change_cycle;
- /*
- * Entries on each list are indices into
- * v4l2_ctrl_h264_decode_params.dpb[].
- */
- __u8 ref_pic_list0[32];
- __u8 ref_pic_list1[32];
+ struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN];
+ struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN];
__u32 flags;
};
From 9e30508e5834c1a37aa07836bf7fc78f96559f82 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:17 -0300
Subject: [PATCH] media: uapi: h264: Further clarify scaling lists order
Commit 0b0393d59eb4a ("media: uapi: h264: clarify
expected scaling_list_4x4/8x8 order") improved the
documentation on H264 scaling lists order.
This commit improves the documentation by clarifying
that the lists themselves are expected in raster scan order.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index b9b2617c3bda..694037ce888a 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1725,12 +1725,14 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
- ``scaling_list_4x4[6][16]``
- Scaling matrix after applying the inverse scanning process.
Expected list order is Intra Y, Intra Cb, Intra Cr, Inter Y,
- Inter Cb, Inter Cr.
+ Inter Cb, Inter Cr. The values on each scaling list are
+ expected in raster scan order.
* - __u8
- ``scaling_list_8x8[6][64]``
- Scaling matrix after applying the inverse scanning process.
Expected list order is Intra Y, Inter Y, Intra Cb, Inter Cb,
- Intra Cr, Inter Cr.
+ Intra Cr, Inter Cr. The values on each scaling list are
+ expected in raster scan order.
``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (struct)``
Specifies the slice parameters (as extracted from the bitstream)
From da0e200cf7bd3c42b97c8fa8e941a756ffdbfb26 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:18 -0300
Subject: [PATCH] media: uapi: h264: Split prediction weight parameters
The prediction weight parameters are only required under
certain conditions, which depend on slice header parameters.
As specified in section 7.3.3 Slice header syntax, the prediction
weight table is present if:
((weighted_pred_flag && (slice_type == P || slice_type == SP)) || \
(weighted_bipred_idc == 1 && slice_type == B))
Given its size, it makes sense to move this table to its control,
so applications can avoid passing it if the slice doesn't specify it.
Before this change struct v4l2_ctrl_h264_slice_params was 960 bytes.
With this change, it's 188 bytes and struct v4l2_ctrl_h264_pred_weight
is 772 bytes.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
.../media/v4l/ext-ctrls-codec.rst | 19 ++++++++++++-------
drivers/media/v4l2-core/v4l2-ctrls.c | 8 ++++++++
drivers/staging/media/sunxi/cedrus/cedrus.c | 7 +++++++
drivers/staging/media/sunxi/cedrus/cedrus.h | 1 +
.../staging/media/sunxi/cedrus/cedrus_dec.c | 2 ++
.../staging/media/sunxi/cedrus/cedrus_h264.c | 12 +++---------
include/media/h264-ctrls.h | 12 ++++++++++--
include/media/v4l2-ctrls.h | 2 ++
8 files changed, 45 insertions(+), 18 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 694037ce888a..ddf9c6af7d0a 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1879,18 +1879,23 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
- 0x00000008
-
-``Prediction Weight Table``
+``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)``
+ Prediction weight table defined according to :ref:`h264`,
+ section 7.4.3.2 "Prediction Weight Table Semantics".
+ The prediction weight table must be passed by applications
+ under the conditions explained in section 7.3.3 "Slice header
+ syntax".
- The bitstream parameters are defined according to :ref:`h264`,
- section 7.4.3.2 "Prediction Weight Table Semantics". For further
- documentation, refer to the above specification, unless there is
- an explicit comment stating otherwise.
+ .. note::
+
+ This compound control is not yet part of the public kernel API and
+ it is expected to change.
-.. c:type:: v4l2_h264_pred_weight_table
+.. c:type:: v4l2_ctrl_h264_pred_weights
.. cssclass:: longtable
-.. flat-table:: struct v4l2_h264_pred_weight_table
+.. flat-table:: struct v4l2_ctrl_h264_pred_weights
:header-rows: 0
:stub-columns: 0
:widths: 1 1 2
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 3f3fbcd60cc6..76c8dc8fb31c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -897,6 +897,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters";
case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: return "H264 Decode Mode";
case V4L2_CID_MPEG_VIDEO_H264_START_CODE: return "H264 Start Code";
+ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table";
case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level";
case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile";
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value";
@@ -1412,6 +1413,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS:
*type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
break;
+ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS:
+ *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS;
+ break;
case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER:
*type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER;
break;
@@ -1790,6 +1794,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
case V4L2_CTRL_TYPE_H264_SPS:
case V4L2_CTRL_TYPE_H264_PPS:
case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
break;
@@ -2553,6 +2558,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
elem_size = sizeof(struct v4l2_ctrl_h264_decode_params);
break;
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
+ break;
case V4L2_CTRL_TYPE_VP8_FRAME_HEADER:
elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header);
break;
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index bc27f9430eeb..826324faad7e 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -78,6 +78,13 @@ static const struct cedrus_control cedrus_controls[] = {
.codec = CEDRUS_CODEC_H264,
.required = true,
},
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS,
+ },
+ .codec = CEDRUS_CODEC_H264,
+ .required = false,
+ },
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h
index 96765555ab8a..93c843ae14bb 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -62,6 +62,7 @@ struct cedrus_h264_run {
const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
const struct v4l2_ctrl_h264_slice_params *slice_params;
const struct v4l2_ctrl_h264_sps *sps;
+ const struct v4l2_ctrl_h264_pred_weights *pred_weights;
};
struct cedrus_mpeg2_run {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
index 58c48e4fdfe9..6385026d1b6b 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -57,6 +57,8 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS);
run.h264.sps = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_H264_SPS);
+ run.h264.pred_weights = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS);
break;
case V4L2_PIX_FMT_HEVC_SLICE:
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index cce527bbdf86..d5636dbbb622 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -256,10 +256,8 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx,
static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
- const struct v4l2_ctrl_h264_slice_params *slice =
- run->h264.slice_params;
- const struct v4l2_h264_pred_weight_table *pred_weight =
- &slice->pred_weight_table;
+ const struct v4l2_ctrl_h264_pred_weights *pred_weight =
+ run->h264.pred_weights;
struct cedrus_dev *dev = ctx->dev;
int i, j, k;
@@ -367,11 +365,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
cedrus_skip_bits(dev, slice->header_bit_size);
- if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) &&
- (slice->slice_type == V4L2_H264_SLICE_TYPE_P ||
- slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) ||
- (pps->weighted_bipred_idc == 1 &&
- slice->slice_type == V4L2_H264_SLICE_TYPE_B))
+ if (V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice))
cedrus_write_pred_weight_table(ctx, run);
if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) ||
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index 5f635e8d25e2..d995614be159 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -36,6 +36,7 @@
#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004)
#define V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (V4L2_CID_MPEG_BASE+1005)
#define V4L2_CID_MPEG_VIDEO_H264_START_CODE (V4L2_CID_MPEG_BASE+1006)
+#define V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (V4L2_CID_MPEG_BASE+1007)
/* enum v4l2_ctrl_type type values */
#define V4L2_CTRL_TYPE_H264_SPS 0x0110
@@ -43,6 +44,7 @@
#define V4L2_CTRL_TYPE_H264_SCALING_MATRIX 0x0112
#define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113
#define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114
+#define V4L2_CTRL_TYPE_H264_PRED_WEIGHTS 0x0115
enum v4l2_mpeg_video_h264_decode_mode {
V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED,
@@ -125,7 +127,14 @@ struct v4l2_h264_weight_factors {
__s16 chroma_offset[32][2];
};
-struct v4l2_h264_pred_weight_table {
+#define V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(pps, slice) \
+ ((((pps)->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && \
+ ((slice)->slice_type == V4L2_H264_SLICE_TYPE_P || \
+ (slice)->slice_type == V4L2_H264_SLICE_TYPE_SP)) || \
+ ((pps)->weighted_bipred_idc == 1 && \
+ (slice)->slice_type == V4L2_H264_SLICE_TYPE_B))
+
+struct v4l2_ctrl_h264_pred_weights {
__u16 luma_log2_weight_denom;
__u16 chroma_log2_weight_denom;
struct v4l2_h264_weight_factors weight_factors[2];
@@ -177,7 +186,6 @@ struct v4l2_ctrl_h264_slice_params {
__s32 delta_pic_order_cnt0;
__s32 delta_pic_order_cnt1;
- struct v4l2_h264_pred_weight_table pred_weight_table;
/* Size in bits of dec_ref_pic_marking() syntax element. */
__u32 dec_ref_pic_marking_bit_size;
/* Size in bits of pic order count syntax. */
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index f40e2cbb21d3..cb25f345e9ad 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -51,6 +51,7 @@ struct video_device;
* @p_h264_scaling_matrix: Pointer to a struct v4l2_ctrl_h264_scaling_matrix.
* @p_h264_slice_params: Pointer to a struct v4l2_ctrl_h264_slice_params.
* @p_h264_decode_params: Pointer to a struct v4l2_ctrl_h264_decode_params.
+ * @p_h264_pred_weights: Pointer to a struct v4l2_ctrl_h264_pred_weights.
* @p_vp8_frame_header: Pointer to a VP8 frame header structure.
* @p_hevc_sps: Pointer to an HEVC sequence parameter set structure.
* @p_hevc_pps: Pointer to an HEVC picture parameter set structure.
@@ -74,6 +75,7 @@ union v4l2_ctrl_ptr {
struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix;
struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
struct v4l2_ctrl_h264_decode_params *p_h264_decode_params;
+ struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header;
struct v4l2_ctrl_hevc_sps *p_hevc_sps;
struct v4l2_ctrl_hevc_pps *p_hevc_pps;
From 82c12e79f57d0b51b81efb2bb87a91288988d958 Mon Sep 17 00:00:00 2001
From: Philipp Zabel <p.zabel@pengutronix.de>
Date: Fri, 14 Aug 2020 10:36:19 -0300
Subject: [PATCH] media: uapi: h264: Clarify pic_order_cnt_bit_size field
Since pic_order_cnt_bit_size is not a syntax element itself, explicitly
state that it is the total size in bits of the pic_order_cnt_lsb,
delta_pic_order_cnt_bottom, delta_pic_order_cnt[0], and
delta_pic_order_cnt[1] syntax elements contained in the slice.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
[Ezequiel: rebase]
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index ddf9c6af7d0a..32f3cebf16e5 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1815,7 +1815,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
- Size in bits of the dec_ref_pic_marking() syntax element.
* - __u32
- ``pic_order_cnt_bit_size``
- -
+ - Combined size in bits of the picture order count related syntax
+ elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom,
+ delta_pic_order_cnt0, and delta_pic_order_cnt1.
* - __u8
- ``cabac_init_idc``
-
From fced897398d6228473f01df99fd09fd4410f623d Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:20 -0300
Subject: [PATCH] media: uapi: h264: Increase size of 'first_mb_in_slice' field
Slice header syntax element 'first_mb_in_slice' can point
to the last macroblock, currently the field can only reference
65536 macroblocks which is insufficient for 8K videos.
Although unlikely, a 8192x4320 video (where macroblocks are 16x16),
would contain 138240 macroblocks on a frame.
As per the H264 specification, 'first_mb_in_slice' can be up to
PicSizeInMbs - 1, so increase the size of the field to 32-bits.
Note that v4l2_ctrl_h264_slice_params struct will be modified
in a follow-up commit, and so we defer its 64-bit padding.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 2 +-
include/media/h264-ctrls.h | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 32f3cebf16e5..714a8d9ae6a0 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1774,7 +1774,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - __u32
- ``header_bit_size``
-
- * - __u16
+ * - __u32
- ``first_mb_in_slice``
-
* - __u8
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index d995614be159..9ff085fdc9ab 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -174,7 +174,8 @@ struct v4l2_ctrl_h264_slice_params {
/* Offset in bits to slice_data() from the beginning of this slice. */
__u32 header_bit_size;
- __u16 first_mb_in_slice;
+ __u32 first_mb_in_slice;
+
__u8 slice_type;
__u8 pic_parameter_set_id;
__u8 colour_plane_id;
From 52266e3675e9359f13aa4d44a4ab392fd1f079c0 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:21 -0300
Subject: [PATCH] media: uapi: h264: Clean DPB entry interface
As discussed recently, the current interface for the
Decoded Picture Buffer is not enough to properly
support field coding.
This commit introduces enough semantics to support
frame and field coding, and to signal how DPB entries
are "used for reference".
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
.../media/v4l/ext-ctrls-codec.rst | 24 ++++++-------------
drivers/media/v4l2-core/v4l2-h264.c | 4 ++--
drivers/staging/media/rkvdec/rkvdec-h264.c | 17 ++++++-------
include/media/h264-ctrls.h | 2 +-
4 files changed, 19 insertions(+), 28 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 714a8d9ae6a0..d14da8325382 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -2063,6 +2063,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - __s32
- ``bottom_field_order_cnt``
-
+ * - enum :c:type:`v4l2_h264_field_reference`
+ - ``reference``
+ - Specifies how the DPB entry is referenced.
* - __u32
- ``flags``
- See :ref:`DPB Entry Flags <h264_dpb_flags>`
@@ -2080,29 +2083,16 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - ``V4L2_H264_DPB_ENTRY_FLAG_VALID``
- 0x00000001
- - The DPB entry is valid and should be considered
+ - The DPB entry is valid (non-empty) and should be considered.
* - ``V4L2_H264_DPB_ENTRY_FLAG_ACTIVE``
- 0x00000002
- - The DPB entry is currently being used as a reference frame
+ - The DPB entry is used for reference.
* - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM``
- 0x00000004
- - The DPB entry is a long term reference frame
+ - The DPB entry is used for long-term reference.
* - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD``
- 0x00000008
- - The DPB entry is a field reference, which means only one of the field
- will be used when decoding the new frame/field. When not set the DPB
- entry is a frame reference (both fields will be used). Note that this
- flag does not say anything about the number of fields contained in the
- reference frame, it just describes the one used to decode the new
- field/frame
- * - ``V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD``
- - 0x00000010
- - The DPB entry is a bottom field reference (only the bottom field of the
- reference frame is needed to decode the new frame/field). Only valid if
- V4L2_H264_DPB_ENTRY_FLAG_FIELD is set. When
- V4L2_H264_DPB_ENTRY_FLAG_FIELD is set but
- V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD is not, that means the
- DPB entry is a top field reference
+ - The DPB entry is a single field or a complementary field pair.
``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)``
Specifies the decoding mode to use. Currently exposes slice-based and
diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c
index edf6225f0522..12b751c09016 100644
--- a/drivers/media/v4l2-core/v4l2-h264.c
+++ b/drivers/media/v4l2-core/v4l2-h264.c
@@ -66,10 +66,10 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
else
b->refs[i].frame_num = dpb[i].frame_num;
- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD))
+ if (dpb[i].reference == V4L2_H264_FRAME_REF)
pic_order_count = min(dpb[i].top_field_order_cnt,
dpb[i].bottom_field_order_cnt);
- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD)
+ else if (dpb[i].reference & V4L2_H264_BOTTOM_FIELD_REF)
pic_order_count = dpb[i].bottom_field_order_cnt;
else
pic_order_count = dpb[i].top_field_order_cnt;
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 7b66e2743a4f..07a80e9a9df2 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -949,16 +949,17 @@ static void config_registers(struct rkvdec_ctx *ctx,
for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
- refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0) |
- RKVDEC_COLMV_USED_FLAG_REF;
+ refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD))
- refer_addr |= RKVDEC_TOPFIELD_USED_REF |
- RKVDEC_BOTFIELD_USED_REF;
- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD)
- refer_addr |= RKVDEC_BOTFIELD_USED_REF;
- else
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
+ refer_addr |= RKVDEC_COLMV_USED_FLAG_REF;
+ if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)
+ refer_addr |= RKVDEC_FIELD_REF;
+
+ if (dpb[i].reference & V4L2_H264_TOP_FIELD_REF)
refer_addr |= RKVDEC_TOPFIELD_USED_REF;
+ if (dpb[i].reference & V4L2_H264_BOTTOM_FIELD_REF)
+ refer_addr |= RKVDEC_BOTFIELD_USED_REF;
writel_relaxed(dpb[i].top_field_order_cnt,
rkvdec->regs + poc_reg_tbl_top_field[i]);
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index 9ff085fdc9ab..4447697e9465 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -212,7 +212,6 @@ struct v4l2_ctrl_h264_slice_params {
#define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02
#define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04
#define V4L2_H264_DPB_ENTRY_FLAG_FIELD 0x08
-#define V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD 0x10
struct v4l2_h264_dpb_entry {
__u64 reference_ts;
@@ -221,6 +220,7 @@ struct v4l2_h264_dpb_entry {
/* Note that field is indicated by v4l2_buffer.field */
__s32 top_field_order_cnt;
__s32 bottom_field_order_cnt;
+ enum v4l2_h264_field_reference reference;
__u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */
};
From cd2980d0ab75400656f854ac48a147ef07b9f9ba Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:22 -0300
Subject: [PATCH] media: uapi: h264: Increase size of DPB entry pic_num
DPB entry PicNum maximum value is 2*MaxFrameNum for interlaced
content (field_pic_flag=1).
As specified, MaxFrameNum is 2^(log2_max_frame_num_minus4 + 4)
and log2_max_frame_num_minus4 is in the range of 0 to 12,
which means pic_num should be a 32-bit field.
The v4l2_h264_dpb_entry struct needs to be padded to avoid a hole,
which might be also useful to allow future uAPI extensions.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
.../userspace-api/media/v4l/ext-ctrls-codec.rst | 5 ++++-
drivers/media/v4l2-core/v4l2-ctrls.c | 13 +++++++++++++
include/media/h264-ctrls.h | 3 ++-
include/media/v4l2-h264.h | 2 +-
4 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index d14da8325382..c0ae7fda803e 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -2054,7 +2054,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - __u16
- ``frame_num``
-
- * - __u16
+ * - __u8
+ - ``reserved[2]``
+ - Applications and drivers must set this to zero.
+ * - __u32
- ``pic_num``
-
* - __s32
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 76c8dc8fb31c..b9457789fa55 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1725,6 +1725,8 @@ static void std_log(const struct v4l2_ctrl *ctrl)
#define zero_padding(s) \
memset(&(s).padding, 0, sizeof((s).padding))
+#define zero_reserved(s) \
+ memset(&(s).reserved, 0, sizeof((s).reserved))
/*
* Compound controls validation requires setting unused fields/flags to zero
@@ -1735,6 +1737,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
{
struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header;
+ struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
struct v4l2_ctrl_hevc_sps *p_hevc_sps;
struct v4l2_ctrl_hevc_pps *p_hevc_pps;
struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
@@ -1796,7 +1799,17 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ break;
+
case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+ p_h264_dec_params = p;
+
+ for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
+ struct v4l2_h264_dpb_entry *dpb_entry =
+ &p_h264_dec_params->dpb[i];
+
+ zero_reserved(*dpb_entry);
+ }
break;
case V4L2_CTRL_TYPE_VP8_FRAME_HEADER:
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index 4447697e9465..d178d7ad53b6 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -216,7 +216,8 @@ struct v4l2_ctrl_h264_slice_params {
struct v4l2_h264_dpb_entry {
__u64 reference_ts;
__u16 frame_num;
- __u16 pic_num;
+ __u8 reserved[2];
+ __u32 pic_num;
/* Note that field is indicated by v4l2_buffer.field */
__s32 top_field_order_cnt;
__s32 bottom_field_order_cnt;
diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h
index bc9ebb560ccf..1a5f26fc2a9a 100644
--- a/include/media/v4l2-h264.h
+++ b/include/media/v4l2-h264.h
@@ -33,7 +33,7 @@ struct v4l2_h264_reflist_builder {
struct {
s32 pic_order_count;
int frame_num;
- u16 pic_num;
+ u32 pic_num;
u16 longterm : 1;
} refs[V4L2_H264_NUM_DPB_ENTRIES];
s32 cur_pic_order_count;
From c380a6c41ab18183ff5d6342d8dc6cf7f22e6ed5 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:23 -0300
Subject: [PATCH] media: uapi: h264: Drop SLICE_PARAMS 'size' field
The SLICE_PARAMS control is intended for slice-based
devices. In this mode, the OUTPUT buffer contains
a single slice, and so the buffer's plane payload size
can be used to query the slice size.
To reduce the API surface drop the size from the
SLICE_PARAMS control.
A follow-up change will remove other members in SLICE_PARAMS
so we don't need to add padding fields here.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 3 ---
drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 7 +++----
include/media/h264-ctrls.h | 3 ---
3 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index c0ae7fda803e..e88c207d945b 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1760,9 +1760,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
:stub-columns: 0
:widths: 1 1 2
- * - __u32
- - ``size``
- -
* - __u32
- ``start_byte_offset``
Offset (in bytes) from the beginning of the OUTPUT buffer to the start
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index d5636dbbb622..7d9bd5860a1b 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -324,17 +324,16 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
struct vb2_buffer *src_buf = &run->src->vb2_buf;
struct cedrus_dev *dev = ctx->dev;
dma_addr_t src_buf_addr;
- u32 len = slice->size * 8;
+ size_t slice_bytes = vb2_get_plane_payload(src_buf, 0);
unsigned int pic_width_in_mbs;
bool mbaff_pic;
u32 reg;
- cedrus_write(dev, VE_H264_VLD_LEN, len);
+ cedrus_write(dev, VE_H264_VLD_LEN, slice_bytes * 8);
cedrus_write(dev, VE_H264_VLD_OFFSET, 0);
src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- cedrus_write(dev, VE_H264_VLD_END,
- src_buf_addr + vb2_get_plane_payload(src_buf, 0));
+ cedrus_write(dev, VE_H264_VLD_END, src_buf_addr + slice_bytes);
cedrus_write(dev, VE_H264_VLD_ADDR,
VE_H264_VLD_ADDR_VAL(src_buf_addr) |
VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index d178d7ad53b6..afcae3052085 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -165,9 +165,6 @@ struct v4l2_h264_reference {
};
struct v4l2_ctrl_h264_slice_params {
- /* Size in bytes, including header */
- __u32 size;
-
/* Offset in bytes to the start of slice in the OUTPUT buffer. */
__u32 start_byte_offset;
From 37293295255bb5ad4063fe1ca6945a6890c65cd4 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:24 -0300
Subject: [PATCH] media: uapi: h264: Clarify SLICE_BASED mode
Currently, the SLICE_BASED and FRAME_BASED modes documentation
is misleading and not matching the intended use-cases.
Drop non-required fields SLICE_PARAMS 'start_byte_offset' and
DECODE_PARAMS 'num_slices' and clarify the decoding modes in the
documentation.
On SLICE_BASED mode, a single slice is expected per OUTPUT buffer,
and therefore 'start_byte_offset' is not needed (since the offset
to the slice is the start of the buffer).
This mode requires the use of CAPTURE buffer holding, and so
the number of slices shall not be required.
On FRAME_BASED mode, the devices are expected to take care of slice
parsing. Neither SLICE_PARAMS are required (and shouldn't be
exposed by frame-based drivers), nor the number of slices.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
.../media/v4l/ext-ctrls-codec.rst | 39 +++++--------------
include/media/h264-ctrls.h | 4 --
2 files changed, 10 insertions(+), 33 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index e88c207d945b..90caf6a0d5a0 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1748,9 +1748,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
This compound control is not yet part of the public kernel API
and it is expected to change.
- This structure is expected to be passed as an array, with one
- entry for each slice included in the bitstream buffer.
-
.. c:type:: v4l2_ctrl_h264_slice_params
.. cssclass:: longtable
@@ -1760,17 +1757,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
:stub-columns: 0
:widths: 1 1 2
- * - __u32
- - ``start_byte_offset``
- Offset (in bytes) from the beginning of the OUTPUT buffer to the start
- of the slice. If the slice starts with a start code, then this is the
- offset to such start code. When operating in slice-based decoding mode
- (see :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field should
- be set to 0. When operating in frame-based decoding mode, this field
- should be 0 for the first slice.
* - __u32
- ``header_bit_size``
- -
+ - Offset in bits to slice_data() from the beginning of this slice.
* - __u32
- ``first_mb_in_slice``
-
@@ -1998,12 +1987,6 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - struct :c:type:`v4l2_h264_dpb_entry`
- ``dpb[16]``
-
- * - __u16
- - ``num_slices``
- - Number of slices needed to decode the current frame/field. When
- operating in slice-based decoding mode (see
- :c:type:`v4l2_mpeg_video_h264_decode_mode`), this field
- should always be set to one.
* - __u16
- ``nal_ref_idc``
- NAL reference ID value coming from the NAL Unit header
@@ -2121,22 +2104,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED``
- 0
- Decoding is done at the slice granularity.
- In this mode, ``num_slices`` field in struct
- :c:type:`v4l2_ctrl_h264_decode_params` should be set to 1,
- and ``start_byte_offset`` in struct
- :c:type:`v4l2_ctrl_h264_slice_params` should be set to 0.
The OUTPUT buffer must contain a single slice.
+ When this mode is selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS``
+ control shall be set. When multiple slices compose a frame,
+ use of ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` flag
+ is required.
* - ``V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED``
- 1
- - Decoding is done at the frame granularity.
- In this mode, ``num_slices`` field in struct
- :c:type:`v4l2_ctrl_h264_decode_params` should be set to the number
- of slices in the frame, and ``start_byte_offset`` in struct
- :c:type:`v4l2_ctrl_h264_slice_params` should be set accordingly
- for each slice. For the first slice, ``start_byte_offset`` should
- be zero.
+ - Decoding is done at the frame granularity,
The OUTPUT buffer must contain all slices needed to decode the
frame. The OUTPUT buffer must also contain both fields.
+ This mode will be supported by devices that
+ parse the slice(s) header(s) in hardware. When this mode is
+ selected, the ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS``
+ control shall not be set.
``V4L2_CID_MPEG_VIDEO_H264_START_CODE (enum)``
Specifies the H264 slice start code expected for each slice.
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index afcae3052085..e180501e6385 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -165,9 +165,6 @@ struct v4l2_h264_reference {
};
struct v4l2_ctrl_h264_slice_params {
- /* Offset in bytes to the start of slice in the OUTPUT buffer. */
- __u32 start_byte_offset;
-
/* Offset in bits to slice_data() from the beginning of this slice. */
__u32 header_bit_size;
@@ -226,7 +223,6 @@ struct v4l2_h264_dpb_entry {
struct v4l2_ctrl_h264_decode_params {
struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES];
- __u16 num_slices;
__u16 nal_ref_idc;
__s32 top_field_order_cnt;
__s32 bottom_field_order_cnt;
From ff81175260cd33feaa7d0407ef50186422215fae Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:25 -0300
Subject: [PATCH] media: uapi: h264: Clean slice invariants syntax elements
The H.264 specification requires in section 7.4.3 "Slice header semantics",
that the following values shall be the same in all slice headers:
pic_parameter_set_id
frame_num
field_pic_flag
bottom_field_flag
idr_pic_id
pic_order_cnt_lsb
delta_pic_order_cnt_bottom
delta_pic_order_cnt[ 0 ]
delta_pic_order_cnt[ 1 ]
sp_for_switch_flag
slice_group_change_cycle
These bitstream fields are part of the slice header, and therefore
passed redundantly on each slice. The purpose of the redundancy
is to make the codec fault-tolerant in network scenarios.
This is of course not needed to be reflected in the V4L2 controls,
given the bitstream has already been parsed by applications.
Therefore, move the redundant fields to the per-frame decode
parameters control (DECODE_PARAMS).
Field 'pic_parameter_set_id' is simply removed in this case,
because the PPS control must currently contain the active PPS.
Syntax elements dec_ref_pic_marking() and those related
to pic order count, remain invariant as well, and therefore,
the fields dec_ref_pic_marking_bit_size and pic_order_cnt_bit_size
are also common to all slices.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
.../media/v4l/ext-ctrls-codec.rst | 86 +++++++++----------
drivers/media/v4l2-core/v4l2-ctrls.c | 7 ++
drivers/media/v4l2-core/v4l2-h264.c | 8 +-
.../staging/media/hantro/hantro_g1_h264_dec.c | 21 +++--
drivers/staging/media/hantro/hantro_h264.c | 3 +-
drivers/staging/media/rkvdec/rkvdec-h264.c | 6 +-
.../staging/media/sunxi/cedrus/cedrus_h264.c | 9 +-
include/media/h264-ctrls.h | 39 +++++----
include/media/v4l2-h264.h | 1 -
9 files changed, 90 insertions(+), 90 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 90caf6a0d5a0..69dd3961b99b 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1766,44 +1766,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - __u8
- ``slice_type``
-
- * - __u8
- - ``pic_parameter_set_id``
- -
* - __u8
- ``colour_plane_id``
-
* - __u8
- ``redundant_pic_cnt``
-
- * - __u16
- - ``frame_num``
- -
- * - __u16
- - ``idr_pic_id``
- -
- * - __u16
- - ``pic_order_cnt_lsb``
- -
- * - __s32
- - ``delta_pic_order_cnt_bottom``
- -
- * - __s32
- - ``delta_pic_order_cnt0``
- -
- * - __s32
- - ``delta_pic_order_cnt1``
- -
- * - struct :c:type:`v4l2_h264_pred_weight_table`
- - ``pred_weight_table``
- -
- * - __u32
- - ``dec_ref_pic_marking_bit_size``
- - Size in bits of the dec_ref_pic_marking() syntax element.
- * - __u32
- - ``pic_order_cnt_bit_size``
- - Combined size in bits of the picture order count related syntax
- elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom,
- delta_pic_order_cnt0, and delta_pic_order_cnt1.
* - __u8
- ``cabac_init_idc``
-
@@ -1830,9 +1798,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
- ``num_ref_idx_l1_active_minus1``
- If num_ref_idx_active_override_flag is not set, this field must be
set to the value of num_ref_idx_l1_default_active_minus1.
- * - __u32
- - ``slice_group_change_cycle``
- -
+ * - __u8
+ - ``reserved``
+ - Applications and drivers must set this to zero.
* - struct :c:type:`v4l2_h264_reference`
- ``ref_pic_list0[32]``
- Reference picture list after applying the per-slice modifications
@@ -1854,17 +1822,11 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
:stub-columns: 0
:widths: 1 1 2
- * - ``V4L2_H264_SLICE_FLAG_FIELD_PIC``
- - 0x00000001
- -
- * - ``V4L2_H264_SLICE_FLAG_BOTTOM_FIELD``
- - 0x00000002
- -
* - ``V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED``
- - 0x00000004
+ - 0x00000001
-
* - ``V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH``
- - 0x00000008
+ - 0x00000002
-
``V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS (struct)``
@@ -1990,12 +1952,44 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - __u16
- ``nal_ref_idc``
- NAL reference ID value coming from the NAL Unit header
+ * - __u16
+ - ``frame_num``
+ -
* - __s32
- ``top_field_order_cnt``
- Picture Order Count for the coded top field
* - __s32
- ``bottom_field_order_cnt``
- Picture Order Count for the coded bottom field
+ * - __u16
+ - ``idr_pic_id``
+ -
+ * - __u16
+ - ``pic_order_cnt_lsb``
+ -
+ * - __s32
+ - ``delta_pic_order_cnt_bottom``
+ -
+ * - __s32
+ - ``delta_pic_order_cnt0``
+ -
+ * - __s32
+ - ``delta_pic_order_cnt1``
+ -
+ * - __u32
+ - ``dec_ref_pic_marking_bit_size``
+ - Size in bits of the dec_ref_pic_marking() syntax element.
+ * - __u32
+ - ``pic_order_cnt_bit_size``
+ - Combined size in bits of the picture order count related syntax
+ elements: pic_order_cnt_lsb, delta_pic_order_cnt_bottom,
+ delta_pic_order_cnt0, and delta_pic_order_cnt1.
+ * - __u32
+ - ``slice_group_change_cycle``
+ -
+ * - __u32
+ - ``reserved``
+ - Applications and drivers must set this to zero.
* - __u32
- ``flags``
- See :ref:`Decode Parameters Flags <h264_decode_params_flags>`
@@ -2014,6 +2008,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - ``V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC``
- 0x00000001
- That picture is an IDR picture
+ * - ``V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC``
+ - 0x00000002
+ -
+ * - ``V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD``
+ - 0x00000004
+ -
.. c:type:: v4l2_h264_dpb_entry
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b9457789fa55..b846f5b089c9 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1737,6 +1737,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
{
struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header;
+ struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
struct v4l2_ctrl_hevc_sps *p_hevc_sps;
struct v4l2_ctrl_hevc_pps *p_hevc_pps;
@@ -1798,7 +1799,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
case V4L2_CTRL_TYPE_H264_PPS:
case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ break;
+
case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ p_h264_slice_params = p;
+
+ zero_reserved(*p_h264_slice_params);
break;
case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
@@ -1810,6 +1816,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
zero_reserved(*dpb_entry);
}
+ zero_reserved(*p_h264_dec_params);
break;
case V4L2_CTRL_TYPE_VP8_FRAME_HEADER:
diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c
index 12b751c09016..101fdeabfb06 100644
--- a/drivers/media/v4l2-core/v4l2-h264.c
+++ b/drivers/media/v4l2-core/v4l2-h264.c
@@ -18,14 +18,12 @@
*
* @b: the builder context to initialize
* @dec_params: decode parameters control
- * @slice_params: first slice parameters control
* @sps: SPS control
* @dpb: DPB to use when creating the reference list
*/
void
v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
const struct v4l2_ctrl_h264_decode_params *dec_params,
- const struct v4l2_ctrl_h264_slice_params *slice_params,
const struct v4l2_ctrl_h264_sps *sps,
const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
{
@@ -33,13 +31,13 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
unsigned int i;
max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
- cur_frame_num = slice_params->frame_num;
+ cur_frame_num = dec_params->frame_num;
memset(b, 0, sizeof(*b));
- if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC))
+ if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
dec_params->top_field_order_cnt);
- else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
else
b->cur_pic_order_count = dec_params->top_field_order_cnt;
diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
index 424c648ce9fc..f9839e9c6da5 100644
--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c
+++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
@@ -23,7 +23,6 @@ static void set_params(struct hantro_ctx *ctx)
{
const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode;
- const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices;
const struct v4l2_ctrl_h264_sps *sps = ctrls->sps;
const struct v4l2_ctrl_h264_pps *pps = ctrls->pps;
struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx);
@@ -42,11 +41,11 @@ static void set_params(struct hantro_ctx *ctx)
if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) &&
(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD ||
- slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC))
+ dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E;
- if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E;
- if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD))
+ if (!(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD))
reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E;
vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0);
@@ -75,7 +74,7 @@ static void set_params(struct hantro_ctx *ctx)
/* Decoder control register 4. */
reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) |
- G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) |
+ G1_REG_DEC_CTRL4_FRAMENUM(dec_param->frame_num) |
G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc);
if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE)
reg |= G1_REG_DEC_CTRL4_CABAC_E;
@@ -88,8 +87,8 @@ static void set_params(struct hantro_ctx *ctx)
vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4);
/* Decoder control register 5. */
- reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) |
- G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id);
+ reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(dec_param->dec_ref_pic_marking_bit_size) |
+ G1_REG_DEC_CTRL5_IDR_PIC_ID(dec_param->idr_pic_id);
if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED)
reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E;
if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT)
@@ -103,10 +102,10 @@ static void set_params(struct hantro_ctx *ctx)
vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5);
/* Decoder control register 6. */
- reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) |
+ reg = G1_REG_DEC_CTRL6_PPS_ID(pps->pic_parameter_set_id) |
G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) |
G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) |
- G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size);
+ G1_REG_DEC_CTRL6_POC_LENGTH(dec_param->pic_order_cnt_bit_size);
vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6);
/* Error concealment register. */
@@ -246,7 +245,7 @@ static void set_buffers(struct hantro_ctx *ctx)
/* Destination (decoded frame) buffer. */
dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf);
/* Adjust dma addr to start at second line for bottom field */
- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
offset = ALIGN(ctx->src_fmt.width, MB_DIM);
vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DST);
@@ -265,7 +264,7 @@ static void set_buffers(struct hantro_ctx *ctx)
* DMV buffer is split in two for field encoded frames,
* adjust offset for bottom field
*/
- if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
offset += 32 * MB_WIDTH(ctx->src_fmt.width) *
MB_HEIGHT(ctx->src_fmt.height);
vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DIR_MV);
diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
index 6dcd47bd9ed3..7578a4fc1b16 100644
--- a/drivers/staging/media/hantro/hantro_h264.c
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -372,8 +372,7 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx)
/* Build the P/B{0,1} ref lists. */
v4l2_h264_init_reflist_builder(&reflist_builder, ctrls->decode,
- &ctrls->slices[0], ctrls->sps,
- ctx->h264_dec.dpb);
+ ctrls->sps, ctx->h264_dec.dpb);
v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
h264_ctx->reflists.b1);
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 07a80e9a9df2..70752e30b3a3 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -730,7 +730,6 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
struct rkvdec_h264_run *run)
{
const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params;
- const struct v4l2_ctrl_h264_slice_params *sl_params = &run->slices_params[0];
const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb;
struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
const struct v4l2_ctrl_h264_sps *sps = run->sps;
@@ -754,7 +753,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
continue;
if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM ||
- dpb[i].frame_num < sl_params->frame_num) {
+ dpb[i].frame_num < dec_params->frame_num) {
p[i] = dpb[i].frame_num;
continue;
}
@@ -1094,8 +1093,7 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
/* Build the P/B{0,1} ref lists. */
v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params,
- &run.slices_params[0], run.sps,
- run.decode_params->dpb);
+ run.sps, run.decode_params->dpb);
h264_ctx->reflists.num_valid = reflist_builder.num_valid;
v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p);
v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index 7d9bd5860a1b..c8f626fdd3dd 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -95,7 +95,6 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
{
struct cedrus_h264_sram_ref_pic pic_list[CEDRUS_H264_FRAME_NUM];
const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
- const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
struct vb2_queue *cap_q;
struct cedrus_buffer *output_buf;
@@ -144,7 +143,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
output_buf->codec.h264.position = position;
- if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_MBAFF;
@@ -407,7 +406,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE;
cedrus_write(dev, VE_H264_SPS, reg);
- mbaff_pic = !(slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) &&
+ mbaff_pic = !(decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) &&
(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
@@ -421,9 +420,9 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
reg |= slice->cabac_init_idc & 0x3;
if (ctx->fh.m2m_ctx->new_frame)
reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC;
- if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
+ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
reg |= VE_H264_SHS_FIELD_PIC;
- if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
reg |= VE_H264_SHS_BOTTOM_FIELD;
if (slice->flags & V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED)
reg |= VE_H264_SHS_DIRECT_SPATIAL_MV_PRED;
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index e180501e6385..1217b706128e 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -146,10 +146,8 @@ struct v4l2_ctrl_h264_pred_weights {
#define V4L2_H264_SLICE_TYPE_SP 3
#define V4L2_H264_SLICE_TYPE_SI 4
-#define V4L2_H264_SLICE_FLAG_FIELD_PIC 0x01
-#define V4L2_H264_SLICE_FLAG_BOTTOM_FIELD 0x02
-#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04
-#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08
+#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x01
+#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x02
enum v4l2_h264_field_reference {
V4L2_H264_TOP_FIELD_REF = 0x1,
@@ -171,21 +169,8 @@ struct v4l2_ctrl_h264_slice_params {
__u32 first_mb_in_slice;
__u8 slice_type;
- __u8 pic_parameter_set_id;
__u8 colour_plane_id;
__u8 redundant_pic_cnt;
- __u16 frame_num;
- __u16 idr_pic_id;
- __u16 pic_order_cnt_lsb;
- __s32 delta_pic_order_cnt_bottom;
- __s32 delta_pic_order_cnt0;
- __s32 delta_pic_order_cnt1;
-
- /* Size in bits of dec_ref_pic_marking() syntax element. */
- __u32 dec_ref_pic_marking_bit_size;
- /* Size in bits of pic order count syntax. */
- __u32 pic_order_cnt_bit_size;
-
__u8 cabac_init_idc;
__s8 slice_qp_delta;
__s8 slice_qs_delta;
@@ -194,7 +179,8 @@ struct v4l2_ctrl_h264_slice_params {
__s8 slice_beta_offset_div2;
__u8 num_ref_idx_l0_active_minus1;
__u8 num_ref_idx_l1_active_minus1;
- __u32 slice_group_change_cycle;
+
+ __u8 reserved;
struct v4l2_h264_reference ref_pic_list0[V4L2_H264_REF_LIST_LEN];
struct v4l2_h264_reference ref_pic_list1[V4L2_H264_REF_LIST_LEN];
@@ -219,13 +205,28 @@ struct v4l2_h264_dpb_entry {
__u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */
};
-#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01
+#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01
+#define V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC 0x02
+#define V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD 0x04
struct v4l2_ctrl_h264_decode_params {
struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES];
__u16 nal_ref_idc;
+ __u16 frame_num;
__s32 top_field_order_cnt;
__s32 bottom_field_order_cnt;
+ __u16 idr_pic_id;
+ __u16 pic_order_cnt_lsb;
+ __s32 delta_pic_order_cnt_bottom;
+ __s32 delta_pic_order_cnt0;
+ __s32 delta_pic_order_cnt1;
+ /* Size in bits of dec_ref_pic_marking() syntax element. */
+ __u32 dec_ref_pic_marking_bit_size;
+ /* Size in bits of pic order count syntax. */
+ __u32 pic_order_cnt_bit_size;
+ __u32 slice_group_change_cycle;
+
+ __u32 reserved;
__u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */
};
diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h
index 1a5f26fc2a9a..f08ba181263d 100644
--- a/include/media/v4l2-h264.h
+++ b/include/media/v4l2-h264.h
@@ -44,7 +44,6 @@ struct v4l2_h264_reflist_builder {
void
v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
const struct v4l2_ctrl_h264_decode_params *dec_params,
- const struct v4l2_ctrl_h264_slice_params *slice_params,
const struct v4l2_ctrl_h264_sps *sps,
const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]);
From c94048bd00c4faa5bf1be0b3b01d3cc41cb475bb Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:26 -0300
Subject: [PATCH] media: uapi: h264: Rename and clarify
PPS_FLAG_SCALING_MATRIX_PRESENT
Applications are expected to fill V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX
if a non-flat scaling matrix applies to the picture. This is the case if
SPS scaling_matrix_present_flag or PPS pic_scaling_matrix_present_flag
are set, and should be handled by applications.
On one hand, the PPS bitstream syntax element signals the presence of a
Picture scaling matrix modifying the Sequence (SPS) scaling matrix.
On the other hand, our flag should indicate if the scaling matrix
V4L2 control is applicable to this request.
Rename the flag from PPS_FLAG_PIC_SCALING_MATRIX_PRESENT to
PPS_FLAG_SCALING_MATRIX_PRESENT, to avoid mixing this flag with
bitstream syntax element pic_scaling_matrix_present_flag,
and clarify the meaning of our flag.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 5 +++--
include/media/h264-ctrls.h | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 69dd3961b99b..03ce87aa5488 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1695,9 +1695,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
* - ``V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE``
- 0x00000040
-
- * - ``V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT``
+ * - ``V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT``
- 0x00000080
- -
+ - Indicates that ``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX``
+ must be used for this picture.
``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (struct)``
Specifies the scaling matrix (as extracted from the bitstream) for
diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h
index 1217b706128e..070b9499d7bc 100644
--- a/include/media/h264-ctrls.h
+++ b/include/media/h264-ctrls.h
@@ -99,7 +99,7 @@ struct v4l2_ctrl_h264_sps {
#define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010
#define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020
#define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040
-#define V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT 0x0080
+#define V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT 0x0080
struct v4l2_ctrl_h264_pps {
__u8 pic_parameter_set_id;
From 2344f270ec7a9f9559e6d1e57a124c6a89ce0602 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:27 -0300
Subject: [PATCH] media: hantro: Don't require unneeded H264_SLICE_PARAMS
Now that slice invariant parameters have been moved,
the driver no longer needs this control, so drop it.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/hantro/hantro_drv.c | 5 -----
drivers/staging/media/hantro/hantro_h264.c | 5 -----
drivers/staging/media/hantro/hantro_hw.h | 2 --
3 files changed, 12 deletions(-)
diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c
index 34797507f214..3cd00cc0a364 100644
--- a/drivers/staging/media/hantro/hantro_drv.c
+++ b/drivers/staging/media/hantro/hantro_drv.c
@@ -306,11 +306,6 @@ static const struct hantro_ctrl controls[] = {
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
},
- }, {
- .codec = HANTRO_H264_DECODER,
- .cfg = {
- .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
- },
}, {
.codec = HANTRO_H264_DECODER,
.cfg = {
diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
index 7578a4fc1b16..089bfa9c625b 100644
--- a/drivers/staging/media/hantro/hantro_h264.c
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -349,11 +349,6 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx)
if (WARN_ON(!ctrls->decode))
return -EINVAL;
- ctrls->slices =
- hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS);
- if (WARN_ON(!ctrls->slices))
- return -EINVAL;
-
ctrls->sps =
hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS);
if (WARN_ON(!ctrls->sps))
diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h
index f066de6b592d..219283a06f52 100644
--- a/drivers/staging/media/hantro/hantro_hw.h
+++ b/drivers/staging/media/hantro/hantro_hw.h
@@ -56,14 +56,12 @@ struct hantro_jpeg_enc_hw_ctx {
* struct hantro_h264_dec_ctrls
* @decode: Decode params
* @scaling: Scaling info
- * @slice: Slice params
* @sps: SPS info
* @pps: PPS info
*/
struct hantro_h264_dec_ctrls {
const struct v4l2_ctrl_h264_decode_params *decode;
const struct v4l2_ctrl_h264_scaling_matrix *scaling;
- const struct v4l2_ctrl_h264_slice_params *slices;
const struct v4l2_ctrl_h264_sps *sps;
const struct v4l2_ctrl_h264_pps *pps;
};
From 419ccc9852409f2553c92ee3be909afa53d24d1d Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:28 -0300
Subject: [PATCH] media: rkvdec: Don't require unneeded H264_SLICE_PARAMS
Now that slice invariant parameters have been moved,
the driver no longer needs this control, so drop it.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Reviewed-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ----
drivers/staging/media/rkvdec/rkvdec.c | 5 -----
2 files changed, 9 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 70752e30b3a3..584e0d5c493b 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -109,7 +109,6 @@ struct rkvdec_h264_reflists {
struct rkvdec_h264_run {
struct rkvdec_run base;
const struct v4l2_ctrl_h264_decode_params *decode_params;
- const struct v4l2_ctrl_h264_slice_params *slices_params;
const struct v4l2_ctrl_h264_sps *sps;
const struct v4l2_ctrl_h264_pps *pps;
const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
@@ -1066,9 +1065,6 @@ static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx,
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS);
run->decode_params = ctrl ? ctrl->p_cur.p : NULL;
- ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
- V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS);
- run->slices_params = ctrl ? ctrl->p_cur.p : NULL;
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
V4L2_CID_MPEG_VIDEO_H264_SPS);
run->sps = ctrl ? ctrl->p_cur.p : NULL;
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index c8151328fb70..7c5129593921 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -59,11 +59,6 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
},
- {
- .per_request = true,
- .mandatory = true,
- .cfg.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS,
- },
{
.per_request = true,
.mandatory = true,
From 85567a00727331d7a3269bd76319a048ef1ed505 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 14 Aug 2020 10:36:29 -0300
Subject: [PATCH] media: cedrus: h264: Properly configure reference field
When interlaced H264 content is being decoded, references must indicate
which field is being referenced. Currently this was done by checking
capture buffer flags. However, that is not correct because capture
buffer may hold both fields.
Fix this by checking newly introduced flags in reference lists.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
---
drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index c8f626fdd3dd..1e89a8438f36 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -182,7 +182,6 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
for (i = 0; i < num_ref; i++) {
const struct v4l2_h264_dpb_entry *dpb;
const struct cedrus_buffer *cedrus_buf;
- const struct vb2_v4l2_buffer *ref_buf;
unsigned int position;
int buf_idx;
u8 dpb_idx;
@@ -197,12 +196,11 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
if (buf_idx < 0)
continue;
- ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]);
- cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf);
+ cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]);
position = cedrus_buf->codec.h264.position;
sram_array[i] |= position << 1;
- if (ref_buf->field == V4L2_FIELD_BOTTOM)
+ if (ref_list[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
sram_array[i] |= BIT(0);
}
From 102efa220abfcf3c08ceaf0a7c3ac5f88db5bc0c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 14 Aug 2020 10:36:30 -0300
Subject: [PATCH] media: cedrus: h264: Fix frame list construction
Current frame list construction algorithm assumes that decoded image
will be output into its own buffer. That is true for progressive content
but not for interlaced where each field is decoded separately into same
buffer.
Fix that by checking if capture buffer is listed in DPB. If it is, reuse
it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index 1e89a8438f36..fe041b444385 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -101,7 +101,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
struct cedrus_dev *dev = ctx->dev;
unsigned long used_dpbs = 0;
unsigned int position;
- unsigned int output = 0;
+ int output = -1;
unsigned int i;
cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -124,6 +124,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
position = cedrus_buf->codec.h264.position;
used_dpbs |= BIT(position);
+ if (run->dst->vb2_buf.timestamp == dpb->reference_ts) {
+ output = position;
+ continue;
+ }
+
if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
continue;
@@ -131,13 +136,11 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
dpb->top_field_order_cnt,
dpb->bottom_field_order_cnt,
&pic_list[position]);
-
- output = max(position, output);
}
- position = find_next_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM,
- output);
- if (position >= CEDRUS_H264_FRAME_NUM)
+ if (output >= 0)
+ position = output;
+ else
position = find_first_zero_bit(&used_dpbs, CEDRUS_H264_FRAME_NUM);
output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
From 47f1224e5d7f2d3d566d1da9df0f72ee0564a0d1 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Wed, 19 Aug 2020 11:37:55 -0300
Subject: [PATCH] media: rkvdec: Drop unneeded per_request driver-specific
control flag
Currently, the drivers makes no distinction between per_request
and mandatory, as both are used in the same request validate check.
The driver only cares to know if a given control is
required to be part of a request, so only one flag is needed.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/rkvdec.c | 8 +-------
drivers/staging/media/rkvdec/rkvdec.h | 1 -
2 files changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 7c5129593921..9f59dfb62d3f 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -55,35 +55,29 @@ static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = {
static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
{
- .per_request = true,
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS,
},
{
- .per_request = true,
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_SPS,
.cfg.ops = &rkvdec_ctrl_ops,
},
{
- .per_request = true,
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS,
},
{
- .per_request = true,
.mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
},
{
- .mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE,
.cfg.min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
.cfg.max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
.cfg.def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED,
},
{
- .mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_START_CODE,
.cfg.min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
.cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
@@ -615,7 +609,7 @@ static int rkvdec_request_validate(struct media_request *req)
u32 id = ctrls->ctrls[i].cfg.id;
struct v4l2_ctrl *ctrl;
- if (!ctrls->ctrls[i].per_request || !ctrls->ctrls[i].mandatory)
+ if (!ctrls->ctrls[i].mandatory)
continue;
ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, id);
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index 2fc9f46b6910..77a137cca88e 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -25,7 +25,6 @@
struct rkvdec_ctx;
struct rkvdec_ctrl_desc {
- u32 per_request : 1;
u32 mandatory : 1;
struct v4l2_ctrl_config cfg;
};
From 90ea71bc465216778ac6fda4ca151f324df4d516 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:32 -0300
Subject: [PATCH] media: rkvdec: Use H264_SCALING_MATRIX only when required
Baseline, Main and Extended profiles are specified to
not support a scaling matrix. Also, High profiles
can optionally specify a scaling matrix, using
SPS and PPS NAL units.
To meet this expectation, applications are required to
set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control
and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT
flag only when a scaling matrix is specified for a picture.
Implement this on rkvdec, which has hardware support for this
case.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++++---
drivers/staging/media/rkvdec/rkvdec.c | 1 -
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 584e0d5c493b..9233260e14c1 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -708,9 +708,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
WRITE_PPS(pps->second_chroma_qp_index_offset,
SECOND_CHROMA_QP_INDEX_OFFSET);
- /* always use the matrix sent from userspace */
- WRITE_PPS(1, SCALING_LIST_ENABLE_FLAG);
-
+ WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT),
+ SCALING_LIST_ENABLE_FLAG);
+ /* To be on the safe side, program the scaling matrix address */
scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list);
scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance;
WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS);
@@ -792,9 +792,13 @@ static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx,
struct rkvdec_h264_run *run)
{
const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix;
+ const struct v4l2_ctrl_h264_pps *pps = run->pps;
struct rkvdec_h264_ctx *h264_ctx = ctx->priv;
struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu;
+ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
+ return;
+
BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) !=
sizeof(scaling->scaling_list_4x4));
BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) !=
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 9f59dfb62d3f..d25c4a37e2af 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -68,7 +68,6 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_PPS,
},
{
- .mandatory = true,
.cfg.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
},
{
From 70d39439f485d511c9c929934a26341ef3b736ef Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:33 -0300
Subject: [PATCH] media: hantro: Use H264_SCALING_MATRIX only when required
Baseline, Main and Extended profiles are specified to
not support a scaling matrix. Also, High profiles
can optionally specify a scaling matrix, using
SPS and PPS NAL units.
To meet this expectation, applications are required to
set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control
and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT
flag only when a scaling matrix is specified for a picture.
Implement this on hantro, which has hardware support for this
case.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/hantro/hantro_g1_h264_dec.c | 5 ++---
drivers/staging/media/hantro/hantro_h264.c | 4 ++++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
index f9839e9c6da5..845bef73d218 100644
--- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c
+++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c
@@ -59,9 +59,8 @@ static void set_params(struct hantro_ctx *ctx)
reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) |
G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset);
- /* always use the matrix sent from userspace */
- reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E;
-
+ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)
+ reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E;
if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E;
vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2);
diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c
index 089bfa9c625b..b1bdc00ac262 100644
--- a/drivers/staging/media/hantro/hantro_h264.c
+++ b/drivers/staging/media/hantro/hantro_h264.c
@@ -197,6 +197,7 @@ assemble_scaling_list(struct hantro_ctx *ctx)
{
const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls;
const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling;
+ const struct v4l2_ctrl_h264_pps *pps = ctrls->pps;
const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4);
const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]);
const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]);
@@ -205,6 +206,9 @@ assemble_scaling_list(struct hantro_ctx *ctx)
const u32 *src;
int i, j;
+ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
+ return;
+
for (i = 0; i < num_list_4x4; i++) {
src = (u32 *)&scaling->scaling_list_4x4[i];
for (j = 0; j < list_len_4x4 / 4; j++)
From 6390458815944ce231b6282771e2a6c3fc6f2fa6 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Fri, 14 Aug 2020 10:36:34 -0300
Subject: [PATCH] media: cedrus: Use H264_SCALING_MATRIX only when required
Baseline, Main and Extended profiles are specified to
not support a scaling matrix. Also, High profiles
can optionally specify a scaling matrix, using
SPS and PPS NAL units.
To meet this expectation, applications are required to
set the V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX control
and set the V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT
flag only when a scaling matrix is specified for a picture.
Implement this on cedrus, which has hardware support for this
case.
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/sunxi/cedrus/cedrus.c | 2 +-
drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index 826324faad7e..6ebb39e0c0ce 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -76,7 +76,7 @@ static const struct cedrus_control cedrus_controls[] = {
.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX,
},
.codec = CEDRUS_CODEC_H264,
- .required = true,
+ .required = false,
},
{
.cfg = {
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index fe041b444385..28319351e909 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -238,8 +238,12 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx,
{
const struct v4l2_ctrl_h264_scaling_matrix *scaling =
run->h264.scaling_matrix;
+ const struct v4l2_ctrl_h264_pps *pps = run->h264.pps;
struct cedrus_dev *dev = ctx->dev;
+ if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT))
+ return;
+
cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_0,
scaling->scaling_list_8x8[0],
sizeof(scaling->scaling_list_8x8[0]));
@@ -442,6 +446,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
reg |= (pps->second_chroma_qp_index_offset & 0x3f) << 16;
reg |= (pps->chroma_qp_index_offset & 0x3f) << 8;
reg |= (pps->pic_init_qp_minus26 + 26 + slice->slice_qp_delta) & 0x3f;
+ if (pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)
+ reg |= VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT;
cedrus_write(dev, VE_H264_SHS_QP, reg);
// clear status flags
From 711f57301ef4368ba23f70f6596994b7242803cc Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:33 +0000
Subject: [PATCH] media: rkvdec: h264: Fix reference frame_num wrap for second
field
When decoding the second field in a complementary field pair the second
field is sharing the same frame_num with the first field.
Currently the frame_num for the first field is wrapped when it matches the
field being decoded, this cause issues to decode the second field in a
complementary field pair.
Fix this by using inclusive comparison, less than or equal.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 9233260e14c1..8fab0151b884 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -752,7 +752,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
continue;
if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM ||
- dpb[i].frame_num < dec_params->frame_num) {
+ dpb[i].frame_num <= dec_params->frame_num) {
p[i] = dpb[i].frame_num;
continue;
}
From a957b522403e98c67b8c184fa3b7709c6e874d40 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:34 +0000
Subject: [PATCH] media: rkvdec: Ensure decoded resolution fit coded resolution
Ensure decoded CAPTURE buffer resolution is larger or equal to the coded
OPTUPT buffer resolution.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index d25c4a37e2af..b3e067031c83 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -223,6 +223,8 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
pix_mp->pixelformat = coded_desc->decoded_fmts[0];
/* Always apply the frmsize constraint of the coded end. */
+ pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width);
+ pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height);
v4l2_apply_frmsize_constraints(&pix_mp->width,
&pix_mp->height,
&coded_desc->frmsize);
From 7c3bb86b8d315c1939a35c4dfe31e120758e5395 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:34 +0000
Subject: [PATCH] media: rkvdec: h264: Validate and use pic width and height in
mbs
The width and height in mbs is currently configured based on OUTPUT buffer
resolution, this works for frame pictures but can cause issues for field
pictures.
When frame_mbs_only_flag is 0 the height in mbs should be height of
the field instead of height of frame.
Validate pic_width_in_mbs_minus1 and pic_height_in_map_units_minus1
against OUTPUT buffer resolution and use these values to configure HW.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ++--
drivers/staging/media/rkvdec/rkvdec.c | 10 ++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 8fab0151b884..20a783a1bcc7 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -671,8 +671,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4);
WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO),
DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG);
- WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.width, 16), PIC_WIDTH_IN_MBS);
- WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.height, 16), PIC_HEIGHT_IN_MBS);
+ WRITE_PPS(sps->pic_width_in_mbs_minus1 + 1, PIC_WIDTH_IN_MBS);
+ WRITE_PPS(sps->pic_height_in_map_units_minus1 + 1, PIC_HEIGHT_IN_MBS);
WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY),
FRAME_MBS_ONLY_FLAG);
WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD),
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index b3e067031c83..06fc58440cd3 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -29,8 +29,11 @@
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
+
if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) {
const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+ unsigned int width, height;
/*
* TODO: The hardware supports 10-bit and 4:2:2 profiles,
* but it's currently broken in the driver.
@@ -45,6 +48,13 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
if (sps->bit_depth_luma_minus8 != 0)
/* Only 8-bit is supported */
return -EINVAL;
+
+ width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
+ height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
+
+ if (width > ctx->coded_fmt.fmt.pix_mp.width ||
+ height > ctx->coded_fmt.fmt.pix_mp.height)
+ return -EINVAL;
}
return 0;
}
From f28529ac6fd75419e2b1806777158b5912ea0cb4 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:35 +0000
Subject: [PATCH] media: rkvdec: h264: Fix bit depth wrap in pps packet
The luma and chroma bit depth fields in the pps packet is 3 bits wide.
8 is wrongly added to the bit depth value written to these 3-bit fields.
Because only the 3 LSB is written the hardware is configured correctly.
Correct this by not adding 8 to the luma and chroma bit depth value.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 20a783a1bcc7..f4b61dd45e7f 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -661,8 +661,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
WRITE_PPS(0xff, PROFILE_IDC);
WRITE_PPS(1, CONSTRAINT_SET3_FLAG);
WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC);
- WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA);
- WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA);
+ WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA);
+ WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA);
WRITE_PPS(0, QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG);
WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4);
WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES);
From a0de7efadd3058c3837714fd1c71e31dd00b9eac Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:35 +0000
Subject: [PATCH] media: rkvdec: h264: Do not override output buffer sizeimage
The output buffer sizeimage is currently forced to 2 bytes per pixel, this
can lead to high memory usage for 4K content when multiple output buffers
is created by userspace.
Do not override output buffer sizeimage and let userspace have control of
output buffer sizeimage by only setting sizeimage if none is provided.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index f4b61dd45e7f..2e7749bac417 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -1015,8 +1015,9 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
fmt->num_planes = 1;
- fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
- RKVDEC_H264_MAX_DEPTH_IN_BYTES;
+ if (!fmt->plane_fmt[0].sizeimage)
+ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height *
+ RKVDEC_H264_MAX_DEPTH_IN_BYTES;
return 0;
}
From 2fd027124722012155dda6bf4af57d978ce0655c Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:35 +0000
Subject: [PATCH] media: v4l2-common: Add helpers to calculate bytesperline and
sizeimage
Add helper functions to calculate plane bytesperline and sizeimage, these
new helpers consider block width and height when calculating plane
bytesperline and sizeimage.
This prepare support for new pixel formats added in next patch that make
use of block width and height.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/media/v4l2-core/v4l2-common.c | 77 +++++++++++++--------------
1 file changed, 38 insertions(+), 39 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 3dc17ebe14fa..4102c373b48a 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -333,6 +333,33 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
return info->block_h[plane];
}
+static inline unsigned int v4l2_format_plane_width(const struct v4l2_format_info *info, int plane,
+ unsigned int width)
+{
+ unsigned int hdiv = plane ? info->hdiv : 1;
+ unsigned int bytes = DIV_ROUND_UP(width * info->bpp[plane],
+ v4l2_format_block_width(info, plane) *
+ v4l2_format_block_height(info, plane));
+
+ return DIV_ROUND_UP(bytes, hdiv);
+}
+
+static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane,
+ unsigned int height)
+{
+ unsigned int vdiv = plane ? info->vdiv : 1;
+ unsigned int lines = ALIGN(height, v4l2_format_block_height(info, plane));
+
+ return DIV_ROUND_UP(lines, vdiv);
+}
+
+static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
+ unsigned int width, unsigned int height)
+{
+ return v4l2_format_plane_width(info, plane, width) *
+ v4l2_format_plane_height(info, plane, height);
+}
+
void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
const struct v4l2_frmsize_stepwise *frmsize)
{
@@ -368,37 +395,19 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
if (info->mem_planes == 1) {
plane = &pixfmt->plane_fmt[0];
- plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
+ plane->bytesperline = v4l2_format_plane_width(info, 0, width);
plane->sizeimage = 0;
- for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
- plane->sizeimage += info->bpp[i] *
- DIV_ROUND_UP(aligned_width, hdiv) *
- DIV_ROUND_UP(aligned_height, vdiv);
- }
+ for (i = 0; i < info->comp_planes; i++)
+ plane->sizeimage +=
+ v4l2_format_plane_size(info, i, width, height);
} else {
for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
plane = &pixfmt->plane_fmt[i];
plane->bytesperline =
- info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv);
- plane->sizeimage =
- plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
+ v4l2_format_plane_width(info, i, width);
+ plane->sizeimage = plane->bytesperline *
+ v4l2_format_plane_height(info, i, height);
}
}
return 0;
@@ -422,22 +431,12 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
pixfmt->width = width;
pixfmt->height = height;
pixfmt->pixelformat = pixelformat;
- pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0];
+ pixfmt->bytesperline = v4l2_format_plane_width(info, 0, width);
pixfmt->sizeimage = 0;
- for (i = 0; i < info->comp_planes; i++) {
- unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
- unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
- unsigned int aligned_width;
- unsigned int aligned_height;
-
- aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
- aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
-
- pixfmt->sizeimage += info->bpp[i] *
- DIV_ROUND_UP(aligned_width, hdiv) *
- DIV_ROUND_UP(aligned_height, vdiv);
- }
+ for (i = 0; i < info->comp_planes; i++)
+ pixfmt->sizeimage +=
+ v4l2_format_plane_size(info, i, width, height);
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
From 889f4693a0947c22188ca643ed9ba3579f0abc66 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:36 +0000
Subject: [PATCH] media: v4l2: Add NV15 and NV20 pixel formats
Add NV15 and NV20 pixel formats used by the Rockchip Video Decoder for
10-bit buffers.
NV15 and NV20 is a packed 10-bit 4:2:0/4:2:2 semi-planar Y/CbCr format
similar to P010 and P210 but has no padding between components. Instead,
luminance and chrominance samples are grouped into 4s so that each group is
packed into an integer number of bytes:
YYYY = UVUV = 4 * 10 bits = 40 bits = 5 bytes
The '15' and '20' suffix refers to the optimum effective bits per pixel
which is achieved when the total number of luminance samples is a multiple
of 8 for NV15 and 4 for NV20.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
.../userspace-api/media/v4l/pixfmt-nv15.rst | 101 ++++++++++++++++++
.../userspace-api/media/v4l/pixfmt-nv20.rst | 99 +++++++++++++++++
.../userspace-api/media/v4l/yuv-formats.rst | 2 +
drivers/media/v4l2-core/v4l2-common.c | 3 +
drivers/media/v4l2-core/v4l2-ioctl.c | 2 +
include/uapi/linux/videodev2.h | 3 +
6 files changed, 210 insertions(+)
create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv15.rst
create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv20.rst
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst
new file mode 100644
index 000000000000..d059db58c6e0
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/pixfmt-nv15.rst
@@ -0,0 +1,101 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/userspace-api/media/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2-PIX-FMT-NV15:
+
+**************************
+V4L2_PIX_FMT_NV15 ('NV15')
+**************************
+
+Format with ½ horizontal and vertical chroma resolution, also known as
+YUV 4:2:0. One luminance and one chrominance plane with alternating
+chroma samples similar to ``V4L2_PIX_FMT_NV12`` but with 10-bit samples
+that are grouped into four and packed into five bytes.
+
+The '15' suffix refers to the optimum effective bits per pixel which is
+achieved when the total number of luminance samples is a multiple of 8.
+
+
+Description
+===========
+
+This is a packed 10-bit two-plane version of the YUV 4:2:0 format. The
+three components are separated into two sub-images or planes. The Y plane
+is first. The Y plane has five bytes per each group of four pixels. A
+combined CbCr plane immediately follows the Y plane in memory. The CbCr
+plane is the same width, in bytes, as the Y plane (and of the image), but
+is half as tall in pixels. Each CbCr pair belongs to four pixels. For
+example, Cb\ :sub:`00`/Cr\ :sub:`00` belongs to Y'\ :sub:`00`,
+Y'\ :sub:`01`, Y'\ :sub:`10`, Y'\ :sub:`11`.
+
+If the Y plane has pad bytes after each row, then the CbCr plane has as
+many pad bytes after its rows.
+
+**Byte Order.**
+Little endian. Each cell is one byte. Pixels cross the byte boundary.
+
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - start + 0:
+ - Y'\ :sub:`00[7:0]`
+ - Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]`
+ - Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]`
+ - Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]`
+ - Y'\ :sub:`03[9:2]`
+ * - start + 5:
+ - Y'\ :sub:`10[7:0]`
+ - Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]`
+ - Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]`
+ - Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]`
+ - Y'\ :sub:`13[9:2]`
+ * - start + 10:
+ - Cb'\ :sub:`00[7:0]`
+ - Cr'\ :sub:`00[5:0]`\ Cb'\ :sub:`00[9:8]`
+ - Cb'\ :sub:`01[3:0]`\ Cr'\ :sub:`00[9:6]`
+ - Cr'\ :sub:`01[1:0]`\ Cb'\ :sub:`01[9:4]`
+ - Cr'\ :sub:`01[9:2]`
+
+
+**Color Sample Location:**
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * -
+ - 0
+ -
+ - 1
+ - 2
+ -
+ - 3
+ * - 0
+ - Y
+ -
+ - Y
+ - Y
+ -
+ - Y
+ * -
+ -
+ - C
+ -
+ -
+ - C
+ -
+ * - 1
+ - Y
+ -
+ - Y
+ - Y
+ -
+ - Y
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst
new file mode 100644
index 000000000000..a8123be0baa3
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/pixfmt-nv20.rst
@@ -0,0 +1,99 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/userspace-api/media/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2-PIX-FMT-NV20:
+
+**************************
+V4L2_PIX_FMT_NV20 ('NV20')
+**************************
+
+Format with ½ horizontal chroma resolution, also known as YUV 4:2:2.
+One luminance and one chrominance plane with alternating chroma samples
+similar to ``V4L2_PIX_FMT_NV16`` but with 10-bit samples
+that are grouped into four and packed into five bytes.
+
+The '20' suffix refers to the optimum effective bits per pixel which is
+achieved when the total number of luminance samples is a multiple of 4.
+
+
+Description
+===========
+
+This is a packed 10-bit two-plane version of the YUV 4:2:2 format. The
+three components are separated into two sub-images or planes. The Y plane
+is first. The Y plane has five bytes per each group of four pixels. A
+combined CbCr plane immediately follows the Y plane in memory. The CbCr
+plane is the same width and height, in bytes, as the Y plane (and of the
+image). Each CbCr pair belongs to two pixels. For example,
+Cb\ :sub:`00`/Cr\ :sub:`00` belongs to Y'\ :sub:`00`, Y'\ :sub:`01`.
+
+If the Y plane has pad bytes after each row, then the CbCr plane has as
+many pad bytes after its rows.
+
+**Byte Order.**
+Little endian. Each cell is one byte. Pixels cross the byte boundary.
+
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * - start + 0:
+ - Y'\ :sub:`00[7:0]`
+ - Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]`
+ - Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]`
+ - Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]`
+ - Y'\ :sub:`03[9:2]`
+ * - start + 5:
+ - Y'\ :sub:`10[7:0]`
+ - Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]`
+ - Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]`
+ - Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]`
+ - Y'\ :sub:`13[9:2]`
+ * - start + 10:
+ - Cb'\ :sub:`00[7:0]`
+ - Cr'\ :sub:`00[5:0]`\ Cb'\ :sub:`00[9:8]`
+ - Cb'\ :sub:`01[3:0]`\ Cr'\ :sub:`00[9:6]`
+ - Cr'\ :sub:`01[1:0]`\ Cb'\ :sub:`01[9:4]`
+ - Cr'\ :sub:`01[9:2]`
+ * - start + 15:
+ - Cb'\ :sub:`10[7:0]`
+ - Cr'\ :sub:`10[5:0]`\ Cb'\ :sub:`10[9:8]`
+ - Cb'\ :sub:`11[3:0]`\ Cr'\ :sub:`10[9:6]`
+ - Cr'\ :sub:`11[1:0]`\ Cb'\ :sub:`11[9:4]`
+ - Cr'\ :sub:`11[9:2]`
+
+
+**Color Sample Location:**
+
+.. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+
+ * -
+ - 0
+ -
+ - 1
+ - 2
+ -
+ - 3
+ * - 0
+ - Y
+ - C
+ - Y
+ - Y
+ - C
+ - Y
+ * - 1
+ - Y
+ - C
+ - Y
+ - Y
+ - C
+ - Y
diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst
index 8ee92d0cd769..7cca883f178a 100644
--- a/Documentation/userspace-api/media/v4l/yuv-formats.rst
+++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst
@@ -61,4 +61,6 @@ to brightness information.
pixfmt-nv16
pixfmt-nv16m
pixfmt-nv24
+ pixfmt-nv15
+ pixfmt-nv20
pixfmt-m420
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 4102c373b48a..0caac755d303 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -267,6 +267,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_NV15, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 2, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } },
+ { .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 5, 0, 0 }, .hdiv = 2, .vdiv = 1, .block_w = { 4, 2, 0, 0 }, .block_h = { 1, 1, 0, 0 } },
+
{ .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 },
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index ccf947632a3b..53de49087938 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1321,6 +1321,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break;
case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break;
case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break;
+ case V4L2_PIX_FMT_NV15: descr = "10-bit Y/CbCr 4:2:0 (Packed)"; break;
+ case V4L2_PIX_FMT_NV20: descr = "10-bit Y/CbCr 4:2:2 (Packed)"; break;
case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 6fe8822d2cb4..c8d7148cd9ae 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -610,6 +610,9 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */
#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */
+#define V4L2_PIX_FMT_NV15 v4l2_fourcc('N', 'V', '1', '5') /* 15 Y/CbCr 4:2:0 10-bit packed */
+#define V4L2_PIX_FMT_NV20 v4l2_fourcc('N', 'V', '2', '0') /* 20 Y/CbCr 4:2:2 10-bit packed */
+
/* two non contiguous planes - one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */
From d09e5dfbcc096eddf5c5d11744d53bae5f1f7d00 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:36 +0000
Subject: [PATCH] media: rkvdec: h264: Use bytesperline and buffer height to
calculate stride
Use bytesperline and buffer height to calculate the strides configured.
This does not really change anything other than ensuring the bytesperline
that is signaled to userspace matches what is configured in HW.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index 2e7749bac417..d33fccc92205 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -893,9 +893,9 @@ static void config_registers(struct rkvdec_ctx *ctx,
dma_addr_t rlc_addr;
dma_addr_t refer_addr;
u32 rlc_len;
- u32 hor_virstride = 0;
- u32 ver_virstride = 0;
- u32 y_virstride = 0;
+ u32 hor_virstride;
+ u32 ver_virstride;
+ u32 y_virstride;
u32 yuv_virstride = 0;
u32 offset;
dma_addr_t dst_addr;
@@ -906,8 +906,8 @@ static void config_registers(struct rkvdec_ctx *ctx,
f = &ctx->decoded_fmt;
dst_fmt = &f->fmt.pix_mp;
- hor_virstride = (sps->bit_depth_luma_minus8 + 8) * dst_fmt->width / 8;
- ver_virstride = round_up(dst_fmt->height, 16);
+ hor_virstride = dst_fmt->plane_fmt[0].bytesperline;
+ ver_virstride = dst_fmt->height;
y_virstride = hor_virstride * ver_virstride;
if (sps->chroma_format_idc == 0)
From f0e873d66825fcd9ea314dcdab0d214226b2b8b4 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: Extract rkvdec_fill_decoded_pixfmt helper
method
This extract setting decoded pixfmt into a helper method, current code is
replaced with a call to the new helper method.
The helper method is also called from a new function in next patch.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 29 ++++++++++++++-------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 06fc58440cd3..dc16bf8d57a9 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -27,6 +27,17 @@
#include "rkvdec.h"
#include "rkvdec-regs.h"
+static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
+ struct v4l2_pix_format_mplane *pix_mp)
+{
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
+ pix_mp->width, pix_mp->height);
+ pix_mp->plane_fmt[0].sizeimage += 128 *
+ DIV_ROUND_UP(pix_mp->width, 16) *
+ DIV_ROUND_UP(pix_mp->height, 16);
+ pix_mp->field = V4L2_FIELD_NONE;
+}
+
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
@@ -167,13 +178,9 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx)
rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- v4l2_fill_pixfmt_mp(&f->fmt.pix_mp,
- ctx->coded_fmt_desc->decoded_fmts[0],
- ctx->coded_fmt.fmt.pix_mp.width,
- ctx->coded_fmt.fmt.pix_mp.height);
- f->fmt.pix_mp.plane_fmt[0].sizeimage += 128 *
- DIV_ROUND_UP(f->fmt.pix_mp.width, 16) *
- DIV_ROUND_UP(f->fmt.pix_mp.height, 16);
+ f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
+ f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height;
+ rkvdec_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp);
}
static int rkvdec_enum_framesizes(struct file *file, void *priv,
@@ -239,13 +246,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
&pix_mp->height,
&coded_desc->frmsize);
- v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
- pix_mp->width, pix_mp->height);
- pix_mp->plane_fmt[0].sizeimage +=
- 128 *
- DIV_ROUND_UP(pix_mp->width, 16) *
- DIV_ROUND_UP(pix_mp->height, 16);
- pix_mp->field = V4L2_FIELD_NONE;
+ rkvdec_fill_decoded_pixfmt(ctx, pix_mp);
return 0;
}
From 7743a31004da67bfd0f6246deaa59e670230c84e Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: Lock capture pixel format in s_ctrl and s_fmt
Add an optional valid_fmt operation that should return the valid
pixelformat of CAPTURE buffers.
This is used in next patch to ensure correct pixelformat is used for 10-bit
and 4:2:2 content.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec.c | 59 ++++++++++++++++++++++++---
drivers/staging/media/rkvdec/rkvdec.h | 2 +
2 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index dc16bf8d57a9..6b2a2f4164b2 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -38,6 +38,16 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
pix_mp->field = V4L2_FIELD_NONE;
}
+static u32 rkvdec_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ const struct rkvdec_coded_fmt_desc *coded_desc = ctx->coded_fmt_desc;
+
+ if (coded_desc->ops->valid_fmt)
+ return coded_desc->ops->valid_fmt(ctx, ctrl);
+
+ return ctx->valid_fmt;
+}
+
static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
@@ -60,6 +70,10 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
/* Only 8-bit is supported */
return -EINVAL;
+ if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl))
+ /* Only current valid format */
+ return -EINVAL;
+
width = (sps->pic_width_in_mbs_minus1 + 1) * 16;
height = (sps->pic_height_in_map_units_minus1 + 1) * 16;
@@ -70,8 +84,27 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl);
+
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS && !ctx->valid_fmt) {
+ ctx->valid_fmt = rkvdec_valid_fmt(ctx, ctrl);
+ if (ctx->valid_fmt) {
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ pix_mp = &ctx->decoded_fmt.fmt.pix_mp;
+ pix_mp->pixelformat = ctx->valid_fmt;
+ rkvdec_fill_decoded_pixfmt(ctx, pix_mp);
+ }
+ }
+
+ return 0;
+}
+
static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = {
.try_ctrl = rkvdec_try_ctrl,
+ .s_ctrl = rkvdec_s_ctrl,
};
static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
@@ -176,6 +209,7 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx)
{
struct v4l2_format *f = &ctx->decoded_fmt;
+ ctx->valid_fmt = 0;
rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]);
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width;
@@ -231,13 +265,17 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv,
if (WARN_ON(!coded_desc))
return -EINVAL;
- for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
- if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
- break;
- }
+ if (ctx->valid_fmt) {
+ pix_mp->pixelformat = ctx->valid_fmt;
+ } else {
+ for (i = 0; i < coded_desc->num_decoded_fmts; i++) {
+ if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat)
+ break;
+ }
- if (i == coded_desc->num_decoded_fmts)
- pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+ if (i == coded_desc->num_decoded_fmts)
+ pix_mp->pixelformat = coded_desc->decoded_fmts[0];
+ }
/* Always apply the frmsize constraint of the coded end. */
pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width);
@@ -312,6 +350,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv,
return ret;
ctx->decoded_fmt = *f;
+ ctx->valid_fmt = f->fmt.pix_mp.pixelformat;
return 0;
}
@@ -401,6 +440,14 @@ static int rkvdec_enum_capture_fmt(struct file *file, void *priv,
if (WARN_ON(!ctx->coded_fmt_desc))
return -EINVAL;
+ if (ctx->valid_fmt) {
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = ctx->valid_fmt;
+ return 0;
+ }
+
if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts)
return -EINVAL;
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index 77a137cca88e..e95c52e3168a 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -63,6 +63,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf)
struct rkvdec_coded_fmt_ops {
int (*adjust_fmt)(struct rkvdec_ctx *ctx,
struct v4l2_format *f);
+ u32 (*valid_fmt)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl);
int (*start)(struct rkvdec_ctx *ctx);
void (*stop)(struct rkvdec_ctx *ctx);
int (*run)(struct rkvdec_ctx *ctx);
@@ -96,6 +97,7 @@ struct rkvdec_ctx {
struct v4l2_fh fh;
struct v4l2_format coded_fmt;
struct v4l2_format decoded_fmt;
+ u32 valid_fmt;
const struct rkvdec_coded_fmt_desc *coded_fmt_desc;
struct v4l2_ctrl_handler ctrl_hdl;
struct rkvdec_dev *dev;
From 15bb8d006a05aecc371e530769f06bf52c2c65bc Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:37 +0000
Subject: [PATCH] media: rkvdec: h264: Support High 10 and 4:2:2 profiles
Add support and enable decoding of H264 High 10 and 4:2:2 profiles.
Decoded CAPTURE buffer width is aligned to 64 pixels to accommodate HW
requirement on 10-bit format buffers.
The new valid_fmt operation is implemented and return a valid pixelformat
for the provided SPS control.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/staging/media/rkvdec/rkvdec-h264.c | 20 ++++++++++++++++++++
drivers/staging/media/rkvdec/rkvdec.c | 19 +++++++++----------
2 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c
index d33fccc92205..afc695d32186 100644
--- a/drivers/staging/media/rkvdec/rkvdec-h264.c
+++ b/drivers/staging/media/rkvdec/rkvdec-h264.c
@@ -1021,6 +1021,25 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx,
return 0;
}
+static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+ if (sps->bit_depth_luma_minus8 == 0) {
+ if (sps->chroma_format_idc == 2)
+ return V4L2_PIX_FMT_NV16;
+ else
+ return V4L2_PIX_FMT_NV12;
+ } else if (sps->bit_depth_luma_minus8 == 2) {
+ if (sps->chroma_format_idc == 2)
+ return V4L2_PIX_FMT_NV20;
+ else
+ return V4L2_PIX_FMT_NV15;
+ }
+
+ return 0;
+}
+
static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
{
struct rkvdec_dev *rkvdec = ctx->dev;
@@ -1124,6 +1143,7 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = {
.adjust_fmt = rkvdec_h264_adjust_fmt,
+ .valid_fmt = rkvdec_h264_valid_fmt,
.start = rkvdec_h264_start,
.stop = rkvdec_h264_stop,
.run = rkvdec_h264_run,
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 6b2a2f4164b2..bd8ec2915fe9 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -31,7 +31,7 @@ static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp)
{
v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
- pix_mp->width, pix_mp->height);
+ ALIGN(pix_mp->width, 64), pix_mp->height);
pix_mp->plane_fmt[0].sizeimage += 128 *
DIV_ROUND_UP(pix_mp->width, 16) *
DIV_ROUND_UP(pix_mp->height, 16);
@@ -55,19 +55,15 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl)
if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) {
const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
unsigned int width, height;
- /*
- * TODO: The hardware supports 10-bit and 4:2:2 profiles,
- * but it's currently broken in the driver.
- * Reject them for now, until it's fixed.
- */
- if (sps->chroma_format_idc > 1)
- /* Only 4:0:0 and 4:2:0 are supported */
+
+ if (sps->chroma_format_idc > 2)
+ /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */
return -EINVAL;
if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
/* Luma and chroma bit depth mismatch */
return -EINVAL;
- if (sps->bit_depth_luma_minus8 != 0)
- /* Only 8-bit is supported */
+ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+ /* Only 8-bit and 10-bit is supported */
return -EINVAL;
if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_valid_fmt(ctx, ctrl))
@@ -145,6 +141,9 @@ static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
static const u32 rkvdec_h264_decoded_fmts[] = {
V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_NV15,
+ V4L2_PIX_FMT_NV16,
+ V4L2_PIX_FMT_NV20,
};
static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
From 26aca7fda4117f4bff16e3fb5349878fb322410b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Mon, 6 Jul 2020 21:54:38 +0000
Subject: [PATCH] media: rkvdec: h264: Support profile and level controls
The Rockchip Video Decoder used in RK3399 supports H.264 profiles from
Baseline to High 4:2:2 up to Level 5.1, except for the Extended profile.
Expose the V4L2_CID_MPEG_VIDEO_H264_PROFILE and the
V4L2_CID_MPEG_VIDEO_H264_LEVEL control, so that userspace can query the
driver for the list of supported profiles and level.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/rkvdec.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index bd8ec2915fe9..87987a782d75 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -132,6 +132,19 @@ static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = {
.cfg.def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
.cfg.max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
},
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE,
+ .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422,
+ .cfg.menu_skip_mask =
+ BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
+ .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
+ },
};
static const struct rkvdec_ctrls rkvdec_h264_ctrls = {
From 272e8a34d1803cc88e74de99b10330cd57d18f26 Mon Sep 17 00:00:00 2001
From: Ezequiel Garcia <ezequiel@collabora.com>
Date: Mon, 18 May 2020 14:40:09 -0300
Subject: [PATCH] media: rkvdec: Fix .buf_prepare
The driver should only set the payload on .buf_prepare
if the buffer is CAPTURE type, or if an OUTPUT buffer
has a zeroed payload.
Fix it.
Fixes: cd33c830448ba ("media: rkvdec: Add the rkvdec driver")
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/rkvdec.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 87987a782d75..91f8a1bb6176 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -543,7 +543,15 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb)
if (vb2_plane_size(vb, i) < sizeimage)
return -EINVAL;
}
- vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage);
+
+ /*
+ * Buffer's bytesused is written by the driver for CAPTURE buffers,
+ * or if the application passed zero bytesused on an OUTPUT buffer.
+ */
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type) ||
+ (V4L2_TYPE_IS_OUTPUT(vq->type) && !vb2_get_plane_payload(vb, 0)))
+ vb2_set_plane_payload(vb, 0,
+ f->fmt.pix_mp.plane_fmt[0].sizeimage);
return 0;
}
From 6e771db436797df6146b1fe0ec94d4138bdaa2bc Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@collabora.com>
Date: Mon, 18 May 2020 14:40:10 -0300
Subject: [PATCH] media: uapi: Add VP9 stateless decoder controls
Add the VP9 stateless decoder controls plus the documentation that goes
with it.
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
.../userspace-api/media/v4l/biblio.rst | 10 +
.../media/v4l/ext-ctrls-codec.rst | 550 ++++++++++++++++++
drivers/media/v4l2-core/v4l2-ctrls.c | 239 ++++++++
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
include/media/v4l2-ctrls.h | 1 +
include/media/vp9-ctrls.h | 485 +++++++++++++++
6 files changed, 1286 insertions(+)
create mode 100644 include/media/vp9-ctrls.h
diff --git a/Documentation/userspace-api/media/v4l/biblio.rst b/Documentation/userspace-api/media/v4l/biblio.rst
index 3c9634173e82..e09102e572fd 100644
--- a/Documentation/userspace-api/media/v4l/biblio.rst
+++ b/Documentation/userspace-api/media/v4l/biblio.rst
@@ -414,3 +414,13 @@ VP8
:title: RFC 6386: "VP8 Data Format and Decoding Guide"
:author: J. Bankoski et al.
+
+.. _vp9:
+
+VP9
+===
+
+
+:title: VP9 Bitstream & Decoding Process Specification
+
+:author: Adrian Grange (Google), Peter de Rivaz (Argon Design), Jonathan Hunt (Argon Design)
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 03ce87aa5488..ca13b141d8c2 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -2689,6 +2689,556 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
- ``padding[3]``
- Applications and drivers must set this to zero.
+.. _v4l2-mpeg-vp9:
+
+``V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0..3) (struct)``
+ Stores VP9 probabilities attached to a specific frame context. The VP9
+ specification allows using a maximum of 4 contexts. Each frame being
+ decoded refers to one of those context. See section '7.1.2 Refresh
+ probs semantics' section of :ref:`vp9` for more details about these
+ contexts.
+
+ This control is bi-directional:
+
+ * all 4 contexts must be initialized by userspace just after the
+ stream is started and before the first decoding request is submitted.
+ * the referenced context might be read by the kernel when a decoding
+ request is submitted, and will be updated after the decoder is done
+ decoding the frame if the `V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX` flag
+ is set.
+ * contexts will be read back by user space before each decoding request
+ to retrieve the updated probabilities.
+ * userspace will re-initialize the context to their default values when
+ a reset context is required.
+
+ .. note::
+
+ This compound control is not yet part of the public kernel API and
+ it is expected to change.
+
+.. c:type:: v4l2_ctrl_vp9_frame_ctx
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{5.8cm}|p{4.8cm}|p{6.6cm}|
+
+.. flat-table:: struct v4l2_ctrl_vp9_frame_ctx
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - struct :c:type:`v4l2_vp9_probabilities`
+ - ``probs``
+ - Structure with VP9 probabilities attached to the context.
+
+.. c:type:: v4l2_vp9_probabilities
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: struct v4l2_vp9_probabilities
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - __u8
+ - ``tx8[2][1]``
+ - TX 8x8 probabilities.
+ * - __u8
+ - ``tx16[2][2]``
+ - TX 16x16 probabilities.
+ * - __u8
+ - ``tx32[2][3]``
+ - TX 32x32 probabilities.
+ * - __u8
+ - ``coef[4][2][2][6][6][3]``
+ - Coefficient probabilities.
+ * - __u8
+ - ``skip[3]``
+ - Skip probabilities.
+ * - __u8
+ - ``inter_mode[7][3]``
+ - Inter prediction mode probabilities.
+ * - __u8
+ - ``interp_filter[4][2]``
+ - Interpolation filter probabilities.
+ * - __u8
+ - ``is_inter[4]``
+ - Is inter-block probabilities.
+ * - __u8
+ - ``comp_mode[5]``
+ - Compound prediction mode probabilities.
+ * - __u8
+ - ``single_ref[5][2]``
+ - Single reference probabilities.
+ * - __u8
+ - ``comp_mode[5]``
+ - Compound reference probabilities.
+ * - __u8
+ - ``y_mode[4][9]``
+ - Y prediction mode probabilities.
+ * - __u8
+ - ``uv_mode[10][9]``
+ - UV prediction mode probabilities.
+ * - __u8
+ - ``partition[16][3]``
+ - Partition probabilities.
+ * - __u8
+ - ``mv.joint[3]``
+ - Motion vector joint probabilities.
+ * - __u8
+ - ``mv.sign[2]``
+ - Motion vector sign probabilities.
+ * - __u8
+ - ``mv.class[2][10]``
+ - Motion vector class probabilities.
+ * - __u8
+ - ``mv.class0_bit[2]``
+ - Motion vector class0 bit probabilities.
+ * - __u8
+ - ``mv.bits[2][10]``
+ - Motion vector bits probabilities.
+ * - __u8
+ - ``mv.class0_fr[2][2][3]``
+ - Motion vector class0 fractional bit probabilities.
+ * - __u8
+ - ``mv.fr[2][3]``
+ - Motion vector fractional bit probabilities.
+ * - __u8
+ - ``mv.class0_hp[2]``
+ - Motion vector class0 high precision fractional bit probabilities.
+ * - __u8
+ - ``mv.hp[2]``
+ - Motion vector high precision fractional bit probabilities.
+
+``V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS (struct)``
+ Specifies the frame parameters for the associated VP9 frame decode request.
+ This includes the necessary parameters for configuring a stateless hardware
+ decoding pipeline for VP9. The bitstream parameters are defined according
+ to :ref:`vp9`.
+
+ .. note::
+
+ This compound control is not yet part of the public kernel API and
+ it is expected to change.
+
+.. c:type:: v4l2_ctrl_vp9_frame_decode_params
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: struct v4l2_ctrl_vp9_frame_decode_params
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - __u32
+ - ``flags``
+ - Combination of V4L2_VP9_FRAME_FLAG_* flags. See
+ :c:type:`v4l2_vp9_frame_flags`.
+ * - __u16
+ - ``compressed_header_size``
+ - Compressed header size in bytes.
+ * - __u16
+ - ``uncompressed_header_size``
+ - Uncompressed header size in bytes.
+ * - __u8
+ - ``profile``
+ - VP9 profile. Can be 0, 1, 2 or 3.
+ * - __u8
+ - ``reset_frame_context``
+ - Frame context that should be used/updated when decoding the frame.
+ * - __u8
+ - ``bit_depth``
+ - Component depth in bits. Must be 8 for profile 0 and 1. Must 10 or 12
+ for profile 2 and 3.
+ * - __u8
+ - ``interpolation_filter``
+ - Specifies the filter selection used for performing inter prediction. See
+ :c:type:`v4l2_vp9_interpolation_filter`.
+ * - __u8
+ - ``tile_cols_log2``
+ - Specifies the base 2 logarithm of the width of each tile (where the
+ width is measured in units of 8x8 blocks). Shall be less than or equal
+ to 6.
+ * - __u8
+ - ``tile_rows_log2``
+ - Specifies the base 2 logarithm of the height of each tile (where the
+ height is measured in units of 8x8 blocks)
+ * - __u8
+ - ``tx_mode``
+ - Specifies the TX mode. See :c:type:`v4l2_vp9_tx_mode`.
+ * - __u8
+ - ``reference_mode``
+ - Specifies the type of inter prediction to be used. See
+ :c:type:`v4l2_vp9_reference_mode`.
+ * - __u8
+ - ``padding``
+ - Needed to make this struct 64 bit aligned. Shall be filled with zeroes.
+ * - __u16
+ - ``frame_width_minus_1``
+ - Add 1 to get the frame width expressed in pixels.
+ * - __u16
+ - ``frame_height_minus_1``
+ - Add 1 to to get the frame height expressed in pixels.
+ * - __u16
+ - ``frame_width_minus_1``
+ - Add 1 to to get the expected render width expressed in pixels. This is
+ not used during the decoding process but might be used by HW scalers to
+ prepare a frame that's ready for scanout.
+ * - __u16
+ - frame_height_minus_1
+ - Add 1 to get the expected render height expressed in pixels. This is
+ not used during the decoding process but might be used by HW scalers to
+ prepare a frame that's ready for scanout.
+ * - __u64
+ - ``refs[3]``
+ - Array of reference frame timestamps.
+ * - struct :c:type:`v4l2_vp9_loop_filter`
+ - ``lf``
+ - Loop filter parameters. See struct :c:type:`v4l2_vp9_loop_filter`.
+ * - struct :c:type:`v4l2_vp9_quantization`
+ - ``quant``
+ - Quantization parameters. See :c:type:`v4l2_vp9_quantization`.
+ * - struct :c:type:`v4l2_vp9_segmentation`
+ - ``seg``
+ - Segmentation parameters. See :c:type:`v4l2_vp9_segmentation`.
+ * - struct :c:type:`v4l2_vp9_probabilities`
+ - ``probs``
+ - Probabilities. See :c:type:`v4l2_vp9_probabilities`.
+
+.. c:type:: v4l2_vp9_frame_flags
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_frame_flags
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_FRAME_FLAG_KEY_FRAME``
+ - The frame is a key frame.
+ * - ``V4L2_VP9_FRAME_FLAG_SHOW_FRAME``
+ - The frame should be displayed.
+ * - ``V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT``
+ - The decoding should be error resilient.
+ * - ``V4L2_VP9_FRAME_FLAG_INTRA_ONLY``
+ - The frame does not reference other frames.
+ * - ``V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV``
+ - the frame might can high precision motion vectors.
+ * - ``V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX``
+ - Frame context should be updated after decoding.
+ * - ``V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE``
+ - Parallel decoding is used.
+ * - ``V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING``
+ - Vertical subsampling is enabled.
+ * - ``V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING``
+ - Horizontal subsampling is enabled.
+ * - ``V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING``
+ - The full UV range is used.
+
+.. c:type:: v4l2_vp9_ref_id
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_ref_id
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_REF_ID_LAST``
+ - Last reference frame.
+ * - ``V4L2_REF_ID_GOLDEN``
+ - Golden reference frame.
+ * - ``V4L2_REF_ID_ALTREF``
+ - Alternative reference frame.
+ * - ``V4L2_REF_ID_CNT``
+ - Number of reference frames.
+
+.. c:type:: v4l2_vp9_tx_mode
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_tx_mode
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_TX_MODE_ONLY_4X4``
+ - Transform size is 4x4.
+ * - ``V4L2_VP9_TX_MODE_ALLOW_8X8``
+ - Transform size can be up to 8x8.
+ * - ``V4L2_VP9_TX_MODE_ALLOW_16X16``
+ - Transform size can be up to 16x16.
+ * - ``V4L2_VP9_TX_MODE_ALLOW_32X32``
+ - transform size can be up to 32x32.
+ * - ``V4L2_VP9_TX_MODE_SELECT``
+ - Bitstream contains transform size for each block.
+
+.. c:type:: v4l2_vp9_reference_mode
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_reference_mode
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_REF_MODE_SINGLE``
+ - Indicates that all the inter blocks use only a single reference frame
+ to generate motion compensated prediction.
+ * - ``V4L2_VP9_REF_MODE_COMPOUND``
+ - Requires all the inter blocks to use compound mode. Single reference
+ frame prediction is not allowed.
+ * - ``V4L2_VP9_REF_MODE_SELECT``
+ - Allows each individual inter block to select between single and
+ compound prediction modes.
+
+.. c:type:: v4l2_vp9_interpolation_filter
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_interpolation_filter
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_INTERP_FILTER_8TAP``
+ - Height tap filter.
+ * - ``V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH``
+ - Height tap smooth filter.
+ * - ``V4L2_VP9_INTERP_FILTER_8TAP_SHARP``
+ - Height tap sharp filter.
+ * - ``V4L2_VP9_INTERP_FILTER_BILINEAR``
+ - Bilinear filter.
+ * - ``V4L2_VP9_INTERP_FILTER_SWITCHABLE``
+ - Filter selection is signaled at the block level.
+
+.. c:type:: v4l2_vp9_reset_frame_context
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_reset_frame_context
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_RESET_FRAME_CTX_NONE``
+ - Do not reset any frame context.
+ * - ``V4L2_VP9_RESET_FRAME_CTX_SPEC``
+ - Reset the frame context pointed by
+ :c:type:`v4l2_ctrl_vp9_frame_decode_params`.frame_context_idx.
+ * - ``V4L2_VP9_RESET_FRAME_CTX_ALL``
+ - Reset all frame contexts.
+
+.. c:type:: v4l2_vp9_intra_prediction_mode
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_intra_prediction_mode
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_INTRA_PRED_DC``
+ - DC intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_V``
+ - Vertical intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_H``
+ - Horizontal intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_D45``
+ - D45 intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_D135``
+ - D135 intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_D117``
+ - D117 intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_D153``
+ - D153 intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_D207``
+ - D207 intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_D63``
+ - D63 intra prediction.
+ * - ``V4L2_VP9_INTRA_PRED_MODE_TM``
+ - True motion intra prediction.
+
+.. c:type:: v4l2_vp9_segmentation
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: struct v4l2_vp9_segmentation
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - __u8
+ - ``flags``
+ - Combination of V4L2_VP9_SEGMENTATION_FLAG_* flags. See
+ :c:type:`v4l2_vp9_segmentation_flags`.
+ * - __u8
+ - ``tree_probs[7]``
+ - Specifies the probability values to be used when decoding a Segment-ID.
+ See '5.15. Segmentation map' section of :ref:`vp9` for more details.
+ * - __u8
+ - ``pred_prob[3]``
+ - Specifies the probability values to be used when decoding a
+ Predicted-Segment-ID. See '6.4.14. Get segment id syntax'
+ section of :ref:`vp9` for more details.
+ * - __u8
+ - ``padding[5]``
+ - Used to align this struct on 64 bit. Shall be filled with zeroes.
+ * - __u8
+ - ``feature_enabled[8]``
+ - Bitmask defining which features are enabled in each segment.
+ * - __u8
+ - ``feature_data[8][4]``
+ - Data attached to each feature. Data entry is only valid if the feature
+ is enabled.
+
+.. c:type:: v4l2_vp9_segment_feature
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_segment_feature
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_SEGMENT_FEATURE_QP_DELTA``
+ - QP delta segment feature.
+ * - ``V4L2_VP9_SEGMENT_FEATURE_LF``
+ - Loop filter segment feature.
+ * - ``V4L2_VP9_SEGMENT_FEATURE_REF_FRAME``
+ - Reference frame segment feature.
+ * - ``V4L2_VP9_SEGMENT_FEATURE_SKIP``
+ - Skip segment feature.
+ * - ``V4L2_VP9_SEGMENT_FEATURE_CNT``
+ - Number of segment features.
+
+.. c:type:: v4l2_vp9_segmentation_flags
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_segmentation_flags
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_SEGMENTATION_FLAG_ENABLED``
+ - Indicates that this frame makes use of the segmentation tool.
+ * - ``V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP``
+ - Indicates that the segmentation map should be updated during the
+ decoding of this frame.
+ * - ``V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE``
+ - Indicates that the updates to the segmentation map are coded
+ relative to the existing segmentation map.
+ * - ``V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA``
+ - Indicates that new parameters are about to be specified for each
+ segment.
+ * - ``V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE``
+ - Indicates that the segmentation parameters represent the actual values
+ to be used.
+
+.. c:type:: v4l2_vp9_quantization
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: struct v4l2_vp9_quantization
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - __u8
+ - ``base_q_idx``
+ - Indicates the base frame qindex.
+ * - __s8
+ - ``delta_q_y_dc``
+ - Indicates the Y DC quantizer relative to base_q_idx.
+ * - __s8
+ - ``delta_q_uv_dc``
+ - Indicates the UV DC quantizer relative to base_q_idx.
+ * - __s8
+ - ``delta_q_uv_ac``
+ - Indicates the UV AC quantizer relative to base_q_idx.
+ * - __u8
+ - ``padding[4]``
+ - Padding bytes used to align this struct on 64 bit. Must be set to 0.
+
+.. c:type:: v4l2_vp9_loop_filter
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: struct v4l2_vp9_loop_filter
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 1 2
+
+ * - __u8
+ - ``flags``
+ - Combination of V4L2_VP9_LOOP_FILTER_FLAG_* flags.
+ See :c:type:`v4l2_vp9_loop_filter_flags`.
+ * - __u8
+ - ``level``
+ - Indicates the loop filter strength.
+ * - __u8
+ - ``sharpness``
+ - Indicates the sharpness level.
+ * - __s8
+ - ``ref_deltas[4]``
+ - Contains the adjustment needed for the filter level based on the chosen
+ reference frame.
+ * - __s8
+ - ``mode_deltas[2]``
+ - Contains the adjustment needed for the filter level based on the chosen
+ mode
+ * - __u8
+ - ``level_lookup[8][4][2]``
+ - Level lookup table.
+
+
+.. c:type:: v4l2_vp9_loop_filter_flags
+
+.. cssclass:: longtable
+
+.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}|
+
+.. flat-table:: enum v4l2_vp9_loop_filter_flags
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 2
+
+ * - ``V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED``
+ - When set, the filter level depends on the mode and reference frame used
+ to predict a block.
+ * - ``V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE``
+ - When set, the bitstream contains additional syntax elements that
+ specify which mode and reference frame deltas are to be updated.
+
.. raw:: latex
\normalsize
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b846f5b089c9..5913088cbc6f 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -940,6 +940,11 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile";
case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile";
case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: return "VP8 Frame Header";
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS: return "VP9 Frame Decode Parameters";
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0): return "VP9 Frame Context 0";
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1): return "VP9 Frame Context 1";
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2): return "VP9 Frame Context 2";
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3): return "VP9 Frame Context 3";
/* HEVC controls */
case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value";
@@ -1419,6 +1424,15 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER:
*type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER;
break;
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS:
+ *type = V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0):
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1):
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2):
+ case V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3):
+ *type = V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT;
+ break;
case V4L2_CID_MPEG_VIDEO_HEVC_SPS:
*type = V4L2_CTRL_TYPE_HEVC_SPS;
break;
@@ -1721,6 +1735,219 @@ static void std_log(const struct v4l2_ctrl *ctrl)
0; \
})
+static int
+validate_vp9_lf_params(struct v4l2_vp9_loop_filter *lf)
+{
+ unsigned int i, j, k;
+
+ if (lf->flags &
+ ~(V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED |
+ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE))
+ return -EINVAL;
+
+ /*
+ * V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED implies
+ * V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE.
+ */
+ if (lf->flags & V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE &&
+ !(lf->flags & V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED))
+ return -EINVAL;
+
+ /* That all values are in the accepted range. */
+ if (lf->level > GENMASK(5, 0))
+ return -EINVAL;
+
+ if (lf->sharpness > GENMASK(2, 0))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
+ if (lf->ref_deltas[i] < -63 || lf->ref_deltas[i] > 63)
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
+ if (lf->mode_deltas[i] < -63 || lf->mode_deltas[i] > 63)
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(lf->level_lookup); i++) {
+ for (j = 0; j < ARRAY_SIZE(lf->level_lookup[0]); j++) {
+ for (k = 0; k < ARRAY_SIZE(lf->level_lookup[0][0]); k++) {
+ if (lf->level_lookup[i][j][k] > 63)
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+validate_vp9_quant_params(struct v4l2_vp9_quantization *quant)
+{
+ if (quant->delta_q_y_dc < -15 || quant->delta_q_y_dc > 15 ||
+ quant->delta_q_uv_dc < -15 || quant->delta_q_uv_dc > 15 ||
+ quant->delta_q_uv_ac < -15 || quant->delta_q_uv_ac > 15)
+ return -EINVAL;
+
+ memset(quant->padding, 0, sizeof(quant->padding));
+ return 0;
+}
+
+static int
+validate_vp9_seg_params(struct v4l2_vp9_segmentation *seg)
+{
+ unsigned int i, j;
+
+ if (seg->flags &
+ ~(V4L2_VP9_SEGMENTATION_FLAG_ENABLED |
+ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP |
+ V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE |
+ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA |
+ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
+ return -EINVAL;
+
+ /*
+ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP and
+ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA imply
+ * V4L2_VP9_SEGMENTATION_FLAG_ENABLED.
+ */
+ if ((seg->flags &
+ (V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP |
+ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA)) &&
+ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED))
+ return -EINVAL;
+
+ /*
+ * V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE implies
+ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP.
+ */
+ if (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE &&
+ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP))
+ return -EINVAL;
+
+ /*
+ * V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE implies
+ * V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA.
+ */
+ if (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE &&
+ !(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(seg->feature_enabled); i++) {
+ if (seg->feature_enabled[i] &
+ ~(V4L2_VP9_SEGMENT_FEATURE_QP_DELTA |
+ V4L2_VP9_SEGMENT_FEATURE_LF |
+ V4L2_VP9_SEGMENT_FEATURE_REF_FRAME |
+ V4L2_VP9_SEGMENT_FEATURE_SKIP))
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(seg->feature_data); i++) {
+ const int range[] = {255, 63, 3, 0};
+
+ for (j = 0; j < ARRAY_SIZE(seg->feature_data[j]); j++) {
+ if (seg->feature_data[i][j] < -range[j] ||
+ seg->feature_data[i][j] > range[j])
+ return -EINVAL;
+ }
+ }
+
+ memset(seg->padding, 0, sizeof(seg->padding));
+ return 0;
+}
+
+static int
+validate_vp9_frame_decode_params(struct v4l2_ctrl_vp9_frame_decode_params *dec_params)
+{
+ int ret;
+
+ /* Make sure we're not passed invalid flags. */
+ if (dec_params->flags &
+ ~(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_SHOW_FRAME |
+ V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY |
+ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV |
+ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX |
+ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE |
+ V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING |
+ V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING |
+ V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING))
+ return -EINVAL;
+
+ /*
+ * The refresh context and error resilient flags are mutually exclusive.
+ * Same goes for parallel decoding and error resilient modes.
+ */
+ if (dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT &&
+ dec_params->flags &
+ (V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX |
+ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE))
+ return -EINVAL;
+
+ if (dec_params->profile > V4L2_VP9_PROFILE_MAX)
+ return -EINVAL;
+
+ if (dec_params->reset_frame_context > V4L2_VP9_RESET_FRAME_CTX_ALL)
+ return -EINVAL;
+
+ if (dec_params->frame_context_idx >= V4L2_VP9_NUM_FRAME_CTX)
+ return -EINVAL;
+
+ /*
+ * Profiles 0 and 1 only support 8-bit depth, profiles 2 and 3 only 10
+ * and 12 bit depths.
+ */
+ if ((dec_params->profile < 2 && dec_params->bit_depth != 8) ||
+ (dec_params->profile >= 2 &&
+ (dec_params->bit_depth != 10 && dec_params->bit_depth != 12)))
+ return -EINVAL;
+
+ /* Profile 0 and 2 only accept YUV 4:2:0. */
+ if ((dec_params->profile == 0 || dec_params->profile == 2) &&
+ (!(dec_params->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) ||
+ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING)))
+ return -EINVAL;
+
+ /* Profile 1 and 3 only accept YUV 4:2:2, 4:4:0 and 4:4:4. */
+ if ((dec_params->profile == 1 || dec_params->profile == 3) &&
+ ((dec_params->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) &&
+ (dec_params->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING)))
+ return -EINVAL;
+
+ if (dec_params->interpolation_filter > V4L2_VP9_INTERP_FILTER_SWITCHABLE)
+ return -EINVAL;
+
+ /*
+ * According to the spec, tile_cols_log2 shall be less than or equal
+ * to 6.
+ */
+ if (dec_params->tile_cols_log2 > 6)
+ return -EINVAL;
+
+ if (dec_params->tx_mode > V4L2_VP9_TX_MODE_SELECT)
+ return -EINVAL;
+
+ if (dec_params->reference_mode > V4L2_VP9_REF_MODE_SELECT)
+ return -EINVAL;
+
+ ret = validate_vp9_lf_params(&dec_params->lf);
+ if (ret)
+ return ret;
+
+ ret = validate_vp9_quant_params(&dec_params->quant);
+ if (ret)
+ return ret;
+
+ ret = validate_vp9_seg_params(&dec_params->seg);
+ if (ret)
+ return ret;
+
+ memset(dec_params->padding, 0, sizeof(dec_params->padding));
+ return 0;
+}
+
/* Validate a new control */
#define zero_padding(s) \
@@ -1838,6 +2065,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
zero_padding(p_vp8_frame_header->coder_state);
break;
+ case V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS:
+ return validate_vp9_frame_decode_params(p);
+
+ case V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT:
+ break;
+
case V4L2_CTRL_TYPE_HEVC_SPS:
p_hevc_sps = p;
@@ -2584,6 +2817,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_VP8_FRAME_HEADER:
elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header);
break;
+ case V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT:
+ elem_size = sizeof(struct v4l2_ctrl_vp9_frame_ctx);
+ break;
+ case V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS:
+ elem_size = sizeof(struct v4l2_ctrl_vp9_frame_decode_params);
+ break;
case V4L2_CTRL_TYPE_HEVC_SPS:
elem_size = sizeof(struct v4l2_ctrl_hevc_sps);
break;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 53de49087938..22eab942c8d4 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1431,6 +1431,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_VP8: descr = "VP8"; break;
case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break;
case V4L2_PIX_FMT_VP9: descr = "VP9"; break;
+ case V4L2_PIX_FMT_VP9_FRAME: descr = "VP9 Frame"; break;
case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */
case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break;
case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index cb25f345e9ad..c427acc964b9 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -21,6 +21,7 @@
#include <media/fwht-ctrls.h>
#include <media/h264-ctrls.h>
#include <media/vp8-ctrls.h>
+#include <media/vp9-ctrls.h>
#include <media/hevc-ctrls.h>
/* forward references */
diff --git a/include/media/vp9-ctrls.h b/include/media/vp9-ctrls.h
new file mode 100644
index 000000000000..0cdea8a18b72
--- /dev/null
+++ b/include/media/vp9-ctrls.h
@@ -0,0 +1,485 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * These are the VP9 state controls for use with stateless VP9
+ * codec drivers.
+ *
+ * It turns out that these structs are not stable yet and will undergo
+ * more changes. So keep them private until they are stable and ready to
+ * become part of the official public API.
+ */
+
+#ifndef _VP9_CTRLS_H_
+#define _VP9_CTRLS_H_
+
+#include <linux/types.h>
+
+#define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F')
+
+#define V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(i) (V4L2_CID_MPEG_BASE + 4000 + (i))
+#define V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS (V4L2_CID_MPEG_BASE + 4004)
+#define V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT 0x400
+#define V4L2_CTRL_TYPE_VP9_FRAME_DECODE_PARAMS 0x404
+
+/**
+ * enum v4l2_vp9_loop_filter_flags - VP9 loop filter flags
+ *
+ * @V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED: the filter level depends on
+ * the mode and reference frame used
+ * to predict a block
+ * @V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE: the bitstream contains additional
+ * syntax elements that specify which
+ * mode and reference frame deltas
+ * are to be updated
+ *
+ * Those are the flags you should pass to &v4l2_vp9_loop_filter.flags. See
+ * section '7.2.8 Loop filter semantics' of the VP9 specification for more
+ * details.
+ */
+enum v4l2_vp9_loop_filter_flags {
+ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED = 1 << 0,
+ V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE = 1 << 1,
+};
+
+/**
+ * struct v4l2_vp9_loop_filter - VP9 loop filter parameters
+ *
+ * @flags: combination of V4L2_VP9_LOOP_FILTER_FLAG_* flags
+ * @level: indicates the loop filter strength
+ * @sharpness: indicates the sharpness level
+ * @ref_deltas: contains the adjustment needed for the filter level based on
+ * the chosen reference frame
+ * @mode_deltas: contains the adjustment needed for the filter level based on
+ * the chosen mode
+ * @level_lookup: level lookup table
+ *
+ * This structure contains all loop filter related parameters. See sections
+ * '7.2.8 Loop filter semantics' and '8.8.1 Loop filter frame init process'
+ * of the VP9 specification for more details.
+ */
+struct v4l2_vp9_loop_filter {
+ __u8 flags;
+ __u8 level;
+ __u8 sharpness;
+ __s8 ref_deltas[4];
+ __s8 mode_deltas[2];
+ __u8 level_lookup[8][4][2];
+};
+
+/**
+ * struct v4l2_vp9_quantization - VP9 quantization parameters
+ *
+ * @base_q_idx: indicates the base frame qindex
+ * @delta_q_y_dc: indicates the Y DC quantizer relative to base_q_idx
+ * @delta_q_uv_dc: indicates the UV DC quantizer relative to base_q_idx
+ * @delta_q_uv_ac indicates the UV AC quantizer relative to base_q_idx
+ * @padding: padding bytes to align things on 64 bits. Must be set to 0
+ *
+ * Encodes the quantization parameters. See section '7.2.9 Quantization params
+ * syntax' of the VP9 specification for more details.
+ */
+struct v4l2_vp9_quantization {
+ __u8 base_q_idx;
+ __s8 delta_q_y_dc;
+ __s8 delta_q_uv_dc;
+ __s8 delta_q_uv_ac;
+ __u8 padding[4];
+};
+
+/**
+ * enum v4l2_vp9_segmentation_flags - VP9 segmentation flags
+ *
+ * @V4L2_VP9_SEGMENTATION_FLAG_ENABLED: indicates that this frame makes use of
+ * the segmentation tool
+ * @V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP: indicates that the segmentation map
+ * should be updated during the
+ * decoding of this frame
+ * @V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE: indicates that the updates to
+ * the segmentation map are coded
+ * relative to the existing
+ * segmentation map
+ * @V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA: indicates that new parameters are
+ * about to be specified for each
+ * segment
+ * @V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE: indicates that the
+ * segmentation parameters
+ * represent the actual values
+ * to be used
+ *
+ * Those are the flags you should pass to &v4l2_vp9_segmentation.flags. See
+ * section '7.2.10 Segmentation params syntax' of the VP9 specification for
+ * more details.
+ */
+enum v4l2_vp9_segmentation_flags {
+ V4L2_VP9_SEGMENTATION_FLAG_ENABLED = 1 << 0,
+ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP = 1 << 1,
+ V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE = 1 << 2,
+ V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA = 1 << 3,
+ V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE = 1 << 4,
+};
+
+#define V4L2_VP9_SEGMENT_FEATURE_ENABLED(id) (1 << (id))
+#define V4L2_VP9_SEGMENT_FEATURE_ENABLED_MASK 0xf
+
+/**
+ * enum v4l2_vp9_segment_feature - VP9 segment feature IDs
+ *
+ * @V4L2_VP9_SEGMENT_FEATURE_QP_DELTA: QP delta segment feature
+ * @V4L2_VP9_SEGMENT_FEATURE_LF: loop filter segment feature
+ * @V4L2_VP9_SEGMENT_FEATURE_REF_FRAME: reference frame segment feature
+ * @V4L2_VP9_SEGMENT_FEATURE_SKIP: skip segment feature
+ * @V4L2_VP9_SEGMENT_FEATURE_CNT: number of segment features
+ *
+ * Segment feature IDs. See section '7.2.10 Segmentation params syntax' of the
+ * VP9 specification for more details.
+ */
+enum v4l2_vp9_segment_feature {
+ V4L2_VP9_SEGMENT_FEATURE_QP_DELTA,
+ V4L2_VP9_SEGMENT_FEATURE_LF,
+ V4L2_VP9_SEGMENT_FEATURE_REF_FRAME,
+ V4L2_VP9_SEGMENT_FEATURE_SKIP,
+ V4L2_VP9_SEGMENT_FEATURE_CNT,
+};
+
+/**
+ * struct v4l2_vp9_segmentation - VP9 segmentation parameters
+ *
+ * @flags: combination of V4L2_VP9_SEGMENTATION_FLAG_* flags
+ * @tree_probs: specifies the probability values to be used when
+ * decoding a Segment-ID. See '5.15. Segmentation map'
+ * section of the VP9 specification for more details.
+ * @pred_prob: specifies the probability values to be used when decoding a
+ * Predicted-Segment-ID. See '6.4.14. Get segment id syntax'
+ * section of :ref:`vp9` for more details..
+ * @padding: padding used to make things aligned on 64 bits. Shall be zero
+ * filled
+ * @feature_enabled: bitmask defining which features are enabled in each
+ * segment
+ * @feature_data: data attached to each feature. Data entry is only valid if
+ * the feature is enabled
+ *
+ * Encodes the quantization parameters. See section '7.2.10 Segmentation
+ * params syntax' of the VP9 specification for more details.
+ */
+struct v4l2_vp9_segmentation {
+ __u8 flags;
+ __u8 tree_probs[7];
+ __u8 pred_probs[3];
+ __u8 padding[5];
+ __u8 feature_enabled[8];
+ __s16 feature_data[8][4];
+};
+
+/**
+ * enum v4l2_vp9_intra_prediction_mode - VP9 Intra prediction modes
+ *
+ * @V4L2_VP9_INTRA_PRED_DC: DC intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_V: vertical intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_H: horizontal intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_D45: D45 intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_D135: D135 intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_D117: D117 intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_D153: D153 intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_D207: D207 intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_D63: D63 intra prediction
+ * @V4L2_VP9_INTRA_PRED_MODE_TM: True Motion intra prediction
+ *
+ * See section '7.4.5 Intra frame mode info semantics' for more details.
+ */
+enum v4l2_vp9_intra_prediction_mode {
+ V4L2_VP9_INTRA_PRED_MODE_DC,
+ V4L2_VP9_INTRA_PRED_MODE_V,
+ V4L2_VP9_INTRA_PRED_MODE_H,
+ V4L2_VP9_INTRA_PRED_MODE_D45,
+ V4L2_VP9_INTRA_PRED_MODE_D135,
+ V4L2_VP9_INTRA_PRED_MODE_D117,
+ V4L2_VP9_INTRA_PRED_MODE_D153,
+ V4L2_VP9_INTRA_PRED_MODE_D207,
+ V4L2_VP9_INTRA_PRED_MODE_D63,
+ V4L2_VP9_INTRA_PRED_MODE_TM,
+};
+
+/**
+ * struct v4l2_vp9_mv_probabilities - VP9 Motion vector probabilities
+ * @joint: motion vector joint probabilities
+ * @sign: motion vector sign probabilities
+ * @class: motion vector class probabilities
+ * @class0_bit: motion vector class0 bit probabilities
+ * @bits: motion vector bits probabilities
+ * @class0_fr: motion vector class0 fractional bit probabilities
+ * @fr: motion vector fractional bit probabilities
+ * @class0_hp: motion vector class0 high precision fractional bit probabilities
+ * @hp: motion vector high precision fractional bit probabilities
+ */
+struct v4l2_vp9_mv_probabilities {
+ __u8 joint[3];
+ __u8 sign[2];
+ __u8 class[2][10];
+ __u8 class0_bit[2];
+ __u8 bits[2][10];
+ __u8 class0_fr[2][2][3];
+ __u8 fr[2][3];
+ __u8 class0_hp[2];
+ __u8 hp[2];
+};
+
+/**
+ * struct v4l2_vp9_probabilities - VP9 Probabilities
+ *
+ * @tx8: TX 8x8 probabilities
+ * @tx16: TX 16x16 probabilities
+ * @tx32: TX 32x32 probabilities
+ * @coef: coefficient probabilities
+ * @skip: skip probabilities
+ * @inter_mode: inter mode probabilities
+ * @interp_filter: interpolation filter probabilities
+ * @is_inter: is inter-block probabilities
+ * @comp_mode: compound prediction mode probabilities
+ * @single_ref: single ref probabilities
+ * @comp_ref: compound ref probabilities
+ * @y_mode: Y prediction mode probabilities
+ * @uv_mode: UV prediction mode probabilities
+ * @partition: partition probabilities
+ * @mv: motion vector probabilities
+ *
+ * Structure containing most VP9 probabilities. See the VP9 specification
+ * for more details.
+ */
+struct v4l2_vp9_probabilities {
+ __u8 tx8[2][1];
+ __u8 tx16[2][2];
+ __u8 tx32[2][3];
+ __u8 coef[4][2][2][6][6][3];
+ __u8 skip[3];
+ __u8 inter_mode[7][3];
+ __u8 interp_filter[4][2];
+ __u8 is_inter[4];
+ __u8 comp_mode[5];
+ __u8 single_ref[5][2];
+ __u8 comp_ref[5];
+ __u8 y_mode[4][9];
+ __u8 uv_mode[10][9];
+ __u8 partition[16][3];
+
+ struct v4l2_vp9_mv_probabilities mv;
+};
+
+/**
+ * enum v4l2_vp9_reset_frame_context - Valid values for
+ * &v4l2_ctrl_vp9_frame_decode_params->reset_frame_context
+ *
+ * @V4L2_VP9_RESET_FRAME_CTX_NONE: don't reset any frame context
+ * @V4L2_VP9_RESET_FRAME_CTX_SPEC: reset the frame context pointed by
+ * &v4l2_ctrl_vp9_frame_decode_params.frame_context_idx
+ * @V4L2_VP9_RESET_FRAME_CTX_ALL: reset all frame contexts
+ *
+ * See section '7.2 Uncompressed header semantics' of the VP9 specification
+ * for more details.
+ */
+enum v4l2_vp9_reset_frame_context {
+ V4L2_VP9_RESET_FRAME_CTX_NONE,
+ V4L2_VP9_RESET_FRAME_CTX_SPEC,
+ V4L2_VP9_RESET_FRAME_CTX_ALL,
+};
+
+/**
+ * enum v4l2_vp9_interpolation_filter - VP9 interpolation filter types
+ *
+ * @V4L2_VP9_INTERP_FILTER_8TAP: height tap filter
+ * @V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH: height tap smooth filter
+ * @V4L2_VP9_INTERP_FILTER_8TAP_SHARP: height tap sharp filter
+ * @V4L2_VP9_INTERP_FILTER_BILINEAR: bilinear filter
+ * @V4L2_VP9_INTERP_FILTER_SWITCHABLE: filter selection is signaled at the
+ * block level
+ *
+ * See section '7.2.7 Interpolation filter semantics' of the VP9 specification
+ * for more details.
+ */
+enum v4l2_vp9_interpolation_filter {
+ V4L2_VP9_INTERP_FILTER_8TAP,
+ V4L2_VP9_INTERP_FILTER_8TAP_SMOOTH,
+ V4L2_VP9_INTERP_FILTER_8TAP_SHARP,
+ V4L2_VP9_INTERP_FILTER_BILINEAR,
+ V4L2_VP9_INTERP_FILTER_SWITCHABLE,
+};
+
+/**
+ * enum v4l2_vp9_reference_mode - VP9 reference modes
+ *
+ * @V4L2_VP9_REF_MODE_SINGLE: indicates that all the inter blocks use only a
+ * single reference frame to generate motion
+ * compensated prediction
+ * @V4L2_VP9_REF_MODE_COMPOUND: requires all the inter blocks to use compound
+ * mode. Single reference frame prediction is not
+ * allowed
+ * @V4L2_VP9_REF_MODE_SELECT: allows each individual inter block to select
+ * between single and compound prediction modes
+ *
+ * See section '7.3.6 Frame reference mode semantics' of the VP9 specification
+ * for more details.
+ */
+enum v4l2_vp9_reference_mode {
+ V4L2_VP9_REF_MODE_SINGLE,
+ V4L2_VP9_REF_MODE_COMPOUND,
+ V4L2_VP9_REF_MODE_SELECT,
+};
+
+/**
+ * enum v4l2_vp9_tx_mode - VP9 TX modes
+ *
+ * @V4L2_VP9_TX_MODE_ONLY_4X4: transform size is 4x4
+ * @V4L2_VP9_TX_MODE_ALLOW_8X8: transform size can be up to 8x8
+ * @V4L2_VP9_TX_MODE_ALLOW_16X16: transform size can be up to 16x16
+ * @V4L2_VP9_TX_MODE_ALLOW_32X32: transform size can be up to 32x32
+ * @V4L2_VP9_TX_MODE_SELECT: bitstream contains transform size for each block
+ *
+ * See section '7.3.1 Tx mode semantics' of the VP9 specification for more
+ * details.
+ */
+enum v4l2_vp9_tx_mode {
+ V4L2_VP9_TX_MODE_ONLY_4X4,
+ V4L2_VP9_TX_MODE_ALLOW_8X8,
+ V4L2_VP9_TX_MODE_ALLOW_16X16,
+ V4L2_VP9_TX_MODE_ALLOW_32X32,
+ V4L2_VP9_TX_MODE_SELECT,
+};
+
+/**
+ * enum v4l2_vp9_ref_id - VP9 Reference frame IDs
+ *
+ * @V4L2_REF_ID_LAST: last reference frame
+ * @V4L2_REF_ID_GOLDEN: golden reference frame
+ * @V4L2_REF_ID_ALTREF: alternative reference frame
+ * @V4L2_REF_ID_CNT: number of reference frames
+ *
+ * See section '7.4.12 Ref frames semantics' of the VP9 specification for more
+ * details.
+ */
+enum v4l2_vp9_ref_id {
+ V4L2_REF_ID_LAST,
+ V4L2_REF_ID_GOLDEN,
+ V4L2_REF_ID_ALTREF,
+ V4L2_REF_ID_CNT,
+};
+
+/**
+ * enum v4l2_vp9_frame_flags - VP9 frame flags
+ * @V4L2_VP9_FRAME_FLAG_KEY_FRAME: the frame is a key frame
+ * @V4L2_VP9_FRAME_FLAG_SHOW_FRAME: the frame should be displayed
+ * @V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT: the decoding should be error resilient
+ * @V4L2_VP9_FRAME_FLAG_INTRA_ONLY: the frame does not reference other frames
+ * @V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV: the frame might can high precision
+ * motion vectors
+ * @V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX: frame context should be updated
+ * after decoding
+ * @V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE: parallel decoding is used
+ * @V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING: vertical subsampling is enabled
+ * @V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING: horizontal subsampling is enabled
+ * @V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING: full UV range is used
+ *
+ * Check the VP9 specification for more details.
+ */
+enum v4l2_vp9_frame_flags {
+ V4L2_VP9_FRAME_FLAG_KEY_FRAME = 1 << 0,
+ V4L2_VP9_FRAME_FLAG_SHOW_FRAME = 1 << 1,
+ V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT = 1 << 2,
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY = 1 << 3,
+ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV = 1 << 4,
+ V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX = 1 << 5,
+ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE = 1 << 6,
+ V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING = 1 << 7,
+ V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING = 1 << 8,
+ V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING = 1 << 9,
+};
+
+#define V4L2_VP9_PROFILE_MAX 3
+
+/**
+ * struct v4l2_ctrl_vp9_frame_decode_params - VP9 frame decoding control
+ *
+ * @flags: combination of V4L2_VP9_FRAME_FLAG_* flags
+ * @compressed_header_size: compressed header size in bytes
+ * @uncompressed_header_size: uncompressed header size in bytes
+ * @profile: VP9 profile. Can be 0, 1, 2 or 3
+ * @reset_frame_context: specifies whether the frame context should be reset
+ * to default values. See &v4l2_vp9_reset_frame_context
+ * for more details
+ * @frame_context_idx: frame context that should be used/updated
+ * @bit_depth: bits per components. Can be 8, 10 or 12. Note that not all
+ * profiles support 10 and/or 12 bits depths
+ * @interpolation_filter: specifies the filter selection used for performing
+ * inter prediction. See &v4l2_vp9_interpolation_filter
+ * for more details
+ * @tile_cols_log2: specifies the base 2 logarithm of the width of each tile
+ * (where the width is measured in units of 8x8 blocks).
+ * Shall be less than or equal to 6
+ * @tile_rows_log2: specifies the base 2 logarithm of the height of each tile
+ * (where the height is measured in units of 8x8 blocks)
+ * @tx_mode: specifies the TX mode. See &v4l2_vp9_tx_mode for more details
+ * @reference_mode: specifies the type of inter prediction to be used. See
+ * &v4l2_vp9_reference_mode for more details
+ * @padding: needed to make this struct 64 bit aligned. Shall be filled with
+ * zeros
+ * @frame_width_minus_1: add 1 to it and you'll get the frame width expressed
+ * in pixels
+ * @frame_height_minus_1: add 1 to it and you'll get the frame height expressed
+ * in pixels
+ * @frame_width_minus_1: add 1 to it and you'll get the expected render width
+ * expressed in pixels. This is not used during the
+ * decoding process but might be used by HW scalers to
+ * prepare a frame that's ready for scanout
+ * @frame_height_minus_1: add 1 to it and you'll get the expected render height
+ * expressed in pixels. This is not used during the
+ * decoding process but might be used by HW scalers to
+ * prepare a frame that's ready for scanout
+ * @refs: array of reference frames. See &v4l2_vp9_ref_id for more details
+ * @lf: loop filter parameters. See &v4l2_vp9_loop_filter for more details
+ * @quant: quantization parameters. See &v4l2_vp9_quantization for more details
+ * @seg: segmentation parameters. See &v4l2_vp9_segmentation for more details
+ * @probs: probabilities. See &v4l2_vp9_probabilities for more details
+ */
+struct v4l2_ctrl_vp9_frame_decode_params {
+ __u32 flags;
+ __u16 compressed_header_size;
+ __u16 uncompressed_header_size;
+ __u8 profile;
+ __u8 reset_frame_context;
+ __u8 frame_context_idx;
+ __u8 bit_depth;
+ __u8 interpolation_filter;
+ __u8 tile_cols_log2;
+ __u8 tile_rows_log2;
+ __u8 tx_mode;
+ __u8 reference_mode;
+ __u8 padding[6];
+ __u16 frame_width_minus_1;
+ __u16 frame_height_minus_1;
+ __u16 render_width_minus_1;
+ __u16 render_height_minus_1;
+ __u64 refs[V4L2_REF_ID_CNT];
+ struct v4l2_vp9_loop_filter lf;
+ struct v4l2_vp9_quantization quant;
+ struct v4l2_vp9_segmentation seg;
+ struct v4l2_vp9_probabilities probs;
+};
+
+#define V4L2_VP9_NUM_FRAME_CTX 4
+
+/**
+ * struct v4l2_ctrl_vp9_frame_ctx - VP9 frame context control
+ *
+ * @probs: VP9 probabilities
+ *
+ * This control is accessed in both direction. The user should initialize the
+ * 4 contexts with default values just after starting the stream. Then before
+ * decoding a frame it should query the current frame context (the one passed
+ * through &v4l2_ctrl_vp9_frame_decode_params.frame_context_idx) to initialize
+ * &v4l2_ctrl_vp9_frame_decode_params.probs. The probs are then adjusted based
+ * on the bitstream info and passed to the kernel. The codec should update
+ * the frame context after the frame has been decoded, so that next time
+ * userspace query this context it contains the updated probabilities.
+ */
+struct v4l2_ctrl_vp9_frame_ctx {
+ struct v4l2_vp9_probabilities probs;
+};
+
+#endif /* _VP9_CTRLS_H_ */
From 3e089d23e73a5eb2b070f875845ff423a492f3ba Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@collabora.com>
Date: Mon, 18 May 2020 14:40:11 -0300
Subject: [PATCH] media: rkvdec: Add the VP9 backend
The Rockchip VDEC supports VP9 profile 0 up to 4096x2304@30fps. Add
a backend for this new format.
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
---
drivers/staging/media/rkvdec/Makefile | 2 +-
drivers/staging/media/rkvdec/rkvdec-vp9.c | 1577 +++++++++++++++++++++
drivers/staging/media/rkvdec/rkvdec.c | 54 +
drivers/staging/media/rkvdec/rkvdec.h | 6 +
4 files changed, 1638 insertions(+), 1 deletion(-)
create mode 100644 drivers/staging/media/rkvdec/rkvdec-vp9.c
diff --git a/drivers/staging/media/rkvdec/Makefile b/drivers/staging/media/rkvdec/Makefile
index c08fed0a39f9..cb86b429cfaa 100644
--- a/drivers/staging/media/rkvdec/Makefile
+++ b/drivers/staging/media/rkvdec/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o
-rockchip-vdec-y += rkvdec.o rkvdec-h264.o
+rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o
diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c
new file mode 100644
index 000000000000..37d0ea4e3570
--- /dev/null
+++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c
@@ -0,0 +1,1577 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip Video Decoder VP9 backend
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Boris Brezillon <boris.brezillon@collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <Alpha.Lin@rock-chips.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-regs.h"
+
+#define RKVDEC_VP9_PROBE_SIZE 4864
+#define RKVDEC_VP9_COUNT_SIZE 13232
+#define RKVDEC_VP9_MAX_SEGMAP_SIZE 73728
+
+struct rkvdec_vp9_intra_mode_probs {
+ u8 y_mode[105];
+ u8 uv_mode[23];
+};
+
+struct rkvdec_vp9_intra_only_frame_probs {
+ u8 coef_intra[4][2][128];
+ struct rkvdec_vp9_intra_mode_probs intra_mode[10];
+};
+
+struct rkvdec_vp9_inter_frame_probs {
+ u8 y_mode[4][9];
+ u8 comp_mode[5];
+ u8 comp_ref[5];
+ u8 single_ref[5][2];
+ u8 inter_mode[7][3];
+ u8 interp_filter[4][2];
+ u8 padding0[11];
+ u8 coef[2][4][2][128];
+ u8 uv_mode_0_2[3][9];
+ u8 padding1[5];
+ u8 uv_mode_3_5[3][9];
+ u8 padding2[5];
+ u8 uv_mode_6_8[3][9];
+ u8 padding3[5];
+ u8 uv_mode_9[9];
+ u8 padding4[7];
+ u8 padding5[16];
+ struct {
+ u8 joint[3];
+ u8 sign[2];
+ u8 class[2][10];
+ u8 class0_bit[2];
+ u8 bits[2][10];
+ u8 class0_fr[2][2][3];
+ u8 fr[2][3];
+ u8 class0_hp[2];
+ u8 hp[2];
+ } mv;
+};
+
+struct rkvdec_vp9_probs {
+ u8 partition[16][3];
+ u8 pred[3];
+ u8 tree[7];
+ u8 skip[3];
+ u8 tx32[2][3];
+ u8 tx16[2][2];
+ u8 tx8[2][1];
+ u8 is_inter[4];
+ /* 128 bit alignment */
+ u8 padding0[3];
+ union {
+ struct rkvdec_vp9_inter_frame_probs inter;
+ struct rkvdec_vp9_intra_only_frame_probs intra_only;
+ };
+};
+
+/* Data structure describing auxiliary buffer format. */
+struct rkvdec_vp9_priv_tbl {
+ struct rkvdec_vp9_probs probs;
+ u8 segmap[2][RKVDEC_VP9_MAX_SEGMAP_SIZE];
+};
+
+struct rkvdec_vp9_refs_counts {
+ u32 eob[2];
+ u32 coeff[3];
+};
+
+struct rkvdec_vp9_inter_frame_symbol_counts {
+ u32 partition[16][4];
+ u32 skip[3][2];
+ u32 inter[4][2];
+ u32 tx32p[2][4];
+ u32 tx16p[2][4];
+ u32 tx8p[2][2];
+ u32 y_mode[4][10];
+ u32 uv_mode[10][10];
+ u32 comp[5][2];
+ u32 comp_ref[5][2];
+ u32 single_ref[5][2][2];
+ u32 mv_mode[7][4];
+ u32 filter[4][3];
+ u32 mv_joint[4];
+ u32 sign[2][2];
+ /* add 1 element for align */
+ u32 classes[2][11 + 1];
+ u32 class0[2][2];
+ u32 bits[2][10][2];
+ u32 class0_fp[2][2][4];
+ u32 fp[2][4];
+ u32 class0_hp[2][2];
+ u32 hp[2][2];
+ struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6];
+};
+
+struct rkvdec_vp9_intra_frame_symbol_counts {
+ u32 partition[4][4][4];
+ u32 skip[3][2];
+ u32 intra[4][2];
+ u32 tx32p[2][4];
+ u32 tx16p[2][4];
+ u32 tx8p[2][2];
+ struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6];
+};
+
+struct rkvdec_vp9_run {
+ struct rkvdec_run base;
+ const struct v4l2_ctrl_vp9_frame_decode_params *decode_params;
+};
+
+struct rkvdec_vp9_frame_info {
+ u32 valid : 1;
+ u32 segmapid : 1;
+ u32 frame_context_idx : 2;
+ u32 reference_mode : 2;
+ u32 tx_mode : 3;
+ u32 interpolation_filter : 3;
+ u32 flags;
+ u64 timestamp;
+ struct v4l2_vp9_segmentation seg;
+ struct v4l2_vp9_loop_filter lf;
+};
+
+struct rkvdec_vp9_ctx {
+ struct rkvdec_aux_buf priv_tbl;
+ struct rkvdec_aux_buf count_tbl;
+ struct v4l2_ctrl_vp9_frame_ctx frame_context;
+ struct rkvdec_vp9_frame_info cur;
+ struct rkvdec_vp9_frame_info last;
+};
+
+static u32 rkvdec_fastdiv(u32 dividend, u16 divisor)
+{
+#define DIV_INV(d) (u32)(((1ULL << 32) + ((d) - 1)) / (d))
+#define DIVS_INV(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) \
+ DIV_INV(d0), DIV_INV(d1), DIV_INV(d2), DIV_INV(d3), \
+ DIV_INV(d4), DIV_INV(d5), DIV_INV(d6), DIV_INV(d7), \
+ DIV_INV(d8), DIV_INV(d9)
+
+ static const u32 inv[] = {
+ DIV_INV(2), DIV_INV(3), DIV_INV(4), DIV_INV(5),
+ DIV_INV(6), DIV_INV(7), DIV_INV(8), DIV_INV(9),
+ DIVS_INV(10, 11, 12, 13, 14, 15, 16, 17, 18, 19),
+ DIVS_INV(20, 21, 22, 23, 24, 25, 26, 27, 28, 29),
+ DIVS_INV(30, 31, 32, 33, 34, 35, 36, 37, 38, 39),
+ DIVS_INV(40, 41, 42, 43, 44, 45, 46, 47, 48, 49),
+ DIVS_INV(50, 51, 52, 53, 54, 55, 56, 57, 58, 59),
+ DIVS_INV(60, 61, 62, 63, 64, 65, 66, 67, 68, 69),
+ DIVS_INV(70, 71, 72, 73, 74, 75, 76, 77, 78, 79),
+ DIVS_INV(80, 81, 82, 83, 84, 85, 86, 87, 88, 89),
+ DIVS_INV(90, 91, 92, 93, 94, 95, 96, 97, 98, 99),
+ DIVS_INV(100, 101, 102, 103, 104, 105, 106, 107, 108, 109),
+ DIVS_INV(110, 111, 112, 113, 114, 115, 116, 117, 118, 119),
+ DIVS_INV(120, 121, 122, 123, 124, 125, 126, 127, 128, 129),
+ DIVS_INV(130, 131, 132, 133, 134, 135, 136, 137, 138, 139),
+ DIVS_INV(140, 141, 142, 143, 144, 145, 146, 147, 148, 149),
+ DIVS_INV(150, 151, 152, 153, 154, 155, 156, 157, 158, 159),
+ DIVS_INV(160, 161, 162, 163, 164, 165, 166, 167, 168, 169),
+ DIVS_INV(170, 171, 172, 173, 174, 175, 176, 177, 178, 179),
+ DIVS_INV(180, 181, 182, 183, 184, 185, 186, 187, 188, 189),
+ DIVS_INV(190, 191, 192, 193, 194, 195, 196, 197, 198, 199),
+ DIVS_INV(200, 201, 202, 203, 204, 205, 206, 207, 208, 209),
+ DIVS_INV(210, 211, 212, 213, 214, 215, 216, 217, 218, 219),
+ DIVS_INV(220, 221, 222, 223, 224, 225, 226, 227, 228, 229),
+ DIVS_INV(230, 231, 232, 233, 234, 235, 236, 237, 238, 239),
+ DIVS_INV(240, 241, 242, 243, 244, 245, 246, 247, 248, 249),
+ DIV_INV(250), DIV_INV(251), DIV_INV(252), DIV_INV(253),
+ DIV_INV(254), DIV_INV(255), DIV_INV(256),
+ };
+
+ if (divisor == 0)
+ return 0;
+ else if (divisor == 1)
+ return dividend;
+
+ if (WARN_ON(divisor - 2 >= ARRAY_SIZE(inv)))
+ return dividend;
+
+ return ((u64)dividend * inv[divisor - 2]) >> 32;
+}
+
+static const u8 vp9_kf_y_mode_prob[10][10][9] = {
+ {
+ /* above = dc */
+ { 137, 30, 42, 148, 151, 207, 70, 52, 91 },/*left = dc */
+ { 92, 45, 102, 136, 116, 180, 74, 90, 100 },/*left = v */
+ { 73, 32, 19, 187, 222, 215, 46, 34, 100 },/*left = h */
+ { 91, 30, 32, 116, 121, 186, 93, 86, 94 },/*left = d45 */
+ { 72, 35, 36, 149, 68, 206, 68, 63, 105 },/*left = d135*/
+ { 73, 31, 28, 138, 57, 124, 55, 122, 151 },/*left = d117*/
+ { 67, 23, 21, 140, 126, 197, 40, 37, 171 },/*left = d153*/
+ { 86, 27, 28, 128, 154, 212, 45, 43, 53 },/*left = d207*/
+ { 74, 32, 27, 107, 86, 160, 63, 134, 102 },/*left = d63 */
+ { 59, 67, 44, 140, 161, 202, 78, 67, 119 } /*left = tm */
+ }, { /* above = v */
+ { 63, 36, 126, 146, 123, 158, 60, 90, 96 },/*left = dc */
+ { 43, 46, 168, 134, 107, 128, 69, 142, 92 },/*left = v */
+ { 44, 29, 68, 159, 201, 177, 50, 57, 77 },/*left = h */
+ { 58, 38, 76, 114, 97, 172, 78, 133, 92 },/*left = d45 */
+ { 46, 41, 76, 140, 63, 184, 69, 112, 57 },/*left = d135*/
+ { 38, 32, 85, 140, 46, 112, 54, 151, 133 },/*left = d117*/
+ { 39, 27, 61, 131, 110, 175, 44, 75, 136 },/*left = d153*/
+ { 52, 30, 74, 113, 130, 175, 51, 64, 58 },/*left = d207*/
+ { 47, 35, 80, 100, 74, 143, 64, 163, 74 },/*left = d63 */
+ { 36, 61, 116, 114, 128, 162, 80, 125, 82 } /*left = tm */
+ }, { /* above = h */
+ { 82, 26, 26, 171, 208, 204, 44, 32, 105 },/*left = dc */
+ { 55, 44, 68, 166, 179, 192, 57, 57, 108 },/*left = v */
+ { 42, 26, 11, 199, 241, 228, 23, 15, 85 },/*left = h */
+ { 68, 42, 19, 131, 160, 199, 55, 52, 83 },/*left = d45 */
+ { 58, 50, 25, 139, 115, 232, 39, 52, 118 },/*left = d135*/
+ { 50, 35, 33, 153, 104, 162, 64, 59, 131 },/*left = d117*/
+ { 44, 24, 16, 150, 177, 202, 33, 19, 156 },/*left = d153*/
+ { 55, 27, 12, 153, 203, 218, 26, 27, 49 },/*left = d207*/
+ { 53, 49, 21, 110, 116, 168, 59, 80, 76 },/*left = d63 */
+ { 38, 72, 19, 168, 203, 212, 50, 50, 107 } /*left = tm */
+ }, { /* above = d45 */
+ { 103, 26, 36, 129, 132, 201, 83, 80, 93 },/*left = dc */
+ { 59, 38, 83, 112, 103, 162, 98, 136, 90 },/*left = v */
+ { 62, 30, 23, 158, 200, 207, 59, 57, 50 },/*left = h */
+ { 67, 30, 29, 84, 86, 191, 102, 91, 59 },/*left = d45 */
+ { 60, 32, 33, 112, 71, 220, 64, 89, 104 },/*left = d135*/
+ { 53, 26, 34, 130, 56, 149, 84, 120, 103 },/*left = d117*/
+ { 53, 21, 23, 133, 109, 210, 56, 77, 172 },/*left = d153*/
+ { 77, 19, 29, 112, 142, 228, 55, 66, 36 },/*left = d207*/
+ { 61, 29, 29, 93, 97, 165, 83, 175, 162 },/*left = d63 */
+ { 47, 47, 43, 114, 137, 181, 100, 99, 95 } /*left = tm */
+ }, { /* above = d135 */
+ { 69, 23, 29, 128, 83, 199, 46, 44, 101 },/*left = dc */
+ { 53, 40, 55, 139, 69, 183, 61, 80, 110 },/*left = v */
+ { 40, 29, 19, 161, 180, 207, 43, 24, 91 },/*left = h */
+ { 60, 34, 19, 105, 61, 198, 53, 64, 89 },/*left = d45 */
+ { 52, 31, 22, 158, 40, 209, 58, 62, 89 },/*left = d135*/
+ { 44, 31, 29, 147, 46, 158, 56, 102, 198 },/*left = d117*/
+ { 35, 19, 12, 135, 87, 209, 41, 45, 167 },/*left = d153*/
+ { 55, 25, 21, 118, 95, 215, 38, 39, 66 },/*left = d207*/
+ { 51, 38, 25, 113, 58, 164, 70, 93, 97 },/*left = d63 */
+ { 47, 54, 34, 146, 108, 203, 72, 103, 151 } /*left = tm */
+ }, { /* above = d117 */
+ { 64, 19, 37, 156, 66, 138, 49, 95, 133 },/*left = dc */
+ { 46, 27, 80, 150, 55, 124, 55, 121, 135 },/*left = v */
+ { 36, 23, 27, 165, 149, 166, 54, 64, 118 },/*left = h */
+ { 53, 21, 36, 131, 63, 163, 60, 109, 81 },/*left = d45 */
+ { 40, 26, 35, 154, 40, 185, 51, 97, 123 },/*left = d135*/
+ { 35, 19, 34, 179, 19, 97, 48, 129, 124 },/*left = d117*/
+ { 36, 20, 26, 136, 62, 164, 33, 77, 154 },/*left = d153*/
+ { 45, 18, 32, 130, 90, 157, 40, 79, 91 },/*left = d207*/
+ { 45, 26, 28, 129, 45, 129, 49, 147, 123 },/*left = d63 */
+ { 38, 44, 51, 136, 74, 162, 57, 97, 121 } /*left = tm */
+ }, { /* above = d153 */
+ { 75, 17, 22, 136, 138, 185, 32, 34, 166 },/*left = dc */
+ { 56, 39, 58, 133, 117, 173, 48, 53, 187 },/*left = v */
+ { 35, 21, 12, 161, 212, 207, 20, 23, 145 },/*left = h */
+ { 56, 29, 19, 117, 109, 181, 55, 68, 112 },/*left = d45 */
+ { 47, 29, 17, 153, 64, 220, 59, 51, 114 },/*left = d135*/
+ { 46, 16, 24, 136, 76, 147, 41, 64, 172 },/*left = d117*/
+ { 34, 17, 11, 108, 152, 187, 13, 15, 209 },/*left = d153*/
+ { 51, 24, 14, 115, 133, 209, 32, 26, 104 },/*left = d207*/
+ { 55, 30, 18, 122, 79, 179, 44, 88, 116 },/*left = d63 */
+ { 37, 49, 25, 129, 168, 164, 41, 54, 148 } /*left = tm */
+ }, { /* above = d207 */
+ { 82, 22, 32, 127, 143, 213, 39, 41, 70 },/*left = dc */
+ { 62, 44, 61, 123, 105, 189, 48, 57, 64 },/*left = v */
+ { 47, 25, 17, 175, 222, 220, 24, 30, 86 },/*left = h */
+ { 68, 36, 17, 106, 102, 206, 59, 74, 74 },/*left = d45 */
+ { 57, 39, 23, 151, 68, 216, 55, 63, 58 },/*left = d135*/
+ { 49, 30, 35, 141, 70, 168, 82, 40, 115 },/*left = d117*/
+ { 51, 25, 15, 136, 129, 202, 38, 35, 139 },/*left = d153*/
+ { 68, 26, 16, 111, 141, 215, 29, 28, 28 },/*left = d207*/
+ { 59, 39, 19, 114, 75, 180, 77, 104, 42 },/*left = d63 */
+ { 40, 61, 26, 126, 152, 206, 61, 59, 93 } /*left = tm */
+ }, { /* above = d63 */
+ { 78, 23, 39, 111, 117, 170, 74, 124, 94 },/*left = dc */
+ { 48, 34, 86, 101, 92, 146, 78, 179, 134 },/*left = v */
+ { 47, 22, 24, 138, 187, 178, 68, 69, 59 },/*left = h */
+ { 56, 25, 33, 105, 112, 187, 95, 177, 129 },/*left = d45 */
+ { 48, 31, 27, 114, 63, 183, 82, 116, 56 },/*left = d135*/
+ { 43, 28, 37, 121, 63, 123, 61, 192, 169 },/*left = d117*/
+ { 42, 17, 24, 109, 97, 177, 56, 76, 122 },/*left = d153*/
+ { 58, 18, 28, 105, 139, 182, 70, 92, 63 },/*left = d207*/
+ { 46, 23, 32, 74, 86, 150, 67, 183, 88 },/*left = d63 */
+ { 36, 38, 48, 92, 122, 165, 88, 137, 91 } /*left = tm */
+ }, { /* above = tm */
+ { 65, 70, 60, 155, 159, 199, 61, 60, 81 },/*left = dc */
+ { 44, 78, 115, 132, 119, 173, 71, 112, 93 },/*left = v */
+ { 39, 38, 21, 184, 227, 206, 42, 32, 64 },/*left = h */
+ { 58, 47, 36, 124, 137, 193, 80, 82, 78 },/*left = d45 */
+ { 49, 50, 35, 144, 95, 205, 63, 78, 59 },/*left = d135*/
+ { 41, 53, 52, 148, 71, 142, 65, 128, 51 },/*left = d117*/
+ { 40, 36, 28, 143, 143, 202, 40, 55, 137 },/*left = d153*/
+ { 52, 34, 29, 129, 183, 227, 42, 35, 43 },/*left = d207*/
+ { 42, 44, 44, 104, 105, 164, 64, 130, 80 },/*left = d63 */
+ { 43, 81, 53, 140, 169, 204, 68, 84, 72 } /*left = tm */
+ }
+};
+
+static const u8 kf_partition_probs[16][3] = {
+ /* 8x8 -> 4x4 */
+ { 158, 97, 94 }, /* a/l both not split */
+ { 93, 24, 99 }, /* a split, l not split */
+ { 85, 119, 44 }, /* l split, a not split */
+ { 62, 59, 67 }, /* a/l both split */
+ /* 16x16 -> 8x8 */
+ { 149, 53, 53 }, /* a/l both not split */
+ { 94, 20, 48 }, /* a split, l not split */
+ { 83, 53, 24 }, /* l split, a not split */
+ { 52, 18, 18 }, /* a/l both split */
+ /* 32x32 -> 16x16 */
+ { 150, 40, 39 }, /* a/l both not split */
+ { 78, 12, 26 }, /* a split, l not split */
+ { 67, 33, 11 }, /* l split, a not split */
+ { 24, 7, 5 }, /* a/l both split */
+ /* 64x64 -> 32x32 */
+ { 174, 35, 49 }, /* a/l both not split */
+ { 68, 11, 27 }, /* a split, l not split */
+ { 57, 15, 9 }, /* l split, a not split */
+ { 12, 3, 3 }, /* a/l both split */
+};
+
+static const u8 kf_uv_mode_prob[10][9] = {
+ { 144, 11, 54, 157, 195, 130, 46, 58, 108 }, /* y = dc */
+ { 118, 15, 123, 148, 131, 101, 44, 93, 131 }, /* y = v */
+ { 113, 12, 23, 188, 226, 142, 26, 32, 125 }, /* y = h */
+ { 120, 11, 50, 123, 163, 135, 64, 77, 103 }, /* y = d45 */
+ { 113, 9, 36, 155, 111, 157, 32, 44, 161 }, /* y = d135 */
+ { 116, 9, 55, 176, 76, 96, 37, 61, 149 }, /* y = d117 */
+ { 115, 9, 28, 141, 161, 167, 21, 25, 193 }, /* y = d153 */
+ { 120, 12, 32, 145, 195, 142, 32, 38, 86 }, /* y = d207 */
+ { 116, 12, 64, 120, 140, 125, 49, 115, 121 }, /* y = d63 */
+ { 102, 19, 66, 162, 182, 122, 35, 59, 128 } /* y = tm */
+};
+
+static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
+{
+ unsigned int idx = 0;
+ u8 byte_count = 0, p;
+ s32 k, m, n;
+
+ for (k = 0; k < 6; k++) {
+ for (m = 0; m < 6; m++) {
+ for (n = 0; n < 3; n++) {
+ p = coef[k][m][n];
+ coeff_plane[idx++] = p;
+ byte_count++;
+ if (byte_count == 27) {
+ idx += 5;
+ byte_count = 0;
+ }
+ }
+ }
+ }
+}
+
+static void init_intra_only_probs(struct rkvdec_ctx *ctx,
+ const struct rkvdec_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params;
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu;
+ struct rkvdec_vp9_intra_only_frame_probs *rkprobs;
+ const struct v4l2_vp9_probabilities *probs;
+ unsigned int i, j, k, m;
+
+ rkprobs = &tbl->probs.intra_only;
+ dec_params = run->decode_params;
+ probs = &dec_params->probs;
+
+ /*
+ * intra only 149 x 128 bits ,aligned to 152 x 128 bits coeff related
+ * prob 64 x 128 bits
+ */
+ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) {
+ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++)
+ write_coeff_plane(probs->coef[i][j][0],
+ rkprobs->coef_intra[i][j]);
+ }
+
+ /* intra mode prob 80 x 128 bits */
+ for (i = 0; i < ARRAY_SIZE(vp9_kf_y_mode_prob); i++) {
+ u32 byte_count = 0;
+ int idx = 0;
+
+ /* vp9_kf_y_mode_prob */
+ for (j = 0; j < ARRAY_SIZE(vp9_kf_y_mode_prob[0]); j++) {
+ for (k = 0; k < ARRAY_SIZE(vp9_kf_y_mode_prob[0][0]);
+ k++) {
+ u8 val = vp9_kf_y_mode_prob[i][j][k];
+
+ rkprobs->intra_mode[i].y_mode[idx++] = val;
+ byte_count++;
+ if (byte_count == 27) {
+ byte_count = 0;
+ idx += 5;
+ }
+ }
+ }
+
+ idx = 0;
+ if (i < 4) {
+ for (m = 0; m < (i < 3 ? 23 : 21); m++) {
+ const u8 *ptr = (const u8 *)kf_uv_mode_prob;
+
+ rkprobs->intra_mode[i].uv_mode[idx++] = ptr[i * 23 + m];
+ }
+ }
+ }
+}
+
+static void init_inter_probs(struct rkvdec_ctx *ctx,
+ const struct rkvdec_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params;
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu;
+ struct rkvdec_vp9_inter_frame_probs *rkprobs;
+ const struct v4l2_vp9_probabilities *probs;
+ unsigned int i, j, k;
+
+ rkprobs = &tbl->probs.inter;
+ dec_params = run->decode_params;
+ probs = &dec_params->probs;
+
+ /*
+ * inter probs
+ * 151 x 128 bits, aligned to 152 x 128 bits
+ * inter only
+ * intra_y_mode & inter_block info 6 x 128 bits
+ */
+
+ memcpy(rkprobs->y_mode, probs->y_mode, sizeof(rkprobs->y_mode));
+ memcpy(rkprobs->comp_mode, probs->comp_mode,
+ sizeof(rkprobs->comp_mode));
+ memcpy(rkprobs->comp_ref, probs->comp_ref,
+ sizeof(rkprobs->comp_ref));
+ memcpy(rkprobs->single_ref, probs->single_ref,
+ sizeof(rkprobs->single_ref));
+ memcpy(rkprobs->inter_mode, probs->inter_mode,
+ sizeof(rkprobs->inter_mode));
+ memcpy(rkprobs->interp_filter, probs->interp_filter,
+ sizeof(rkprobs->interp_filter));
+
+ /* 128 x 128 bits coeff related */
+ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) {
+ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) {
+ for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); k++)
+ write_coeff_plane(probs->coef[i][j][k],
+ rkprobs->coef[k][i][j]);
+ }
+ }
+
+ /* intra uv mode 6 x 128 */
+ memcpy(rkprobs->uv_mode_0_2, &probs->uv_mode[0],
+ sizeof(rkprobs->uv_mode_0_2));
+ memcpy(rkprobs->uv_mode_3_5, &probs->uv_mode[3],
+ sizeof(rkprobs->uv_mode_3_5));
+ memcpy(rkprobs->uv_mode_6_8, &probs->uv_mode[6],
+ sizeof(rkprobs->uv_mode_6_8));
+ memcpy(rkprobs->uv_mode_9, &probs->uv_mode[9],
+ sizeof(rkprobs->uv_mode_9));
+
+ /* mv related 6 x 128 */
+ memcpy(rkprobs->mv.joint, probs->mv.joint,
+ sizeof(rkprobs->mv.joint));
+ memcpy(rkprobs->mv.sign, probs->mv.sign,
+ sizeof(rkprobs->mv.sign));
+ memcpy(rkprobs->mv.class, probs->mv.class,
+ sizeof(rkprobs->mv.class));
+ memcpy(rkprobs->mv.class0_bit, probs->mv.class0_bit,
+ sizeof(rkprobs->mv.class0_bit));
+ memcpy(rkprobs->mv.bits, probs->mv.bits,
+ sizeof(rkprobs->mv.bits));
+ memcpy(rkprobs->mv.class0_fr, probs->mv.class0_fr,
+ sizeof(rkprobs->mv.class0_fr));
+ memcpy(rkprobs->mv.fr, probs->mv.fr,
+ sizeof(rkprobs->mv.fr));
+ memcpy(rkprobs->mv.class0_hp, probs->mv.class0_hp,
+ sizeof(rkprobs->mv.class0_hp));
+ memcpy(rkprobs->mv.hp, probs->mv.hp,
+ sizeof(rkprobs->mv.hp));
+}
+
+static void init_probs(struct rkvdec_ctx *ctx,
+ const struct rkvdec_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params;
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu;
+ struct rkvdec_vp9_probs *rkprobs = &tbl->probs;
+ const struct v4l2_vp9_segmentation *seg;
+ const struct v4l2_vp9_probabilities *probs;
+ bool intra_only;
+
+ dec_params = run->decode_params;
+ probs = &dec_params->probs;
+ seg = &dec_params->seg;
+
+ memset(rkprobs, 0, sizeof(*rkprobs));
+
+ intra_only = !!(dec_params->flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
+
+ /* sb info 5 x 128 bit */
+ memcpy(rkprobs->partition,
+ intra_only ? kf_partition_probs : probs->partition,
+ sizeof(rkprobs->partition));
+
+ memcpy(rkprobs->pred, seg->pred_probs, sizeof(rkprobs->pred));
+ memcpy(rkprobs->tree, seg->tree_probs, sizeof(rkprobs->tree));
+ memcpy(rkprobs->skip, probs->skip, sizeof(rkprobs->skip));
+ memcpy(rkprobs->tx32, probs->tx32, sizeof(rkprobs->tx32));
+ memcpy(rkprobs->tx16, probs->tx16, sizeof(rkprobs->tx16));
+ memcpy(rkprobs->tx8, probs->tx8, sizeof(rkprobs->tx8));
+ memcpy(rkprobs->is_inter, probs->is_inter, sizeof(rkprobs->is_inter));
+
+ if (intra_only)
+ init_intra_only_probs(ctx, run);
+ else
+ init_inter_probs(ctx, run);
+}
+
+struct vp9d_ref_config {
+ u32 reg_frm_size;
+ u32 reg_hor_stride;
+ u32 reg_y_stride;
+ u32 reg_yuv_stride;
+ u32 reg_ref_base;
+};
+
+static struct vp9d_ref_config ref_config[3] = {
+ {
+ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0),
+ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0),
+ .reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE,
+ .reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE,
+ .reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE,
+ },
+ {
+ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1),
+ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1),
+ .reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE,
+ .reg_yuv_stride = 0,
+ .reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE,
+ },
+ {
+ .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2),
+ .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2),
+ .reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE,
+ .reg_yuv_stride = 0,
+ .reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE,
+ }
+};
+
+static struct rkvdec_decoded_buffer *
+get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+ int buf_idx;
+
+ /*
+ * If a ref is unused or invalid, address of current destination
+ * buffer is returned.
+ */
+ buf_idx = vb2_find_timestamp(cap_q, timestamp, 0);
+ if (buf_idx < 0)
+ return vb2_to_rkvdec_decoded_buf(&dst->vb2_buf);
+
+ return vb2_to_rkvdec_decoded_buf(vb2_get_buffer(cap_q, buf_idx));
+}
+
+static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
+{
+ u32 aligned_pitch, aligned_height, yuv_len;
+
+ aligned_height = round_up(buf->vp9.height, 64);
+ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8;
+ yuv_len = (aligned_height * aligned_pitch * 3) / 2;
+
+ return vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0) +
+ yuv_len;
+}
+
+static void
+config_ref_registers(struct rkvdec_ctx *ctx,
+ const struct rkvdec_vp9_run *run,
+ struct rkvdec_decoded_buffer **ref_bufs,
+ enum v4l2_vp9_ref_id id)
+{
+ u32 aligned_pitch, aligned_height, y_len, yuv_len;
+ struct rkvdec_decoded_buffer *buf = ref_bufs[id];
+ struct rkvdec_dev *rkvdec = ctx->dev;
+
+ aligned_height = round_up(buf->vp9.height, 64);
+ writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(buf->vp9.width) |
+ RKVDEC_VP9_FRAMEHEIGHT(buf->vp9.height),
+ rkvdec->regs + ref_config[id].reg_frm_size);
+
+ writel_relaxed(vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0),
+ rkvdec->regs + ref_config[id].reg_ref_base);
+
+ if (&buf->base.vb == run->base.bufs.dst)
+ return;
+
+ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8;
+ y_len = aligned_height * aligned_pitch;
+ yuv_len = (y_len * 3) / 2;
+
+ writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) |
+ RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16),
+ rkvdec->regs + ref_config[id].reg_hor_stride);
+ writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16),
+ rkvdec->regs + ref_config[id].reg_y_stride);
+
+ if (!ref_config[id].reg_yuv_stride)
+ return;
+
+ writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16),
+ rkvdec->regs + ref_config[id].reg_yuv_stride);
+}
+
+static bool seg_featured_enabled(const struct v4l2_vp9_segmentation *seg,
+ enum v4l2_vp9_segment_feature feature,
+ unsigned int segid)
+{
+ u8 mask = V4L2_VP9_SEGMENT_FEATURE_ENABLED(feature);
+
+ return !!(seg->feature_enabled[segid] & mask);
+}
+
+static void
+config_seg_registers(struct rkvdec_ctx *ctx,
+ unsigned int segid)
+{
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ const struct v4l2_vp9_segmentation *seg;
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ s16 feature_val;
+ u8 feature_id;
+ u32 val = 0;
+
+ seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg;
+ feature_id = V4L2_VP9_SEGMENT_FEATURE_QP_DELTA;
+ if (seg_featured_enabled(seg, feature_id, segid)) {
+ feature_val = seg->feature_data[segid][feature_id];
+ val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) |
+ RKVDEC_SEGID_FRAME_QP_DELTA(feature_val);
+ }
+
+ feature_id = V4L2_VP9_SEGMENT_FEATURE_LF;
+ if (seg_featured_enabled(seg, feature_id, segid)) {
+ feature_val = seg->feature_data[segid][feature_id];
+ val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) |
+ RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val);
+ }
+
+ feature_id = V4L2_VP9_SEGMENT_FEATURE_REF_FRAME;
+ if (seg_featured_enabled(seg, feature_id, segid)) {
+ feature_val = seg->feature_data[segid][feature_id];
+ val |= RKVDEC_SEGID_REFERINFO_EN(1) |
+ RKVDEC_SEGID_REFERINFO(feature_val);
+ }
+
+ feature_id = V4L2_VP9_SEGMENT_FEATURE_SKIP;
+ if (seg_featured_enabled(seg, feature_id, segid))
+ val |= RKVDEC_SEGID_FRAME_SKIP_EN(1);
+
+ if (!segid &&
+ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
+ val |= RKVDEC_SEGID_ABS_DELTA(1);
+
+ writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid));
+}
+
+static void
+update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params)
+{
+ buf->vp9.width = dec_params->frame_width_minus_1 + 1;
+ buf->vp9.height = dec_params->frame_height_minus_1 + 1;
+ buf->vp9.bit_depth = dec_params->bit_depth;
+}
+
+static void
+update_ctx_cur_info(struct rkvdec_vp9_ctx *vp9_ctx,
+ struct rkvdec_decoded_buffer *buf,
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params)
+{
+ vp9_ctx->cur.valid = true;
+ vp9_ctx->cur.frame_context_idx = dec_params->frame_context_idx;
+ vp9_ctx->cur.reference_mode = dec_params->reference_mode;
+ vp9_ctx->cur.tx_mode = dec_params->tx_mode;
+ vp9_ctx->cur.interpolation_filter = dec_params->interpolation_filter;
+ vp9_ctx->cur.flags = dec_params->flags;
+ vp9_ctx->cur.timestamp = buf->base.vb.vb2_buf.timestamp;
+ vp9_ctx->cur.seg = dec_params->seg;
+ vp9_ctx->cur.lf = dec_params->lf;
+}
+
+static void
+update_ctx_last_info(struct rkvdec_vp9_ctx *vp9_ctx)
+{
+ vp9_ctx->last = vp9_ctx->cur;
+}
+
+static void config_registers(struct rkvdec_ctx *ctx,
+ const struct rkvdec_vp9_run *run)
+{
+ u32 y_len, uv_len, yuv_len, bit_depth, aligned_height, aligned_pitch;
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params;
+ struct rkvdec_decoded_buffer *ref_bufs[V4L2_REF_ID_CNT];
+ struct rkvdec_decoded_buffer *dst, *last, *mv_ref;
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ u32 val, stream_len, last_frame_info = 0;
+ const struct v4l2_vp9_segmentation *seg;
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ dma_addr_t addr;
+ bool intra_only;
+ unsigned int i;
+
+ dec_params = run->decode_params;
+ dst = vb2_to_rkvdec_decoded_buf(&run->base.bufs.dst->vb2_buf);
+ for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
+ ref_bufs[i] = get_ref_buf(ctx, &dst->base.vb,
+ dec_params->refs[i]);
+
+ if (vp9_ctx->last.valid)
+ last = get_ref_buf(ctx, &dst->base.vb, vp9_ctx->last.timestamp);
+ else
+ last = dst;
+
+ update_dec_buf_info(dst, dec_params);
+ update_ctx_cur_info(vp9_ctx, dst, dec_params);
+ seg = &dec_params->seg;
+
+ intra_only = !!(dec_params->flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
+
+ writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9),
+ rkvdec->regs + RKVDEC_REG_SYSCTRL);
+
+ bit_depth = dec_params->bit_depth;
+ aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64);
+
+ aligned_pitch = round_up(ctx->decoded_fmt.fmt.pix_mp.width *
+ bit_depth,
+ 512) / 8;
+ y_len = aligned_height * aligned_pitch;
+ uv_len = y_len / 2;
+ yuv_len = y_len + uv_len;
+
+ writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) |
+ RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16),
+ rkvdec->regs + RKVDEC_REG_PICPAR);
+ writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16),
+ rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE);
+ writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16),
+ rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE);
+
+ stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0);
+ writel_relaxed(RKVDEC_STRM_LEN(stream_len),
+ rkvdec->regs + RKVDEC_REG_STRM_LEN);
+
+ /*
+ * Reset count buffer, because decoder only output intra related syntax
+ * counts when decoding intra frame, but update entropy need to update
+ * all the probabilities.
+ */
+ if (intra_only)
+ memset(vp9_ctx->count_tbl.cpu, 0, vp9_ctx->count_tbl.size);
+
+ vp9_ctx->cur.segmapid = vp9_ctx->last.segmapid;
+ if (!intra_only &&
+ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
+ (!(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) ||
+ (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP)))
+ vp9_ctx->cur.segmapid++;
+
+ for (i = 0; i < ARRAY_SIZE(ref_bufs); i++)
+ config_ref_registers(ctx, run, ref_bufs, i);
+
+ for (i = 0; i < 8; i++)
+ config_seg_registers(ctx, i);
+
+ writel_relaxed(RKVDEC_VP9_TX_MODE(dec_params->tx_mode) |
+ RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode),
+ rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG);
+
+ if (!intra_only) {
+ const struct v4l2_vp9_loop_filter *lf;
+ s8 delta;
+
+ if (vp9_ctx->last.valid)
+ lf = &vp9_ctx->last.lf;
+ else
+ lf = &vp9_ctx->cur.lf;
+
+ val = 0;
+ for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
+ delta = lf->ref_deltas[i];
+ val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta);
+ }
+
+ writel_relaxed(val,
+ rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME);
+
+ for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
+ delta = lf->mode_deltas[i];
+ last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i,
+ delta);
+ }
+ }
+
+ if (vp9_ctx->last.valid && !intra_only &&
+ vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED)
+ last_frame_info |= RKVDEC_SEG_EN_LASTFRAME;
+
+ if (vp9_ctx->last.valid &&
+ vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME)
+ last_frame_info |= RKVDEC_LAST_SHOW_FRAME;
+
+ if (vp9_ctx->last.valid &&
+ vp9_ctx->last.flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY))
+ last_frame_info |= RKVDEC_LAST_INTRA_ONLY;
+
+ if (vp9_ctx->last.valid &&
+ last->vp9.width == dst->vp9.width &&
+ last->vp9.height == dst->vp9.height)
+ last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR;
+
+ writel_relaxed(last_frame_info,
+ rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME);
+
+ writel_relaxed(stream_len - dec_params->compressed_header_size -
+ dec_params->uncompressed_header_size,
+ rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE);
+
+ for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) {
+ u32 refw = ref_bufs[i]->vp9.width;
+ u32 refh = ref_bufs[i]->vp9.height;
+ u32 hscale, vscale;
+
+ hscale = (refw << 14) / dst->vp9.width;
+ vscale = (refh << 14) / dst->vp9.height;
+ writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) |
+ RKVDEC_VP9_REF_VER_SCALE(vscale),
+ rkvdec->regs + RKVDEC_VP9_REF_SCALE(i));
+ }
+
+ addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0);
+ writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE);
+ addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0);
+ writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE);
+ writel_relaxed(vp9_ctx->priv_tbl.dma +
+ offsetof(struct rkvdec_vp9_priv_tbl, probs),
+ rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE);
+ writel_relaxed(vp9_ctx->count_tbl.dma,
+ rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE);
+
+ writel_relaxed(vp9_ctx->priv_tbl.dma +
+ offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+ (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid),
+ rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE);
+ writel_relaxed(vp9_ctx->priv_tbl.dma +
+ offsetof(struct rkvdec_vp9_priv_tbl, segmap) +
+ (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)),
+ rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE);
+
+ if (!intra_only &&
+ !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) &&
+ vp9_ctx->last.valid)
+ mv_ref = last;
+ else
+ mv_ref = dst;
+
+ writel_relaxed(get_mv_base_addr(mv_ref),
+ rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE);
+
+ writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width |
+ (ctx->decoded_fmt.fmt.pix_mp.height << 16),
+ rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE);
+}
+
+static int
+validate_dec_params(struct rkvdec_ctx *ctx,
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params)
+{
+ unsigned int aligned_width, aligned_height;
+
+ /* We only support profile 0. */
+ if (dec_params->profile != 0) {
+ dev_err(ctx->dev->dev, "unsupported profile %d\n",
+ dec_params->profile);
+ return -EINVAL;
+ }
+
+ aligned_width = round_up(dec_params->frame_width_minus_1 + 1, 64);
+ aligned_height = round_up(dec_params->frame_height_minus_1 + 1, 64);
+
+ /*
+ * Userspace should update the capture/decoded format when the
+ * resolution changes.
+ */
+ if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width ||
+ aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) {
+ dev_err(ctx->dev->dev,
+ "unexpected bitstream resolution %dx%d\n",
+ dec_params->frame_width_minus_1 + 1,
+ dec_params->frame_height_minus_1 +1);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rkvdec_vp9_run_preamble(struct rkvdec_ctx *ctx,
+ struct rkvdec_vp9_run *run)
+{
+ const struct v4l2_ctrl_vp9_frame_decode_params *dec_params;
+ const struct v4l2_ctrl_vp9_frame_ctx *fctx = NULL;
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct v4l2_ctrl *ctrl;
+ u8 frm_ctx;
+ int ret;
+
+ rkvdec_run_preamble(ctx, &run->base);
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS);
+ WARN_ON(!ctrl);
+
+ dec_params = ctrl ? ctrl->p_cur.p : NULL;
+ if (WARN_ON(!dec_params))
+ return -EINVAL;
+
+ ret = validate_dec_params(ctx, dec_params);
+ if (ret)
+ return ret;
+
+ run->decode_params = dec_params;
+
+ /* No need to load the frame context if we don't need to update it. */
+ if (!(dec_params->flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX))
+ return 0;
+
+ /*
+ * When a refresh context is requested in parallel mode, we should just
+ * update the context with the probs passed in the decode parameters.
+ */
+ if (dec_params->flags & V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE) {
+ vp9_ctx->frame_context.probs = dec_params->probs;
+ return 0;
+ }
+
+ frm_ctx = run->decode_params->frame_context_idx;
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(frm_ctx));
+ if (WARN_ON(!ctrl))
+ return 0;
+
+ fctx = ctrl->p_cur.p;
+ vp9_ctx->frame_context = *fctx;
+
+ /*
+ * For intra-only frames, we must update the context TX and skip probs
+ * with the value passed in the decode params.
+ */
+ if (dec_params->flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY)) {
+ struct v4l2_vp9_probabilities *probs;
+
+ probs = &vp9_ctx->frame_context.probs;
+ memcpy(probs->skip, dec_params->probs.skip,
+ sizeof(probs->skip));
+ memcpy(probs->tx8, dec_params->probs.tx8,
+ sizeof(probs->tx8));
+ memcpy(probs->tx16, dec_params->probs.tx16,
+ sizeof(probs->tx16));
+ memcpy(probs->tx32, dec_params->probs.tx32,
+ sizeof(probs->tx32));
+ }
+
+ return 0;
+}
+
+static int rkvdec_vp9_run(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ struct rkvdec_vp9_run run = { };
+ int ret;
+
+ ret = rkvdec_vp9_run_preamble(ctx, &run);
+ if (ret) {
+ rkvdec_run_postamble(ctx, &run.base);
+ return ret;
+ }
+
+ /* Prepare probs. */
+ init_probs(ctx, &run);
+
+ /* Configure hardware registers. */
+ config_registers(ctx, &run);
+
+ rkvdec_run_postamble(ctx, &run.base);
+
+ schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000));
+
+ writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND);
+ writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND);
+
+ writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN);
+ /* Start decoding! */
+ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E |
+ RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E,
+ rkvdec->regs + RKVDEC_REG_INTERRUPT);
+
+ return 0;
+}
+
+static u8 adapt_prob(u8 p1, u32 ct0, u32 ct1, u16 max_count, u32 update_factor)
+{
+ u32 ct = ct0 + ct1, p2;
+ u32 lo = 1;
+ u32 hi = 255;
+
+ if (!ct)
+ return p1;
+
+ p2 = ((ct0 << 8) + (ct >> 1)) / ct;
+ p2 = clamp(p2, lo, hi);
+ ct = min_t(u32, ct, max_count);
+
+ if (WARN_ON(max_count >= 257))
+ return p1;
+
+ update_factor = rkvdec_fastdiv(update_factor * ct, max_count);
+
+ return p1 + (((p2 - p1) * update_factor + 128) >> 8);
+}
+
+#define BAND_6(band) ((band) == 0 ? 3 : 6)
+
+static void adapt_coeff(u8 coef[6][6][3],
+ const struct rkvdec_vp9_refs_counts ref_cnt[6][6],
+ u32 uf)
+{
+ s32 l, m, n;
+
+ for (l = 0; l < 6; l++) {
+ for (m = 0; m < BAND_6(l); m++) {
+ u8 *p = coef[l][m];
+ const u32 n0 = ref_cnt[l][m].coeff[0];
+ const u32 n1 = ref_cnt[l][m].coeff[1];
+ const u32 n2 = ref_cnt[l][m].coeff[2];
+ const u32 neob = ref_cnt[l][m].eob[1];
+ const u32 eob_count = ref_cnt[l][m].eob[0];
+ const u32 branch_ct[3][2] = {
+ { neob, eob_count - neob },
+ { n0, n1 + n2 },
+ { n1, n2 }
+ };
+
+ for (n = 0; n < 3; n++)
+ p[n] = adapt_prob(p[n], branch_ct[n][0],
+ branch_ct[n][1], 24, uf);
+ }
+ }
+}
+
+static void
+adapt_coef_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6],
+ unsigned int uf)
+{
+ unsigned int i, j, k;
+
+ for (i = 0; i < ARRAY_SIZE(probs->coef); i++) {
+ for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) {
+ for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]);
+ k++) {
+ adapt_coeff(probs->coef[i][j][k],
+ ref_cnt[k][i][j],
+ uf);
+ }
+ }
+ }
+}
+
+static void adapt_intra_frame_probs(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct v4l2_vp9_probabilities *probs = &vp9_ctx->frame_context.probs;
+ const struct rkvdec_vp9_intra_frame_symbol_counts *sym_cnts;
+
+ sym_cnts = vp9_ctx->count_tbl.cpu;
+ adapt_coef_probs(probs, sym_cnts->ref_cnt, 112);
+}
+
+static void
+adapt_skip_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->skip); i++)
+ probs->skip[i] = adapt_prob(probs->skip[i],
+ sym_cnts->skip[i][0],
+ sym_cnts->skip[i][1],
+ 20, 128);
+}
+
+static void
+adapt_is_inter_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->is_inter); i++)
+ probs->is_inter[i] = adapt_prob(probs->is_inter[i],
+ sym_cnts->inter[i][0],
+ sym_cnts->inter[i][1],
+ 20, 128);
+}
+
+static void
+adapt_comp_mode_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->comp_mode); i++)
+ probs->comp_mode[i] = adapt_prob(probs->comp_mode[i],
+ sym_cnts->comp[i][0],
+ sym_cnts->comp[i][1],
+ 20, 128);
+}
+
+static void
+adapt_comp_ref_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->comp_ref); i++)
+ probs->comp_ref[i] = adapt_prob(probs->comp_ref[i],
+ sym_cnts->comp_ref[i][0],
+ sym_cnts->comp_ref[i][1],
+ 20, 128);
+}
+
+static void
+adapt_single_ref_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->single_ref); i++) {
+ u8 *p = probs->single_ref[i];
+
+ p[0] = adapt_prob(p[0], sym_cnts->single_ref[i][0][0],
+ sym_cnts->single_ref[i][0][1], 20, 128);
+ p[1] = adapt_prob(p[1], sym_cnts->single_ref[i][1][0],
+ sym_cnts->single_ref[i][1][1], 20, 128);
+ }
+}
+
+static void
+adapt_partition_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->partition); i++) {
+ const u32 *c = sym_cnts->partition[i];
+ u8 *p = probs->partition[i];
+
+ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128);
+ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128);
+ }
+}
+
+static void
+adapt_tx_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->tx8); i++) {
+ u8 *p16x16 = probs->tx16[i];
+ u8 *p32x32 = probs->tx32[i];
+ const u32 *c16 = sym_cnts->tx16p[i];
+ const u32 *c32 = sym_cnts->tx32p[i];
+ const u32 *c8 = sym_cnts->tx8p[i];
+ u8 *p8x8 = probs->tx8[i];
+
+ p8x8[0] = adapt_prob(p8x8[0], c8[0], c8[1], 20, 128);
+ p16x16[0] = adapt_prob(p16x16[0], c16[0], c16[1] + c16[2],
+ 20, 128);
+ p16x16[1] = adapt_prob(p16x16[1], c16[1], c16[2], 20, 128);
+ p32x32[0] = adapt_prob(p32x32[0], c32[0],
+ c32[1] + c32[2] + c32[3], 20, 128);
+ p32x32[1] = adapt_prob(p32x32[1], c32[1], c32[2] + c32[3],
+ 20, 128);
+ p32x32[2] = adapt_prob(p32x32[2], c32[2], c32[3], 20, 128);
+ }
+}
+
+static void
+adapt_interp_filter_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->interp_filter); i++) {
+ u8 *p = probs->interp_filter[i];
+ const u32 *c = sym_cnts->filter[i];
+
+ p[0] = adapt_prob(p[0], c[0], c[1] + c[2], 20, 128);
+ p[1] = adapt_prob(p[1], c[1], c[2], 20, 128);
+ }
+}
+
+static void
+adapt_inter_mode_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->inter_mode); i++) {
+ const u32 *c = sym_cnts->mv_mode[i];
+ u8 *p = probs->inter_mode[i];
+
+ p[0] = adapt_prob(p[0], c[2], c[1] + c[0] + c[3], 20, 128);
+ p[1] = adapt_prob(p[1], c[0], c[1] + c[3], 20, 128);
+ p[2] = adapt_prob(p[2], c[1], c[3], 20, 128);
+ }
+}
+
+static void
+adapt_mv_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts,
+ bool high_prec_mv)
+{
+ const u32 *c = sym_cnts->mv_joint;
+ u8 *p = probs->mv.joint;
+ unsigned int i, j;
+ u32 sum;
+
+ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128);
+ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128);
+
+ for (i = 0; i < ARRAY_SIZE(probs->mv.sign); i++) {
+ p = probs->mv.sign;
+
+ p[i] = adapt_prob(p[i], sym_cnts->sign[i][0],
+ sym_cnts->sign[i][1], 20, 128);
+
+ p = probs->mv.class[i];
+ c = sym_cnts->classes[i];
+ sum = c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] +
+ c[9] + c[10];
+ p[0] = adapt_prob(p[0], c[0], sum, 20, 128);
+ sum -= c[1];
+ p[1] = adapt_prob(p[1], c[1], sum, 20, 128);
+ sum -= c[2] + c[3];
+ p[2] = adapt_prob(p[2], c[2] + c[3], sum, 20, 128);
+ p[3] = adapt_prob(p[3], c[2], c[3], 20, 128);
+ sum -= c[4] + c[5];
+ p[4] = adapt_prob(p[4], c[4] + c[5], sum, 20, 128);
+ p[5] = adapt_prob(p[5], c[4], c[5], 20, 128);
+ sum -= c[6];
+ p[6] = adapt_prob(p[6], c[6], sum, 20, 128);
+ p[7] = adapt_prob(p[7], c[7] + c[8], c[9] + c[10], 20, 128);
+ p[8] = adapt_prob(p[8], c[7], c[8], 20, 128);
+ p[9] = adapt_prob(p[9], c[9], c[10], 20, 128);
+
+ p = probs->mv.class0_bit;
+ p[i] = adapt_prob(p[i],
+ sym_cnts->class0[i][0],
+ sym_cnts->class0[i][1], 20, 128);
+
+ p = probs->mv.bits[i];
+ for (j = 0; j < 10; j++)
+ p[j] = adapt_prob(p[j], sym_cnts->bits[i][j][0],
+ sym_cnts->bits[i][j][1], 20, 128);
+
+ for (j = 0; j < 2; j++) {
+ p = probs->mv.class0_fr[i][j];
+ c = sym_cnts->class0_fp[i][j];
+ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3],
+ 20, 128);
+ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128);
+ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128);
+ }
+
+ p = probs->mv.fr[i];
+ c = sym_cnts->fp[i];
+ p[0] = adapt_prob(p[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ p[1] = adapt_prob(p[1], c[1], c[2] + c[3], 20, 128);
+ p[2] = adapt_prob(p[2], c[2], c[3], 20, 128);
+
+ if (!high_prec_mv)
+ continue;
+
+ p = probs->mv.class0_hp;
+ p[i] = adapt_prob(p[i], sym_cnts->class0_hp[i][0],
+ sym_cnts->class0_hp[i][1], 20, 128);
+
+ p = probs->mv.hp;
+ p[i] = adapt_prob(p[i], sym_cnts->hp[i][0],
+ sym_cnts->hp[i][1], 20, 128);
+ }
+}
+
+static void
+adapt_intra_mode_probs(u8 *p, const u32 *c)
+{
+ u32 sum = 0, s2;
+ unsigned int i;
+
+ for (i = V4L2_VP9_INTRA_PRED_MODE_V; i <= V4L2_VP9_INTRA_PRED_MODE_TM;
+ i++)
+ sum += c[i];
+
+ p[0] = adapt_prob(p[0], c[V4L2_VP9_INTRA_PRED_MODE_DC], sum, 20, 128);
+ sum -= c[V4L2_VP9_INTRA_PRED_MODE_TM];
+ p[1] = adapt_prob(p[1], c[V4L2_VP9_INTRA_PRED_MODE_TM], sum, 20, 128);
+ sum -= c[V4L2_VP9_INTRA_PRED_MODE_V];
+ p[2] = adapt_prob(p[2], c[V4L2_VP9_INTRA_PRED_MODE_V], sum, 20, 128);
+ s2 = c[V4L2_VP9_INTRA_PRED_MODE_H] + c[V4L2_VP9_INTRA_PRED_MODE_D135] +
+ c[V4L2_VP9_INTRA_PRED_MODE_D117];
+ sum -= s2;
+ p[3] = adapt_prob(p[3], s2, sum, 20, 128);
+ s2 -= c[V4L2_VP9_INTRA_PRED_MODE_H];
+ p[4] = adapt_prob(p[4], c[V4L2_VP9_INTRA_PRED_MODE_H], s2, 20, 128);
+ p[5] = adapt_prob(p[5], c[V4L2_VP9_INTRA_PRED_MODE_D135],
+ c[V4L2_VP9_INTRA_PRED_MODE_D117], 20, 128);
+ sum -= c[V4L2_VP9_INTRA_PRED_MODE_D45];
+ p[6] = adapt_prob(p[6], c[V4L2_VP9_INTRA_PRED_MODE_D45],
+ sum, 20, 128);
+ sum -= c[V4L2_VP9_INTRA_PRED_MODE_D63];
+ p[7] = adapt_prob(p[7], c[V4L2_VP9_INTRA_PRED_MODE_D63], sum,
+ 20, 128);
+ p[8] = adapt_prob(p[8], c[V4L2_VP9_INTRA_PRED_MODE_D153],
+ c[V4L2_VP9_INTRA_PRED_MODE_D207], 20, 128);
+}
+
+static void
+adapt_y_intra_mode_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->y_mode); i++)
+ adapt_intra_mode_probs(probs->y_mode[i], sym_cnts->y_mode[i]);
+}
+
+static void
+adapt_uv_intra_mode_probs(struct v4l2_vp9_probabilities *probs,
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(probs->uv_mode); i++)
+ adapt_intra_mode_probs(probs->uv_mode[i],
+ sym_cnts->uv_mode[i]);
+}
+
+static void
+adapt_inter_frame_probs(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct v4l2_vp9_probabilities *probs = &vp9_ctx->frame_context.probs;
+ const struct rkvdec_vp9_inter_frame_symbol_counts *sym_cnts;
+
+ sym_cnts = vp9_ctx->count_tbl.cpu;
+ /* coefficients */
+ if (vp9_ctx->last.valid &&
+ !(vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME))
+ adapt_coef_probs(probs, sym_cnts->ref_cnt, 112);
+ else
+ adapt_coef_probs(probs, sym_cnts->ref_cnt, 128);
+
+ /* skip flag */
+ adapt_skip_probs(probs, sym_cnts);
+
+ /* intra/inter flag */
+ adapt_is_inter_probs(probs, sym_cnts);
+
+ /* comppred flag */
+ adapt_comp_mode_probs(probs, sym_cnts);
+
+ /* reference frames */
+ adapt_comp_ref_probs(probs, sym_cnts);
+
+ if (vp9_ctx->cur.reference_mode != V4L2_VP9_REF_MODE_COMPOUND)
+ adapt_single_ref_probs(probs, sym_cnts);
+
+ /* block partitioning */
+ adapt_partition_probs(probs, sym_cnts);
+
+ /* tx size */
+ if (vp9_ctx->cur.tx_mode == V4L2_VP9_TX_MODE_SELECT)
+ adapt_tx_probs(probs, sym_cnts);
+
+ /* interpolation filter */
+ if (vp9_ctx->cur.interpolation_filter == V4L2_VP9_INTERP_FILTER_SWITCHABLE)
+ adapt_interp_filter_probs(probs, sym_cnts);
+
+ /* inter modes */
+ adapt_inter_mode_probs(probs, sym_cnts);
+
+ /* mv probs */
+ adapt_mv_probs(probs, sym_cnts,
+ !!(vp9_ctx->cur.flags &
+ V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV));
+
+ /* y intra modes */
+ adapt_y_intra_mode_probs(probs, sym_cnts);
+
+ /* uv intra modes */
+ adapt_uv_intra_mode_probs(probs, sym_cnts);
+}
+
+static void adapt_probs(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ bool intra_only;
+
+ intra_only = !!(vp9_ctx->cur.flags &
+ (V4L2_VP9_FRAME_FLAG_KEY_FRAME |
+ V4L2_VP9_FRAME_FLAG_INTRA_ONLY));
+
+ if (intra_only)
+ adapt_intra_frame_probs(ctx);
+ else
+ adapt_inter_frame_probs(ctx);
+}
+
+static void rkvdec_vp9_done(struct rkvdec_ctx *ctx,
+ struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf,
+ enum vb2_buffer_state result)
+{
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct v4l2_ctrl *ctrl;
+ unsigned int fctx_idx;
+
+ if (result == VB2_BUF_STATE_ERROR)
+ goto out_update_last;
+
+ if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX))
+ goto out_update_last;
+
+ fctx_idx = vp9_ctx->cur.frame_context_idx;
+
+ if (!(vp9_ctx->cur.flags &
+ (V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT |
+ V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE)))
+ adapt_probs(ctx);
+
+ ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
+ V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(fctx_idx));
+ if (WARN_ON(!ctrl))
+ goto out_update_last;
+
+ v4l2_ctrl_s_ctrl_compound(ctrl, V4L2_CTRL_TYPE_VP9_FRAME_CONTEXT,
+ &vp9_ctx->frame_context);
+
+out_update_last:
+ update_ctx_last_info(vp9_ctx);
+}
+
+static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_dev *rkvdec = ctx->dev;
+ struct rkvdec_vp9_priv_tbl *priv_tbl;
+ struct rkvdec_vp9_ctx *vp9_ctx;
+ u8 *count_tbl;
+ int ret;
+
+ vp9_ctx = kzalloc(sizeof(*vp9_ctx), GFP_KERNEL);
+ if (!vp9_ctx)
+ return -ENOMEM;
+
+ ctx->priv = vp9_ctx;
+
+ priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl),
+ &vp9_ctx->priv_tbl.dma, GFP_KERNEL);
+ if (!priv_tbl) {
+ ret = -ENOMEM;
+ goto err_free_ctx;
+ }
+
+ vp9_ctx->priv_tbl.size = sizeof(*priv_tbl);
+ vp9_ctx->priv_tbl.cpu = priv_tbl;
+ memset(priv_tbl, 0, sizeof(*priv_tbl));
+
+ count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE,
+ &vp9_ctx->count_tbl.dma, GFP_KERNEL);
+ if (!count_tbl) {
+ ret = -ENOMEM;
+ goto err_free_priv_tbl;
+ }
+
+ vp9_ctx->count_tbl.size = RKVDEC_VP9_COUNT_SIZE;
+ vp9_ctx->count_tbl.cpu = count_tbl;
+ memset(count_tbl, 0, sizeof(*count_tbl));
+
+ return 0;
+
+err_free_priv_tbl:
+ dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size,
+ vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma);
+
+err_free_ctx:
+ kfree(vp9_ctx);
+ return ret;
+}
+
+static void rkvdec_vp9_stop(struct rkvdec_ctx *ctx)
+{
+ struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv;
+ struct rkvdec_dev *rkvdec = ctx->dev;
+
+ dma_free_coherent(rkvdec->dev, vp9_ctx->count_tbl.size,
+ vp9_ctx->count_tbl.cpu, vp9_ctx->count_tbl.dma);
+ dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size,
+ vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma);
+ kfree(vp9_ctx);
+}
+
+static int rkvdec_vp9_adjust_fmt(struct rkvdec_ctx *ctx,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp;
+
+ fmt->num_planes = 1;
+ if (!fmt->plane_fmt[0].sizeimage)
+ fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * 2;
+ return 0;
+}
+
+const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops = {
+ .adjust_fmt = rkvdec_vp9_adjust_fmt,
+ .start = rkvdec_vp9_start,
+ .stop = rkvdec_vp9_stop,
+ .run = rkvdec_vp9_run,
+ .done = rkvdec_vp9_done,
+};
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 91f8a1bb6176..f0f28f6a68cf 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -159,6 +159,45 @@ static const u32 rkvdec_h264_decoded_fmts[] = {
V4L2_PIX_FMT_NV20,
};
+static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = {
+ {
+ .per_request = true,
+ .mandatory = true,
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_DECODE_PARAMS,
+ },
+ {
+ .mandatory = true,
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(0),
+ },
+ {
+ .mandatory = true,
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(1),
+ },
+ {
+ .mandatory = true,
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(2),
+ },
+ {
+ .mandatory = true,
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_FRAME_CONTEXT(3),
+ },
+ {
+ .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+ .cfg.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ .cfg.max = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ .cfg.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
+ },
+};
+
+static const struct rkvdec_ctrls rkvdec_vp9_ctrls = {
+ .ctrls = rkvdec_vp9_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs),
+};
+
+static const u32 rkvdec_vp9_decoded_fmts[] = {
+ V4L2_PIX_FMT_NV12,
+};
+
static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
{
.fourcc = V4L2_PIX_FMT_H264_SLICE,
@@ -174,6 +213,21 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = {
.ops = &rkvdec_h264_fmt_ops,
.num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts),
.decoded_fmts = rkvdec_h264_decoded_fmts,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP9_FRAME,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 4096,
+ .step_width = 64,
+ .min_height = 64,
+ .max_height = 2304,
+ .step_height = 64,
+ },
+ .ctrls = &rkvdec_vp9_ctrls,
+ .ops = &rkvdec_vp9_fmt_ops,
+ .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts),
+ .decoded_fmts = rkvdec_vp9_decoded_fmts,
}
};
diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h
index e95c52e3168a..5f66f07acac5 100644
--- a/drivers/staging/media/rkvdec/rkvdec.h
+++ b/drivers/staging/media/rkvdec/rkvdec.h
@@ -51,6 +51,10 @@ struct rkvdec_vp9_decoded_buffer_info {
struct rkvdec_decoded_buffer {
/* Must be the first field in this struct. */
struct v4l2_m2m_buffer base;
+
+ union {
+ struct rkvdec_vp9_decoded_buffer_info vp9;
+ };
};
static inline struct rkvdec_decoded_buffer *
@@ -119,4 +123,6 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run);
extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops;
+extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops;
+
#endif /* RKVDEC_H_ */