diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 103 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/inno_hdmi.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rk3066_hdmi.c | 315 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 94 |
8 files changed, 334 insertions, 246 deletions
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 26c4410b2407..ab525668939a 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -2,12 +2,14 @@ config DRM_ROCKCHIP tristate "DRM Support for Rockchip" depends on DRM && ROCKCHIP_IOMMU + depends on OF select DRM_CLIENT_SELECTION select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL select VIDEOMODE_HELPERS select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP + select DRM_DISPLAY_DP_AUX_BUS if ROCKCHIP_ANALOGIX_DP select DRM_DW_HDMI if ROCKCHIP_DW_HDMI select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index a8265a1bf9ff..d30f0983a53a 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -21,6 +21,7 @@ #include <video/of_videomode.h> #include <video/videomode.h> +#include <drm/display/drm_dp_aux_bus.h> #include <drm/display/drm_dp_helper.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> @@ -51,11 +52,13 @@ struct rockchip_grf_reg_field { /** * struct rockchip_dp_chip_data - splite the grf setting of kind of chips * @lcdc_sel: grf register field of lcdc_sel + * @edp_mode: grf register field of edp_mode * @chip_type: specific chip type * @reg: register base address */ struct rockchip_dp_chip_data { const struct rockchip_grf_reg_field lcdc_sel; + const struct rockchip_grf_reg_field edp_mode; u32 chip_type; u32 reg; }; @@ -70,6 +73,7 @@ struct rockchip_dp_device { struct clk *grfclk; struct regmap *grf; struct reset_control *rst; + struct reset_control *apbrst; const struct rockchip_dp_chip_data *data; @@ -115,6 +119,10 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp) usleep_range(10, 20); reset_control_deassert(dp->rst); + reset_control_assert(dp->apbrst); + usleep_range(10, 20); + reset_control_deassert(dp->apbrst); + return 0; } @@ -136,12 +144,21 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data) return ret; } + ret = rockchip_grf_field_write(dp->grf, &dp->data->edp_mode, 1); + if (ret != 0) + DRM_DEV_ERROR(dp->dev, "failed to set edp mode %d\n", ret); + return ret; } static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data) { struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); + int ret; + + ret = rockchip_grf_field_write(dp->grf, &dp->data->edp_mode, 0); + if (ret != 0) + DRM_DEV_ERROR(dp->dev, "failed to set edp mode %d\n", ret); clk_disable_unprepare(dp->pclk); @@ -205,6 +222,10 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, struct rockchip_dp_device *dp = encoder_to_dp(encoder); struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; + struct of_endpoint endpoint; + struct device_node *remote_port, *remote_port_parent; + char name[32]; + u32 port_id; int ret; crtc = rockchip_dp_drm_get_new_crtc(encoder, state); @@ -222,13 +243,27 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, return; } - ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); + ret = drm_of_encoder_active_endpoint(dp->dev->of_node, encoder, &endpoint); if (ret < 0) return; - DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); + remote_port_parent = of_graph_get_remote_port_parent(endpoint.local_node); + if (remote_port_parent) { + if (of_get_child_by_name(remote_port_parent, "ports")) { + remote_port = of_graph_get_remote_port(endpoint.local_node); + of_property_read_u32(remote_port, "reg", &port_id); + of_node_put(remote_port); + sprintf(name, "%s vp%d", remote_port_parent->full_name, port_id); + } else { + sprintf(name, "%s %s", + remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb"); + } + of_node_put(remote_port_parent); + + DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); + } - ret = rockchip_grf_field_write(dp->grf, &dp->data->lcdc_sel, ret); + ret = rockchip_grf_field_write(dp->grf, &dp->data->lcdc_sel, endpoint.id); if (ret != 0) DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); @@ -322,6 +357,12 @@ static int rockchip_dp_of_probe(struct rockchip_dp_device *dp) return PTR_ERR(dp->rst); } + dp->apbrst = devm_reset_control_get_optional(dev, "apb"); + if (IS_ERR(dp->apbrst)) { + DRM_DEV_ERROR(dev, "failed to get apb reset control\n"); + return PTR_ERR(dp->apbrst); + } + return 0; } @@ -392,11 +433,28 @@ static const struct component_ops rockchip_dp_component_ops = { .unbind = rockchip_dp_unbind, }; +static int rockchip_dp_link_panel(struct drm_dp_aux *aux) +{ + struct analogix_dp_plat_data *plat_data = analogix_dp_aux_to_plat_data(aux); + struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data); + int ret; + + /* + * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel + * or bridge nodes. The driver should go on for the driver-free bridge or the DP + * mode applications. + */ + ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 1, 0, &plat_data->panel, NULL); + if (ret && ret != -ENODEV) + return ret; + + return component_add(dp->dev, &rockchip_dp_component_ops); +} + static int rockchip_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct rockchip_dp_chip_data *dp_data; - struct drm_panel *panel = NULL; struct rockchip_dp_device *dp; struct resource *res; int i; @@ -406,10 +464,6 @@ static int rockchip_dp_probe(struct platform_device *pdev) if (!dp_data) return -ENODEV; - ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); - if (ret < 0 && ret != -ENODEV) - return ret; - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; @@ -432,7 +486,6 @@ static int rockchip_dp_probe(struct platform_device *pdev) dp->dev = dev; dp->adp = ERR_PTR(-ENODEV); - dp->plat_data.panel = panel; dp->plat_data.dev_type = dp->data->chip_type; dp->plat_data.power_on = rockchip_dp_poweron; dp->plat_data.power_off = rockchip_dp_powerdown; @@ -448,9 +501,20 @@ static int rockchip_dp_probe(struct platform_device *pdev) if (IS_ERR(dp->adp)) return PTR_ERR(dp->adp); - ret = component_add(dev, &rockchip_dp_component_ops); - if (ret) - return ret; + ret = devm_of_dp_aux_populate_bus(analogix_dp_get_aux(dp->adp), rockchip_dp_link_panel); + if (ret) { + /* + * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will not + * be called because there are no EP devices. Then the rockchip_dp_link_panel() + * will be called directly in order to support the other valid DT configurations. + * + * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER. + */ + if (ret != -ENODEV) + return dev_err_probe(dp->dev, ret, "failed to populate aux bus\n"); + + return rockchip_dp_link_panel(analogix_dp_get_aux(dp->adp)); + } return 0; } @@ -501,9 +565,24 @@ static const struct rockchip_dp_chip_data rk3288_dp[] = { { /* sentinel */ } }; +static const struct rockchip_dp_chip_data rk3588_edp[] = { + { + .edp_mode = GRF_REG_FIELD(0x0000, 0, 0), + .chip_type = RK3588_EDP, + .reg = 0xfdec0000, + }, + { + .edp_mode = GRF_REG_FIELD(0x0004, 0, 0), + .chip_type = RK3588_EDP, + .reg = 0xfded0000, + }, + { /* sentinel */ } +}; + static const struct of_device_id rockchip_dp_dt_ids[] = { {.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp }, {.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp }, + {.compatible = "rockchip,rk3588-edp", .data = &rk3588_edp }, {} }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 483ecfeaebb0..db4b4038e51d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -10,10 +10,12 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/hdmi.h> +#include <linux/mfd/syscon.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> @@ -29,8 +31,19 @@ #include "inno_hdmi.h" +#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) + #define INNO_HDMI_MIN_TMDS_CLOCK 25000000U +#define RK3036_GRF_SOC_CON2 0x148 +#define RK3036_HDMI_PHSYNC BIT(4) +#define RK3036_HDMI_PVSYNC BIT(5) + +enum inno_hdmi_dev_type { + RK3036_HDMI, + RK3128_HDMI, +}; + struct inno_hdmi_phy_config { unsigned long pixelclock; u8 pre_emphasis; @@ -38,6 +51,7 @@ struct inno_hdmi_phy_config { }; struct inno_hdmi_variant { + enum inno_hdmi_dev_type dev_type; struct inno_hdmi_phy_config *phy_configs; struct inno_hdmi_phy_config *default_phy_config; }; @@ -58,6 +72,7 @@ struct inno_hdmi { struct clk *pclk; struct clk *refclk; void __iomem *regs; + struct regmap *grf; struct drm_connector connector; struct rockchip_encoder encoder; @@ -374,7 +389,15 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { - int value; + int value, psync; + + if (hdmi->variant->dev_type == RK3036_HDMI) { + psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? RK3036_HDMI_PHSYNC : 0; + value = HIWORD_UPDATE(psync, RK3036_HDMI_PHSYNC); + psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? RK3036_HDMI_PVSYNC : 0; + value |= HIWORD_UPDATE(psync, RK3036_HDMI_PVSYNC); + regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value); + } /* Set detail external video timing polarity and interlace mode */ value = v_EXTERANL_VIDEO(1); @@ -885,32 +908,34 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, return PTR_ERR(hdmi->regs); hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); - if (IS_ERR(hdmi->pclk)) { - DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI pclk clk\n"); - return PTR_ERR(hdmi->pclk); - } + if (IS_ERR(hdmi->pclk)) + return dev_err_probe(dev, PTR_ERR(hdmi->pclk), "Unable to get HDMI pclk\n"); ret = clk_prepare_enable(hdmi->pclk); - if (ret) { - DRM_DEV_ERROR(hdmi->dev, - "Cannot enable HDMI pclk clock: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Cannot enable HDMI pclk: %d\n", ret); hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref"); if (IS_ERR(hdmi->refclk)) { - DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n"); - ret = PTR_ERR(hdmi->refclk); + ret = dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n"); goto err_disable_pclk; } ret = clk_prepare_enable(hdmi->refclk); if (ret) { - DRM_DEV_ERROR(hdmi->dev, - "Cannot enable HDMI reference clock: %d\n", ret); + ret = dev_err_probe(dev, ret, "Cannot enable HDMI refclk: %d\n", ret); goto err_disable_pclk; } + if (hdmi->variant->dev_type == RK3036_HDMI) { + hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); + if (IS_ERR(hdmi->grf)) { + ret = dev_err_probe(dev, PTR_ERR(hdmi->grf), + "Unable to get rockchip,grf\n"); + goto err_disable_clk; + } + } + irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; @@ -995,11 +1020,13 @@ static void inno_hdmi_remove(struct platform_device *pdev) } static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { + .dev_type = RK3036_HDMI, .phy_configs = rk3036_hdmi_phy_configs, .default_phy_config = &rk3036_hdmi_phy_configs[1], }; static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = { + .dev_type = RK3128_HDMI, .phy_configs = rk3128_hdmi_phy_configs, .default_phy_config = &rk3128_hdmi_phy_configs[1], }; diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index f7a460190313..e7875b52f298 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -5,6 +5,9 @@ */ #include <drm/drm_atomic.h> +#include <drm/drm_bridge_connector.h> +#include <drm/display/drm_hdmi_helper.h> +#include <drm/display/drm_hdmi_state_helper.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> @@ -46,27 +49,20 @@ struct rk3066_hdmi { struct clk *hclk; void __iomem *regs; - struct drm_connector connector; + struct drm_bridge bridge; + struct drm_connector *connector; struct rockchip_encoder encoder; struct rk3066_hdmi_i2c *i2c; - struct i2c_adapter *ddc; unsigned int tmdsclk; struct hdmi_data_info hdmi_data; }; -static struct rk3066_hdmi *encoder_to_rk3066_hdmi(struct drm_encoder *encoder) +static struct rk3066_hdmi *bridge_to_rk3066_hdmi(struct drm_bridge *bridge) { - 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); + return container_of(bridge, struct rk3066_hdmi, bridge); } static inline u8 hdmi_readb(struct rk3066_hdmi *hdmi, u16 offset) @@ -161,57 +157,40 @@ static void rk3066_hdmi_set_power_mode(struct rk3066_hdmi *hdmi, int mode) hdmi->tmdsclk = DEFAULT_PLLA_RATE; } -static int -rk3066_hdmi_upload_frame(struct rk3066_hdmi *hdmi, int setup_rc, - union hdmi_infoframe *frame, u32 frame_index, - u32 mask, u32 disable, u32 enable) +static int rk3066_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) { - if (mask) - hdmi_modb(hdmi, HDMI_CP_AUTO_SEND_CTRL, mask, disable); - - hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, frame_index); - - if (setup_rc >= 0) { - u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; - ssize_t rc, i; + struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); - rc = hdmi_infoframe_pack(frame, packed_frame, - sizeof(packed_frame)); - if (rc < 0) - return rc; - - for (i = 0; i < rc; i++) - hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4, - packed_frame[i]); - - if (mask) - hdmi_modb(hdmi, HDMI_CP_AUTO_SEND_CTRL, mask, enable); + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type); + return 0; } - return setup_rc; + hdmi_writeb(hdmi, HDMI_CP_BUF_INDEX, HDMI_INFOFRAME_AVI); + + return 0; } -static int rk3066_hdmi_config_avi(struct rk3066_hdmi *hdmi, - struct drm_display_mode *mode) +static int +rk3066_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) { - union hdmi_infoframe frame; - int rc; + struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); + ssize_t i; - rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - &hdmi->connector, mode); + if (type != HDMI_INFOFRAME_TYPE_AVI) { + drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type); + return 0; + } - if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) - frame.avi.colorspace = HDMI_COLORSPACE_YUV444; - else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422) - frame.avi.colorspace = HDMI_COLORSPACE_YUV422; - else - frame.avi.colorspace = HDMI_COLORSPACE_RGB; + rk3066_hdmi_bridge_clear_infoframe(bridge, type); - frame.avi.colorimetry = hdmi->hdmi_data.colorimetry; - frame.avi.scan_mode = HDMI_SCAN_MODE_NONE; + for (i = 0; i < len; i++) + hdmi_writeb(hdmi, HDMI_CP_BUF_ACC_HB0 + i * 4, buffer[i]); - return rk3066_hdmi_upload_frame(hdmi, rc, &frame, - HDMI_INFOFRAME_AVI, 0, 0, 0); + return 0; } static int rk3066_hdmi_config_video_timing(struct rk3066_hdmi *hdmi, @@ -324,9 +303,27 @@ static void rk3066_hdmi_config_phy(struct rk3066_hdmi *hdmi) } static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi, - struct drm_display_mode *mode) + struct drm_atomic_state *state) { - struct drm_display_info *display = &hdmi->connector.display_info; + struct drm_bridge *bridge = &hdmi->bridge; + struct drm_connector *connector; + struct drm_display_info *display; + struct drm_display_mode *mode; + struct drm_connector_state *new_conn_state; + struct drm_crtc_state *new_crtc_state; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + + new_conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!new_conn_state)) + return -EINVAL; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + if (WARN_ON(!new_crtc_state)) + return -EINVAL; + + display = &connector->display_info; + mode = &new_crtc_state->adjusted_mode; hdmi->hdmi_data.vic = drm_match_cea_mode(mode); hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; @@ -363,7 +360,7 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi, if (display->is_hdmi) { hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK, HDMI_VIDEO_MODE_HDMI); - rk3066_hdmi_config_avi(hdmi, mode); + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); } else { hdmi_modb(hdmi, HDMI_HDCP_CTRL, HDMI_VIDEO_MODE_MASK, 0); } @@ -386,15 +383,15 @@ static int rk3066_hdmi_setup(struct rk3066_hdmi *hdmi, return 0; } -static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder, - struct drm_atomic_state *state) +static void rk3066_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); + struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); struct drm_connector_state *conn_state; struct drm_crtc_state *crtc_state; int mux, val; - conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); + conn_state = drm_atomic_get_new_connector_state(state, hdmi->connector); if (WARN_ON(!conn_state)) return; @@ -402,7 +399,7 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder, if (WARN_ON(!crtc_state)) return; - mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, encoder); + mux = drm_of_encoder_active_endpoint_id(hdmi->dev->of_node, &hdmi->encoder.encoder); if (mux) val = (HDMI_VIDEO_SEL << 16) | HDMI_VIDEO_SEL; else @@ -413,13 +410,13 @@ static void rk3066_hdmi_encoder_enable(struct drm_encoder *encoder, DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder enable select: vop%s\n", (mux) ? "1" : "0"); - rk3066_hdmi_setup(hdmi, &crtc_state->adjusted_mode); + rk3066_hdmi_setup(hdmi, state); } -static void rk3066_hdmi_encoder_disable(struct drm_encoder *encoder, - struct drm_atomic_state *state) +static void rk3066_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { - struct rk3066_hdmi *hdmi = encoder_to_rk3066_hdmi(encoder); + struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); DRM_DEV_DEBUG(hdmi->dev, "hdmi encoder disable\n"); @@ -450,39 +447,34 @@ rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder, static const struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = { .atomic_check = rk3066_hdmi_encoder_atomic_check, - .atomic_enable = rk3066_hdmi_encoder_enable, - .atomic_disable = rk3066_hdmi_encoder_disable, }; static enum drm_connector_status -rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force) +rk3066_hdmi_bridge_detect(struct drm_bridge *bridge) { - struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector); + struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); return (hdmi_readb(hdmi, HDMI_HPG_MENS_STA) & HDMI_HPG_IN_STATUS_HIGH) ? connector_status_connected : connector_status_disconnected; } -static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector) +static const struct drm_edid * +rk3066_hdmi_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector) { - struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector); + struct rk3066_hdmi *hdmi = bridge_to_rk3066_hdmi(bridge); const struct drm_edid *drm_edid; - int ret = 0; - - if (!hdmi->ddc) - return 0; - drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); - drm_edid_connector_update(connector, drm_edid); - ret = drm_edid_connector_add_modes(connector); - drm_edid_free(drm_edid); + drm_edid = drm_edid_read_ddc(connector, bridge->ddc); + if (!drm_edid) + dev_dbg(hdmi->dev, "failed to get edid\n"); - return ret; + return drm_edid; } static enum drm_mode_status -rk3066_hdmi_connector_mode_valid(struct drm_connector *connector, - const struct drm_display_mode *mode) +rk3066_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) { u32 vic = drm_match_cea_mode(mode); @@ -492,82 +484,19 @@ rk3066_hdmi_connector_mode_valid(struct drm_connector *connector, return MODE_BAD; } -static struct drm_encoder * -rk3066_hdmi_connector_best_encoder(struct drm_connector *connector) -{ - struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector); - - return &hdmi->encoder.encoder; -} - -static int -rk3066_hdmi_probe_single_connector_modes(struct drm_connector *connector, - uint32_t maxX, uint32_t maxY) -{ - if (maxX > 1920) - maxX = 1920; - if (maxY > 1080) - maxY = 1080; - - return drm_helper_probe_single_connector_modes(connector, maxX, maxY); -} - -static void rk3066_hdmi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static const struct drm_connector_funcs rk3066_hdmi_connector_funcs = { - .fill_modes = rk3066_hdmi_probe_single_connector_modes, - .detect = rk3066_hdmi_connector_detect, - .destroy = rk3066_hdmi_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const -struct drm_connector_helper_funcs rk3066_hdmi_connector_helper_funcs = { - .get_modes = rk3066_hdmi_connector_get_modes, - .mode_valid = rk3066_hdmi_connector_mode_valid, - .best_encoder = rk3066_hdmi_connector_best_encoder, +static const struct drm_bridge_funcs rk3066_hdmi_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_enable = rk3066_hdmi_bridge_atomic_enable, + .atomic_disable = rk3066_hdmi_bridge_atomic_disable, + .detect = rk3066_hdmi_bridge_detect, + .edid_read = rk3066_hdmi_bridge_edid_read, + .hdmi_clear_infoframe = rk3066_hdmi_bridge_clear_infoframe, + .hdmi_write_infoframe = rk3066_hdmi_bridge_write_infoframe, + .mode_valid = rk3066_hdmi_bridge_mode_valid, }; -static int -rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi) -{ - struct drm_encoder *encoder = &hdmi->encoder.encoder; - struct device *dev = hdmi->dev; - - encoder->possible_crtcs = - drm_of_find_possible_crtcs(drm, dev->of_node); - - /* - * If we failed to find the CRTC(s) which this encoder is - * supposed to be connected to, it's because the CRTC has - * not been registered yet. Defer probing, and hope that - * the required CRTC is added later. - */ - if (encoder->possible_crtcs == 0) - return -EPROBE_DEFER; - - drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs); - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); - - hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; - - drm_connector_helper_add(&hdmi->connector, - &rk3066_hdmi_connector_helper_funcs); - drm_connector_init_with_ddc(drm, &hdmi->connector, - &rk3066_hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - hdmi->ddc); - - drm_connector_attach_encoder(&hdmi->connector, encoder); - - return 0; -} static irqreturn_t rk3066_hdmi_hardirq(int irq, void *dev_id) { @@ -597,7 +526,7 @@ static irqreturn_t rk3066_hdmi_irq(int irq, void *dev_id) { struct rk3066_hdmi *hdmi = dev_id; - drm_helper_hpd_irq_event(hdmi->connector.dev); + drm_helper_hpd_irq_event(hdmi->connector->dev); return IRQ_HANDLED; } @@ -720,7 +649,7 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi) strscpy(adap->name, "RK3066 HDMI", sizeof(adap->name)); i2c_set_adapdata(adap, hdmi); - ret = i2c_add_adapter(adap); + ret = devm_i2c_add_adapter(hdmi->dev, adap); if (ret) { DRM_DEV_ERROR(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); @@ -735,6 +664,66 @@ static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi) return adap; } +static int +rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi) +{ + struct drm_encoder *encoder = &hdmi->encoder.encoder; + struct device *dev = hdmi->dev; + int ret; + + encoder->possible_crtcs = + drm_of_find_possible_crtcs(drm, dev->of_node); + + /* + * If we failed to find the CRTC(s) which this encoder is + * supposed to be connected to, it's because the CRTC has + * not been registered yet. Defer probing, and hope that + * the required CRTC is added later. + */ + if (encoder->possible_crtcs == 0) + return -EPROBE_DEFER; + + drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs); + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); + + hdmi->bridge.driver_private = hdmi; + hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs; + hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID | + DRM_BRIDGE_OP_HDMI | + DRM_BRIDGE_OP_HPD; + hdmi->bridge.of_node = hdmi->dev->of_node; + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; + hdmi->bridge.vendor = "Rockchip"; + hdmi->bridge.product = "RK3066 HDMI"; + + hdmi->bridge.ddc = rk3066_hdmi_i2c_adapter(hdmi); + if (IS_ERR(hdmi->bridge.ddc)) + return PTR_ERR(hdmi->bridge.ddc); + + if (IS_ERR(hdmi->bridge.ddc)) + return PTR_ERR(hdmi->bridge.ddc); + + ret = devm_drm_bridge_add(dev, &hdmi->bridge); + if (ret) + return ret; + + ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; + + hdmi->connector = drm_bridge_connector_init(drm, encoder); + if (IS_ERR(hdmi->connector)) { + ret = PTR_ERR(hdmi->connector); + dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret); + return ret; + } + + drm_connector_attach_encoder(hdmi->connector, encoder); + + return 0; +} + static int rk3066_hdmi_bind(struct device *dev, struct device *master, void *data) { @@ -781,13 +770,6 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master, /* internal hclk = hdmi_hclk / 25 */ hdmi_writeb(hdmi, HDMI_INTERNAL_CLK_DIVIDER, 25); - hdmi->ddc = rk3066_hdmi_i2c_adapter(hdmi); - if (IS_ERR(hdmi->ddc)) { - ret = PTR_ERR(hdmi->ddc); - hdmi->ddc = NULL; - goto err_disable_hclk; - } - rk3066_hdmi_set_power_mode(hdmi, HDMI_SYS_POWER_MODE_B); usleep_range(999, 1000); hdmi_writeb(hdmi, HDMI_INTR_MASK1, HDMI_INTR_HOTPLUG); @@ -798,7 +780,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master, ret = rk3066_hdmi_register(drm, hdmi); if (ret) - goto err_disable_i2c; + goto err_disable_hclk; dev_set_drvdata(dev, hdmi); @@ -813,10 +795,7 @@ static int rk3066_hdmi_bind(struct device *dev, struct device *master, return 0; err_cleanup_hdmi: - hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); -err_disable_i2c: - i2c_put_adapter(hdmi->ddc); err_disable_hclk: clk_disable_unprepare(hdmi->hclk); @@ -828,10 +807,8 @@ 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.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_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index e3596e2b557d..ba6b0528d1e5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -733,11 +733,10 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, WARN_ON(vop->event); - if (crtc->state->self_refresh_active) + if (crtc->state->self_refresh_active) { rockchip_drm_set_win_enabled(crtc, false); - - if (crtc->state->self_refresh_active) goto out; + } mutex_lock(&vop->vop_lock); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 680bedbb770e..fc3ecb9fcd95 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -710,6 +710,7 @@ enum dst_factor_mode { #define VOP2_COLOR_KEY_MASK BIT(31) +#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL GENMASK(31, 30) #define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD BIT(28) #define RK3568_OVL_CTRL__YUV_MODE(vp) BIT(vp) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 0a2840cbe8e2..32c4ed685739 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2070,7 +2070,10 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL); - ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; + ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; + ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL; + ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id); + if (vcstate->yuv_overlay) ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id); else diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 4e2099d86517..d1f788763318 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -906,21 +906,21 @@ static const struct vop_data rk3366_vop = { static const struct vop_output rk3399_output = { .dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), - .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19), - .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23), - .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27), - .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31), + .rgb_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 31), .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), - .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16), - .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20), - .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24), - .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28), + .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 28), .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), - .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), - .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), - .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), - .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), - .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), + .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), + .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), + .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), + .mipi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 15), + .mipi_dual_channel_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 3), }; static const struct vop_common rk3399_common = { @@ -975,23 +975,23 @@ static const struct vop_win_phy rk3399_win0_data = { .data_formats = formats_win_full_10, .nformats = ARRAY_SIZE(formats_win_full_10), .format_modifiers = format_modifiers_win_full_afbc, - .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), - .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), - .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), - .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), - .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15), - .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21), - .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), - .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), - .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), - .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), - .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), - .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), - .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), + .enable = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3399_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3399_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3399_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3399_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3399_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3399_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3399_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3399_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3399_WIN0_CTRL2, 0xff, 0), }; static const struct vop_win_phy rk3399_win1_data = { @@ -999,23 +999,23 @@ static const struct vop_win_phy rk3399_win1_data = { .data_formats = formats_win_full_10, .nformats = ARRAY_SIZE(formats_win_full_10), .format_modifiers = format_modifiers_win_full, - .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), - .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), - .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), - .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), - .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15), - .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21), - .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), - .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), - .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), - .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), - .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), - .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), - .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), + .enable = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3399_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3399_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3399_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3399_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3399_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3399_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3399_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3399_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3399_WIN0_CTRL2, 0xff, 0), }; /* |