This is v9 of the VOP2 series. Biggest change this time is that I marked the hclk_vo as critical instead of enabling it in the HDMI driver. Also a little bugfix is included for a bug in setting up the layer mixer, reported by Andy Yan.
Note that this series depends on these patches:
clk: rk3568: Add CLK_SET_RATE_PARENT to the HDMI reference clock clk: rk3568: drop CLK_SET_RATE_PARENT from dclk_vop* clk: rockchip: rk3568: Add more PLL rates
These are not included in this series as they are already applied by Heiko. They haven't hit mainline yet, you can pick them from v4 of this series.
Sascha
Changes since v8: - make hclk_vo a critical clock instead of enabling it in the hdmi driver - Fix vop2_setup_layer_mixer(), reported by Andy Yan - Limit planes possible_crtcs to actually existing crtcs - simplify vop2_create_crtc() a bit
Changes since v7: - rename hclk to niu
Changes since v6: - Move of_graph parsing out of runtime code to initialization
Changes since v5: - Add new patch to fix dw-hdmi of_graph binding - Drop "drm/encoder: Add of_graph port to struct drm_encoder" and solve issue internally in the driver - make checkpatch cleaner
Changes since v4: - Reorder patches in a way that binding/dts/driver patches are closer together - Drop clk patches already applied by Heiko
Changes since v3: - added changelog to each patch - Add 4k support to hdmi driver - rebase on v5.17-rc1
Changes since v2: - Add pin names to HDMI supply pin description - Add hclk support to HDMI driver - Dual license rockchip-vop2 binding, update binding - Add HDMI connector to board dts files - drop unnecessary gamma_lut registers from vop2 - Update dclk_vop[012] clock handling, no longer hacks needed - Complete regmap conversion
Changes since v1: - drop all unnecessary waiting for frames within atomic modeset and plane update - Cluster subwin support removed - gamma support removed - unnecessary irq_lock removed - interrupt handling simplified - simplified zpos handling - drop is_alpha_support(), use fb->format->has_alpha instead - use devm_regulator_get() rather than devm_regulator_get_optional() for hdmi regulators - Use fixed number of planes per video port - Drop homegrown regmap code from vop2 driver (not complete yet) - Add separate include file for vop2 driver to not pollute the vop include
Andy Yan (1): drm: rockchip: Add VOP2 driver
Benjamin Gaignard (1): dt-bindings: display: rockchip: dw-hdmi: Add compatible for rk3568 HDMI
Douglas Anderson (2): drm/rockchip: dw_hdmi: Use auto-generated tables drm/rockchip: dw_hdmi: Set cur_ctr to 0 always
Michael Riesch (1): arm64: dts: rockchip: enable vop2 and hdmi tx on quartz64a
Nickey Yang (1): drm/rockchip: dw_hdmi: add default 594Mhz clk for 4K@60hz
Sascha Hauer (17): clk: rk3568: Mark hclk_vo as critical drm/rockchip: Embed drm_encoder into rockchip_decoder drm/rockchip: Add crtc_endpoint_id to rockchip_encoder drm/rockchip: dw_hdmi: rename vpll clock to reference clock dt-bindings: display: rockchip: dw-hdmi: use "ref" as clock name arm64: dts: rockchip: rk3399: rename HDMI ref clock to 'ref' drm/rockchip: dw_hdmi: add rk3568 support drm/rockchip: dw_hdmi: add regulator support dt-bindings: display: rockchip: dw-hdmi: Add regulator support drm/rockchip: dw_hdmi: drop mode_valid hook dt-bindings: display: rockchip: dw-hdmi: Make unwedge pinctrl optional arm64: dts: rockchip: rk356x: Add VOP2 nodes arm64: dts: rockchip: rk356x: Add HDMI nodes arm64: dts: rockchip: rk3568-evb: Enable VOP2 and hdmi drm/rockchip: Make VOP driver optional dt-bindings: display: rockchip: Add binding for VOP2 dt-bindings: display: rockchip: dw-hdmi: fix ports description
.../display/rockchip/rockchip,dw-hdmi.yaml | 46 +- .../display/rockchip/rockchip-vop2.yaml | 140 + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +- .../boot/dts/rockchip/rk3566-quartz64-a.dts | 47 + arch/arm64/boot/dts/rockchip/rk3566.dtsi | 4 + .../boot/dts/rockchip/rk3568-evb1-v10.dts | 47 + arch/arm64/boot/dts/rockchip/rk3568.dtsi | 4 + arch/arm64/boot/dts/rockchip/rk356x.dtsi | 83 + drivers/clk/rockchip/clk-rk3568.c | 1 + drivers/gpu/drm/rockchip/Kconfig | 14 + drivers/gpu/drm/rockchip/Makefile | 4 +- .../gpu/drm/rockchip/analogix_dp-rockchip.c | 32 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 18 +- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 +- .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 17 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 276 +- drivers/gpu/drm/rockchip/inno_hdmi.c | 32 +- drivers/gpu/drm/rockchip/rk3066_hdmi.c | 34 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 36 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 20 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 2 + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 15 + drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2688 +++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 477 +++ drivers/gpu/drm/rockchip/rockchip_lvds.c | 26 +- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 281 ++ include/dt-bindings/soc/rockchip,vop2.h | 14 + 27 files changed, 4167 insertions(+), 195 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c create mode 100644 include/dt-bindings/soc/rockchip,vop2.h
Whenever pclk_vo is enabled hclk_vo must be enabled as well. This is described in the Reference Manual as:
| 2.8.6 NIU Clock gating reliance | | A part of niu clocks have a dependence on another niu clock in order to | sharing the internal bus. When these clocks are in use, another niu | clock must be opened, and cannot be gated. These clocks and the special | clock on which they are relied are as following: | | Clocks which have dependency The clock which can not be gated | ----------------------------------------------------------------- | ... | pclk_vo_niu, hclk_vo_s_niu hclk_vo_niu | ...
The clock framework doesn't offer a way to enable clock B whenever clock A is enabled, at least not when B is not an ancestor of A. Workaround this by marking hclk_vo as critical so it is never disabled. This is suboptimal in terms of power consumption, but a stop gap solution until the clock framework has a way to deal with this.
We have this clock tree:
| aclk_vo 2 2 0 300000000 0 0 50000 Y | aclk_hdcp 0 0 0 300000000 0 0 50000 N | pclk_vo 2 3 0 75000000 0 0 50000 Y | pclk_edp_ctrl 0 0 0 75000000 0 0 50000 N | pclk_dsitx_1 0 0 0 75000000 0 0 50000 N | pclk_dsitx_0 1 2 0 75000000 0 0 50000 Y | pclk_hdmi_host 1 2 0 75000000 0 0 50000 Y | pclk_hdcp 0 0 0 75000000 0 0 50000 N | hclk_vo 2 5 0 150000000 0 0 50000 Y | hclk_hdcp 0 0 0 150000000 0 0 50000 N | hclk_vop 0 2 0 150000000 0 0 50000 N
Without this patch the edp, dsitx, hdmi and hdcp driver would enable their clocks which then enables pclk_vo, but hclk_vo stays disabled and register accesses just hang. hclk_vo is enabled by the VOP2 driver, so reproducibility of this issue depends on the probe order.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v8: - new patch
drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 63dfbeeeb06d9..62694d95173ab 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -1591,6 +1591,7 @@ static const char *const rk3568_cru_critical_clocks[] __initconst = { "hclk_php", "pclk_php", "hclk_usb", + "hclk_vo", };
static const char *const rk3568_pmucru_critical_clocks[] __initconst = {
On 3/28/22 18:10, Sascha Hauer wrote:
Whenever pclk_vo is enabled hclk_vo must be enabled as well. This is described in the Reference Manual as:
| 2.8.6 NIU Clock gating reliance | | A part of niu clocks have a dependence on another niu clock in order to | sharing the internal bus. When these clocks are in use, another niu | clock must be opened, and cannot be gated. These clocks and the special | clock on which they are relied are as following: | | Clocks which have dependency The clock which can not be gated | ----------------------------------------------------------------- | ... | pclk_vo_niu, hclk_vo_s_niu hclk_vo_niu | ...
The clock framework doesn't offer a way to enable clock B whenever clock A is enabled, at least not when B is not an ancestor of A. Workaround this by marking hclk_vo as critical so it is never disabled. This is suboptimal in terms of power consumption, but a stop gap solution until the clock framework has a way to deal with this.
We have this clock tree:
| aclk_vo 2 2 0 300000000 0 0 50000 Y | aclk_hdcp 0 0 0 300000000 0 0 50000 N | pclk_vo 2 3 0 75000000 0 0 50000 Y | pclk_edp_ctrl 0 0 0 75000000 0 0 50000 N | pclk_dsitx_1 0 0 0 75000000 0 0 50000 N | pclk_dsitx_0 1 2 0 75000000 0 0 50000 Y | pclk_hdmi_host 1 2 0 75000000 0 0 50000 Y | pclk_hdcp 0 0 0 75000000 0 0 50000 N | hclk_vo 2 5 0 150000000 0 0 50000 Y | hclk_hdcp 0 0 0 150000000 0 0 50000 N | hclk_vop 0 2 0 150000000 0 0 50000 N
Without this patch the edp, dsitx, hdmi and hdcp driver would enable their clocks which then enables pclk_vo, but hclk_vo stays disabled and register accesses just hang. hclk_vo is enabled by the VOP2 driver, so reproducibility of this issue depends on the probe order.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
Notes: Changes since v8: - new patch
drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 63dfbeeeb06d9..62694d95173ab 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -1591,6 +1591,7 @@ static const char *const rk3568_cru_critical_clocks[] __initconst = { "hclk_php", "pclk_php", "hclk_usb",
- "hclk_vo",
};
static const char *const rk3568_pmucru_critical_clocks[] __initconst = {
Nice! That's much better than the DT hacks, IMO, thank you.
Reviewed-by: Dmitry Osipenko dmitry.osipenko@collabora.com
On 2022-03-28 16:10, Sascha Hauer wrote:
Whenever pclk_vo is enabled hclk_vo must be enabled as well. This is described in the Reference Manual as:
| 2.8.6 NIU Clock gating reliance | | A part of niu clocks have a dependence on another niu clock in order to | sharing the internal bus. When these clocks are in use, another niu | clock must be opened, and cannot be gated. These clocks and the special | clock on which they are relied are as following: | | Clocks which have dependency The clock which can not be gated | ----------------------------------------------------------------- | ... | pclk_vo_niu, hclk_vo_s_niu hclk_vo_niu | ...
The clock framework doesn't offer a way to enable clock B whenever clock A is enabled, at least not when B is not an ancestor of A. Workaround this by marking hclk_vo as critical so it is never disabled. This is suboptimal in terms of power consumption, but a stop gap solution until the clock framework has a way to deal with this.
We have this clock tree:
| aclk_vo 2 2 0 300000000 0 0 50000 Y | aclk_hdcp 0 0 0 300000000 0 0 50000 N | pclk_vo 2 3 0 75000000 0 0 50000 Y | pclk_edp_ctrl 0 0 0 75000000 0 0 50000 N | pclk_dsitx_1 0 0 0 75000000 0 0 50000 N | pclk_dsitx_0 1 2 0 75000000 0 0 50000 Y | pclk_hdmi_host 1 2 0 75000000 0 0 50000 Y | pclk_hdcp 0 0 0 75000000 0 0 50000 N | hclk_vo 2 5 0 150000000 0 0 50000 Y | hclk_hdcp 0 0 0 150000000 0 0 50000 N | hclk_vop 0 2 0 150000000 0 0 50000 N
Without this patch the edp, dsitx, hdmi and hdcp driver would enable their clocks which then enables pclk_vo, but hclk_vo stays disabled and register accesses just hang. hclk_vo is enabled by the VOP2 driver, so reproducibility of this issue depends on the probe order.
FWIW,
Reviewed-by: Robin Murphy robin.murphy@arm.com
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
Notes: Changes since v8: - new patch
drivers/clk/rockchip/clk-rk3568.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index 63dfbeeeb06d9..62694d95173ab 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -1591,6 +1591,7 @@ static const char *const rk3568_cru_critical_clocks[] __initconst = { "hclk_php", "pclk_php", "hclk_usb",
"hclk_vo", };
static const char *const rk3568_pmucru_critical_clocks[] __initconst = {
The VOP2 driver needs rockchip specific information for a drm_encoder.
This patch creates a struct rockchip_encoder with a struct drm_encoder embedded in it. This is used throughout the rockchip driver instead of struct drm_encoder directly.
The information the VOP2 drivers needs is the of_graph endpoint node of the encoder. To ease bisectability this is added here.
While at it convert the different encoder-to-driverdata macros to static inline functions in order to gain type safety and readability.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v5: - new patch
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 32 +++++++++++------ drivers/gpu/drm/rockchip/cdn-dp-core.c | 18 ++++++---- drivers/gpu/drm/rockchip/cdn-dp-core.h | 2 +- .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 17 ++++++---- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 11 ++++-- drivers/gpu/drm/rockchip/inno_hdmi.c | 32 +++++++++++------ drivers/gpu/drm/rockchip/rk3066_hdmi.c | 34 ++++++++++++------- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 10 ++++++ drivers/gpu/drm/rockchip/rockchip_lvds.c | 26 ++++++++------ 9 files changed, 122 insertions(+), 60 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index c82901d9a9ccd..28fcc8efa33db 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -40,8 +40,6 @@
#define PSR_WAIT_LINE_FLAG_TIMEOUT_MS 100
-#define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm) - /** * struct rockchip_dp_chip_data - splite the grf setting of kind of chips * @lcdsel_grf_reg: grf register offset of lcdc select @@ -59,7 +57,7 @@ struct rockchip_dp_chip_data { struct rockchip_dp_device { struct drm_device *drm_dev; struct device *dev; - struct drm_encoder encoder; + struct rockchip_encoder encoder; struct drm_display_mode mode;
struct clk *pclk; @@ -73,6 +71,18 @@ struct rockchip_dp_device { struct analogix_dp_plat_data plat_data; };
+static struct rockchip_dp_device *encoder_to_dp(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct rockchip_dp_device, encoder); +} + +static struct rockchip_dp_device *pdata_encoder_to_dp(struct analogix_dp_plat_data *plat_data) +{ + return container_of(plat_data, struct rockchip_dp_device, plat_data); +} + static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) { reset_control_assert(dp->rst); @@ -84,7 +94,7 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data) { - struct rockchip_dp_device *dp = to_dp(plat_data); + struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); int ret;
ret = clk_prepare_enable(dp->pclk); @@ -105,7 +115,7 @@ static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) { - struct rockchip_dp_device *dp = to_dp(plat_data); + struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
clk_disable_unprepare(dp->pclk);
@@ -166,7 +176,7 @@ struct drm_crtc *rockchip_dp_drm_get_new_crtc(struct drm_encoder *encoder, static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct rockchip_dp_device *dp = to_dp(encoder); + struct rockchip_dp_device *dp = encoder_to_dp(encoder); struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; int ret; @@ -208,7 +218,7 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, static void rockchip_dp_drm_encoder_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct rockchip_dp_device *dp = to_dp(encoder); + struct rockchip_dp_device *dp = encoder_to_dp(encoder); struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; int ret; @@ -297,7 +307,7 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp)
static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp) { - struct drm_encoder *encoder = &dp->encoder; + struct drm_encoder *encoder = &dp->encoder.encoder; struct drm_device *drm_dev = dp->drm_dev; struct device *dev = dp->dev; int ret; @@ -333,7 +343,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, return ret; }
- dp->plat_data.encoder = &dp->encoder; + dp->plat_data.encoder = &dp->encoder.encoder;
ret = analogix_dp_bind(dp->adp, drm_dev); if (ret) @@ -341,7 +351,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
return 0; err_cleanup_encoder: - dp->encoder.funcs->destroy(&dp->encoder); + dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); return ret; }
@@ -351,7 +361,7 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master, struct rockchip_dp_device *dp = dev_get_drvdata(dev);
analogix_dp_unbind(dp->adp); - dp->encoder.funcs->destroy(&dp->encoder); + dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); }
static const struct component_ops rockchip_dp_component_ops = { diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index d3e6c93739bf6..8584e19792be2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -26,11 +26,17 @@ #include "cdn-dp-reg.h" #include "rockchip_drm_vop.h"
-#define connector_to_dp(c) \ - container_of(c, struct cdn_dp_device, connector) +static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector) +{ + return container_of(connector, struct cdn_dp_device, connector); +}
-#define encoder_to_dp(c) \ - container_of(c, struct cdn_dp_device, encoder) +static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct cdn_dp_device, encoder); +}
#define GRF_SOC_CON9 0x6224 #define DP_SEL_VOP_LIT BIT(12) @@ -1050,7 +1056,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
- encoder = &dp->encoder; + encoder = &dp->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node); @@ -1115,7 +1121,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) { struct cdn_dp_device *dp = dev_get_drvdata(dev); - struct drm_encoder *encoder = &dp->encoder; + struct drm_encoder *encoder = &dp->encoder.encoder; struct drm_connector *connector = &dp->connector;
cancel_work_sync(&dp->event_work); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 6d0c5032ef3ad..f7d4cecb46ba4 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -66,7 +66,7 @@ struct cdn_dp_device { struct device *dev; struct drm_device *drm_dev; struct drm_connector connector; - struct drm_encoder encoder; + struct rockchip_encoder encoder; struct drm_display_mode mode; struct platform_device *audio_pdev; struct work_struct event_work; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 4ed7a68681978..110e83aad9bb4 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -181,8 +181,6 @@
#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
-#define to_dsi(nm) container_of(nm, struct dw_mipi_dsi_rockchip, nm) - enum { DW_DSI_USAGE_IDLE, DW_DSI_USAGE_DSI, @@ -236,7 +234,7 @@ struct rockchip_dw_dsi_chip_data {
struct dw_mipi_dsi_rockchip { struct device *dev; - struct drm_encoder encoder; + struct rockchip_encoder encoder; void __iomem *base;
struct regmap *grf_regmap; @@ -271,6 +269,13 @@ struct dw_mipi_dsi_rockchip { bool dsi_bound; };
+static struct dw_mipi_dsi_rockchip *to_dsi(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct dw_mipi_dsi_rockchip, encoder); +} + struct dphy_pll_parameter_map { unsigned int max_mbps; u8 hsfreqrange; @@ -770,7 +775,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) int ret, mux;
mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, - &dsi->encoder); + &dsi->encoder.encoder); if (mux < 0) return;
@@ -801,7 +806,7 @@ dw_mipi_dsi_encoder_helper_funcs = { static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi, struct drm_device *drm_dev) { - struct drm_encoder *encoder = &dsi->encoder; + struct drm_encoder *encoder = &dsi->encoder.encoder; int ret;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, @@ -959,7 +964,7 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev, goto out_pll_clk; }
- ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder); + ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder.encoder); if (ret) { DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret); goto out_pll_clk; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 8677c82716784..06c9ddef6f362 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -67,7 +67,7 @@ struct rockchip_hdmi_chip_data { struct rockchip_hdmi { struct device *dev; struct regmap *regmap; - struct drm_encoder encoder; + struct rockchip_encoder encoder; const struct rockchip_hdmi_chip_data *chip_data; struct clk *vpll_clk; struct clk *grf_clk; @@ -75,7 +75,12 @@ struct rockchip_hdmi { struct phy *phy; };
-#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) +static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct rockchip_hdmi, encoder); +}
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { { @@ -511,7 +516,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, hdmi->dev = &pdev->dev; hdmi->chip_data = plat_data->phy_data; plat_data->phy_data = hdmi; - encoder = &hdmi->encoder; + encoder = &hdmi->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); /* diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 046e8ec2a71c5..0a4f72021d6af 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -26,8 +26,6 @@
#include "inno_hdmi.h"
-#define to_inno_hdmi(x) container_of(x, struct inno_hdmi, x) - struct hdmi_data_info { int vic; bool sink_is_hdmi; @@ -56,7 +54,7 @@ struct inno_hdmi { void __iomem *regs;
struct drm_connector connector; - struct drm_encoder encoder; + struct rockchip_encoder encoder;
struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; @@ -67,6 +65,18 @@ struct inno_hdmi { struct drm_display_mode previous_mode; };
+static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct inno_hdmi, encoder); +} + +static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) +{ + return container_of(connector, struct inno_hdmi, connector); +} + enum { CSC_ITU601_16_235_TO_RGB_0_255_8BIT, CSC_ITU601_0_255_TO_RGB_0_255_8BIT, @@ -483,7 +493,7 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - struct inno_hdmi *hdmi = to_inno_hdmi(encoder); + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
inno_hdmi_setup(hdmi, adj_mode);
@@ -493,14 +503,14 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) { - struct inno_hdmi *hdmi = to_inno_hdmi(encoder); + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
inno_hdmi_set_pwr_mode(hdmi, NORMAL); }
static void inno_hdmi_encoder_disable(struct drm_encoder *encoder) { - struct inno_hdmi *hdmi = to_inno_hdmi(encoder); + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder);
inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); } @@ -536,7 +546,7 @@ static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { static enum drm_connector_status inno_hdmi_connector_detect(struct drm_connector *connector, bool force) { - struct inno_hdmi *hdmi = to_inno_hdmi(connector); + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector);
return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ? connector_status_connected : connector_status_disconnected; @@ -544,7 +554,7 @@ inno_hdmi_connector_detect(struct drm_connector *connector, bool force)
static int inno_hdmi_connector_get_modes(struct drm_connector *connector) { - struct inno_hdmi *hdmi = to_inno_hdmi(connector); + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); struct edid *edid; int ret = 0;
@@ -599,7 +609,7 @@ static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = {
static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) { - struct drm_encoder *encoder = &hdmi->encoder; + struct drm_encoder *encoder = &hdmi->encoder.encoder; struct device *dev = hdmi->dev;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); @@ -879,7 +889,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, return 0; err_cleanup_hdmi: hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder.funcs->destroy(&hdmi->encoder); + hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); err_put_adapter: i2c_put_adapter(hdmi->ddc); err_disable_clk: @@ -893,7 +903,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, struct inno_hdmi *hdmi = dev_get_drvdata(dev);
hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder.funcs->destroy(&hdmi->encoder); + hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
i2c_put_adapter(hdmi->ddc); clk_disable_unprepare(hdmi->pclk); diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 1c546c3a89984..319240c33dcc0 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -47,7 +47,7 @@ struct rk3066_hdmi { void __iomem *regs;
struct drm_connector connector; - struct drm_encoder encoder; + struct rockchip_encoder encoder;
struct rk3066_hdmi_i2c *i2c; struct i2c_adapter *ddc; @@ -58,7 +58,17 @@ struct rk3066_hdmi { struct drm_display_mode previous_mode; };
-#define to_rk3066_hdmi(x) container_of(x, struct rk3066_hdmi, x) +static struct rk3066_hdmi *encoder_to_rk3066_hdmi(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct rk3066_hdmi, encoder); +} + +static struct rk3066_hdmi *connector_to_rk3066_hdmi(struct drm_connector *connector) +{ + return container_of(connector, struct rk3066_hdmi, connector); +}
static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset) { @@ -380,7 +390,7 @@ rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder); + struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
/* Store the display mode for plugin/DPMS poweron events. */ memcpy(&hdmi->previous_mode, adj_mode, sizeof(hdmi->previous_mode)); @@ -388,7 +398,7 @@ rk3066_hdmi_encoder_mode_set(struct drm_encoder *encoder,
static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder) { - struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder); + struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); int mux, val;
mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); @@ -407,7 +417,7 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder)
static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder) { - struct rk3066_hdmi *hdmi = to_rk3066_hdmi(encoder); + struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder);
DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder disable\n");
@@ -455,7 +465,7 @@ struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = { static enum drm_connector_status rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force) { - struct rk3066_hdmi *hdmi = to_rk3066_hdmi(connector); + struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
return (hdmi_readb(hdmi, HDMI_HPG_MENS_STA) & HDMI_HPG_IN_STATUS_HIGH) ? connector_status_connected : connector_status_disconnected; @@ -463,7 +473,7 @@ rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force)
static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector) { - struct rk3066_hdmi *hdmi = to_rk3066_hdmi(connector); + struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector); struct edid *edid; int ret = 0;
@@ -496,9 +506,9 @@ rk3066_hdmi_connector_mode_valid(struct drm_connector *connector, static struct drm_encoder * rk3066_hdmi_connector_best_encoder(struct drm_connector *connector) { - struct rk3066_hdmi *hdmi = to_rk3066_hdmi(connector); + struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector);
- return &hdmi->encoder; + return &hdmi->encoder.encoder; }
static int @@ -538,7 +548,7 @@ struct drm_connector_helper_funcs rk3066_hdmi_connector_helper_funcs = { static int rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi) { - struct drm_encoder *encoder = &hdmi->encoder; + struct drm_encoder *encoder = &hdmi->encoder.encoder; struct device *dev = hdmi->dev;
encoder->possible_crtcs = @@ -816,7 +826,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master,
err_cleanup_hdmi: hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder.funcs->destroy(&hdmi->encoder); + hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); err_disable_i2c: i2c_put_adapter(hdmi->ddc); err_disable_hclk: @@ -831,7 +841,7 @@ static void rk3066_hdmi_unbind(struct device *dev, struct device *master, struct rk3066_hdmi *hdmi = dev_get_drvdata(dev);
hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder.funcs->destroy(&hdmi->encoder); + hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder);
i2c_put_adapter(hdmi->ddc); clk_disable_unprepare(hdmi->hclk); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 143a48330f849..686f687a76a37 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -48,6 +48,10 @@ struct rockchip_drm_private { struct drm_mm mm; };
+struct rockchip_encoder { + struct drm_encoder encoder; +}; + int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, struct device *dev); void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, @@ -63,4 +67,10 @@ extern struct platform_driver rockchip_dp_driver; extern struct platform_driver rockchip_lvds_driver; extern struct platform_driver vop_platform_driver; extern struct platform_driver rk3066_hdmi_driver; + +static inline struct rockchip_encoder *to_rockchip_encoder(struct drm_encoder *encoder) +{ + return container_of(encoder, struct rockchip_encoder, encoder); +} + #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 0b972418067e8..25d8c24ef7729 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -36,12 +36,6 @@
struct rockchip_lvds;
-#define connector_to_lvds(c) \ - container_of(c, struct rockchip_lvds, connector) - -#define encoder_to_lvds(c) \ - container_of(c, struct rockchip_lvds, encoder) - /** * struct rockchip_lvds_soc_data - rockchip lvds Soc private data * @probe: LVDS platform probe function @@ -65,10 +59,22 @@ struct rockchip_lvds { struct drm_panel *panel; struct drm_bridge *bridge; struct drm_connector connector; - struct drm_encoder encoder; + struct rockchip_encoder encoder; struct dev_pin_info *pins; };
+static inline struct rockchip_lvds *connector_to_lvds(struct drm_connector *connector) +{ + return container_of(connector, struct rockchip_lvds, connector); +} + +static inline struct rockchip_lvds *encoder_to_lvds(struct drm_encoder *encoder) +{ + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + return container_of(rkencoder, struct rockchip_lvds, encoder); +} + static inline void rk3288_writel(struct rockchip_lvds *lvds, u32 offset, u32 val) { @@ -599,7 +605,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, goto err_put_remote; }
- encoder = &lvds->encoder; + encoder = &lvds->encoder.encoder; encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
@@ -674,10 +680,10 @@ static void rockchip_lvds_unbind(struct device *dev, struct device *master, const struct drm_encoder_helper_funcs *encoder_funcs;
encoder_funcs = lvds->soc_data->helper_funcs; - encoder_funcs->disable(&lvds->encoder); + encoder_funcs->disable(&lvds->encoder.encoder); pm_runtime_disable(dev); drm_connector_cleanup(&lvds->connector); - drm_encoder_cleanup(&lvds->encoder); + drm_encoder_cleanup(&lvds->encoder.encoder); }
static const struct component_ops rockchip_lvds_component_ops = {
The VOP2 has an interface mux which decides to which encoder(s) a CRTC is routed to. The encoders and CRTCs are connected via of_graphs in the device tree. When given an encoder the VOP2 driver needs to know to which internal register setting this encoder matches. For this the VOP2 binding offers different endpoints, one for each possible encoder. The endpoint ids of these endpoints are used as a key from an encoders device tree description to the internal register setting.
This patch adds the key aka endpoint id to struct rockchip_encoder plus a function to read the endpoint id starting from the encoders device node.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v6: - new patch
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 33 +++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 ++- 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index ac190e2b1f7aa..214214190fef1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -236,6 +236,39 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = { static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; static int num_rockchip_sub_drivers;
+/* + * Get the endpoint id of the remote endpoint of the given encoder. This + * information is used by the VOP2 driver to identify the encoder. + * + * @rkencoder: The encoder to get the remote endpoint id from + * @np: The encoder device node + * @port: The number of the port leading to the VOP2 + * @reg: The endpoint number leading to the VOP2 + */ +int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rkencoder, + struct device_node *np, int port, int reg) +{ + struct of_endpoint ep; + struct device_node *en, *ren; + int ret; + + en = of_graph_get_endpoint_by_regs(np, port, reg); + if (!en) + return -ENOENT; + + ren = of_graph_get_remote_endpoint(en); + if (!ren) + return -ENOENT; + + ret = of_graph_parse_endpoint(ren, &ep); + if (ret) + return ret; + + rkencoder->crtc_endpoint_id = ep.id; + + return 0; +} + /* * Check if a vop endpoint is leading to a rockchip subdriver or bridge. * Should be called from the component bind stage of the drivers diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 686f687a76a37..1f66a447acada 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -49,6 +49,7 @@ struct rockchip_drm_private { };
struct rockchip_encoder { + int crtc_endpoint_id; struct drm_encoder encoder; };
@@ -57,7 +58,8 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev, void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout); - +int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rencoder, + struct device_node *np, int port, int reg); int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); extern struct platform_driver cdn_dp_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
"vpll" is a misnomer. A clock input to a device should be named after the usage in the device, not after the clock that drives it. On the rk3568 the same clock is driven by the HPLL. To fix that, this patch renames the vpll clock to ref clock. The clock name "vpll" is left for compatibility to old device trees.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Reviewed-by: Dmitry Osipenko dmitry.osipenko@collabora.com ---
Notes: Changes since v6: - Simplify by using devm_clk_get_optional() instead of devm_clk_get()
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 06c9ddef6f362..912181429880a 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -69,7 +69,7 @@ struct rockchip_hdmi { struct regmap *regmap; struct rockchip_encoder encoder; const struct rockchip_hdmi_chip_data *chip_data; - struct clk *vpll_clk; + struct clk *ref_clk; struct clk *grf_clk; struct dw_hdmi *hdmi; struct phy *phy; @@ -201,14 +201,15 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return PTR_ERR(hdmi->regmap); }
- hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll"); - if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) { - hdmi->vpll_clk = NULL; - } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) { + hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref"); + if (!hdmi->ref_clk) + hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll"); + + if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) { return -EPROBE_DEFER; - } else if (IS_ERR(hdmi->vpll_clk)) { - DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n"); - return PTR_ERR(hdmi->vpll_clk); + } else if (IS_ERR(hdmi->ref_clk)) { + DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n"); + return PTR_ERR(hdmi->ref_clk); }
hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf"); @@ -262,7 +263,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, { struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000); + clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000); }
static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder) @@ -542,9 +543,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, return ret; }
- ret = clk_prepare_enable(hdmi->vpll_clk); + ret = clk_prepare_enable(hdmi->ref_clk); if (ret) { - DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n", + DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n", ret); return ret; } @@ -563,7 +564,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, if (IS_ERR(hdmi->hdmi)) { ret = PTR_ERR(hdmi->hdmi); drm_encoder_cleanup(encoder); - clk_disable_unprepare(hdmi->vpll_clk); + clk_disable_unprepare(hdmi->ref_clk); }
return ret; @@ -575,7 +576,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
dw_hdmi_unbind(hdmi->hdmi); - clk_disable_unprepare(hdmi->vpll_clk); + clk_disable_unprepare(hdmi->ref_clk); }
static const struct component_ops dw_hdmi_rockchip_ops = {
"vpll" is a misnomer. A clock input to a device should be named after the usage in the device, not after the clock that drives it. On the rk3568 the same clock is driven by the HPLL. This patch adds "ref" as a new alternative clock name for "vpll"
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Acked-by: Rob Herring robh@kernel.org ---
Notes: Changes since v4: - Add Robs Ack
Changes since v3: - Keep old clock name for compatibility reasons
.../bindings/display/rockchip/rockchip,dw-hdmi.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index da3b889ad8fcd..0400f67e5f2c9 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -36,7 +36,8 @@ properties: # order when present. - description: The HDMI CEC controller main clock - description: Power for GRF IO - - description: External clock for some HDMI PHY + - description: External clock for some HDMI PHY (old clock name, deprecated) + - description: External clock for some HDMI PHY (new name)
clock-names: minItems: 2 @@ -47,10 +48,14 @@ properties: - cec - grf - vpll + - ref - enum: - grf - vpll - - const: vpll + - ref + - enum: + - vpll + - ref
ddc-i2c-bus: $ref: /schemas/types.yaml#/definitions/phandle
The reference clock for the HDMI controller has been renamed to 'ref', the previous 'vpll' name is only left for compatibility in the driver. Rename the clock to the new name.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 080457a68e3c7..d0add619b0d22 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -1884,7 +1884,7 @@ hdmi: hdmi@ff940000 { <&cru SCLK_HDMI_CEC>, <&cru PCLK_VIO_GRF>, <&cru PLL_VPLL>; - clock-names = "iahb", "isfr", "cec", "grf", "vpll"; + clock-names = "iahb", "isfr", "cec", "grf", "ref"; power-domains = <&power RK3399_PD_HDCP>; reg-io-width = <4>; rockchip,grf = <&grf>;
Add a new dw_hdmi_plat_data struct and new compatible for rk3568.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@collabora.com Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 912181429880a..b64cc62c7b5af 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -50,6 +50,10 @@ #define RK3399_GRF_SOC_CON20 0x6250 #define RK3399_HDMI_LCDC_SEL BIT(6)
+#define RK3568_GRF_VO_CON1 0x0364 +#define RK3568_HDMI_SDAIN_MSK BIT(15) +#define RK3568_HDMI_SCLIN_MSK BIT(14) + #define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
/** @@ -473,6 +477,19 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { .use_drm_infoframe = true, };
+static struct rockchip_hdmi_chip_data rk3568_chip_data = { + .lcdsel_grf_reg = -1, +}; + +static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { + .mode_valid = dw_hdmi_rockchip_mode_valid, + .mpll_cfg = rockchip_mpll_cfg, + .cur_ctr = rockchip_cur_ctr, + .phy_config = rockchip_phy_config, + .phy_data = &rk3568_chip_data, + .use_drm_infoframe = true, +}; + static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { { .compatible = "rockchip,rk3228-dw-hdmi", .data = &rk3228_hdmi_drv_data @@ -486,6 +503,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { { .compatible = "rockchip,rk3399-dw-hdmi", .data = &rk3399_hdmi_drv_data }, + { .compatible = "rockchip,rk3568-dw-hdmi", + .data = &rk3568_hdmi_drv_data + }, {}, }; MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids); @@ -520,6 +540,9 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, encoder = &hdmi->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); + rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, + dev->of_node, 0, 0); + /* * If we failed to find the CRTC(s) which this encoder is * supposed to be connected to, it's because the CRTC has @@ -550,6 +573,14 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, return ret; }
+ if (hdmi->chip_data == &rk3568_chip_data) { + regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, + HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | + RK3568_HDMI_SCLIN_MSK, + RK3568_HDMI_SDAIN_MSK | + RK3568_HDMI_SCLIN_MSK)); + } + drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
From: Benjamin Gaignard benjamin.gaignard@collabora.com
Define a new compatible for rk3568 HDMI. This version of HDMI hardware block needs two new clocks hclk_vio and hclk to provide phy reference clocks.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@collabora.com Reviewed-by: Rob Herring robh@kernel.org Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- .../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml | 1 + 1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index 0400f67e5f2c9..e6b8437a1e2d1 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -23,6 +23,7 @@ properties: - rockchip,rk3288-dw-hdmi - rockchip,rk3328-dw-hdmi - rockchip,rk3399-dw-hdmi + - rockchip,rk3568-dw-hdmi
reg-io-width: const: 4
The RK3568 has HDMI_TX_AVDD0V9 and HDMI_TX_AVDD_1V8 supply inputs needed for the HDMI port. add support for these to the driver for boards which have them supplied by switchable regulators.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Reviewed-by: Dmitry Osipenko dmitry.osipenko@collabora.com --- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 41 +++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index b64cc62c7b5af..fe4f9556239ac 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -9,6 +9,7 @@ #include <linux/platform_device.h> #include <linux/phy/phy.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h>
#include <drm/bridge/dw_hdmi.h> #include <drm/drm_edid.h> @@ -76,6 +77,8 @@ struct rockchip_hdmi { struct clk *ref_clk; struct clk *grf_clk; struct dw_hdmi *hdmi; + struct regulator *avdd_0v9; + struct regulator *avdd_1v8; struct phy *phy; };
@@ -226,6 +229,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return PTR_ERR(hdmi->grf_clk); }
+ hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9"); + if (IS_ERR(hdmi->avdd_0v9)) + return PTR_ERR(hdmi->avdd_0v9); + + hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8"); + if (IS_ERR(hdmi->avdd_1v8)) + return PTR_ERR(hdmi->avdd_1v8); + return 0; }
@@ -566,11 +577,23 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, return ret; }
+ ret = regulator_enable(hdmi->avdd_0v9); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret); + goto err_avdd_0v9; + } + + ret = regulator_enable(hdmi->avdd_1v8); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret); + goto err_avdd_1v8; + } + ret = clk_prepare_enable(hdmi->ref_clk); if (ret) { DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n", ret); - return ret; + goto err_clk; }
if (hdmi->chip_data == &rk3568_chip_data) { @@ -594,10 +617,19 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, */ if (IS_ERR(hdmi->hdmi)) { ret = PTR_ERR(hdmi->hdmi); - drm_encoder_cleanup(encoder); - clk_disable_unprepare(hdmi->ref_clk); + goto err_bind; }
+ return 0; + +err_bind: + clk_disable_unprepare(hdmi->ref_clk); + drm_encoder_cleanup(encoder); +err_clk: + regulator_disable(hdmi->avdd_1v8); +err_avdd_1v8: + regulator_disable(hdmi->avdd_0v9); +err_avdd_0v9: return ret; }
@@ -608,6 +640,9 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
dw_hdmi_unbind(hdmi->hdmi); clk_disable_unprepare(hdmi->ref_clk); + + regulator_disable(hdmi->avdd_1v8); + regulator_disable(hdmi->avdd_0v9); }
static const struct component_ops dw_hdmi_rockchip_ops = {
The RK3568 has HDMI_TX_AVDD0V9 and HDMI_TX_AVDD_1V8 supply inputs needed for the HDMI port. Add the binding for these supplies.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Acked-by: Rob Herring robh@kernel.org ---
Notes: Changes since v4: - Add Robs Ack
.../bindings/display/rockchip/rockchip,dw-hdmi.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index e6b8437a1e2d1..38ebb69830287 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -28,6 +28,17 @@ properties: reg-io-width: const: 4
+ avdd-0v9-supply: + description: + A 0.9V supply that powers up the SoC internal circuitry. The actual pin name + varies between the different SoCs and is usually HDMI_TX_AVDD_0V9 or sometimes + HDMI_AVDD_1V0. + + avdd-1v8-supply: + description: + A 1.8V supply that powers up the SoC internal circuitry. The pin name on the + SoC usually is HDMI_TX_AVDD_1V8. + clocks: minItems: 2 items:
From: Douglas Anderson dianders@chromium.org
The previous tables for mpll_cfg and curr_ctrl were created using the 20-pages of example settings provided by the PHY vendor. Those example settings weren't particularly dense, so there were places where we were guessing what the settings would be for 10-bit and 12-bit (not that we use those anyway). It was also always a lot of extra work every time we wanted to add a new clock rate since we had to cross-reference several tables.
In https://crrev.com/c/285855 I've gone through the work to figure out how to generate this table automatically. Let's now use the automatically generated table and then we'll never need to look at it again.
We only support 8-bit mode right now and only support a small number of clock rates and I've verified that the only 8-bit rate that was affected was 148.5. That mode appears to have been wrong in the old table.
Signed-off-by: Douglas Anderson dianders@chromium.org Signed-off-by: Yakir Yang ykk@rock-chips.com Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v5: - Add missing Signed-off-by me
Changes since v3: - new patch
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 130 +++++++++++--------- 1 file changed, 69 insertions(+), 61 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index fe4f9556239ac..cb43e7b47157d 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -91,80 +91,88 @@ static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { { - 27000000, { - { 0x00b3, 0x0000}, - { 0x2153, 0x0000}, - { 0x40f3, 0x0000} + 30666000, { + { 0x00b3, 0x0000 }, + { 0x2153, 0x0000 }, + { 0x40f3, 0x0000 }, }, - }, { - 36000000, { - { 0x00b3, 0x0000}, - { 0x2153, 0x0000}, - { 0x40f3, 0x0000} + }, { + 36800000, { + { 0x00b3, 0x0000 }, + { 0x2153, 0x0000 }, + { 0x40a2, 0x0001 }, }, - }, { - 40000000, { - { 0x00b3, 0x0000}, - { 0x2153, 0x0000}, - { 0x40f3, 0x0000} + }, { + 46000000, { + { 0x00b3, 0x0000 }, + { 0x2142, 0x0001 }, + { 0x40a2, 0x0001 }, }, - }, { - 54000000, { - { 0x0072, 0x0001}, - { 0x2142, 0x0001}, - { 0x40a2, 0x0001}, + }, { + 61333000, { + { 0x0072, 0x0001 }, + { 0x2142, 0x0001 }, + { 0x40a2, 0x0001 }, }, - }, { - 65000000, { - { 0x0072, 0x0001}, - { 0x2142, 0x0001}, - { 0x40a2, 0x0001}, + }, { + 73600000, { + { 0x0072, 0x0001 }, + { 0x2142, 0x0001 }, + { 0x4061, 0x0002 }, }, - }, { - 66000000, { - { 0x013e, 0x0003}, - { 0x217e, 0x0002}, - { 0x4061, 0x0002} + }, { + 92000000, { + { 0x0072, 0x0001 }, + { 0x2145, 0x0002 }, + { 0x4061, 0x0002 }, }, - }, { - 74250000, { - { 0x0072, 0x0001}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + }, { + 122666000, { + { 0x0051, 0x0002 }, + { 0x2145, 0x0002 }, + { 0x4061, 0x0002 }, }, - }, { - 83500000, { - { 0x0072, 0x0001}, + }, { + 147200000, { + { 0x0051, 0x0002 }, + { 0x2145, 0x0002 }, + { 0x4064, 0x0003 }, }, - }, { - 108000000, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + }, { + 184000000, { + { 0x0051, 0x0002 }, + { 0x214c, 0x0003 }, + { 0x4064, 0x0003 }, }, - }, { - 106500000, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + }, { + 226666000, { + { 0x0040, 0x0003 }, + { 0x214c, 0x0003 }, + { 0x4064, 0x0003 }, }, - }, { - 146250000, { - { 0x0051, 0x0002}, - { 0x2145, 0x0002}, - { 0x4061, 0x0002} + }, { + 272000000, { + { 0x0040, 0x0003 }, + { 0x214c, 0x0003 }, + { 0x5a64, 0x0003 }, }, - }, { - 148500000, { - { 0x0051, 0x0003}, - { 0x214c, 0x0003}, - { 0x4064, 0x0003} + }, { + 340000000, { + { 0x0040, 0x0003 }, + { 0x3b4c, 0x0003 }, + { 0x5a64, 0x0003 }, }, - }, { + }, { + 600000000, { + { 0x1a40, 0x0003 }, + { 0x3b4c, 0x0003 }, + { 0x5a64, 0x0003 }, + }, + }, { ~0UL, { - { 0x00a0, 0x000a }, - { 0x2001, 0x000f }, - { 0x4002, 0x000f }, + { 0x0000, 0x0000 }, + { 0x0000, 0x0000 }, + { 0x0000, 0x0000 }, }, } };
The driver checks if the pixel clock of the given mode matches an entry in the mpll config table. The frequencies in the mpll table are meant as a frequency range up to which the entry works, not as a frequency that must match the pixel clock. The downstream Kernel also does not have this check, so drop it to allow for more display resolutions.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v3: - new patch
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 25 --------------------- 1 file changed, 25 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index cb43e7b47157d..008ab20f39ee6 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -248,26 +248,6 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return 0; }
-static enum drm_mode_status -dw_hdmi_rockchip_mode_valid(struct dw_hdmi *hdmi, void *data, - const struct drm_display_info *info, - const struct drm_display_mode *mode) -{ - const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; - int pclk = mode->clock * 1000; - bool valid = false; - int i; - - for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { - if (pclk == mpll_cfg[i].mpixelclock) { - valid = true; - break; - } - } - - return (valid) ? MODE_OK : MODE_BAD; -} - static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) { } @@ -433,7 +413,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { };
static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, @@ -450,7 +429,6 @@ static struct rockchip_hdmi_chip_data rk3288_chip_data = { };
static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, @@ -470,7 +448,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { };
static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, @@ -488,7 +465,6 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { };
static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, @@ -501,7 +477,6 @@ static struct rockchip_hdmi_chip_data rk3568_chip_data = { };
static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { - .mode_valid = dw_hdmi_rockchip_mode_valid, .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config,
From: Douglas Anderson dianders@chromium.org
Jitter was improved by lowering the MPLL bandwidth to account for high frequency noise in the rk3288 PLL. In each case MPLL bandwidth was lowered only enough to get us a comfortable margin. We believe that lowering the bandwidth like this is safe given sufficient testing.
Signed-off-by: Douglas Anderson dianders@chromium.org Signed-off-by: Yakir Yang ykk@rock-chips.com Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v3: - new patch
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 008ab20f39ee6..5be5d1d4963cd 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -180,20 +180,8 @@ static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { /* pixelclk bpp8 bpp10 bpp12 */ { - 40000000, { 0x0018, 0x0018, 0x0018 }, - }, { - 65000000, { 0x0028, 0x0028, 0x0028 }, - }, { - 66000000, { 0x0038, 0x0038, 0x0038 }, - }, { - 74250000, { 0x0028, 0x0038, 0x0038 }, - }, { - 83500000, { 0x0028, 0x0038, 0x0038 }, - }, { - 146250000, { 0x0038, 0x0038, 0x0038 }, - }, { - 148500000, { 0x0000, 0x0038, 0x0038 }, - }, { + 600000000, { 0x0000, 0x0000, 0x0000 }, + }, { ~0UL, { 0x0000, 0x0000, 0x0000}, } };
From: Nickey Yang nickey.yang@rock-chips.com
add 594Mhz configuration parameters in rockchip_phy_config
Signed-off-by: Nickey Yang nickey.yang@rock-chips.com Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v3: - new patch
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 5be5d1d4963cd..7e6dc851a9c8b 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -191,6 +191,7 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { { 74250000, 0x8009, 0x0004, 0x0272}, { 148500000, 0x802b, 0x0004, 0x028d}, { 297000000, 0x8039, 0x0005, 0x028d}, + { 594000000, 0x8039, 0x0000, 0x019d}, { ~0UL, 0x0000, 0x0000, 0x0000} };
None of the upstream device tree files has a "unwedge" pinctrl specified. Make it optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Acked-by: Rob Herring robh@kernel.org ---
Notes: Changes since v4: - Add Robs Ack
.../devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml | 1 + 1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index 38ebb69830287..d7cb2b2be60e8 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -89,6 +89,7 @@ properties: The unwedge pinctrl entry shall drive the DDC SDA line low. This is intended to work around a hardware errata that can cause the DDC I2C bus to be wedged. + minItems: 1 items: - const: default - const: unwedge
The VOP2 is the display output controller on the RK3568. Add the node for it to the dtsi file along with the required display-subsystem node and the iommu node.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Acked-by: Rob Herring robh@kernel.org ---
Notes: Changes since v6: - Change RK3568_ prefix to ROCKCHIP_ prefix - start counting from one instead of zero
Changes since v4: - Add Robs Ack
Changes since v3: - Bring back gamma_lut regs - Drop redundant _vop suffix from clock names
arch/arm64/boot/dts/rockchip/rk3566.dtsi | 4 ++ arch/arm64/boot/dts/rockchip/rk3568.dtsi | 4 ++ arch/arm64/boot/dts/rockchip/rk356x.dtsi | 51 ++++++++++++++++++++++++ include/dt-bindings/soc/rockchip,vop2.h | 14 +++++++ 4 files changed, 73 insertions(+) create mode 100644 include/dt-bindings/soc/rockchip,vop2.h
diff --git a/arch/arm64/boot/dts/rockchip/rk3566.dtsi b/arch/arm64/boot/dts/rockchip/rk3566.dtsi index 3839eef5e4f76..595fa2562cb8e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566.dtsi @@ -18,3 +18,7 @@ power-domain@RK3568_PD_PIPE { #power-domain-cells = <0>; }; }; + +&vop { + compatible = "rockchip,rk3566-vop"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 5b0f528d68180..4deab90e83834 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -114,3 +114,7 @@ power-domain@RK3568_PD_PIPE { #power-domain-cells = <0>; }; }; + +&vop { + compatible = "rockchip,rk3568-vop"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi index 7cdef800cb3ce..fdb7a9a6ca743 100644 --- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi @@ -129,6 +129,11 @@ opp-1800000000 { }; };
+ display_subsystem: display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vop_out>; + }; + firmware { scmi: scmi { compatible = "arm,scmi-smc"; @@ -569,6 +574,52 @@ gmac1_mtl_tx_setup: tx-queues-config { }; };
+ vop: vop@fe040000 { + reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>; + reg-names = "regs", "gamma_lut"; + interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, + <&cru DCLK_VOP1>, <&cru DCLK_VOP2>; + clock-names = "aclk", "hclk", "dclk_vp0", "dclk_vp1", "dclk_vp2"; + iommus = <&vop_mmu>; + power-domains = <&power RK3568_PD_VO>; + rockchip,grf = <&grf>; + status = "disabled"; + + vop_out: ports { + #address-cells = <1>; + #size-cells = <0>; + + vp0: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + vp1: port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + vp2: port@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + vop_mmu: iommu@fe043e00 { + compatible = "rockchip,rk3568-iommu"; + reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>; + interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + status = "disabled"; + }; + qos_gpu: qos@fe128000 { compatible = "rockchip,rk3568-qos", "syscon"; reg = <0x0 0xfe128000 0x0 0x20>; diff --git a/include/dt-bindings/soc/rockchip,vop2.h b/include/dt-bindings/soc/rockchip,vop2.h new file mode 100644 index 0000000000000..6e66a802b96a5 --- /dev/null +++ b/include/dt-bindings/soc/rockchip,vop2.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + +#ifndef __DT_BINDINGS_ROCKCHIP_VOP2_H +#define __DT_BINDINGS_ROCKCHIP_VOP2_H + +#define ROCKCHIP_VOP2_EP_RGB0 1 +#define ROCKCHIP_VOP2_EP_HDMI0 2 +#define ROCKCHIP_VOP2_EP_EDP0 3 +#define ROCKCHIP_VOP2_EP_MIPI0 4 +#define ROCKCHIP_VOP2_EP_LVDS0 5 +#define ROCKCHIP_VOP2_EP_MIPI1 6 +#define ROCKCHIP_VOP2_EP_LVDS1 7 + +#endif /* __DT_BINDINGS_ROCKCHIP_VOP2_H */
Add support for the HDMI port found on RK3568.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v7: - Rename hclk to niu
Changes since v5: - Drop unnecessary #size-cells/#address-cells from nodes with only single endpoint
arch/arm64/boot/dts/rockchip/rk356x.dtsi | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi index fdb7a9a6ca743..1a359bbf65300 100644 --- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi @@ -620,6 +620,38 @@ vop_mmu: iommu@fe043e00 { status = "disabled"; };
+ hdmi: hdmi@fe0a0000 { + compatible = "rockchip,rk3568-dw-hdmi"; + reg = <0x0 0xfe0a0000 0x0 0x20000>; + interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru PCLK_HDMI_HOST>, + <&cru CLK_HDMI_SFR>, + <&cru CLK_HDMI_CEC>, + <&pmucru CLK_HDMI_REF>, + <&cru HCLK_VO>; + clock-names = "iahb", "isfr", "cec", "ref"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>; + power-domains = <&power RK3568_PD_VO>; + reg-io-width = <4>; + rockchip,grf = <&grf>; + #sound-dai-cells = <0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in: port@0 { + reg = <0>; + }; + + hdmi_out: port@1 { + reg = <1>; + }; + }; + }; + qos_gpu: qos@fe128000 { compatible = "rockchip,rk3568-qos", "syscon"; reg = <0x0 0xfe128000 0x0 0x20>;
This enabled the VOP2 display controller along with hdmi and the required port routes which is enough to get a picture out of the hdmi port of the board.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v5: - Drop reg property from single endpoint node
Changes since v4: - Sort nodes alphabetically
Changes since v3: - Fix HDMI connector type
.../boot/dts/rockchip/rk3568-evb1-v10.dts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts index a794a0ea5c701..096b66d7697e2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts @@ -8,6 +8,7 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/leds/common.h> #include <dt-bindings/pinctrl/rockchip.h> +#include <dt-bindings/soc/rockchip,vop2.h> #include "rk3568.dtsi"
/ { @@ -34,6 +35,17 @@ dc_12v: dc-12v { regulator-max-microvolt = <12000000>; };
+ hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds";
@@ -189,6 +201,24 @@ &gpu { status = "okay"; };
+&hdmi { + avdd-0v9-supply = <&vdda0v9_image>; + avdd-1v8-supply = <&vcca1v8_image>; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &i2c0 { status = "okay";
@@ -589,3 +619,20 @@ &usb2phy1_otg { phy-supply = <&vcc5v0_usb_host>; status = "okay"; }; + +&vop { + assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; + assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>; + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = <ROCKCHIP_VOP2_EP_HDMI0>; + remote-endpoint = <&hdmi_in_vp0>; + }; +};
From: Michael Riesch michael.riesch@wolfvision.net
Enable the RK356x Video Output Processor (VOP) 2 on the Pine64 Quartz64 Model A.
Signed-off-by: Michael Riesch michael.riesch@wolfvision.net Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v5: - Drop reg property from single endpoint node
Changes since v4: - Sort nodes alphabetically
Changes since v3: - Fix HDMI connector type
.../boot/dts/rockchip/rk3566-quartz64-a.dts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts index dd7f4b9b686b8..6504f7ab3ea77 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts @@ -4,6 +4,7 @@
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/pinctrl/rockchip.h> +#include <dt-bindings/soc/rockchip,vop2.h> #include "rk3566.dtsi"
/ { @@ -35,6 +36,17 @@ fan: gpio_fan { #cooling-cells = <2>; };
+ hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds";
@@ -248,6 +260,24 @@ &gpu { status = "okay"; };
+&hdmi { + avdd-0v9-supply = <&vdda_0v9>; + avdd-1v8-supply = <&vcc_1v8>; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &i2c0 { status = "okay";
@@ -685,3 +715,20 @@ &usb2phy1_otg { phy-supply = <&vcc5v0_usb20_host>; status = "okay"; }; + +&vop { + assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; + assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>; + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = <ROCKCHIP_VOP2_EP_HDMI0>; + remote-endpoint = <&hdmi_in_vp0>; + }; +};
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP
if DRM_ROCKCHIP
+config ROCKCHIP_VOP + bool "Rockchip VOP driver" + default y + help + This selects support for the VOP driver. You should enable it + on all older SoCs up to RK3399. + config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver" + depends on ROCKCHIP_VOP help This selects support for Rockchip SoC specific extensions for the Analogix Core DP driver. If you want to enable DP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 1a56f696558ca..dfc5512fdb9f1 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -4,8 +4,9 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o + rockchip_drm_gem.o
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 214214190fef1..7cf8b9665e5cf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -494,7 +494,7 @@ static int __init rockchip_drm_init(void) return -ENODEV;
num_rockchip_sub_drivers = 0; - ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); + ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, CONFIG_ROCKCHIP_LVDS); ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote:
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP
if DRM_ROCKCHIP
+config ROCKCHIP_VOP
- bool "Rockchip VOP driver"
- default y
- help
This selects support for the VOP driver. You should enable it
on all older SoCs up to RK3399.
- config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver"
- depends on ROCKCHIP_VOP
Aanlogix dp is also on vop2 base soc such as rk356x and rk3588 .
help This selects support for Rockchip SoC specific extensions for the Analogix Core DP driver. If you want to enable DP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index 1a56f696558ca..dfc5512fdb9f1 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -4,8 +4,9 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o
rockchip_drm_gem.o
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 214214190fef1..7cf8b9665e5cf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -494,7 +494,7 @@ static int __init rockchip_drm_init(void) return -ENODEV;
num_rockchip_sub_drivers = 0;
- ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP);
- ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, CONFIG_ROCKCHIP_LVDS); ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote:
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP if DRM_ROCKCHIP +config ROCKCHIP_VOP
- bool "Rockchip VOP driver"
- default y
- help
This selects support for the VOP driver. You should enable it
on all older SoCs up to RK3399.
That reminds me that I wanted to rephrase this. Will change in next round.
- config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver"
- depends on ROCKCHIP_VOP
Aanlogix dp is also on vop2 base soc such as rk356x and rk3588 .
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Sascha
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote:
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote:
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP if DRM_ROCKCHIP +config ROCKCHIP_VOP
- bool "Rockchip VOP driver"
- default y
- help
This selects support for the VOP driver. You should enable it
on all older SoCs up to RK3399.
That reminds me that I wanted to rephrase this. Will change in next round.
- config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver"
- depends on ROCKCHIP_VOP
Aanlogix dp is also on vop2 base soc such as rk356x and rk3588 .
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout) { struct rockchip_drm_private *priv; int pipe, ret = 0;
if (!crtc) return -ENODEV;
if (mstimeout <= 0) return -EINVAL;
priv = crtc->dev->dev_private; pipe = drm_crtc_index(crtc);
if (priv->crtc_funcs[pipe] && priv->crtc_funcs[pipe]->wait_vact_end) ret = priv->crtc_funcs[pipe]->wait_vact_end(crtc, mstimeout);
return ret; } EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
Sascha
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote:
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote:
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP if DRM_ROCKCHIP +config ROCKCHIP_VOP
- bool "Rockchip VOP driver"
- default y
- help
This selects support for the VOP driver. You should enable it
on all older SoCs up to RK3399.
That reminds me that I wanted to rephrase this. Will change in next round.
- config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver"
- depends on ROCKCHIP_VOP
Aanlogix dp is also on vop2 base soc such as rk356x and rk3588.
BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
Sascha
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote:
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote:
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP if DRM_ROCKCHIP +config ROCKCHIP_VOP
- bool "Rockchip VOP driver"
- default y
- help
This selects support for the VOP driver. You should enable it
on all older SoCs up to RK3399.
That reminds me that I wanted to rephrase this. Will change in next round.
- config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver"
- depends on ROCKCHIP_VOP
Aanlogix dp is also on vop2 base soc such as rk356x and rk3588.
BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
I think the current solution is just a workaround to make your patch pass the kernel compile
but not reflect the real situation.
Sascha
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote:
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote:
With upcoming VOP2 support VOP won't be the only choice anymore, so make the VOP driver optional.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ drivers/gpu/drm/rockchip/Makefile | 3 ++- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index fa5cfda4e90e3..7d22e2997a571 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,8 +23,16 @@ config DRM_ROCKCHIP if DRM_ROCKCHIP +config ROCKCHIP_VOP
- bool "Rockchip VOP driver"
- default y
- help
This selects support for the VOP driver. You should enable it
on all older SoCs up to RK3399.
That reminds me that I wanted to rephrase this. Will change in next round.
- config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver"
- depends on ROCKCHIP_VOP
Aanlogix dp is also on vop2 base soc such as rk356x and rk3588.
BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
What about the others, like LVDS and RGB?
I think the current solution is just a workaround to make your patch pass the kernel compile
Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
Sascha
Hi:
On 3/31/22 16:18, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote:
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/28/22 23:11, Sascha Hauer wrote: > With upcoming VOP2 support VOP won't be the only choice anymore, so make > the VOP driver optional. > > Signed-off-by: Sascha Hauer s.hauer@pengutronix.de > --- > drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ > drivers/gpu/drm/rockchip/Makefile | 3 ++- > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > 3 files changed, 11 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig > index fa5cfda4e90e3..7d22e2997a571 100644 > --- a/drivers/gpu/drm/rockchip/Kconfig > +++ b/drivers/gpu/drm/rockchip/Kconfig > @@ -23,8 +23,16 @@ config DRM_ROCKCHIP > if DRM_ROCKCHIP > +config ROCKCHIP_VOP > + bool "Rockchip VOP driver" > + default y > + help > + This selects support for the VOP driver. You should enable it > + on all older SoCs up to RK3399.
That reminds me that I wanted to rephrase this. Will change in next round.
> + > config ROCKCHIP_ANALOGIX_DP > bool "Rockchip specific extensions for Analogix DP driver" > + depends on ROCKCHIP_VOP Aanlogix dp is also on vop2 base soc such as rk356x and rk3588.
BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
What about the others, like LVDS and RGB?
Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
I think the current solution is just a workaround to make your patch pass the kernel compile
Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Sascha
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote:
Hi:
On 3/31/22 16:18, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote:
Hi Andy,
On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: > Hi Sascha: > > On 3/28/22 23:11, Sascha Hauer wrote: > > With upcoming VOP2 support VOP won't be the only choice anymore, so make > > the VOP driver optional. > > > > Signed-off-by: Sascha Hauer s.hauer@pengutronix.de > > --- > > drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ > > drivers/gpu/drm/rockchip/Makefile | 3 ++- > > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > > 3 files changed, 11 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig > > index fa5cfda4e90e3..7d22e2997a571 100644 > > --- a/drivers/gpu/drm/rockchip/Kconfig > > +++ b/drivers/gpu/drm/rockchip/Kconfig > > @@ -23,8 +23,16 @@ config DRM_ROCKCHIP > > if DRM_ROCKCHIP > > +config ROCKCHIP_VOP > > + bool "Rockchip VOP driver" > > + default y > > + help > > + This selects support for the VOP driver. You should enable it > > + on all older SoCs up to RK3399. That reminds me that I wanted to rephrase this. Will change in next round.
> > + > > config ROCKCHIP_ANALOGIX_DP > > bool "Rockchip specific extensions for Analogix DP driver" > > + depends on ROCKCHIP_VOP > Aanlogix dp is also on vop2 base soc such as rk356x and rk3588.
BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
I added the dependency because analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so this driver currenty can't work with the VOP2 driver and can't be linked without the VOP driver being present. I'll add a few words to the commit message.
Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
What about the others, like LVDS and RGB?
Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
I think the current solution is just a workaround to make your patch pass the kernel compile
Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non buildable kernel.
Sascha
Hi Sascha:
On 4/1/22 20:55, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote:
Hi:
On 3/31/22 16:18, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/30/22 14:39, Sascha Hauer wrote: > Hi Andy, > > On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: >> Hi Sascha: >> >> On 3/28/22 23:11, Sascha Hauer wrote: >>> With upcoming VOP2 support VOP won't be the only choice anymore, so make >>> the VOP driver optional. >>> >>> Signed-off-by: Sascha Hauer s.hauer@pengutronix.de >>> --- >>> drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ >>> drivers/gpu/drm/rockchip/Makefile | 3 ++- >>> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- >>> 3 files changed, 11 insertions(+), 2 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig >>> index fa5cfda4e90e3..7d22e2997a571 100644 >>> --- a/drivers/gpu/drm/rockchip/Kconfig >>> +++ b/drivers/gpu/drm/rockchip/Kconfig >>> @@ -23,8 +23,16 @@ config DRM_ROCKCHIP >>> if DRM_ROCKCHIP >>> +config ROCKCHIP_VOP >>> + bool "Rockchip VOP driver" >>> + default y >>> + help >>> + This selects support for the VOP driver. You should enable it >>> + on all older SoCs up to RK3399. > That reminds me that I wanted to rephrase this. Will change in next > round. > >>> + >>> config ROCKCHIP_ANALOGIX_DP >>> bool "Rockchip specific extensions for Analogix DP driver" >>> + depends on ROCKCHIP_VOP >> Aanlogix dp is also on vop2 base soc such as rk356x and rk3588.
BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
> I added the dependency because analogix_dp-rockchip.c calls > rockchip_drm_wait_vact_end() which is implemented in the VOP driver, > so this driver currenty can't work with the VOP2 driver and can't > be linked without the VOP driver being present. > I'll add a few words to the commit message. Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP driver to rockchip_drm_drv.c
I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
What about the others, like LVDS and RGB?
Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
I think the current solution is just a workaround to make your patch pass the kernel compile
Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non
Excuse me? How do you get this conclusion ?
I said before, vop and vop2 based platforms both have ROCKCHIP_ANALOGIX_DP.
If this patch will cause the compile error, please do a real fix, not a
workaround that may deliver misleading information.
buildable kernel.
Sascha
On Sat, Apr 02, 2022 at 09:25:33AM +0800, Andy Yan wrote:
Hi Sascha:
On 4/1/22 20:55, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote:
Hi:
On 3/31/22 16:18, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote: > Hi Sascha: > > On 3/30/22 14:39, Sascha Hauer wrote: > > Hi Andy, > > > > On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: > > > Hi Sascha: > > > > > > On 3/28/22 23:11, Sascha Hauer wrote: > > > > With upcoming VOP2 support VOP won't be the only choice anymore, so make > > > > the VOP driver optional. > > > > > > > > Signed-off-by: Sascha Hauer s.hauer@pengutronix.de > > > > --- > > > > drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ > > > > drivers/gpu/drm/rockchip/Makefile | 3 ++- > > > > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > > > > 3 files changed, 11 insertions(+), 2 deletions(-) > > > > > > > > diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig > > > > index fa5cfda4e90e3..7d22e2997a571 100644 > > > > --- a/drivers/gpu/drm/rockchip/Kconfig > > > > +++ b/drivers/gpu/drm/rockchip/Kconfig > > > > @@ -23,8 +23,16 @@ config DRM_ROCKCHIP > > > > if DRM_ROCKCHIP > > > > +config ROCKCHIP_VOP > > > > + bool "Rockchip VOP driver" > > > > + default y > > > > + help > > > > + This selects support for the VOP driver. You should enable it > > > > + on all older SoCs up to RK3399. > > That reminds me that I wanted to rephrase this. Will change in next > > round. > > > > > > + > > > > config ROCKCHIP_ANALOGIX_DP > > > > bool "Rockchip specific extensions for Analogix DP driver" > > > > + depends on ROCKCHIP_VOP > > > Aanlogix dp is also on vop2 base soc such as rk356x and rk3588. BTW I just looked at the downstream driver. Here we have the same situation that the analogix dp driver calls rockchip_drm_wait_vact_end() which is implemented in the VOP driver, so when the analogix dp driver is actually used on a VOP2 SoC then it is either used in a way that rockchip_drm_wait_vact_end() will never be called or it explodes in all colours.
> > I added the dependency because analogix_dp-rockchip.c calls > > rockchip_drm_wait_vact_end() which is implemented in the VOP driver, > > so this driver currenty can't work with the VOP2 driver and can't > > be linked without the VOP driver being present. > > I'll add a few words to the commit message. > Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP > driver to rockchip_drm_drv.c I am not sure if that's really worth it. Yes, the direction might be the right one, but I would really prefer when somebody does the change who can test and confirm that the analogix dp really works with VOP2 in the end.
If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
Here you are suggesting to add even more Kconfig dependencies.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
What about the others, like LVDS and RGB?
Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
I think the current solution is just a workaround to make your patch pass the kernel compile
Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Here you say Kconfig dependencies are no good idea.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non
Excuse me? How do you get this conclusion ?
Given that you say that you want to have both more and less Kconfig dependencies I came to the conclusion that I only add one where it's necessary to compile the driver.
I said before, vop and vop2 based platforms both have ROCKCHIP_ANALOGIX_DP.
Maybe, but vop2 with ROCKCHIP_ANALOGIX_DP doesn't even work in the Rockchip downstream kernel, so I wonder how relevant this usecase really is.
If this patch will cause the compile error, please do a real fix, not a
I can't, because I don't have any hardware to test the Analogix DP on a VOP hardware, and given that Analogix DP in conjunction with VOP2 hardware is not even supported in the downstream Kernel I am not sure if it's really worth doing that.
Moving rockchip_drm_wait_vact_end() to rockchip_drm_drv.c doesn't work with mainline currently, we first would have to add a struct crtc_funcs to struct rockchip_drm_private. Yes, that could be done.
workaround that may deliver misleading information.
The Kconfig dependency quite clearly says that the Analogix DP currently doesn't work with the VOP2. Anyone who wants to change that can use that information as a starting point and implement whatever is necessary and likely has the hardware to verify the work. I don't want to solve problems that *might* arise in the future, and in this case it's not a direction decision that we might regret in the future.
Sascha
Hi Sacha:
On 4/5/22 17:05, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:25:33AM +0800, Andy Yan wrote:
Hi Sascha:
On 4/1/22 20:55, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote:
Hi:
On 3/31/22 16:18, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote:
Hi Sascha:
On 3/31/22 15:06, Sascha Hauer wrote: > On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote: >> Hi Sascha: >> >> On 3/30/22 14:39, Sascha Hauer wrote: >>> Hi Andy, >>> >>> On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: >>>> Hi Sascha: >>>> >>>> On 3/28/22 23:11, Sascha Hauer wrote: >>>>> With upcoming VOP2 support VOP won't be the only choice anymore, so make >>>>> the VOP driver optional. >>>>> >>>>> Signed-off-by: Sascha Hauer s.hauer@pengutronix.de >>>>> --- >>>>> drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ >>>>> drivers/gpu/drm/rockchip/Makefile | 3 ++- >>>>> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- >>>>> 3 files changed, 11 insertions(+), 2 deletions(-) >>>>> >>>>> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig >>>>> index fa5cfda4e90e3..7d22e2997a571 100644 >>>>> --- a/drivers/gpu/drm/rockchip/Kconfig >>>>> +++ b/drivers/gpu/drm/rockchip/Kconfig >>>>> @@ -23,8 +23,16 @@ config DRM_ROCKCHIP >>>>> if DRM_ROCKCHIP >>>>> +config ROCKCHIP_VOP >>>>> + bool "Rockchip VOP driver" >>>>> + default y >>>>> + help >>>>> + This selects support for the VOP driver. You should enable it >>>>> + on all older SoCs up to RK3399. >>> That reminds me that I wanted to rephrase this. Will change in next >>> round. >>> >>>>> + >>>>> config ROCKCHIP_ANALOGIX_DP >>>>> bool "Rockchip specific extensions for Analogix DP driver" >>>>> + depends on ROCKCHIP_VOP >>>> Aanlogix dp is also on vop2 base soc such as rk356x and rk3588. > BTW I just looked at the downstream driver. Here we have the same > situation that the analogix dp driver calls rockchip_drm_wait_vact_end() > which is implemented in the VOP driver, so when the analogix dp driver > is actually used on a VOP2 SoC then it is either used in a way that > rockchip_drm_wait_vact_end() will never be called or it explodes in all > colours. > >>> I added the dependency because analogix_dp-rockchip.c calls >>> rockchip_drm_wait_vact_end() which is implemented in the VOP driver, >>> so this driver currenty can't work with the VOP2 driver and can't >>> be linked without the VOP driver being present. >>> I'll add a few words to the commit message. >> Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP >> driver to rockchip_drm_drv.c > I am not sure if that's really worth it. Yes, the direction might be the > right one, but I would really prefer when somebody does the change who > can test and confirm that the analogix dp really works with VOP2 in the > end. If follow this point, the current DW_MIPI also has not been tested for confirm that it
can really work with VOP2, so you should also make it depends on ROCKCHIP_VOP.
Here you are suggesting to add even more Kconfig dependencies.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
What about the others, like LVDS and RGB?
Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
I think the current solution is just a workaround to make your patch pass the kernel compile
Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Here you say Kconfig dependencies are no good idea.
Yes. It's not a good idea. So I don't want to see you use a Kcofig dependence
to disable a module to avoid compile which introduced by your patch.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non
Excuse me? How do you get this conclusion ?
Given that you say that you want to have both more and less Kconfig dependencies I came to the conclusion that I only add one where it's necessary to compile the driver.
I said before, vop and vop2 based platforms both have ROCKCHIP_ANALOGIX_DP.
Maybe, but vop2 with ROCKCHIP_ANALOGIX_DP doesn't even work in the Rockchip downstream kernel, so I wonder how relevant this usecase really is.
No, this is not the truth. Rockchip_ANALOGIX_DP of course work with the
vendor kernel. We have many rk356x based products shipped with edp.
Even the VGA output interface on RK3568_EVB1 is drived by
ROCKCHIP_ANALOGIX_DP with a RTD2166 eDP to VGA convert
chip.
So how do you get conclusion that ROCKCHIP_ANALOGIX_DP can't work with
the Rockchip downstream kernel? Is it because you can't make the DP work on
your board? If it is, please contact the supplier who gave you the board.
Do you have a RK3568_EVB1 that has a VGA output interface on board?
If you have it, I can offer you image to verify the DP.
If this patch will cause the compile error, please do a real fix, not a
I can't, because I don't have any hardware to test the Analogix DP on a VOP hardware, and given that Analogix DP in conjunction with VOP2 hardware is not even supported in the downstream Kernel I am not sure if it's really worth doing that.
Again, this is not the truth, see above.
I am not ask you support the ROCKCHIP_ANALOGIX_DP on upstream, I just
want you can give a better solution when you patch cause the compile error.
Disable a module when it conflict with your patch is too rough.
Moving rockchip_drm_wait_vact_end() to rockchip_drm_drv.c doesn't work with mainline currently, we first would have to add a struct crtc_funcs to struct rockchip_drm_private. Yes, that could be done.
workaround that may deliver misleading information.
The Kconfig dependency quite clearly says that the Analogix DP currently doesn't work with the VOP2. Anyone who wants to change that can use that information as a starting point and implement whatever is necessary and likely has the hardware to verify the work. I don't want to solve problems that *might* arise in the future, and in this case it's not a direction decision that we might regret in the future.
Sascha
On Wed, Apr 06, 2022 at 09:43:49AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/5/22 17:05, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:25:33AM +0800, Andy Yan wrote:
Hi Sascha:
On 4/1/22 20:55, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote:
Hi:
On 3/31/22 16:18, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote: > Hi Sascha: > > On 3/31/22 15:06, Sascha Hauer wrote: > > On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote: > > > Hi Sascha: > > > > > > On 3/30/22 14:39, Sascha Hauer wrote: > > > > Hi Andy, > > > > > > > > On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: > > > > > Hi Sascha: > > > > > > > > > > On 3/28/22 23:11, Sascha Hauer wrote: > > > > > > With upcoming VOP2 support VOP won't be the only choice anymore, so make > > > > > > the VOP driver optional. > > > > > > > > > > > > Signed-off-by: Sascha Hauer s.hauer@pengutronix.de > > > > > > --- > > > > > > drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ > > > > > > drivers/gpu/drm/rockchip/Makefile | 3 ++- > > > > > > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > > > > > > 3 files changed, 11 insertions(+), 2 deletions(-) > > > > > > > > > > > > diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig > > > > > > index fa5cfda4e90e3..7d22e2997a571 100644 > > > > > > --- a/drivers/gpu/drm/rockchip/Kconfig > > > > > > +++ b/drivers/gpu/drm/rockchip/Kconfig > > > > > > @@ -23,8 +23,16 @@ config DRM_ROCKCHIP > > > > > > if DRM_ROCKCHIP > > > > > > +config ROCKCHIP_VOP > > > > > > + bool "Rockchip VOP driver" > > > > > > + default y > > > > > > + help > > > > > > + This selects support for the VOP driver. You should enable it > > > > > > + on all older SoCs up to RK3399. > > > > That reminds me that I wanted to rephrase this. Will change in next > > > > round. > > > > > > > > > > + > > > > > > config ROCKCHIP_ANALOGIX_DP > > > > > > bool "Rockchip specific extensions for Analogix DP driver" > > > > > > + depends on ROCKCHIP_VOP > > > > > Aanlogix dp is also on vop2 base soc such as rk356x and rk3588. > > BTW I just looked at the downstream driver. Here we have the same > > situation that the analogix dp driver calls rockchip_drm_wait_vact_end() > > which is implemented in the VOP driver, so when the analogix dp driver > > is actually used on a VOP2 SoC then it is either used in a way that > > rockchip_drm_wait_vact_end() will never be called or it explodes in all > > colours. > > > > > > I added the dependency because analogix_dp-rockchip.c calls > > > > rockchip_drm_wait_vact_end() which is implemented in the VOP driver, > > > > so this driver currenty can't work with the VOP2 driver and can't > > > > be linked without the VOP driver being present. > > > > I'll add a few words to the commit message. > > > Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP > > > driver to rockchip_drm_drv.c > > I am not sure if that's really worth it. Yes, the direction might be the > > right one, but I would really prefer when somebody does the change who > > can test and confirm that the analogix dp really works with VOP2 in the > > end. > If follow this point, the current DW_MIPI also has not been tested for > confirm that it > > can really work with VOP2, so you should also make it depends on > ROCKCHIP_VOP.
Here you are suggesting to add even more Kconfig dependencies.
Well at least I have patches here which make DW_MIPI work with VOP2 ;)
But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
What about the others, like LVDS and RGB?
Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
> I think the current solution is just a workaround to make your patch pass > the kernel compile Indeed.
I agree that it would be good to add a note somewhere which outputs work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig dependencies is the right place for it, because only people who deliberately disable VOP support will see this information. Maybe we should rather add it to the Kconfig help text?
If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Here you say Kconfig dependencies are no good idea.
Yes. It's not a good idea. So I don't want to see you use a Kcofig dependence
to disable a module to avoid compile which introduced by your patch.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non
Excuse me? How do you get this conclusion ?
Given that you say that you want to have both more and less Kconfig dependencies I came to the conclusion that I only add one where it's necessary to compile the driver.
I said before, vop and vop2 based platforms both have ROCKCHIP_ANALOGIX_DP.
Maybe, but vop2 with ROCKCHIP_ANALOGIX_DP doesn't even work in the Rockchip downstream kernel, so I wonder how relevant this usecase really is.
No, this is not the truth. Rockchip_ANALOGIX_DP of course work with the vendor kernel. We have many rk356x based products shipped with edp. Even the VGA output interface on RK3568_EVB1 is drived by ROCKCHIP_ANALOGIX_DP with a RTD2166 eDP to VGA convert chip.
So how do you get conclusion that ROCKCHIP_ANALOGIX_DP can't work with the Rockchip downstream kernel? Is it because you can't make the DP work on your board? If it is, please contact the supplier who gave you the board.
In the downstream kernel I have available (which is a 5.10.66) analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in rockchip_drm_vop.c and assumes that the passed struct drm_crtc * can be converted to a struct vop *. Basically it's the same situation we have right now with the mainline kernel, just that the linker issues won't show up because the VOP driver can't be disabled in the downstream kernel.
Do you have a RK3568_EVB1 that has a VGA output interface on board?
If you have it, I can offer you image to verify the DP.
If this patch will cause the compile error, please do a real fix, not a
I can't, because I don't have any hardware to test the Analogix DP on a VOP hardware, and given that Analogix DP in conjunction with VOP2 hardware is not even supported in the downstream Kernel I am not sure if it's really worth doing that.
Again, this is not the truth, see above. I am not ask you support the ROCKCHIP_ANALOGIX_DP on upstream, I just want you can give a better solution when you patch cause the compile error. Disable a module when it conflict with your patch is too rough.
It does not conflict with my patch. The dependency only means that you can't enable the Analogix DP driver when the VOP driver is disabled. That doesn't hurt, because currently you can't do anything with the Analogix DP driver without the VOP driver. With the added dependency the Analogix DP driver can still be used with the VOP driver, even when the VOP2 driver is enabled. I really can't see a problem with that.
Sascha
Hi:
On 4/6/22 15:04, Sascha Hauer wrote:
On Wed, Apr 06, 2022 at 09:43:49AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/5/22 17:05, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:25:33AM +0800, Andy Yan wrote:
Hi Sascha:
On 4/1/22 20:55, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote:
Hi:
On 3/31/22 16:18, Sascha Hauer wrote: > On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote: >> Hi Sascha: >> >> On 3/31/22 15:06, Sascha Hauer wrote: >>> On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote: >>>> Hi Sascha: >>>> >>>> On 3/30/22 14:39, Sascha Hauer wrote: >>>>> Hi Andy, >>>>> >>>>> On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: >>>>>> Hi Sascha: >>>>>> >>>>>> On 3/28/22 23:11, Sascha Hauer wrote: >>>>>>> With upcoming VOP2 support VOP won't be the only choice anymore, so make >>>>>>> the VOP driver optional. >>>>>>> >>>>>>> Signed-off-by: Sascha Hauer s.hauer@pengutronix.de >>>>>>> --- >>>>>>> drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ >>>>>>> drivers/gpu/drm/rockchip/Makefile | 3 ++- >>>>>>> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- >>>>>>> 3 files changed, 11 insertions(+), 2 deletions(-) >>>>>>> >>>>>>> diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig >>>>>>> index fa5cfda4e90e3..7d22e2997a571 100644 >>>>>>> --- a/drivers/gpu/drm/rockchip/Kconfig >>>>>>> +++ b/drivers/gpu/drm/rockchip/Kconfig >>>>>>> @@ -23,8 +23,16 @@ config DRM_ROCKCHIP >>>>>>> if DRM_ROCKCHIP >>>>>>> +config ROCKCHIP_VOP >>>>>>> + bool "Rockchip VOP driver" >>>>>>> + default y >>>>>>> + help >>>>>>> + This selects support for the VOP driver. You should enable it >>>>>>> + on all older SoCs up to RK3399. >>>>> That reminds me that I wanted to rephrase this. Will change in next >>>>> round. >>>>> >>>>>>> + >>>>>>> config ROCKCHIP_ANALOGIX_DP >>>>>>> bool "Rockchip specific extensions for Analogix DP driver" >>>>>>> + depends on ROCKCHIP_VOP >>>>>> Aanlogix dp is also on vop2 base soc such as rk356x and rk3588. >>> BTW I just looked at the downstream driver. Here we have the same >>> situation that the analogix dp driver calls rockchip_drm_wait_vact_end() >>> which is implemented in the VOP driver, so when the analogix dp driver >>> is actually used on a VOP2 SoC then it is either used in a way that >>> rockchip_drm_wait_vact_end() will never be called or it explodes in all >>> colours. >>> >>>>> I added the dependency because analogix_dp-rockchip.c calls >>>>> rockchip_drm_wait_vact_end() which is implemented in the VOP driver, >>>>> so this driver currenty can't work with the VOP2 driver and can't >>>>> be linked without the VOP driver being present. >>>>> I'll add a few words to the commit message. >>>> Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP >>>> driver to rockchip_drm_drv.c >>> I am not sure if that's really worth it. Yes, the direction might be the >>> right one, but I would really prefer when somebody does the change who >>> can test and confirm that the analogix dp really works with VOP2 in the >>> end. >> If follow this point, the current DW_MIPI also has not been tested for >> confirm that it >> >> can really work with VOP2, so you should also make it depends on >> ROCKCHIP_VOP.
Here you are suggesting to add even more Kconfig dependencies.
> Well at least I have patches here which make DW_MIPI work with VOP2 ;) But you DW_MIPI patches for rk356x didn't come. So this is not keep consistency with this point.
> What about the others, like LVDS and RGB? Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 has BT1120/BT656, no LVDS or RGB.
>> I think the current solution is just a workaround to make your patch pass >> the kernel compile > Indeed. > > I agree that it would be good to add a note somewhere which outputs > work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig > dependencies is the right place for it, because only people who deliberately > disable VOP support will see this information. > Maybe we should rather add it to the Kconfig help text? If a device is supported for this soc, we will add dt node at the dtsi file.
A Kconfig dependencies don't seems a good idea.
Here you say Kconfig dependencies are no good idea.
Yes. It's not a good idea. So I don't want to see you use a Kcofig dependence
to disable a module to avoid compile which introduced by your patch.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non
Excuse me? How do you get this conclusion ?
Given that you say that you want to have both more and less Kconfig dependencies I came to the conclusion that I only add one where it's necessary to compile the driver.
I said before, vop and vop2 based platforms both have ROCKCHIP_ANALOGIX_DP.
Maybe, but vop2 with ROCKCHIP_ANALOGIX_DP doesn't even work in the Rockchip downstream kernel, so I wonder how relevant this usecase really is.
No, this is not the truth. Rockchip_ANALOGIX_DP of course work with the vendor kernel. We have many rk356x based products shipped with edp. Even the VGA output interface on RK3568_EVB1 is drived by ROCKCHIP_ANALOGIX_DP with a RTD2166 eDP to VGA convert chip.
So how do you get conclusion that ROCKCHIP_ANALOGIX_DP can't work with the Rockchip downstream kernel? Is it because you can't make the DP work on your board? If it is, please contact the supplier who gave you the board.
In the downstream kernel I have available (which is a 5.10.66) analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in rockchip_drm_vop.c and assumes that the passed struct drm_crtc * can be converted to a struct vop *. Basically it's the same situation we have right now with the mainline kernel, just that the linker issues won't show up because the VOP driver can't be disabled in the downstream kernel.
So you judge ROCKCHIP_ANALOGIX_DP can't work by this(as vop2 doesn't has rockchip_drm_wait_vact_end interface)?
No, you may not know clearly about this function, this function is used for eDP PSR, which is a
optional function, that means not every eDP panel has PSR function(this function usually parsed from edid).
This really not means than ROCKCHIP_ANALOGIX_DP can't work.
And your 5.10 downstream kernel seems out of dated. We have already move this function out from rockchip_drm_vop to rockchip_drm_drv.
Do you have a RK3568_EVB1 that has a VGA output interface on board?
If you have it, I can offer you image to verify the DP.
If this patch will cause the compile error, please do a real fix, not a
I can't, because I don't have any hardware to test the Analogix DP on a VOP hardware, and given that Analogix DP in conjunction with VOP2 hardware is not even supported in the downstream Kernel I am not sure if it's really worth doing that.
Again, this is not the truth, see above. I am not ask you support the ROCKCHIP_ANALOGIX_DP on upstream, I just want you can give a better solution when you patch cause the compile error. Disable a module when it conflict with your patch is too rough.
It does not conflict with my patch. The dependency only means that you can't enable the Analogix DP driver when the VOP driver is disabled. That doesn't hurt, because currently you can't do anything with the Analogix DP driver without the VOP driver. With the added dependency the Analogix DP driver can still be used with the VOP driver, even when the VOP2 driver is enabled. I really can't see a problem with that.
Sascha
On Wed, Apr 06, 2022 at 03:47:18PM +0800, Andy Yan wrote:
Hi:
On 4/6/22 15:04, Sascha Hauer wrote:
On Wed, Apr 06, 2022 at 09:43:49AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/5/22 17:05, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:25:33AM +0800, Andy Yan wrote:
Hi Sascha:
On 4/1/22 20:55, Sascha Hauer wrote:
On Thu, Mar 31, 2022 at 07:00:34PM +0800, Andy Yan wrote: > Hi: > > On 3/31/22 16:18, Sascha Hauer wrote: > > On Thu, Mar 31, 2022 at 03:20:37PM +0800, Andy Yan wrote: > > > Hi Sascha: > > > > > > On 3/31/22 15:06, Sascha Hauer wrote: > > > > On Wed, Mar 30, 2022 at 08:50:09PM +0800, Andy Yan wrote: > > > > > Hi Sascha: > > > > > > > > > > On 3/30/22 14:39, Sascha Hauer wrote: > > > > > > Hi Andy, > > > > > > > > > > > > On Tue, Mar 29, 2022 at 07:56:27PM +0800, Andy Yan wrote: > > > > > > > Hi Sascha: > > > > > > > > > > > > > > On 3/28/22 23:11, Sascha Hauer wrote: > > > > > > > > With upcoming VOP2 support VOP won't be the only choice anymore, so make > > > > > > > > the VOP driver optional. > > > > > > > > > > > > > > > > Signed-off-by: Sascha Hauer s.hauer@pengutronix.de > > > > > > > > --- > > > > > > > > drivers/gpu/drm/rockchip/Kconfig | 8 ++++++++ > > > > > > > > drivers/gpu/drm/rockchip/Makefile | 3 ++- > > > > > > > > drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 +- > > > > > > > > 3 files changed, 11 insertions(+), 2 deletions(-) > > > > > > > > > > > > > > > > diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig > > > > > > > > index fa5cfda4e90e3..7d22e2997a571 100644 > > > > > > > > --- a/drivers/gpu/drm/rockchip/Kconfig > > > > > > > > +++ b/drivers/gpu/drm/rockchip/Kconfig > > > > > > > > @@ -23,8 +23,16 @@ config DRM_ROCKCHIP > > > > > > > > if DRM_ROCKCHIP > > > > > > > > +config ROCKCHIP_VOP > > > > > > > > + bool "Rockchip VOP driver" > > > > > > > > + default y > > > > > > > > + help > > > > > > > > + This selects support for the VOP driver. You should enable it > > > > > > > > + on all older SoCs up to RK3399. > > > > > > That reminds me that I wanted to rephrase this. Will change in next > > > > > > round. > > > > > > > > > > > > > > + > > > > > > > > config ROCKCHIP_ANALOGIX_DP > > > > > > > > bool "Rockchip specific extensions for Analogix DP driver" > > > > > > > > + depends on ROCKCHIP_VOP > > > > > > > Aanlogix dp is also on vop2 base soc such as rk356x and rk3588. > > > > BTW I just looked at the downstream driver. Here we have the same > > > > situation that the analogix dp driver calls rockchip_drm_wait_vact_end() > > > > which is implemented in the VOP driver, so when the analogix dp driver > > > > is actually used on a VOP2 SoC then it is either used in a way that > > > > rockchip_drm_wait_vact_end() will never be called or it explodes in all > > > > colours. > > > > > > > > > > I added the dependency because analogix_dp-rockchip.c calls > > > > > > rockchip_drm_wait_vact_end() which is implemented in the VOP driver, > > > > > > so this driver currenty can't work with the VOP2 driver and can't > > > > > > be linked without the VOP driver being present. > > > > > > I'll add a few words to the commit message. > > > > > Maybe a better direction is move rockchip_drm_wait_vact_end from the VOP > > > > > driver to rockchip_drm_drv.c > > > > I am not sure if that's really worth it. Yes, the direction might be the > > > > right one, but I would really prefer when somebody does the change who > > > > can test and confirm that the analogix dp really works with VOP2 in the > > > > end. > > > If follow this point, the current DW_MIPI also has not been tested for > > > confirm that it > > > > > > can really work with VOP2, so you should also make it depends on > > > ROCKCHIP_VOP.
Here you are suggesting to add even more Kconfig dependencies.
> > Well at least I have patches here which make DW_MIPI work with VOP2 ;) > But you DW_MIPI patches for rk356x didn't come. So this is not keep > consistency with this point. > > > What about the others, like LVDS and RGB? > Yes, we also have other interface , RK356X has LVDS/RGB/BT1120/BT656, RK3588 > has BT1120/BT656, no LVDS or RGB. > > > > I think the current solution is just a workaround to make your patch pass > > > the kernel compile > > Indeed. > > > > I agree that it would be good to add a note somewhere which outputs > > work with the VOP2 driver (currently only HDMI), but I wonder if Kconfig > > dependencies is the right place for it, because only people who deliberately > > disable VOP support will see this information. > > Maybe we should rather add it to the Kconfig help text? > If a device is supported for this soc, we will add dt node at the dtsi file. > > A Kconfig dependencies don't seems a good idea.
Here you say Kconfig dependencies are no good idea.
Yes. It's not a good idea. So I don't want to see you use a Kcofig dependence
to disable a module to avoid compile which introduced by your patch.
Ok, this means we can keep my current approach with just letting ROCKCHIP_ANALOGIX_DP depend on ROCKCHIP_VOP to avoid having a non
Excuse me? How do you get this conclusion ?
Given that you say that you want to have both more and less Kconfig dependencies I came to the conclusion that I only add one where it's necessary to compile the driver.
I said before, vop and vop2 based platforms both have ROCKCHIP_ANALOGIX_DP.
Maybe, but vop2 with ROCKCHIP_ANALOGIX_DP doesn't even work in the Rockchip downstream kernel, so I wonder how relevant this usecase really is.
No, this is not the truth. Rockchip_ANALOGIX_DP of course work with the vendor kernel. We have many rk356x based products shipped with edp. Even the VGA output interface on RK3568_EVB1 is drived by ROCKCHIP_ANALOGIX_DP with a RTD2166 eDP to VGA convert chip.
So how do you get conclusion that ROCKCHIP_ANALOGIX_DP can't work with the Rockchip downstream kernel? Is it because you can't make the DP work on your board? If it is, please contact the supplier who gave you the board.
In the downstream kernel I have available (which is a 5.10.66) analogix_dp-rockchip.c calls rockchip_drm_wait_vact_end() which is implemented in rockchip_drm_vop.c and assumes that the passed struct drm_crtc * can be converted to a struct vop *. Basically it's the same situation we have right now with the mainline kernel, just that the linker issues won't show up because the VOP driver can't be disabled in the downstream kernel.
So you judge ROCKCHIP_ANALOGIX_DP can't work by this(as vop2 doesn't has rockchip_drm_wait_vact_end interface)?
No, you may not know clearly about this function, this function is used for eDP PSR, which is a
optional function, that means not every eDP panel has PSR function(this function usually parsed from edid).
This really not means than ROCKCHIP_ANALOGIX_DP can't work.
And your 5.10 downstream kernel seems out of dated. We have already move this function out from rockchip_drm_vop to rockchip_drm_drv.
I guessed that. Well we can do the same once we are there, but currently we are not. My patch doesn't break any existing features and we can add Analogix DP support later. I know the VOP2 driver is not feature complete and it doesn't aim to be.
Please let's stop arguing about this topic. Once somebody wants to add Analogix DP support with VOP2 we can discuss the right way at length and until then my patch won't do any harm.
Sascha
From: Andy Yan andy.yan@rock-chips.com
The VOP2 unit is found on Rockchip SoCs beginning with rk3566/rk3568. It replaces the VOP unit found in the older Rockchip SoCs.
This driver has been derived from the downstream Rockchip Kernel and heavily modified:
- All nonstandard DRM properties have been removed - dropped struct vop2_plane_state and pass around less data between functions - Dropped all DRM_FORMAT_* not known on upstream - rework register access to get rid of excessively used macros - Drop all waiting for framesyncs
The driver is tested with HDMI and MIPI-DSI display on a RK3568-EVB board. Overlay support is tested with the modetest utility. AFBC support on the cluster windows is tested with weston-simple-dmabuf-egl on weston using the (yet to be upstreamed) panfrost driver support.
Signed-off-by: Andy Yan andy.yan@rock-chips.com Signed-off-by: Sascha Hauer s.hauer@pengutronix.de ---
Notes: Changes since v6: - Drop device tree parsing during runtime - Fix typo in Kconfig help text
Changes since v5: - consistently use u8/u16/u32 rather than uint8_t/uint16_t/uint32_t - Use spin_lock rather than spin_lock_irqsave - replace printk with drm_dbg - break some overlong lines
Changes since v4: - Avoid stack frame overflow by not allocating big array on the stack
Changes since v3: - Sort includes - fix typos - Drop spinlock - Use regmap_set_bits()/regmap_clear_bits() - simplify vop2_scale_factor() - simplify vop2_afbc_transform_offset()
drivers/gpu/drm/rockchip/Kconfig | 6 + drivers/gpu/drm/rockchip/Makefile | 1 + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 1 + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 6 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 2 + drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 15 + drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2688 ++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 477 ++++ drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 281 ++ 9 files changed, 3476 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h create mode 100644 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 7d22e2997a571..0ad15cfe95322 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -30,6 +30,12 @@ config ROCKCHIP_VOP This selects support for the VOP driver. You should enable it on all older SoCs up to RK3399.
+config ROCKCHIP_VOP2 + bool "Rockchip VOP2 driver" + help + This selects support for the VOP2 driver. You should enable it + on all newer SoCs beginning from RK3568. + config ROCKCHIP_ANALOGIX_DP bool "Rockchip specific extensions for Analogix DP driver" depends on ROCKCHIP_VOP diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index dfc5512fdb9f1..3ff7b21c04149 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -6,6 +6,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ rockchip_drm_gem.o
+rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 7cf8b9665e5cf..a96bfb8f538fd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -495,6 +495,7 @@ static int __init rockchip_drm_init(void)
num_rockchip_sub_drivers = 0; ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP); + ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2); ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver, CONFIG_ROCKCHIP_LVDS); ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 1f66a447acada..370d9e6c8e6d5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -18,7 +18,7 @@
#define ROCKCHIP_MAX_FB_BUFFER 3 #define ROCKCHIP_MAX_CONNECTOR 2 -#define ROCKCHIP_MAX_CRTC 2 +#define ROCKCHIP_MAX_CRTC 4
struct drm_device; struct drm_connector; @@ -31,6 +31,9 @@ struct rockchip_crtc_state { int output_bpc; int output_flags; bool enable_afbc; + u32 bus_format; + u32 bus_flags; + int color_space; }; #define to_rockchip_crtc_state(s) \ container_of(s, struct rockchip_crtc_state, base) @@ -69,6 +72,7 @@ extern struct platform_driver rockchip_dp_driver; extern struct platform_driver rockchip_lvds_driver; extern struct platform_driver vop_platform_driver; extern struct platform_driver rk3066_hdmi_driver; +extern struct platform_driver vop2_platform_driver;
static inline struct rockchip_encoder *to_rockchip_encoder(struct drm_encoder *encoder) { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 3aa37e177667e..0d2cb4f3922b8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -134,4 +134,6 @@ void rockchip_drm_mode_config_init(struct drm_device *dev)
dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; dev->mode_config.helper_private = &rockchip_mode_config_helpers; + + dev->mode_config.normalize_zpos = true; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 857d97cdc67c6..1e364d7b50e69 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -54,9 +54,23 @@ struct vop_afbc { struct vop_reg enable; struct vop_reg win_sel; struct vop_reg format; + struct vop_reg rb_swap; + struct vop_reg uv_swap; + struct vop_reg auto_gating_en; + struct vop_reg block_split_en; + struct vop_reg pic_vir_width; + struct vop_reg tile_num; struct vop_reg hreg_block_split; + struct vop_reg pic_offset; struct vop_reg pic_size; + struct vop_reg dsp_offset; + struct vop_reg transform_offset; struct vop_reg hdr_ptr; + struct vop_reg half_block_en; + struct vop_reg xmirror; + struct vop_reg ymirror; + struct vop_reg rotate_270; + struct vop_reg rotate_90; struct vop_reg rstn; };
@@ -410,4 +424,5 @@ static inline int scl_vop_cal_lb_mode(int width, bool is_yuv) }
extern const struct component_ops vop_component_ops; + #endif /* _ROCKCHIP_DRM_VOP_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c new file mode 100644 index 0000000000000..69e9870d5f2dc --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -0,0 +1,2688 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * Author: Andy Yan andy.yan@rock-chips.com + */ +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/swab.h> + +#include <drm/drm.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_uapi.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_flip_work.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#include <uapi/linux/videodev2.h> +#include <dt-bindings/soc/rockchip,vop2.h> + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_gem.h" +#include "rockchip_drm_fb.h" +#include "rockchip_drm_vop2.h" + +/* + * VOP2 architecture + * + +----------+ +-------------+ +-----------+ + | Cluster | | Sel 1 from 6| | 1 from 3 | + | window0 | | Layer0 | | RGB | + +----------+ +-------------+ +---------------+ +-------------+ +-----------+ + +----------+ +-------------+ |N from 6 layers| | | + | Cluster | | Sel 1 from 6| | Overlay0 +--->| Video Port0 | +-----------+ + | window1 | | Layer1 | | | | | | 1 from 3 | + +----------+ +-------------+ +---------------+ +-------------+ | LVDS | + +----------+ +-------------+ +-----------+ + | Esmart | | Sel 1 from 6| + | window0 | | Layer2 | +---------------+ +-------------+ +-----------+ + +----------+ +-------------+ |N from 6 Layers| | | +--> | 1 from 3 | + +----------+ +-------------+ --------> | Overlay1 +--->| Video Port1 | | MIPI | + | Esmart | | Sel 1 from 6| --------> | | | | +-----------+ + | Window1 | | Layer3 | +---------------+ +-------------+ + +----------+ +-------------+ +-----------+ + +----------+ +-------------+ | 1 from 3 | + | Smart | | Sel 1 from 6| +---------------+ +-------------+ | HDMI | + | Window0 | | Layer4 | |N from 6 Layers| | | +-----------+ + +----------+ +-------------+ | Overlay2 +--->| Video Port2 | + +----------+ +-------------+ | | | | +-----------+ + | Smart | | Sel 1 from 6| +---------------+ +-------------+ | 1 from 3 | + | Window1 | | Layer5 | | eDP | + +----------+ +-------------+ +-----------+ + * + */ + +enum vop2_data_format { + VOP2_FMT_ARGB8888 = 0, + VOP2_FMT_RGB888, + VOP2_FMT_RGB565, + VOP2_FMT_XRGB101010, + VOP2_FMT_YUV420SP, + VOP2_FMT_YUV422SP, + VOP2_FMT_YUV444SP, + VOP2_FMT_YUYV422 = 8, + VOP2_FMT_YUYV420, + VOP2_FMT_VYUY422, + VOP2_FMT_VYUY420, + VOP2_FMT_YUV420SP_TILE_8x4 = 0x10, + VOP2_FMT_YUV420SP_TILE_16x2, + VOP2_FMT_YUV422SP_TILE_8x4, + VOP2_FMT_YUV422SP_TILE_16x2, + VOP2_FMT_YUV420SP_10, + VOP2_FMT_YUV422SP_10, + VOP2_FMT_YUV444SP_10, +}; + +enum vop2_afbc_format { + VOP2_AFBC_FMT_RGB565, + VOP2_AFBC_FMT_ARGB2101010 = 2, + VOP2_AFBC_FMT_YUV420_10BIT, + VOP2_AFBC_FMT_RGB888, + VOP2_AFBC_FMT_ARGB8888, + VOP2_AFBC_FMT_YUV420 = 9, + VOP2_AFBC_FMT_YUV422 = 0xb, + VOP2_AFBC_FMT_YUV422_10BIT = 0xe, + VOP2_AFBC_FMT_INVALID = -1, +}; + +union vop2_alpha_ctrl { + u32 val; + struct { + /* [0:1] */ + u32 color_mode:1; + u32 alpha_mode:1; + /* [2:3] */ + u32 blend_mode:2; + u32 alpha_cal_mode:1; + /* [5:7] */ + u32 factor_mode:3; + /* [8:9] */ + u32 alpha_en:1; + u32 src_dst_swap:1; + u32 reserved:6; + /* [16:23] */ + u32 glb_alpha:8; + } bits; +}; + +struct vop2_alpha { + union vop2_alpha_ctrl src_color_ctrl; + union vop2_alpha_ctrl dst_color_ctrl; + union vop2_alpha_ctrl src_alpha_ctrl; + union vop2_alpha_ctrl dst_alpha_ctrl; +}; + +struct vop2_alpha_config { + bool src_premulti_en; + bool dst_premulti_en; + bool src_pixel_alpha_en; + bool dst_pixel_alpha_en; + u16 src_glb_alpha_value; + u16 dst_glb_alpha_value; +}; + +struct vop2_win { + struct vop2 *vop2; + struct drm_plane base; + const struct vop2_win_data *data; + struct regmap_field *reg[VOP2_WIN_MAX_REG]; + + /** + * @win_id: graphic window id, a cluster may be split into two + * graphics windows. + */ + u8 win_id; + u8 delay; + u32 offset; + + enum drm_plane_type type; +}; + +struct vop2_video_port { + struct drm_crtc crtc; + struct vop2 *vop2; + struct clk *dclk; + unsigned int id; + const struct vop2_video_port_regs *regs; + const struct vop2_video_port_data *data; + + struct completion dsp_hold_completion; + + /** + * @win_mask: Bitmask of windows attached to the video port; + */ + u32 win_mask; + + struct vop2_win *primary_plane; + struct drm_pending_vblank_event *event; + + unsigned int nlayers; +}; + +struct vop2 { + struct device *dev; + struct drm_device *drm; + struct vop2_video_port vps[ROCKCHIP_MAX_CRTC]; + + const struct vop2_data *data; + /* + * Number of windows that are registered as plane, may be less than the + * total number of hardware windows. + */ + u32 registered_num_wins; + + void __iomem *regs; + struct regmap *map; + + struct regmap *grf; + + /* physical map length of vop2 register */ + u32 len; + + void __iomem *lut_regs; + + /* protects crtc enable/disable */ + struct mutex vop2_lock; + + int irq; + + /* + * Some global resources are shared between all video ports(crtcs), so + * we need a ref counter here. + */ + unsigned int enable_count; + struct clk *hclk; + struct clk *aclk; + + /* must be put at the end of the struct */ + struct vop2_win win[]; +}; + +static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc) +{ + return container_of(crtc, struct vop2_video_port, crtc); +} + +static struct vop2_win *to_vop2_win(struct drm_plane *p) +{ + return container_of(p, struct vop2_win, base); +} + +static void vop2_lock(struct vop2 *vop2) +{ + mutex_lock(&vop2->vop2_lock); +} + +static void vop2_unlock(struct vop2 *vop2) +{ + mutex_unlock(&vop2->vop2_lock); +} + +static void vop2_writel(struct vop2 *vop2, u32 offset, u32 v) +{ + regmap_write(vop2->map, offset, v); +} + +static void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v) +{ + regmap_write(vp->vop2->map, vp->data->offset + offset, v); +} + +static u32 vop2_readl(struct vop2 *vop2, u32 offset) +{ + u32 val; + + regmap_read(vop2->map, offset, &val); + + return val; +} + +static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v) +{ + regmap_field_write(win->reg[reg], v); +} + +static bool vop2_cluster_window(const struct vop2_win *win) +{ + return win->data->feature & WIN_FEATURE_CLUSTER; +} + +static void vop2_cfg_done(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + + regmap_set_bits(vop2->map, RK3568_REG_CFG_DONE, + BIT(vp->id) | RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); +} + +static void vop2_win_disable(struct vop2_win *win) +{ + vop2_win_write(win, VOP2_WIN_ENABLE, 0); + + if (vop2_cluster_window(win)) + vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 0); +} + +static enum vop2_data_format vop2_convert_format(u32 format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return VOP2_FMT_ARGB8888; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + return VOP2_FMT_RGB888; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + return VOP2_FMT_RGB565; + case DRM_FORMAT_NV12: + return VOP2_FMT_YUV420SP; + case DRM_FORMAT_NV16: + return VOP2_FMT_YUV422SP; + case DRM_FORMAT_NV24: + return VOP2_FMT_YUV444SP; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + return VOP2_FMT_VYUY422; + case DRM_FORMAT_VYUY: + case DRM_FORMAT_UYVY: + return VOP2_FMT_YUYV422; + default: + DRM_ERROR("unsupported format[%08x]\n", format); + return -EINVAL; + } +} + +static enum vop2_afbc_format vop2_convert_afbc_format(u32 format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return VOP2_AFBC_FMT_ARGB8888; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + return VOP2_AFBC_FMT_RGB888; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + return VOP2_AFBC_FMT_RGB565; + case DRM_FORMAT_NV12: + return VOP2_AFBC_FMT_YUV420; + case DRM_FORMAT_NV16: + return VOP2_AFBC_FMT_YUV422; + default: + return VOP2_AFBC_FMT_INVALID; + } + + return VOP2_AFBC_FMT_INVALID; +} + +static bool vop2_win_rb_swap(u32 format) +{ + switch (format) { + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_BGR565: + return true; + default: + return false; + } +} + +static bool vop2_afbc_rb_swap(u32 format) +{ + switch (format) { + case DRM_FORMAT_NV24: + return true; + default: + return false; + } +} + +static bool vop2_afbc_uv_swap(u32 format) +{ + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + return true; + default: + return false; + } +} + +static bool vop2_win_uv_swap(u32 format) +{ + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV24: + return true; + default: + return false; + } +} + +static bool vop2_win_dither_up(u32 format) +{ + switch (format) { + case DRM_FORMAT_BGR565: + case DRM_FORMAT_RGB565: + return true; + default: + return false; + } +} + +static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode) +{ + /* + * FIXME: + * + * There is no media type for YUV444 output, + * so when out_mode is AAAA or P888, assume output is YUV444 on + * yuv format. + * + * From H/W testing, YUV444 mode need a rb swap. + */ + if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 || + bus_format == MEDIA_BUS_FMT_VYUY8_1X16 || + bus_format == MEDIA_BUS_FMT_YVYU8_2X8 || + bus_format == MEDIA_BUS_FMT_VYUY8_2X8 || + ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 || + bus_format == MEDIA_BUS_FMT_YUV10_1X30) && + (output_mode == ROCKCHIP_OUT_MODE_AAAA || + output_mode == ROCKCHIP_OUT_MODE_P888))) + return true; + else + return false; +} + +static bool is_yuv_output(u32 bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_YUV10_1X30: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YVYU8_1X16: + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_VYUY8_1X16: + return true; + default: + return false; + } +} + +static bool rockchip_afbc(struct drm_plane *plane, u64 modifier) +{ + int i; + + if (modifier == DRM_FORMAT_MOD_LINEAR) + return false; + + for (i = 0 ; i < plane->modifier_count; i++) + if (plane->modifiers[i] == modifier) + return true; + + return false; + +} + +static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, + u64 modifier) +{ + struct vop2_win *win = to_vop2_win(plane); + struct vop2 *vop2 = win->vop2; + + if (modifier == DRM_FORMAT_MOD_INVALID) + return false; + + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + if (!rockchip_afbc(plane, modifier)) { + drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", + modifier); + + return false; + } + + return vop2_convert_afbc_format(format) >= 0; +} + +static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate, + bool afbc_half_block_en) +{ + struct drm_rect *src = &pstate->src; + struct drm_framebuffer *fb = pstate->fb; + u32 bpp = fb->format->cpp[0] * 8; + u32 vir_width = (fb->pitches[0] << 3) / bpp; + u32 width = drm_rect_width(src) >> 16; + u32 height = drm_rect_height(src) >> 16; + u32 act_xoffset = src->x1 >> 16; + u32 act_yoffset = src->y1 >> 16; + u32 align16_crop = 0; + u32 align64_crop = 0; + u32 height_tmp; + u8 tx, ty; + u8 bottom_crop_line_num = 0; + + /* 16 pixel align */ + if (height & 0xf) + align16_crop = 16 - (height & 0xf); + + height_tmp = height + align16_crop; + + /* 64 pixel align */ + if (height_tmp & 0x3f) + align64_crop = 64 - (height_tmp & 0x3f); + + bottom_crop_line_num = align16_crop + align64_crop; + + switch (pstate->rotation & + (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | + DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) { + case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y: + tx = 16 - ((act_xoffset + width) & 0xf); + ty = bottom_crop_line_num - act_yoffset; + break; + case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90: + tx = bottom_crop_line_num - act_yoffset; + ty = vir_width - width - act_xoffset; + break; + case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270: + tx = act_yoffset; + ty = act_xoffset; + break; + case DRM_MODE_REFLECT_X: + tx = 16 - ((act_xoffset + width) & 0xf); + ty = act_yoffset; + break; + case DRM_MODE_REFLECT_Y: + tx = act_xoffset; + ty = bottom_crop_line_num - act_yoffset; + break; + case DRM_MODE_ROTATE_90: + tx = bottom_crop_line_num - act_yoffset; + ty = act_xoffset; + break; + case DRM_MODE_ROTATE_270: + tx = act_yoffset; + ty = vir_width - width - act_xoffset; + break; + case 0: + tx = act_xoffset; + ty = act_yoffset; + break; + } + + if (afbc_half_block_en) + ty &= 0x7f; + +#define TRANSFORM_XOFFSET GENMASK(7, 0) +#define TRANSFORM_YOFFSET GENMASK(23, 16) + return FIELD_PREP(TRANSFORM_XOFFSET, tx) | + FIELD_PREP(TRANSFORM_YOFFSET, ty); +} + +/* + * A Cluster window has 2048 x 16 line buffer, which can + * works at 2048 x 16(Full) or 4096 x 8 (Half) mode. + * for Cluster_lb_mode register: + * 0: half mode, for plane input width range 2048 ~ 4096 + * 1: half mode, for cluster work at 2 * 2048 plane mode + * 2: half mode, for rotate_90/270 mode + * + */ +static int vop2_get_cluster_lb_mode(struct vop2_win *win, + struct drm_plane_state *pstate) +{ + if ((pstate->rotation & DRM_MODE_ROTATE_270) || + (pstate->rotation & DRM_MODE_ROTATE_90)) + return 2; + else + return 0; +} + +static u16 vop2_scale_factor(u32 src, u32 dst) +{ + u32 fac; + int shift; + + if (src == dst) + return 0; + + if (dst < 2) + return U16_MAX; + + if (src < 2) + return 0; + + if (src > dst) + shift = 12; + else + shift = 16; + + src--; + dst--; + + fac = DIV_ROUND_UP(src << shift, dst) - 1; + + if (fac > U16_MAX) + return U16_MAX; + + return fac; +} + +static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, + u32 src_w, u32 src_h, u32 dst_w, + u32 dst_h, u32 pixel_format) +{ + const struct drm_format_info *info; + u16 hor_scl_mode, ver_scl_mode; + u16 hscl_filter_mode, vscl_filter_mode; + u8 gt2 = 0; + u8 gt4 = 0; + u32 val; + + info = drm_format_info(pixel_format); + + if (src_h >= (4 * dst_h)) { + gt4 = 1; + src_h >>= 2; + } else if (src_h >= (2 * dst_h)) { + gt2 = 1; + src_h >>= 1; + } + + hor_scl_mode = scl_get_scl_mode(src_w, dst_w); + ver_scl_mode = scl_get_scl_mode(src_h, dst_h); + + if (hor_scl_mode == SCALE_UP) + hscl_filter_mode = VOP2_SCALE_UP_BIC; + else + hscl_filter_mode = VOP2_SCALE_DOWN_BIL; + + if (ver_scl_mode == SCALE_UP) + vscl_filter_mode = VOP2_SCALE_UP_BIL; + else + vscl_filter_mode = VOP2_SCALE_DOWN_BIL; + + /* + * RK3568 VOP Esmart/Smart dsp_w should be even pixel + * at scale down mode + */ + if (!(win->data->feature & WIN_FEATURE_AFBDC)) { + if ((hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) { + drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n", + win->data->name, dst_w); + dst_w++; + } + } + + val = vop2_scale_factor(src_w, dst_w); + vop2_win_write(win, VOP2_WIN_SCALE_YRGB_X, val); + val = vop2_scale_factor(src_h, dst_h); + vop2_win_write(win, VOP2_WIN_SCALE_YRGB_Y, val); + + vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT4, gt4); + vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT2, gt2); + + vop2_win_write(win, VOP2_WIN_YRGB_HOR_SCL_MODE, hor_scl_mode); + vop2_win_write(win, VOP2_WIN_YRGB_VER_SCL_MODE, ver_scl_mode); + + if (vop2_cluster_window(win)) + return; + + vop2_win_write(win, VOP2_WIN_YRGB_HSCL_FILTER_MODE, hscl_filter_mode); + vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode); + + if (info->is_yuv) { + src_w /= info->hsub; + src_h /= info->vsub; + + gt4 = gt2 = 0; + + if (src_h >= (4 * dst_h)) { + gt4 = 1; + src_h >>= 2; + } else if (src_h >= (2 * dst_h)) { + gt2 = 1; + src_h >>= 1; + } + + hor_scl_mode = scl_get_scl_mode(src_w, dst_w); + ver_scl_mode = scl_get_scl_mode(src_h, dst_h); + + val = vop2_scale_factor(src_w, dst_w); + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val); + + val = vop2_scale_factor(src_h, dst_h); + vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val); + + vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4); + vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT2, gt2); + vop2_win_write(win, VOP2_WIN_CBCR_HOR_SCL_MODE, hor_scl_mode); + vop2_win_write(win, VOP2_WIN_CBCR_VER_SCL_MODE, ver_scl_mode); + vop2_win_write(win, VOP2_WIN_CBCR_HSCL_FILTER_MODE, hscl_filter_mode); + vop2_win_write(win, VOP2_WIN_CBCR_VSCL_FILTER_MODE, vscl_filter_mode); + } +} + +static int vop2_convert_csc_mode(int csc_mode) +{ + switch (csc_mode) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_470_SYSTEM_M: + case V4L2_COLORSPACE_470_SYSTEM_BG: + return CSC_BT601L; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_SMPTE240M: + case V4L2_COLORSPACE_DEFAULT: + return CSC_BT709L; + case V4L2_COLORSPACE_JPEG: + return CSC_BT601F; + case V4L2_COLORSPACE_BT2020: + return CSC_BT2020; + default: + return CSC_BT709L; + } +} + +/* + * colorspace path: + * Input Win csc Output + * 1. YUV(2020) --> Y2R->2020To709->R2Y --> YUV_OUTPUT(601/709) + * RGB --> R2Y __/ + * + * 2. YUV(2020) --> bypasss --> YUV_OUTPUT(2020) + * RGB --> 709To2020->R2Y __/ + * + * 3. YUV(2020) --> Y2R->2020To709 --> RGB_OUTPUT(709) + * RGB --> R2Y __/ + * + * 4. YUV(601/709)-> Y2R->709To2020->R2Y --> YUV_OUTPUT(2020) + * RGB --> 709To2020->R2Y __/ + * + * 5. YUV(601/709)-> bypass --> YUV_OUTPUT(709) + * RGB --> R2Y __/ + * + * 6. YUV(601/709)-> bypass --> YUV_OUTPUT(601) + * RGB --> R2Y(601) __/ + * + * 7. YUV --> Y2R(709) --> RGB_OUTPUT(709) + * RGB --> bypass __/ + * + * 8. RGB --> 709To2020->R2Y --> YUV_OUTPUT(2020) + * + * 9. RGB --> R2Y(709) --> YUV_OUTPUT(709) + * + * 10. RGB --> R2Y(601) --> YUV_OUTPUT(601) + * + * 11. RGB --> bypass --> RGB_OUTPUT(709) + */ + +static void vop2_setup_csc_mode(struct vop2_video_port *vp, + struct vop2_win *win, + struct drm_plane_state *pstate) +{ + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); + int is_input_yuv = pstate->fb->format->is_yuv; + int is_output_yuv = is_yuv_output(vcstate->bus_format); + int input_csc = V4L2_COLORSPACE_DEFAULT; + int output_csc = vcstate->color_space; + bool r2y_en, y2r_en; + int csc_mode; + + if (is_input_yuv && !is_output_yuv) { + y2r_en = true; + r2y_en = false; + csc_mode = vop2_convert_csc_mode(input_csc); + } else if (!is_input_yuv && is_output_yuv) { + y2r_en = false; + r2y_en = true; + csc_mode = vop2_convert_csc_mode(output_csc); + } else { + y2r_en = false; + r2y_en = false; + csc_mode = false; + } + + vop2_win_write(win, VOP2_WIN_Y2R_EN, y2r_en); + vop2_win_write(win, VOP2_WIN_R2Y_EN, r2y_en); + vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode); +} + +static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq) +{ + struct vop2 *vop2 = vp->vop2; + + vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irq << 16 | irq); + vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16 | irq); +} + +static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq) +{ + struct vop2 *vop2 = vp->vop2; + + vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16); +} + +static int vop2_core_clks_prepare_enable(struct vop2 *vop2) +{ + int ret; + + ret = clk_prepare_enable(vop2->hclk); + if (ret < 0) { + drm_err(vop2->drm, "failed to enable hclk - %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(vop2->aclk); + if (ret < 0) { + drm_err(vop2->drm, "failed to enable aclk - %d\n", ret); + goto err; + } + + return 0; +err: + clk_disable_unprepare(vop2->hclk); + + return ret; +} + +static void vop2_enable(struct vop2 *vop2) +{ + int ret; + + ret = pm_runtime_get_sync(vop2->dev); + if (ret < 0) { + drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret); + return; + } + + ret = vop2_core_clks_prepare_enable(vop2); + if (ret) { + pm_runtime_put_sync(vop2->dev); + return; + } + + if (vop2->data->soc_id == 3566) + vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); + + vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); + + /* + * Disable auto gating, this is a workaround to + * avoid display image shift when a window enabled. + */ + regmap_clear_bits(vop2->map, RK3568_SYS_AUTO_GATING_CTRL, + RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN); + + vop2_writel(vop2, RK3568_SYS0_INT_CLR, + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); + vop2_writel(vop2, RK3568_SYS0_INT_EN, + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); + vop2_writel(vop2, RK3568_SYS1_INT_CLR, + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); + vop2_writel(vop2, RK3568_SYS1_INT_EN, + VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); +} + +static void vop2_disable(struct vop2 *vop2) +{ + pm_runtime_put_sync(vop2->dev); + + clk_disable_unprepare(vop2->aclk); + clk_disable_unprepare(vop2->hclk); +} + +static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + int ret; + + vop2_lock(vop2); + + drm_crtc_vblank_off(crtc); + + /* + * Vop standby will take effect at end of current frame, + * if dsp hold valid irq happen, it means standby complete. + * + * we must wait standby complete when we want to disable aclk, + * if not, memory bus maybe dead. + */ + reinit_completion(&vp->dsp_hold_completion); + + vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID); + + vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY); + + ret = wait_for_completion_timeout(&vp->dsp_hold_completion, + msecs_to_jiffies(50)); + if (!ret) + drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id); + + vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); + + clk_disable_unprepare(vp->dclk); + + vop2->enable_count--; + + if (!vop2->enable_count) + vop2_disable(vop2); + + vop2_unlock(vop2); + + if (crtc->state->event && !crtc->state->active) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + spin_unlock_irq(&crtc->dev->event_lock); + + crtc->state->event = NULL; + } +} + +static int vop2_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *astate) +{ + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane); + struct drm_framebuffer *fb = pstate->fb; + struct drm_crtc *crtc = pstate->crtc; + struct drm_crtc_state *cstate; + struct vop2_video_port *vp; + struct vop2 *vop2; + const struct vop2_data *vop2_data; + struct drm_rect *dest = &pstate->dst; + struct drm_rect *src = &pstate->src; + int min_scale = FRAC_16_16(1, 8); + int max_scale = FRAC_16_16(8, 1); + int format; + int ret; + + if (!crtc) + return 0; + + vp = to_vop2_video_port(crtc); + vop2 = vp->vop2; + vop2_data = vop2->data; + + cstate = drm_atomic_get_existing_crtc_state(pstate->state, crtc); + if (WARN_ON(!cstate)) + return -EINVAL; + + ret = drm_atomic_helper_check_plane_state(pstate, cstate, + min_scale, max_scale, + true, true); + if (ret) + return ret; + + if (!pstate->visible) + return 0; + + format = vop2_convert_format(fb->format->format); + if (format < 0) + return format; + + if (drm_rect_width(src) >> 16 < 4 || drm_rect_height(src) >> 16 < 4 || + drm_rect_width(dest) < 4 || drm_rect_width(dest) < 4) { + drm_err(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", + drm_rect_width(src) >> 16, drm_rect_height(src) >> 16, + drm_rect_width(dest), drm_rect_height(dest)); + pstate->visible = false; + return 0; + } + + if (drm_rect_width(src) >> 16 > vop2_data->max_input.width || + drm_rect_height(src) >> 16 > vop2_data->max_input.height) { + drm_err(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", + drm_rect_width(src) >> 16, + drm_rect_height(src) >> 16, + vop2_data->max_input.width, + vop2_data->max_input.height); + return -EINVAL; + } + + /* + * Src.x1 can be odd when do clip, but yuv plane start point + * need align with 2 pixel. + */ + if (fb->format->is_yuv && ((pstate->src.x1 >> 16) % 2)) { + drm_err(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); + return -EINVAL; + } + + return 0; +} + +static void vop2_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(state, plane); + struct vop2_win *win = to_vop2_win(plane); + struct vop2 *vop2 = win->vop2; + + drm_dbg(vop2->drm, "%s disable\n", win->data->name); + + if (!old_pstate->crtc) + return; + + vop2_win_disable(win); + vop2_win_write(win, VOP2_WIN_YUV_CLIP, 0); +} + +/* + * The color key is 10 bit, so all format should + * convert to 10 bit here. + */ +static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key) +{ + struct drm_plane_state *pstate = plane->state; + struct drm_framebuffer *fb = pstate->fb; + struct vop2_win *win = to_vop2_win(plane); + u32 color_key_en = 0; + u32 r = 0; + u32 g = 0; + u32 b = 0; + + if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) { + vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, 0); + return; + } + + switch (fb->format->format) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + r = (color_key & 0xf800) >> 11; + g = (color_key & 0x7e0) >> 5; + b = (color_key & 0x1f); + r <<= 5; + g <<= 4; + b <<= 5; + color_key_en = 1; + break; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + r = (color_key & 0xff0000) >> 16; + g = (color_key & 0xff00) >> 8; + b = (color_key & 0xff); + r <<= 2; + g <<= 2; + b <<= 2; + color_key_en = 1; + break; + } + + vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, color_key_en); + vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b); +} + +static void vop2_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *pstate = plane->state; + struct drm_crtc *crtc = pstate->crtc; + struct vop2_win *win = to_vop2_win(plane); + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; + struct vop2 *vop2 = win->vop2; + struct drm_framebuffer *fb = pstate->fb; + u32 bpp = fb->format->cpp[0] * 8; + u32 actual_w, actual_h, dsp_w, dsp_h; + u32 act_info, dsp_info; + u32 format; + u32 afbc_format; + u32 rb_swap; + u32 uv_swap; + struct drm_rect *src = &pstate->src; + struct drm_rect *dest = &pstate->dst; + u32 afbc_tile_num; + u32 transform_offset; + bool dither_up; + bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false; + bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false; + bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270; + bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90; + struct rockchip_gem_object *rk_obj; + unsigned long offset; + bool afbc_en; + dma_addr_t yrgb_mst; + dma_addr_t uv_mst; + + /* + * can't update plane when vop2 is disabled. + */ + if (WARN_ON(!crtc)) + return; + + if (!pstate->visible) { + vop2_plane_atomic_disable(plane, state); + return; + } + + afbc_en = rockchip_afbc(plane, fb->modifier); + + offset = (src->x1 >> 16) * fb->format->cpp[0]; + + /* + * AFBC HDR_PTR must set to the zero offset of the framebuffer. + */ + if (afbc_en) + offset = 0; + else if (pstate->rotation & DRM_MODE_REFLECT_Y) + offset += ((src->y2 >> 16) - 1) * fb->pitches[0]; + else + offset += (src->y1 >> 16) * fb->pitches[0]; + + rk_obj = to_rockchip_obj(fb->obj[0]); + + yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; + if (fb->format->is_yuv) { + int hsub = fb->format->hsub; + int vsub = fb->format->vsub; + + offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub; + offset += (src->y1 >> 16) * fb->pitches[1] / vsub; + + if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en) + offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2) / vsub; + + rk_obj = to_rockchip_obj(fb->obj[0]); + uv_mst = rk_obj->dma_addr + offset + fb->offsets[1]; + } + + actual_w = drm_rect_width(src) >> 16; + actual_h = drm_rect_height(src) >> 16; + dsp_w = drm_rect_width(dest); + + if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { + drm_err(vop2->drm, "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", + vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay); + dsp_w = adjusted_mode->hdisplay - dest->x1; + if (dsp_w < 4) + dsp_w = 4; + actual_w = dsp_w * actual_w / drm_rect_width(dest); + } + + dsp_h = drm_rect_height(dest); + + if (dest->y1 + dsp_h > adjusted_mode->vdisplay) { + drm_err(vop2->drm, "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", + vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay); + dsp_h = adjusted_mode->vdisplay - dest->y1; + if (dsp_h < 4) + dsp_h = 4; + actual_h = dsp_h * actual_h / drm_rect_height(dest); + } + + /* + * This is workaround solution for IC design: + * esmart can't support scale down when actual_w % 16 == 1. + */ + if (!(win->data->feature & WIN_FEATURE_AFBDC)) { + if (actual_w > dsp_w && (actual_w & 0xf) == 1) { + drm_err(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", + vp->id, win->data->name, actual_w); + actual_w -= 1; + } + } + + if (afbc_en && actual_w % 4) { + drm_err(vop2->drm, "vp%d %s actual_w[%d] not 4 pixel aligned\n", + vp->id, win->data->name, actual_w); + actual_w = ALIGN_DOWN(actual_w, 4); + } + + act_info = (actual_h - 1) << 16 | ((actual_w - 1) & 0xffff); + dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); + + format = vop2_convert_format(fb->format->format); + + drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n", + vp->id, win->data->name, actual_w, actual_h, dsp_w, dsp_h, + dest->x1, dest->y1, + &fb->format->format, + afbc_en ? "AFBC" : "", &yrgb_mst); + + if (afbc_en) { + u32 stride; + + /* the afbc superblock is 16 x 16 */ + afbc_format = vop2_convert_afbc_format(fb->format->format); + + /* Enable color transform for YTR */ + if (fb->modifier & AFBC_FORMAT_MOD_YTR) + afbc_format |= (1 << 4); + + afbc_tile_num = ALIGN(actual_w, 16) >> 4; + + /* + * AFBC pic_vir_width is count by pixel, this is different + * with WIN_VIR_STRIDE. + */ + stride = (fb->pitches[0] << 3) / bpp; + if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270)) + drm_err(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligened\n", + vp->id, win->data->name, stride); + + rb_swap = vop2_afbc_rb_swap(fb->format->format); + uv_swap = vop2_afbc_uv_swap(fb->format->format); + /* + * This is a workaround for crazy IC design, Cluster + * and Esmart/Smart use different format configuration map: + * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart. + * + * This is one thing we can make the convert simple: + * AFBCD decode all the YUV data to YUV444. So we just + * set all the yuv 10 bit to YUV444_10. + */ + if (fb->format->is_yuv && (bpp == 10)) + format = VOP2_CLUSTER_YUV444_10; + + if (vop2_cluster_window(win)) + vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1); + vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format); + vop2_win_write(win, VOP2_WIN_AFBC_RB_SWAP, rb_swap); + vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap); + vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0); + vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0); + if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90)) { + vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 0); + transform_offset = vop2_afbc_transform_offset(pstate, false); + } else { + vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, 1); + transform_offset = vop2_afbc_transform_offset(pstate, true); + } + vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst); + vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info); + vop2_win_write(win, VOP2_WIN_AFBC_TRANSFORM_OFFSET, transform_offset); + vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1)); + vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16))); + vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride); + vop2_win_write(win, VOP2_WIN_AFBC_TILE_NUM, afbc_tile_num); + vop2_win_write(win, VOP2_WIN_XMIRROR, xmirror); + vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270); + vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90); + } else { + vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4)); + } + + vop2_win_write(win, VOP2_WIN_YMIRROR, ymirror); + + if (rotate_90 || rotate_270) { + act_info = swahw32(act_info); + actual_w = drm_rect_height(src) >> 16; + actual_h = drm_rect_width(src) >> 16; + } + + vop2_win_write(win, VOP2_WIN_FORMAT, format); + vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst); + + rb_swap = vop2_win_rb_swap(fb->format->format); + vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap); + if (!vop2_cluster_window(win)) { + uv_swap = vop2_win_uv_swap(fb->format->format); + vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); + } + + if (fb->format->is_yuv) { + vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4)); + vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst); + } + + vop2_setup_scale(vop2, win, actual_w, actual_h, dsp_w, dsp_h, fb->format->format); + if (!vop2_cluster_window(win)) + vop2_plane_setup_color_key(plane, 0); + vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info); + vop2_win_write(win, VOP2_WIN_DSP_INFO, dsp_info); + vop2_win_write(win, VOP2_WIN_DSP_ST, dest->y1 << 16 | (dest->x1 & 0xffff)); + + vop2_setup_csc_mode(vp, win, pstate); + + dither_up = vop2_win_dither_up(fb->format->format); + vop2_win_write(win, VOP2_WIN_DITHER_UP, dither_up); + + vop2_win_write(win, VOP2_WIN_ENABLE, 1); + + if (vop2_cluster_window(win)) { + int lb_mode = vop2_get_cluster_lb_mode(win, pstate); + + vop2_win_write(win, VOP2_WIN_CLUSTER_LB_MODE, lb_mode); + vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 1); + } +} + +static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = { + .atomic_check = vop2_plane_atomic_check, + .atomic_update = vop2_plane_atomic_update, + .atomic_disable = vop2_plane_atomic_disable, +}; + +static const struct drm_plane_funcs vop2_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .format_mod_supported = rockchip_vop2_mod_supported, +}; + +static int vop2_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + + vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD); + + return 0; +} + +static void vop2_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + + vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD); +} + +static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | + CRTC_STEREO_DOUBLE); + + return true; +} + +static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl) +{ + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + + switch (vcstate->bus_format) { + case MEDIA_BUS_FMT_RGB565_1X16: + *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN; + break; + case MEDIA_BUS_FMT_RGB666_1X18: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN; + *dsp_ctrl |= RGB888_TO_RGB666; + break; + case MEDIA_BUS_FMT_YUV8_1X24: + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN; + break; + default: + break; + } + + if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA) + *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN; + + *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL, + DITHER_DOWN_ALLEGRO); +} + +static void vop2_post_config(struct drm_crtc *crtc) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + u16 vtotal = mode->crtc_vtotal; + u16 hdisplay = mode->crtc_hdisplay; + u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; + u16 vdisplay = mode->crtc_vdisplay; + u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; + u32 left_margin = 100, right_margin = 100; + u32 top_margin = 100, bottom_margin = 100; + u16 hsize = hdisplay * (left_margin + right_margin) / 200; + u16 vsize = vdisplay * (top_margin + bottom_margin) / 200; + u16 hact_end, vact_end; + u32 val; + + vsize = rounddown(vsize, 2); + hsize = rounddown(hsize, 2); + hact_st += hdisplay * (100 - left_margin) / 200; + hact_end = hact_st + hsize; + val = hact_st << 16; + val |= hact_end; + vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val); + vact_st += vdisplay * (100 - top_margin) / 200; + vact_end = vact_st + vsize; + val = vact_st << 16; + val |= vact_end; + vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO, val); + val = scl_cal_scale2(vdisplay, vsize) << 16; + val |= scl_cal_scale2(hdisplay, hsize); + vop2_vp_write(vp, RK3568_VP_POST_SCL_FACTOR_YRGB, val); + + val = 0; + if (hdisplay != hsize) + val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN; + if (vdisplay != vsize) + val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN; + vop2_vp_write(vp, RK3568_VP_POST_SCL_CTRL, val); + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + u16 vact_st_f1 = vtotal + vact_st + 1; + u16 vact_end_f1 = vact_st_f1 + vsize; + + val = vact_st_f1 << 16 | vact_end_f1; + vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val); + } + + vop2_vp_write(vp, RK3568_VP_DSP_BG, 0); +} + +static void rk3568_set_intf_mux(struct vop2_video_port *vp, int id, + u32 polflags) +{ + struct vop2 *vop2 = vp->vop2; + u32 die, dip; + + die = vop2_readl(vop2, RK3568_DSP_IF_EN); + dip = vop2_readl(vop2, RK3568_DSP_IF_POL); + + switch (id) { + case ROCKCHIP_VOP2_EP_RGB0: + die &= ~RK3568_SYS_DSP_INFACE_EN_RGB_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_RGB | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_RGB_MUX, vp->id); + if (polflags & POLFLAG_DCLK_INV) + regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16) | BIT(3)); + else + regmap_write(vop2->grf, RK3568_GRF_VO_CON1, BIT(3 + 16)); + break; + case ROCKCHIP_VOP2_EP_HDMI0: + die &= ~RK3568_SYS_DSP_INFACE_EN_HDMI_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_HDMI | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_HDMI_MUX, vp->id); + break; + case ROCKCHIP_VOP2_EP_EDP0: + die &= ~RK3568_SYS_DSP_INFACE_EN_EDP_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_EDP | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_EDP_MUX, vp->id); + break; + case ROCKCHIP_VOP2_EP_MIPI0: + die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_MIPI0 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_MIPI1: + die &= ~RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_MIPI1 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__MIPI_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__MIPI_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_LVDS0: + die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_LVDS0 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags); + break; + case ROCKCHIP_VOP2_EP_LVDS1: + die &= ~RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX; + die |= RK3568_SYS_DSP_INFACE_EN_LVDS1 | + FIELD_PREP(RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX, vp->id); + dip &= ~RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL; + dip |= FIELD_PREP(RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL, polflags); + break; + default: + drm_err(vop2->drm, "Invalid interface id %d on vp%d\n", id, vp->id); + return; + }; + + dip |= RK3568_DSP_IF_POL__CFG_DONE_IMD; + + vop2_writel(vop2, RK3568_DSP_IF_EN, die); + vop2_writel(vop2, RK3568_DSP_IF_POL, dip); +} + +static int us_to_vertical_line(struct drm_display_mode *mode, int us) +{ + return us * mode->clock / mode->htotal / 1000; +} + +static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + const struct vop2_data *vop2_data = vop2->data; + const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + unsigned long clock = mode->crtc_clock * 1000; + u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + u16 hdisplay = mode->crtc_hdisplay; + u16 htotal = mode->crtc_htotal; + u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; + u16 hact_end = hact_st + hdisplay; + u16 vdisplay = mode->crtc_vdisplay; + u16 vtotal = mode->crtc_vtotal; + u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; + u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; + u16 vact_end = vact_st + vdisplay; + u8 out_mode; + u32 dsp_ctrl = 0; + int act_end; + u32 val, polflags; + int ret; + struct drm_encoder *encoder; + + drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n", + hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p", + drm_mode_vrefresh(mode), vcstate->output_type, vp->id); + + vop2_lock(vop2); + + ret = clk_prepare_enable(vp->dclk); + if (ret < 0) { + drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n", + vp->id, ret); + return; + } + + if (!vop2->enable_count) + vop2_enable(vop2); + + vop2->enable_count++; + + vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY); + + polflags = 0; + if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) + polflags |= POLFLAG_DCLK_INV; + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + polflags |= BIT(HSYNC_POSITIVE); + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + polflags |= BIT(VSYNC_POSITIVE); + + drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { + struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); + + rk3568_set_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); + } + + if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && + !(vp_data->feature & VOP_FEATURE_OUTPUT_10BIT)) + out_mode = ROCKCHIP_OUT_MODE_P888; + else + out_mode = vcstate->output_mode; + + dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode); + + if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode)) + dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP; + + if (is_yuv_output(vcstate->bus_format)) + dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y; + + vop2_dither_setup(crtc, &dsp_ctrl); + + vop2_vp_write(vp, RK3568_VP_DSP_HTOTAL_HS_END, (htotal << 16) | hsync_len); + val = hact_st << 16; + val |= hact_end; + vop2_vp_write(vp, RK3568_VP_DSP_HACT_ST_END, val); + + val = vact_st << 16; + val |= vact_end; + vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END, val); + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + u16 vact_st_f1 = vtotal + vact_st + 1; + u16 vact_end_f1 = vact_st_f1 + vdisplay; + + val = vact_st_f1 << 16 | vact_end_f1; + vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END_F1, val); + + val = vtotal << 16 | (vtotal + vsync_len); + vop2_vp_write(vp, RK3568_VP_DSP_VS_ST_END_F1, val); + dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE; + dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL; + dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN; + vtotal += vtotal + 1; + act_end = vact_end_f1; + } else { + act_end = vact_end; + } + + vop2_writel(vop2, RK3568_VP_LINE_FLAG(vp->id), + (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end); + + vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len); + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) { + dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; + clock *= 2; + } + + vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); + + clk_set_rate(vp->dclk, clock); + + vop2_post_config(crtc); + + vop2_cfg_done(vp); + + vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); + + drm_crtc_vblank_on(crtc); + + vop2_unlock(vop2); +} + +static int vop2_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct drm_plane *plane; + int nplanes = 0; + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) + nplanes++; + + if (nplanes > vp->nlayers) + return -EINVAL; + + return 0; +} + +static bool is_opaque(u16 alpha) +{ + return (alpha >> 8) == 0xff; +} + +static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, + struct vop2_alpha *alpha) +{ + int src_glb_alpha_en = is_opaque(alpha_config->src_glb_alpha_value) ? 0 : 1; + int dst_glb_alpha_en = is_opaque(alpha_config->dst_glb_alpha_value) ? 0 : 1; + int src_color_mode = alpha_config->src_premulti_en ? + ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; + int dst_color_mode = alpha_config->dst_premulti_en ? + ALPHA_SRC_PRE_MUL : ALPHA_SRC_NO_PRE_MUL; + + alpha->src_color_ctrl.val = 0; + alpha->dst_color_ctrl.val = 0; + alpha->src_alpha_ctrl.val = 0; + alpha->dst_alpha_ctrl.val = 0; + + if (!alpha_config->src_pixel_alpha_en) + alpha->src_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; + else if (alpha_config->src_pixel_alpha_en && !src_glb_alpha_en) + alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX; + else + alpha->src_color_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; + + alpha->src_color_ctrl.bits.alpha_en = 1; + + if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_GLOBAL) { + alpha->src_color_ctrl.bits.color_mode = src_color_mode; + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; + } else if (alpha->src_color_ctrl.bits.blend_mode == ALPHA_PER_PIX) { + alpha->src_color_ctrl.bits.color_mode = src_color_mode; + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_ONE; + } else { + alpha->src_color_ctrl.bits.color_mode = ALPHA_SRC_PRE_MUL; + alpha->src_color_ctrl.bits.factor_mode = SRC_FAC_ALPHA_SRC_GLOBAL; + } + alpha->src_color_ctrl.bits.glb_alpha = alpha_config->src_glb_alpha_value >> 8; + alpha->src_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + alpha->src_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; + + alpha->dst_color_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + alpha->dst_color_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; + alpha->dst_color_ctrl.bits.blend_mode = ALPHA_GLOBAL; + alpha->dst_color_ctrl.bits.glb_alpha = alpha_config->dst_glb_alpha_value >> 8; + alpha->dst_color_ctrl.bits.color_mode = dst_color_mode; + alpha->dst_color_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; + + alpha->src_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + alpha->src_alpha_ctrl.bits.blend_mode = alpha->src_color_ctrl.bits.blend_mode; + alpha->src_alpha_ctrl.bits.alpha_cal_mode = ALPHA_SATURATION; + alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE; + + alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; + if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en) + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX; + else + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; + alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION; + alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; +} + +static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id) +{ + struct vop2_video_port *vp; + int used_layer = 0; + int i; + + for (i = 0; i < port_id; i++) { + vp = &vop2->vps[i]; + used_layer += hweight32(vp->win_mask); + } + + return used_layer; +} + +static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win) +{ + u32 offset = (main_win->data->phys_id * 0x10); + struct vop2_alpha_config alpha_config; + struct vop2_alpha alpha; + struct drm_plane_state *bottom_win_pstate; + bool src_pixel_alpha_en = false; + u16 src_glb_alpha_val, dst_glb_alpha_val; + bool premulti_en = false; + bool swap = false; + + /* At one win mode, win0 is dst/bottom win, and win1 is a all zero src/top win */ + bottom_win_pstate = main_win->base.state; + src_glb_alpha_val = 0; + dst_glb_alpha_val = main_win->base.state->alpha; + + if (!bottom_win_pstate->fb) + return; + + alpha_config.src_premulti_en = premulti_en; + alpha_config.dst_premulti_en = false; + alpha_config.src_pixel_alpha_en = src_pixel_alpha_en; + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ + alpha_config.src_glb_alpha_value = src_glb_alpha_val; + alpha_config.dst_glb_alpha_value = dst_glb_alpha_val; + vop2_parse_alpha(&alpha_config, &alpha); + + alpha.src_color_ctrl.bits.src_dst_swap = swap; + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL + offset, + alpha.src_color_ctrl.val); + vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_COLOR_CTRL + offset, + alpha.dst_color_ctrl.val); + vop2_writel(vop2, RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL + offset, + alpha.src_alpha_ctrl.val); + vop2_writel(vop2, RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL + offset, + alpha.dst_alpha_ctrl.val); +} + +static void vop2_setup_alpha(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_framebuffer *fb; + struct vop2_alpha_config alpha_config; + struct vop2_alpha alpha; + struct drm_plane *plane; + int pixel_alpha_en; + int premulti_en, gpremulti_en = 0; + int mixer_id; + u32 offset; + bool bottom_layer_alpha_en = false; + u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE; + + mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id); + alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + + if (plane->state->normalized_zpos == 0 && + !is_opaque(plane->state->alpha) && + !vop2_cluster_window(win)) { + /* + * If bottom layer have global alpha effect [except cluster layer, + * because cluster have deal with bottom layer global alpha value + * at cluster mix], bottom layer mix need deal with global alpha. + */ + bottom_layer_alpha_en = true; + dst_global_alpha = plane->state->alpha; + } + } + + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + int zpos = plane->state->normalized_zpos; + + if (plane->state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) + premulti_en = 1; + else + premulti_en = 0; + + plane = &win->base; + fb = plane->state->fb; + + pixel_alpha_en = fb->format->has_alpha; + + alpha_config.src_premulti_en = premulti_en; + + if (bottom_layer_alpha_en && zpos == 1) { + gpremulti_en = premulti_en; + /* Cd = Cs + (1 - As) * Cd * Agd */ + alpha_config.dst_premulti_en = false; + alpha_config.src_pixel_alpha_en = pixel_alpha_en; + alpha_config.src_glb_alpha_value = plane->state->alpha; + alpha_config.dst_glb_alpha_value = dst_global_alpha; + } else if (vop2_cluster_window(win)) { + /* Mix output data only have pixel alpha */ + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = true; + alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + } else { + /* Cd = Cs + (1 - As) * Cd */ + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = pixel_alpha_en; + alpha_config.src_glb_alpha_value = plane->state->alpha; + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + } + + vop2_parse_alpha(&alpha_config, &alpha); + + offset = (mixer_id + zpos - 1) * 0x10; + vop2_writel(vop2, RK3568_MIX0_SRC_COLOR_CTRL + offset, + alpha.src_color_ctrl.val); + vop2_writel(vop2, RK3568_MIX0_DST_COLOR_CTRL + offset, + alpha.dst_color_ctrl.val); + vop2_writel(vop2, RK3568_MIX0_SRC_ALPHA_CTRL + offset, + alpha.src_alpha_ctrl.val); + vop2_writel(vop2, RK3568_MIX0_DST_ALPHA_CTRL + offset, + alpha.dst_alpha_ctrl.val); + } + + if (vp->id == 0) { + if (bottom_layer_alpha_en) { + /* Transfer pixel alpha to hdr mix */ + alpha_config.src_premulti_en = gpremulti_en; + alpha_config.dst_premulti_en = true; + alpha_config.src_pixel_alpha_en = true; + alpha_config.src_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + alpha_config.dst_glb_alpha_value = DRM_BLEND_ALPHA_OPAQUE; + vop2_parse_alpha(&alpha_config, &alpha); + + vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, + alpha.src_color_ctrl.val); + vop2_writel(vop2, RK3568_HDR0_DST_COLOR_CTRL, + alpha.dst_color_ctrl.val); + vop2_writel(vop2, RK3568_HDR0_SRC_ALPHA_CTRL, + alpha.src_alpha_ctrl.val); + vop2_writel(vop2, RK3568_HDR0_DST_ALPHA_CTRL, + alpha.dst_alpha_ctrl.val); + } else { + vop2_writel(vop2, RK3568_HDR0_SRC_COLOR_CTRL, 0); + } + } +} + +static void vop2_setup_layer_mixer(struct vop2_video_port *vp) +{ + struct vop2 *vop2 = vp->vop2; + struct drm_plane *plane; + u32 layer_sel = 0; + u32 port_sel; + unsigned int nlayer, ofs; + struct drm_display_mode *adjusted_mode; + u16 hsync_len; + u16 hdisplay; + u32 bg_dly; + u32 pre_scan_dly; + int i; + struct vop2_video_port *vp0 = &vop2->vps[0]; + struct vop2_video_port *vp1 = &vop2->vps[1]; + struct vop2_video_port *vp2 = &vop2->vps[2]; + + adjusted_mode = &vp->crtc.state->adjusted_mode; + hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + hdisplay = adjusted_mode->crtc_hdisplay; + + bg_dly = vp->data->pre_scan_max_dly[3]; + vop2_writel(vop2, RK3568_VP_BG_MIX_CTRL(vp->id), + FIELD_PREP(RK3568_VP_BG_MIX_CTRL__BG_DLY, bg_dly)); + + pre_scan_dly = ((bg_dly + (hdisplay >> 1) - 1) << 16) | hsync_len; + vop2_vp_write(vp, RK3568_VP_PRE_SCAN_HTIMING, pre_scan_dly); + + vop2_writel(vop2, RK3568_OVL_CTRL, 0); + port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL); + port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT; + + if (vp0->nlayers) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, + vp0->nlayers - 1); + else + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT0_MUX, 8); + + if (vp1->nlayers) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, + (vp0->nlayers + vp1->nlayers - 1)); + else + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); + + if (vp2->nlayers) + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT2_MUX, + (vp2->nlayers + vp1->nlayers + vp0->nlayers - 1)); + else + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SET__PORT1_MUX, 8); + + layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); + + ofs = 0; + for (i = 0; i < vp->id; i++) + ofs += vop2->vps[i].nlayers; + + nlayer = 0; + drm_atomic_crtc_for_each_plane(plane, &vp->crtc) { + struct vop2_win *win = to_vop2_win(plane); + + switch (win->data->phys_id) { + case ROCKCHIP_VOP2_CLUSTER0: + port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER0; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER0, vp->id); + break; + case ROCKCHIP_VOP2_CLUSTER1: + port_sel &= ~RK3568_OVL_PORT_SEL__CLUSTER1; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__CLUSTER1, vp->id); + break; + case ROCKCHIP_VOP2_ESMART0: + port_sel &= ~RK3568_OVL_PORT_SEL__ESMART0; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART0, vp->id); + break; + case ROCKCHIP_VOP2_ESMART1: + port_sel &= ~RK3568_OVL_PORT_SEL__ESMART1; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__ESMART1, vp->id); + break; + case ROCKCHIP_VOP2_SMART0: + port_sel &= ~RK3568_OVL_PORT_SEL__SMART0; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART0, vp->id); + break; + case ROCKCHIP_VOP2_SMART1: + port_sel &= ~RK3568_OVL_PORT_SEL__SMART1; + port_sel |= FIELD_PREP(RK3568_OVL_PORT_SEL__SMART1, vp->id); + break; + } + + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, win->data->layer_sel_id); + nlayer++; + } + + /* configure unused layers to 0x5 (reserved) */ + for (; nlayer < vp->nlayers; nlayer++) { + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 5); + } + + vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); + vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel); + vop2_writel(vop2, RK3568_OVL_CTRL, RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD); +} + +static void vop2_setup_dly_for_windows(struct vop2 *vop2) +{ + struct vop2_win *win; + int i = 0; + u32 cdly = 0, sdly = 0; + + for (i = 0; i < vop2->data->win_size; i++) { + u32 dly; + + win = &vop2->win[i]; + dly = win->delay; + + switch (win->data->phys_id) { + case ROCKCHIP_VOP2_CLUSTER0: + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_0, dly); + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER0_1, dly); + break; + case ROCKCHIP_VOP2_CLUSTER1: + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_0, dly); + cdly |= FIELD_PREP(RK3568_CLUSTER_DLY_NUM__CLUSTER1_1, dly); + break; + case ROCKCHIP_VOP2_ESMART0: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART0, dly); + break; + case ROCKCHIP_VOP2_ESMART1: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly); + break; + case ROCKCHIP_VOP2_SMART0: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); + break; + case ROCKCHIP_VOP2_SMART1: + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); + break; + } + } + + vop2_writel(vop2, RK3568_CLUSTER_DLY_NUM, cdly); + vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly); +} + +static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + struct vop2 *vop2 = vp->vop2; + struct drm_plane *plane; + + vp->win_mask = 0; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct vop2_win *win = to_vop2_win(plane); + + win->delay = win->data->dly[VOP2_DLY_MODE_DEFAULT]; + + vp->win_mask |= BIT(win->data->phys_id); + + if (vop2_cluster_window(win)) + vop2_setup_cluster_alpha(vop2, win); + } + + if (!vp->win_mask) + return; + + vop2_setup_layer_mixer(vp); + vop2_setup_alpha(vp); + vop2_setup_dly_for_windows(vop2); +} + +static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct vop2_video_port *vp = to_vop2_video_port(crtc); + + vop2_post_config(crtc); + + vop2_cfg_done(vp); + + spin_lock_irq(&crtc->dev->event_lock); + + if (crtc->state->event) { + WARN_ON(drm_crtc_vblank_get(crtc)); + vp->event = crtc->state->event; + crtc->state->event = NULL; + } + + spin_unlock_irq(&crtc->dev->event_lock); +} + +static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { + .mode_fixup = vop2_crtc_mode_fixup, + .atomic_check = vop2_crtc_atomic_check, + .atomic_begin = vop2_crtc_atomic_begin, + .atomic_flush = vop2_crtc_atomic_flush, + .atomic_enable = vop2_crtc_atomic_enable, + .atomic_disable = vop2_crtc_atomic_disable, +}; + +static void vop2_crtc_reset(struct drm_crtc *crtc) +{ + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); + + if (crtc->state) { + __drm_atomic_helper_crtc_destroy_state(crtc->state); + kfree(vcstate); + } + + vcstate = kzalloc(sizeof(*vcstate), GFP_KERNEL); + if (!vcstate) + return; + + crtc->state = &vcstate->base; + crtc->state->crtc = crtc; +} + +static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct rockchip_crtc_state *vcstate, *old_vcstate; + + old_vcstate = to_rockchip_crtc_state(crtc->state); + + vcstate = kmemdup(old_vcstate, sizeof(*old_vcstate), GFP_KERNEL); + if (!vcstate) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base); + + return &vcstate->base; +} + +static void vop2_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state); + + __drm_atomic_helper_crtc_destroy_state(&vcstate->base); + kfree(vcstate); +} + +static const struct drm_crtc_funcs vop2_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .destroy = drm_crtc_cleanup, + .reset = vop2_crtc_reset, + .atomic_duplicate_state = vop2_crtc_duplicate_state, + .atomic_destroy_state = vop2_crtc_destroy_state, + .enable_vblank = vop2_crtc_enable_vblank, + .disable_vblank = vop2_crtc_disable_vblank, +}; + +static irqreturn_t vop2_isr(int irq, void *data) +{ + struct vop2 *vop2 = data; + const struct vop2_data *vop2_data = vop2->data; + u32 axi_irqs[VOP2_SYS_AXI_BUS_NUM]; + int ret = IRQ_NONE; + int i; + + /* + * The irq is shared with the iommu. If the runtime-pm state of the + * vop2-device is disabled the irq has to be targeted at the iommu. + */ + if (!pm_runtime_get_if_in_use(vop2->dev)) + return IRQ_NONE; + + for (i = 0; i < vop2_data->nr_vps; i++) { + struct vop2_video_port *vp = &vop2->vps[i]; + struct drm_crtc *crtc = &vp->crtc; + u32 irqs; + + irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); + vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); + + if (irqs & VP_INT_DSP_HOLD_VALID) { + complete(&vp->dsp_hold_completion); + ret = IRQ_HANDLED; + } + + if (irqs & VP_INT_FS_FIELD) { + drm_crtc_handle_vblank(crtc); + spin_lock(&crtc->dev->event_lock); + if (vp->event) { + u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); + + if (!(val & BIT(vp->id))) { + drm_crtc_send_vblank_event(crtc, vp->event); + vp->event = NULL; + drm_crtc_vblank_put(crtc); + } + } + spin_unlock(&crtc->dev->event_lock); + + ret = IRQ_HANDLED; + } + + if (irqs & VP_INT_POST_BUF_EMPTY) { + drm_err_ratelimited(vop2->drm, + "POST_BUF_EMPTY irq err at vp%d\n", + vp->id); + ret = IRQ_HANDLED; + } + } + + axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS); + vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]); + axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS); + vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]); + + for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) { + if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) { + drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n"); + ret = IRQ_HANDLED; + } + } + + pm_runtime_put(vop2->dev); + + return ret; +} + +static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, + unsigned long possible_crtcs) +{ + const struct vop2_win_data *win_data = win->data; + unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE); + int ret; + + ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs, + &vop2_plane_funcs, win_data->formats, + win_data->nformats, + win_data->format_modifiers, + win->type, win_data->name); + if (ret) { + drm_err(vop2->drm, "failed to initialize plane %d\n", ret); + return ret; + } + + drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs); + + if (win->data->supported_rotations) + drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0, + DRM_MODE_ROTATE_0 | + win->data->supported_rotations); + drm_plane_create_alpha_property(&win->base); + drm_plane_create_blend_mode_property(&win->base, blend_caps); + drm_plane_create_zpos_property(&win->base, win->win_id, 0, + vop2->registered_num_wins - 1); + + return 0; +} + +static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2) +{ + int i; + + for (i = 0; i < vop2->data->nr_vps; i++) { + struct vop2_video_port *vp = &vop2->vps[i]; + + if (!vp->crtc.port) + continue; + if (vp->primary_plane) + continue; + + return vp; + } + + return NULL; +} + +#define NR_LAYERS 6 + +static int vop2_create_crtc(struct vop2 *vop2) +{ + const struct vop2_data *vop2_data = vop2->data; + struct drm_device *drm = vop2->drm; + struct device *dev = vop2->dev; + struct drm_plane *plane; + struct device_node *port; + struct vop2_video_port *vp; + int i, nvp, nvps = 0; + int ret; + + for (i = 0; i < vop2_data->nr_vps; i++) { + const struct vop2_video_port_data *vp_data; + struct device_node *np; + char dclk_name[9]; + + vp_data = &vop2_data->vp[i]; + vp = &vop2->vps[i]; + vp->vop2 = vop2; + vp->id = vp_data->id; + vp->regs = vp_data->regs; + vp->data = vp_data; + + snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id); + vp->dclk = devm_clk_get(vop2->dev, dclk_name); + if (IS_ERR(vp->dclk)) { + drm_err(vop2->drm, "failed to get %s\n", dclk_name); + return PTR_ERR(vp->dclk); + } + + np = of_graph_get_remote_node(dev->of_node, i, -1); + if (!np) { + drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i); + continue; + } + of_node_put(np); + + port = of_graph_get_port_by_id(dev->of_node, i); + if (!port) { + drm_err(vop2->drm, "no port node found for video_port%d\n", i); + return -ENOENT; + } + + vp->crtc.port = port; + nvps++; + } + + nvp = 0; + for (i = 0; i < vop2->registered_num_wins; i++) { + struct vop2_win *win = &vop2->win[i]; + u32 possible_crtcs; + + if (win->type == DRM_PLANE_TYPE_PRIMARY) { + vp = find_vp_without_primary(vop2); + if (vp) { + possible_crtcs = BIT(nvp); + vp->primary_plane = win; + nvp++; + } else { + /* change the unused primary window to overlay window */ + win->type = DRM_PLANE_TYPE_OVERLAY; + } + } + + if (win->type == DRM_PLANE_TYPE_OVERLAY) + possible_crtcs = (1 << nvps) - 1; + + ret = vop2_plane_init(vop2, win, possible_crtcs); + if (ret) { + drm_err(vop2->drm, "failed to init plane %s: %d\n", + win->data->name, ret); + return ret; + } + } + + for (i = 0; i < vop2_data->nr_vps; i++) { + vp = &vop2->vps[i]; + + if (!vp->crtc.port) + continue; + + plane = &vp->primary_plane->base; + + ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL, + &vop2_crtc_funcs, + "video_port%d", vp->id); + if (ret) { + drm_err(vop2->drm, "crtc init for video_port%d failed\n", i); + return ret; + } + + drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs); + + init_completion(&vp->dsp_hold_completion); + } + + /* + * On the VOP2 it's very hard to change the number of layers on a VP + * during runtime, so we distribute the layers equally over the used + * VPs + */ + for (i = 0; i < vop2->data->nr_vps; i++) { + struct vop2_video_port *vp = &vop2->vps[i]; + + if (vp->crtc.port) + vp->nlayers = NR_LAYERS / nvps; + } + + return 0; +} + +static void vop2_destroy_crtc(struct drm_crtc *crtc) +{ + of_node_put(crtc->port); + + /* + * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane() + * references the CRTC. + */ + drm_crtc_cleanup(crtc); +} + +static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] = { + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 0, 0), + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 1, 5), + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 14, 14), + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 18, 18), + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_ACT_INFO, 0, 31), + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_INFO, 0, 31), + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_CLUSTER_WIN_DSP_ST, 0, 31), + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_CLUSTER_WIN_YRGB_MST, 0, 31), + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_CLUSTER_WIN_CBR_MST, 0, 31), + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 19, 19), + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 0, 15), + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_CLUSTER_WIN_VIR, 16, 31), + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 8, 8), + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 9, 9), + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL0, 10, 11), + + /* Scale */ + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 0, 15), + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB, 16, 31), + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 14, 15), + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 12, 13), + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 2, 3), + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 28, 28), + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_CLUSTER_WIN_CTRL1, 29, 29), + + /* cluster regs */ + [VOP2_WIN_AFBC_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 1, 1), + [VOP2_WIN_CLUSTER_ENABLE] = REG_FIELD(RK3568_CLUSTER_CTRL, 0, 0), + [VOP2_WIN_CLUSTER_LB_MODE] = REG_FIELD(RK3568_CLUSTER_CTRL, 4, 7), + + /* afbc regs */ + [VOP2_WIN_AFBC_FORMAT] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 2, 6), + [VOP2_WIN_AFBC_RB_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 9, 9), + [VOP2_WIN_AFBC_UV_SWAP] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 10, 10), + [VOP2_WIN_AFBC_AUTO_GATING_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL, 4, 4), + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 7, 7), + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_CTRL, 8, 8), + [VOP2_WIN_AFBC_HDR_PTR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_HDR_PTR, 0, 31), + [VOP2_WIN_AFBC_PIC_SIZE] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE, 0, 31), + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 0, 15), + [VOP2_WIN_AFBC_TILE_NUM] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH, 16, 31), + [VOP2_WIN_AFBC_PIC_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET, 0, 31), + [VOP2_WIN_AFBC_DSP_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET, 0, 31), + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET, 0, 31), + [VOP2_WIN_AFBC_ROTATE_90] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 0, 0), + [VOP2_WIN_AFBC_ROTATE_270] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 1, 1), + [VOP2_WIN_XMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 2, 2), + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE, 3, 3), + [VOP2_WIN_UV_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_COLOR_KEY] = { .reg = 0xffffffff }, + [VOP2_WIN_COLOR_KEY_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_SCALE_CBCR_X] = { .reg = 0xffffffff }, + [VOP2_WIN_SCALE_CBCR_Y] = { .reg = 0xffffffff }, + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_VER_SCL_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_HOR_SCL_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_VSD_CBCR_GT2] = { .reg = 0xffffffff }, + [VOP2_WIN_VSD_CBCR_GT4] = { .reg = 0xffffffff }, +}; + +static int vop2_cluster_init(struct vop2_win *win) +{ + struct vop2 *vop2 = win->vop2; + struct reg_field *cluster_regs; + int ret, i; + + cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs), + GFP_KERNEL); + if (!cluster_regs) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++) + if (cluster_regs[i].reg != 0xffffffff) + cluster_regs[i].reg += win->offset; + + ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg, + cluster_regs, + ARRAY_SIZE(vop2_cluster_regs)); + + kfree(cluster_regs); + + return ret; +}; + +static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] = { + [VOP2_WIN_ENABLE] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 0, 0), + [VOP2_WIN_FORMAT] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 1, 5), + [VOP2_WIN_DITHER_UP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 12, 12), + [VOP2_WIN_RB_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 14, 14), + [VOP2_WIN_UV_SWAP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 16, 16), + [VOP2_WIN_ACT_INFO] = REG_FIELD(RK3568_SMART_REGION0_ACT_INFO, 0, 31), + [VOP2_WIN_DSP_INFO] = REG_FIELD(RK3568_SMART_REGION0_DSP_INFO, 0, 31), + [VOP2_WIN_DSP_ST] = REG_FIELD(RK3568_SMART_REGION0_DSP_ST, 0, 28), + [VOP2_WIN_YRGB_MST] = REG_FIELD(RK3568_SMART_REGION0_YRGB_MST, 0, 31), + [VOP2_WIN_UV_MST] = REG_FIELD(RK3568_SMART_REGION0_CBR_MST, 0, 31), + [VOP2_WIN_YUV_CLIP] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 17, 17), + [VOP2_WIN_YRGB_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 0, 15), + [VOP2_WIN_UV_VIR] = REG_FIELD(RK3568_SMART_REGION0_VIR, 16, 31), + [VOP2_WIN_Y2R_EN] = REG_FIELD(RK3568_SMART_CTRL0, 0, 0), + [VOP2_WIN_R2Y_EN] = REG_FIELD(RK3568_SMART_CTRL0, 1, 1), + [VOP2_WIN_CSC_MODE] = REG_FIELD(RK3568_SMART_CTRL0, 2, 3), + [VOP2_WIN_YMIRROR] = REG_FIELD(RK3568_SMART_CTRL1, 31, 31), + [VOP2_WIN_COLOR_KEY] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 0, 29), + [VOP2_WIN_COLOR_KEY_EN] = REG_FIELD(RK3568_SMART_COLOR_KEY_CTRL, 31, 31), + + /* Scale */ + [VOP2_WIN_SCALE_YRGB_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 0, 15), + [VOP2_WIN_SCALE_YRGB_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_YRGB, 16, 31), + [VOP2_WIN_SCALE_CBCR_X] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 0, 15), + [VOP2_WIN_SCALE_CBCR_Y] = REG_FIELD(RK3568_SMART_REGION0_SCL_FACTOR_CBR, 16, 31), + [VOP2_WIN_YRGB_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 0, 1), + [VOP2_WIN_YRGB_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 2, 3), + [VOP2_WIN_YRGB_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 4, 5), + [VOP2_WIN_YRGB_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 6, 7), + [VOP2_WIN_CBCR_HOR_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 8, 9), + [VOP2_WIN_CBCR_HSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 10, 11), + [VOP2_WIN_CBCR_VER_SCL_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 12, 13), + [VOP2_WIN_CBCR_VSCL_FILTER_MODE] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 14, 15), + [VOP2_WIN_BIC_COE_SEL] = REG_FIELD(RK3568_SMART_REGION0_SCL_CTRL, 16, 17), + [VOP2_WIN_VSD_YRGB_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 8, 8), + [VOP2_WIN_VSD_YRGB_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 9, 9), + [VOP2_WIN_VSD_CBCR_GT2] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 10, 10), + [VOP2_WIN_VSD_CBCR_GT4] = REG_FIELD(RK3568_SMART_REGION0_CTRL, 11, 11), + [VOP2_WIN_XMIRROR] = { .reg = 0xffffffff }, + [VOP2_WIN_CLUSTER_ENABLE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ENABLE] = { .reg = 0xffffffff }, + [VOP2_WIN_CLUSTER_LB_MODE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_FORMAT] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_RB_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_UV_SWAP] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_AUTO_GATING_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_BLOCK_SPLIT_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_VIR_WIDTH] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_TILE_NUM] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_PIC_SIZE] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_DSP_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_TRANSFORM_OFFSET] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_HDR_PTR] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_HALF_BLOCK_EN] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ROTATE_270] = { .reg = 0xffffffff }, + [VOP2_WIN_AFBC_ROTATE_90] = { .reg = 0xffffffff }, +}; + +static int vop2_esmart_init(struct vop2_win *win) +{ + struct vop2 *vop2 = win->vop2; + struct reg_field *esmart_regs; + int ret, i; + + esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs), + GFP_KERNEL); + if (!esmart_regs) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++) + if (esmart_regs[i].reg != 0xffffffff) + esmart_regs[i].reg += win->offset; + + ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg, + esmart_regs, + ARRAY_SIZE(vop2_esmart_regs)); + + kfree(esmart_regs); + + return ret; +}; + +static int vop2_win_init(struct vop2 *vop2) +{ + const struct vop2_data *vop2_data = vop2->data; + struct vop2_win *win; + int i, ret; + + for (i = 0; i < vop2_data->win_size; i++) { + const struct vop2_win_data *win_data = &vop2_data->win[i]; + + win = &vop2->win[i]; + win->data = win_data; + win->type = win_data->type; + win->offset = win_data->base; + win->win_id = i; + win->vop2 = vop2; + if (vop2_cluster_window(win)) + ret = vop2_cluster_init(win); + else + ret = vop2_esmart_init(win); + if (ret) + return ret; + } + + vop2->registered_num_wins = vop2_data->win_size; + + return 0; +} + +/* + * The window registers are only updated when config done is written. + * Until that they read back the old value. As we read-modify-write + * these registers mark them as non-volatile. This makes sure we read + * the new values from the regmap register cache. + */ +static const struct regmap_range vop2_nonvolatile_range[] = { + regmap_reg_range(0x1000, 0x23ff), +}; + +static const struct regmap_access_table vop2_volatile_table = { + .no_ranges = vop2_nonvolatile_range, + .n_no_ranges = ARRAY_SIZE(vop2_nonvolatile_range), +}; + +static const struct regmap_config vop2_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x3000, + .name = "vop2", + .volatile_table = &vop2_volatile_table, + .cache_type = REGCACHE_RBTREE, +}; + +static int vop2_bind(struct device *dev, struct device *master, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + const struct vop2_data *vop2_data; + struct drm_device *drm = data; + struct vop2 *vop2; + struct resource *res; + size_t alloc_size; + int ret; + + vop2_data = of_device_get_match_data(dev); + if (!vop2_data) + return -ENODEV; + + /* Allocate vop2 struct and its vop2_win array */ + alloc_size = sizeof(*vop2) + sizeof(*vop2->win) * vop2_data->win_size; + vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL); + if (!vop2) + return -ENOMEM; + + vop2->dev = dev; + vop2->data = vop2_data; + vop2->drm = drm; + + dev_set_drvdata(dev, vop2); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); + if (!res) { + drm_err(vop2->drm, "failed to get vop2 register byname\n"); + return -EINVAL; + } + + vop2->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(vop2->regs)) + return PTR_ERR(vop2->regs); + vop2->len = resource_size(res); + + vop2->map = devm_regmap_init_mmio(dev, vop2->regs, &vop2_regmap_config); + + ret = vop2_win_init(vop2); + if (ret) + return ret; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma_lut"); + if (res) { + vop2->lut_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(vop2->lut_regs)) + return PTR_ERR(vop2->lut_regs); + } + + vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); + + vop2->hclk = devm_clk_get(vop2->dev, "hclk"); + if (IS_ERR(vop2->hclk)) { + drm_err(vop2->drm, "failed to get hclk source\n"); + return PTR_ERR(vop2->hclk); + } + + vop2->aclk = devm_clk_get(vop2->dev, "aclk"); + if (IS_ERR(vop2->aclk)) { + drm_err(vop2->drm, "failed to get aclk source\n"); + return PTR_ERR(vop2->aclk); + } + + vop2->irq = platform_get_irq(pdev, 0); + if (vop2->irq < 0) { + drm_err(vop2->drm, "cannot find irq for vop2\n"); + return vop2->irq; + } + + mutex_init(&vop2->vop2_lock); + + ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2); + if (ret) + return ret; + + ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev); + if (ret) { + drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret); + return ret; + } + + ret = vop2_create_crtc(vop2); + if (ret) + return ret; + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static void vop2_unbind(struct device *dev, struct device *master, void *data) +{ + struct vop2 *vop2 = dev_get_drvdata(dev); + struct drm_device *drm = vop2->drm; + struct list_head *plane_list = &drm->mode_config.plane_list; + struct list_head *crtc_list = &drm->mode_config.crtc_list; + struct drm_crtc *crtc, *tmpc; + struct drm_plane *plane, *tmpp; + + rockchip_drm_dma_detach_device(vop2->drm, vop2->dev); + + pm_runtime_disable(dev); + + list_for_each_entry_safe(plane, tmpp, plane_list, head) + drm_plane_cleanup(plane); + + list_for_each_entry_safe(crtc, tmpc, crtc_list, head) + vop2_destroy_crtc(crtc); +} + +const struct component_ops vop2_component_ops = { + .bind = vop2_bind, + .unbind = vop2_unbind, +}; +EXPORT_SYMBOL_GPL(vop2_component_ops); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h new file mode 100644 index 0000000000000..c727093a06d68 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -0,0 +1,477 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author:Mark Yao mark.yao@rock-chips.com + */ + +#ifndef _ROCKCHIP_DRM_VOP2_H +#define _ROCKCHIP_DRM_VOP2_H + +#include "rockchip_drm_vop.h" + +#include <linux/regmap.h> +#include <drm/drm_modes.h> + +#define VOP_FEATURE_OUTPUT_10BIT BIT(0) + +#define WIN_FEATURE_AFBDC BIT(0) +#define WIN_FEATURE_CLUSTER BIT(1) + +/* + * the delay number of a window in different mode. + */ +enum win_dly_mode { + VOP2_DLY_MODE_DEFAULT, /**< default mode */ + VOP2_DLY_MODE_HISO_S, /** HDR in SDR out mode, as a SDR window */ + VOP2_DLY_MODE_HIHO_H, /** HDR in HDR out mode, as a HDR window */ + VOP2_DLY_MODE_MAX, +}; + +struct vop_rect { + int width; + int height; +}; + +enum vop2_scale_up_mode { + VOP2_SCALE_UP_NRST_NBOR, + VOP2_SCALE_UP_BIL, + VOP2_SCALE_UP_BIC, +}; + +enum vop2_scale_down_mode { + VOP2_SCALE_DOWN_NRST_NBOR, + VOP2_SCALE_DOWN_BIL, + VOP2_SCALE_DOWN_AVG, +}; + +enum vop2_win_regs { + VOP2_WIN_ENABLE, + VOP2_WIN_FORMAT, + VOP2_WIN_CSC_MODE, + VOP2_WIN_XMIRROR, + VOP2_WIN_YMIRROR, + VOP2_WIN_RB_SWAP, + VOP2_WIN_UV_SWAP, + VOP2_WIN_ACT_INFO, + VOP2_WIN_DSP_INFO, + VOP2_WIN_DSP_ST, + VOP2_WIN_YRGB_MST, + VOP2_WIN_UV_MST, + VOP2_WIN_YRGB_VIR, + VOP2_WIN_UV_VIR, + VOP2_WIN_YUV_CLIP, + VOP2_WIN_Y2R_EN, + VOP2_WIN_R2Y_EN, + VOP2_WIN_COLOR_KEY, + VOP2_WIN_COLOR_KEY_EN, + VOP2_WIN_DITHER_UP, + + /* scale regs */ + VOP2_WIN_SCALE_YRGB_X, + VOP2_WIN_SCALE_YRGB_Y, + VOP2_WIN_SCALE_CBCR_X, + VOP2_WIN_SCALE_CBCR_Y, + VOP2_WIN_YRGB_HOR_SCL_MODE, + VOP2_WIN_YRGB_HSCL_FILTER_MODE, + VOP2_WIN_YRGB_VER_SCL_MODE, + VOP2_WIN_YRGB_VSCL_FILTER_MODE, + VOP2_WIN_CBCR_VER_SCL_MODE, + VOP2_WIN_CBCR_HSCL_FILTER_MODE, + VOP2_WIN_CBCR_HOR_SCL_MODE, + VOP2_WIN_CBCR_VSCL_FILTER_MODE, + VOP2_WIN_VSD_CBCR_GT2, + VOP2_WIN_VSD_CBCR_GT4, + VOP2_WIN_VSD_YRGB_GT2, + VOP2_WIN_VSD_YRGB_GT4, + VOP2_WIN_BIC_COE_SEL, + + /* cluster regs */ + VOP2_WIN_CLUSTER_ENABLE, + VOP2_WIN_AFBC_ENABLE, + VOP2_WIN_CLUSTER_LB_MODE, + + /* afbc regs */ + VOP2_WIN_AFBC_FORMAT, + VOP2_WIN_AFBC_RB_SWAP, + VOP2_WIN_AFBC_UV_SWAP, + VOP2_WIN_AFBC_AUTO_GATING_EN, + VOP2_WIN_AFBC_BLOCK_SPLIT_EN, + VOP2_WIN_AFBC_PIC_VIR_WIDTH, + VOP2_WIN_AFBC_TILE_NUM, + VOP2_WIN_AFBC_PIC_OFFSET, + VOP2_WIN_AFBC_PIC_SIZE, + VOP2_WIN_AFBC_DSP_OFFSET, + VOP2_WIN_AFBC_TRANSFORM_OFFSET, + VOP2_WIN_AFBC_HDR_PTR, + VOP2_WIN_AFBC_HALF_BLOCK_EN, + VOP2_WIN_AFBC_ROTATE_270, + VOP2_WIN_AFBC_ROTATE_90, + VOP2_WIN_MAX_REG, +}; + +struct vop2_win_data { + const char *name; + unsigned int phys_id; + + u32 base; + enum drm_plane_type type; + + u32 nformats; + const u32 *formats; + const uint64_t *format_modifiers; + const unsigned int supported_rotations; + + /** + * @layer_sel_id: defined by register OVERLAY_LAYER_SEL of VOP2 + */ + unsigned int layer_sel_id; + uint64_t feature; + + unsigned int max_upscale_factor; + unsigned int max_downscale_factor; + const u8 dly[VOP2_DLY_MODE_MAX]; +}; + +struct vop2_video_port_data { + unsigned int id; + u32 feature; + u16 gamma_lut_len; + u16 cubic_lut_len; + struct vop_rect max_output; + const u8 pre_scan_max_dly[4]; + const struct vop2_video_port_regs *regs; + unsigned int offset; +}; + +struct vop2_data { + u8 nr_vps; + const struct vop2_ctrl *ctrl; + const struct vop2_win_data *win; + const struct vop2_video_port_data *vp; + const struct vop_csc_table *csc_table; + struct vop_rect max_input; + struct vop_rect max_output; + + unsigned int win_size; + unsigned int soc_id; +}; + +/* interrupt define */ +#define FS_NEW_INTR BIT(4) +#define ADDR_SAME_INTR BIT(5) +#define LINE_FLAG1_INTR BIT(6) +#define WIN0_EMPTY_INTR BIT(7) +#define WIN1_EMPTY_INTR BIT(8) +#define WIN2_EMPTY_INTR BIT(9) +#define WIN3_EMPTY_INTR BIT(10) +#define HWC_EMPTY_INTR BIT(11) +#define POST_BUF_EMPTY_INTR BIT(12) +#define PWM_GEN_INTR BIT(13) +#define DMA_FINISH_INTR BIT(14) +#define FS_FIELD_INTR BIT(15) +#define FE_INTR BIT(16) +#define WB_UV_FIFO_FULL_INTR BIT(17) +#define WB_YRGB_FIFO_FULL_INTR BIT(18) +#define WB_COMPLETE_INTR BIT(19) + +/* + * display output interface supported by rockchip lcdc + */ +#define ROCKCHIP_OUT_MODE_P888 0 +#define ROCKCHIP_OUT_MODE_BT1120 0 +#define ROCKCHIP_OUT_MODE_P666 1 +#define ROCKCHIP_OUT_MODE_P565 2 +#define ROCKCHIP_OUT_MODE_BT656 5 +#define ROCKCHIP_OUT_MODE_S888 8 +#define ROCKCHIP_OUT_MODE_S888_DUMMY 12 +#define ROCKCHIP_OUT_MODE_YUV420 14 +/* for use special outface */ +#define ROCKCHIP_OUT_MODE_AAAA 15 + +enum vop_csc_format { + CSC_BT601L, + CSC_BT709L, + CSC_BT601F, + CSC_BT2020, +}; + +enum src_factor_mode { + SRC_FAC_ALPHA_ZERO, + SRC_FAC_ALPHA_ONE, + SRC_FAC_ALPHA_DST, + SRC_FAC_ALPHA_DST_INVERSE, + SRC_FAC_ALPHA_SRC, + SRC_FAC_ALPHA_SRC_GLOBAL, +}; + +enum dst_factor_mode { + DST_FAC_ALPHA_ZERO, + DST_FAC_ALPHA_ONE, + DST_FAC_ALPHA_SRC, + DST_FAC_ALPHA_SRC_INVERSE, + DST_FAC_ALPHA_DST, + DST_FAC_ALPHA_DST_GLOBAL, +}; + +#define RK3568_GRF_VO_CON1 0x0364 +/* System registers definition */ +#define RK3568_REG_CFG_DONE 0x000 +#define RK3568_VERSION_INFO 0x004 +#define RK3568_SYS_AUTO_GATING_CTRL 0x008 +#define RK3568_SYS_AXI_LUT_CTRL 0x024 +#define RK3568_DSP_IF_EN 0x028 +#define RK3568_DSP_IF_CTRL 0x02c +#define RK3568_DSP_IF_POL 0x030 +#define RK3568_WB_CTRL 0x40 +#define RK3568_WB_XSCAL_FACTOR 0x44 +#define RK3568_WB_YRGB_MST 0x48 +#define RK3568_WB_CBR_MST 0x4C +#define RK3568_OTP_WIN_EN 0x050 +#define RK3568_LUT_PORT_SEL 0x058 +#define RK3568_SYS_STATUS0 0x060 +#define RK3568_VP_LINE_FLAG(vp) (0x70 + (vp) * 0x4) +#define RK3568_SYS0_INT_EN 0x80 +#define RK3568_SYS0_INT_CLR 0x84 +#define RK3568_SYS0_INT_STATUS 0x88 +#define RK3568_SYS1_INT_EN 0x90 +#define RK3568_SYS1_INT_CLR 0x94 +#define RK3568_SYS1_INT_STATUS 0x98 +#define RK3568_VP_INT_EN(vp) (0xA0 + (vp) * 0x10) +#define RK3568_VP_INT_CLR(vp) (0xA4 + (vp) * 0x10) +#define RK3568_VP_INT_STATUS(vp) (0xA8 + (vp) * 0x10) +#define RK3568_VP_INT_RAW_STATUS(vp) (0xAC + (vp) * 0x10) + +/* Video Port registers definition */ +#define RK3568_VP_DSP_CTRL 0x00 +#define RK3568_VP_MIPI_CTRL 0x04 +#define RK3568_VP_COLOR_BAR_CTRL 0x08 +#define RK3568_VP_3D_LUT_CTRL 0x10 +#define RK3568_VP_3D_LUT_MST 0x20 +#define RK3568_VP_DSP_BG 0x2C +#define RK3568_VP_PRE_SCAN_HTIMING 0x30 +#define RK3568_VP_POST_DSP_HACT_INFO 0x34 +#define RK3568_VP_POST_DSP_VACT_INFO 0x38 +#define RK3568_VP_POST_SCL_FACTOR_YRGB 0x3C +#define RK3568_VP_POST_SCL_CTRL 0x40 +#define RK3568_VP_POST_DSP_VACT_INFO_F1 0x44 +#define RK3568_VP_DSP_HTOTAL_HS_END 0x48 +#define RK3568_VP_DSP_HACT_ST_END 0x4C +#define RK3568_VP_DSP_VTOTAL_VS_END 0x50 +#define RK3568_VP_DSP_VACT_ST_END 0x54 +#define RK3568_VP_DSP_VS_ST_END_F1 0x58 +#define RK3568_VP_DSP_VACT_ST_END_F1 0x5C +#define RK3568_VP_BCSH_CTRL 0x60 +#define RK3568_VP_BCSH_BCS 0x64 +#define RK3568_VP_BCSH_H 0x68 +#define RK3568_VP_BCSH_COLOR_BAR 0x6C + +/* Overlay registers definition */ +#define RK3568_OVL_CTRL 0x600 +#define RK3568_OVL_LAYER_SEL 0x604 +#define RK3568_OVL_PORT_SEL 0x608 +#define RK3568_CLUSTER0_MIX_SRC_COLOR_CTRL 0x610 +#define RK3568_CLUSTER0_MIX_DST_COLOR_CTRL 0x614 +#define RK3568_CLUSTER0_MIX_SRC_ALPHA_CTRL 0x618 +#define RK3568_CLUSTER0_MIX_DST_ALPHA_CTRL 0x61C +#define RK3568_MIX0_SRC_COLOR_CTRL 0x650 +#define RK3568_MIX0_DST_COLOR_CTRL 0x654 +#define RK3568_MIX0_SRC_ALPHA_CTRL 0x658 +#define RK3568_MIX0_DST_ALPHA_CTRL 0x65C +#define RK3568_HDR0_SRC_COLOR_CTRL 0x6C0 +#define RK3568_HDR0_DST_COLOR_CTRL 0x6C4 +#define RK3568_HDR0_SRC_ALPHA_CTRL 0x6C8 +#define RK3568_HDR0_DST_ALPHA_CTRL 0x6CC +#define RK3568_VP_BG_MIX_CTRL(vp) (0x6E0 + (vp) * 4) +#define RK3568_CLUSTER_DLY_NUM 0x6F0 +#define RK3568_SMART_DLY_NUM 0x6F8 + +/* Cluster register definition, offset relative to window base */ +#define RK3568_CLUSTER_WIN_CTRL0 0x00 +#define RK3568_CLUSTER_WIN_CTRL1 0x04 +#define RK3568_CLUSTER_WIN_YRGB_MST 0x10 +#define RK3568_CLUSTER_WIN_CBR_MST 0x14 +#define RK3568_CLUSTER_WIN_VIR 0x18 +#define RK3568_CLUSTER_WIN_ACT_INFO 0x20 +#define RK3568_CLUSTER_WIN_DSP_INFO 0x24 +#define RK3568_CLUSTER_WIN_DSP_ST 0x28 +#define RK3568_CLUSTER_WIN_SCL_FACTOR_YRGB 0x30 +#define RK3568_CLUSTER_WIN_AFBCD_TRANSFORM_OFFSET 0x3C +#define RK3568_CLUSTER_WIN_AFBCD_OUTPUT_CTRL 0x50 +#define RK3568_CLUSTER_WIN_AFBCD_ROTATE_MODE 0x54 +#define RK3568_CLUSTER_WIN_AFBCD_HDR_PTR 0x58 +#define RK3568_CLUSTER_WIN_AFBCD_VIR_WIDTH 0x5C +#define RK3568_CLUSTER_WIN_AFBCD_PIC_SIZE 0x60 +#define RK3568_CLUSTER_WIN_AFBCD_PIC_OFFSET 0x64 +#define RK3568_CLUSTER_WIN_AFBCD_DSP_OFFSET 0x68 +#define RK3568_CLUSTER_WIN_AFBCD_CTRL 0x6C + +#define RK3568_CLUSTER_CTRL 0x100 + +/* (E)smart register definition, offset relative to window base */ +#define RK3568_SMART_CTRL0 0x00 +#define RK3568_SMART_CTRL1 0x04 +#define RK3568_SMART_REGION0_CTRL 0x10 +#define RK3568_SMART_REGION0_YRGB_MST 0x14 +#define RK3568_SMART_REGION0_CBR_MST 0x18 +#define RK3568_SMART_REGION0_VIR 0x1C +#define RK3568_SMART_REGION0_ACT_INFO 0x20 +#define RK3568_SMART_REGION0_DSP_INFO 0x24 +#define RK3568_SMART_REGION0_DSP_ST 0x28 +#define RK3568_SMART_REGION0_SCL_CTRL 0x30 +#define RK3568_SMART_REGION0_SCL_FACTOR_YRGB 0x34 +#define RK3568_SMART_REGION0_SCL_FACTOR_CBR 0x38 +#define RK3568_SMART_REGION0_SCL_OFFSET 0x3C +#define RK3568_SMART_REGION1_CTRL 0x40 +#define RK3568_SMART_REGION1_YRGB_MST 0x44 +#define RK3568_SMART_REGION1_CBR_MST 0x48 +#define RK3568_SMART_REGION1_VIR 0x4C +#define RK3568_SMART_REGION1_ACT_INFO 0x50 +#define RK3568_SMART_REGION1_DSP_INFO 0x54 +#define RK3568_SMART_REGION1_DSP_ST 0x58 +#define RK3568_SMART_REGION1_SCL_CTRL 0x60 +#define RK3568_SMART_REGION1_SCL_FACTOR_YRGB 0x64 +#define RK3568_SMART_REGION1_SCL_FACTOR_CBR 0x68 +#define RK3568_SMART_REGION1_SCL_OFFSET 0x6C +#define RK3568_SMART_REGION2_CTRL 0x70 +#define RK3568_SMART_REGION2_YRGB_MST 0x74 +#define RK3568_SMART_REGION2_CBR_MST 0x78 +#define RK3568_SMART_REGION2_VIR 0x7C +#define RK3568_SMART_REGION2_ACT_INFO 0x80 +#define RK3568_SMART_REGION2_DSP_INFO 0x84 +#define RK3568_SMART_REGION2_DSP_ST 0x88 +#define RK3568_SMART_REGION2_SCL_CTRL 0x90 +#define RK3568_SMART_REGION2_SCL_FACTOR_YRGB 0x94 +#define RK3568_SMART_REGION2_SCL_FACTOR_CBR 0x98 +#define RK3568_SMART_REGION2_SCL_OFFSET 0x9C +#define RK3568_SMART_REGION3_CTRL 0xA0 +#define RK3568_SMART_REGION3_YRGB_MST 0xA4 +#define RK3568_SMART_REGION3_CBR_MST 0xA8 +#define RK3568_SMART_REGION3_VIR 0xAC +#define RK3568_SMART_REGION3_ACT_INFO 0xB0 +#define RK3568_SMART_REGION3_DSP_INFO 0xB4 +#define RK3568_SMART_REGION3_DSP_ST 0xB8 +#define RK3568_SMART_REGION3_SCL_CTRL 0xC0 +#define RK3568_SMART_REGION3_SCL_FACTOR_YRGB 0xC4 +#define RK3568_SMART_REGION3_SCL_FACTOR_CBR 0xC8 +#define RK3568_SMART_REGION3_SCL_OFFSET 0xCC +#define RK3568_SMART_COLOR_KEY_CTRL 0xD0 + +/* HDR register definition */ +#define RK3568_HDR_LUT_CTRL 0x2000 +#define RK3568_HDR_LUT_MST 0x2004 +#define RK3568_SDR2HDR_CTRL 0x2010 +#define RK3568_HDR2SDR_CTRL 0x2020 +#define RK3568_HDR2SDR_SRC_RANGE 0x2024 +#define RK3568_HDR2SDR_NORMFACEETF 0x2028 +#define RK3568_HDR2SDR_DST_RANGE 0x202C +#define RK3568_HDR2SDR_NORMFACCGAMMA 0x2030 +#define RK3568_HDR_EETF_OETF_Y0 0x203C +#define RK3568_HDR_SAT_Y0 0x20C0 +#define RK3568_HDR_EOTF_OETF_Y0 0x20F0 +#define RK3568_HDR_OETF_DX_POW1 0x2200 +#define RK3568_HDR_OETF_XN1 0x2300 + +#define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN BIT(15) + +#define RK3568_VP_DSP_CTRL__STANDBY BIT(31) +#define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE BIT(20) +#define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL GENMASK(19, 18) +#define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN BIT(17) +#define RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN BIT(16) +#define RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y BIT(15) +#define RK3568_VP_DSP_CTRL__DSP_RB_SWAP BIT(9) +#define RK3568_VP_DSP_CTRL__DSP_INTERLACE BIT(7) +#define RK3568_VP_DSP_CTRL__DSP_FILED_POL BIT(6) +#define RK3568_VP_DSP_CTRL__P2I_EN BIT(5) +#define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV BIT(4) +#define RK3568_VP_DSP_CTRL__OUT_MODE GENMASK(3, 0) + +#define RK3568_VP_POST_SCL_CTRL__VSCALEDOWN BIT(1) +#define RK3568_VP_POST_SCL_CTRL__HSCALEDOWN BIT(0) + +#define RK3568_SYS_DSP_INFACE_EN_LVDS1_MUX GENMASK(26, 25) +#define RK3568_SYS_DSP_INFACE_EN_LVDS1 BIT(24) +#define RK3568_SYS_DSP_INFACE_EN_MIPI1_MUX GENMASK(22, 21) +#define RK3568_SYS_DSP_INFACE_EN_MIPI1 BIT(20) +#define RK3568_SYS_DSP_INFACE_EN_LVDS0_MUX GENMASK(19, 18) +#define RK3568_SYS_DSP_INFACE_EN_MIPI0_MUX GENMASK(17, 16) +#define RK3568_SYS_DSP_INFACE_EN_EDP_MUX GENMASK(15, 14) +#define RK3568_SYS_DSP_INFACE_EN_HDMI_MUX GENMASK(11, 10) +#define RK3568_SYS_DSP_INFACE_EN_RGB_MUX GENMASK(9, 8) +#define RK3568_SYS_DSP_INFACE_EN_LVDS0 BIT(5) +#define RK3568_SYS_DSP_INFACE_EN_MIPI0 BIT(4) +#define RK3568_SYS_DSP_INFACE_EN_EDP BIT(3) +#define RK3568_SYS_DSP_INFACE_EN_HDMI BIT(1) +#define RK3568_SYS_DSP_INFACE_EN_RGB BIT(0) + +#define RK3568_DSP_IF_POL__MIPI_PIN_POL GENMASK(19, 16) +#define RK3568_DSP_IF_POL__EDP_PIN_POL GENMASK(15, 12) +#define RK3568_DSP_IF_POL__HDMI_PIN_POL GENMASK(7, 4) +#define RK3568_DSP_IF_POL__RGB_LVDS_PIN_POL GENMASK(3, 0) + +#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK BIT(5) +#define RK3568_VP0_MIPI_CTRL__DCLK_DIV2 BIT(4) + +#define RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN BIT(31) + +#define RK3568_DSP_IF_POL__CFG_DONE_IMD BIT(28) + +#define VOP2_SYS_AXI_BUS_NUM 2 + +#define VOP2_CLUSTER_YUV444_10 0x12 + +#define VOP2_COLOR_KEY_MASK BIT(31) + +#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD BIT(28) + +#define RK3568_VP_BG_MIX_CTRL__BG_DLY GENMASK(31, 24) + +#define RK3568_OVL_PORT_SEL__SEL_PORT GENMASK(31, 16) +#define RK3568_OVL_PORT_SEL__SMART1 GENMASK(31, 30) +#define RK3568_OVL_PORT_SEL__SMART0 GENMASK(29, 28) +#define RK3568_OVL_PORT_SEL__ESMART1 GENMASK(27, 26) +#define RK3568_OVL_PORT_SEL__ESMART0 GENMASK(25, 24) +#define RK3568_OVL_PORT_SEL__CLUSTER1 GENMASK(19, 18) +#define RK3568_OVL_PORT_SEL__CLUSTER0 GENMASK(17, 16) +#define RK3568_OVL_PORT_SET__PORT2_MUX GENMASK(11, 8) +#define RK3568_OVL_PORT_SET__PORT1_MUX GENMASK(7, 4) +#define RK3568_OVL_PORT_SET__PORT0_MUX GENMASK(3, 0) +#define RK3568_OVL_LAYER_SEL__LAYER(layer, x) ((x) << ((layer) * 4)) + +#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_1 GENMASK(31, 24) +#define RK3568_CLUSTER_DLY_NUM__CLUSTER1_0 GENMASK(23, 16) +#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_1 GENMASK(15, 8) +#define RK3568_CLUSTER_DLY_NUM__CLUSTER0_0 GENMASK(7, 0) + +#define RK3568_SMART_DLY_NUM__SMART1 GENMASK(31, 24) +#define RK3568_SMART_DLY_NUM__SMART0 GENMASK(23, 16) +#define RK3568_SMART_DLY_NUM__ESMART1 GENMASK(15, 8) +#define RK3568_SMART_DLY_NUM__ESMART0 GENMASK(7, 0) + +#define VP_INT_DSP_HOLD_VALID BIT(6) +#define VP_INT_FS_FIELD BIT(5) +#define VP_INT_POST_BUF_EMPTY BIT(4) +#define VP_INT_LINE_FLAG1 BIT(3) +#define VP_INT_LINE_FLAG0 BIT(2) +#define VOP2_INT_BUS_ERRPR BIT(1) +#define VP_INT_FS BIT(0) + +#define POLFLAG_DCLK_INV BIT(3) + +enum vop2_layer_phy_id { + ROCKCHIP_VOP2_CLUSTER0 = 0, + ROCKCHIP_VOP2_CLUSTER1, + ROCKCHIP_VOP2_ESMART0, + ROCKCHIP_VOP2_ESMART1, + ROCKCHIP_VOP2_SMART0, + ROCKCHIP_VOP2_SMART1, + ROCKCHIP_VOP2_CLUSTER2, + ROCKCHIP_VOP2_CLUSTER3, + ROCKCHIP_VOP2_ESMART2, + ROCKCHIP_VOP2_ESMART3, + ROCKCHIP_VOP2_PHY_ID_INVALID = -1, +}; + +extern const struct component_ops vop2_component_ops; + +#endif /* _ROCKCHIP_DRM_VOP2_H */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c new file mode 100644 index 0000000000000..9bf0637bf8e26 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) Rockchip Electronics Co.Ltd + * Author: Andy Yan andy.yan@rock-chips.com + */ + +#include <linux/kernel.h> +#include <linux/component.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_plane.h> +#include <drm/drm_print.h> + +#include "rockchip_drm_vop2.h" + +static const uint32_t formats_win_full_10bit[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV24, +}; + +static const uint32_t formats_win_full_10bit_yuyv[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + DRM_FORMAT_NV24, + DRM_FORMAT_YVYU, + DRM_FORMAT_VYUY, +}; + +static const uint32_t formats_win_lite[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, +}; + +static const uint64_t format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +static const uint64_t format_modifiers_afbc[] = { + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_SPARSE), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_CBR), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_CBR | + AFBC_FORMAT_MOD_SPARSE), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_CBR), + + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_CBR | + AFBC_FORMAT_MOD_SPARSE), + + /* SPLIT mandates SPARSE, RGB modes mandates YTR */ + DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | + AFBC_FORMAT_MOD_YTR | + AFBC_FORMAT_MOD_SPARSE | + AFBC_FORMAT_MOD_SPLIT), + DRM_FORMAT_MOD_INVALID, +}; + +static const struct vop2_video_port_data rk3568_vop_video_ports[] = { + { + .id = 0, + .feature = VOP_FEATURE_OUTPUT_10BIT, + .gamma_lut_len = 1024, + .cubic_lut_len = 9 * 9 * 9, + .max_output = { 4096, 2304 }, + .pre_scan_max_dly = { 69, 53, 53, 42 }, + .offset = 0xc00, + }, { + .id = 1, + .gamma_lut_len = 1024, + .max_output = { 2048, 1536 }, + .pre_scan_max_dly = { 40, 40, 40, 40 }, + .offset = 0xd00, + }, { + .id = 2, + .gamma_lut_len = 1024, + .max_output = { 1920, 1080 }, + .pre_scan_max_dly = { 40, 40, 40, 40 }, + .offset = 0xe00, + }, +}; + +/* + * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win. + * Every cluster can work as 4K win or split into two win. + * All win in cluster support AFBCD. + * + * Every esmart win and smart win support 4 Multi-region. + * + * Scale filter mode: + * + * * Cluster: bicubic for horizontal scale up, others use bilinear + * * ESmart: + * * nearest-neighbor/bilinear/bicubic for scale up + * * nearest-neighbor/bilinear/average for scale down + * + * + * @TODO describe the wind like cpu-map dt nodes; + */ +static const struct vop2_win_data rk3568_vop_win_data[] = { + { + .name = "Smart0-win0", + .phys_id = ROCKCHIP_VOP2_SMART0, + .base = 0x1c00, + .formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers, + .layer_sel_id = 3, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 20, 47, 41 }, + }, { + .name = "Smart1-win0", + .phys_id = ROCKCHIP_VOP2_SMART1, + .formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers, + .base = 0x1e00, + .layer_sel_id = 7, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 20, 47, 41 }, + }, { + .name = "Esmart1-win0", + .phys_id = ROCKCHIP_VOP2_ESMART1, + .formats = formats_win_full_10bit_yuyv, + .nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv), + .format_modifiers = format_modifiers, + .base = 0x1a00, + .layer_sel_id = 6, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_PRIMARY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 20, 47, 41 }, + }, { + .name = "Esmart0-win0", + .phys_id = ROCKCHIP_VOP2_ESMART0, + .formats = formats_win_full_10bit_yuyv, + .nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv), + .format_modifiers = format_modifiers, + .base = 0x1800, + .layer_sel_id = 2, + .supported_rotations = DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 8, + .max_downscale_factor = 8, + .dly = { 20, 47, 41 }, + }, { + .name = "Cluster0-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER0, + .base = 0x1000, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .layer_sel_id = 0, + .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .dly = { 0, 27, 21 }, + .type = DRM_PLANE_TYPE_OVERLAY, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, + }, { + .name = "Cluster1-win0", + .phys_id = ROCKCHIP_VOP2_CLUSTER1, + .base = 0x1200, + .formats = formats_win_full_10bit, + .nformats = ARRAY_SIZE(formats_win_full_10bit), + .format_modifiers = format_modifiers_afbc, + .layer_sel_id = 1, + .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 | + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y, + .type = DRM_PLANE_TYPE_OVERLAY, + .max_upscale_factor = 4, + .max_downscale_factor = 4, + .dly = { 0, 27, 21 }, + .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER, + }, +}; + +static const struct vop2_data rk3566_vop = { + .nr_vps = 3, + .max_input = { 4096, 2304 }, + .max_output = { 4096, 2304 }, + .vp = rk3568_vop_video_ports, + .win = rk3568_vop_win_data, + .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .soc_id = 3566, +}; + +static const struct vop2_data rk3568_vop = { + .nr_vps = 3, + .max_input = { 4096, 2304 }, + .max_output = { 4096, 2304 }, + .vp = rk3568_vop_video_ports, + .win = rk3568_vop_win_data, + .win_size = ARRAY_SIZE(rk3568_vop_win_data), + .soc_id = 3568, +}; + +static const struct of_device_id vop2_dt_match[] = { + { + .compatible = "rockchip,rk3566-vop", + .data = &rk3566_vop, + }, { + .compatible = "rockchip,rk3568-vop", + .data = &rk3568_vop, + }, { + }, +}; +MODULE_DEVICE_TABLE(of, vop2_dt_match); + +static int vop2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + return component_add(dev, &vop2_component_ops); +} + +static int vop2_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &vop2_component_ops); + + return 0; +} + +struct platform_driver vop2_platform_driver = { + .probe = vop2_probe, + .remove = vop2_remove, + .driver = { + .name = "rockchip-vop2", + .of_match_table = of_match_ptr(vop2_dt_match), + }, +};
The VOP2 is found on newer Rockchip SoCs like the rk3568 or the rk3566. The binding differs slightly from the existing VOP binding, so add a new binding file for it.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Reviewed-by: Rob Herring robh@kernel.org ---
Notes: Changes since v5: - Add Robs Reviewed-by:
Changes since v4: - Fix clk names in example - Drop unnecessary assigned-clocks, assigned-clock-rates and assigned-clock-parents
Changes since v3: - drop redundant _vop suffix from clock names
Changes since v3: - new patch
.../display/rockchip/rockchip-vop2.yaml | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml new file mode 100644 index 0000000000000..655d9b327f7d3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip SoC display controller (VOP2) + +description: + VOP2 (Video Output Processor v2) is the display controller for the Rockchip + series of SoCs which transfers the image data from a video memory + buffer to an external LCD interface. + +maintainers: + - Sandy Huang hjc@rock-chips.com + - Heiko Stuebner heiko@sntech.de + +properties: + compatible: + enum: + - rockchip,rk3566-vop + - rockchip,rk3568-vop + + reg: + minItems: 1 + items: + - description: + Must contain one entry corresponding to the base address and length + of the register space. + - description: + Can optionally contain a second entry corresponding to + the CRTC gamma LUT address. + + interrupts: + maxItems: 1 + description: + The VOP interrupt is shared by several interrupt sources, such as + frame start (VSYNC), line flag and other status interrupts. + + clocks: + items: + - description: Clock for ddr buffer transfer. + - description: Clock for the ahb bus to R/W the phy regs. + - description: Pixel clock for video port 0. + - description: Pixel clock for video port 1. + - description: Pixel clock for video port 2. + + clock-names: + items: + - const: aclk + - const: hclk + - const: dclk_vp0 + - const: dclk_vp1 + - const: dclk_vp2 + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to GRF regs used for misc control + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + Output endpoint of VP0 + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Output endpoint of VP1 + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: + Output endpoint of VP2 + + iommus: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - ports + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/rk3568-cru.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/power/rk3568-power.h> + bus { + #address-cells = <2>; + #size-cells = <2>; + vop: vop@fe040000 { + compatible = "rockchip,rk3568-vop"; + reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>; + interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cru ACLK_VOP>, + <&cru HCLK_VOP>, + <&cru DCLK_VOP0>, + <&cru DCLK_VOP1>, + <&cru DCLK_VOP2>; + clock-names = "aclk", + "hclk", + "dclk_vp0", + "dclk_vp1", + "dclk_vp2"; + power-domains = <&power RK3568_PD_VO>; + iommus = <&vop_mmu>; + vop_out: ports { + #address-cells = <1>; + #size-cells = <0>; + vp0: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + vp1: port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + vp2: port@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + };
Current port description doesn't cover all possible cases. It currently expects one single port with two endpoints.
When the HDMI connector is described in the device tree there can be two ports, first one going to the VOP and the second one going to the connector.
Also on SoCs which only have a single VOP there will be only one endpoint instead of two.
This patch addresses both issues. With this there can either be a single port ("port") , or two of them ("port@0", "port@1") when the connector is also in the device tree. Also the first or only port can either have one endpoint ("endpoint") for single VOP SoCs or two ("endpoint@0", "endpoint@1") for dual VOP SoCs.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de Reviewed-by: Rob Herring robh@kernel.org ---
Notes: Changes since v6: - Add Reviewed-by: Rob Herring robh@kernel.org Changes since v5: - new patch
.../display/rockchip/rockchip,dw-hdmi.yaml | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index d7cb2b2be60e8..7e59dee15a5f4 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -97,27 +97,21 @@ properties: ports: $ref: /schemas/graph.yaml#/properties/ports
- properties: - port: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false + patternProperties: + "^port(@0)?$": + $ref: /schemas/graph.yaml#/properties/port description: Input of the DWC HDMI TX - properties: + endpoint: + description: Connection to the VOP endpoint@0: - $ref: /schemas/graph.yaml#/properties/endpoint description: Connection to the VOPB - endpoint@1: - $ref: /schemas/graph.yaml#/properties/endpoint description: Connection to the VOPL - - required: - - endpoint@0 - - endpoint@1 - - required: - - port + properties: + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Output of the DWC HDMI TX
rockchip,grf: $ref: /schemas/types.yaml#/definitions/phandle
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 28.03.2022, o godz. 17:10:
Changes since v8:
- make hclk_vo a critical clock instead of enabling it in the hdmi driver
- Fix vop2_setup_layer_mixer(), reported by Andy Yan
- Limit planes possible_crtcs to actually existing crtcs
Sascha,
FYI: I was hoping v9 will fix green screen issue i see when video player wants to draw to nv12 capable drm plane. It look issue is still present :-(
You can easily reproduce with modetest utility:
modetest -P 43@67:1920x1080@NV12
gives green screen.
however if you do:
modetest #43 (green screen) modetest #49 (ok)
then
modetest #43
gives expected result ("rainbow" picture on screen)
let me know if i can do any extra tests helping you to fix issue
br
Hi Piotr,
On Tue, Mar 29, 2022 at 09:31:01AM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 28.03.2022, o godz. 17:10:
Changes since v8:
- make hclk_vo a critical clock instead of enabling it in the hdmi driver
- Fix vop2_setup_layer_mixer(), reported by Andy Yan
- Limit planes possible_crtcs to actually existing crtcs
Sascha,
FYI: I was hoping v9 will fix green screen issue i see when video player wants to draw to nv12 capable drm plane. It look issue is still present :-(
You can easily reproduce with modetest utility:
modetest -P 43@67:1920x1080@NV12
This only sets the overlay, but how did you get something on the screen initially?
I did with "modetest -s 69@67:1920x1080 -d" and with this it works as expected, I can't reproduce any green screen issue here.
I found another problem though which might or might not be related with your issue. I saw that the overlay is not exactly centered as it ought to be. This goes down to wrong delay settings for the overlay, the following patch fixes this.
Sascha
---------------------------------8<-------------------------------
From f9a92401344e8aa3203fca2236dd4a40cc8690f6 Mon Sep 17 00:00:00 2001
From: Sascha Hauer s.hauer@pengutronix.de Date: Wed, 30 Mar 2022 09:22:26 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
--- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 69e9870d5f2dc..7dba7b9b63dc6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1979,10 +1979,10 @@ static void vop2_setup_dly_for_windows(struct vop2 *vop2) sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly); break; case ROCKCHIP_VOP2_SMART0: - sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); break; case ROCKCHIP_VOP2_SMART1: - sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); + sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); break; } }
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 09:28:
You can easily reproduce with modetest utility:
modetest -P 43@67:1920x1080@NV12
This only sets the overlay, but how did you get something on the screen initially?
I'm not sure that above command only sets plane. On other SoCs i’m testing it gives expected results: diagonal colored stripes. There is single exception: rk356x with vop2 - where screen is green unless i „fix/enable” by playing with plane #69
I did with "modetest -s 69@67:1920x1080 -d" and with this it works as expected, I can't reproduce any green screen issue here.
I see you are using plane #69. Why not #43? Is plane #43 working ok for you?
I’m using plane #43 because: application (player) - at start - queries all planes and selects first plane offering format being within offered formats by provider (video decoder; NV12 from rk356x hantro video decoder).
pls look on app log regarding planes discovery and election: https://pastebin.com/edAhbcvU
Now - looking what VOP2 reports: https://pastebin.com/8ujkaV9n is see first plane accepting NV12 is #43 - so my app is electing this plane to use for displaying video.
This strategy works well for all 13 platforms i’m supporting (only 13 i have in my testbed).
If this approach is - by Yours VOP2 patches goal - is not supported - then OK. I understand this :-)
But - if You want to support DRM features in the same way like other SOC are doing (and working well with KODI/MythTV/mpv/etc) - then i think:
1\ DRM plane #43 not supports NV12 - but code wrongly reports NV12 format is supported, or 2\ DRM plane #43 is supported - but code has bug resulting with green screen.
Pls let me know what you think!
I found another problem though which might or might not be related with your issue. I saw that the overlay is not exactly centered as it ought to be. This goes down to wrong delay settings for the overlay, the following patch fixes this.
Sascha
---------------------------------8<-------------------------------
From f9a92401344e8aa3203fca2236dd4a40cc8690f6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer s.hauer@pengutronix.de Date: Wed, 30 Mar 2022 09:22:26 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 69e9870d5f2dc..7dba7b9b63dc6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1979,10 +1979,10 @@ static void vop2_setup_dly_for_windows(struct vop2 *vop2) sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__ESMART1, dly); break; case ROCKCHIP_VOP2_SMART0:
sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly);
case ROCKCHIP_VOP2_SMART1:sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly); break;
sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART0, dly);
} }sdly |= FIELD_PREP(RK3568_SMART_DLY_NUM__SMART1, dly); break;
-- 2.30.2
-- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
On Wed, Mar 30, 2022 at 10:41:56AM +0200, piotro.oniszczuk@google.com wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 09:28:
You can easily reproduce with modetest utility:
modetest -P 43@67:1920x1080@NV12
This only sets the overlay, but how did you get something on the screen initially?
Let me rephrase this: The above sets a plane, but it doesn't set a mode on the crtc. When my system boots up then the output of modetest looks like this:
Encoders: id crtc type possible crtcs possible clones 68 0 TMDS 0x00000001 0x00000001 Connectors: id encoder status name size (mm) modes encoders 69 0 connected HDMI-A-1 530x300 9 68 CRTCs: id fb pos size 67 0 (0,0) (0x0) #0 nan 0 0 0 0 0 0 0 0 0 flags: ; type:
No mode is set on the CRTC and the encoder/connector/crtc are not bound to each other, consequently the screen is in standby. "modetest -P 43@67:1920x1080@NV12" doesn't change this, still no mode set. Hence my question: How did you set a mode initially?
I'm not sure that above command only sets plane. On other SoCs i’m testing it gives expected results: diagonal colored stripes. There is single exception: rk356x with vop2 - where screen is green unless i „fix/enable” by playing with plane #69
I did with "modetest -s 69@67:1920x1080 -d" and with this it works as expected, I can't reproduce any green screen issue here.
I see you are using plane #69. Why not #43?
I used "modetest -s 69@67:1920x1080 -d" to set a mode. The '69' is the connector id, not a plane.
Is plane #43 working ok for you?
Yes.
I’m using plane #43 because: application (player) - at start - queries all planes and selects first plane offering format being within offered formats by provider (video decoder; NV12 from rk356x hantro video decoder).
pls look on app log regarding planes discovery and election: https://pastebin.com/edAhbcvU
Now - looking what VOP2 reports: https://pastebin.com/8ujkaV9n is see first plane accepting NV12 is #43 - so my app is electing this plane to use for displaying video.
This strategy works well for all 13 platforms i’m supporting (only 13 i have in my testbed).
If this approach is - by Yours VOP2 patches goal - is not supported - then OK. I understand this :-)
But - if You want to support DRM features in the same way like other SOC are doing (and working well with KODI/MythTV/mpv/etc) - then i think:
1\ DRM plane #43 not supports NV12 - but code wrongly reports NV12 format is supported, or 2\ DRM plane #43 is supported - but code has bug resulting with green screen.
plane #43 should support NV12 and it seems to work fine here.
I believe you that there's a problem, but I can't reproduce it here and I might need further assistence to reproduce it.
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 11:45:
On Wed, Mar 30, 2022 at 10:41:56AM +0200, piotro.oniszczuk@google.com wrote:
Let me rephrase this: The above sets a plane, but it doesn't set a mode on the crtc. When my system boots up then the output of modetest looks like this:
Encoders: id crtc type possible crtcs possible clones 68 0 TMDS 0x00000001 0x00000001 Connectors: id encoder status name size (mm) modes encoders 69 0 connected HDMI-A-1 530x300 9 68 CRTCs: id fb pos size 67 0 (0,0) (0x0) #0 nan 0 0 0 0 0 0 0 0 0 flags: ; type:
No mode is set on the CRTC and the encoder/connector/crtc are not bound to each other, consequently the screen is in standby. "modetest -P 43@67:1920x1080@NV12" doesn't change this, still no mode set. Hence my question: How did you set a mode initially?
Ah ok. I see your point. mode is set by app (player).
Sequence was like this: -boot board -start app -on UI select playback -playback has green screen -exit app -run modetest -P 43@67:1920x1080@NV12 (the same green screen like in playback) -run modetest -P 49@67:1920x1080@NV12 (works ok) -run modetest -P 43@67:1920x1080@NV12 (now works ok)
I'm not sure that above command only sets plane. On other SoCs i’m testing it gives expected results: diagonal colored stripes. There is single exception: rk356x with vop2 - where screen is green unless i „fix/enable” by playing with plane #69
I did with "modetest -s 69@67:1920x1080 -d" and with this it works as expected, I can't reproduce any green screen issue here.
I see you are using plane #69. Why not #43?
I used "modetest -s 69@67:1920x1080 -d" to set a mode. The '69' is the connector id, not a plane.
ack. typo from my side.
it was modetest -P 49@67:1920x1080@NV12
Is plane #43 working ok for you?
Yes.
So it looks your testing method of #43 is not meaningful for verifying issue we are discussing here.
In my case: 12 SOC (except rk356x VOP2) gives me: -boot board -start app -on UI select playback -playback is ok -exit app -run modetest -P XX@YY:1920x1080@NV12 (diagonal stripes)
(XX/YY are plane/connector elected by app: plane@conector with format matching provider format)
rk356x with vop2 v9: -boot board -start app -on UI select playback -playback has green screen -exit app -run modetest -P 43@67:1920x1080@NV12 (the same green screen like in playback) -run modetest -P 49@67:1920x1080@NV12 (works ok) -run modetest -P 43@67:1920x1080@NV12 (now works ok)
On Wed, Mar 30, 2022 at 12:01:05PM +0200, piotro.oniszczuk@google.com wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 11:45:
On Wed, Mar 30, 2022 at 10:41:56AM +0200, piotro.oniszczuk@google.com wrote:
Let me rephrase this: The above sets a plane, but it doesn't set a mode on the crtc. When my system boots up then the output of modetest looks like this:
Encoders: id crtc type possible crtcs possible clones 68 0 TMDS 0x00000001 0x00000001 Connectors: id encoder status name size (mm) modes encoders 69 0 connected HDMI-A-1 530x300 9 68 CRTCs: id fb pos size 67 0 (0,0) (0x0) #0 nan 0 0 0 0 0 0 0 0 0 flags: ; type:
No mode is set on the CRTC and the encoder/connector/crtc are not bound to each other, consequently the screen is in standby. "modetest -P 43@67:1920x1080@NV12" doesn't change this, still no mode set. Hence my question: How did you set a mode initially?
Ah ok. I see your point. mode is set by app (player).
Sequence was like this: -boot board -start app -on UI select playback -playback has green screen -exit app -run modetest -P 43@67:1920x1080@NV12 (the same green screen like in playback) -run modetest -P 49@67:1920x1080@NV12 (works ok) -run modetest -P 43@67:1920x1080@NV12 (now works ok)
I'm not sure that above command only sets plane. On other SoCs i’m testing it gives expected results: diagonal colored stripes. There is single exception: rk356x with vop2 - where screen is green unless i „fix/enable” by playing with plane #69
I did with "modetest -s 69@67:1920x1080 -d" and with this it works as expected, I can't reproduce any green screen issue here.
I see you are using plane #69. Why not #43?
I used "modetest -s 69@67:1920x1080 -d" to set a mode. The '69' is the connector id, not a plane.
ack. typo from my side.
it was modetest -P 49@67:1920x1080@NV12
Is plane #43 working ok for you?
Yes.
So it looks your testing method of #43 is not meaningful for verifying issue we are discussing here.
In my case: 12 SOC (except rk356x VOP2) gives me: -boot board -start app -on UI select playback -playback is ok -exit app -run modetest -P XX@YY:1920x1080@NV12 (diagonal stripes)
(XX/YY are plane/connector elected by app: plane@conector with format matching provider format)
rk356x with vop2 v9: -boot board -start app -on UI select playback -playback has green screen -exit app -run modetest -P 43@67:1920x1080@NV12 (the same green screen like in playback) -run modetest -P 49@67:1920x1080@NV12 (works ok) -run modetest -P 43@67:1920x1080@NV12 (now works ok)
Does it change anything if you do a "modetest -s 69@67:1920x1080" before starting the app? Or if you run "modetest -P 43@67:1920x1080@NV12" before starting the app? Or other combinations thereof?
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 12:20:
Does it change anything if you do a "modetest -s 69@67:1920x1080" before starting the app? Or if you run "modetest -P 43@67:1920x1080@NV12" before starting the app? Or other combinations thereof?
So i tried following combinations
1. -boot -start app -stop app -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
2. -boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
3. -boot -modetest -s 69@67:1920x1080 -> ok -start app -playback in app -> green screen -stop app -modetest -P 43@67:1920x1080@NV12 -> green screen
4. -boot -modetest -s 69@67:1920x1080 -> ok -start app -playback in app -> green screen -stop app -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
br
On Wed, Mar 30, 2022 at 04:52:22PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 12:20:
Does it change anything if you do a "modetest -s 69@67:1920x1080" before starting the app? Or if you run "modetest -P 43@67:1920x1080@NV12" before starting the app? Or other combinations thereof?
So i tried following combinations
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
I have no idea what is going on here. There same commands work for me. You could provide me your kernel config and upstream commitish you are working on, maybe that gets me closer to your setup.
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 21:20:
So i tried following combinations
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
I have no idea what is going on here. There same commands work for me. You could provide me your kernel config and upstream commitish you are working on, maybe that gets me closer to your setup.
Sascha
May you try with my kernel config? https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-5.17/fil...
If this config will work for you then:
i'll try to build vanilla 5.17 + minimal possible set of patches allowing me to get video decoder working on rk3566. This may help us to find why: -you have it working -I have it not working
On Wed, Mar 30, 2022 at 09:35:17PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 21:20:
So i tried following combinations
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
I have no idea what is going on here. There same commands work for me. You could provide me your kernel config and upstream commitish you are working on, maybe that gets me closer to your setup.
Sascha
May you try with my kernel config? https://github.com/warpme/minimyth2/blob/master/script/kernel/linux-5.17/fil...
This works for me as well.
If this config will work for you then:
i'll try to build vanilla 5.17 + minimal possible set of patches allowing me to get video decoder working on rk3566.
You shouldn't need a video decoder for this test.
For your convenience I pushed the branch I just tested to:
git://git.pengutronix.de/sha/linux rockchip-vop2-v9
Sascha
Hi Piotr:
On 3/31/22 03:20, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 04:52:22PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 12:20:
Does it change anything if you do a "modetest -s 69@67:1920x1080" before starting the app? Or if you run "modetest -P 43@67:1920x1080@NV12" before starting the app? Or other combinations thereof?
So i tried following combinations
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
I have no idea what is going on here. There same commands work for me. You could provide me your kernel config and upstream commitish you are working on, maybe that gets me closer to your setup.
It's a little strange, I can't reproduce this issue neither.
But I have problem with this two step command sequence.
step 1: modetest -s 69@67:1920x1080 -> ok
step 2: modetest -P 43@67:1920x1080@NV12,
I got the failed message: "failed to enable plane: Permission denied"
Because the drm core will stop step2 by drm_ioctrl_permit as DRM_IOCTL_SETPLANE need a master,
but the current master is the modetest run by step1.
static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) {
/* ROOT_ONLY is only for CAP_SYS_ADMIN */ if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN))) { printk("DRM_ROOT_ONLY\n"); return -EACCES; }
/* AUTH is only for authenticated or render client */ if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) && !file_priv->authenticated)) { printk("DRM_AUTH\n"); return -EACCES; }
/* MASTER is only for master or control clients */ if (unlikely((flags & DRM_MASTER) && !drm_is_current_master(file_priv))) { printk("DRM_MASTER\n"); return -EACCES; }
/* Render clients must be explicitly allowed */ if (unlikely(!(flags & DRM_RENDER_ALLOW) && drm_is_render_client(file_priv))) { printk("DRM_RENDER_NOT_ALLOW\n"); return -EACCES; }
return 0; }
After bypass the permission check, I can run step 2 , but the display on the screen will have a shift as the wrong dly configuration.
So how you two got step two run success?
Piotr:
What soc is on you board? rk3566 or rk3568?
I have a scripts[0] use io[1] command to dump the VOP2 register you can use it dump the register configuration when you meet a display failure,
then send the dump to me, maybe I can figure out something.
[0]https://github.com/andyshrk/buildroot/blob/2022/board/andyshrk/rootfs_overla...
[1] https://github.com/andyshrk/io
Sascha
On Thu, Mar 31, 2022 at 08:13:09PM +0800, Andy Yan wrote:
Hi Piotr:
On 3/31/22 03:20, Sascha Hauer wrote:
On Wed, Mar 30, 2022 at 04:52:22PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 30.03.2022, o godz. 12:20:
Does it change anything if you do a "modetest -s 69@67:1920x1080" before starting the app? Or if you run "modetest -P 43@67:1920x1080@NV12" before starting the app? Or other combinations thereof?
So i tried following combinations
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
I have no idea what is going on here. There same commands work for me. You could provide me your kernel config and upstream commitish you are working on, maybe that gets me closer to your setup.
It's a little strange, I can't reproduce this issue neither.
But I have problem with this two step command sequence.
step 1: modetest -s 69@67:1920x1080 -> ok
step 2: modetest -P 43@67:1920x1080@NV12,
I got the failed message: "failed to enable plane: Permission denied"
Because the drm core will stop step2 by drm_ioctrl_permit as DRM_IOCTL_SETPLANE need a master,
but the current master is the modetest run by step1.
[...]
So how you two got step two run success?
You have to stop the first modetest by hitting return. Alternatively you could pass the -d option to the first modetest.
Sascha
Wiadomość napisana przez Andy Yan andy.yan@rock-chips.com w dniu 31.03.2022, o godz. 14:13:
Piotr:
What soc is on you board? rk3566 or rk3568?
it is rk3566 in x96-x6 tvbox
I have a scripts[0] use io[1] command to dump the VOP2 register you can use it dump the register configuration when you meet a display failure,
then send the dump to me, maybe I can figure out something.
[0]https://github.com/andyshrk/buildroot/blob/2022/board/andyshrk/rootfs_overla...
Andy
Pls see https://pastebin.com/CHmu9s22
I put dumps for following scenarios:
1. -boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
2. -boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width) (setting palne#49 fixes plane #43. Here i set plane #49 but not yet setting #43)
3. -boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width) -modetest -P 43@67:1920x1080@NV12 -> now ok (but shifted horizontally by about 5% of screen width)
On Thu, Mar 31, 2022 at 04:53:05PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Andy Yan andy.yan@rock-chips.com w dniu 31.03.2022, o godz. 14:13:
Piotr:
What soc is on you board? rk3566 or rk3568?
it is rk3566 in x96-x6 tvbox
I have a scripts[0] use io[1] command to dump the VOP2 register you can use it dump the register configuration when you meet a display failure,
then send the dump to me, maybe I can figure out something.
[0]https://github.com/andyshrk/buildroot/blob/2022/board/andyshrk/rootfs_overla...
Andy
Pls see https://pastebin.com/CHmu9s22
I put dumps for following scenarios:
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width)
Have you applied the bugfix I shared with you here:
https://lore.kernel.org/linux-arm-kernel/20220330072822.GX12181@pengutronix....
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 31.03.2022, o godz. 17:00:
Have you applied the bugfix I shared with you here:
https://lore.kernel.org/linux-arm-kernel/20220330072822.GX12181@pengutronix....
oooops
noooooo didn't noticed :-(
let me try with it!
Wiadomość napisana przez Piotr Oniszczuk piotr.oniszczuk@gmail.com w dniu 31.03.2022, o godz. 17:06:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 31.03.2022, o godz. 17:00:
Have you applied the bugfix I shared with you here:
https://lore.kernel.org/linux-arm-kernel/20220330072822.GX12181@pengutronix....
oooops
noooooo didn't noticed :-(
let me try with it!
ok - i tried. unfortunately no any difference :-(
Hi Piotr:
On 3/31/22 22:53, Piotr Oniszczuk wrote:
Wiadomość napisana przez Andy Yanandy.yan@rock-chips.com w dniu 31.03.2022, o godz. 14:13:
Piotr:
What soc is on you board? rk3566 or rk3568?
it is rk3566 in x96-x6 tvbox
RK3566? Maybe that is the problem.
plane[43]: Esmart1-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
From your dri/state dump, Plane 43 is Esmart1.
Cluster1, Esmart1, Smart1 are special on rk3566, they are
mirror window of Cluster0, Esmart0, Esmart0. That means
the software can't program a independent framebuffer for
these three windows. They can only share the fb address set
in Cluster0, Esmart0, Smart0.
For rk3566, we only use it for two VP display same content:
assign Cluster0,Esmart0,Smart0 to VP1 for primary display(MIPI),
assign Cluster1,Esmart1, Smart1 to VP0 for extend display(HDMI)
we handle this logic in Android hwc:
When a hdmi is connected, hwc will commit Esmart1 with Esmart0 with the
same fb and src buffer size, the dst can be different(by window scale)
I have code comment in my downstream kernel and explained this detail when Sascha start submit this serials.
I have a scripts[0] use io[1] command to dump the VOP2 register you can use it dump the register configuration when you meet a display failure,
then send the dump to me, maybe I can figure out something.
[0]https://github.com/andyshrk/buildroot/blob/2022/board/andyshrk/rootfs_overla...
Andy
The dump is a little strange, I will check it in the later night.
I put dumps for following scenarios:
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width) (setting palne#49 fixes plane #43. Here i set plane #49 but not yet setting #43)
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width) -modetest -P 43@67:1920x1080@NV12 -> now ok (but shifted horizontally by about 5% of screen width)
On Fri, Apr 01, 2022 at 09:52:01AM +0800, Andy Yan wrote:
Hi Piotr:
On 3/31/22 22:53, Piotr Oniszczuk wrote:
Wiadomość napisana przez Andy Yan [1]andy.yan@rock-chips.com w dniu 31.03.2022, o godz. 14:13:
Piotr:
What soc is on you board? rk3566 or rk3568?
it is rk3566 in x96-x6 tvbox
RK3566? Maybe that is the problem.
Likely, yes.
plane[43]: Esmart1-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
From your dri/state dump, Plane 43 is Esmart1.
Cluster1, Esmart1, Smart1 are special on rk3566, they are
mirror window of Cluster0, Esmart0, Esmart0. That means
the software can't program a independent framebuffer for
these three windows. They can only share the fb address set
in Cluster0, Esmart0, Smart0.
Downstream Kernel has this:
static bool vop2_is_mirror_win(struct vop2_win *win) { return soc_is_rk3566() && (win->feature & WIN_FEATURE_MIRROR); }
static int vop2_create_crtc(struct vop2 *vop2) { ...
for (j = 0; j < vop2->registered_num_wins; j++) { win = &vop2->win[j];
if (win->type != DRM_PLANE_TYPE_OVERLAY) continue; /* * Only dual display on rk3568(which need two crtcs) need mirror win */ if (registered_num_crtcs < 2 && vop2_is_mirror_win(win)) continue;
...
ret = vop2_plane_init(vop2, win, possible_crtcs); }
... }
"Smart1-win0" and "Esmart1-win0" have this WIN_FEATURE_MIRROR bit set. It seems we just should just don't register these windows for rk3566.
Sascha
Hi Piotr:
On 4/1/22 09:52, Andy Yan wrote:
Hi Piotr:
On 3/31/22 22:53, Piotr Oniszczuk wrote:
Wiadomość napisana przez Andy Yanandy.yan@rock-chips.com w dniu 31.03.2022, o godz. 14:13:
Piotr:
What soc is on you board? rk3566 or rk3568?
it is rk3566 in x96-x6 tvbox
RK3566? Maybe that is the problem.
plane[43]: Esmart1-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
From your dri/state dump, Plane 43 is Esmart1.
Cluster1, Esmart1, Smart1 are special on rk3566, they are
mirror window of Cluster0, Esmart0, Esmart0. That means
the software can't program a independent framebuffer for
these three windows. They can only share the fb address set
in Cluster0, Esmart0, Smart0.
For rk3566, we only use it for two VP display same content:
assign Cluster0,Esmart0,Smart0 to VP1 for primary display(MIPI),
assign Cluster1,Esmart1, Smart1 to VP0 for extend display(HDMI)
we handle this logic in Android hwc:
When a hdmi is connected, hwc will commit Esmart1 with Esmart0 with the
same fb and src buffer size, the dst can be different(by window scale)
I have code comment in my downstream kernel and explained this detail when Sascha start submit this serials.
I have a scripts[0] use io[1] command to dump the VOP2 register you can use it dump the register configuration when you meet a display failure,
then send the dump to me, maybe I can figure out something.
[0]https://github.com/andyshrk/buildroot/blob/2022/board/andyshrk/rootfs_overla...
Andy
The dump is a little strange, I will check it in the later night.
Pls update the new vop2_dump.sh scripts from github. The
previous scripts I gave you has some bug. sorry.
I put dumps for following scenarios:
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 43@67:1920x1080@NV12 -> green screen
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width) (setting palne#49 fixes plane #43. Here i set plane #49 but not yet setting #43)
-boot -modetest -s 69@67:1920x1080 -> ok -modetest -P 49@67:1920x1080@NV12 -> ok (but shifted horizontally by about 5% of screen width) -modetest -P 43@67:1920x1080@NV12 -> now ok (but shifted horizontally by about 5% of screen width)
Wiadomość napisana przez Andy Yan andy.yan@rock-chips.com w dniu 01.04.2022, o godz. 14:04:
Hi Piotr:
On 4/1/22 09:52, Andy Yan wrote:
Pls update the new vop2_dump.sh scripts from github. The
previous scripts I gave you has some bug. sorry.
Andy,
Sure. np. Pls find dump with current vop2_dump.sh https://pastebin.com/CwVj0kuX
btw: this is with latest patch from Sascha: https://lore.kernel.org/linux-arm-kernel/20220330072822.GX12181@pengutronix....
Hi Piotr,
On Tue, Mar 29, 2022 at 09:31:01AM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 28.03.2022, o godz. 17:10:
Changes since v8:
- make hclk_vo a critical clock instead of enabling it in the hdmi driver
- Fix vop2_setup_layer_mixer(), reported by Andy Yan
- Limit planes possible_crtcs to actually existing crtcs
Sascha,
FYI: I was hoping v9 will fix green screen issue i see when video player wants to draw to nv12 capable drm plane. It look issue is still present :-(
Based on the discussion with Andy please try the following patch, it should fix your green screen issue. Note that with this patch the CRTC and plane ids will change, so the modetest commands need to be adjusted accordingly.
Sascha
-------------------------8<---------------------------
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 01.04.2022, o godz. 14:52:
Based on the discussion with Andy please try the following patch, it should fix your green screen issue. Note that with this patch the CRTC and plane ids will change, so the modetest commands need to be adjusted accordingly.
Sascha
-------------------------8<---------------------------
-- From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001 From: Sascha Hauer s.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
}
- if (win->type == DRM_PLANE_TYPE_OVERLAY) possible_crtcs = (1 << nvps) - 1;
-- 2.30.2
Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Sascha
Now works perfectly! (hd playback with 3.5...5.5% cpu while rendering to drm plane)
Fantastic work of You!
Wiadomość napisana przez Piotr Oniszczuk piotr.oniszczuk@gmail.com w dniu 01.04.2022, o godz. 15:05:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 01.04.2022, o godz. 14:52:
Based on the discussion with Andy please try the following patch, it should fix your green screen issue. Note that with this patch the CRTC and plane ids will change, so the modetest commands need to be adjusted accordingly.
Sascha
-------------------------8<---------------------------
-- From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001 From: Sascha Hauer s.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
}
- if (win->type == DRM_PLANE_TYPE_OVERLAY) possible_crtcs = (1 << nvps) - 1;
-- 2.30.2
Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Sascha
Now works perfectly! (hd playback with 3.5...5.5% cpu while rendering to drm plane)
Fantastic work of You!
Sascha,
Having vop2 finally working with drm planes rendering i discovered another issue: overlay osd is invisible at playback.
context: player draws video on plane #X and osd on overlay plane #Y When user do i.e. seek at playback - app uses overlay OSD plane to display OSD to user. This approach is used by majority of players (KODI, etc.)
This works well on all platforms i have - except rk3566
For me it looks like z-order vop2 issue or alpha blending issue. As this is only on rk3566 and only on drm-planes mode - issue is vop2 related imho.
what you think?
On Wed, Apr 06, 2022 at 11:47:22AM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Piotr Oniszczuk piotr.oniszczuk@gmail.com w dniu 01.04.2022, o godz. 15:05:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 01.04.2022, o godz. 14:52:
Based on the discussion with Andy please try the following patch, it should fix your green screen issue. Note that with this patch the CRTC and plane ids will change, so the modetest commands need to be adjusted accordingly.
Sascha
-------------------------8<---------------------------
-- From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001 From: Sascha Hauer s.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
}
- if (win->type == DRM_PLANE_TYPE_OVERLAY) possible_crtcs = (1 << nvps) - 1;
-- 2.30.2
Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
Sascha
Now works perfectly! (hd playback with 3.5...5.5% cpu while rendering to drm plane)
Fantastic work of You!
Sascha,
Having vop2 finally working with drm planes rendering i discovered another issue: overlay osd is invisible at playback.
context: player draws video on plane #X and osd on overlay plane #Y When user do i.e. seek at playback - app uses overlay OSD plane to display OSD to user. This approach is used by majority of players (KODI, etc.)
This works well on all platforms i have - except rk3566
For me it looks like z-order vop2 issue or alpha blending issue. As this is only on rk3566 and only on drm-planes mode - issue is vop2 related imho.
During my testing I haven't seen any z-order issues, but that doesn't mean much. With Weston I can currently only use the AFBC enabled cluster windows and with modetest I can only use the non-cluster windows. Are you able to find out which window is used for the OSD?
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 06.04.2022, o godz. 16:58:
On Wed, Apr 06, 2022 at 11:47:22AM +0200, Piotr Oniszczuk wrote:
Sascha,
Having vop2 finally working with drm planes rendering i discovered another issue: overlay osd is invisible at playback.
context: player draws video on plane #X and osd on overlay plane #Y When user do i.e. seek at playback - app uses overlay OSD plane to display OSD to user. This approach is used by majority of players (KODI, etc.)
This works well on all platforms i have - except rk3566
For me it looks like z-order vop2 issue or alpha blending issue. As this is only on rk3566 and only on drm-planes mode - issue is vop2 related imho.
During my testing I haven't seen any z-order issues, but that doesn't mean much. With Weston I can currently only use the AFBC enabled cluster windows and with modetest I can only use the non-cluster windows. Are you able to find out which window is used for the OSD?
Sascha
-- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
WiIl this answer to your Q?
player:
2022-04-06 17:52:26.424487 I Display: Geometry: 1920x1080+0+0 Size(Qt): 930mmx530mm 2022-04-06 17:52:26.424922 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-06 17:52:26.425061 I /dev/dri/card0: Authenticated 2022-04-06 17:52:26.534362 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-06 17:52:26.534384 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-06 17:52:26.534430 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-06 17:52:26.534437 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-06 17:52:26.534480 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-06 17:52:26.534489 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
so: plane #37 is where video is drawing plane #43 is GUI/OSD
dri state:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[37]: Esmart0-win0 crtc=(null) fb=0 crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[43]: Cluster0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range crtc[49]: video_port0 enable=1 active=1 self_refresh_active=0 planes_changed=1 mode_changed=0 active_changed=0 connectors_changed=0 color_mgmt_changed=0 plane_mask=1 connector_mask=1 encoder_mask=1 mode: "1920x1080": 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5 connector[51]: HDMI-A-1 crtc=video_port0 self_refresh_aware=0
On Wed, Apr 06, 2022 at 06:00:00PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 06.04.2022, o godz. 16:58:
On Wed, Apr 06, 2022 at 11:47:22AM +0200, Piotr Oniszczuk wrote:
Sascha,
Having vop2 finally working with drm planes rendering i discovered another issue: overlay osd is invisible at playback.
context: player draws video on plane #X and osd on overlay plane #Y When user do i.e. seek at playback - app uses overlay OSD plane to display OSD to user. This approach is used by majority of players (KODI, etc.)
This works well on all platforms i have - except rk3566
For me it looks like z-order vop2 issue or alpha blending issue. As this is only on rk3566 and only on drm-planes mode - issue is vop2 related imho.
During my testing I haven't seen any z-order issues, but that doesn't mean much. With Weston I can currently only use the AFBC enabled cluster windows and with modetest I can only use the non-cluster windows. Are you able to find out which window is used for the OSD?
Sascha
-- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
WiIl this answer to your Q?
Yes, and it raises a few more ;)
player:
2022-04-06 17:52:26.424487 I Display: Geometry: 1920x1080+0+0 Size(Qt): 930mmx530mm 2022-04-06 17:52:26.424922 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-06 17:52:26.425061 I /dev/dri/card0: Authenticated 2022-04-06 17:52:26.534362 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-06 17:52:26.534384 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-06 17:52:26.534430 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-06 17:52:26.534437 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-06 17:52:26.534480 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-06 17:52:26.534489 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
so: plane #37 is where video is drawing plane #43 is GUI/OSD
dri state:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Ok, this seems to be the base plane.
plane[37]: Esmart0-win0 crtc=(null)
crtc=null? Did you capture the state without a video playing? Otherwise I would expect a crtc associated here.
fb=0 crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
plane[43]: Cluster0-win0 crtc=(null)
This plane is selected for OSD by your application. The cluster windows can't show a regular linear framebuffer, they can only do AFBC. You'll see that in modetest:
in_formats blob decoded: XR24: ARM_BLOCK_SIZE=16x16, ARM_BLOCK_SIZE=16x16,MODE=SPARSE ARM_BLOCK_SIZE=16x16,MODE=YTR ARM_BLOCK_SIZE=16x16,MODE=CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|SPARSE ARM_BLOCK_SIZE=16x16,MODE=SPARSE|CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|SPARSE|CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|SPLIT|SPARSE ...
The other windows show "XR24: LINEAR" here. Does your application use the GPU to render the OSD? Otherwise I doubt your application can handle this format, so it should not use this layer.
fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0
I would be interested in this output when the player is actually playing something. This normalized-zpos puzzles me a bit. Normally it should be unique over all enabled planes for a CRTC. Maybe 0 is ok here because it's currently not associated to any CRTC.
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 07.04.2022, o godz. 12:16:
Yes, and it raises a few more ;)
pls see at end of email: DRI state with playback
player:
2022-04-06 17:52:26.424487 I Display: Geometry: 1920x1080+0+0 Size(Qt): 930mmx530mm 2022-04-06 17:52:26.424922 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-06 17:52:26.425061 I /dev/dri/card0: Authenticated 2022-04-06 17:52:26.534362 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-06 17:52:26.534384 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-06 17:52:26.534430 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-06 17:52:26.534437 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-06 17:52:26.534480 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-06 17:52:26.534489 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
so: plane #37 is where video is drawing plane #43 is GUI/OSD
dri state:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Ok, this seems to be the base plane.
plane[37]: Esmart0-win0 crtc=(null)
crtc=null? Did you capture the state without a video playing? Otherwise I would expect a crtc associated here.
Indeed. This was from player sitting in UI (no playback). Pls see at bottom of email state with video playback (it has crtc=video_port0)
fb=0 crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
plane[43]: Cluster0-win0 crtc=(null)
This plane is selected for OSD by your application. The cluster windows can't show a regular linear framebuffer, they can only do AFBC. You'll see that in modetest:
in_formats blob decoded: XR24: ARM_BLOCK_SIZE=16x16, ARM_BLOCK_SIZE=16x16,MODE=SPARSE ARM_BLOCK_SIZE=16x16,MODE=YTR ARM_BLOCK_SIZE=16x16,MODE=CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|SPARSE ARM_BLOCK_SIZE=16x16,MODE=SPARSE|CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|SPARSE|CBR ARM_BLOCK_SIZE=16x16,MODE=YTR|SPLIT|SPARSE ...
The other windows show "XR24: LINEAR" here. Does your application use the GPU to render the OSD?
Yes.
Otherwise I doubt your application can handle this format, so it should not use this layer.
fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0
I would be interested in this output when the player is actually playing something.
Pls see at bottom.
This normalized-zpos puzzles me a bit.
I'm not surprised :-). You are puzzled probably because rk35xx current VOP2 code requires - from me - to force Z-position = 0 in Qt if I want to have GUI visible on screen. Without this screen is black. This seems to be i think - another issue to resolve (no any other SoC requires this....). I'm not sure where issue is - but as i need to do this only on VOP2 - i think there is somewhere something not right in VOP2 code.
Normally it should be unique over all enabled planes for a CRTC. Maybe 0 is ok here because it's currently not associated to any CRTC.
It is because of me setting it to 0 (see explanations above)
DRI state with video playback:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=55 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[37]: Esmart0-win0 crtc=video_port0 fb=65 allocated by = mythfrontend refcount=2 format=NV12 little-endian (0x3231564e) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=1920 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=3657728 imported=yes size[1]=960x540 pitch[1]=1920 offset[1]=2088960 obj[1]: name=0 refcount=3 start=00000000 size=3657728 imported=yes crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[43]: Cluster0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range crtc[49]: video_port0 enable=1 active=1 self_refresh_active=0 planes_changed=1 mode_changed=0 active_changed=0 connectors_changed=0 color_mgmt_changed=0 plane_mask=3 connector_mask=1 encoder_mask=1 mode: "1920x1080": 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5 connector[51]: HDMI-A-1 crtc=video_port0 self_refresh_aware=0
On Wed, Apr 06, 2022 at 11:47:22AM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Piotr Oniszczuk piotr.oniszczuk@gmail.com w dniu 01.04.2022, o godz. 15:05: Sascha
Now works perfectly! (hd playback with 3.5...5.5% cpu while rendering to drm plane)
Fantastic work of You!
Sascha,
Having vop2 finally working with drm planes rendering i discovered another issue: overlay osd is invisible at playback.
context: player draws video on plane #X and osd on overlay plane #Y When user do i.e. seek at playback - app uses overlay OSD plane to display OSD to user. This approach is used by majority of players (KODI, etc.)
This works well on all platforms i have - except rk3566
For me it looks like z-order vop2 issue or alpha blending issue. As this is only on rk3566 and only on drm-planes mode - issue is vop2 related imho.
That turned out to be simpler than I thought it would be. The zpos values were never actually written to the hardware. Please try the following fixup, it should fix this issue.
Thanks for your valuable testing feedback so far :)
Sascha
----------------------------8<------------------------
From d5a102ff1d3010320f492a6ebac6710276fc641f Mon Sep 17 00:00:00 2001
From: Sascha Hauer s.hauer@pengutronix.de Date: Fri, 8 Apr 2022 09:45:24 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
--- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 54208b20a5a7e..8d1323a47f822 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1943,8 +1943,10 @@ static void vop2_setup_layer_mixer(struct vop2_video_port *vp) break; }
- layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, 0x7); - layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(nlayer + ofs, win->data->layer_sel_id); + layer_sel &= ~RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, + 0x7); + layer_sel |= RK3568_OVL_LAYER_SEL__LAYER(plane->state->normalized_zpos + ofs, + win->data->layer_sel_id); nlayer++; }
On Fri, Apr 08, 2022 at 10:07:48AM +0200, Sascha Hauer wrote:
On Wed, Apr 06, 2022 at 11:47:22AM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Piotr Oniszczuk piotr.oniszczuk@gmail.com w dniu 01.04.2022, o godz. 15:05: Sascha
Now works perfectly! (hd playback with 3.5...5.5% cpu while rendering to drm plane)
Fantastic work of You!
Sascha,
Having vop2 finally working with drm planes rendering i discovered another issue: overlay osd is invisible at playback.
context: player draws video on plane #X and osd on overlay plane #Y When user do i.e. seek at playback - app uses overlay OSD plane to display OSD to user. This approach is used by majority of players (KODI, etc.)
This works well on all platforms i have - except rk3566
For me it looks like z-order vop2 issue or alpha blending issue. As this is only on rk3566 and only on drm-planes mode - issue is vop2 related imho.
That turned out to be simpler than I thought it would be. The zpos values were never actually written to the hardware. Please try the following fixup, it should fix this issue.
Or better try v10 which I have just sent.
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 08.04.2022, o godz. 14:00:
That turned out to be simpler than I thought it would be. The zpos values were never actually written to the hardware. Please try the following fixup, it should fix this issue.
Or better try v10 which I have just sent.
Sascha,
I applied v10 on 5.17.2 and...can't see difference. I still need to play with zpos to get ui screen. if i have playback - no OSD. If I have OSD - no playback.
Maybe fix needs some adjustments for 3566?
Here is short summary of playings with zpos and kms plane in Qt:
QT_QPA_EGLFS_KMS_ZPOS, QT_QPA_EGLFS_KMS_PLANE_INDEX
0,0 - GUI=ok, playback=ok, OSD=nok 1,0 - GUI=ok, playback=nok, OSD=ok 2,0 - GUI=ok, playback=nok, OSD=ok
0,1 - GUI=ok, playback=nok, OSD=ok 1,1 - GUI=ok, playback=nok, OSD=ok 2,1 - GUI=ok, playback=nok, OSD=ok
0,2 - GUI=nok, playback=n/a, OSD=n/a 1,2 - GUI=nok, playback=n/a, OSD=n/a 2,2 - GUI=nok, playback=n/a, OSD=n/a
player launch: ....... 2022-04-08 17:47:57.035668 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-08 17:47:57.035806 I /dev/dri/card0: Authenticated 2022-04-08 17:47:57.145447 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-08 17:47:57.145469 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-08 17:47:57.145515 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-08 17:47:57.145523 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-08 17:47:57.145567 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-08 17:47:57.145574 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1 .......
playback: ..... 2022-04-08 17:48:55.457823 I DRMVideo: Using Plane #37 for video .....
DRI state with zpos=0, kms_id=0 and ongoing playback:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[37]: Esmart0-win0 crtc=video_port0 fb=65 allocated by = mythfrontend refcount=2 format=NV12 little-endian (0x3231564e) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=1920 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=3657728 imported=yes size[1]=960x540 pitch[1]=1920 offset[1]=2088960 obj[1]: name=0 refcount=3 start=00000000 size=3657728 imported=yes crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[43]: Cluster0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range crtc[49]: video_port0 enable=1 active=1 self_refresh_active=0 planes_changed=1 mode_changed=0 active_changed=0 connectors_changed=0 color_mgmt_changed=0 plane_mask=3 connector_mask=1 encoder_mask=1 mode: "1920x1080": 50 148500 1920 2448 2492 2640 1080 1084 1089 1125 0x40 0x5 connector[51]: HDMI-A-1 crtc=video_port0 self_refresh_aware=0 root@Myth-Frontend-06c7e973c2f1:~ #
On Fri, Apr 08, 2022 at 05:54:24PM +0200, Piotr Oniszczuk wrote:
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 08.04.2022, o godz. 14:00:
That turned out to be simpler than I thought it would be. The zpos values were never actually written to the hardware. Please try the following fixup, it should fix this issue.
Or better try v10 which I have just sent.
Sascha,
I applied v10 on 5.17.2 and...can't see difference. I still need to play with zpos to get ui screen. if i have playback - no OSD. If I have OSD - no playback.
Maybe fix needs some adjustments for 3566?
I don't think so.
player launch: ....... 2022-04-08 17:47:57.035668 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-08 17:47:57.035806 I /dev/dri/card0: Authenticated 2022-04-08 17:47:57.145447 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-08 17:47:57.145469 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-08 17:47:57.145515 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-08 17:47:57.145523 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-08 17:47:57.145567 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-08 17:47:57.145574 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
Ok, so #37 for video, #43 for GUI.
Where is the OSD rendered? Is it rendered on the GUI layer?
.......
playback: ..... 2022-04-08 17:48:55.457823 I DRMVideo: Using Plane #37 for video .....
DRI state with zpos=0, kms_id=0 and ongoing playback:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Base plane.
plane[37]: Esmart0-win0 crtc=video_port0 fb=65 allocated by = mythfrontend refcount=2 format=NV12 little-endian (0x3231564e) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=1920 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=3657728 imported=yes size[1]=960x540 pitch[1]=1920 offset[1]=2088960 obj[1]: name=0 refcount=3 start=00000000 size=3657728 imported=yes crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Video plane, rendered full screen above the base plane without alpha.
plane[43]: Cluster0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Here should be the GUI, but this plane is not active.
With this state I would expect to see a full screen video without anything on it. Is that the case? If yes, then fine.
Could you post a state where you expect something else than is actually seen?
Sascha
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 11.04.2022, o godz. 11:08:
Ok, so #37 for video, #43 for GUI.
Where is the OSD rendered? Is it rendered on the GUI layer?
Yes
.......
playback: ..... 2022-04-08 17:48:55.457823 I DRMVideo: Using Plane #37 for video .....
DRI state with zpos=0, kms_id=0 and ongoing playback:
root@Myth-Frontend-06c7e973c2f1:~ # cat /sys/kernel/debug/dri/0/state plane[31]: Smart0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Base plane.
plane[37]: Esmart0-win0 crtc=video_port0 fb=65 allocated by = mythfrontend refcount=2 format=NV12 little-endian (0x3231564e) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=1920 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=3657728 imported=yes size[1]=960x540 pitch[1]=1920 offset[1]=2088960 obj[1]: name=0 refcount=3 start=00000000 size=3657728 imported=yes crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Video plane, rendered full screen above the base plane without alpha.
plane[43]: Cluster0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range
Here should be the GUI, but this plane is not active.
I suspect this is because above DRI state report was with user-forced Qt vars. This was because to get UI non-black screen. I done this by request to provide DRI state with video playback. (to get playback I need UI to navigate) By this DRI state report might misleading as i'm manually forcing Qt KMS_Index/Zpos.
With this state I would expect to see a full screen video without anything on it. Is that the case? If yes, then fine.
yes. this is a case. so this is fine.
So I think non-visible OSD issue is side effect of other, root cause issue: issue causing user to force Qt vars to get UI on VOP2
Context: (my view):
We have stack of 3 components interacting: 1.player (draws video to DRM plane) 2.Qt (draws UI to GL to DRM plane) 3.DRM (mixing planes+displaying)
Stack coperation: a. DRM reports available planes+attributes to player b. player - accordingly to above report - sets Qt (KMS/Zpos, etc). c. user starting player. player uses Qt for drawing UI d. user asks for playback e. player draws (by Qt) OSD and directly video (accordingly to Qt setup in (b)
With VOP2 i have issue at (c): screen is black. Above procedure works fully automated on all other platforms i have/supporting.
For me most probable hypothesis:
1\ - In steep (b) Qt is set (or configured to use DRM) in way that UI resulting with black screen - this is because in (a) player receives (wrong?) DRM report - and by this Qt is wrongly set This may explain we have issue at (c)
2\ - In steep (b) Qt is set & using DRM in way that UI should work ok - but VOP2 draws black screen (by some reason) This may explain we have issue at (c)
Alternative hypothesis: DRM properly realises (a) Player wrongly realises (b) This hypothesis is way less probable (for me) because: 1. procedure (a)...(e) works well on all other SoC. No need from user to overwrite automatically detected/set of Qt vars. 2. vop2 is single requiring from user overwrite of autodetected Qt vars. to get non-black screen UI.
I'm a bit out of ideas how to progress with this.
As (a)...(e) concept works ok (and afaik also is used by other players exploiting DRM planes rendering) - i'm not sure should I play with (b) because of VOP2 black-screen?
BTW: this is DRI state when there is no any Qt.vars overwrites. (so all is autodetected/setup like in other working SoCs; VOP2 gives here black screen UI):
2022-04-08 17:47:57.035668 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-08 17:47:57.035806 I /dev/dri/card0: Authenticated 2022-04-08 17:47:57.145447 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-08 17:47:57.145469 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-08 17:47:57.145515 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-08 17:47:57.145523 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-08 17:47:57.145567 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-08 17:47:57.145574 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
plane[31]: Smart0-win0 crtc=video_port0 fb=53 allocated by = [fbcon] refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[37]: Esmart0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[43]: Cluster0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=AR24 little-endian (0x34325241) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=4 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=1 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range crtc[49]: video_port0 enable=1 active=1 self_refresh_active=0 planes_changed=1 mode_changed=0 active_changed=0 connectors_changed=0 color_mgmt_changed=0 plane_mask=5 connector_mask=1 encoder_mask=1 mode: "1920x1080": 60 148500 1920 2008 2052 2200 1080 1084 1089 1125 0x48 0x5 connector[51]: HDMI-A-1 crtc=video_port0 self_refresh_aware=0
On Mon, Apr 11, 2022 at 01:07:56PM +0200, Piotr Oniszczuk wrote:
this is DRI state when there is no any Qt.vars overwrites. (so all is autodetected/setup like in other working SoCs; VOP2 gives here black screen UI):
2022-04-08 17:47:57.035668 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-08 17:47:57.035806 I /dev/dri/card0: Authenticated 2022-04-08 17:47:57.145447 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-08 17:47:57.145469 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-08 17:47:57.145515 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-08 17:47:57.145523 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-08 17:47:57.145567 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-08 17:47:57.145574 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
plane[31]: Smart0-win0 crtc=video_port0 fb=53 allocated by = [fbcon] refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[37]: Esmart0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[43]: Cluster0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=AR24 little-endian (0x34325241)
Here is your problem. The cluster windows only allow AFBC compressed formats. AR24 is supported by the cluster windows, but not by the GPU, see panfrost_afbc_format() in Mesa:
enum pipe_format panfrost_afbc_format(const struct panfrost_device *dev, enum pipe_format format) { /* Don't allow swizzled formats on v7 */ switch (format) { case PIPE_FORMAT_B8G8R8A8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_A8R8G8B8_UNORM: case PIPE_FORMAT_X8R8G8B8_UNORM: case PIPE_FORMAT_X8B8G8R8_UNORM: case PIPE_FORMAT_A8B8G8R8_UNORM: case PIPE_FORMAT_B8G8R8_UNORM: case PIPE_FORMAT_B5G6R5_UNORM: if (dev->arch >= 7) return PIPE_FORMAT_NONE;
break; default: break; }
Somehow negotiation of the format goes wrong. Applications shouldn't pick these formats when the GPU is used for rendering. I don't know how and where this should be fixed properly, but your application should use DRM_FORMAT_ABGR8888 aka AB24 aka PIPE_FORMAT_R8G8B8A8_UNORM instead of DRM_FORMAT_ARGB8888 aka AR24 aka PIPE_FORMAT_B8G8R8A8_UNORM.
Could you try the following patch? It removed the formats in question from the list of supported formats in the hope that your application then picks one of the supported formats.
Sascha
-----------------------8<-----------------------------
From 7427109cfd16803902b55cd5536b9212abd09665 Mon Sep 17 00:00:00 2001
From: Sascha Hauer s.hauer@pengutronix.de Date: Tue, 12 Apr 2022 09:42:32 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
The cluster windows only allow AFBC compressed formats. Not all of the offered formats are supported by the GPU though. Applications pick one of the formats and assume that this is also supported by the GPU they use to render on them, but this is not the case for all formats. Particularly DRM_FORMAT_XRGB8888 and DRM_FORMAT_ARGB8888 are not supported by the GPU and choosing them results in a black screen. Drop these formats for now.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 9bf0637bf8e26..38412766e3659 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -16,8 +16,6 @@ #include "rockchip_drm_vop2.h"
static const uint32_t formats_win_full_10bit[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB888,
Am Dienstag, dem 12.04.2022 um 09:50 +0200 schrieb Sascha Hauer:
On Mon, Apr 11, 2022 at 01:07:56PM +0200, Piotr Oniszczuk wrote:
this is DRI state when there is no any Qt.vars overwrites. (so all is autodetected/setup like in other working SoCs; VOP2 gives here black screen UI):
2022-04-08 17:47:57.035668 I /dev/dri/card0 Qt EGLFS/KMS Fd:5 Crtc id:49 Connector id:51 Atomic: 1 2022-04-08 17:47:57.035806 I /dev/dri/card0: Authenticated 2022-04-08 17:47:57.145447 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 2022-04-08 17:47:57.145469 I /dev/dri/card0: Selected Plane #37 Overlay for video 2022-04-08 17:47:57.145515 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 2022-04-08 17:47:57.145523 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 2022-04-08 17:47:57.145567 I /dev/dri/card0: DRM device retrieved from Qt 2022-04-08 17:47:57.145574 I /dev/dri/card0: Multi-plane setup: Requested: 1 Setup: 1
plane[31]: Smart0-win0 crtc=video_port0 fb=53 allocated by = [fbcon] refcount=2 format=XR24 little-endian (0x34325258) modifier=0x0 size=1920x1080 layers: size[0]=1920x1080 pitch[0]=7680 offset[0]=0 obj[0]: name=0 refcount=3 start=00000000 size=8294400 imported=no crtc-pos=1920x1080+0+0 src-pos=1920.000000x1080.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[37]: Esmart0-win0 crtc=(null) fb=0 crtc-pos=0x0+0+0 src-pos=0.000000x0.000000+0.000000+0.000000 rotation=1 normalized-zpos=0 color-encoding=ITU-R BT.601 YCbCr color-range=YCbCr limited range plane[43]: Cluster0-win0 crtc=video_port0 fb=58 allocated by = mythfrontend refcount=2 format=AR24 little-endian (0x34325241)
Here is your problem. The cluster windows only allow AFBC compressed formats. AR24 is supported by the cluster windows, but not by the GPU, see panfrost_afbc_format() in Mesa:
enum pipe_format panfrost_afbc_format(const struct panfrost_device *dev, enum pipe_format format) { /* Don't allow swizzled formats on v7 */ switch (format) { case PIPE_FORMAT_B8G8R8A8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_A8R8G8B8_UNORM: case PIPE_FORMAT_X8R8G8B8_UNORM: case PIPE_FORMAT_X8B8G8R8_UNORM: case PIPE_FORMAT_A8B8G8R8_UNORM: case PIPE_FORMAT_B8G8R8_UNORM: case PIPE_FORMAT_B5G6R5_UNORM: if (dev->arch >= 7) return PIPE_FORMAT_NONE;
break; default: break; }
Somehow negotiation of the format goes wrong. Applications shouldn't pick these formats when the GPU is used for rendering. I don't know how and where this should be fixed properly, but your application should use DRM_FORMAT_ABGR8888 aka AB24 aka PIPE_FORMAT_R8G8B8A8_UNORM instead of DRM_FORMAT_ARGB8888 aka AR24 aka PIPE_FORMAT_B8G8R8A8_UNORM.
This could be both a Mesa/Panfrost or application issue. The application is supposed to try to allocate with a arbitrary chosen format and the valid modifiers queried from the plane it wants to put the surface on. However I'm not sure if all applications have a fallback path in place to try another format swizzling if the surface allocation fails. Now there are two possible failures here:
1. The application feeds a wrong modifier list to the GBM implementation, as it may have queried another plane in the assumption that supported modifiers are uniform across all planes.
2. The GBM implementation (Panfrost) actually allocates a surface instead of failing the allocation, even if it does not support any combination of the provided format and modifier list.
Regards, Lucas
Could you try the following patch? It removed the formats in question from the list of supported formats in the hope that your application then picks one of the supported formats.
Sascha
-----------------------8<-----------------------------
From 7427109cfd16803902b55cd5536b9212abd09665 Mon Sep 17 00:00:00 2001 From: Sascha Hauer s.hauer@pengutronix.de Date: Tue, 12 Apr 2022 09:42:32 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
The cluster windows only allow AFBC compressed formats. Not all of the offered formats are supported by the GPU though. Applications pick one of the formats and assume that this is also supported by the GPU they use to render on them, but this is not the case for all formats. Particularly DRM_FORMAT_XRGB8888 and DRM_FORMAT_ARGB8888 are not supported by the GPU and choosing them results in a black screen. Drop these formats for now.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 9bf0637bf8e26..38412766e3659 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -16,8 +16,6 @@ #include "rockchip_drm_vop2.h"
static const uint32_t formats_win_full_10bit[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB888,
-- 2.30.2
Wiadomość napisana przez Lucas Stach l.stach@pengutronix.de w dniu 12.04.2022, o godz. 10:10:
This could be both a Mesa/Panfrost or application issue. The application is supposed to try to allocate with a arbitrary chosen format and the valid modifiers queried from the plane it wants to put the surface on. However I'm not sure if all applications have a fallback path in place to try another format swizzling if the surface allocation fails.
This is good remark imho. I think we have this fallback. I'll try verify this.
Generalising a bit - I think we my consider following cases:
a\ format is correctly negotiated and signalled to consumer/provider but we don't see expected results (=correct screen seen by user) b\ format was correctly negotiated but consumer/provider failed using signalled format (i.e. due bug in implementation) c\ consumer or provider advertising - in reality unsupported format (false positive) - so negotiation resulting with signalling efficiently non-working format
Sascha says (in today's email):
"Here is your problem. The cluster windows only allow AFBC compressed formats. AR24 is supported by the cluster windows, but not by the GPU, see panfrost_afbc_format() in Mesa:"
I'm reading this as case c\ as Sascha said "negotiated format is not supported by GPU" ....but this format was negotiated.
......but for sure Sascha is much better than me here in subject - so i'm might be wrong here
Now there are two possible failures here:
- The application feeds a wrong modifier list to the GBM
implementation, as it may have queried another plane in the assumption that supported modifiers are uniform across all planes.
This will be cardinal design error. (keeping in mind we have multiple producers (GPU/video decoder) and multiple consumers (base & overlay DRM planes)
- The GBM implementation (Panfrost) actually allocates a surface
instead of failing the allocation, even if it does not support any combination of the provided format and modifier list.
Testing Sacha patch (see today's email from Sascha) i'm getting
Qt: EGL Error : Could not create the egl surface: error = 0x3009
i'm reading this as: Qt tries allocate EGL surface and EGL returns error.
or i'm wrong?
On Tue, 12 Apr 2022 at 11:14, Piotr Oniszczuk piotr.oniszczuk@gmail.com wrote:
Wiadomość napisana przez Lucas Stach l.stach@pengutronix.de w dniu 12.04.2022, o godz. 10:10:
- The application feeds a wrong modifier list to the GBM
implementation, as it may have queried another plane in the assumption that supported modifiers are uniform across all planes.
This will be cardinal design error. (keeping in mind we have multiple producers (GPU/video decoder) and multiple consumers (base & overlay DRM planes)
- The GBM implementation (Panfrost) actually allocates a surface
instead of failing the allocation, even if it does not support any combination of the provided format and modifier list.
Testing Sacha patch (see today's email from Sascha) i'm getting
Qt: EGL Error : Could not create the egl surface: error = 0x3009
i'm reading this as: Qt tries allocate EGL surface and EGL returns error. or i'm wrong?
Correct, that's EGL_BAD_MATCH. There are very few ways that can happen; by far the most likely is that Qt has chosen an EGLConfig which does not correctly correspond to the format. (If it was an impossible format/modifier combination, then this would be already caught when allocating the gbm_surface.)
Either way, it seems quite clear that the VOP2 driver is totally fine here, and that you have a Qt (likely) or Mesa (tbh less likely) issue to debug to get the app working.
Cheers, Daniel
Wiadomość napisana przez Daniel Stone daniel@fooishbar.org w dniu 12.04.2022, o godz. 13:30:
Testing Sacha patch (see today's email from Sascha) i'm getting
Qt: EGL Error : Could not create the egl surface: error = 0x3009
i'm reading this as: Qt tries allocate EGL surface and EGL returns error. or i'm wrong?
Correct, that's EGL_BAD_MATCH. There are very few ways that can happen; by far the most likely is that Qt has chosen an EGLConfig which does not correctly correspond to the format. (If it was an impossible format/modifier combination, then this would be already caught when allocating the gbm_surface.)
Either way, it seems quite clear that the VOP2 driver is totally fine here, and that you have a Qt (likely) or Mesa (tbh less likely) issue to debug to get the app working.
Cheers, Daniel
Thx Daniel!
Indeed - this is probably another case where I see: writing DRM planes rendering mediaplayer with help of Qt is (too)corner case for Qt....
@all
Looking on Qt sources it looks to me this format should be supported:
https://code.qt.io/cgit/qt/qtbase.git/tree/src/platformsupport/kmsconvenienc...
Interesting that with custom Qt config1: "format": "argb8888", DRI state shows: format=AR24 little-endian (0x34325241)
UI is OK, playback is OK. OSD not visible (*)
custom config2: "format": "abgr8888" Qt crashes with EGL_BAD_MATCH
So it looks forcing some Qt formats works while other - not.
Looking why this:
Qt logging says nothing. export MESA_DEBUG=1 gives no any message. I'm a lost here a bit...
But from a bit more distant perspective:
1. Sascha concludes in (*) that issue is most probably in format negotiation by app.
2. imho app probably correctly negotiates accordingly to inputs it gets from providers (DRM) and clients (mesa). Test with patch excluding DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, shows imho proper app reaction on this (new format elected; but Qt fails with this format). Indirectly i conclude app logic is ok....
3. Sum of p1 & p2 tells me: i need to add extra logic in format election to specifically deal with constrains of rk356x (see explanation in (*))
4. Even if i implement p3 - then user world - (this using Qt) - will be not happy as: - majority users are using pre-build Qt - I don't believe Trolltech will fix this soon
So i see following path:
we will verify is issue of Qt with abgr8888 an Qt root cause issue,
If Yes - then: - Investigate is there reasonable way to workaround with this outside of Qt? If not - then: - conclude: vop2 - due Qt bug - will not work ok with Qt until Qt will be fixed.
If you think this make sense - i need some help with: verify is issue of Qt with abgr8888 an Qt root cause issue
let me know what you think
(*) Sascha mentioned:
Somehow negotiation of the format goes wrong. Applications shouldn't pick these formats when the GPU is used for rendering. I don't know how and where this should be fixed properly, but your application should use DRM_FORMAT_ABGR8888 aka AB24 aka PIPE_FORMAT_R8G8B8A8_UNORM instead of DRM_FORMAT_ARGB8888 aka AR24 aka PIPE_FORMAT_B8G8R8A8_UNORM.
Hi Piotr,
On Fri, 15 Apr 2022 at 12:11, Piotr Oniszczuk piotr.oniszczuk@gmail.com wrote:
Looking on Qt sources it looks to me this format should be supported:
https://code.qt.io/cgit/qt/qtbase.git/tree/src/platformsupport/kmsconvenienc...
Interesting that with custom Qt config1: "format": "argb8888", DRI state shows: format=AR24 little-endian (0x34325241)
UI is OK, playback is OK. OSD not visible (*)
custom config2: "format": "abgr8888" Qt crashes with EGL_BAD_MATCH
So it looks forcing some Qt formats works while other - not.
Looking why this:
Qt logging says nothing. export MESA_DEBUG=1 gives no any message. I'm a lost here a bit...
I bet if you dumped the gbm_surface format (passed by Qt as a parameter to gbm_surface_create_with_modifiers or gbm_surface_create) and the EGLConfig's EGL_NATIVE_VISUAL_ID (from eglQueryConfig), you would see that the format tokens are different. Which is a Qt coding error.
But from a bit more distant perspective:
Sascha concludes in (*) that issue is most probably in format negotiation by app.
imho app probably correctly negotiates accordingly to inputs it gets from providers (DRM) and clients (mesa).
Test with patch excluding DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, shows imho proper app reaction on this (new format elected; but Qt fails with this format). Indirectly i conclude app logic is ok....
- Sum of p1 & p2 tells me:
i need to add extra logic in format election to specifically deal with constrains of rk356x (see explanation in (*))
I disagree. I looked at a clone of Qt, and I could not see a coherent path that ensured that the gbm_surface format chosen by Qt matched the EGLConfig format used on that EGLSurface. A mismatch is an error.
There are some workarounds allowing you to specify a format, however those only work by coincidence sometimes. Even with the explicit format specification, Qt never makes any attempt to match gbm_surface and EGLConfig formats; it just hopes that they will match by coincidence.
There is no additional complexity or strangeness that RK356x is introducing here. It only works by pure luck on other platforms.
- Even if i implement p3 - then user world - (this using Qt) - will be not happy as:
- majority users are using pre-build Qt
- I don't believe Trolltech will fix this soon
So i see following path:
we will verify is issue of Qt with abgr8888 an Qt root cause issue,
If Yes - then: - Investigate is there reasonable way to workaround with this outside of Qt? If not - then: - conclude: vop2 - due Qt bug - will not work ok with Qt until Qt will be fixed.
If you think this make sense - i need some help with: verify is issue of Qt with abgr8888 an Qt root cause issue
Unfortunately there is no reasonable workaround outside of Qt. Looking at the Qt/QPA source tree, it looks like the usual way of 'fixing' this is to hack platform specific configuration into the Qt backend. If Qt won't be fixed to use generic APIs correctly, then I guess your best option is to just hack up yet another platform-specific backend. Which is a shame, but there is no reasonable workaround we can do in low-level code for toolkits doing the wrong thing and hoping it works.
Cheers, Daniel
Wiadomość napisana przez Sascha Hauer s.hauer@pengutronix.de w dniu 12.04.2022, o godz. 09:50:
Somehow negotiation of the format goes wrong. Applications shouldn't pick these formats when the GPU is used for rendering. I don't know how and where this should be fixed properly, but your application should use DRM_FORMAT_ABGR8888 aka AB24 aka PIPE_FORMAT_R8G8B8A8_UNORM instead of DRM_FORMAT_ARGB8888 aka AR24 aka PIPE_FORMAT_B8G8R8A8_UNORM.
Applied :-) Results: pls see below
Could you try the following patch? It removed the formats in question from the list of supported formats in the hope that your application then picks one of the supported formats.
Sascha
-----------------------8<-----------------------------
From 7427109cfd16803902b55cd5536b9212abd09665 Mon Sep 17 00:00:00 2001 From: Sascha Hauer s.hauer@pengutronix.de Date: Tue, 12 Apr 2022 09:42:32 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
The cluster windows only allow AFBC compressed formats. Not all of the offered formats are supported by the GPU though. Applications pick one of the formats and assume that this is also supported by the GPU they use to render on them, but this is not the case for all formats. Particularly DRM_FORMAT_XRGB8888 and DRM_FORMAT_ARGB8888 are not supported by the GPU and choosing them results in a black screen. Drop these formats for now.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 9bf0637bf8e26..38412766e3659 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -16,8 +16,6 @@ #include "rockchip_drm_vop2.h"
static const uint32_t formats_win_full_10bit[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_RGB888,
--
With above patch app select expected format (i think):
1970-01-01 01:00:31.074643 I /dev/dri/card0: Authenticated 1970-01-01 01:00:31.189420 I /dev/dri/card0: Found 3 planes; 3 for this CRTC 1970-01-01 01:00:31.189444 I /dev/dri/card0: Selected Plane #37 Overlay for video 1970-01-01 01:00:31.189528 I /dev/dri/card0: Supported DRM video formats: NV12,NV16,NV24,YVYU,VYUY 1970-01-01 01:00:31.189536 I /dev/dri/card0: Selected Plane #43 Overlay for GUI 1970-01-01 01:00:31.190279 I Wrote /home/minimyth/.mythtv/eglfs_kms_config.json: { "device": "/dev/dri/card0", "outputs": [ { "name": "HDMI1", "format": "abgr8888", "mode": "current" } ] }
(file eglfs_kms_config.json is generated by app to configure Qt; it is steep (b) in yesterday's email) I see format abgr8888 is now selected by app (this is expected t think)
but later Qt says:
1970-01-01 01:00:34.985215 I Qt: EGL Error : Could not create the egl surface: error = 0x3009 Handling Aborted Aborted
I suspect Qt tries with this format talk to GLES provider - but it wasn't somehow accepted by underlying EGL provider (mesa GLES)?
Hi Sacha:
On 4/1/22 20:52, Sascha Hauer wrote:
--
From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001
From: Sascha Hauers.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
Think about this , there maybe other upcoming vop2 base soc, they may only have
mirror window Smart1 Esmart1, or Smart1, Esmart1, Esmart2, Cluster1.
I think this should add WIN_FEATURE at the platform description file rockchip_vop2_reg.c, then
check the FEATURE to decide whether the driver should give this window a special treatment.
this can make one code run for different soc with different platform description. or we should add
the same code logic for different soc again and again.
}
- if (win->type == DRM_PLANE_TYPE_OVERLAY) possible_crtcs = (1 << nvps) - 1;
On Sat, Apr 02, 2022 at 09:37:17AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/1/22 20:52, Sascha Hauer wrote:
--
From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001
From: Sascha Hauers.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
Think about this , there maybe other upcoming vop2 base soc, they may only have
mirror window Smart1 Esmart1, or Smart1, Esmart1, Esmart2, Cluster1.
I think this should add WIN_FEATURE at the platform description file rockchip_vop2_reg.c, then
check the FEATURE to decide whether the driver should give this window a special treatment.
this can make one code run for different soc with different platform description. or we should add
the same code logic for different soc again and again.
You mean like done in the downstream Kernel? Here indeed we have a WIN_FEATURE_MIRROR flag added to the platform description. This is then evaluated with:
static bool vop2_is_mirror_win(struct vop2_win *win) { return soc_is_rk3566() && (win->feature & WIN_FEATURE_MIRROR); }
So a flag is added and afterwards its evaluation is SoC specific. That doesn't help at all and only obfuscates things.
Besides, experience shows that you can't predict a good abstraction for future hardware revisions, the hardware guys are just too creative in creating hardware that breaks existing abstractions.
Sascha
Hi:
On 4/5/22 17:37, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:37:17AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/1/22 20:52, Sascha Hauer wrote:
--
From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001
From: Sascha Hauers.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
Think about this , there maybe other upcoming vop2 base soc, they may only have
mirror window Smart1 Esmart1, or Smart1, Esmart1, Esmart2, Cluster1.
I think this should add WIN_FEATURE at the platform description file rockchip_vop2_reg.c, then
check the FEATURE to decide whether the driver should give this window a special treatment.
this can make one code run for different soc with different platform description. or we should add
the same code logic for different soc again and again.
You mean like done in the downstream Kernel? Here indeed we have a WIN_FEATURE_MIRROR flag added to the platform description. This is then evaluated with:
static bool vop2_is_mirror_win(struct vop2_win *win) { return soc_is_rk3566() && (win->feature & WIN_FEATURE_MIRROR); }
So a flag is added and afterwards its evaluation is SoC specific. That doesn't help at all and only obfuscates things.
Besides, experience shows that you can't predict a good abstraction for
This is not a predict, this is an IP feature, so it will appeared on upcoming SOC.
We have rk3588 with 8 windows(4 Cluster + 4 Esmart, no Smart window), and
also have a entry level soc which only have 4 windows, they both have this feature.
future hardware revisions, the hardware guys are just too creative in creating hardware that breaks existing abstractions.
Sascha
On Wed, Apr 06, 2022 at 10:02:59AM +0800, Andy Yan wrote:
Hi:
On 4/5/22 17:37, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:37:17AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/1/22 20:52, Sascha Hauer wrote:
--
From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001
From: Sascha Hauers.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
Think about this , there maybe other upcoming vop2 base soc, they may only have
mirror window Smart1 Esmart1, or Smart1, Esmart1, Esmart2, Cluster1.
I think this should add WIN_FEATURE at the platform description file rockchip_vop2_reg.c, then
check the FEATURE to decide whether the driver should give this window a special treatment.
this can make one code run for different soc with different platform description. or we should add
the same code logic for different soc again and again.
You mean like done in the downstream Kernel? Here indeed we have a WIN_FEATURE_MIRROR flag added to the platform description. This is then evaluated with:
static bool vop2_is_mirror_win(struct vop2_win *win) { return soc_is_rk3566() && (win->feature & WIN_FEATURE_MIRROR); }
So a flag is added and afterwards its evaluation is SoC specific. That doesn't help at all and only obfuscates things.
Besides, experience shows that you can't predict a good abstraction for
This is not a predict, this is an IP feature, so it will appeared on upcoming SOC.
We have rk3588 with 8 windows(4 Cluster + 4 Esmart, no Smart window), and
also have a entry level soc which only have 4 windows, they both have this feature.
Same as with the other discussion: Please let's solve this once we are there. For now my addition is the easiest way out. Once other SoCs shall be supported we can re-evaluate that and find better suitable ways for SoC abstractions. This may result in just your suggestion (in which case you can say told-you-so) or completely different.
Sascha
Hi:
On 4/6/22 16:13, Sascha Hauer wrote:
On Wed, Apr 06, 2022 at 10:02:59AM +0800, Andy Yan wrote:
Hi:
On 4/5/22 17:37, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:37:17AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/1/22 20:52, Sascha Hauer wrote:
--
From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001
From: Sascha Hauers.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
Think about this , there maybe other upcoming vop2 base soc, they may only have
mirror window Smart1 Esmart1, or Smart1, Esmart1, Esmart2, Cluster1.
I think this should add WIN_FEATURE at the platform description file rockchip_vop2_reg.c, then
check the FEATURE to decide whether the driver should give this window a special treatment.
this can make one code run for different soc with different platform description. or we should add
the same code logic for different soc again and again.
You mean like done in the downstream Kernel? Here indeed we have a WIN_FEATURE_MIRROR flag added to the platform description. This is then evaluated with:
static bool vop2_is_mirror_win(struct vop2_win *win) { return soc_is_rk3566() && (win->feature & WIN_FEATURE_MIRROR); }
So a flag is added and afterwards its evaluation is SoC specific. That doesn't help at all and only obfuscates things.
Besides, experience shows that you can't predict a good abstraction for
This is not a predict, this is an IP feature, so it will appeared on upcoming SOC.
We have rk3588 with 8 windows(4 Cluster + 4 Esmart, no Smart window), and
also have a entry level soc which only have 4 windows, they both have this feature.
Same as with the other discussion: Please let's solve this once we are there.
I am not sure if this is the suitable way for upstream, this sound like
just solve the issue appeared at the front of eyes and not think any
thing about make this driver easy to support new hardware in the future.
For now my addition is the easiest way out. Once other SoCs shall be supported we can re-evaluate that and find better suitable ways for SoC abstractions. This may result in just your suggestion (in which case you can say told-you-so) or completely different.
Sascha
On Wed, Apr 06, 2022 at 04:36:42PM +0800, Andy Yan wrote:
Hi:
On 4/6/22 16:13, Sascha Hauer wrote:
On Wed, Apr 06, 2022 at 10:02:59AM +0800, Andy Yan wrote:
Hi:
On 4/5/22 17:37, Sascha Hauer wrote:
On Sat, Apr 02, 2022 at 09:37:17AM +0800, Andy Yan wrote:
Hi Sacha:
On 4/1/22 20:52, Sascha Hauer wrote:
-- >From cbc03073623a7180243331ac24c3afaf9dec7522 Mon Sep 17 00:00:00 2001 From: Sascha Hauers.hauer@pengutronix.de Date: Fri, 1 Apr 2022 14:48:49 +0200 Subject: [PATCH] fixup! drm: rockchip: Add VOP2 driver
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 7dba7b9b63dc6..1421bf2f133f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2287,6 +2287,20 @@ static int vop2_create_crtc(struct vop2 *vop2) } }
if (vop2->data->soc_id == 3566) {
/*
* On RK3566 these windows don't have an independent
* framebuffer. They share the framebuffer with smart0,
* esmart0 and cluster0 respectively.
*/
switch (win->data->phys_id) {
case ROCKCHIP_VOP2_SMART1:
case ROCKCHIP_VOP2_ESMART1:
case ROCKCHIP_VOP2_CLUSTER1:
continue;
}
Think about this , there maybe other upcoming vop2 base soc, they may only have
mirror window Smart1 Esmart1, or Smart1, Esmart1, Esmart2, Cluster1.
I think this should add WIN_FEATURE at the platform description file rockchip_vop2_reg.c, then
check the FEATURE to decide whether the driver should give this window a special treatment.
this can make one code run for different soc with different platform description. or we should add
the same code logic for different soc again and again.
You mean like done in the downstream Kernel? Here indeed we have a WIN_FEATURE_MIRROR flag added to the platform description. This is then evaluated with:
static bool vop2_is_mirror_win(struct vop2_win *win) { return soc_is_rk3566() && (win->feature & WIN_FEATURE_MIRROR); }
So a flag is added and afterwards its evaluation is SoC specific. That doesn't help at all and only obfuscates things.
Besides, experience shows that you can't predict a good abstraction for
This is not a predict, this is an IP feature, so it will appeared on upcoming SOC.
We have rk3588 with 8 windows(4 Cluster + 4 Esmart, no Smart window), and
also have a entry level soc which only have 4 windows, they both have this feature.
Same as with the other discussion: Please let's solve this once we are there.
I am not sure if this is the suitable way for upstream, this sound like
just solve the issue appeared at the front of eyes and not think any
thing about make this driver easy to support new hardware in the future.
Oh come on, we are not talking about any major design decisions here, this is merely a small implementation detail that can be refactored anytime.
I would change it when all it takes is to add a feature (or better: nonfeature) flag to the window data, but the combination of the flag *and* testing on which SoC the flag shall be honoured makes me feel that the feature flag is still not the best abstraction.
Sascha
dri-devel@lists.freedesktop.org