Commit 54587d99 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-next-20230127' of...

Merge tag 'drm-next-20230127' of git://git.kernel.org/pub/scm/linux/kernel/git/pinchartl/linux into drm-next

Renesas R-Car DU fixes and improvements
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/Y9QCw3SkHm6k1bwJ@pendragon.ideasonboard.com
parents 49ed9f39 fd228eb0
...@@ -11,13 +11,14 @@ maintainers: ...@@ -11,13 +11,14 @@ maintainers:
description: | description: |
This binding describes the MIPI DSI/CSI-2 encoder embedded in the Renesas This binding describes the MIPI DSI/CSI-2 encoder embedded in the Renesas
R-Car V3U SoC. The encoder can operate in either DSI or CSI-2 mode, with up R-Car Gen4 SoCs. The encoder can operate in either DSI or CSI-2 mode, with up
to four data lanes. to four data lanes.
properties: properties:
compatible: compatible:
enum: enum:
- renesas,r8a779a0-dsi-csi2-tx # for V3U - renesas,r8a779a0-dsi-csi2-tx # for V3U
- renesas,r8a779g0-dsi-csi2-tx # for V4H
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -40,6 +40,7 @@ properties: ...@@ -40,6 +40,7 @@ properties:
- renesas,du-r8a77990 # for R-Car E3 compatible DU - renesas,du-r8a77990 # for R-Car E3 compatible DU
- renesas,du-r8a77995 # for R-Car D3 compatible DU - renesas,du-r8a77995 # for R-Car D3 compatible DU
- renesas,du-r8a779a0 # for R-Car V3U compatible DU - renesas,du-r8a779a0 # for R-Car V3U compatible DU
- renesas,du-r8a779g0 # for R-Car V4H compatible DU
reg: reg:
maxItems: 1 maxItems: 1
...@@ -762,6 +763,7 @@ allOf: ...@@ -762,6 +763,7 @@ allOf:
contains: contains:
enum: enum:
- renesas,du-r8a779a0 - renesas,du-r8a779a0
- renesas,du-r8a779g0
then: then:
properties: properties:
clocks: clocks:
......
...@@ -262,7 +262,12 @@ the second byte and Y'\ :sub:`7-0` in the third byte. ...@@ -262,7 +262,12 @@ the second byte and Y'\ :sub:`7-0` in the third byte.
================= =================
These formats, commonly referred to as YUYV or YUY2, subsample the chroma These formats, commonly referred to as YUYV or YUY2, subsample the chroma
components horizontally by 2, storing 2 pixels in 4 bytes. components horizontally by 2, storing 2 pixels in a container. The container
is 32-bits for 8-bit formats, and 64-bits for 10+-bit formats.
The packed YUYV formats with more than 8 bits per component are stored as four
16-bit little-endian words. Each word's most significant bits contain one
component, and the least significant bits are zero padding.
.. raw:: latex .. raw:: latex
...@@ -270,7 +275,7 @@ components horizontally by 2, storing 2 pixels in 4 bytes. ...@@ -270,7 +275,7 @@ components horizontally by 2, storing 2 pixels in 4 bytes.
.. tabularcolumns:: |p{3.4cm}|p{1.2cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}| .. tabularcolumns:: |p{3.4cm}|p{1.2cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|
.. flat-table:: Packed YUV 4:2:2 Formats .. flat-table:: Packed YUV 4:2:2 Formats in 32-bit container
:header-rows: 1 :header-rows: 1
:stub-columns: 0 :stub-columns: 0
...@@ -337,6 +342,46 @@ components horizontally by 2, storing 2 pixels in 4 bytes. ...@@ -337,6 +342,46 @@ components horizontally by 2, storing 2 pixels in 4 bytes.
- Y'\ :sub:`3` - Y'\ :sub:`3`
- Cb\ :sub:`2` - Cb\ :sub:`2`
.. tabularcolumns:: |p{3.4cm}|p{1.2cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|p{0.8cm}|
.. flat-table:: Packed YUV 4:2:2 Formats in 64-bit container
:header-rows: 1
:stub-columns: 0
* - Identifier
- Code
- Word 0
- Word 1
- Word 2
- Word 3
* .. _V4L2-PIX-FMT-Y210:
- ``V4L2_PIX_FMT_Y210``
- 'Y210'
- Y'\ :sub:`0` (bits 15-6)
- Cb\ :sub:`0` (bits 15-6)
- Y'\ :sub:`1` (bits 15-6)
- Cr\ :sub:`0` (bits 15-6)
* .. _V4L2-PIX-FMT-Y212:
- ``V4L2_PIX_FMT_Y212``
- 'Y212'
- Y'\ :sub:`0` (bits 15-4)
- Cb\ :sub:`0` (bits 15-4)
- Y'\ :sub:`1` (bits 15-4)
- Cr\ :sub:`0` (bits 15-4)
* .. _V4L2-PIX-FMT-Y216:
- ``V4L2_PIX_FMT_Y216``
- 'Y216'
- Y'\ :sub:`0` (bits 15-0)
- Cb\ :sub:`0` (bits 15-0)
- Y'\ :sub:`1` (bits 15-0)
- Cr\ :sub:`0` (bits 15-0)
.. raw:: latex .. raw:: latex
\normalsize \normalsize
......
...@@ -763,6 +763,200 @@ nomenclature that instead use the order of components as seen in a 24- or ...@@ -763,6 +763,200 @@ nomenclature that instead use the order of components as seen in a 24- or
\normalsize \normalsize
10 Bits Per Component
=====================
These formats store a 30-bit RGB triplet with an optional 2 bit alpha in four
bytes. They are named based on the order of the RGB components as seen in a
32-bit word, which is then stored in memory in little endian byte order
(unless otherwise noted by the presence of bit 31 in the 4CC value), and on the
number of bits for each component.
.. raw:: latex
\begingroup
\tiny
\setlength{\tabcolsep}{2pt}
.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|
.. flat-table:: RGB Formats 10 Bits Per Color Component
:header-rows: 2
:stub-columns: 0
* - Identifier
- Code
- :cspan:`7` Byte 0 in memory
- :cspan:`7` Byte 1
- :cspan:`7` Byte 2
- :cspan:`7` Byte 3
* -
-
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- 0
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- 0
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- 0
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- 0
* .. _V4L2-PIX-FMT-RGBX1010102:
- ``V4L2_PIX_FMT_RGBX1010102``
- 'RX30'
- b\ :sub:`5`
- b\ :sub:`4`
- b\ :sub:`3`
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
- x
- x
- g\ :sub:`3`
- g\ :sub:`2`
- g\ :sub:`1`
- g\ :sub:`0`
- b\ :sub:`9`
- b\ :sub:`8`
- b\ :sub:`7`
- b\ :sub:`6`
- r\ :sub:`1`
- r\ :sub:`0`
- g\ :sub:`9`
- g\ :sub:`8`
- g\ :sub:`7`
- g\ :sub:`6`
- g\ :sub:`5`
- g\ :sub:`4`
- r\ :sub:`9`
- r\ :sub:`8`
- r\ :sub:`7`
- r\ :sub:`6`
- r\ :sub:`5`
- r\ :sub:`4`
- r\ :sub:`3`
- r\ :sub:`2`
-
* .. _V4L2-PIX-FMT-RGBA1010102:
- ``V4L2_PIX_FMT_RGBA1010102``
- 'RA30'
- b\ :sub:`5`
- b\ :sub:`4`
- b\ :sub:`3`
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
- a\ :sub:`1`
- a\ :sub:`0`
- g\ :sub:`3`
- g\ :sub:`2`
- g\ :sub:`1`
- g\ :sub:`0`
- b\ :sub:`9`
- b\ :sub:`8`
- b\ :sub:`7`
- b\ :sub:`6`
- r\ :sub:`1`
- r\ :sub:`0`
- g\ :sub:`9`
- g\ :sub:`8`
- g\ :sub:`7`
- g\ :sub:`6`
- g\ :sub:`5`
- g\ :sub:`4`
- r\ :sub:`9`
- r\ :sub:`8`
- r\ :sub:`7`
- r\ :sub:`6`
- r\ :sub:`5`
- r\ :sub:`4`
- r\ :sub:`3`
- r\ :sub:`2`
-
* .. _V4L2-PIX-FMT-ARGB2101010:
- ``V4L2_PIX_FMT_ARGB2101010``
- 'AR30'
- b\ :sub:`7`
- b\ :sub:`6`
- b\ :sub:`5`
- b\ :sub:`4`
- b\ :sub:`3`
- b\ :sub:`2`
- b\ :sub:`1`
- b\ :sub:`0`
- g\ :sub:`5`
- g\ :sub:`4`
- g\ :sub:`3`
- g\ :sub:`2`
- g\ :sub:`1`
- g\ :sub:`0`
- b\ :sub:`9`
- b\ :sub:`8`
- r\ :sub:`3`
- r\ :sub:`2`
- r\ :sub:`1`
- r\ :sub:`0`
- g\ :sub:`9`
- g\ :sub:`8`
- g\ :sub:`7`
- g\ :sub:`6`
- a\ :sub:`1`
- a\ :sub:`0`
- r\ :sub:`9`
- r\ :sub:`8`
- r\ :sub:`7`
- r\ :sub:`6`
- r\ :sub:`5`
- r\ :sub:`4`
-
.. raw:: latex
\endgroup
Deprecated RGB Formats Deprecated RGB Formats
====================== ======================
......
...@@ -25,6 +25,7 @@ config DRM_RCAR_CMM ...@@ -25,6 +25,7 @@ config DRM_RCAR_CMM
config DRM_RCAR_DW_HDMI config DRM_RCAR_DW_HDMI
tristate "R-Car Gen3 and RZ/G2 DU HDMI Encoder Support" tristate "R-Car Gen3 and RZ/G2 DU HDMI Encoder Support"
depends on DRM && OF depends on DRM && OF
depends on DRM_RCAR_DU || COMPILE_TEST
select DRM_DW_HDMI select DRM_DW_HDMI
help help
Enable support for R-Car Gen3 or RZ/G2 internal HDMI encoder. Enable support for R-Car Gen3 or RZ/G2 internal HDMI encoder.
...@@ -32,6 +33,7 @@ config DRM_RCAR_DW_HDMI ...@@ -32,6 +33,7 @@ config DRM_RCAR_DW_HDMI
config DRM_RCAR_USE_LVDS config DRM_RCAR_USE_LVDS
bool "R-Car DU LVDS Encoder Support" bool "R-Car DU LVDS Encoder Support"
depends on DRM_BRIDGE && OF depends on DRM_BRIDGE && OF
depends on DRM_RCAR_DU || COMPILE_TEST
default DRM_RCAR_DU default DRM_RCAR_DU
help help
Enable support for the R-Car Display Unit embedded LVDS encoders. Enable support for the R-Car Display Unit embedded LVDS encoders.
...@@ -39,12 +41,15 @@ config DRM_RCAR_USE_LVDS ...@@ -39,12 +41,15 @@ config DRM_RCAR_USE_LVDS
config DRM_RCAR_LVDS config DRM_RCAR_LVDS
def_tristate DRM_RCAR_DU def_tristate DRM_RCAR_DU
depends on DRM_RCAR_USE_LVDS depends on DRM_RCAR_USE_LVDS
depends on PM
select DRM_KMS_HELPER select DRM_KMS_HELPER
select DRM_PANEL select DRM_PANEL
select RESET_CONTROLLER
config DRM_RCAR_USE_MIPI_DSI config DRM_RCAR_USE_MIPI_DSI
bool "R-Car DU MIPI DSI Encoder Support" bool "R-Car DU MIPI DSI Encoder Support"
depends on DRM_BRIDGE && OF depends on DRM_BRIDGE && OF
depends on DRM_RCAR_DU || COMPILE_TEST
default DRM_RCAR_DU default DRM_RCAR_DU
help help
Enable support for the R-Car Display Unit embedded MIPI DSI encoders. Enable support for the R-Car Display Unit embedded MIPI DSI encoders.
...@@ -53,6 +58,7 @@ config DRM_RCAR_MIPI_DSI ...@@ -53,6 +58,7 @@ config DRM_RCAR_MIPI_DSI
def_tristate DRM_RCAR_DU def_tristate DRM_RCAR_DU
depends on DRM_RCAR_USE_MIPI_DSI depends on DRM_RCAR_USE_MIPI_DSI
select DRM_MIPI_DSI select DRM_MIPI_DSI
select RESET_CONTROLLER
config DRM_RZG2L_MIPI_DSI config DRM_RZG2L_MIPI_DSI
tristate "RZ/G2L MIPI DSI Encoder Support" tristate "RZ/G2L MIPI DSI Encoder Support"
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
...@@ -204,11 +203,6 @@ static void rcar_du_escr_divider(struct clk *clk, unsigned long target, ...@@ -204,11 +203,6 @@ static void rcar_du_escr_divider(struct clk *clk, unsigned long target,
} }
} }
static const struct soc_device_attribute rcar_du_r8a7795_es1[] = {
{ .soc_id = "r8a7795", .revision = "ES1.*" },
{ /* sentinel */ }
};
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{ {
const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
...@@ -238,7 +232,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) ...@@ -238,7 +232,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
* no post-divider when a display PLL is present (as shown by * no post-divider when a display PLL is present (as shown by
* the workaround breaking HDMI output on M3-W during testing). * the workaround breaking HDMI output on M3-W during testing).
*/ */
if (soc_device_match(rcar_du_r8a7795_es1)) { if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY) {
target *= 2; target *= 2;
div = 1; div = 1;
} }
...@@ -251,13 +245,30 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) ...@@ -251,13 +245,30 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
| DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m) | DPLLCR_N(dpll.n) | DPLLCR_M(dpll.m)
| DPLLCR_STBY; | DPLLCR_STBY;
if (rcrtc->index == 1) if (rcrtc->index == 1) {
dpllcr |= DPLLCR_PLCS1 dpllcr |= DPLLCR_PLCS1
| DPLLCR_INCS_DOTCLKIN1; | DPLLCR_INCS_DOTCLKIN1;
else } else {
dpllcr |= DPLLCR_PLCS0 dpllcr |= DPLLCR_PLCS0_PLL
| DPLLCR_INCS_DOTCLKIN0; | DPLLCR_INCS_DOTCLKIN0;
/*
* On ES2.x we have a single mux controlled via bit 21,
* which selects between DCLKIN source (bit 21 = 0) and
* a PLL source (bit 21 = 1), where the PLL is always
* PLL1.
*
* On ES1.x we have an additional mux, controlled
* via bit 20, for choosing between PLL0 (bit 20 = 0)
* and PLL1 (bit 20 = 1). We always want to use PLL1,
* so on ES1.x, in addition to setting bit 21, we need
* to set the bit 20.
*/
if (rcdu->info->quirks & RCAR_DU_QUIRK_H3_ES1_PLL)
dpllcr |= DPLLCR_PLCS0_H3ES1X_PLL1;
}
rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr); rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr);
escr = ESCR_DCLKSEL_DCLKIN | div; escr = ESCR_DCLKSEL_DCLKIN | div;
...@@ -287,10 +298,12 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) ...@@ -287,10 +298,12 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
escr = params.escr; escr = params.escr;
} }
dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr); if (rcdu->info->gen < 4) {
dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr); rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr);
rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? OTAR13 : OTAR02, 0); rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? OTAR13 : OTAR02, 0);
}
/* Signal polarities */ /* Signal polarities */
dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0) dsmr = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sys_soc.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
...@@ -386,6 +387,43 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = { ...@@ -386,6 +387,43 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
.dpll_mask = BIT(2) | BIT(1), .dpll_mask = BIT(2) | BIT(1),
}; };
static const struct rcar_du_device_info rcar_du_r8a7795_es1_info = {
.gen = 3,
.features = RCAR_DU_FEATURE_CRTC_IRQ
| RCAR_DU_FEATURE_CRTC_CLOCK
| RCAR_DU_FEATURE_VSP1_SOURCE
| RCAR_DU_FEATURE_INTERLACED
| RCAR_DU_FEATURE_TVM_SYNC,
.quirks = RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY
| RCAR_DU_QUIRK_H3_ES1_PLL,
.channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
.routes = {
/*
* R8A7795 has one RGB output, two HDMI outputs and one
* LVDS output.
*/
[RCAR_DU_OUTPUT_DPAD0] = {
.possible_crtcs = BIT(3),
.port = 0,
},
[RCAR_DU_OUTPUT_HDMI0] = {
.possible_crtcs = BIT(1),
.port = 1,
},
[RCAR_DU_OUTPUT_HDMI1] = {
.possible_crtcs = BIT(2),
.port = 2,
},
[RCAR_DU_OUTPUT_LVDS0] = {
.possible_crtcs = BIT(0),
.port = 3,
},
},
.num_lvds = 1,
.num_rpf = 5,
.dpll_mask = BIT(2) | BIT(1),
};
static const struct rcar_du_device_info rcar_du_r8a7796_info = { static const struct rcar_du_device_info rcar_du_r8a7796_info = {
.gen = 3, .gen = 3,
.features = RCAR_DU_FEATURE_CRTC_IRQ .features = RCAR_DU_FEATURE_CRTC_IRQ
...@@ -504,7 +542,7 @@ static const struct rcar_du_device_info rcar_du_r8a7799x_info = { ...@@ -504,7 +542,7 @@ static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
}; };
static const struct rcar_du_device_info rcar_du_r8a779a0_info = { static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
.gen = 3, .gen = 4,
.features = RCAR_DU_FEATURE_CRTC_IRQ .features = RCAR_DU_FEATURE_CRTC_IRQ
| RCAR_DU_FEATURE_VSP1_SOURCE | RCAR_DU_FEATURE_VSP1_SOURCE
| RCAR_DU_FEATURE_NO_BLENDING, | RCAR_DU_FEATURE_NO_BLENDING,
...@@ -524,6 +562,27 @@ static const struct rcar_du_device_info rcar_du_r8a779a0_info = { ...@@ -524,6 +562,27 @@ static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
.dsi_clk_mask = BIT(1) | BIT(0), .dsi_clk_mask = BIT(1) | BIT(0),
}; };
static const struct rcar_du_device_info rcar_du_r8a779g0_info = {
.gen = 4,
.features = RCAR_DU_FEATURE_CRTC_IRQ
| RCAR_DU_FEATURE_VSP1_SOURCE
| RCAR_DU_FEATURE_NO_BLENDING,
.channels_mask = BIT(1) | BIT(0),
.routes = {
/* R8A779G0 has two MIPI DSI outputs. */
[RCAR_DU_OUTPUT_DSI0] = {
.possible_crtcs = BIT(0),
.port = 0,
},
[RCAR_DU_OUTPUT_DSI1] = {
.possible_crtcs = BIT(1),
.port = 1,
},
},
.num_rpf = 5,
.dsi_clk_mask = BIT(1) | BIT(0),
};
static const struct of_device_id rcar_du_of_table[] = { static const struct of_device_id rcar_du_of_table[] = {
{ .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info }, { .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
{ .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info }, { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
...@@ -549,11 +608,17 @@ static const struct of_device_id rcar_du_of_table[] = { ...@@ -549,11 +608,17 @@ static const struct of_device_id rcar_du_of_table[] = {
{ .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info }, { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
{ .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info }, { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
{ .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info }, { .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
{ .compatible = "renesas,du-r8a779g0", .data = &rcar_du_r8a779g0_info },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, rcar_du_of_table); MODULE_DEVICE_TABLE(of, rcar_du_of_table);
static const struct soc_device_attribute rcar_du_soc_table[] = {
{ .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_du_r8a7795_es1_info },
{ /* sentinel */ }
};
const char *rcar_du_output_name(enum rcar_du_output output) const char *rcar_du_output_name(enum rcar_du_output output)
{ {
static const char * const names[] = { static const char * const names[] = {
...@@ -642,6 +707,7 @@ static void rcar_du_shutdown(struct platform_device *pdev) ...@@ -642,6 +707,7 @@ static void rcar_du_shutdown(struct platform_device *pdev)
static int rcar_du_probe(struct platform_device *pdev) static int rcar_du_probe(struct platform_device *pdev)
{ {
const struct soc_device_attribute *soc_attr;
struct rcar_du_device *rcdu; struct rcar_du_device *rcdu;
unsigned int mask; unsigned int mask;
int ret; int ret;
...@@ -656,8 +722,13 @@ static int rcar_du_probe(struct platform_device *pdev) ...@@ -656,8 +722,13 @@ static int rcar_du_probe(struct platform_device *pdev)
return PTR_ERR(rcdu); return PTR_ERR(rcdu);
rcdu->dev = &pdev->dev; rcdu->dev = &pdev->dev;
rcdu->info = of_device_get_match_data(rcdu->dev); rcdu->info = of_device_get_match_data(rcdu->dev);
soc_attr = soc_device_match(rcar_du_soc_table);
if (soc_attr)
rcdu->info = soc_attr->data;
platform_set_drvdata(pdev, rcdu); platform_set_drvdata(pdev, rcdu);
/* I/O resources */ /* I/O resources */
......
...@@ -34,6 +34,8 @@ struct rcar_du_device; ...@@ -34,6 +34,8 @@ struct rcar_du_device;
#define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */ #define RCAR_DU_FEATURE_NO_BLENDING BIT(5) /* PnMR.SPIM does not have ALP nor EOR bits */
#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ #define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */
#define RCAR_DU_QUIRK_H3_ES1_PCLK_STABILITY BIT(1) /* H3 ES1 has pclk stability issue */
#define RCAR_DU_QUIRK_H3_ES1_PLL BIT(2) /* H3 ES1 PLL setup differs from non-ES1 */
enum rcar_du_output { enum rcar_du_output {
RCAR_DU_OUTPUT_DPAD0, RCAR_DU_OUTPUT_DPAD0,
......
...@@ -107,7 +107,7 @@ static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp) ...@@ -107,7 +107,7 @@ static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp)
*/ */
rcrtc = rcdu->crtcs; rcrtc = rcdu->crtcs;
num_crtcs = rcdu->num_crtcs; num_crtcs = rcdu->num_crtcs;
} else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) { } else if (rcdu->info->gen >= 3 && rgrp->num_crtcs > 1) {
/* /*
* On Gen3 dot clocks are setup through per-group registers, * On Gen3 dot clocks are setup through per-group registers,
* only available when the group has two channels. * only available when the group has two channels.
...@@ -148,19 +148,23 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) ...@@ -148,19 +148,23 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
} }
rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5); rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
rcar_du_group_setup_pins(rgrp); if (rcdu->info->gen < 4)
rcar_du_group_setup_pins(rgrp);
/* if (rcdu->info->gen < 4) {
* TODO: Handle routing of the DU output to CMM dynamically, as we /*
* should bypass CMM completely when no color management feature is * TODO: Handle routing of the DU output to CMM dynamically, as
* used. * we should bypass CMM completely when no color management
*/ * feature is used.
defr7 |= (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) | */
(rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0); defr7 |= (rgrp->cmms_mask & BIT(1) ? DEFR7_CMME1 : 0) |
rcar_du_group_write(rgrp, DEFR7, defr7); (rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0);
rcar_du_group_write(rgrp, DEFR7, defr7);
}
if (rcdu->info->gen >= 2) { if (rcdu->info->gen >= 2) {
rcar_du_group_setup_defr8(rgrp); if (rcdu->info->gen < 4)
rcar_du_group_setup_defr8(rgrp);
rcar_du_group_setup_didsr(rgrp); rcar_du_group_setup_didsr(rgrp);
} }
......
...@@ -259,6 +259,24 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = { ...@@ -259,6 +259,24 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = {
.bpp = 32, .bpp = 32,
.planes = 1, .planes = 1,
.hsub = 1, .hsub = 1,
}, {
.fourcc = DRM_FORMAT_RGBX1010102,
.v4l2 = V4L2_PIX_FMT_RGBX1010102,
.bpp = 32,
.planes = 1,
.hsub = 1,
}, {
.fourcc = DRM_FORMAT_RGBA1010102,
.v4l2 = V4L2_PIX_FMT_RGBA1010102,
.bpp = 32,
.planes = 1,
.hsub = 1,
}, {
.fourcc = DRM_FORMAT_ARGB2101010,
.v4l2 = V4L2_PIX_FMT_ARGB2101010,
.bpp = 32,
.planes = 1,
.hsub = 1,
}, { }, {
.fourcc = DRM_FORMAT_YVYU, .fourcc = DRM_FORMAT_YVYU,
.v4l2 = V4L2_PIX_FMT_YVYU, .v4l2 = V4L2_PIX_FMT_YVYU,
...@@ -307,6 +325,18 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = { ...@@ -307,6 +325,18 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = {
.bpp = 24, .bpp = 24,
.planes = 3, .planes = 3,
.hsub = 1, .hsub = 1,
}, {
.fourcc = DRM_FORMAT_Y210,
.v4l2 = V4L2_PIX_FMT_Y210,
.bpp = 32,
.planes = 1,
.hsub = 2,
}, {
.fourcc = DRM_FORMAT_Y212,
.v4l2 = V4L2_PIX_FMT_Y212,
.bpp = 32,
.planes = 1,
.hsub = 2,
}, },
}; };
......
...@@ -283,12 +283,8 @@ ...@@ -283,12 +283,8 @@
#define DPLLCR 0x20044 #define DPLLCR 0x20044
#define DPLLCR_CODE (0x95 << 24) #define DPLLCR_CODE (0x95 << 24)
#define DPLLCR_PLCS1 (1 << 23) #define DPLLCR_PLCS1 (1 << 23)
/* #define DPLLCR_PLCS0_PLL (1 << 21)
* PLCS0 is bit 21, but H3 ES1.x requires bit 20 to be set as well. As bit 20 #define DPLLCR_PLCS0_H3ES1X_PLL1 (1 << 20)
* isn't implemented by other SoC in the Gen3 family it can safely be set
* unconditionally.
*/
#define DPLLCR_PLCS0 (3 << 20)
#define DPLLCR_CLKE (1 << 18) #define DPLLCR_CLKE (1 << 18)
#define DPLLCR_FDPLL(n) ((n) << 12) #define DPLLCR_FDPLL(n) ((n) << 12)
#define DPLLCR_N(n) ((n) << 5) #define DPLLCR_N(n) ((n) << 5)
......
...@@ -139,6 +139,43 @@ static const u32 rcar_du_vsp_formats[] = { ...@@ -139,6 +139,43 @@ static const u32 rcar_du_vsp_formats[] = {
DRM_FORMAT_YVU444, DRM_FORMAT_YVU444,
}; };
/*
* Gen4 supports the same formats as above, and additionally 2-10-10-10 RGB
* formats and Y210 & Y212 formats.
*/
static const u32 rcar_du_vsp_formats_gen4[] = {
DRM_FORMAT_RGB332,
DRM_FORMAT_ARGB4444,
DRM_FORMAT_XRGB4444,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_XRGB1555,
DRM_FORMAT_RGB565,
DRM_FORMAT_BGR888,
DRM_FORMAT_RGB888,
DRM_FORMAT_BGRA8888,
DRM_FORMAT_BGRX8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_RGBX1010102,
DRM_FORMAT_RGBA1010102,
DRM_FORMAT_ARGB2101010,
DRM_FORMAT_UYVY,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
DRM_FORMAT_NV12,
DRM_FORMAT_NV21,
DRM_FORMAT_NV16,
DRM_FORMAT_NV61,
DRM_FORMAT_YUV420,
DRM_FORMAT_YVU420,
DRM_FORMAT_YUV422,
DRM_FORMAT_YVU422,
DRM_FORMAT_YUV444,
DRM_FORMAT_YVU444,
DRM_FORMAT_Y210,
DRM_FORMAT_Y212,
};
static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
{ {
struct rcar_du_vsp_plane_state *state = struct rcar_du_vsp_plane_state *state =
...@@ -436,14 +473,23 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, ...@@ -436,14 +473,23 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
? DRM_PLANE_TYPE_PRIMARY ? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY; : DRM_PLANE_TYPE_OVERLAY;
struct rcar_du_vsp_plane *plane = &vsp->planes[i]; struct rcar_du_vsp_plane *plane = &vsp->planes[i];
unsigned int num_formats;
const u32 *formats;
if (rcdu->info->gen < 4) {
num_formats = ARRAY_SIZE(rcar_du_vsp_formats);
formats = rcar_du_vsp_formats;
} else {
num_formats = ARRAY_SIZE(rcar_du_vsp_formats_gen4);
formats = rcar_du_vsp_formats_gen4;
}
plane->vsp = vsp; plane->vsp = vsp;
plane->index = i; plane->index = i;
ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane, ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
crtcs, &rcar_du_vsp_plane_funcs, crtcs, &rcar_du_vsp_plane_funcs,
rcar_du_vsp_formats, formats, num_formats,
ARRAY_SIZE(rcar_du_vsp_formats),
NULL, type, NULL); NULL, type, NULL);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
...@@ -60,6 +62,7 @@ struct rcar_lvds_device_info { ...@@ -60,6 +62,7 @@ struct rcar_lvds_device_info {
struct rcar_lvds { struct rcar_lvds {
struct device *dev; struct device *dev;
const struct rcar_lvds_device_info *info; const struct rcar_lvds_device_info *info;
struct reset_control *rstc;
struct drm_bridge bridge; struct drm_bridge bridge;
...@@ -80,6 +83,11 @@ struct rcar_lvds { ...@@ -80,6 +83,11 @@ struct rcar_lvds {
#define bridge_to_rcar_lvds(b) \ #define bridge_to_rcar_lvds(b) \
container_of(b, struct rcar_lvds, bridge) container_of(b, struct rcar_lvds, bridge)
static u32 rcar_lvds_read(struct rcar_lvds *lvds, u32 reg)
{
return ioread32(lvds->mmio + reg);
}
static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data) static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
{ {
iowrite32(data, lvds->mmio + reg); iowrite32(data, lvds->mmio + reg);
...@@ -316,8 +324,8 @@ int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq) ...@@ -316,8 +324,8 @@ int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq)
dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq); dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq);
ret = clk_prepare_enable(lvds->clocks.mod); ret = pm_runtime_resume_and_get(lvds->dev);
if (ret < 0) if (ret)
return ret; return ret;
__rcar_lvds_pll_setup_d3_e3(lvds, freq, true); __rcar_lvds_pll_setup_d3_e3(lvds, freq, true);
...@@ -337,7 +345,7 @@ void rcar_lvds_pclk_disable(struct drm_bridge *bridge) ...@@ -337,7 +345,7 @@ void rcar_lvds_pclk_disable(struct drm_bridge *bridge)
rcar_lvds_write(lvds, LVDPLLCR, 0); rcar_lvds_write(lvds, LVDPLLCR, 0);
clk_disable_unprepare(lvds->clocks.mod); pm_runtime_put_sync(lvds->dev);
} }
EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable); EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable);
...@@ -396,8 +404,8 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, ...@@ -396,8 +404,8 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
u32 lvdcr0; u32 lvdcr0;
int ret; int ret;
ret = clk_prepare_enable(lvds->clocks.mod); ret = pm_runtime_resume_and_get(lvds->dev);
if (ret < 0) if (ret)
return; return;
/* Enable the companion LVDS encoder in dual-link mode. */ /* Enable the companion LVDS encoder in dual-link mode. */
...@@ -541,6 +549,32 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, ...@@ -541,6 +549,32 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state) struct drm_bridge_state *old_bridge_state)
{ {
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
u32 lvdcr0;
/*
* Clear the LVDCR0 bits in the order specified by the hardware
* documentation, ending with a write of 0 to the full register to
* clear all remaining bits.
*/
lvdcr0 = rcar_lvds_read(lvds, LVDCR0);
lvdcr0 &= ~LVDCR0_LVRES;
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) {
lvdcr0 &= ~LVDCR0_LVEN;
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
}
if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
lvdcr0 &= ~LVDCR0_PWD;
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
}
if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
lvdcr0 &= ~LVDCR0_PLLON;
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
}
rcar_lvds_write(lvds, LVDCR0, 0); rcar_lvds_write(lvds, LVDCR0, 0);
rcar_lvds_write(lvds, LVDCR1, 0); rcar_lvds_write(lvds, LVDCR1, 0);
...@@ -551,7 +585,7 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, ...@@ -551,7 +585,7 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
lvds->companion->funcs->atomic_disable(lvds->companion, lvds->companion->funcs->atomic_disable(lvds->companion,
old_bridge_state); old_bridge_state);
clk_disable_unprepare(lvds->clocks.mod); pm_runtime_put_sync(lvds->dev);
} }
static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge, static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
...@@ -844,6 +878,13 @@ static int rcar_lvds_probe(struct platform_device *pdev) ...@@ -844,6 +878,13 @@ static int rcar_lvds_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
return ret; return ret;
lvds->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(lvds->rstc))
return dev_err_probe(&pdev->dev, PTR_ERR(lvds->rstc),
"failed to get cpg reset\n");
pm_runtime_enable(&pdev->dev);
drm_bridge_add(&lvds->bridge); drm_bridge_add(&lvds->bridge);
return 0; return 0;
...@@ -855,6 +896,8 @@ static int rcar_lvds_remove(struct platform_device *pdev) ...@@ -855,6 +896,8 @@ static int rcar_lvds_remove(struct platform_device *pdev)
drm_bridge_remove(&lvds->bridge); drm_bridge_remove(&lvds->bridge);
pm_runtime_disable(&pdev->dev);
return 0; return 0;
} }
...@@ -913,11 +956,48 @@ static const struct of_device_id rcar_lvds_of_table[] = { ...@@ -913,11 +956,48 @@ static const struct of_device_id rcar_lvds_of_table[] = {
MODULE_DEVICE_TABLE(of, rcar_lvds_of_table); MODULE_DEVICE_TABLE(of, rcar_lvds_of_table);
static int rcar_lvds_runtime_suspend(struct device *dev)
{
struct rcar_lvds *lvds = dev_get_drvdata(dev);
clk_disable_unprepare(lvds->clocks.mod);
reset_control_assert(lvds->rstc);
return 0;
}
static int rcar_lvds_runtime_resume(struct device *dev)
{
struct rcar_lvds *lvds = dev_get_drvdata(dev);
int ret;
ret = reset_control_deassert(lvds->rstc);
if (ret)
return ret;
ret = clk_prepare_enable(lvds->clocks.mod);
if (ret < 0)
goto err_reset_assert;
return 0;
err_reset_assert:
reset_control_assert(lvds->rstc);
return ret;
}
static const struct dev_pm_ops rcar_lvds_pm_ops = {
SET_RUNTIME_PM_OPS(rcar_lvds_runtime_suspend, rcar_lvds_runtime_resume, NULL)
};
static struct platform_driver rcar_lvds_platform_driver = { static struct platform_driver rcar_lvds_platform_driver = {
.probe = rcar_lvds_probe, .probe = rcar_lvds_probe,
.remove = rcar_lvds_remove, .remove = rcar_lvds_remove,
.driver = { .driver = {
.name = "rcar-lvds", .name = "rcar-lvds",
.pm = &rcar_lvds_pm_ops,
.of_match_table = rcar_lvds_of_table, .of_match_table = rcar_lvds_of_table,
}, },
}; };
......
This diff is collapsed.
...@@ -122,7 +122,8 @@ ...@@ -122,7 +122,8 @@
#define VCLKSET_CKEN (1 << 16) #define VCLKSET_CKEN (1 << 16)
#define VCLKSET_COLOR_RGB (0 << 8) #define VCLKSET_COLOR_RGB (0 << 8)
#define VCLKSET_COLOR_YCC (1 << 8) #define VCLKSET_COLOR_YCC (1 << 8)
#define VCLKSET_DIV(x) (((x) & 0x3) << 4) #define VCLKSET_DIV_V3U(x) (((x) & 0x3) << 4)
#define VCLKSET_DIV_V4H(x) (((x) & 0x7) << 4)
#define VCLKSET_BPP_16 (0 << 2) #define VCLKSET_BPP_16 (0 << 2)
#define VCLKSET_BPP_18 (1 << 2) #define VCLKSET_BPP_18 (1 << 2)
#define VCLKSET_BPP_18L (2 << 2) #define VCLKSET_BPP_18L (2 << 2)
...@@ -166,6 +167,9 @@ ...@@ -166,6 +167,9 @@
#define PHTW_CWEN (1 << 8) #define PHTW_CWEN (1 << 8)
#define PHTW_TESTDIN_CODE(x) (((x) & 0xff) << 0) #define PHTW_TESTDIN_CODE(x) (((x) & 0xff) << 0)
#define PHTR 0x1038
#define PHTR_TEST (1 << 16)
#define PHTC 0x103c #define PHTC 0x103c
#define PHTC_TESTCLR (1 << 0) #define PHTC_TESTCLR (1 << 0)
......
...@@ -818,9 +818,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = { ...@@ -818,9 +818,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = {
.wpf_count = 2, .wpf_count = 2,
.num_bru_inputs = 5, .num_bru_inputs = 5,
}, { }, {
.version = VI6_IP_VERSION_MODEL_VSPD_V3U, .version = VI6_IP_VERSION_MODEL_VSPD_GEN4,
.model = "VSP2-D", .model = "VSP2-D",
.gen = 3, .gen = 4,
.features = VSP1_HAS_BRU | VSP1_HAS_EXT_DL, .features = VSP1_HAS_BRU | VSP1_HAS_EXT_DL,
.lif_count = 1, .lif_count = 1,
.rpf_count = 5, .rpf_count = 5,
......
...@@ -196,10 +196,10 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1) ...@@ -196,10 +196,10 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
/* Initialize the control handler. */ /* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgo->ctrls.handler, v4l2_ctrl_handler_init(&hgo->ctrls.handler,
vsp1->info->gen == 3 ? 2 : 1); vsp1->info->gen >= 3 ? 2 : 1);
hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler, hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler,
&hgo_max_rgb_control, NULL); &hgo_max_rgb_control, NULL);
if (vsp1->info->gen == 3) if (vsp1->info->gen >= 3)
hgo->ctrls.num_bins = hgo->ctrls.num_bins =
v4l2_ctrl_new_custom(&hgo->ctrls.handler, v4l2_ctrl_new_custom(&hgo->ctrls.handler,
&hgo_num_bins_control, NULL); &hgo_num_bins_control, NULL);
......
...@@ -114,6 +114,7 @@ static void lif_configure_stream(struct vsp1_entity *entity, ...@@ -114,6 +114,7 @@ static void lif_configure_stream(struct vsp1_entity *entity,
break; break;
case VI6_IP_VERSION_MODEL_VSPD_GEN3: case VI6_IP_VERSION_MODEL_VSPD_GEN3:
case VI6_IP_VERSION_MODEL_VSPD_GEN4:
default: default:
hbth = 0; hbth = 0;
obth = 3000; obth = 3000;
......
...@@ -146,6 +146,18 @@ static const struct vsp1_format_info vsp1_video_formats[] = { ...@@ -146,6 +146,18 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 32, 0, 0 }, false, false, 1, 1, false }, 1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_RGBX1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB10_RGB10A2_A2RGB10,
VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_RGBA1010102, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB10_RGB10A2_A2RGB10,
VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_ARGB2101010, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB10_RGB10A2_A2RGB10,
VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32, { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
...@@ -202,6 +214,12 @@ static const struct vsp1_format_info vsp1_video_formats[] = { ...@@ -202,6 +214,12 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
3, { 8, 8, 8 }, false, true, 1, 1, false }, 3, { 8, 8, 8 }, false, true, 1, 1, false },
{ V4L2_PIX_FMT_Y210, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 2, 1, false },
{ V4L2_PIX_FMT_Y212, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 2, 1, false },
}; };
/** /**
......
...@@ -228,6 +228,28 @@ ...@@ -228,6 +228,28 @@
#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0) #define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0)
#define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0 #define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0
#define VI6_RPF_EXT_INFMT0 0x0370
#define VI6_RPF_EXT_INFMT0_F2B BIT(12)
#define VI6_RPF_EXT_INFMT0_IPBD_Y_8 (0 << 8)
#define VI6_RPF_EXT_INFMT0_IPBD_Y_10 (1 << 8)
#define VI6_RPF_EXT_INFMT0_IPBD_Y_12 (2 << 8)
#define VI6_RPF_EXT_INFMT0_IPBD_C_8 (0 << 4)
#define VI6_RPF_EXT_INFMT0_IPBD_C_10 (1 << 4)
#define VI6_RPF_EXT_INFMT0_IPBD_C_12 (2 << 4)
#define VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10 (3 << 0)
#define VI6_RPF_EXT_INFMT1 0x0374
#define VI6_RPF_EXT_INFMT1_PACK_CPOS(a, b, c, d) \
(((a) << 24) | ((b) << 16) | ((c) << 8) | ((d) << 0))
#define VI6_RPF_EXT_INFMT2 0x0378
#define VI6_RPF_EXT_INFMT2_PACK_CLEN(a, b, c, d) \
(((a) << 24) | ((b) << 16) | ((c) << 8) | ((d) << 0))
#define VI6_RPF_BRDITH_CTRL 0x03e0
#define VI6_RPF_BRDITH_CTRL_ODE BIT(8)
#define VI6_RPF_BRDITH_CTRL_CBRM BIT(0)
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* WPF Control Registers * WPF Control Registers
*/ */
...@@ -766,7 +788,7 @@ ...@@ -766,7 +788,7 @@
#define VI6_IP_VERSION_MODEL_VSPD_V3 (0x18 << 8) #define VI6_IP_VERSION_MODEL_VSPD_V3 (0x18 << 8)
#define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) #define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8)
#define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) #define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8)
#define VI6_IP_VERSION_MODEL_VSPD_V3U (0x1c << 8) #define VI6_IP_VERSION_MODEL_VSPD_GEN4 (0x1c << 8)
/* RZ/G2L SoCs have no version register, So use 0x80 as the model version */ /* RZ/G2L SoCs have no version register, So use 0x80 as the model version */
#define VI6_IP_VERSION_MODEL_VSPD_RZG2L (0x80 << 8) #define VI6_IP_VERSION_MODEL_VSPD_RZG2L (0x80 << 8)
...@@ -782,6 +804,7 @@ ...@@ -782,6 +804,7 @@
#define VI6_IP_VERSION_SOC_M3N (0x04 << 0) #define VI6_IP_VERSION_SOC_M3N (0x04 << 0)
#define VI6_IP_VERSION_SOC_E3 (0x04 << 0) #define VI6_IP_VERSION_SOC_E3 (0x04 << 0)
#define VI6_IP_VERSION_SOC_V3U (0x05 << 0) #define VI6_IP_VERSION_SOC_V3U (0x05 << 0)
#define VI6_IP_VERSION_SOC_V4H (0x06 << 0)
/* RZ/G2L SoCs have no version register, So use 0x80 for SoC Identification */ /* RZ/G2L SoCs have no version register, So use 0x80 for SoC Identification */
#define VI6_IP_VERSION_SOC_RZG2L (0x80 << 0) #define VI6_IP_VERSION_SOC_RZG2L (0x80 << 0)
...@@ -845,6 +868,7 @@ ...@@ -845,6 +868,7 @@
#define VI6_FMT_XBXGXR_262626 0x21 #define VI6_FMT_XBXGXR_262626 0x21
#define VI6_FMT_ABGR_8888 0x22 #define VI6_FMT_ABGR_8888 0x22
#define VI6_FMT_XXRGB_88565 0x23 #define VI6_FMT_XXRGB_88565 0x23
#define VI6_FMT_RGB10_RGB10A2_A2RGB10 0x30
#define VI6_FMT_Y_UV_444 0x40 #define VI6_FMT_Y_UV_444 0x40
#define VI6_FMT_Y_UV_422 0x41 #define VI6_FMT_Y_UV_422 0x41
......
...@@ -109,6 +109,58 @@ static void rpf_configure_stream(struct vsp1_entity *entity, ...@@ -109,6 +109,58 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt); vsp1_rpf_write(rpf, dlb, VI6_RPF_INFMT, infmt);
vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap); vsp1_rpf_write(rpf, dlb, VI6_RPF_DSWAP, fmtinfo->swap);
if (entity->vsp1->info->gen == 4) {
u32 ext_infmt0;
u32 ext_infmt1;
u32 ext_infmt2;
switch (fmtinfo->fourcc) {
case V4L2_PIX_FMT_RGBX1010102:
ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10;
ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(0, 10, 20, 0);
ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 0);
break;
case V4L2_PIX_FMT_RGBA1010102:
ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10;
ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(0, 10, 20, 30);
ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 2);
break;
case V4L2_PIX_FMT_ARGB2101010:
ext_infmt0 = VI6_RPF_EXT_INFMT0_BYPP_M1_RGB10;
ext_infmt1 = VI6_RPF_EXT_INFMT1_PACK_CPOS(2, 12, 22, 0);
ext_infmt2 = VI6_RPF_EXT_INFMT2_PACK_CLEN(10, 10, 10, 2);
break;
case V4L2_PIX_FMT_Y210:
ext_infmt0 = VI6_RPF_EXT_INFMT0_F2B |
VI6_RPF_EXT_INFMT0_IPBD_Y_10 |
VI6_RPF_EXT_INFMT0_IPBD_C_10;
ext_infmt1 = 0x0;
ext_infmt2 = 0x0;
break;
case V4L2_PIX_FMT_Y212:
ext_infmt0 = VI6_RPF_EXT_INFMT0_F2B |
VI6_RPF_EXT_INFMT0_IPBD_Y_12 |
VI6_RPF_EXT_INFMT0_IPBD_C_12;
ext_infmt1 = 0x0;
ext_infmt2 = 0x0;
break;
default:
ext_infmt0 = 0;
ext_infmt1 = 0;
ext_infmt2 = 0;
break;
}
vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT0, ext_infmt0);
vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT1, ext_infmt1);
vsp1_rpf_write(rpf, dlb, VI6_RPF_EXT_INFMT2, ext_infmt2);
}
/* Output location. */ /* Output location. */
if (pipe->brx) { if (pipe->brx) {
const struct v4l2_rect *compose; const struct v4l2_rect *compose;
...@@ -133,18 +185,18 @@ static void rpf_configure_stream(struct vsp1_entity *entity, ...@@ -133,18 +185,18 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
* a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control
* otherwise. * otherwise.
* *
* The Gen3 RPF has extended alpha capability and can both multiply the * The Gen3+ RPF has extended alpha capability and can both multiply the
* alpha channel by a fixed global alpha value, and multiply the pixel * alpha channel by a fixed global alpha value, and multiply the pixel
* components to convert the input to premultiplied alpha. * components to convert the input to premultiplied alpha.
* *
* As alpha premultiplication is available in the BRx for both Gen2 and * As alpha premultiplication is available in the BRx for both Gen2 and
* Gen3 we handle it there and use the Gen3 alpha multiplier for global * Gen3+ we handle it there and use the Gen3 alpha multiplier for global
* alpha multiplication only. This however prevents conversion to * alpha multiplication only. This however prevents conversion to
* premultiplied alpha if no BRx is present in the pipeline. If that use * premultiplied alpha if no BRx is present in the pipeline. If that use
* case turns out to be useful we will revisit the implementation (for * case turns out to be useful we will revisit the implementation (for
* Gen3 only). * Gen3 only).
* *
* We enable alpha multiplication on Gen3 using the fixed alpha value * We enable alpha multiplication on Gen3+ using the fixed alpha value
* set through the V4L2_CID_ALPHA_COMPONENT control when the input * set through the V4L2_CID_ALPHA_COMPONENT control when the input
* contains an alpha channel. On Gen2 the global alpha is ignored in * contains an alpha channel. On Gen2 the global alpha is ignored in
* that case. * that case.
...@@ -155,7 +207,7 @@ static void rpf_configure_stream(struct vsp1_entity *entity, ...@@ -155,7 +207,7 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
(fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
: VI6_RPF_ALPH_SEL_ASEL_FIXED)); : VI6_RPF_ALPH_SEL_ASEL_FIXED));
if (entity->vsp1->info->gen == 3) { if (entity->vsp1->info->gen >= 3) {
u32 mult; u32 mult;
if (fmtinfo->alpha) { if (fmtinfo->alpha) {
...@@ -301,10 +353,10 @@ static void rpf_configure_partition(struct vsp1_entity *entity, ...@@ -301,10 +353,10 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
} }
/* /*
* On Gen3 hardware the SPUVS bit has no effect on 3-planar * On Gen3+ hardware the SPUVS bit has no effect on 3-planar
* formats. Swap the U and V planes manually in that case. * formats. Swap the U and V planes manually in that case.
*/ */
if (vsp1->info->gen == 3 && format->num_planes == 3 && if (vsp1->info->gen >= 3 && format->num_planes == 3 &&
fmtinfo->swap_uv) fmtinfo->swap_uv)
swap(mem.addr[1], mem.addr[2]); swap(mem.addr[1], mem.addr[2]);
......
...@@ -267,10 +267,10 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) ...@@ -267,10 +267,10 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
div_size = format->width; div_size = format->width;
/* /*
* Only Gen3 hardware requires image partitioning, Gen2 will operate * Only Gen3+ hardware requires image partitioning, Gen2 will operate
* with a single partition that covers the whole output. * with a single partition that covers the whole output.
*/ */
if (vsp1->info->gen == 3) { if (vsp1->info->gen >= 3) {
list_for_each_entry(entity, &pipe->entities, list_pipe) { list_for_each_entry(entity, &pipe->entities, list_pipe) {
unsigned int entity_max; unsigned int entity_max;
......
...@@ -512,10 +512,10 @@ static void wpf_configure_partition(struct vsp1_entity *entity, ...@@ -512,10 +512,10 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
} }
/* /*
* On Gen3 hardware the SPUVS bit has no effect on 3-planar * On Gen3+ hardware the SPUVS bit has no effect on 3-planar
* formats. Swap the U and V planes manually in that case. * formats. Swap the U and V planes manually in that case.
*/ */
if (vsp1->info->gen == 3 && format->num_planes == 3 && if (vsp1->info->gen >= 3 && format->num_planes == 3 &&
fmtinfo->swap_uv) fmtinfo->swap_uv)
swap(mem.addr[1], mem.addr[2]); swap(mem.addr[1], mem.addr[2]);
......
...@@ -1298,6 +1298,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) ...@@ -1298,6 +1298,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_BGRX32: descr = "32-bit XBGR 8-8-8-8"; break; case V4L2_PIX_FMT_BGRX32: descr = "32-bit XBGR 8-8-8-8"; break;
case V4L2_PIX_FMT_RGBA32: descr = "32-bit RGBA 8-8-8-8"; break; case V4L2_PIX_FMT_RGBA32: descr = "32-bit RGBA 8-8-8-8"; break;
case V4L2_PIX_FMT_RGBX32: descr = "32-bit RGBX 8-8-8-8"; break; case V4L2_PIX_FMT_RGBX32: descr = "32-bit RGBX 8-8-8-8"; break;
case V4L2_PIX_FMT_RGBX1010102: descr = "32-bit RGBX 10-10-10-2"; break;
case V4L2_PIX_FMT_RGBA1010102: descr = "32-bit RGBA 10-10-10-2"; break;
case V4L2_PIX_FMT_ARGB2101010: descr = "32-bit ARGB 2-10-10-10"; break;
case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break; case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break;
case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break; case V4L2_PIX_FMT_Y4: descr = "4-bit Greyscale"; break;
case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break; case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break;
...@@ -1442,6 +1445,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) ...@@ -1442,6 +1445,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break;
case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break; case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break;
case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break; case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break;
case V4L2_PIX_FMT_Y210: descr = "10-bit YUYV Packed"; break;
case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break;
case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break;
default: default:
/* Compressed formats */ /* Compressed formats */
......
...@@ -576,6 +576,9 @@ struct v4l2_pix_format { ...@@ -576,6 +576,9 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_RGBX32 v4l2_fourcc('X', 'B', '2', '4') /* 32 RGBX-8-8-8-8 */ #define V4L2_PIX_FMT_RGBX32 v4l2_fourcc('X', 'B', '2', '4') /* 32 RGBX-8-8-8-8 */
#define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4') /* 32 ARGB-8-8-8-8 */ #define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4') /* 32 ARGB-8-8-8-8 */
#define V4L2_PIX_FMT_XRGB32 v4l2_fourcc('B', 'X', '2', '4') /* 32 XRGB-8-8-8-8 */ #define V4L2_PIX_FMT_XRGB32 v4l2_fourcc('B', 'X', '2', '4') /* 32 XRGB-8-8-8-8 */
#define V4L2_PIX_FMT_RGBX1010102 v4l2_fourcc('R', 'X', '3', '0') /* 32 RGBX-10-10-10-2 */
#define V4L2_PIX_FMT_RGBA1010102 v4l2_fourcc('R', 'A', '3', '0') /* 32 RGBA-10-10-10-2 */
#define V4L2_PIX_FMT_ARGB2101010 v4l2_fourcc('A', 'R', '3', '0') /* 32 ARGB-2-10-10-10 */
/* Grey formats */ /* Grey formats */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */
...@@ -618,6 +621,14 @@ struct v4l2_pix_format { ...@@ -618,6 +621,14 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_YUVX32 v4l2_fourcc('Y', 'U', 'V', 'X') /* 32 YUVX-8-8-8-8 */ #define V4L2_PIX_FMT_YUVX32 v4l2_fourcc('Y', 'U', 'V', 'X') /* 32 YUVX-8-8-8-8 */
#define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */
/*
* YCbCr packed format. For each Y2xx format, xx bits of valid data occupy the MSBs
* of the 16 bit components, and 16-xx bits of zero padding occupy the LSBs.
*/
#define V4L2_PIX_FMT_Y210 v4l2_fourcc('Y', '2', '1', '0') /* 32 YUYV 4:2:2 */
#define V4L2_PIX_FMT_Y212 v4l2_fourcc('Y', '2', '1', '2') /* 32 YUYV 4:2:2 */
#define V4L2_PIX_FMT_Y216 v4l2_fourcc('Y', '2', '1', '6') /* 32 YUYV 4:2:2 */
/* two planes -- one Y, one Cr + Cb interleaved */ /* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment