diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index e37557b30f62..f9cfcdcdf024 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -109,6 +109,15 @@ Framebuffer CMA Helper Functions Reference .. _drm_bridges: +Framebuffer GEM Helper Reference +================================ + +.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c + :export: + Bridges ======= @@ -169,6 +178,15 @@ Display Port Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c :export: +Display Port CEC Helper Functions Reference +=========================================== + +.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c + :doc: dp cec helpers + +.. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c + :export: + Display Port Dual Mode Adaptor Helper Functions Reference ========================================================= @@ -282,13 +300,13 @@ Auxiliary Modeset Helpers .. kernel-doc:: drivers/gpu/drm/drm_modeset_helper.c :export: -Framebuffer GEM Helper Reference -================================ +OF/DT Helpers +============= -.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_of.c :doc: overview -.. kernel-doc:: drivers/gpu/drm/drm_gem_framebuffer_helper.c +.. kernel-doc:: drivers/gpu/drm/drm_of.c :export: Legacy Plane Helper Reference diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 514939433004..5dee6b8a4c12 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -56,11 +56,12 @@ Overview The basic object structure KMS presents to userspace is fairly simple. Framebuffers (represented by :c:type:`struct drm_framebuffer `, -see `Frame Buffer Abstraction`_) feed into planes. One or more (or even no) -planes feed their pixel data into a CRTC (represented by :c:type:`struct -drm_crtc `, see `CRTC Abstraction`_) for blending. The precise -blending step is explained in more detail in `Plane Composition Properties`_ and -related chapters. +see `Frame Buffer Abstraction`_) feed into planes. Planes are represented by +:c:type:`struct drm_plane `, see `Plane Abstraction`_ for more +details. One or more (or even no) planes feed their pixel data into a CRTC +(represented by :c:type:`struct drm_crtc `, see `CRTC Abstraction`_) +for blending. The precise blending step is explained in more detail in `Plane +Composition Properties`_ and related chapters. For the output routing the first step is encoders (represented by :c:type:`struct drm_encoder `, see `Encoder Abstraction`_). Those @@ -466,7 +467,7 @@ Output discovery and initialization example drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - drm_mode_connector_attach_encoder(&intel_output->base, + drm_connector_attach_encoder(&intel_output->base, &intel_output->enc); /* Set up the DDC bus. */ diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 20bf90f4ee63..6c95f61a32e7 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -141,6 +141,7 @@ reservation_object_add_shared_inplace(struct reservation_object *obj, if (signaled) { RCU_INIT_POINTER(fobj->shared[signaled_idx], fence); } else { + BUG_ON(fobj->shared_count >= fobj->shared_max); RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); fobj->shared_count++; } @@ -230,10 +231,9 @@ void reservation_object_add_shared_fence(struct reservation_object *obj, old = reservation_object_get_list(obj); obj->staged = NULL; - if (!fobj) { - BUG_ON(old->shared_count >= old->shared_max); + if (!fobj) reservation_object_add_shared_inplace(obj, old, fence); - } else + else reservation_object_add_shared_replace(obj, old, fobj, fence); } EXPORT_SYMBOL(reservation_object_add_shared_fence); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index a8054dde49b5..cb88528e7b10 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -122,6 +122,16 @@ config DRM_LOAD_EDID_FIRMWARE default case is N. Details and instructions how to build your own EDID data are given in Documentation/EDID/HOWTO.txt. +config DRM_DP_CEC + bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" + select CEC_CORE + help + Choose this option if you want to enable HDMI CEC support for + DisplayPort/USB-C to HDMI adapters. + + Note: not all adapters support this feature, and even for those + that do support this they often do not hook up the CEC pin. + config DRM_TTM tristate depends on DRM && MMU diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 0e0a3ef1abad..a6771cef85e2 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -41,6 +41,7 @@ drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o +drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 881f7cb7ae6e..c770d73352a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -334,11 +334,11 @@ static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector) int ret; if (amdgpu_connector->edid) { - drm_mode_connector_update_edid_property(connector, amdgpu_connector->edid); + drm_connector_update_edid_property(connector, amdgpu_connector->edid); ret = drm_add_edid_modes(connector, amdgpu_connector->edid); return ret; } - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c index 94138abe093b..ae8fac34f7a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_encoders.c @@ -46,7 +46,7 @@ amdgpu_link_encoder_connector(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { amdgpu_encoder = to_amdgpu_encoder(encoder); if (amdgpu_encoder->devices & amdgpu_connector->devices) { - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { amdgpu_atombios_encoder_init_backlight(amdgpu_encoder, connector); adev->mode_info.bl_encoder = amdgpu_encoder; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index 016f15093173..677e96a56330 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -627,7 +627,7 @@ static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, drm_connector_register(connector); /* link them */ - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index ca017c1dd4da..28da18b1da52 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -903,14 +903,14 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector) (struct edid *) sink->dc_edid.raw_edid; - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, aconnector->edid); } amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid); } else { amdgpu_dm_remove_sink_from_freesync_module(connector); - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); aconnector->num_modes = 0; aconnector->dc_sink = NULL; aconnector->edid = NULL; @@ -3663,7 +3663,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, link, link_index); - drm_mode_connector_attach_encoder( + drm_connector_attach_encoder( &aconnector->base, &aencoder->base); drm_connector_register(&aconnector->base); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 4304d9e408b8..65f210d3497b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -233,7 +233,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port); if (!edid) { - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( &aconnector->base, NULL); return ret; @@ -261,7 +261,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) connector, aconnector->edid); } - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( &aconnector->base, aconnector->edid); ret = drm_add_edid_modes(connector, aconnector->edid); @@ -345,7 +345,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, aconnector, connector->base.id, aconnector->mst_port); aconnector->port = port; - drm_mode_connector_set_path_property(connector, pathprop); + drm_connector_set_path_property(connector, pathprop); drm_connector_list_iter_end(&conn_iter); aconnector->mst_connected = true; @@ -393,7 +393,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, dev->mode_config.tile_property, 0); - drm_mode_connector_set_path_property(connector, pathprop); + drm_connector_set_path_property(connector, pathprop); /* * Initialize connector state before adding the connectror to drm and @@ -441,7 +441,7 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) static void dm_dp_mst_link_status_reset(struct drm_connector *connector) { mutex_lock(&connector->dev->mode_config.mutex); - drm_mode_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD); + drm_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD); mutex_unlock(&connector->dev->mode_config.mutex); } diff --git a/drivers/gpu/drm/arc/arcpgu_sim.c b/drivers/gpu/drm/arc/arcpgu_sim.c index b8f6f9a5dfbe..68629e614990 100644 --- a/drivers/gpu/drm/arc/arcpgu_sim.c +++ b/drivers/gpu/drm/arc/arcpgu_sim.c @@ -99,7 +99,7 @@ int arcpgu_drm_sim_init(struct drm_device *drm, struct device_node *np) goto error_encoder_cleanup; } - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) { dev_err(drm->dev, "could not attach connector to encoder\n"); drm_connector_unregister(connector); diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 036dff8a1f33..5e77d456d9bb 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -790,12 +790,12 @@ static int ast_get_modes(struct drm_connector *connector) if (!flags) edid = drm_get_edid(connector, &ast_connector->i2c->adapter); if (edid) { - drm_mode_connector_update_edid_property(&ast_connector->base, edid); + drm_connector_update_edid_property(&ast_connector->base, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); return ret; } else - drm_mode_connector_update_edid_property(&ast_connector->base, NULL); + drm_connector_update_edid_property(&ast_connector->base, NULL); return 0; } @@ -900,7 +900,7 @@ static int ast_connector_init(struct drm_device *dev) connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); ast_connector->i2c = ast_i2c_create(dev); if (!ast_connector->i2c) diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 233980a78591..ca5a9afdd5cf 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -259,7 +259,7 @@ int bochs_kms_init(struct bochs_device *bochs) bochs_crtc_init(bochs->dev); bochs_encoder_init(bochs->dev); bochs_connector_init(bochs->dev); - drm_mode_connector_attach_encoder(&bochs->connector, + drm_connector_attach_encoder(&bochs->connector, &bochs->encoder); return 0; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 73021b388e12..6437b878724a 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -601,7 +601,7 @@ static int adv7511_get_modes(struct adv7511 *adv7511, __adv7511_power_off(adv7511); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); adv7511_set_config_csc(adv7511, connector, adv7511->rgb, @@ -860,7 +860,7 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge) } drm_connector_helper_add(&adv->connector, &adv7511_connector_helper_funcs); - drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder); + drm_connector_attach_encoder(&adv->connector, bridge->encoder); if (adv->type == ADV7533) ret = adv7533_attach_dsi(adv); diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index b49043866be6..f8433c93f463 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -969,8 +969,8 @@ static int anx78xx_get_modes(struct drm_connector *connector) goto unlock; } - err = drm_mode_connector_update_edid_property(connector, - anx78xx->edid); + err = drm_connector_update_edid_property(connector, + anx78xx->edid); if (err) { DRM_ERROR("Failed to update EDID property: %d\n", err); goto unlock; @@ -1048,8 +1048,8 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge) anx78xx->connector.polled = DRM_CONNECTOR_POLL_HPD; - err = drm_mode_connector_attach_encoder(&anx78xx->connector, - bridge->encoder); + err = drm_connector_attach_encoder(&anx78xx->connector, + bridge->encoder); if (err) { DRM_ERROR("Failed to link up connector to encoder: %d\n", err); return err; diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 2bcbfadb6ac5..d68986cea132 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1119,8 +1119,8 @@ static int analogix_dp_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &dp->aux.ddc); pm_runtime_put(dp->dev); if (edid) { - drm_mode_connector_update_edid_property(&dp->connector, - edid); + drm_connector_update_edid_property(&dp->connector, + edid); num_modes += drm_add_edid_modes(&dp->connector, edid); kfree(edid); } @@ -1210,7 +1210,7 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) drm_connector_helper_add(connector, &analogix_dp_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); } /* diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 9837c8d69e69..9b706789a341 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -55,7 +55,7 @@ static int dumb_vga_get_modes(struct drm_connector *connector) goto fallback; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); return ret; @@ -122,7 +122,7 @@ static int dumb_vga_attach(struct drm_bridge *bridge) return ret; } - drm_mode_connector_attach_encoder(&vga->connector, + drm_connector_attach_encoder(&vga->connector, bridge->encoder); return 0; diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index 7ccadba7c98c..2136c97aeb8e 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -152,7 +152,7 @@ static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client); if (ge_b850v3_lvds_ptr->edid) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, ge_b850v3_lvds_ptr->edid); num_modes = drm_add_edid_modes(connector, ge_b850v3_lvds_ptr->edid); @@ -241,7 +241,7 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge) return ret; } - ret = drm_mode_connector_attach_encoder(connector, bridge->encoder); + ret = drm_connector_attach_encoder(connector, bridge->encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index d64a3283822a..a3e817abace1 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -222,7 +222,7 @@ static int ptn3460_get_modes(struct drm_connector *connector) } ptn_bridge->edid = (struct edid *)edid; - drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); + drm_connector_update_edid_property(connector, ptn_bridge->edid); num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); @@ -265,7 +265,7 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge) drm_connector_helper_add(&ptn_bridge->connector, &ptn3460_connector_helper_funcs); drm_connector_register(&ptn_bridge->connector); - drm_mode_connector_attach_encoder(&ptn_bridge->connector, + drm_connector_attach_encoder(&ptn_bridge->connector, bridge->encoder); if (ptn_bridge->panel) diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 6d99d4a3beb3..7cbaba213ef6 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -79,7 +79,7 @@ static int panel_bridge_attach(struct drm_bridge *bridge) return ret; } - drm_mode_connector_attach_encoder(&panel_bridge->connector, + drm_connector_attach_encoder(&panel_bridge->connector, bridge->encoder); ret = drm_panel_attach(panel_bridge->panel, &panel_bridge->connector); diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index 81198f5e9afa..7334d1b62b71 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -503,7 +503,7 @@ static int ps8622_attach(struct drm_bridge *bridge) drm_connector_helper_add(&ps8622->connector, &ps8622_connector_helper_funcs); drm_connector_register(&ps8622->connector); - drm_mode_connector_attach_encoder(&ps8622->connector, + drm_connector_attach_encoder(&ps8622->connector, bridge->encoder); if (ps8622->panel) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 60373d7eb220..e59a13542333 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -170,7 +170,7 @@ static int sii902x_get_modes(struct drm_connector *connector) return ret; edid = drm_get_edid(connector, sii902x->i2c->adapter); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { num = drm_add_edid_modes(connector, edid); kfree(edid); @@ -324,7 +324,7 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) else sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; - drm_mode_connector_attach_encoder(&sii902x->connector, bridge->encoder); + drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); return 0; } diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 3c136f2b954f..5971976284bf 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1922,7 +1922,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); @@ -1974,7 +1974,7 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 0fd9cf27542c..8e28e738cb52 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1140,7 +1140,7 @@ static int tc_connector_get_modes(struct drm_connector *connector) if (!edid) return 0; - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); return count; @@ -1195,7 +1195,7 @@ static int tc_bridge_attach(struct drm_bridge *bridge) drm_display_info_set_bus_formats(&tc->connector.display_info, &bus_format, 1); - drm_mode_connector_attach_encoder(&tc->connector, tc->bridge.encoder); + drm_connector_attach_encoder(&tc->connector, tc->bridge.encoder); return 0; } diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index acb857030951..c3e32138c6bb 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -62,7 +62,7 @@ static int tfp410_get_modes(struct drm_connector *connector) goto fallback; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); return drm_add_edid_modes(connector, edid); fallback: @@ -132,7 +132,7 @@ static int tfp410_attach(struct drm_bridge *bridge) return ret; } - drm_mode_connector_attach_encoder(&dvi->connector, + drm_connector_attach_encoder(&dvi->connector, bridge->encoder); return 0; diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index b529f8c8e2a6..336bfda40125 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -530,7 +530,7 @@ int cirrus_modeset_init(struct cirrus_device *cdev) return -1; } - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); ret = cirrus_fbdev_init(cdev); if (ret) { diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 91fda6b8926e..866a2cc72ef6 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2867,7 +2867,7 @@ static int update_output_state(struct drm_atomic_state *state, * resets the "link-status" property to GOOD, to force any link * re-training. The SETCRTC ioctl does not define whether an update does * need a full modeset or just a plane update, hence we're allowed to do - * that. See also drm_mode_connector_set_link_status_property(). + * that. See also drm_connector_set_link_status_property(). * * Returns: * Returns 0 on success, negative errno numbers on failure. diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 9b142f58d489..baff50a4c234 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -218,7 +218,9 @@ static void drm_client_buffer_delete(struct drm_client_buffer *buffer) if (buffer->gem) drm_gem_object_put_unlocked(buffer->gem); - drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); + if (buffer->handle) + drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file); + kfree(buffer); } @@ -243,7 +245,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8; ret = drm_mode_create_dumb(dev, &dumb_args, client->file); if (ret) - goto err_free; + goto err_delete; buffer->handle = dumb_args.handle; buffer->pitch = dumb_args.pitch; @@ -276,8 +278,6 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u err_delete: drm_client_buffer_delete(buffer); -err_free: - kfree(buffer); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 5ada0640de5a..6011d769d50b 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -48,7 +48,7 @@ * * Connectors must be attached to an encoder to be used. For devices that map * connectors to encoders 1:1, the connector should be attached at - * initialization time with a call to drm_mode_connector_attach_encoder(). The + * initialization time with a call to drm_connector_attach_encoder(). The * driver must also set the &drm_connector.encoder field to point to the * attached encoder. * @@ -291,7 +291,7 @@ out_put: EXPORT_SYMBOL(drm_connector_init); /** - * drm_mode_connector_attach_encoder - attach a connector to an encoder + * drm_connector_attach_encoder - attach a connector to an encoder * @connector: connector to attach * @encoder: encoder to attach @connector to * @@ -302,8 +302,8 @@ EXPORT_SYMBOL(drm_connector_init); * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_connector_attach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder) +int drm_connector_attach_encoder(struct drm_connector *connector, + struct drm_encoder *encoder) { int i; @@ -329,7 +329,7 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, } return -ENOMEM; } -EXPORT_SYMBOL(drm_mode_connector_attach_encoder); +EXPORT_SYMBOL(drm_connector_attach_encoder); /** * drm_connector_has_possible_encoder - check if the connector and encoder are assosicated with each other @@ -606,7 +606,7 @@ __drm_connector_put_safe(struct drm_connector *conn) /** * drm_connector_list_iter_next - return next connector - * @iter: connectr_list iterator + * @iter: connector_list iterator * * Returns the next connector for @iter, or NULL when the list walk has * completed. @@ -814,7 +814,7 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * Blob property which contains the current EDID read from the sink. This * is useful to parse sink identification information like vendor, model * and serial. Drivers should update this property by calling - * drm_mode_connector_update_edid_property(), usually after having parsed + * drm_connector_update_edid_property(), usually after having parsed * the EDID using drm_add_edid_modes(). Userspace cannot change this * property. * DPMS: @@ -852,7 +852,7 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * PATH: * Connector path property to identify how this sink is physically * connected. Used by DP MST. This should be set by calling - * drm_mode_connector_set_path_property(), in the case of DP MST with the + * drm_connector_set_path_property(), in the case of DP MST with the * path property the MST manager created. Userspace cannot change this * property. * TILE: @@ -863,14 +863,14 @@ DRM_ENUM_NAME_FN(drm_get_content_protection_name, drm_cp_enum_list) * are not gen-locked. Note that for tiled panels which are genlocked, like * dual-link LVDS or dual-link DSI, the driver should try to not expose the * tiling and virtualize both &drm_crtc and &drm_plane if needed. Drivers - * should update this value using drm_mode_connector_set_tile_property(). + * should update this value using drm_connector_set_tile_property(). * Userspace cannot change this property. * link-status: * Connector link-status property to indicate the status of link. The * default value of link-status is "GOOD". If something fails during or * after modeset, the kernel driver may set this to "BAD" and issue a * hotplug uevent. Drivers should update this value using - * drm_mode_connector_set_link_status_property(). + * drm_connector_set_link_status_property(). * non_desktop: * Indicates the output should be ignored for purposes of displaying a * standard desktop environment or console. This is most likely because @@ -1425,7 +1425,7 @@ int drm_mode_create_suggested_offset_properties(struct drm_device *dev) EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); /** - * drm_mode_connector_set_path_property - set tile property on connector + * drm_connector_set_path_property - set tile property on connector * @connector: connector to set property on. * @path: path to use for property; must not be NULL. * @@ -1437,8 +1437,8 @@ EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_connector_set_path_property(struct drm_connector *connector, - const char *path) +int drm_connector_set_path_property(struct drm_connector *connector, + const char *path) { struct drm_device *dev = connector->dev; int ret; @@ -1451,10 +1451,10 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, dev->mode_config.path_property); return ret; } -EXPORT_SYMBOL(drm_mode_connector_set_path_property); +EXPORT_SYMBOL(drm_connector_set_path_property); /** - * drm_mode_connector_set_tile_property - set tile property on connector + * drm_connector_set_tile_property - set tile property on connector * @connector: connector to set property on. * * This looks up the tile information for a connector, and creates a @@ -1464,7 +1464,7 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property); * Returns: * Zero on success, errno on failure. */ -int drm_mode_connector_set_tile_property(struct drm_connector *connector) +int drm_connector_set_tile_property(struct drm_connector *connector) { struct drm_device *dev = connector->dev; char tile[256]; @@ -1494,10 +1494,10 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector) dev->mode_config.tile_property); return ret; } -EXPORT_SYMBOL(drm_mode_connector_set_tile_property); +EXPORT_SYMBOL(drm_connector_set_tile_property); /** - * drm_mode_connector_update_edid_property - update the edid property of a connector + * drm_connector_update_edid_property - update the edid property of a connector * @connector: drm connector * @edid: new value of the edid property * @@ -1507,8 +1507,8 @@ EXPORT_SYMBOL(drm_mode_connector_set_tile_property); * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_connector_update_edid_property(struct drm_connector *connector, - const struct edid *edid) +int drm_connector_update_edid_property(struct drm_connector *connector, + const struct edid *edid) { struct drm_device *dev = connector->dev; size_t size = 0; @@ -1546,10 +1546,10 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, dev->mode_config.edid_property); return ret; } -EXPORT_SYMBOL(drm_mode_connector_update_edid_property); +EXPORT_SYMBOL(drm_connector_update_edid_property); /** - * drm_mode_connector_set_link_status_property - Set link status property of a connector + * drm_connector_set_link_status_property - Set link status property of a connector * @connector: drm connector * @link_status: new value of link status property (0: Good, 1: Bad) * @@ -1567,8 +1567,8 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property); * it is not limited to DP or link training. For example, if we implement * asynchronous setcrtc, this property can be used to report any failures in that. */ -void drm_mode_connector_set_link_status_property(struct drm_connector *connector, - uint64_t link_status) +void drm_connector_set_link_status_property(struct drm_connector *connector, + uint64_t link_status) { struct drm_device *dev = connector->dev; @@ -1576,7 +1576,7 @@ void drm_mode_connector_set_link_status_property(struct drm_connector *connector connector->state->link_status = link_status; drm_modeset_unlock(&dev->mode_config.connection_mutex); } -EXPORT_SYMBOL(drm_mode_connector_set_link_status_property); +EXPORT_SYMBOL(drm_connector_set_link_status_property); /** * drm_connector_init_panel_orientation_property - @@ -1629,7 +1629,7 @@ int drm_connector_init_panel_orientation_property( } EXPORT_SYMBOL(drm_connector_init_panel_orientation_property); -int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, +int drm_connector_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value) { @@ -1647,8 +1647,8 @@ int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, return ret; } -int drm_mode_connector_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_connector_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { struct drm_mode_connector_set_property *conn_set_prop = data; struct drm_mode_obj_set_property obj_set_prop = { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index a6906c4ab880..bae43938c8f6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -461,6 +461,8 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, struct drm_crtc *tmp; int ret; + WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev)); + /* * NOTE: ->set_config can also disable other crtcs (if we steal all * connectors from it), hence we need to refcount the fbs across all @@ -478,10 +480,8 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, if (ret == 0) { struct drm_plane *plane = crtc->primary; - if (!plane->state) { - plane->crtc = fb ? crtc : NULL; - plane->fb = fb; - } + plane->crtc = fb ? crtc : NULL; + plane->fb = fb; } drm_for_each_crtc(tmp, crtc->dev) { @@ -496,6 +496,7 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, return ret; } + /** * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config * @set: modeset config to set @@ -740,7 +741,11 @@ retry: set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = __drm_mode_set_config_internal(&set, &ctx); + + if (drm_drv_uses_atomic_modeset(dev)) + ret = crtc->funcs->set_config(&set, &ctx); + else + ret = __drm_mode_set_config_internal(&set, &ctx); out: if (fb) diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 235d40fce8b5..b61322763394 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -148,7 +148,7 @@ void drm_connector_ida_init(void); void drm_connector_ida_destroy(void); void drm_connector_unregister_all(struct drm_device *dev); int drm_connector_register_all(struct drm_device *dev); -int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, +int drm_connector_set_obj_prop(struct drm_mode_object *obj, struct drm_property *property, uint64_t value); int drm_connector_create_standard_properties(struct drm_device *dev); @@ -156,8 +156,8 @@ const char *drm_get_connector_force_name(enum drm_connector_force force); void drm_connector_free_work_fn(struct work_struct *work); /* IOCTL */ -int drm_mode_connector_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); +int drm_connector_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 50a20bfc07ea..6f28fe58f169 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -314,13 +314,13 @@ static ssize_t edid_write(struct file *file, const char __user *ubuf, if (len == 5 && !strncmp(buf, "reset", 5)) { connector->override_edid = false; - ret = drm_mode_connector_update_edid_property(connector, NULL); + ret = drm_connector_update_edid_property(connector, NULL); } else if (len < EDID_LENGTH || EDID_LENGTH * (1 + edid->extensions) > len) ret = -EINVAL; else { connector->override_edid = false; - ret = drm_mode_connector_update_edid_property(connector, edid); + ret = drm_connector_update_edid_property(connector, edid); if (!ret) connector->override_edid = true; } diff --git a/drivers/gpu/drm/drm_dp_cec.c b/drivers/gpu/drm/drm_dp_cec.c new file mode 100644 index 000000000000..ddb1c5adebb9 --- /dev/null +++ b/drivers/gpu/drm/drm_dp_cec.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DisplayPort CEC-Tunneling-over-AUX support + * + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include + +/* + * Unfortunately it turns out that we have a chicken-and-egg situation + * here. Quite a few active (mini-)DP-to-HDMI or USB-C-to-HDMI adapters + * have a converter chip that supports CEC-Tunneling-over-AUX (usually the + * Parade PS176), but they do not wire up the CEC pin, thus making CEC + * useless. + * + * Sadly there is no way for this driver to know this. What happens is + * that a /dev/cecX device is created that is isolated and unable to see + * any of the other CEC devices. Quite literally the CEC wire is cut + * (or in this case, never connected in the first place). + * + * The reason so few adapters support this is that this tunneling protocol + * was never supported by any OS. So there was no easy way of testing it, + * and no incentive to correctly wire up the CEC pin. + * + * Hopefully by creating this driver it will be easier for vendors to + * finally fix their adapters and test the CEC functionality. + * + * I keep a list of known working adapters here: + * + * https://hverkuil.home.xs4all.nl/cec-status.txt + * + * Please mail me (hverkuil@xs4all.nl) if you find an adapter that works + * and is not yet listed there. + * + * Note that the current implementation does not support CEC over an MST hub. + * As far as I can see there is no mechanism defined in the DisplayPort + * standard to transport CEC interrupts over an MST device. It might be + * possible to do this through polling, but I have not been able to get that + * to work. + */ + +/** + * DOC: dp cec helpers + * + * These functions take care of supporting the CEC-Tunneling-over-AUX + * feature of DisplayPort-to-HDMI adapters. + */ + +/* + * When the EDID is unset because the HPD went low, then the CEC DPCD registers + * typically can no longer be read (true for a DP-to-HDMI adapter since it is + * powered by the HPD). However, some displays toggle the HPD off and on for a + * short period for one reason or another, and that would cause the CEC adapter + * to be removed and added again, even though nothing else changed. + * + * This module parameter sets a delay in seconds before the CEC adapter is + * actually unregistered. Only if the HPD does not return within that time will + * the CEC adapter be unregistered. + * + * If it is set to a value >= NEVER_UNREG_DELAY, then the CEC adapter will never + * be unregistered for as long as the connector remains registered. + * + * If it is set to 0, then the CEC adapter will be unregistered immediately as + * soon as the HPD disappears. + * + * The default is one second to prevent short HPD glitches from unregistering + * the CEC adapter. + * + * Note that for integrated HDMI branch devices that support CEC the DPCD + * registers remain available even if the HPD goes low since it is not powered + * by the HPD. In that case the CEC adapter will never be unregistered during + * the life time of the connector. At least, this is the theory since I do not + * have hardware with an integrated HDMI branch device that supports CEC. + */ +#define NEVER_UNREG_DELAY 1000 +static unsigned int drm_dp_cec_unregister_delay = 1; +module_param(drm_dp_cec_unregister_delay, uint, 0600); +MODULE_PARM_DESC(drm_dp_cec_unregister_delay, + "CEC unregister delay in seconds, 0: no delay, >= 1000: never unregister"); + +static int drm_dp_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + u32 val = enable ? DP_CEC_TUNNELING_ENABLE : 0; + ssize_t err = 0; + + err = drm_dp_dpcd_writeb(aux, DP_CEC_TUNNELING_CONTROL, val); + return (enable && err < 0) ? err : 0; +} + +static int drm_dp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + /* Bit 15 (logical address 15) should always be set */ + u16 la_mask = 1 << CEC_LOG_ADDR_BROADCAST; + u8 mask[2]; + ssize_t err; + + if (addr != CEC_LOG_ADDR_INVALID) + la_mask |= adap->log_addrs.log_addr_mask | (1 << addr); + mask[0] = la_mask & 0xff; + mask[1] = la_mask >> 8; + err = drm_dp_dpcd_write(aux, DP_CEC_LOGICAL_ADDRESS_MASK, mask, 2); + return (addr != CEC_LOG_ADDR_INVALID && err < 0) ? err : 0; +} + +static int drm_dp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + unsigned int retries = min(5, attempts - 1); + ssize_t err; + + err = drm_dp_dpcd_write(aux, DP_CEC_TX_MESSAGE_BUFFER, + msg->msg, msg->len); + if (err < 0) + return err; + + err = drm_dp_dpcd_writeb(aux, DP_CEC_TX_MESSAGE_INFO, + (msg->len - 1) | (retries << 4) | + DP_CEC_TX_MESSAGE_SEND); + return err < 0 ? err : 0; +} + +static int drm_dp_cec_adap_monitor_all_enable(struct cec_adapter *adap, + bool enable) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + ssize_t err; + u8 val; + + if (!(adap->capabilities & CEC_CAP_MONITOR_ALL)) + return 0; + + err = drm_dp_dpcd_readb(aux, DP_CEC_TUNNELING_CONTROL, &val); + if (err >= 0) { + if (enable) + val |= DP_CEC_SNOOPING_ENABLE; + else + val &= ~DP_CEC_SNOOPING_ENABLE; + err = drm_dp_dpcd_writeb(aux, DP_CEC_TUNNELING_CONTROL, val); + } + return (enable && err < 0) ? err : 0; +} + +static void drm_dp_cec_adap_status(struct cec_adapter *adap, + struct seq_file *file) +{ + struct drm_dp_aux *aux = cec_get_drvdata(adap); + struct drm_dp_desc desc; + struct drm_dp_dpcd_ident *id = &desc.ident; + + if (drm_dp_read_desc(aux, &desc, true)) + return; + seq_printf(file, "OUI: %*pdH\n", + (int)sizeof(id->oui), id->oui); + seq_printf(file, "ID: %*pE\n", + (int)strnlen(id->device_id, sizeof(id->device_id)), + id->device_id); + seq_printf(file, "HW Rev: %d.%d\n", id->hw_rev >> 4, id->hw_rev & 0xf); + /* + * Show this both in decimal and hex: at least one vendor + * always reports this in hex. + */ + seq_printf(file, "FW/SW Rev: %d.%d (0x%02x.0x%02x)\n", + id->sw_major_rev, id->sw_minor_rev, + id->sw_major_rev, id->sw_minor_rev); +} + +static const struct cec_adap_ops drm_dp_cec_adap_ops = { + .adap_enable = drm_dp_cec_adap_enable, + .adap_log_addr = drm_dp_cec_adap_log_addr, + .adap_transmit = drm_dp_cec_adap_transmit, + .adap_monitor_all_enable = drm_dp_cec_adap_monitor_all_enable, + .adap_status = drm_dp_cec_adap_status, +}; + +static int drm_dp_cec_received(struct drm_dp_aux *aux) +{ + struct cec_adapter *adap = aux->cec.adap; + struct cec_msg msg; + u8 rx_msg_info; + ssize_t err; + + err = drm_dp_dpcd_readb(aux, DP_CEC_RX_MESSAGE_INFO, &rx_msg_info); + if (err < 0) + return err; + + if (!(rx_msg_info & DP_CEC_RX_MESSAGE_ENDED)) + return 0; + + msg.len = (rx_msg_info & DP_CEC_RX_MESSAGE_LEN_MASK) + 1; + err = drm_dp_dpcd_read(aux, DP_CEC_RX_MESSAGE_BUFFER, msg.msg, msg.len); + if (err < 0) + return err; + + cec_received_msg(adap, &msg); + return 0; +} + +static void drm_dp_cec_handle_irq(struct drm_dp_aux *aux) +{ + struct cec_adapter *adap = aux->cec.adap; + u8 flags; + + if (drm_dp_dpcd_readb(aux, DP_CEC_TUNNELING_IRQ_FLAGS, &flags) < 0) + return; + + if (flags & DP_CEC_RX_MESSAGE_INFO_VALID) + drm_dp_cec_received(aux); + + if (flags & DP_CEC_TX_MESSAGE_SENT) + cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK); + else if (flags & DP_CEC_TX_LINE_ERROR) + cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR | + CEC_TX_STATUS_MAX_RETRIES); + else if (flags & + (DP_CEC_TX_ADDRESS_NACK_ERROR | DP_CEC_TX_DATA_NACK_ERROR)) + cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK | + CEC_TX_STATUS_MAX_RETRIES); + drm_dp_dpcd_writeb(aux, DP_CEC_TUNNELING_IRQ_FLAGS, flags); +} + +/** + * drm_dp_cec_irq() - handle CEC interrupt, if any + * @aux: DisplayPort AUX channel + * + * Should be called when handling an IRQ_HPD request. If CEC-tunneling-over-AUX + * is present, then it will check for a CEC_IRQ and handle it accordingly. + */ +void drm_dp_cec_irq(struct drm_dp_aux *aux) +{ + u8 cec_irq; + int ret; + + mutex_lock(&aux->cec.lock); + if (!aux->cec.adap) + goto unlock; + + ret = drm_dp_dpcd_readb(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1, + &cec_irq); + if (ret < 0 || !(cec_irq & DP_CEC_IRQ)) + goto unlock; + + drm_dp_cec_handle_irq(aux); + drm_dp_dpcd_writeb(aux, DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1, DP_CEC_IRQ); +unlock: + mutex_unlock(&aux->cec.lock); +} +EXPORT_SYMBOL(drm_dp_cec_irq); + +static bool drm_dp_cec_cap(struct drm_dp_aux *aux, u8 *cec_cap) +{ + u8 cap = 0; + + if (drm_dp_dpcd_readb(aux, DP_CEC_TUNNELING_CAPABILITY, &cap) != 1 || + !(cap & DP_CEC_TUNNELING_CAPABLE)) + return false; + if (cec_cap) + *cec_cap = cap; + return true; +} + +/* + * Called if the HPD was low for more than drm_dp_cec_unregister_delay + * seconds. This unregisters the CEC adapter. + */ +static void drm_dp_cec_unregister_work(struct work_struct *work) +{ + struct drm_dp_aux *aux = container_of(work, struct drm_dp_aux, + cec.unregister_work.work); + + mutex_lock(&aux->cec.lock); + cec_unregister_adapter(aux->cec.adap); + aux->cec.adap = NULL; + mutex_unlock(&aux->cec.lock); +} + +/* + * A new EDID is set. If there is no CEC adapter, then create one. If + * there was a CEC adapter, then check if the CEC adapter properties + * were unchanged and just update the CEC physical address. Otherwise + * unregister the old CEC adapter and create a new one. + */ +void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) +{ + u32 cec_caps = CEC_CAP_DEFAULTS | CEC_CAP_NEEDS_HPD; + unsigned int num_las = 1; + u8 cap; + +#ifndef CONFIG_MEDIA_CEC_RC + /* + * CEC_CAP_RC is part of CEC_CAP_DEFAULTS, but it is stripped by + * cec_allocate_adapter() if CONFIG_MEDIA_CEC_RC is undefined. + * + * Do this here as well to ensure the tests against cec_caps are + * correct. + */ + cec_caps &= ~CEC_CAP_RC; +#endif + cancel_delayed_work_sync(&aux->cec.unregister_work); + + mutex_lock(&aux->cec.lock); + if (!drm_dp_cec_cap(aux, &cap)) { + /* CEC is not supported, unregister any existing adapter */ + cec_unregister_adapter(aux->cec.adap); + aux->cec.adap = NULL; + goto unlock; + } + + if (cap & DP_CEC_SNOOPING_CAPABLE) + cec_caps |= CEC_CAP_MONITOR_ALL; + if (cap & DP_CEC_MULTIPLE_LA_CAPABLE) + num_las = CEC_MAX_LOG_ADDRS; + + if (aux->cec.adap) { + if (aux->cec.adap->capabilities == cec_caps && + aux->cec.adap->available_log_addrs == num_las) { + /* Unchanged, so just set the phys addr */ + cec_s_phys_addr_from_edid(aux->cec.adap, edid); + goto unlock; + } + /* + * The capabilities changed, so unregister the old + * adapter first. + */ + cec_unregister_adapter(aux->cec.adap); + } + + /* Create a new adapter */ + aux->cec.adap = cec_allocate_adapter(&drm_dp_cec_adap_ops, + aux, aux->cec.name, cec_caps, + num_las); + if (IS_ERR(aux->cec.adap)) { + aux->cec.adap = NULL; + goto unlock; + } + if (cec_register_adapter(aux->cec.adap, aux->cec.parent)) { + cec_delete_adapter(aux->cec.adap); + aux->cec.adap = NULL; + } else { + /* + * Update the phys addr for the new CEC adapter. When called + * from drm_dp_cec_register_connector() edid == NULL, so in + * that case the phys addr is just invalidated. + */ + cec_s_phys_addr_from_edid(aux->cec.adap, edid); + } +unlock: + mutex_unlock(&aux->cec.lock); +} +EXPORT_SYMBOL(drm_dp_cec_set_edid); + +/* + * The EDID disappeared (likely because of the HPD going down). + */ +void drm_dp_cec_unset_edid(struct drm_dp_aux *aux) +{ + cancel_delayed_work_sync(&aux->cec.unregister_work); + + mutex_lock(&aux->cec.lock); + if (!aux->cec.adap) + goto unlock; + + cec_phys_addr_invalidate(aux->cec.adap); + /* + * We're done if we want to keep the CEC device + * (drm_dp_cec_unregister_delay is >= NEVER_UNREG_DELAY) or if the + * DPCD still indicates the CEC capability (expected for an integrated + * HDMI branch device). + */ + if (drm_dp_cec_unregister_delay < NEVER_UNREG_DELAY && + !drm_dp_cec_cap(aux, NULL)) { + /* + * Unregister the CEC adapter after drm_dp_cec_unregister_delay + * seconds. This to debounce short HPD off-and-on cycles from + * displays. + */ + schedule_delayed_work(&aux->cec.unregister_work, + drm_dp_cec_unregister_delay * HZ); + } +unlock: + mutex_unlock(&aux->cec.lock); +} +EXPORT_SYMBOL(drm_dp_cec_unset_edid); + +/** + * drm_dp_cec_register_connector() - register a new connector + * @aux: DisplayPort AUX channel + * @name: name of the CEC device + * @parent: parent device + * + * A new connector was registered with associated CEC adapter name and + * CEC adapter parent device. After registering the name and parent + * drm_dp_cec_set_edid() is called to check if the connector supports + * CEC and to register a CEC adapter if that is the case. + */ +void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name, + struct device *parent) +{ + WARN_ON(aux->cec.adap); + aux->cec.name = name; + aux->cec.parent = parent; + INIT_DELAYED_WORK(&aux->cec.unregister_work, + drm_dp_cec_unregister_work); + + drm_dp_cec_set_edid(aux, NULL); +} +EXPORT_SYMBOL(drm_dp_cec_register_connector); + +/** + * drm_dp_cec_unregister_connector() - unregister the CEC adapter, if any + * @aux: DisplayPort AUX channel + */ +void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux) +{ + if (!aux->cec.adap) + return; + cancel_delayed_work_sync(&aux->cec.unregister_work); + cec_unregister_adapter(aux->cec.adap); + aux->cec.adap = NULL; +} +EXPORT_SYMBOL(drm_dp_cec_unregister_connector); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index a7ba602a43a8..0cccbcb2d03e 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -185,6 +185,20 @@ EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); #define AUX_RETRY_INTERVAL 500 /* us */ +static inline void +drm_dp_dump_access(const struct drm_dp_aux *aux, + u8 request, uint offset, void *buffer, int ret) +{ + const char *arrow = request == DP_AUX_NATIVE_READ ? "->" : "<-"; + + if (ret > 0) + drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d) %*ph\n", + aux->name, offset, arrow, ret, min(ret, 20), buffer); + else + drm_dbg(DRM_UT_DP, "%s: 0x%05x AUX %s (ret=%3d)\n", + aux->name, offset, arrow, ret); +} + /** * DOC: dp helpers * @@ -288,10 +302,14 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, DP_DPCD_REV, buffer, 1); if (ret != 1) - return ret; + goto out; - return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, - size); + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer, + size); + +out: + drm_dp_dump_access(aux, DP_AUX_NATIVE_READ, offset, buffer, ret); + return ret; } EXPORT_SYMBOL(drm_dp_dpcd_read); @@ -312,8 +330,12 @@ EXPORT_SYMBOL(drm_dp_dpcd_read); ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, void *buffer, size_t size) { - return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, - size); + int ret; + + ret = drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, + size); + drm_dp_dump_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer, ret); + return ret; } EXPORT_SYMBOL(drm_dp_dpcd_write); @@ -1087,6 +1109,7 @@ static void drm_dp_aux_crc_work(struct work_struct *work) void drm_dp_aux_init(struct drm_dp_aux *aux) { mutex_init(&aux->hw_mutex); + mutex_init(&aux->cec.lock); INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work); aux->ddc.algo = &drm_dp_i2c_algo; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 658830620ca3..7780567aa669 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1215,7 +1215,7 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, port->pdt == DP_PEER_DEVICE_SST_SINK) && port->port_num >= DP_MST_LOGICAL_PORT_0) { port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); - drm_mode_connector_set_tile_property(port->connector); + drm_connector_set_tile_property(port->connector); } (*mstb->mgr->cbs->register_connector)(port->connector); } @@ -2559,7 +2559,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ edid = drm_edid_duplicate(port->cached_edid); else { edid = drm_get_edid(connector, &port->aux.ddc); - drm_mode_connector_set_tile_property(connector); + drm_connector_set_tile_property(connector); } port->has_audio = drm_detect_monitor_audio(edid); drm_dp_put_port(port); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 6eb935bb2f92..ea4941da9b27 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -54,13 +54,14 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); MODULE_DESCRIPTION("DRM shared core routines"); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n" -"\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" -"\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n" -"\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n" -"\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n" -"\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n" -"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" -"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)"); +"\t\tBit 0 (0x01) will enable CORE messages (drm core code)\n" +"\t\tBit 1 (0x02) will enable DRIVER messages (drm controller code)\n" +"\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n" +"\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n" +"\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n" +"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n" +"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)\n" +"\t\tBit 8 (0x100) will enable DP messages (displayport code)"); module_param_named(debug, drm_debug, int, 0600); static DEFINE_SPINLOCK(drm_minor_lock); diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 5ca6395cd4d3..35c1e2742c27 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -152,27 +152,27 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_XBGR8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, { .format = DRM_FORMAT_RGBX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, { .format = DRM_FORMAT_BGRX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, - { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, - { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 }, - { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, - { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 }, - { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2 }, - { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1 }, - { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, - { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true }, + { .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4, .is_yuv = true }, + { .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4, .is_yuv = true }, + { .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVU411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YUV420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_YVU420, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_YUV422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, + { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV61, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV24, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_NV42, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YUYV, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_YVYU, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_UYVY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true }, }; unsigned int i; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 3c125041a597..ea10e9a26aad 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -641,7 +641,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, DRM_UNLOCKED), diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index ce4d2fb32810..fcb0ab0abb75 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -433,8 +433,7 @@ static int set_property_legacy(struct drm_mode_object *obj, drm_modeset_lock_all(dev); switch (obj->type) { case DRM_MODE_OBJECT_CONNECTOR: - ret = drm_mode_connector_set_obj_prop(obj, prop, - prop_value); + ret = drm_connector_set_obj_prop(obj, prop, prop_value); break; case DRM_MODE_OBJECT_CRTC: ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index f8f7eae738ab..02db9ac82d7a 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1353,7 +1353,7 @@ void drm_mode_sort(struct list_head *mode_list) EXPORT_SYMBOL(drm_mode_sort); /** - * drm_mode_connector_list_update - update the mode list for the connector + * drm_connector_list_update - update the mode list for the connector * @connector: the connector to update * * This moves the modes from the @connector probed_modes list @@ -1363,7 +1363,7 @@ EXPORT_SYMBOL(drm_mode_sort); * This is just a helper functions doesn't validate any modes itself and also * doesn't prune any invalid modes. Callers need to do that themselves. */ -void drm_mode_connector_list_update(struct drm_connector *connector) +void drm_connector_list_update(struct drm_connector *connector) { struct drm_display_mode *pmode, *pt; @@ -1412,7 +1412,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector) } } } -EXPORT_SYMBOL(drm_mode_connector_list_update); +EXPORT_SYMBOL(drm_connector_list_update); /** * drm_mode_parse_command_line_for_connector - parse command line modeline for connector diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index 260612958cbe..2763a5ec845b 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -9,6 +9,13 @@ #include #include +/** + * DOC: overview + * + * A set of helper functions to aid DRM drivers in parsing standard DT + * properties. + */ + static void drm_release_of(struct device *dev, void *data) { of_node_put(data); @@ -94,7 +101,7 @@ EXPORT_SYMBOL_GPL(drm_of_component_match_add); * drm_of_component_probe - Generic probe function for a component based master * @dev: master device containing the OF node * @compare_of: compare function used for matching components - * @master_ops: component master ops to be used + * @m_ops: component master ops to be used * * Parse the platform device OF node and bind all the components associated * with the master. Interface ports are added before the encoders in order to diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index df0b4ebbedbf..6153cbda239f 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -583,6 +583,52 @@ int drm_plane_check_pixel_format(struct drm_plane *plane, return 0; } +static int __setplane_check(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + int ret; + + /* Check whether this plane is usable on this CRTC */ + if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { + DRM_DEBUG_KMS("Invalid crtc for plane\n"); + return -EINVAL; + } + + /* Check whether this plane supports the fb pixel format. */ + ret = drm_plane_check_pixel_format(plane, fb->format->format, + fb->modifier); + if (ret) { + struct drm_format_name_buf format_name; + + DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", + drm_get_format_name(fb->format->format, + &format_name), + fb->modifier); + return ret; + } + + /* Give drivers some help against integer overflows */ + if (crtc_w > INT_MAX || + crtc_x > INT_MAX - (int32_t) crtc_w || + crtc_h > INT_MAX || + crtc_y > INT_MAX - (int32_t) crtc_h) { + DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", + crtc_w, crtc_h, crtc_x, crtc_y); + return -ERANGE; + } + + ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); + if (ret) + return ret; + + return 0; +} + /* * __setplane_internal - setplane handler for internal callers * @@ -603,6 +649,8 @@ static int __setplane_internal(struct drm_plane *plane, { int ret = 0; + WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); + /* No fb means shut it down */ if (!fb) { plane->old_fb = plane->fb; @@ -616,37 +664,9 @@ static int __setplane_internal(struct drm_plane *plane, goto out; } - /* Check whether this plane is usable on this CRTC */ - if (!(plane->possible_crtcs & drm_crtc_mask(crtc))) { - DRM_DEBUG_KMS("Invalid crtc for plane\n"); - ret = -EINVAL; - goto out; - } - - /* Check whether this plane supports the fb pixel format. */ - ret = drm_plane_check_pixel_format(plane, fb->format->format, - fb->modifier); - if (ret) { - struct drm_format_name_buf format_name; - DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n", - drm_get_format_name(fb->format->format, - &format_name), - fb->modifier); - goto out; - } - - /* Give drivers some help against integer overflows */ - if (crtc_w > INT_MAX || - crtc_x > INT_MAX - (int32_t) crtc_w || - crtc_h > INT_MAX || - crtc_y > INT_MAX - (int32_t) crtc_h) { - DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", - crtc_w, crtc_h, crtc_x, crtc_y); - ret = -ERANGE; - goto out; - } - - ret = drm_framebuffer_check_src_coords(src_x, src_y, src_w, src_h, fb); + ret = __setplane_check(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); if (ret) goto out; @@ -655,11 +675,9 @@ static int __setplane_internal(struct drm_plane *plane, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, ctx); if (!ret) { - if (!plane->state) { - plane->crtc = crtc; - plane->fb = fb; - drm_framebuffer_get(plane->fb); - } + plane->crtc = crtc; + plane->fb = fb; + drm_framebuffer_get(plane->fb); } else { plane->old_fb = NULL; } @@ -672,6 +690,41 @@ out: return ret; } +static int __setplane_atomic(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) +{ + int ret; + + WARN_ON(!drm_drv_uses_atomic_modeset(plane->dev)); + + /* No fb means shut it down */ + if (!fb) + return plane->funcs->disable_plane(plane, ctx); + + /* + * FIXME: This is redundant with drm_atomic_plane_check(), + * but the legacy cursor/"async" .update_plane() tricks + * don't call that so we still need this here. Should remove + * this when all .update_plane() implementations have been + * fixed to call drm_atomic_plane_check(). + */ + ret = __setplane_check(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + if (ret) + return ret; + + return plane->funcs->update_plane(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, ctx); +} + static int setplane_internal(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -689,9 +742,15 @@ retry: ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); if (ret) goto fail; - ret = __setplane_internal(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h, &ctx); + + if (drm_drv_uses_atomic_modeset(plane->dev)) + ret = __setplane_atomic(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, &ctx); + else + ret = __setplane_internal(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h, &ctx); fail: if (ret == -EDEADLK) { @@ -823,9 +882,14 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, src_h = fb->height << 16; } - ret = __setplane_internal(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h, ctx); + if (drm_drv_uses_atomic_modeset(dev)) + ret = __setplane_atomic(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, src_w, src_h, ctx); + else + ret = __setplane_internal(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, src_w, src_h, ctx); if (fb) drm_framebuffer_put(fb); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 34fe2704a31c..a1bb157bfdfa 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -360,7 +360,7 @@ EXPORT_SYMBOL(drm_helper_probe_detect); * using the VESA GTF/CVT formulas. * * 3. Modes are moved from the probed_modes list to the modes list. Potential - * duplicates are merged together (see drm_mode_connector_list_update()). + * duplicates are merged together (see drm_connector_list_update()). * After this step the probed_modes list will be empty again. * * 4. Any non-stale mode on the modes list then undergoes validation @@ -472,7 +472,7 @@ retry: if (connector->status == connector_status_disconnected) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", connector->base.id, connector->name); - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); verbose_prune = false; goto prune; } @@ -485,7 +485,7 @@ retry: if (count == 0) goto prune; - drm_mode_connector_list_update(connector); + drm_connector_list_update(connector); if (connector->interlace_allowed) mode_flags |= DRM_MODE_FLAG_INTERLACE; diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index b72fcf1e9605..51fa978f0d23 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -287,7 +287,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev, if (ret || !connector) return ret; - return drm_mode_connector_attach_encoder(connector, encoder); + return drm_connector_attach_encoder(connector, encoder); } EXPORT_SYMBOL(drm_simple_display_pipe_init); diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index 69e7a63cfcc3..c20e6fe00cb3 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -25,8 +25,8 @@ * * * Writeback connectors don't provide a way to output visually to the user. * - * * Writeback connectors should always report as "disconnected" (so that - * clients which don't understand them will ignore them). + * * Writeback connectors are visible to userspace only when the client sets + * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS. * * * Writeback connectors don't have EDID. * @@ -202,7 +202,7 @@ int drm_writeback_connector_init(struct drm_device *dev, if (ret) goto connector_fail; - ret = drm_mode_connector_attach_encoder(connector, + ret = drm_connector_attach_encoder(connector, &wb_connector->encoder); if (ret) goto attach_fail; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 5887e8522b70..2f0babb67c51 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -113,7 +113,7 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder) } drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 809e1e0447df..a1ed6146a3b5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1479,7 +1479,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) connector->status = connector_status_disconnected; drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index e6b0940b1ac2..19697c1362d8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -319,7 +319,7 @@ static int vidi_get_modes(struct drm_connector *connector) return -ENOMEM; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); return drm_add_edid_modes(connector, edid); } @@ -344,7 +344,7 @@ static int vidi_create_connector(struct drm_encoder *encoder) } drm_connector_helper_add(connector, &vidi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index db91932550cf..3a11c719a580 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -888,7 +888,7 @@ static int hdmi_get_modes(struct drm_connector *connector) (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), edid->width_cm, edid->height_cm); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); cec_notifier_set_phys_addr_from_edid(hdata->notifier, edid); ret = drm_add_edid_modes(connector, edid); @@ -951,7 +951,7 @@ static int hdmi_create_connector(struct drm_encoder *encoder) } drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (hdata->bridge) { ret = drm_bridge_attach(encoder, hdata->bridge, NULL); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 681e2a07d03b..2298ed2a9e1c 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -117,7 +117,7 @@ static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, if (ret < 0) goto err_cleanup; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) goto err_sysfs; diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 5ea785f07ba8..90ed20083009 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -1770,7 +1770,7 @@ static int cdv_intel_dp_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &intel_dp->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index f0878998526a..4e4e4a66eaee 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -216,7 +216,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &gma_encoder->i2c_bus->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 08f17f85b801..09c1161a7ac6 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -665,7 +665,7 @@ void gma_connector_attach_encoder(struct gma_connector *connector, struct gma_encoder *encoder) { connector->encoder = encoder; - drm_mode_connector_attach_encoder(&connector->base, + drm_connector_attach_encoder(&connector->base, &encoder->base); } diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h index 978ae4b25e82..e0ccf1d19a4d 100644 --- a/drivers/gpu/drm/gma500/intel_bios.h +++ b/drivers/gpu/drm/gma500/intel_bios.h @@ -34,7 +34,7 @@ struct vbt_header { u8 reserved0; u32 bdb_offset; /**< from beginning of VBT */ u32 aim_offset[4]; /**< from beginning of VBT */ -} __attribute__((packed)); +} __packed; struct bdb_header { @@ -61,7 +61,7 @@ struct vbios_data { u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; u8 rsvd5; /* is crt already on ddc2 */ -} __attribute__((packed)); +} __packed; /* * There are several types of BIOS data blocks (BDBs), each block has @@ -133,7 +133,7 @@ struct bdb_general_features { u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ u8 rsvd11:3; /* finish byte */ -} __attribute__((packed)); +} __packed; /* pre-915 */ #define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ @@ -213,7 +213,7 @@ struct child_device_config { u8 dvo2_wiring; u16 extended_type; u8 dvo_function; -} __attribute__((packed)); +} __packed; struct bdb_general_definitions { @@ -256,7 +256,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; -} __attribute__((packed)); +} __packed; struct bdb_lvds_backlight { u8 type:2; @@ -268,7 +268,7 @@ struct bdb_lvds_backlight { u8 i2caddr; u8 brightnesscmd; /*FIXME: more...*/ -} __attribute__((packed)); +} __packed; /* LFP pointer table contains entries to the struct below */ struct bdb_lvds_lfp_data_ptr { @@ -278,12 +278,12 @@ struct bdb_lvds_lfp_data_ptr { u8 dvo_table_size; u16 panel_pnp_id_offset; u8 pnp_table_size; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct bdb_lvds_lfp_data_ptr ptr[16]; -} __attribute__((packed)); +} __packed; /* LFP data has 3 blocks per entry */ struct lvds_fp_timing { @@ -300,7 +300,7 @@ struct lvds_fp_timing { u32 pfit_reg; u32 pfit_reg_val; u16 terminator; -} __attribute__((packed)); +} __packed; struct lvds_dvo_timing { u16 clock; /**< In 10khz */ @@ -328,7 +328,7 @@ struct lvds_dvo_timing { u8 vsync_positive:1; u8 hsync_positive:1; u8 rsvd2:1; -} __attribute__((packed)); +} __packed; struct lvds_pnp_id { u16 mfg_name; @@ -336,17 +336,17 @@ struct lvds_pnp_id { u32 serial; u8 mfg_week; u8 mfg_year; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_entry { struct lvds_fp_timing fp_timing; struct lvds_dvo_timing dvo_timing; struct lvds_pnp_id pnp_id; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; -} __attribute__((packed)); +} __packed; struct aimdb_header { char signature[16]; @@ -354,12 +354,12 @@ struct aimdb_header { u16 aimdb_version; u16 aimdb_header_size; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct aimdb_block { u8 aimdb_id; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct vch_panel_data { u16 fp_timing_offset; @@ -370,12 +370,12 @@ struct vch_panel_data { u8 text_fitting_size; u16 graphics_fitting_offset; u8 graphics_fitting_size; -} __attribute__((packed)); +} __packed; struct vch_bdb_22 { struct aimdb_block aimdb_block; struct vch_panel_data panels[16]; -} __attribute__((packed)); +} __packed; struct bdb_sdvo_lvds_options { u8 panel_backlight; @@ -391,7 +391,7 @@ struct bdb_sdvo_lvds_options { u8 panel_misc_bits_2; u8 panel_misc_bits_3; u8 panel_misc_bits_4; -} __attribute__((packed)); +} __packed; #define BDB_DRIVER_FEATURE_NO_LVDS 0 #define BDB_DRIVER_FEATURE_INT_LVDS 1 @@ -436,7 +436,7 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; -} __attribute__((packed)); +} __packed; #define EDP_18BPP 0 #define EDP_24BPP 1 diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c index a05c020602bd..d0bf5a1e94e8 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c @@ -999,7 +999,7 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev, p_funcs->encoder_helper_funcs); /*attach to given connector*/ - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); /*set possible crtcs and clones*/ if (dsi_connector->pipe) { diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 78566a80ad25..c6d72de1c054 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -578,7 +578,7 @@ static int oaktrail_hdmi_get_modes(struct drm_connector *connector) } if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); } return ret; diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index e6943fef0611..83babb815a5d 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -376,7 +376,7 @@ void oaktrail_lvds_init(struct drm_device *dev, * preferred mode is the right one. */ if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/gma500/psb_intel_modes.c b/drivers/gpu/drm/gma500/psb_intel_modes.c index e5360726d80b..fb4da3cd6681 100644 --- a/drivers/gpu/drm/gma500/psb_intel_modes.c +++ b/drivers/gpu/drm/gma500/psb_intel_modes.c @@ -66,7 +66,7 @@ int psb_intel_ddc_get_modes(struct drm_connector *connector, edid = drm_get_edid(connector, adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 1d40746ab625..dd3cec0e3190 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1472,7 +1472,7 @@ static void psb_intel_sdvo_get_ddc_modes(struct drm_connector *connector) bool connector_is_digital = !!IS_TMDS(psb_intel_sdvo_connector); if (connector_is_digital == monitor_is_digital) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index d2f4749ebf8d..744956cea749 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -133,7 +133,7 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv) } drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 0038c976536a..eecdc327b9f8 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1243,7 +1243,7 @@ static int tda998x_connector_get_modes(struct drm_connector *connector) return 0; } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); kfree(edid); @@ -1301,7 +1301,7 @@ static int tda998x_connector_init(struct tda998x_priv *priv, if (ret) return ret; - drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder); + drm_connector_attach_encoder(&priv->connector, &priv->encoder); return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8f3199b06d1f..e348b27e901f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3657,7 +3657,7 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; plane_color_ctl |= glk_plane_color_ctl_alpha(fb->format->format); - if (intel_format_is_yuv(fb->format->format)) { + if (fb->format->is_yuv) { if (plane_state->base.color_encoding == DRM_COLOR_YCBCR_BT709) plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; else @@ -15933,8 +15933,7 @@ void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder) { connector->encoder = encoder; - drm_mode_connector_attach_encoder(&connector->base, - &encoder->base); + drm_connector_attach_encoder(&connector->base, &encoder->base); } /* diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5be07e1d816d..53302bb77ad6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4487,6 +4487,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); } + /* Handle CEC interrupts, if any */ + drm_dp_cec_irq(&intel_dp->aux); + /* defer to the hotplug work for link retraining if needed */ if (intel_dp_needs_link_retrain(intel_dp)) return false; @@ -4803,6 +4806,7 @@ intel_dp_set_edid(struct intel_dp *intel_dp) intel_connector->detect_edid = edid; intel_dp->has_audio = drm_detect_monitor_audio(edid); + drm_dp_cec_set_edid(&intel_dp->aux, edid); } static void @@ -4810,6 +4814,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) { struct intel_connector *intel_connector = intel_dp->attached_connector; + drm_dp_cec_unset_edid(&intel_dp->aux); kfree(intel_connector->detect_edid); intel_connector->detect_edid = NULL; @@ -4998,6 +5003,7 @@ static int intel_dp_connector_register(struct drm_connector *connector) { struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_device *dev = connector->dev; int ret; ret = intel_connector_register(connector); @@ -5010,13 +5016,20 @@ intel_dp_connector_register(struct drm_connector *connector) intel_dp->aux.name, connector->kdev->kobj.name); intel_dp->aux.dev = connector->kdev; - return drm_dp_aux_register(&intel_dp->aux); + ret = drm_dp_aux_register(&intel_dp->aux); + if (!ret) + drm_dp_cec_register_connector(&intel_dp->aux, + connector->name, dev->dev); + return ret; } static void intel_dp_connector_unregister(struct drm_connector *connector) { - drm_dp_aux_unregister(&intel_attached_dp(connector)->aux); + struct intel_dp *intel_dp = intel_attached_dp(connector); + + drm_dp_cec_unregister_connector(&intel_dp->aux); + drm_dp_aux_unregister(&intel_dp->aux); intel_connector_unregister(connector); } @@ -6212,7 +6225,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, edid = drm_get_edid(connector, &intel_dp->aux.ddc); if (edid) { if (drm_add_edid_modes(connector, edid)) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, edid); } else { kfree(edid); @@ -6301,8 +6314,8 @@ static void intel_dp_modeset_retry_work_fn(struct work_struct *work) /* Set connector link status to BAD and send a Uevent to notify * userspace to do a modeset. */ - drm_mode_connector_set_link_status_property(connector, - DRM_MODE_LINK_STATUS_BAD); + drm_connector_set_link_status_property(connector, + DRM_MODE_LINK_STATUS_BAD); mutex_unlock(&connector->dev->mode_config.mutex); /* Send Hotplug uevent so userspace can reprobe */ drm_kms_helper_hotplug_event(connector->dev); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 85ecf41eeabb..7e3e01607643 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -466,8 +466,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo struct drm_encoder *enc = &intel_dp->mst_encoders[pipe]->base.base; - ret = drm_mode_connector_attach_encoder(&intel_connector->base, - enc); + ret = drm_connector_attach_encoder(&intel_connector->base, enc); if (ret) goto err; } @@ -475,7 +474,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); - ret = drm_mode_connector_set_path_property(connector, pathprop); + ret = drm_connector_set_path_property(connector, pathprop); if (ret) goto err; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 61e715ddd0d5..6fa0acddf014 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -2072,7 +2072,6 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, /* intel_sprite.c */ -bool intel_format_is_yuv(u32 format); int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, int usecs); struct intel_plane *intel_sprite_plane_create(struct drm_i915_private *dev_priv, @@ -2088,7 +2087,6 @@ void skl_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc); bool skl_plane_get_hw_state(struct intel_plane *plane, enum pipe *pipe); bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); -bool intel_format_is_yuv(uint32_t format); bool skl_plane_has_planar(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bb06744d28a4..ca55b0a82ba6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1131,7 +1131,7 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) intel_gmbus_get_adapter(dev_priv, pin)); if (edid) { if (drm_add_edid_modes(connector, edid)) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, edid); } else { kfree(edid); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index b39846613e3c..ca44bf368e24 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -40,7 +40,7 @@ int intel_connector_update_modes(struct drm_connector *connector, { int ret; - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); return ret; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 396cb59ca4b8..812fe7b06f87 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1911,7 +1911,7 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) if (edid != NULL) { if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector), edid)) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 4990d6e84ddf..4b9b1d4224d8 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -41,20 +41,6 @@ #include #include "i915_drv.h" -bool intel_format_is_yuv(u32 format) -{ - switch (format) { - case DRM_FORMAT_YUYV: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_NV12: - return true; - default: - return false; - } -} - int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, int usecs) { @@ -416,7 +402,7 @@ chv_update_csc(const struct intel_plane_state *plane_state) const s16 *csc = csc_matrix[plane_state->base.color_encoding]; /* Seems RGB data bypasses the CSC always */ - if (!intel_format_is_yuv(fb->format->format)) + if (!fb->format->is_yuv) return; I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); @@ -451,7 +437,7 @@ vlv_update_clrc(const struct intel_plane_state *plane_state) enum plane_id plane_id = plane->id; int contrast, brightness, sh_scale, sh_sin, sh_cos; - if (intel_format_is_yuv(fb->format->format) && + if (fb->format->is_yuv && plane_state->base.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) { /* * Expand limited range to full range: @@ -1052,7 +1038,7 @@ intel_check_sprite_plane(struct intel_plane *plane, src->y1 = src_y << 16; src->y2 = (src_y + src_h) << 16; - if (intel_format_is_yuv(fb->format->format) && + if (fb->format->is_yuv && fb->format->format != DRM_FORMAT_NV12 && (src_x % 2 || src_w % 2)) { DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n", diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 56dd7a9a8e25..7312beb6f1fc 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -143,7 +143,7 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); if (imx_ldb_ch->edid) { - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, imx_ldb_ch->edid); num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid); } @@ -471,8 +471,7 @@ static int imx_ldb_register(struct drm_device *drm, drm_connector_init(drm, &imx_ldb_ch->connector, &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, - encoder); + drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder); } if (imx_ldb_ch->panel) { diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index bc27c2699464..cffd3310240e 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -235,7 +235,7 @@ static int imx_tve_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, tve->ddc); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } @@ -493,7 +493,7 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); + drm_connector_attach_encoder(&tve->connector, &tve->encoder); return 0; } diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index aedecda9728a..aefd04e18f93 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -63,7 +63,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) } if (imxpd->edid) { - drm_mode_connector_update_edid_property(connector, imxpd->edid); + drm_connector_update_edid_property(connector, imxpd->edid); num_modes = drm_add_edid_modes(connector, imxpd->edid); } @@ -197,7 +197,7 @@ static int imx_pd_register(struct drm_device *drm, return ret; } } else { - drm_mode_connector_attach_encoder(&imxpd->connector, encoder); + drm_connector_attach_encoder(&imxpd->connector, encoder); } return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index aa0943ec32b0..66df1b177959 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -782,7 +782,7 @@ static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi) drm_connector_helper_add(&dsi->conn, &mtk_dsi_connector_helper_funcs); dsi->conn.dpms = DRM_MODE_DPMS_OFF; - drm_mode_connector_attach_encoder(&dsi->conn, &dsi->encoder); + drm_connector_attach_encoder(&dsi->conn, &dsi->encoder); if (dsi->panel) { ret = drm_panel_attach(dsi->panel, &dsi->conn); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 59a11026dceb..2d45d1dd9554 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1220,7 +1220,7 @@ static int mtk_hdmi_conn_get_modes(struct drm_connector *conn) hdmi->dvi_mode = !drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(conn, edid); + drm_connector_update_edid_property(conn, edid); ret = drm_add_edid_modes(conn, edid); kfree(edid); @@ -1306,7 +1306,7 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge) hdmi->conn.interlace_allowed = true; hdmi->conn.doublescan_allowed = false; - ret = drm_mode_connector_attach_encoder(&hdmi->conn, + ret = drm_connector_attach_encoder(&hdmi->conn, bridge->encoder); if (ret) { dev_err(hdmi->dev, diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index c9ad45686e7a..df7247cd93f9 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -329,6 +329,12 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, vclk_freq = mode->clock; + if (!vic) { + meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq, + vclk_freq, vclk_freq, false); + return; + } + if (mode->flags & DRM_MODE_FLAG_DBLCLK) vclk_freq *= 2; @@ -542,10 +548,12 @@ static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector, const struct drm_display_mode *mode) { + struct meson_drm *priv = connector->dev->dev_private; unsigned int vclk_freq; unsigned int venc_freq; unsigned int hdmi_freq; int vic = drm_match_cea_mode(mode); + enum drm_mode_status status; DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->base.id, mode->name, mode->vrefresh, mode->clock, @@ -556,8 +564,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, /* Check against non-VIC supported modes */ if (!vic) { - if (!meson_venc_hdmi_supported_mode(mode)) - return MODE_BAD; + status = meson_venc_hdmi_supported_mode(mode); + if (status != MODE_OK) + return status; + + return meson_vclk_dmt_supported_freq(priv, mode->clock); /* Check against supported VIC modes */ } else if (!meson_venc_hdmi_supported_vic(vic)) return MODE_BAD; @@ -583,16 +594,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, vclk_freq, venc_freq, hdmi_freq); - /* Finally filter by configurable vclk frequencies */ + /* Finally filter by configurable vclk frequencies for VIC modes */ switch (vclk_freq) { - case 25175: - case 40000: case 54000: - case 65000: case 74250: - case 108000: case 148500: - case 162000: case 297000: case 594000: return MODE_OK; diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index f0511220317f..ae5473257f72 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -320,32 +320,23 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) CTS_VDAC_EN, CTS_VDAC_EN); } - +enum { /* PLL O1 O2 O3 VP DV EN TX */ /* 4320 /4 /4 /1 /5 /1 => /2 /2 */ -#define MESON_VCLK_HDMI_ENCI_54000 1 + MESON_VCLK_HDMI_ENCI_54000 = 1, /* 4320 /4 /4 /1 /5 /1 => /1 /2 */ -#define MESON_VCLK_HDMI_DDR_54000 2 + MESON_VCLK_HDMI_DDR_54000, /* 2970 /4 /1 /1 /5 /1 => /1 /2 */ -#define MESON_VCLK_HDMI_DDR_148500 3 -/* 4028 /4 /4 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_25175 4 -/* 3200 /4 /2 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_40000 5 -/* 5200 /4 /2 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_65000 6 + MESON_VCLK_HDMI_DDR_148500, /* 2970 /2 /2 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_74250 7 -/* 4320 /4 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_108000 8 + MESON_VCLK_HDMI_74250, /* 2970 /1 /2 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_148500 9 -/* 3240 /2 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_162000 10 + MESON_VCLK_HDMI_148500, /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ -#define MESON_VCLK_HDMI_297000 11 + MESON_VCLK_HDMI_297000, /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ -#define MESON_VCLK_HDMI_594000 12 + MESON_VCLK_HDMI_594000 +}; struct meson_vclk_params { unsigned int pll_base_freq; @@ -411,46 +402,6 @@ struct meson_vclk_params { .vid_pll_div = VID_PLL_DIV_5, .vclk_div = 1, }, - [MESON_VCLK_HDMI_25175] = { - .pll_base_freq = 4028000, - .pll_od1 = 4, - .pll_od2 = 4, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_40000] = { - .pll_base_freq = 3200000, - .pll_od1 = 4, - .pll_od2 = 2, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_65000] = { - .pll_base_freq = 5200000, - .pll_od1 = 4, - .pll_od2 = 2, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_108000] = { - .pll_base_freq = 4320000, - .pll_od1 = 4, - .pll_od2 = 1, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, - [MESON_VCLK_HDMI_162000] = { - .pll_base_freq = 3240000, - .pll_od1 = 2, - .pll_od2 = 1, - .pll_od3 = 1, - .vid_pll_div = VID_PLL_DIV_5, - .vclk_div = 2, - }, }; static inline unsigned int pll_od_to_reg(unsigned int od) @@ -470,358 +421,217 @@ static inline unsigned int pll_od_to_reg(unsigned int od) return 0; } -void meson_hdmi_pll_set(struct meson_drm *priv, - unsigned int base, - unsigned int od1, - unsigned int od2, - unsigned int od3) +void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, + unsigned int frac, unsigned int od1, + unsigned int od2, unsigned int od3) { unsigned int val; if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { - switch (base) { - case 2970000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m); + if (frac) + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0x00004000 | frac); + else + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, + 0x00000000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - /* Enable and unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - 0x7 << 28, 0x4 << 28); + /* Enable and unreset */ + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + 0x7 << 28, 0x4 << 28); - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4e00); - break; - - case 3200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4aab); - break; - - case 3240000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4800); - break; - - case 3865000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4855); - break; - - case 4028000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - - /* div_frac */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4eab); - break; - - case 4320000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - break; - - case 5940000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b); - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 0xFFFF, 0x4c00); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - break; - - case 5200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); - - /* unreset */ - regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - BIT(28), 0); - - /* Poll for lock bit */ - regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, - val, (val & HDMI_PLL_LOCK), 10, 0); - break; - }; + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, + val, (val & HDMI_PLL_LOCK), 10, 0); } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { - switch (base) { - case 2970000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 3200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 3240000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 3865000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 4028000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 4320000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 5940000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - case 5200000: - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); - regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); - break; - - }; + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500); /* Reset PLL */ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - HDMI_PLL_RESET, HDMI_PLL_RESET); + HDMI_PLL_RESET, HDMI_PLL_RESET); regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - HDMI_PLL_RESET, 0); + HDMI_PLL_RESET, 0); /* Poll for lock bit */ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, (val & HDMI_PLL_LOCK), 10, 0); - }; + } if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 16, pll_od_to_reg(od1) << 16); + 3 << 16, pll_od_to_reg(od1) << 16); else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 21, pll_od_to_reg(od1) << 21); + 3 << 21, pll_od_to_reg(od1) << 21); if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 22, pll_od_to_reg(od2) << 22); + 3 << 22, pll_od_to_reg(od2) << 22); else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 23, pll_od_to_reg(od2) << 23); + 3 << 23, pll_od_to_reg(od2) << 23); if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, - 3 << 18, pll_od_to_reg(od3) << 18); + 3 << 18, pll_od_to_reg(od3) << 18); else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || - meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, - 3 << 19, pll_od_to_reg(od3) << 19); + 3 << 19, pll_od_to_reg(od3) << 19); + } -void meson_vclk_setup(struct meson_drm *priv, unsigned int target, - unsigned int vclk_freq, unsigned int venc_freq, - unsigned int dac_freq, bool hdmi_use_enci) +#define XTAL_FREQ 24000 + +static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, + unsigned int pll_freq) { - unsigned int freq; - unsigned int hdmi_tx_div; - unsigned int venc_div; + /* The GXBB PLL has a /2 pre-multiplier */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + pll_freq /= 2; + + return pll_freq / XTAL_FREQ; +} + +#define HDMI_FRAC_MAX_GXBB 4096 +#define HDMI_FRAC_MAX_GXL 1024 + +static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, + unsigned int m, + unsigned int pll_freq) +{ + unsigned int parent_freq = XTAL_FREQ; + unsigned int frac_max = HDMI_FRAC_MAX_GXL; + unsigned int frac_m; + unsigned int frac; + + /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + frac_max = HDMI_FRAC_MAX_GXBB; + parent_freq *= 2; + } + + /* We can have a perfect match !*/ + if (pll_freq / m == parent_freq && + pll_freq % m == 0) + return 0; + + frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq); + frac_m = m * frac_max; + if (frac_m > frac) + return frac_max; + frac -= frac_m; + + return min((u16)frac, (u16)(frac_max - 1)); +} + +static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, + unsigned int m, + unsigned int frac) +{ + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + /* Empiric supported min/max dividers */ + if (m < 53 || m > 123) + return false; + if (frac >= HDMI_FRAC_MAX_GXBB) + return false; + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + /* Empiric supported min/max dividers */ + if (m < 106 || m > 247) + return false; + if (frac >= HDMI_FRAC_MAX_GXL) + return false; + } + + return true; +} + +static bool meson_hdmi_pll_find_params(struct meson_drm *priv, + unsigned int freq, + unsigned int *m, + unsigned int *frac, + unsigned int *od) +{ + /* Cycle from /16 to /2 */ + for (*od = 16 ; *od > 1 ; *od >>= 1) { + *m = meson_hdmi_pll_get_m(priv, freq * *od); + if (!*m) + continue; + *frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od); + + DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d\n", + freq, *m, *frac, *od); + + if (meson_hdmi_pll_validate_params(priv, *m, *frac)) + return true; + } + + return false; +} + +/* pll_freq is the frequency after the OD dividers */ +enum drm_mode_status +meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq) +{ + unsigned int od, m, frac; + + /* In DMT mode, path after PLL is always /10 */ + freq *= 10; + + if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od)) + return MODE_OK; + + return MODE_CLOCK_RANGE; +} +EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq); + +/* pll_freq is the frequency after the OD dividers */ +static void meson_hdmi_pll_generic_set(struct meson_drm *priv, + unsigned int pll_freq) +{ + unsigned int od, m, frac, od1, od2, od3; + + if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) { + od3 = 1; + if (od < 4) { + od1 = 2; + od2 = 1; + } else { + od2 = od / 4; + od1 = od / od2; + } + + DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n", + pll_freq, m, frac, od1, od2, od3); + + meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); - if (target == MESON_VCLK_TARGET_CVBS) { - meson_venci_cvbs_clock_config(priv); return; } - hdmi_tx_div = vclk_freq / dac_freq; - - if (hdmi_tx_div == 0) { - pr_err("Fatal Error, invalid HDMI-TX freq %d\n", - dac_freq); - return; - } - - venc_div = vclk_freq / venc_freq; - - if (venc_div == 0) { - pr_err("Fatal Error, invalid HDMI venc freq %d\n", - venc_freq); - return; - } - - switch (vclk_freq) { - case 54000: - if (hdmi_use_enci) - freq = MESON_VCLK_HDMI_ENCI_54000; - else - freq = MESON_VCLK_HDMI_DDR_54000; - break; - case 25175: - freq = MESON_VCLK_HDMI_25175; - break; - case 40000: - freq = MESON_VCLK_HDMI_40000; - break; - case 65000: - freq = MESON_VCLK_HDMI_65000; - break; - case 74250: - freq = MESON_VCLK_HDMI_74250; - break; - case 108000: - freq = MESON_VCLK_HDMI_108000; - break; - case 148500: - if (dac_freq != 148500) - freq = MESON_VCLK_HDMI_DDR_148500; - else - freq = MESON_VCLK_HDMI_148500; - break; - case 162000: - freq = MESON_VCLK_HDMI_162000; - break; - case 297000: - freq = MESON_VCLK_HDMI_297000; - break; - case 594000: - freq = MESON_VCLK_HDMI_594000; - break; - default: - pr_err("Fatal Error, invalid HDMI vclk freq %d\n", - vclk_freq); - return; - } + DRM_ERROR("Fatal, unable to find parameters for PLL freq %d\n", + pll_freq); +} +static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, + unsigned int od1, unsigned int od2, unsigned int od3, + unsigned int vid_pll_div, unsigned int vclk_div, + unsigned int hdmi_tx_div, unsigned int venc_div, + bool hdmi_use_enci) +{ /* Set HDMI-TX sys clock */ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, CTS_HDMI_SYS_SEL_MASK, 0); @@ -831,19 +641,49 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN); /* Set HDMI PLL rate */ - meson_hdmi_pll_set(priv, params[freq].pll_base_freq, - params[freq].pll_od1, - params[freq].pll_od2, - params[freq].pll_od3); + if (!od1 && !od2 && !od3) { + meson_hdmi_pll_generic_set(priv, pll_base_freq); + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + switch (pll_base_freq) { + case 2970000: + meson_hdmi_pll_set_params(priv, 0x3d, 0xe00, + od1, od2, od3); + break; + case 4320000: + meson_hdmi_pll_set_params(priv, 0x5a, 0, + od1, od2, od3); + break; + case 5940000: + meson_hdmi_pll_set_params(priv, 0x7b, 0xc00, + od1, od2, od3); + break; + } + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + switch (pll_base_freq) { + case 2970000: + meson_hdmi_pll_set_params(priv, 0x7b, 0x300, + od1, od2, od3); + break; + case 4320000: + meson_hdmi_pll_set_params(priv, 0xb4, 0, + od1, od2, od3); + break; + case 5940000: + meson_hdmi_pll_set_params(priv, 0xf7, 0x200, + od1, od2, od3); + break; + } + } /* Setup vid_pll divider */ - meson_vid_pll_set(priv, params[freq].vid_pll_div); + meson_vid_pll_set(priv, vid_pll_div); /* Set VCLK div */ regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_SEL_MASK, 0); regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV, - VCLK_DIV_MASK, params[freq].vclk_div - 1); + VCLK_DIV_MASK, vclk_div - 1); /* Set HDMI-TX source */ switch (hdmi_tx_div) { @@ -981,4 +821,80 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN); } + +void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + unsigned int vclk_freq, unsigned int venc_freq, + unsigned int dac_freq, bool hdmi_use_enci) +{ + unsigned int freq; + unsigned int hdmi_tx_div; + unsigned int venc_div; + + if (target == MESON_VCLK_TARGET_CVBS) { + meson_venci_cvbs_clock_config(priv); + return; + } else if (target == MESON_VCLK_TARGET_DMT) { + /* The DMT clock path is fixed after the PLL: + * - automatic PLL freq + OD management + * - vid_pll_div = VID_PLL_DIV_5 + * - vclk_div = 2 + * - hdmi_tx_div = 1 + * - venc_div = 1 + * - encp encoder + */ + meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, + VID_PLL_DIV_5, 2, 1, 1, false); + return; + } + + hdmi_tx_div = vclk_freq / dac_freq; + + if (hdmi_tx_div == 0) { + pr_err("Fatal Error, invalid HDMI-TX freq %d\n", + dac_freq); + return; + } + + venc_div = vclk_freq / venc_freq; + + if (venc_div == 0) { + pr_err("Fatal Error, invalid HDMI venc freq %d\n", + venc_freq); + return; + } + + switch (vclk_freq) { + case 54000: + if (hdmi_use_enci) + freq = MESON_VCLK_HDMI_ENCI_54000; + else + freq = MESON_VCLK_HDMI_DDR_54000; + break; + case 74250: + freq = MESON_VCLK_HDMI_74250; + break; + case 148500: + if (dac_freq != 148500) + freq = MESON_VCLK_HDMI_DDR_148500; + else + freq = MESON_VCLK_HDMI_148500; + break; + case 297000: + freq = MESON_VCLK_HDMI_297000; + break; + case 594000: + freq = MESON_VCLK_HDMI_594000; + break; + default: + pr_err("Fatal Error, invalid HDMI vclk freq %d\n", + vclk_freq); + return; + } + + meson_vclk_set(priv, params[freq].pll_base_freq, + params[freq].pll_od1, params[freq].pll_od2, + params[freq].pll_od3, params[freq].vid_pll_div, + params[freq].vclk_div, hdmi_tx_div, venc_div, + hdmi_use_enci); +} EXPORT_SYMBOL_GPL(meson_vclk_setup); diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h index 0401b5213471..869fa3a3073e 100644 --- a/drivers/gpu/drm/meson/meson_vclk.h +++ b/drivers/gpu/drm/meson/meson_vclk.h @@ -24,11 +24,15 @@ enum { MESON_VCLK_TARGET_CVBS = 0, MESON_VCLK_TARGET_HDMI = 1, + MESON_VCLK_TARGET_DMT = 2, }; /* 27MHz is the CVBS Pixel Clock */ #define MESON_VCLK_CVBS 27000 +enum drm_mode_status +meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); + void meson_vclk_setup(struct meson_drm *priv, unsigned int target, unsigned int vclk_freq, unsigned int venc_freq, unsigned int dac_freq, bool hdmi_use_enci); diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 6e2701389801..514245e69b38 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -697,314 +697,6 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = { }, }; -union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x31f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x90, - .havon_end = 0x30f, - .vavon_bline = 0x23, - .vavon_eline = 0x202, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x60, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 2, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x20c, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x41f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0xD8, - .havon_end = 0x3f7, - .vavon_bline = 0x1b, - .vavon_eline = 0x272, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x80, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 4, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x273, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 1343, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 296, - .havon_end = 1319, - .vavon_bline = 35, - .vavon_eline = 802, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 136, - .vso_begin = 30, - .vso_end = 50, - .vso_bline = 0, - .vso_eline = 6, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 805, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x63f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x180, - .havon_end = 0x5ff, - .vavon_bline = 0x23, - .vavon_eline = 0x382, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x80, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 3, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x383, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x697, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x168, - .havon_end = 0x667, - .vavon_bline = 0x29, - .vavon_eline = 0x428, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0x70, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 3, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x429, - }, -}; - -union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = { - .encp = { - .dvi_settings = 0x21, - .video_mode = 0x4040, - .video_mode_adv = 0x18, - /* video_prog_mode */ - /* video_sync_mode */ - /* video_yc_dly */ - /* video_rgb_ctrl */ - /* video_filt_ctrl */ - /* video_ofld_voav_ofst */ - /* yfp1_htime */ - /* yfp2_htime */ - .max_pxcnt = 0x86f, - /* hspuls_begin */ - /* hspuls_end */ - /* hspuls_switch */ - /* vspuls_begin */ - /* vspuls_end */ - /* vspuls_bline */ - /* vspuls_eline */ - .havon_begin = 0x1f0, - .havon_end = 0x82f, - .vavon_bline = 0x31, - .vavon_eline = 0x4e0, - /* eqpuls_begin */ - /* eqpuls_end */ - /* eqpuls_bline */ - /* eqpuls_eline */ - .hso_begin = 0, - .hso_end = 0xc0, - .vso_begin = 0x1e, - .vso_end = 0x32, - .vso_bline = 0, - .vso_eline = 3, - .vso_eline_present = true, - /* sy_val */ - /* sy2_val */ - .max_lncnt = 0x4e1, - }, -}; - -struct meson_hdmi_venc_dmt_mode { - struct drm_display_mode drm_mode; - union meson_hdmi_venc_mode *mode; -} meson_hdmi_venc_dmt_modes[] = { - /* 640x480@60Hz */ - { - { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, - 752, 800, 0, 480, 490, 492, 525, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, - &meson_hdmi_encp_mode_640x480_60, - }, - /* 800x600@60Hz */ - { - { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, - 968, 1056, 0, 600, 601, 605, 628, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_800x600_60, - }, - /* 1024x768@60Hz */ - { - { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, - 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, - &meson_hdmi_encp_mode_1024x768_60, - }, - /* 1152x864@75Hz */ - { - { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, - 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_1152x864_75, - }, - /* 1280x1024@60Hz */ - { - { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, - 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_1280x1024_60, - }, - /* 1600x1200@60Hz */ - { - { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, - 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0, - DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - &meson_hdmi_encp_mode_1600x1200_60, - }, - /* 1920x1080@60Hz */ - { - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, - 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, - &meson_hdmi_encp_mode_1080p60 - }, - { }, /* sentinel */ -}; - struct meson_hdmi_venc_vic_mode { unsigned int vic; union meson_hdmi_venc_mode *mode; @@ -1044,17 +736,20 @@ static unsigned long modulo(unsigned long a, unsigned long b) return a; } -bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) +enum drm_mode_status +meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode) { - struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; + if (mode->flags & ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)) + return MODE_BAD; - while (vmode->mode) { - if (drm_mode_equal(&vmode->drm_mode, mode)) - return true; - vmode++; - } + if (mode->hdisplay < 640 || mode->hdisplay > 1920) + return MODE_BAD_HVALUE; - return false; + if (mode->vdisplay < 480 || mode->vdisplay > 1200) + return MODE_BAD_VVALUE; + + return MODE_OK; } EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode); @@ -1072,18 +767,29 @@ bool meson_venc_hdmi_supported_vic(int vic) } EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic); -static union meson_hdmi_venc_mode -*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode) +void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode, + union meson_hdmi_venc_mode *dmt_mode) { - struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes; + memset(dmt_mode, 0, sizeof(*dmt_mode)); - while (vmode->mode) { - if (drm_mode_equal(&vmode->drm_mode, mode)) - return vmode->mode; - vmode++; - } - - return NULL; + dmt_mode->encp.dvi_settings = 0x21; + dmt_mode->encp.video_mode = 0x4040; + dmt_mode->encp.video_mode_adv = 0x18; + dmt_mode->encp.max_pxcnt = mode->htotal - 1; + dmt_mode->encp.havon_begin = mode->htotal - mode->hsync_start; + dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin + + mode->hdisplay - 1; + dmt_mode->encp.vavon_bline = mode->vtotal - mode->vsync_start; + dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline + + mode->vdisplay - 1; + dmt_mode->encp.hso_begin = 0; + dmt_mode->encp.hso_end = mode->hsync_end - mode->hsync_start; + dmt_mode->encp.vso_begin = 30; + dmt_mode->encp.vso_end = 50; + dmt_mode->encp.vso_bline = 0; + dmt_mode->encp.vso_eline = mode->vsync_end - mode->vsync_start; + dmt_mode->encp.vso_eline_present = true; + dmt_mode->encp.max_lncnt = mode->vtotal - 1; } static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic) @@ -1120,6 +826,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, struct drm_display_mode *mode) { union meson_hdmi_venc_mode *vmode = NULL; + union meson_hdmi_venc_mode vmode_dmt; bool use_enci = false; bool venc_repeat = false; bool hdmi_repeat = false; @@ -1147,14 +854,17 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int sof_lines; unsigned int vsync_lines; - if (meson_venc_hdmi_supported_vic(vic)) + if (meson_venc_hdmi_supported_vic(vic)) { vmode = meson_venc_hdmi_get_vic_vmode(vic); - else - vmode = meson_venc_hdmi_get_dmt_vmode(mode); - if (!vmode) { - dev_err(priv->dev, "%s: Fatal Error, unsupported mode " - DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode)); - return; + if (!vmode) { + dev_err(priv->dev, "%s: Fatal Error, unsupported mode " + DRM_MODE_FMT "\n", __func__, + DRM_MODE_ARG(mode)); + return; + } + } else { + meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt); + vmode = &vmode_dmt; } /* Use VENCI for 480i and 576i and double HDMI pixels */ diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h index 7c18a36a0dd0..97eaebbfa0c4 100644 --- a/drivers/gpu/drm/meson/meson_venc.h +++ b/drivers/gpu/drm/meson/meson_venc.h @@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode { }; /* HDMI Clock parameters */ -bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); +enum drm_mode_status +meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); bool meson_venc_hdmi_supported_vic(int vic); bool meson_venc_hdmi_venc_repeat(int vic); diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 79d95ca8a0c0..f7945bae3b4a 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -282,7 +282,7 @@ int meson_venc_cvbs_create(struct meson_drm *priv) encoder->possible_crtcs = BIT(0); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 8918539a19aa..acf7bfe68454 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1553,7 +1553,7 @@ static int mga_vga_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, &mga_connector->i2c->adapter); if (edid) { - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } @@ -1747,7 +1747,7 @@ int mgag200_modeset_init(struct mga_device *mdev) return -1; } - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); ret = mgag200_fbdev_init(mdev); if (ret) { diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c index 32fba5664b0e..5368e621999c 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c @@ -132,7 +132,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return connector; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 4beba3f7d067..d5006d6923e0 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -393,7 +393,7 @@ static int dsi_mgr_connector_get_modes(struct drm_connector *connector) ret = dsi_dual_connector_tile_init(connector, id); if (ret) return ret; - ret = drm_mode_connector_set_tile_property(connector); + ret = drm_connector_set_tile_property(connector); if (ret) { pr_err("%s: set tile property failed, %d\n", __func__, ret); @@ -684,7 +684,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_mode_connector_attach_encoder(connector, msm_dsi->encoder); + drm_connector_attach_encoder(connector, msm_dsi->encoder); return connector; } diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c index 6f3fc6b0f0a3..058ff92a0207 100644 --- a/drivers/gpu/drm/msm/edp/edp_connector.c +++ b/drivers/gpu/drm/msm/edp/edp_connector.c @@ -56,7 +56,7 @@ static int edp_connector_get_modes(struct drm_connector *connector) if (ret) return ret; - drm_mode_connector_update_edid_property(connector, drm_edid); + drm_connector_update_edid_property(connector, drm_edid); if (drm_edid) ret = drm_add_edid_modes(connector, drm_edid); @@ -134,7 +134,7 @@ struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_mode_connector_attach_encoder(connector, edp->encoder); + drm_connector_attach_encoder(connector, edp->encoder); return connector; } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index c0848dfedd50..e9c9a0af508e 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -392,7 +392,7 @@ static int msm_hdmi_connector_get_modes(struct drm_connector *connector) hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { ret = drm_add_edid_modes(connector, edid); @@ -477,7 +477,7 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) return ERR_PTR(ret); } - drm_mode_connector_attach_encoder(connector, hdmi->encoder); + drm_connector_attach_encoder(connector, hdmi->encoder); return connector; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index 4feab0a5419d..e7af95d37ddb 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -556,6 +556,6 @@ nv04_dac_create(struct drm_connector *connector, struct dcb_output *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 9805d2cdc1a1..73d41abbb510 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -716,6 +716,6 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_output *entry) entry->location != DCB_LOC_ON_CHIP) nv04_tmds_slave_init(encoder); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index 01664357d3e1..de4490b4ed30 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -244,7 +244,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) /* Attach it to the specified connector. */ get_slave_funcs(encoder)->create_resources(encoder, connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 6d99f11fee4e..6a4ca139cf5d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -821,6 +821,6 @@ nv17_tv_create(struct drm_connector *connector, struct dcb_output *entry) encoder->possible_clones = 0; nv17_tv_create_resources(encoder, connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 4a372f805eb9..0190377b02a6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -449,7 +449,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) "dac-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_dac_help); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } @@ -875,7 +875,7 @@ nv50_mstc_get_modes(struct drm_connector *connector) int ret = 0; mstc->edid = drm_dp_mst_get_edid(&mstc->connector, mstc->port->mgr, mstc->port); - drm_mode_connector_update_edid_property(&mstc->connector, mstc->edid); + drm_connector_update_edid_property(&mstc->connector, mstc->edid); if (mstc->edid) ret = drm_add_edid_modes(&mstc->connector, mstc->edid); @@ -952,11 +952,11 @@ nv50_mstc_new(struct nv50_mstm *mstm, struct drm_dp_mst_port *port, nouveau_conn_attach_properties(&mstc->connector); for (i = 0; i < ARRAY_SIZE(mstm->msto) && mstm->msto[i]; i++) - drm_mode_connector_attach_encoder(&mstc->connector, &mstm->msto[i]->encoder); + drm_connector_attach_encoder(&mstc->connector, &mstm->msto[i]->encoder); drm_object_attach_property(&mstc->connector.base, dev->mode_config.path_property, 0); drm_object_attach_property(&mstc->connector.base, dev->mode_config.tile_property, 0); - drm_mode_connector_set_path_property(&mstc->connector, path); + drm_connector_set_path_property(&mstc->connector, path); return 0; } @@ -1443,7 +1443,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) "sor-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_sor_help); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (dcbe->type == DCB_OUTPUT_DP) { struct nv50_disp *disp = nv50_disp(encoder->dev); @@ -1601,7 +1601,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) "pior-%04x-%04x", dcbe->hasht, dcbe->hashm); drm_encoder_helper_add(encoder, &nv50_pior_help); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index bb46c1d489cf..22a15478d23d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -550,7 +550,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) /* Cleanup the previous EDID block. */ if (nv_connector->edid) { - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); kfree(nv_connector->edid); nv_connector->edid = NULL; } @@ -575,7 +575,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) else nv_connector->edid = drm_get_edid(connector, i2c); - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { NV_ERROR(drm, "DDC responded, but no EDID for %s\n", @@ -657,7 +657,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) /* Cleanup the previous EDID block. */ if (nv_connector->edid) { - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); kfree(nv_connector->edid); nv_connector->edid = NULL; } @@ -721,7 +721,7 @@ out: status = connector_status_unknown; #endif - drm_mode_connector_update_edid_property(connector, nv_connector->edid); + drm_connector_update_edid_property(connector, nv_connector->edid); nouveau_connector_set_encoder(connector, nv_encoder); return status; } diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 5cde26ac937b..2ddb856666c4 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -126,14 +126,14 @@ static int omap_connector_get_modes(struct drm_connector *connector) if ((dssdrv->read_edid(dssdev, edid, MAX_EDID) > 0) && drm_edid_is_valid(edid)) { - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( connector, edid); n = drm_add_edid_modes(connector, edid); omap_connector->hdmi_mode = drm_detect_hdmi_monitor(edid); } else { - drm_mode_connector_update_edid_property( + drm_connector_update_edid_property( connector, NULL); } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 5005ecc284d2..1b6601e9b107 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -274,7 +274,7 @@ static int omap_modeset_init(struct drm_device *dev) if (IS_ERR(crtc)) return PTR_ERR(crtc); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << crtc_idx); priv->crtcs[priv->num_crtcs++] = crtc; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 86fec03dd260..5b5d0a24e713 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -252,7 +252,7 @@ static int panel_simple_get_modes(struct drm_panel *panel) /* probe EDID if a DDC bus is available */ if (p->ddc) { struct edid *edid = drm_get_edid(panel->connector, p->ddc); - drm_mode_connector_update_edid_property(panel->connector, edid); + drm_connector_update_edid_property(panel->connector, edid); if (edid) { num += drm_add_edid_modes(panel->connector, edid); kfree(edid); diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index a432eb7ad445..754f6b25f265 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -63,7 +63,7 @@ pl111_mode_valid(struct drm_crtc *crtc, * We use the pixelclock to also account for interlaced modes, the * resulting bandwidth is in bytes per second. */ - bw = mode->clock * 1000; /* In Hz */ + bw = mode->clock * 1000ULL; /* In Hz */ bw = bw * mode->hdisplay * mode->vdisplay * cpp; bw = div_u64(bw, mode->htotal * mode->vtotal); diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index 17a38e85ba7d..47fe30223444 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -304,13 +304,14 @@ static int pl111_amba_probe(struct amba_device *amba_dev, if (IS_ERR(priv->regs)) { dev_err(dev, "%s failed mmio\n", __func__); ret = PTR_ERR(priv->regs); - goto dev_unref; + goto dev_put; } /* This may override some variant settings */ ret = pl111_versatile_init(dev, priv); if (ret) - goto dev_unref; + goto dev_put; + pl111_nomadik_init(dev); /* turn off interrupts before requesting the irq */ @@ -325,16 +326,16 @@ static int pl111_amba_probe(struct amba_device *amba_dev, ret = pl111_modeset_init(drm); if (ret != 0) - goto dev_unref; + goto dev_put; ret = drm_dev_register(drm, 0); if (ret < 0) - goto dev_unref; + goto dev_put; return 0; -dev_unref: - drm_dev_unref(drm); +dev_put: + drm_dev_put(drm); of_reserved_mem_device_release(dev); return ret; @@ -351,7 +352,7 @@ static int pl111_amba_remove(struct amba_device *amba_dev) if (priv->panel) drm_panel_bridge_remove(priv->bridge); drm_mode_config_cleanup(drm); - drm_dev_unref(drm); + drm_dev_put(drm); of_reserved_mem_device_release(dev); return 0; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 768207fbbae3..0570c6826bff 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -1086,7 +1086,7 @@ static int qdev_output_init(struct drm_device *dev, int num_output) /* we get HPD via client monitors config */ connector->polled = DRM_CONNECTOR_POLL_HPD; encoder->possible_crtcs = 1 << num_output; - drm_mode_connector_attach_encoder(&qxl_output->base, + drm_connector_attach_encoder(&qxl_output->base, &qxl_output->enc); drm_encoder_helper_add(encoder, &qxl_enc_helper_funcs); drm_connector_helper_add(connector, &qxl_connector_helper_funcs); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 0655698f2956..414642e5b7a3 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -368,11 +368,11 @@ static int radeon_ddc_get_modes(struct drm_connector *connector) int ret; if (radeon_connector->edid) { - drm_mode_connector_update_edid_property(connector, radeon_connector->edid); + drm_connector_update_edid_property(connector, radeon_connector->edid); ret = drm_add_edid_modes(connector, radeon_connector->edid); return ret; } - drm_mode_connector_update_edid_property(connector, NULL); + drm_connector_update_edid_property(connector, NULL); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index cd8a3ee16649..f920be236cc9 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -195,11 +195,11 @@ static int radeon_dp_mst_get_ddc_modes(struct drm_connector *connector) radeon_connector->edid = edid; DRM_DEBUG_KMS("edid retrieved %p\n", edid); if (radeon_connector->edid) { - drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); + drm_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); return ret; } - drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); + drm_connector_update_edid_property(&radeon_connector->base, NULL); return ret; } @@ -290,7 +290,7 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); - drm_mode_connector_set_path_property(connector, pathprop); + drm_connector_set_path_property(connector, pathprop); return connector; } diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index c6ee80216cf4..c341fb2a5b56 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -211,7 +211,7 @@ radeon_link_encoder_connector(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->devices & radeon_connector->devices) { - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) radeon_encoder_add_backlight(radeon_encoder, connector); } diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 5d8e391e75f4..4c39de3f4f0f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -353,7 +353,7 @@ static int rcar_lvds_attach(struct drm_bridge *bridge) drm_connector_helper_add(connector, &rcar_lvds_conn_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index c6fbdcd87c16..8ad0d773dc33 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -275,7 +275,7 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector) dp->sink_has_audio = drm_detect_monitor_audio(edid); ret = drm_add_edid_modes(connector, edid); if (ret) - drm_mode_connector_update_edid_property(connector, + drm_connector_update_edid_property(connector, edid); } mutex_unlock(&dp->lock); @@ -1062,7 +1062,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_ERROR("failed to attach connector and encoder\n"); goto err_free_connector; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 01642aaf6127..662b6cb5d3f0 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -1129,7 +1129,7 @@ static int dw_mipi_dsi_register(struct drm_device *drm, &dw_mipi_dsi_atomic_connector_funcs, DRM_MODE_CONNECTOR_DSI); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 88d0774c97bd..1c02b3e61299 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -565,7 +565,7 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector) if (edid) { hdmi->hdmi_data.sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); } @@ -634,7 +634,7 @@ static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) drm_connector_init(drm, &hdmi->connector, &inno_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); - drm_mode_connector_attach_encoder(&hdmi->connector, encoder); + drm_connector_attach_encoder(&hdmi->connector, encoder); return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index effecbed2d11..1359e5c773e4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -243,18 +243,6 @@ static enum vop_data_format vop_convert_format(uint32_t format) } } -static bool is_yuv_support(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_NV12: - case DRM_FORMAT_NV16: - case DRM_FORMAT_NV24: - return true; - default: - return false; - } -} - static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, uint32_t dst, bool is_horizontal, int vsu_mode, int *vskiplines) @@ -298,7 +286,8 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, uint16_t cbcr_ver_scl_mode = SCALE_NONE; int hsub = drm_format_horz_chroma_subsampling(pixel_format); int vsub = drm_format_vert_chroma_subsampling(pixel_format); - bool is_yuv = is_yuv_support(pixel_format); + const struct drm_format_info *info; + bool is_yuv = false; uint16_t cbcr_src_w = src_w / hsub; uint16_t cbcr_src_h = src_h / vsub; uint16_t vsu_mode; @@ -306,6 +295,11 @@ static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, uint32_t val; int vskiplines; + info = drm_format_info(pixel_format); + + if (info->is_yuv) + is_yuv = true; + if (dst_w > 3840) { DRM_DEV_ERROR(vop->dev, "Maximum dst width (3840) exceeded\n"); return; @@ -680,7 +674,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane, * Src.x1 can be odd when do clip, but yuv plane start point * need align with 2 pixel. */ - if (is_yuv_support(fb->format->format) && ((state->src.x1 >> 16) % 2)) { + if (fb->format->is_yuv && ((state->src.x1 >> 16) % 2)) { DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n"); return -EINVAL; } @@ -767,7 +761,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane, VOP_WIN_SET(vop, win, format, format); VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); - if (is_yuv_support(fb->format->format)) { + if (fb->format->is_yuv) { int hsub = drm_format_horz_chroma_subsampling(fb->format->format); int vsub = drm_format_vert_chroma_subsampling(fb->format->format); int bpp = fb->format->cpp[1]; diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index b3f6f524b402..456bd9f13bae 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -434,7 +434,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, drm_connector_helper_add(connector, &rockchip_lvds_connector_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) { DRM_DEV_ERROR(drm_dev->dev, "failed to attach encoder: %d\n", ret); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 40df8887fc17..fc66167b0641 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -675,7 +675,7 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev, if (ret < 0) goto err_cleanup; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret < 0) goto err_backlight; diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 90c46b49c931..832fc43960ee 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -224,7 +224,7 @@ static int sti_bind(struct device *dev) ret = sti_init(ddev); if (ret) - goto err_drm_dev_unref; + goto err_drm_dev_put; ret = component_bind_all(ddev->dev, ddev); if (ret) @@ -248,8 +248,8 @@ err_register: drm_mode_config_cleanup(ddev); err_cleanup: sti_cleanup(ddev); -err_drm_dev_unref: - drm_dev_unref(ddev); +err_drm_dev_put: + drm_dev_put(ddev); return ret; } @@ -259,7 +259,7 @@ static void sti_unbind(struct device *dev) drm_dev_unregister(ddev); sti_cleanup(ddev); - drm_dev_unref(ddev); + drm_dev_put(ddev); } static const struct component_master_ops sti_ops = { diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 030da55a8d30..b08376b7611b 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -486,7 +486,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_dvo_connector_helper_funcs); - err = drm_mode_connector_attach_encoder(drm_connector, encoder); + err = drm_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 67bbdb49fffc..49438337f70d 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -709,7 +709,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_hda_connector_helper_funcs); - err = drm_mode_connector_attach_encoder(drm_connector, encoder); + err = drm_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 58f431102512..34cdc4644435 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -977,7 +977,7 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid); count = drm_add_edid_modes(connector, edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); kfree(edid); return count; @@ -1290,7 +1290,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) hdmi->drm_connector = drm_connector; - err = drm_mode_connector_attach_encoder(drm_connector, encoder); + err = drm_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 8698e08313e1..f2021b23554d 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -148,16 +148,16 @@ static int stm_drm_platform_probe(struct platform_device *pdev) ret = drv_load(ddev); if (ret) - goto err_unref; + goto err_put; ret = drm_dev_register(ddev, 0); if (ret) - goto err_unref; + goto err_put; return 0; -err_unref: - drm_dev_unref(ddev); +err_put: + drm_dev_put(ddev); return ret; } @@ -170,7 +170,7 @@ static int stm_drm_platform_remove(struct platform_device *pdev) drm_dev_unregister(ddev); drv_unload(ddev); - drm_dev_unref(ddev); + drm_dev_put(ddev); return 0; } diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index 156a865c3e6d..c2c042287c19 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -68,4 +68,11 @@ config DRM_SUN8I_MIXER graphics mixture and feed graphics to TCON, If M is selected the module will be called sun8i-mixer. +config DRM_SUN8I_TCON_TOP + tristate + default DRM_SUN4I if DRM_SUN8I_MIXER!=n + help + TCON TOP is responsible for configuring display pipeline for + HTMI, TVE and LCD. + endif diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 14f420f1d4ae..b04ea0f3da75 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -36,4 +36,5 @@ obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o obj-$(CONFIG_DRM_SUN6I_DSI) += sun6i-dsi.o obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o -obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o sun8i_tcon_top.o +obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o +obj-$(CONFIG_DRM_SUN8I_TCON_TOP) += sun8i_tcon_top.o diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index de0a76dfa1a2..d7950b52a1fd 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -86,12 +86,6 @@ static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) } } -static inline bool sun4i_backend_format_is_yuv(uint32_t format) -{ - return sun4i_backend_format_is_planar_yuv(format) || - sun4i_backend_format_is_packed_yuv422(format); -} - static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; @@ -304,7 +298,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN, val); - if (sun4i_backend_format_is_yuv(fb->format->format)) + if (fb->format->is_yuv) return sun4i_backend_update_yuv_format(backend, layer, plane); ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val); @@ -384,7 +378,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, */ paddr -= PHYS_OFFSET; - if (sun4i_backend_format_is_yuv(fb->format->format)) + if (fb->format->is_yuv) return sun4i_backend_update_yuv_buffer(backend, fb, paddr); /* Write the 32 lower bits of the address (in bits) */ @@ -502,7 +496,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine, if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) num_alpha_planes++; - if (sun4i_backend_format_is_yuv(fb->format->format)) { + if (fb->format->is_yuv) { DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); num_yuv_planes++; } diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index a15feb807393..dd19d674055c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -144,7 +144,7 @@ cleanup_mode_config: drm_mode_config_cleanup(drm); of_reserved_mem_device_release(dev); free_drm: - drm_dev_unref(drm); + drm_dev_put(drm); return ret; } @@ -157,7 +157,7 @@ static void sun4i_drv_unbind(struct device *dev) sun4i_framebuffer_free(drm); drm_mode_config_cleanup(drm); of_reserved_mem_device_release(dev); - drm_dev_unref(drm); + drm_dev_put(drm); } static const struct component_master_ops sun4i_drv_master_ops = { @@ -216,7 +216,8 @@ static bool sun4i_drv_node_is_tcon_with_ch0(struct device_node *node) static bool sun4i_drv_node_is_tcon_top(struct device_node *node) { - return !!of_match_node(sun8i_tcon_top_of_table, node); + return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) && + !!of_match_node(sun8i_tcon_top_of_table, node); } static int compare_of(struct device *dev, void *data) diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index fa4bcd092eaf..061d2e0d9011 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -220,7 +220,7 @@ static int sun4i_hdmi_get_modes(struct drm_connector *connector) DRM_DEBUG_DRIVER("Monitor is %s monitor\n", hdmi->hdmi_monitor ? "an HDMI" : "a DVI"); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); cec_s_phys_addr_from_edid(hdmi->cec_adap, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); @@ -623,7 +623,7 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master, ret = cec_register_adapter(hdmi->cec_adap, dev); if (ret < 0) goto err_cleanup_connector; - drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); + drm_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); return 0; diff --git a/drivers/gpu/drm/sun4i/sun4i_lvds.c b/drivers/gpu/drm/sun4i/sun4i_lvds.c index a69fe2e1f9d1..af7dcb6da351 100644 --- a/drivers/gpu/drm/sun4i/sun4i_lvds.c +++ b/drivers/gpu/drm/sun4i/sun4i_lvds.c @@ -149,7 +149,7 @@ int sun4i_lvds_init(struct drm_device *drm, struct sun4i_tcon *tcon) goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&lvds->connector, + drm_connector_attach_encoder(&lvds->connector, &lvds->encoder); ret = drm_panel_attach(tcon->panel, &lvds->connector); diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 96d21b07f8fc..bf068da6b12e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -215,7 +215,7 @@ int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon) goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&rgb->connector, + drm_connector_attach_encoder(&rgb->connector, &rgb->encoder); ret = drm_panel_attach(tcon->panel, &rgb->connector); diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index b070d522ed8d..1a838d208211 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -623,7 +623,7 @@ static int sun4i_tv_bind(struct device *dev, struct device *master, } tv->connector.interlace_allowed = true; - drm_mode_connector_attach_encoder(&tv->connector, &tv->encoder); + drm_connector_attach_encoder(&tv->connector, &tv->encoder); return 0; diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c index 2b40d1f6aee8..e3b34a345546 100644 --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c @@ -941,7 +941,7 @@ static int sun6i_dsi_bind(struct device *dev, struct device *master, goto err_cleanup_connector; } - drm_mode_connector_attach_encoder(&dsi->connector, &dsi->encoder); + drm_connector_attach_encoder(&dsi->connector, &dsi->encoder); drm_panel_attach(dsi->panel, &dsi->connector); return 0; diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 21dc9ebad0b4..31875b636434 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -44,7 +44,8 @@ sun8i_dw_hdmi_mode_valid(struct drm_connector *connector, static bool sun8i_dw_hdmi_node_is_tcon_top(struct device_node *node) { - return !!of_match_node(sun8i_tcon_top_of_table, node); + return IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) && + !!of_match_node(sun8i_tcon_top_of_table, node); } static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm, @@ -220,7 +221,7 @@ static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids); -struct platform_driver sun8i_dw_hdmi_pltfm_driver = { +static struct platform_driver sun8i_dw_hdmi_pltfm_driver = { .probe = sun8i_dw_hdmi_probe, .remove = sun8i_dw_hdmi_remove, .driver = { diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c index aa81b9838ae8..fc3713608f78 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "sun4i_drv.h" @@ -322,6 +323,42 @@ static struct regmap_config sun8i_mixer_regmap_config = { .max_register = 0xbfffc, /* guessed */ }; +static int sun8i_mixer_of_get_id(struct device_node *node) +{ + struct device_node *port, *ep; + int ret = -EINVAL; + + /* output is port 1 */ + port = of_graph_get_port_by_id(node, 1); + if (!port) + return -EINVAL; + + /* try to find downstream endpoint */ + for_each_available_child_of_node(port, ep) { + struct device_node *remote; + u32 reg; + + remote = of_graph_get_remote_endpoint(ep); + if (!remote) + continue; + + ret = of_property_read_u32(remote, "reg", ®); + if (!ret) { + of_node_put(remote); + of_node_put(ep); + of_node_put(port); + + return reg; + } + + of_node_put(remote); + } + + of_node_put(port); + + return ret; +} + static int sun8i_mixer_bind(struct device *dev, struct device *master, void *data) { @@ -353,8 +390,16 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, dev_set_drvdata(dev, mixer); mixer->engine.ops = &sun8i_engine_ops; mixer->engine.node = dev->of_node; - /* The ID of the mixer currently doesn't matter */ - mixer->engine.id = -1; + + /* + * While this function can fail, we shouldn't do anything + * if this happens. Some early DE2 DT entries don't provide + * mixer id but work nevertheless because matching between + * TCON and mixer is done by comparing node pointers (old + * way) instead comparing ids. If this function fails and + * id is needed, it will fail during id matching anyway. + */ + mixer->engine.id = sun8i_mixer_of_get_id(dev->of_node); mixer->cfg = of_device_get_match_data(dev); if (!mixer->cfg) @@ -432,14 +477,14 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master, regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(0), SUN8I_MIXER_BLEND_COLOR_BLACK); - /* Fixed zpos for now */ - regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE, 0x43210); - plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num; for (i = 0; i < plane_cnt; i++) regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(i), SUN8I_MIXER_BLEND_MODE_DEF); + regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0); + return 0; err_disable_bus_clk: diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h index f34e70c42adf..406c42e752d7 100644 --- a/drivers/gpu/drm/sun4i/sun8i_mixer.h +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h @@ -44,6 +44,7 @@ #define SUN8I_MIXER_BLEND_CK_MIN(x) (0x10e0 + 0x04 * (x)) #define SUN8I_MIXER_BLEND_OUTCTL 0x10fc +#define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8) #define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe) #define SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(pipe) BIT(pipe) /* colors are always in AARRGGBB format */ @@ -51,6 +52,9 @@ /* The following numbers are some still unknown magic numbers */ #define SUN8I_MIXER_BLEND_MODE_DEF 0x03010301 +#define SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(n) (0xf << ((n) << 2)) +#define SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(n) ((n) << 2) + #define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED BIT(1) #define SUN8I_MIXER_FBFMT_ARGB8888 0 diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c index 046f8dd66f90..55fe398d8290 100644 --- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c @@ -99,7 +99,7 @@ static struct clk_hw *sun8i_tcon_top_register_gate(struct device *dev, index = of_property_match_string(dev->of_node, "clock-names", parent); if (index < 0) - return index; + return ERR_PTR(index); parent_name = of_clk_get_parent_name(dev->of_node, index); diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c index 9a540330cb79..28c15c6ef1ef 100644 --- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c @@ -27,7 +27,8 @@ #include "sun8i_ui_scaler.h" static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable) + int overlay, bool enable, unsigned int zpos, + unsigned int old_zpos) { u32 val; @@ -43,18 +44,36 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val); - if (enable) - val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel); - else - val = 0; + if (!enable || zpos != old_zpos) { + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), + 0); - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_PIPE_CTL, - SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val); + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), + 0); + } + + if (enable) { + val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, val, val); + + val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), + val); + } } static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) + int overlay, struct drm_plane *plane, + unsigned int zpos) { struct drm_plane_state *state = plane->state; u32 src_w, src_h, dst_w, dst_h; @@ -137,10 +156,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel, state->dst.x1, state->dst.y1); DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_COORD(channel), + SUN8I_MIXER_BLEND_ATTR_COORD(zpos), SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_INSIZE(channel), + SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), outsize); return 0; @@ -236,30 +255,35 @@ static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false); + sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0, + old_zpos); } static void sun8i_ui_layer_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane); + unsigned int zpos = plane->state->normalized_zpos; + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; if (!plane->state->visible) { sun8i_ui_layer_enable(mixer, layer->channel, - layer->overlay, false); + layer->overlay, false, 0, old_zpos); return; } sun8i_ui_layer_update_coord(mixer, layer->channel, - layer->overlay, plane); + layer->overlay, plane, zpos); sun8i_ui_layer_update_formats(mixer, layer->channel, layer->overlay, plane); sun8i_ui_layer_update_buffer(mixer, layer->channel, layer->overlay, plane); - sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, true); + sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, + true, zpos, old_zpos); } static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = { @@ -307,6 +331,7 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY; int channel = mixer->cfg->vi_num + index; struct sun8i_ui_layer *layer; + unsigned int plane_cnt; int ret; layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); @@ -327,8 +352,10 @@ struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm, return ERR_PTR(ret); } - /* fixed zpos for now */ - ret = drm_plane_create_zpos_immutable_property(&layer->plane, channel); + plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; + + ret = drm_plane_create_zpos_property(&layer->plane, channel, + 0, plane_cnt - 1); if (ret) { dev_err(drm->dev, "Couldn't add zpos property\n"); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c index 5877f8ef5895..f4fe97813f94 100644 --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c @@ -21,7 +21,8 @@ #include "sun8i_vi_scaler.h" static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, - int overlay, bool enable) + int overlay, bool enable, unsigned int zpos, + unsigned int old_zpos) { u32 val; @@ -37,18 +38,36 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel, SUN8I_MIXER_CHAN_VI_LAYER_ATTR(channel, overlay), SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val); - if (enable) - val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel); - else - val = 0; + if (!enable || zpos != old_zpos) { + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, + SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos), + 0); - regmap_update_bits(mixer->engine.regs, - SUN8I_MIXER_BLEND_PIPE_CTL, - SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val); + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos), + 0); + } + + if (enable) { + val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_PIPE_CTL, val, val); + + val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos); + + regmap_update_bits(mixer->engine.regs, + SUN8I_MIXER_BLEND_ROUTE, + SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos), + val); + } } static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, - int overlay, struct drm_plane *plane) + int overlay, struct drm_plane *plane, + unsigned int zpos) { struct drm_plane_state *state = plane->state; const struct drm_format_info *format = state->fb->format; @@ -130,10 +149,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel, state->dst.x1, state->dst.y1); DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_COORD(channel), + SUN8I_MIXER_BLEND_ATTR_COORD(zpos), SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1)); regmap_write(mixer->engine.regs, - SUN8I_MIXER_BLEND_ATTR_INSIZE(channel), + SUN8I_MIXER_BLEND_ATTR_INSIZE(zpos), outsize); return 0; @@ -264,30 +283,35 @@ static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; - sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false); + sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0, + old_zpos); } static void sun8i_vi_layer_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane); + unsigned int zpos = plane->state->normalized_zpos; + unsigned int old_zpos = old_state->normalized_zpos; struct sun8i_mixer *mixer = layer->mixer; if (!plane->state->visible) { sun8i_vi_layer_enable(mixer, layer->channel, - layer->overlay, false); + layer->overlay, false, 0, old_zpos); return; } sun8i_vi_layer_update_coord(mixer, layer->channel, - layer->overlay, plane); + layer->overlay, plane, zpos); sun8i_vi_layer_update_formats(mixer, layer->channel, layer->overlay, plane); sun8i_vi_layer_update_buffer(mixer, layer->channel, layer->overlay, plane); - sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, true); + sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, + true, zpos, old_zpos); } static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = { @@ -351,6 +375,7 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, int index) { struct sun8i_vi_layer *layer; + unsigned int plane_cnt; int ret; layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL); @@ -368,8 +393,10 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm, return ERR_PTR(ret); } - /* fixed zpos for now */ - ret = drm_plane_create_zpos_immutable_property(&layer->plane, index); + plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num; + + ret = drm_plane_create_zpos_property(&layer->plane, index, + 0, plane_cnt - 1); if (ret) { dev_err(drm->dev, "Couldn't add zpos property\n"); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index ad88ec230329..ee6ca8fa1c65 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1052,7 +1052,7 @@ static int tegra_dsi_init(struct host1x_client *client) drm_encoder_helper_add(&dsi->output.encoder, &tegra_dsi_encoder_helper_funcs); - drm_mode_connector_attach_encoder(&dsi->output.connector, + drm_connector_attach_encoder(&dsi->output.connector, &dsi->output.encoder); drm_connector_register(&dsi->output.connector); diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 784739a9f497..0082468f703c 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1488,7 +1488,7 @@ static int tegra_hdmi_init(struct host1x_client *client) drm_encoder_helper_add(&hdmi->output.encoder, &tegra_hdmi_encoder_helper_funcs); - drm_mode_connector_attach_encoder(&hdmi->output.connector, + drm_connector_attach_encoder(&hdmi->output.connector, &hdmi->output.encoder); drm_connector_register(&hdmi->output.connector); diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 0c0936511bb4..c662efc7e413 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -37,7 +37,7 @@ int tegra_output_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, output->ddc); cec_notifier_set_phys_addr_from_edid(output->notifier, edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { err = drm_add_edid_modes(connector, edid); diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 78ec5193741d..28a78d3120bc 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -289,7 +289,7 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) drm_encoder_helper_add(&output->encoder, &tegra_rgb_encoder_helper_funcs); - drm_mode_connector_attach_encoder(&output->connector, + drm_connector_attach_encoder(&output->connector, &output->encoder); drm_connector_register(&output->connector); diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 7d2a955fc515..d7fe9f15def1 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -2622,7 +2622,7 @@ static int tegra_sor_init(struct host1x_client *client) encoder, NULL); drm_encoder_helper_add(&sor->output.encoder, helpers); - drm_mode_connector_attach_encoder(&sor->output.connector, + drm_connector_attach_encoder(&sor->output.connector, &sor->output.encoder); drm_connector_register(&sor->output.connector); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index d616d64a6725..a1acab39d87f 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -223,7 +223,7 @@ static struct drm_connector *panel_connector_create(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) goto fail; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index c45cabb38db0..daebf1aa6b0a 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -173,7 +173,7 @@ static int tfp410_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, tfp410_connector->mod->i2c); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); if (edid) { ret = drm_add_edid_modes(connector, edid); @@ -240,7 +240,7 @@ static struct drm_connector *tfp410_connector_create(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) goto fail; diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig index 7a8008b0783f..16f4b5c91f1b 100644 --- a/drivers/gpu/drm/tinydrm/Kconfig +++ b/drivers/gpu/drm/tinydrm/Kconfig @@ -23,6 +23,7 @@ config TINYDRM_ILI9225 config TINYDRM_ILI9341 tristate "DRM support for ILI9341 display panels" depends on DRM_TINYDRM && SPI + depends on BACKLIGHT_CLASS_DEVICE select TINYDRM_MIPI_DBI help DRM driver for the following Ilitek ILI9341 panels: diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c index 09dc585aa46f..68e88bed77ca 100644 --- a/drivers/gpu/drm/udl/udl_connector.c +++ b/drivers/gpu/drm/udl/udl_connector.c @@ -99,7 +99,7 @@ static int udl_get_modes(struct drm_connector *connector) struct udl_drm_connector, connector); - drm_mode_connector_update_edid_property(connector, udl_connector->edid); + drm_connector_update_edid_property(connector, udl_connector->edid); if (udl_connector->edid) return drm_add_edid_modes(connector, udl_connector->edid); return 0; @@ -200,7 +200,7 @@ int udl_connector_init(struct drm_device *dev, struct drm_encoder *encoder) drm_connector_helper_add(connector, &udl_connector_helper_funcs); drm_connector_register(connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); connector->polled = DRM_CONNECTOR_POLL_HPD | DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index e42fd5ec41cc..04270a14fcaa 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -288,7 +288,7 @@ static int vc4_drm_bind(struct device *dev) ret = vc4_bo_cache_init(drm); if (ret) - goto dev_unref; + goto dev_put; drm_mode_config_init(drm); @@ -313,8 +313,8 @@ unbind_all: gem_destroy: vc4_gem_destroy(drm); vc4_bo_cache_destroy(drm); -dev_unref: - drm_dev_unref(drm); +dev_put: + drm_dev_put(drm); return ret; } @@ -331,7 +331,7 @@ static void vc4_drm_unbind(struct device *dev) drm_atomic_private_obj_fini(&vc4->ctm_manager); - drm_dev_unref(drm); + drm_dev_put(drm); } static const struct component_master_ops vc4_drm_ops = { diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b8d50533e2bb..fd5522fd179e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -285,7 +285,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) drm_rgb_quant_range_selectable(edid); } - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); @@ -329,7 +329,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return connector; } diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index 3a9a302247a2..8e7facb6514e 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -404,7 +404,7 @@ static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev, VC4_VEC_TV_MODE_NTSC); vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC]; - drm_mode_connector_attach_encoder(connector, vec->encoder); + drm_connector_attach_encoder(connector, vec->encoder); return connector; } diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index ff9933e79416..25503b933599 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -292,7 +292,7 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index) drm_encoder_helper_add(encoder, &virtio_gpu_enc_helper_funcs); encoder->possible_crtcs = 1 << index; - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); drm_connector_register(connector); return 0; } diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index 3f774a6a9c58..986297da51bf 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -1,3 +1,3 @@ -vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o +vkms-y := vkms_drv.o vkms_plane.o vkms_output.o vkms_crtc.o vkms_gem.o obj-$(CONFIG_DRM_VKMS) += vkms.o diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index bf76cd39ece7..875fca662ac0 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -10,6 +10,60 @@ #include #include +static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) +{ + struct vkms_output *output = container_of(timer, struct vkms_output, + vblank_hrtimer); + struct drm_crtc *crtc = &output->crtc; + int ret_overrun; + bool ret; + + ret = drm_crtc_handle_vblank(crtc); + if (!ret) + DRM_ERROR("vkms failure on handling vblank"); + + ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, + output->period_ns); + + return HRTIMER_RESTART; +} + +static int vkms_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + struct vkms_output *out = drm_crtc_to_vkms_output(crtc); + + drm_calc_timestamping_constants(crtc, &crtc->mode); + + hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + out->vblank_hrtimer.function = &vkms_vblank_simulate; + out->period_ns = ktime_set(0, vblank->framedur_ns); + hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL); + + return 0; +} + +static void vkms_disable_vblank(struct drm_crtc *crtc) +{ + struct vkms_output *out = drm_crtc_to_vkms_output(crtc); + + hrtimer_cancel(&out->vblank_hrtimer); +} + +bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, + int *max_error, ktime_t *vblank_time, + bool in_vblank_irq) +{ + struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev); + struct vkms_output *output = &vkmsdev->output; + + *vblank_time = output->vblank_hrtimer.node.expires; + + return true; +} + static const struct drm_crtc_funcs vkms_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, @@ -17,6 +71,45 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .enable_vblank = vkms_enable_vblank, + .disable_vblank = vkms_disable_vblank, +}; + +static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + drm_crtc_vblank_on(crtc); +} + +static void vkms_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + drm_crtc_vblank_off(crtc); +} + +static void vkms_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + unsigned long flags; + + if (crtc->state->event) { + spin_lock_irqsave(&crtc->dev->event_lock, flags); + + if (drm_crtc_vblank_get(crtc) != 0) + drm_crtc_send_vblank_event(crtc, crtc->state->event); + else + drm_crtc_arm_vblank_event(crtc, crtc->state->event); + + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + + crtc->state->event = NULL; + } +} + +static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { + .atomic_flush = vkms_crtc_atomic_flush, + .atomic_enable = vkms_crtc_atomic_enable, + .atomic_disable = vkms_crtc_atomic_disable, }; int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, @@ -31,5 +124,7 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, return ret; } + drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); + return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 740a4cbfed91..37aa2ef33b21 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "vkms_drv.h" #define DRIVER_NAME "vkms" @@ -17,12 +19,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -#define XRES_MIN 32 -#define YRES_MIN 32 - -#define XRES_MAX 8192 -#define YRES_MAX 8192 - static struct vkms_device *vkms_device; static const struct file_operations vkms_driver_fops = { @@ -37,6 +33,12 @@ static const struct file_operations vkms_driver_fops = { .release = drm_release, }; +static const struct vm_operations_struct vkms_gem_vm_ops = { + .fault = vkms_gem_fault, + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + static void vkms_release(struct drm_device *dev) { struct vkms_device *vkms = container_of(dev, struct vkms_device, drm); @@ -50,6 +52,11 @@ static struct drm_driver vkms_driver = { .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM, .release = vkms_release, .fops = &vkms_driver_fops, + .dumb_create = vkms_dumb_create, + .dumb_map_offset = vkms_dumb_map, + .gem_vm_ops = &vkms_gem_vm_ops, + .gem_free_object_unlocked = vkms_gem_free_object, + .get_vblank_timestamp = vkms_get_vblank_timestamp, .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -59,6 +66,7 @@ static struct drm_driver vkms_driver = { }; static const struct drm_mode_config_funcs vkms_mode_funcs = { + .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; @@ -96,6 +104,14 @@ static int __init vkms_init(void) goto out_fini; } + vkms_device->drm.irq_enabled = true; + + ret = drm_vblank_init(&vkms_device->drm, 1); + if (ret) { + DRM_ERROR("Failed to vblank\n"); + goto out_fini; + } + ret = vkms_modeset_init(vkms_device); if (ret) goto out_unregister; diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index b0f9d2e61a42..07be29f2dc44 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -3,7 +3,18 @@ #include #include +#include #include +#include + +#define XRES_MIN 32 +#define YRES_MIN 32 + +#define XRES_DEF 1024 +#define YRES_DEF 768 + +#define XRES_MAX 8192 +#define YRES_MAX 8192 static const u32 vkms_formats[] = { DRM_FORMAT_XRGB8888, @@ -13,6 +24,9 @@ struct vkms_output { struct drm_crtc crtc; struct drm_encoder encoder; struct drm_connector connector; + struct hrtimer vblank_hrtimer; + ktime_t period_ns; + struct drm_pending_vblank_event *event; }; struct vkms_device { @@ -21,11 +35,44 @@ struct vkms_device { struct vkms_output output; }; +struct vkms_gem_object { + struct drm_gem_object gem; + struct mutex pages_lock; /* Page lock used in page fault handler */ + struct page **pages; +}; + +#define drm_crtc_to_vkms_output(target) \ + container_of(target, struct vkms_output, crtc) + +#define drm_device_to_vkms_device(target) \ + container_of(target, struct vkms_device, drm) + +/* CRTC */ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, struct drm_plane *cursor); +bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, + int *max_error, ktime_t *vblank_time, + bool in_vblank_irq); + int vkms_output_init(struct vkms_device *vkmsdev); struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev); +/* Gem stuff */ +struct drm_gem_object *vkms_gem_create(struct drm_device *dev, + struct drm_file *file, + u32 *handle, + u64 size); + +int vkms_gem_fault(struct vm_fault *vmf); + +int vkms_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); + +int vkms_dumb_map(struct drm_file *file, struct drm_device *dev, + u32 handle, u64 *offset); + +void vkms_gem_free_object(struct drm_gem_object *obj); + #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_gem.c b/drivers/gpu/drm/vkms/vkms_gem.c new file mode 100644 index 000000000000..c7e38368602b --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_gem.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include "vkms_drv.h" + +static struct vkms_gem_object *__vkms_gem_create(struct drm_device *dev, + u64 size) +{ + struct vkms_gem_object *obj; + int ret; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return ERR_PTR(-ENOMEM); + + size = roundup(size, PAGE_SIZE); + ret = drm_gem_object_init(dev, &obj->gem, size); + if (ret) { + kfree(obj); + return ERR_PTR(ret); + } + + mutex_init(&obj->pages_lock); + + return obj; +} + +void vkms_gem_free_object(struct drm_gem_object *obj) +{ + struct vkms_gem_object *gem = container_of(obj, struct vkms_gem_object, + gem); + + kvfree(gem->pages); + mutex_destroy(&gem->pages_lock); + drm_gem_object_release(obj); + kfree(gem); +} + +int vkms_gem_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct vkms_gem_object *obj = vma->vm_private_data; + unsigned long vaddr = vmf->address; + pgoff_t page_offset; + loff_t num_pages; + int ret; + + page_offset = (vaddr - vma->vm_start) >> PAGE_SHIFT; + num_pages = DIV_ROUND_UP(obj->gem.size, PAGE_SIZE); + + if (page_offset > num_pages) + return VM_FAULT_SIGBUS; + + ret = -ENOENT; + mutex_lock(&obj->pages_lock); + if (obj->pages) { + get_page(obj->pages[page_offset]); + vmf->page = obj->pages[page_offset]; + ret = 0; + } + mutex_unlock(&obj->pages_lock); + if (ret) { + struct page *page; + struct address_space *mapping; + + mapping = file_inode(obj->gem.filp)->i_mapping; + page = shmem_read_mapping_page(mapping, page_offset); + + if (!IS_ERR(page)) { + vmf->page = page; + ret = 0; + } else { + switch (PTR_ERR(page)) { + case -ENOSPC: + case -ENOMEM: + ret = VM_FAULT_OOM; + break; + case -EBUSY: + ret = VM_FAULT_RETRY; + break; + case -EFAULT: + case -EINVAL: + ret = VM_FAULT_SIGBUS; + break; + default: + WARN_ON(PTR_ERR(page)); + ret = VM_FAULT_SIGBUS; + break; + } + } + } + return ret; +} + +struct drm_gem_object *vkms_gem_create(struct drm_device *dev, + struct drm_file *file, + u32 *handle, + u64 size) +{ + struct vkms_gem_object *obj; + int ret; + + if (!file || !dev || !handle) + return ERR_PTR(-EINVAL); + + obj = __vkms_gem_create(dev, size); + if (IS_ERR(obj)) + return ERR_CAST(obj); + + ret = drm_gem_handle_create(file, &obj->gem, handle); + drm_gem_object_put_unlocked(&obj->gem); + if (ret) { + drm_gem_object_release(&obj->gem); + kfree(obj); + return ERR_PTR(ret); + } + + return &obj->gem; +} + +int vkms_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct drm_gem_object *gem_obj; + u64 pitch, size; + + if (!args || !dev || !file) + return -EINVAL; + + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + size = pitch * args->height; + + if (!size) + return -EINVAL; + + gem_obj = vkms_gem_create(dev, file, &args->handle, size); + if (IS_ERR(gem_obj)) + return PTR_ERR(gem_obj); + + args->size = gem_obj->size; + args->pitch = pitch; + + DRM_DEBUG_DRIVER("Created object of size %lld\n", size); + + return 0; +} + +int vkms_dumb_map(struct drm_file *file, struct drm_device *dev, + u32 handle, u64 *offset) +{ + struct drm_gem_object *obj; + int ret; + + obj = drm_gem_object_lookup(file, handle); + if (!obj) + return -ENOENT; + + if (!obj->filp) { + ret = -EINVAL; + goto unref; + } + + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto unref; + + *offset = drm_vma_node_offset_addr(&obj->vma_node); +unref: + drm_gem_object_put_unlocked(obj); + + return ret; +} diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 48143eac3c12..901012cb1af1 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -8,6 +8,7 @@ #include "vkms_drv.h" #include +#include static void vkms_connector_destroy(struct drm_connector *connector) { @@ -18,12 +19,29 @@ static void vkms_connector_destroy(struct drm_connector *connector) static const struct drm_connector_funcs vkms_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .destroy = vkms_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_encoder_funcs vkms_encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static int vkms_conn_get_modes(struct drm_connector *connector) +{ + int count; + + count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX); + drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); + + return count; +} + +static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { + .get_modes = vkms_conn_get_modes, +}; + int vkms_output_init(struct vkms_device *vkmsdev) { struct vkms_output *output = &vkmsdev->output; @@ -49,6 +67,8 @@ int vkms_output_init(struct vkms_device *vkmsdev) goto err_connector; } + drm_connector_helper_add(connector, &vkms_conn_helper_funcs); + ret = drm_connector_register(connector); if (ret) { DRM_ERROR("Failed to register connector\n"); @@ -63,7 +83,7 @@ int vkms_output_init(struct vkms_device *vkmsdev) } encoder->possible_crtcs = 1; - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_ERROR("Failed to attach connector to encoder\n"); goto err_attach; diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index 2c25b1d6ab5b..9f75b1e2c1c4 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -19,6 +19,15 @@ static const struct drm_plane_funcs vkms_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; +static void vkms_primary_plane_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ +} + +static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = { + .atomic_update = vkms_primary_plane_update, +}; + struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev) { struct drm_device *dev = &vkmsdev->drm; @@ -42,5 +51,7 @@ struct drm_plane *vkms_plane_init(struct vkms_device *vkmsdev) return ERR_PTR(ret); } + drm_plane_helper_add(plane, &vkms_primary_helper_funcs); + return plane; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 466336b34fff..23beff5d8e3c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -2268,7 +2268,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, drm_mode_probed_add(connector, mode); } - drm_mode_connector_list_update(connector); + drm_connector_list_update(connector); /* Move the prefered mode first, help apps pick the right mode. */ drm_mode_sort(&connector->modes); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 030d49c243e1..723578117191 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -438,7 +438,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_connector; } - (void) drm_mode_connector_attach_encoder(connector, encoder); + (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 4eea456b9d4e..ad0de7f0cd60 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -703,7 +703,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_connector; } - (void) drm_mode_connector_attach_encoder(connector, encoder); + (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 8d13628e8a86..93f6b96ca7bb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1498,7 +1498,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) goto err_free_connector; } - (void) drm_mode_connector_attach_encoder(connector, encoder); + (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index 13ea90f7a185..78655269d843 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -272,7 +272,7 @@ static int zx_hdmi_connector_get_modes(struct drm_connector *connector) hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid); hdmi->sink_has_audio = drm_detect_monitor_audio(edid); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); @@ -326,7 +326,7 @@ static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi) drm_connector_helper_add(&hdmi->connector, &zx_hdmi_connector_helper_funcs); - drm_mode_connector_attach_encoder(&hdmi->connector, encoder); + drm_connector_attach_encoder(&hdmi->connector, encoder); return 0; } diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c index 0de1a71ca4e0..b73afb212fb2 100644 --- a/drivers/gpu/drm/zte/zx_tvenc.c +++ b/drivers/gpu/drm/zte/zx_tvenc.c @@ -297,7 +297,7 @@ static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc) DRM_MODE_CONNECTOR_Composite); drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/zte/zx_vga.c b/drivers/gpu/drm/zte/zx_vga.c index 3e7e33cd3dfa..23d1ff4355a0 100644 --- a/drivers/gpu/drm/zte/zx_vga.c +++ b/drivers/gpu/drm/zte/zx_vga.c @@ -109,7 +109,7 @@ static int zx_vga_connector_get_modes(struct drm_connector *connector) */ zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, VGA_DETECT_SEL_HAS_DEVICE); - drm_mode_connector_update_edid_property(connector, edid); + drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); @@ -175,7 +175,7 @@ static int zx_vga_register(struct drm_device *drm, struct zx_vga *vga) drm_connector_helper_add(connector, &zx_vga_connector_helper_funcs); - ret = drm_mode_connector_attach_encoder(connector, encoder); + ret = drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_DEV_ERROR(dev, "failed to attach encoder: %d\n", ret); goto clean_connector; diff --git a/drivers/staging/vboxvideo/vbox_mode.c b/drivers/staging/vboxvideo/vbox_mode.c index 5c7ea237893e..da4a93df8d75 100644 --- a/drivers/staging/vboxvideo/vbox_mode.c +++ b/drivers/staging/vboxvideo/vbox_mode.c @@ -504,7 +504,7 @@ static void vbox_set_edid(struct drm_connector *connector, int width, for (i = 0; i < EDID_SIZE - 1; ++i) sum += edid[i]; edid[EDID_SIZE - 1] = (0x100 - (sum & 0xFF)) & 0xFF; - drm_mode_connector_update_edid_property(connector, (struct edid *)edid); + drm_connector_update_edid_property(connector, (struct edid *)edid); } static int vbox_get_modes(struct drm_connector *connector) @@ -655,7 +655,7 @@ static int vbox_connector_init(struct drm_device *dev, dev->mode_config.suggested_y_property, 0); drm_connector_register(connector); - drm_mode_connector_attach_encoder(connector, encoder); + drm_connector_attach_encoder(connector, encoder); return 0; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index c5dfbdb7271d..f7a19c2a7a80 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -102,25 +102,6 @@ struct pci_controller; #define DRM_SWITCH_POWER_CHANGING 2 #define DRM_SWITCH_POWER_DYNAMIC_OFF 3 -static inline bool drm_core_check_feature(struct drm_device *dev, int feature) -{ - return dev->driver->driver_features & feature; -} - -/** - * drm_drv_uses_atomic_modeset - check if the driver implements - * atomic_commit() - * @dev: DRM device - * - * This check is useful if drivers do not have DRIVER_ATOMIC set but - * have atomic modesetting internally implemented. - */ -static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) -{ - return drm_core_check_feature(dev, DRIVER_ATOMIC) || - dev->mode_config.funcs->atomic_commit != NULL; -} - /* returns true if currently okay to sleep */ static inline bool drm_can_sleep(void) { diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index a5179eb9e56f..97ea41dc678f 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -378,12 +378,9 @@ struct drm_tv_connector_state { /** * struct drm_connector_state - mutable connector state - * @connector: backpointer to the connector - * @best_encoder: can be used by helpers and drivers to select the encoder - * @state: backpointer to global drm_atomic_state - * @tv: TV connector state */ struct drm_connector_state { + /** @connector: backpointer to the connector */ struct drm_connector *connector; /** @@ -394,6 +391,13 @@ struct drm_connector_state { */ struct drm_crtc *crtc; + /** + * @best_encoder: + * + * Used by the atomic helpers to select the encoder, through the + * &drm_connector_helper_funcs.atomic_best_encoder or + * &drm_connector_helper_funcs.best_encoder callbacks. + */ struct drm_encoder *best_encoder; /** @@ -402,6 +406,7 @@ struct drm_connector_state { */ enum drm_link_status link_status; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; /** @@ -411,6 +416,7 @@ struct drm_connector_state { */ struct drm_crtc_commit *commit; + /** @tv: TV connector state */ struct drm_tv_connector_state tv; /** @@ -555,8 +561,7 @@ struct drm_connector_funcs { * received for this output connector->edid must be NULL. * * Drivers using the probe helpers should use - * drm_helper_probe_single_connector_modes() or - * drm_helper_probe_single_connector_modes_nomerge() to implement this + * drm_helper_probe_single_connector_modes() to implement this * function. * * RETURNS: @@ -767,45 +772,6 @@ struct drm_cmdline_mode { /** * struct drm_connector - central DRM connector control structure - * @dev: parent DRM device - * @kdev: kernel device for sysfs attributes - * @attr: sysfs attributes - * @head: list management - * @base: base KMS object - * @name: human readable name, can be overwritten by the driver - * @connector_type: one of the DRM_MODE_CONNECTOR_ types from drm_mode.h - * @connector_type_id: index into connector type enum - * @interlace_allowed: can this connector handle interlaced modes? - * @doublescan_allowed: can this connector handle doublescan? - * @stereo_allowed: can this connector handle stereo modes? - * @funcs: connector control functions - * @edid_blob_ptr: DRM property containing EDID if present - * @properties: property tracking for this connector - * @dpms: current dpms state - * @helper_private: mid-layer private data - * @cmdline_mode: mode line parsed from the kernel cmdline for this connector - * @force: a DRM_FORCE_ state for forced mode sets - * @override_edid: has the EDID been overwritten through debugfs for testing? - * @encoder_ids: valid encoders for this connector - * @eld: EDID-like data, if present - * @latency_present: AV delay info from ELD, if found - * @video_latency: video latency info from ELD, if found - * @audio_latency: audio latency info from ELD, if found - * @null_edid_counter: track sinks that give us all zeros for the EDID - * @bad_edid_counter: track sinks that give us an EDID with invalid checksum - * @edid_corrupt: indicates whether the last read EDID was corrupt - * @debugfs_entry: debugfs directory for this connector - * @has_tile: is this connector connected to a tiled monitor - * @tile_group: tile group for the connected monitor - * @tile_is_single_monitor: whether the tile is one monitor housing - * @num_h_tile: number of horizontal tiles in the tile group - * @num_v_tile: number of vertical tiles in the tile group - * @tile_h_loc: horizontal location of this tile - * @tile_v_loc: vertical location of this tile - * @tile_h_size: horizontal size of this tile. - * @tile_v_size: vertical size of this tile. - * @scaling_mode_property: Optional atomic property to control the upscaling. - * @content_protection_property: Optional property to control content protection * * Each connector may be connected to one or more CRTCs, or may be clonable by * another connector if they can share a CRTC. Each connector also has a specific @@ -813,13 +779,27 @@ struct drm_cmdline_mode { * span multiple monitors). */ struct drm_connector { + /** @dev: parent DRM device */ struct drm_device *dev; + /** @kdev: kernel device for sysfs attributes */ struct device *kdev; + /** @attr: sysfs attributes */ struct device_attribute *attr; + + /** + * @head: + * + * List of all connectors on a @dev, linked from + * &drm_mode_config.connector_list. Protected by + * &drm_mode_config.connector_list_lock, but please only use + * &drm_connector_list_iter to walk this list. + */ struct list_head head; + /** @base: base KMS object */ struct drm_mode_object base; + /** @name: human readable name, can be overwritten by the driver */ char *name; /** @@ -837,10 +817,30 @@ struct drm_connector { */ unsigned index; + /** + * @connector_type: + * one of the DRM_MODE_CONNECTOR_ types from drm_mode.h + */ int connector_type; + /** @connector_type_id: index into connector type enum */ int connector_type_id; + /** + * @interlace_allowed: + * Can this connector handle interlaced modes? Only used by + * drm_helper_probe_single_connector_modes() for mode filtering. + */ bool interlace_allowed; + /** + * @doublescan_allowed: + * Can this connector handle doublescan? Only used by + * drm_helper_probe_single_connector_modes() for mode filtering. + */ bool doublescan_allowed; + /** + * @stereo_allowed: + * Can this connector handle stereo modes? Only used by + * drm_helper_probe_single_connector_modes() for mode filtering. + */ bool stereo_allowed; /** @@ -889,45 +889,42 @@ struct drm_connector { * Protected by &drm_mode_config.mutex. */ struct drm_display_info display_info; + + /** @funcs: connector control functions */ const struct drm_connector_funcs *funcs; + /** + * @edid_blob_ptr: DRM property containing EDID if present. Protected by + * &drm_mode_config.mutex. This should be updated only by calling + * drm_connector_update_edid_property(). + */ struct drm_property_blob *edid_blob_ptr; + + /** @properties: property tracking for this connector */ struct drm_object_properties properties; + /** + * @scaling_mode_property: Optional atomic property to control the + * upscaling. See drm_connector_attach_content_protection_property(). + */ struct drm_property *scaling_mode_property; /** * @content_protection_property: DRM ENUM property for content - * protection + * protection. See drm_connector_attach_content_protection_property(). */ struct drm_property *content_protection_property; /** * @path_blob_ptr: * - * DRM blob property data for the DP MST path property. + * DRM blob property data for the DP MST path property. This should only + * be updated by calling drm_connector_set_path_property(). */ struct drm_property_blob *path_blob_ptr; - /** - * @tile_blob_ptr: - * - * DRM blob property data for the tile property (used mostly by DP MST). - * This is meant for screens which are driven through separate display - * pipelines represented by &drm_crtc, which might not be running with - * genlocked clocks. For tiled panels which are genlocked, like - * dual-link LVDS or dual-link DSI, the driver should try to not expose - * the tiling and virtualize both &drm_crtc and &drm_plane if needed. - */ - struct drm_property_blob *tile_blob_ptr; - -/* should we poll this connector for connects and disconnects */ -/* hot plug detectable */ #define DRM_CONNECTOR_POLL_HPD (1 << 0) -/* poll for connections */ #define DRM_CONNECTOR_POLL_CONNECT (1 << 1) -/* can cleanly poll for disconnections without flickering the screen */ -/* DACs should rarely do this without a lot of testing */ #define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) /** @@ -944,25 +941,40 @@ struct drm_connector { * Periodically poll the connector for connection. * * DRM_CONNECTOR_POLL_DISCONNECT - * Periodically poll the connector for disconnection. + * Periodically poll the connector for disconnection, without + * causing flickering even when the connector is in use. DACs should + * rarely do this without a lot of testing. * * Set to 0 for connectors that don't support connection status * discovery. */ uint8_t polled; - /* requested DPMS state */ + /** + * @dpms: Current dpms state. For legacy drivers the + * &drm_connector_funcs.dpms callback must update this. For atomic + * drivers, this is handled by the core atomic code, and drivers must + * only take &drm_crtc_state.active into account. + */ int dpms; + /** @helper_private: mid-layer private data */ const struct drm_connector_helper_funcs *helper_private; - /* forced on connector */ + /** @cmdline_mode: mode line parsed from the kernel cmdline for this connector */ struct drm_cmdline_mode cmdline_mode; + /** @force: a DRM_FORCE_ state for forced mode sets */ enum drm_connector_force force; + /** @override_edid: has the EDID been overwritten through debugfs for testing? */ bool override_edid; #define DRM_CONNECTOR_MAX_ENCODER 3 + /** + * @encoder_ids: Valid encoders for this connector. Please only use + * drm_connector_for_each_possible_encoder() to enumerate these. + */ uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + /** * @encoder: Currently bound encoder driving this connector, if any. * Only really meaningful for non-atomic drivers. Atomic drivers should @@ -972,19 +984,37 @@ struct drm_connector { struct drm_encoder *encoder; #define MAX_ELD_BYTES 128 - /* EDID bits */ + /** @eld: EDID-like data, if present */ uint8_t eld[MAX_ELD_BYTES]; + /** @latency_present: AV delay info from ELD, if found */ bool latency_present[2]; - int video_latency[2]; /* [0]: progressive, [1]: interlaced */ + /** + * @video_latency: Video latency info from ELD, if found. + * [0]: progressive, [1]: interlaced + */ + int video_latency[2]; + /** + * @audio_latency: audio latency info from ELD, if found + * [0]: progressive, [1]: interlaced + */ int audio_latency[2]; - int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ + /** + * @null_edid_counter: track sinks that give us all zeros for the EDID. + * Needed to workaround some HW bugs where we get all 0s + */ + int null_edid_counter; + + /** @bad_edid_counter: track sinks that give us an EDID with invalid checksum */ unsigned bad_edid_counter; - /* Flag for raw EDID header corruption - used in Displayport - * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 + /** + * @edid_corrupt: Indicates whether the last read EDID was corrupt. Used + * in Displayport compliance testing - Displayport Link CTS Core 1.2 + * rev1.1 4.2.2.6 */ bool edid_corrupt; + /** @debugfs_entry: debugfs directory for this connector */ struct dentry *debugfs_entry; /** @@ -992,7 +1022,7 @@ struct drm_connector { * * Current atomic state for this connector. * - * This is protected by @drm_mode_config.connection_mutex. Note that + * This is protected by &drm_mode_config.connection_mutex. Note that * nonblocking atomic commits access the current connector state without * taking locks. Either by going through the &struct drm_atomic_state * pointers, see for_each_oldnew_connector_in_state(), @@ -1003,19 +1033,44 @@ struct drm_connector { */ struct drm_connector_state *state; - /* DisplayID bits */ + /* DisplayID bits. FIXME: Extract into a substruct? */ + + /** + * @tile_blob_ptr: + * + * DRM blob property data for the tile property (used mostly by DP MST). + * This is meant for screens which are driven through separate display + * pipelines represented by &drm_crtc, which might not be running with + * genlocked clocks. For tiled panels which are genlocked, like + * dual-link LVDS or dual-link DSI, the driver should try to not expose + * the tiling and virtualize both &drm_crtc and &drm_plane if needed. + * + * This should only be updated by calling + * drm_connector_set_tile_property(). + */ + struct drm_property_blob *tile_blob_ptr; + + /** @has_tile: is this connector connected to a tiled monitor */ bool has_tile; + /** @tile_group: tile group for the connected monitor */ struct drm_tile_group *tile_group; + /** @tile_is_single_monitor: whether the tile is one monitor housing */ bool tile_is_single_monitor; + /** @num_h_tile: number of horizontal tiles in the tile group */ + /** @num_v_tile: number of vertical tiles in the tile group */ uint8_t num_h_tile, num_v_tile; + /** @tile_h_loc: horizontal location of this tile */ + /** @tile_v_loc: vertical location of this tile */ uint8_t tile_h_loc, tile_v_loc; + /** @tile_h_size: horizontal size of this tile. */ + /** @tile_v_size: vertical size of this tile. */ uint16_t tile_h_size, tile_v_size; /** * @free_node: * - * List used only by &drm_connector_iter to be able to clean up a + * List used only by &drm_connector_list_iter to be able to clean up a * connector from any context, in conjunction with * &drm_mode_config.connector_free_work. */ @@ -1030,7 +1085,7 @@ int drm_connector_init(struct drm_device *dev, int connector_type); int drm_connector_register(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector); -int drm_mode_connector_attach_encoder(struct drm_connector *connector, +int drm_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); void drm_connector_cleanup(struct drm_connector *connector); @@ -1136,13 +1191,13 @@ void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, int drm_mode_create_suggested_offset_properties(struct drm_device *dev); -int drm_mode_connector_set_path_property(struct drm_connector *connector, - const char *path); -int drm_mode_connector_set_tile_property(struct drm_connector *connector); -int drm_mode_connector_update_edid_property(struct drm_connector *connector, - const struct edid *edid); -void drm_mode_connector_set_link_status_property(struct drm_connector *connector, - uint64_t link_status); +int drm_connector_set_path_property(struct drm_connector *connector, + const char *path); +int drm_connector_set_tile_property(struct drm_connector *connector); +int drm_connector_update_edid_property(struct drm_connector *connector, + const struct edid *edid); +void drm_connector_set_link_status_property(struct drm_connector *connector, + uint64_t link_status); int drm_connector_init_panel_orientation_property( struct drm_connector *connector, int width, int height); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 17f4f93340b8..92e7fc7f05a4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -77,21 +77,6 @@ struct drm_plane_helper_funcs; /** * struct drm_crtc_state - mutable CRTC state - * @crtc: backpointer to the CRTC - * @enable: whether the CRTC should be enabled, gates all other state - * @active: whether the CRTC is actively displaying (used for DPMS) - * @planes_changed: planes on this crtc are updated - * @mode_changed: @mode or @enable has been changed - * @active_changed: @active has been toggled. - * @connectors_changed: connectors to this crtc have been updated - * @zpos_changed: zpos values of planes on this crtc have been updated - * @color_mgmt_changed: color management properties have changed (degamma or - * gamma LUT or CSC matrix) - * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes - * @connector_mask: bitmask of (1 << drm_connector_index(connector)) of attached connectors - * @encoder_mask: bitmask of (1 << drm_encoder_index(encoder)) of attached encoders - * @mode_blob: &drm_property_blob for @mode - * @state: backpointer to global drm_atomic_state * * Note that the distinction between @enable and @active is rather subtile: * Flipping @active while @enable is set without changing anything else may @@ -102,21 +87,86 @@ struct drm_plane_helper_funcs; * * The three booleans active_changed, connectors_changed and mode_changed are * intended to indicate whether a full modeset is needed, rather than strictly - * describing what has changed in a commit. - * See also: drm_atomic_crtc_needs_modeset() + * describing what has changed in a commit. See also: + * drm_atomic_crtc_needs_modeset() + * + * WARNING: Transitional helpers (like drm_helper_crtc_mode_set() or + * drm_helper_crtc_mode_set_base()) do not maintain many of the derived control + * state like @plane_mask so drivers not converted over to atomic helpers should + * not rely on these being accurate! */ struct drm_crtc_state { + /** @crtc: backpointer to the CRTC */ struct drm_crtc *crtc; + /** + * @enable: Whether the CRTC should be enabled, gates all other state. + * This controls reservations of shared resources. Actual hardware state + * is controlled by @active. + */ bool enable; + + /** + * @active: Whether the CRTC is actively displaying (used for DPMS). + * Implies that @enable is set. The driver must not release any shared + * resources if @active is set to false but @enable still true, because + * userspace expects that a DPMS ON always succeeds. + * + * Hence drivers must not consult @active in their various + * &drm_mode_config_funcs.atomic_check callback to reject an atomic + * commit. They can consult it to aid in the computation of derived + * hardware state, since even in the DPMS OFF state the display hardware + * should be as much powered down as when the CRTC is completely + * disabled through setting @enable to false. + */ bool active; - /* computed state bits used by helpers and drivers */ + /** + * @planes_changed: Planes on this crtc are updated. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. + */ bool planes_changed : 1; + + /** + * @mode_changed: @mode or @enable has been changed. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. See also + * drm_atomic_crtc_needs_modeset(). + * + * Drivers are supposed to set this for any CRTC state changes that + * require a full modeset. They can also reset it to false if e.g. a + * @mode change can be done without a full modeset by only changing + * scaler settings. + */ bool mode_changed : 1; + + /** + * @active_changed: @active has been toggled. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. See also + * drm_atomic_crtc_needs_modeset(). + */ bool active_changed : 1; + + /** + * @connectors_changed: Connectors to this crtc have been updated, + * either in their state or routing. Used by the atomic + * helpers and drivers to steer the atomic commit control flow. See also + * drm_atomic_crtc_needs_modeset(). + * + * Drivers are supposed to set this as-needed from their own atomic + * check code, e.g. from &drm_encoder_helper_funcs.atomic_check + */ bool connectors_changed : 1; + /** + * @zpos_changed: zpos values of planes on this crtc have been updated. + * Used by the atomic helpers and drivers to steer the atomic commit + * control flow. + */ bool zpos_changed : 1; + /** + * @color_mgmt_changed: Color management properties have changed + * (@gamma_lut, @degamma_lut or @ctm). Used by the atomic helpers and + * drivers to steer the atomic commit control flow. + */ bool color_mgmt_changed : 1; /** @@ -142,14 +192,22 @@ struct drm_crtc_state { */ bool no_vblank : 1; - /* attached planes bitmask: - * WARNING: transitional helpers do not maintain plane_mask so - * drivers not converted over to atomic helpers should not rely - * on plane_mask being accurate! + /** + * @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to + * this CRTC. */ u32 plane_mask; + /** + * @connector_mask: Bitmask of drm_connector_mask(connector) of + * connectors attached to this CRTC. + */ u32 connector_mask; + + /** + * @encoder_mask: Bitmask of drm_encoder_mask(encoder) of encoders + * attached to this CRTC. + */ u32 encoder_mask; /** @@ -159,7 +217,7 @@ struct drm_crtc_state { * differences between the mode requested by userspace in @mode and what * is actually programmed into the hardware. * - * For drivers using drm_bridge, this stores hardware display timings + * For drivers using &drm_bridge, this stores hardware display timings * used between the CRTC and the first bridge. For other drivers, the * meaning of the adjusted_mode field is purely driver implementation * defined information, and will usually be used to store the hardware @@ -184,7 +242,10 @@ struct drm_crtc_state { */ struct drm_display_mode mode; - /* blob property to expose current mode to atomic userspace */ + /** + * @mode_blob: &drm_property_blob for @mode, for exposing the mode to + * atomic userspace. + */ struct drm_property_blob *mode_blob; /** @@ -288,6 +349,7 @@ struct drm_crtc_state { */ struct drm_crtc_commit *commit; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; }; @@ -747,35 +809,25 @@ struct drm_crtc_funcs { /** * struct drm_crtc - central CRTC control structure - * @dev: parent DRM device - * @port: OF node used by drm_of_find_possible_crtcs() - * @head: list management - * @name: human readable name, can be overwritten by the driver - * @mutex: per-CRTC locking - * @base: base KMS object for ID tracking etc. - * @primary: primary plane for this CRTC - * @cursor: cursor plane for this CRTC - * @cursor_x: current x position of the cursor, used for universal cursor planes - * @cursor_y: current y position of the cursor, used for universal cursor planes - * @enabled: is this CRTC enabled? - * @mode: current mode timings - * @hwmode: mode timings as programmed to hw regs - * @x: x position on screen - * @y: y position on screen - * @funcs: CRTC control functions - * @gamma_size: size of gamma ramp - * @gamma_store: gamma ramp values - * @helper_private: mid-layer private data - * @properties: property tracking for this CRTC * * Each CRTC may have one or more connectors associated with it. This structure * allows the CRTC to be controlled. */ struct drm_crtc { + /** @dev: parent DRM device */ struct drm_device *dev; + /** @port: OF node used by drm_of_find_possible_crtcs(). */ struct device_node *port; + /** + * @head: + * + * List of all CRTCs on @dev, linked from &drm_mode_config.crtc_list. + * Invariant over the lifetime of @dev and therefore does not need + * locking. + */ struct list_head head; + /** @name: human readable name, can be overwritten by the driver */ char *name; /** @@ -790,10 +842,25 @@ struct drm_crtc { */ struct drm_modeset_lock mutex; + /** @base: base KMS object for ID tracking etc. */ struct drm_mode_object base; - /* primary and cursor planes for CRTC */ + /** + * @primary: + * Primary plane for this CRTC. Note that this is only + * relevant for legacy IOCTL, it specifies the plane implicitly used by + * the SETCRTC and PAGE_FLIP IOCTLs. It does not have any significance + * beyond that. + */ struct drm_plane *primary; + + /** + * @cursor: + * Cursor plane for this CRTC. Note that this is only relevant for + * legacy IOCTL, it specifies the plane implicitly used by the SETCURSOR + * and SETCURSOR2 IOCTLs. It does not have any significance + * beyond that. + */ struct drm_plane *cursor; /** @@ -802,30 +869,94 @@ struct drm_crtc { */ unsigned index; - /* position of cursor plane on crtc */ + /** + * @cursor_x: Current x position of the cursor, used for universal + * cursor planes because the SETCURSOR IOCTL only can update the + * framebuffer without supplying the coordinates. Drivers should not use + * this directly, atomic drivers should look at &drm_plane_state.crtc_x + * of the cursor plane instead. + */ int cursor_x; + /** + * @cursor_y: Current y position of the cursor, used for universal + * cursor planes because the SETCURSOR IOCTL only can update the + * framebuffer without supplying the coordinates. Drivers should not use + * this directly, atomic drivers should look at &drm_plane_state.crtc_y + * of the cursor plane instead. + */ int cursor_y; + /** + * @enabled: + * + * Is this CRTC enabled? Should only be used by legacy drivers, atomic + * drivers should instead consult &drm_crtc_state.enable and + * &drm_crtc_state.active. Atomic drivers can update this by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ bool enabled; - /* Requested mode from modesetting. */ + /** + * @mode: + * + * Current mode timings. Should only be used by legacy drivers, atomic + * drivers should instead consult &drm_crtc_state.mode. Atomic drivers + * can update this by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ struct drm_display_mode mode; - /* Programmed mode in hw, after adjustments for encoders, - * crtc, panel scaling etc. Needed for timestamping etc. + /** + * @hwmode: + * + * Programmed mode in hw, after adjustments for encoders, crtc, panel + * scaling etc. Should only be used by legacy drivers, for high + * precision vblank timestamps in + * drm_calc_vbltimestamp_from_scanoutpos(). + * + * Note that atomic drivers should not use this, but instead use + * &drm_crtc_state.adjusted_mode. And for high-precision timestamps + * drm_calc_vbltimestamp_from_scanoutpos() used &drm_vblank_crtc.hwmode, + * which is filled out by calling drm_calc_timestamping_constants(). */ struct drm_display_mode hwmode; - int x, y; + /** + * @x: + * x position on screen. Should only be used by legacy drivers, atomic + * drivers should look at &drm_plane_state.crtc_x of the primary plane + * instead. Updated by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ + int x; + /** + * @y: + * y position on screen. Should only be used by legacy drivers, atomic + * drivers should look at &drm_plane_state.crtc_y of the primary plane + * instead. Updated by calling + * drm_atomic_helper_update_legacy_modeset_state(). + */ + int y; + + /** @funcs: CRTC control functions */ const struct drm_crtc_funcs *funcs; - /* Legacy FB CRTC gamma size for reporting to userspace */ + /** + * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up + * by calling drm_mode_crtc_set_gamma_size(). + */ uint32_t gamma_size; + + /** + * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and + * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size(). + */ uint16_t *gamma_store; - /* if you are using the helper */ + /** @helper_private: mid-layer private data */ const struct drm_crtc_helper_funcs *helper_private; + /** @properties: property tracking for this CRTC */ struct drm_object_properties properties; /** @@ -895,7 +1026,6 @@ struct drm_crtc { * * spinlock to protect the fences in the fence_context. */ - spinlock_t fence_lock; /** * @fence_seqno: @@ -965,8 +1095,8 @@ static inline unsigned int drm_crtc_index(const struct drm_crtc *crtc) * drm_crtc_mask - find the mask of a registered CRTC * @crtc: CRTC to find mask for * - * Given a registered CRTC, return the mask bit of that CRTC for an - * encoder's possible_crtcs field. + * Given a registered CRTC, return the mask bit of that CRTC for the + * &drm_encoder.possible_crtcs and &drm_plane.possible_crtcs fields. */ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) { diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c01564991a9f..05cc31b5db16 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1078,6 +1078,25 @@ struct drm_dp_aux_msg { size_t size; }; +struct cec_adapter; +struct edid; + +/** + * struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX + * @lock: mutex protecting this struct + * @adap: the CEC adapter for CEC-Tunneling-over-AUX support. + * @name: name of the CEC adapter + * @parent: parent device of the CEC adapter + * @unregister_work: unregister the CEC adapter + */ +struct drm_dp_aux_cec { + struct mutex lock; + struct cec_adapter *adap; + const char *name; + struct device *parent; + struct delayed_work unregister_work; +}; + /** * struct drm_dp_aux - DisplayPort AUX channel * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter @@ -1136,6 +1155,10 @@ struct drm_dp_aux { * @i2c_defer_count: Counts I2C DEFERs, used for DP validation. */ unsigned i2c_defer_count; + /** + * @cec: struct containing fields used for CEC-Tunneling-over-AUX. + */ + struct drm_dp_aux_cec cec; }; ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, @@ -1258,4 +1281,37 @@ drm_dp_has_quirk(const struct drm_dp_desc *desc, enum drm_dp_quirk quirk) return desc->quirks & BIT(quirk); } +#ifdef CONFIG_DRM_DP_CEC +void drm_dp_cec_irq(struct drm_dp_aux *aux); +void drm_dp_cec_register_connector(struct drm_dp_aux *aux, const char *name, + struct device *parent); +void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux); +void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid); +void drm_dp_cec_unset_edid(struct drm_dp_aux *aux); +#else +static inline void drm_dp_cec_irq(struct drm_dp_aux *aux) +{ +} + +static inline void drm_dp_cec_register_connector(struct drm_dp_aux *aux, + const char *name, + struct device *parent) +{ +} + +static inline void drm_dp_cec_unregister_connector(struct drm_dp_aux *aux) +{ +} + +static inline void drm_dp_cec_set_edid(struct drm_dp_aux *aux, + const struct edid *edid) +{ +} + +static inline void drm_dp_cec_unset_edid(struct drm_dp_aux *aux) +{ +} + +#endif + #endif /* _DRM_DP_HELPER_H_ */ diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 7e545f5f94d3..46a8009784df 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -649,6 +649,35 @@ static inline bool drm_dev_is_unplugged(struct drm_device *dev) return true; } +/** + * drm_core_check_feature - check driver feature flags + * @dev: DRM device to check + * @feature: feature flag + * + * This checks @dev for driver features, see &drm_driver.driver_features and the + * various DRIVER_\* flags. + * + * Returns true if the @feature is supported, false otherwise. + */ +static inline bool drm_core_check_feature(struct drm_device *dev, int feature) +{ + return dev->driver->driver_features & feature; +} + +/** + * drm_drv_uses_atomic_modeset - check if the driver implements + * atomic_commit() + * @dev: DRM device + * + * This check is useful if drivers do not have DRIVER_ATOMIC set but + * have atomic modesetting internally implemented. + */ +static inline bool drm_drv_uses_atomic_modeset(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_ATOMIC) || + dev->mode_config.funcs->atomic_commit != NULL; +} + int drm_dev_set_unique(struct drm_device *dev, const char *name); diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 3e86408dac9f..f9c15845f465 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -39,6 +39,7 @@ struct drm_mode_fb_cmd2; * @hsub: Horizontal chroma subsampling factor * @vsub: Vertical chroma subsampling factor * @has_alpha: Does the format embeds an alpha component? + * @is_yuv: Is it a YUV format? */ struct drm_format_info { u32 format; @@ -48,6 +49,7 @@ struct drm_format_info { u8 hsub; u8 vsub; bool has_alpha; + bool is_yuv; }; /** diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index b159fe07fcf9..baded6514456 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -530,7 +530,7 @@ drm_mode_validate_ycbcr420(const struct drm_display_mode *mode, void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); void drm_mode_sort(struct list_head *mode_list); -void drm_mode_connector_list_update(struct drm_connector *connector); +void drm_connector_list_update(struct drm_connector *connector); /* parsing cmdline modes */ bool diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h index d0eb76c4b309..61142aa0ab23 100644 --- a/include/drm/drm_modeset_helper_vtables.h +++ b/include/drm/drm_modeset_helper_vtables.h @@ -785,7 +785,7 @@ struct drm_connector_helper_funcs { * * This function should fill in all modes currently valid for the sink * into the &drm_connector.probed_modes list. It should also update the - * EDID property by calling drm_mode_connector_update_edid_property(). + * EDID property by calling drm_connector_update_edid_property(). * * The usual way to implement this is to cache the EDID retrieved in the * probe callback somewhere in the driver-private connector structure. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index cee9dfaaa740..8a152dc16ea5 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -34,31 +34,15 @@ struct drm_modeset_acquire_ctx; /** * struct drm_plane_state - mutable plane state - * @plane: backpointer to the plane - * @crtc_w: width of visible portion of plane on crtc - * @crtc_h: height of visible portion of plane on crtc - * @src_x: left position of visible portion of plane within - * plane (in 16.16) - * @src_y: upper position of visible portion of plane within - * plane (in 16.16) - * @src_w: width of visible portion of plane (in 16.16) - * @src_h: height of visible portion of plane (in 16.16) - * @alpha: opacity of the plane - * @rotation: rotation of the plane - * @zpos: priority of the given plane on crtc (optional) - * Note that multiple active planes on the same crtc can have an identical - * zpos value. The rule to solving the conflict is to compare the plane - * object IDs; the plane with a higher ID must be stacked on top of a - * plane with a lower ID. - * @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1 - * where N is the number of active planes for given crtc. Note that - * the driver must set drm_mode_config.normalize_zpos or call - * drm_atomic_normalize_zpos() to update this before it can be trusted. - * @src: clipped source coordinates of the plane (in 16.16) - * @dst: clipped destination coordinates of the plane - * @state: backpointer to global drm_atomic_state + * + * Please not that the destination coordinates @crtc_x, @crtc_y, @crtc_h and + * @crtc_w and the source coordinates @src_x, @src_y, @src_h and @src_w are the + * raw coordinates provided by userspace. Drivers should use + * drm_atomic_helper_check_plane_state() and only use the derived rectangles in + * @src and @dst to program the hardware. */ struct drm_plane_state { + /** @plane: backpointer to the plane */ struct drm_plane *plane; /** @@ -87,7 +71,7 @@ struct drm_plane_state { * preserved. * * Drivers should store any implicit fence in this from their - * &drm_plane_helper.prepare_fb callback. See drm_gem_fb_prepare_fb() + * &drm_plane_helper_funcs.prepare_fb callback. See drm_gem_fb_prepare_fb() * and drm_gem_fb_simple_display_pipe_prepare_fb() for suitable helpers. */ struct dma_fence *fence; @@ -108,20 +92,60 @@ struct drm_plane_state { */ int32_t crtc_y; + /** @crtc_w: width of visible portion of plane on crtc */ + /** @crtc_h: height of visible portion of plane on crtc */ uint32_t crtc_w, crtc_h; - /* Source values are 16.16 fixed point */ - uint32_t src_x, src_y; + /** + * @src_x: left position of visible portion of plane within plane (in + * 16.16 fixed point). + */ + uint32_t src_x; + /** + * @src_y: upper position of visible portion of plane within plane (in + * 16.16 fixed point). + */ + uint32_t src_y; + /** @src_w: width of visible portion of plane (in 16.16) */ + /** @src_h: height of visible portion of plane (in 16.16) */ uint32_t src_h, src_w; - /* Plane opacity */ + /** + * @alpha: + * Opacity of the plane with 0 as completely transparent and 0xffff as + * completely opaque. See drm_plane_create_alpha_property() for more + * details. + */ u16 alpha; - /* Plane rotation */ + /** + * @rotation: + * Rotation of the plane. See drm_plane_create_rotation_property() for + * more details. + */ unsigned int rotation; - /* Plane zpos */ + /** + * @zpos: + * Priority of the given plane on crtc (optional). + * + * Note that multiple active planes on the same crtc can have an + * identical zpos value. The rule to solving the conflict is to compare + * the plane object IDs; the plane with a higher ID must be stacked on + * top of a plane with a lower ID. + * + * See drm_plane_create_zpos_property() and + * drm_plane_create_zpos_immutable_property() for more details. + */ unsigned int zpos; + + /** + * @normalized_zpos: + * Normalized value of zpos: unique, range from 0 to N-1 where N is the + * number of active planes for given crtc. Note that the driver must set + * &drm_mode_config.normalize_zpos or call drm_atomic_normalize_zpos() to + * update this before it can be trusted. + */ unsigned int normalized_zpos; /** @@ -138,7 +162,8 @@ struct drm_plane_state { */ enum drm_color_range color_range; - /* Clipped coordinates */ + /** @src: clipped source coordinates of the plane (in 16.16) */ + /** @dst: clipped destination coordinates of the plane */ struct drm_rect src, dst; /** @@ -157,6 +182,7 @@ struct drm_plane_state { */ struct drm_crtc_commit *commit; + /** @state: backpointer to global drm_atomic_state */ struct drm_atomic_state *state; }; @@ -499,30 +525,27 @@ enum drm_plane_type { /** * struct drm_plane - central DRM plane control structure - * @dev: DRM device this plane belongs to - * @head: for list management - * @name: human readable name, can be overwritten by the driver - * @base: base mode object - * @possible_crtcs: pipes this plane can be bound to - * @format_types: array of formats supported by this plane - * @format_count: number of formats supported - * @format_default: driver hasn't supplied supported formats for the plane - * @modifiers: array of modifiers supported by this plane - * @modifier_count: number of modifiers supported - * @old_fb: Temporary tracking of the old fb while a modeset is ongoing. Used by - * drm_mode_set_config_internal() to implement correct refcounting. - * @funcs: helper functions - * @properties: property tracking for this plane - * @type: type of plane (overlay, primary, cursor) - * @alpha_property: alpha property for this plane - * @zpos_property: zpos property for this plane - * @rotation_property: rotation property for this plane - * @helper_private: mid-layer private data + * + * Planes represent the scanout hardware of a display block. They receive their + * input data from a &drm_framebuffer and feed it to a &drm_crtc. Planes control + * the color conversion, see `Plane Composition Properties`_ for more details, + * and are also involved in the color conversion of input pixels, see `Color + * Management Properties`_ for details on that. */ struct drm_plane { + /** @dev: DRM device this plane belongs to */ struct drm_device *dev; + + /** + * @head: + * + * List of all planes on @dev, linked from &drm_mode_config.plane_list. + * Invariant over the lifetime of @dev and therefore does not need + * locking. + */ struct list_head head; + /** @name: human readable name, can be overwritten by the driver */ char *name; /** @@ -536,35 +559,62 @@ struct drm_plane { */ struct drm_modeset_lock mutex; + /** @base: base mode object */ struct drm_mode_object base; + /** + * @possible_crtcs: pipes this plane can be bound to constructed from + * drm_crtc_mask() + */ uint32_t possible_crtcs; + /** @format_types: array of formats supported by this plane */ uint32_t *format_types; + /** @format_count: Size of the array pointed at by @format_types. */ unsigned int format_count; + /** + * @format_default: driver hasn't supplied supported formats for the + * plane. Used by the drm_plane_init compatibility wrapper only. + */ bool format_default; + /** @modifiers: array of modifiers supported by this plane */ uint64_t *modifiers; + /** @modifier_count: Size of the array pointed at by @modifier_count. */ unsigned int modifier_count; /** - * @crtc: Currently bound CRTC, only really meaningful for non-atomic - * drivers. Atomic drivers should instead check &drm_plane_state.crtc. + * @crtc: + * + * Currently bound CRTC, only meaningful for non-atomic drivers. For + * atomic drivers this is forced to be NULL, atomic drivers should + * instead check &drm_plane_state.crtc. */ struct drm_crtc *crtc; /** - * @fb: Currently bound framebuffer, only really meaningful for - * non-atomic drivers. Atomic drivers should instead check - * &drm_plane_state.fb. + * @fb: + * + * Currently bound framebuffer, only meaningful for non-atomic drivers. + * For atomic drivers this is forced to be NULL, atomic drivers should + * instead check &drm_plane_state.fb. */ struct drm_framebuffer *fb; + /** + * @old_fb: + * + * Temporary tracking of the old fb while a modeset is ongoing. Only + * used by non-atomic drivers, forced to be NULL for atomic drivers. + */ struct drm_framebuffer *old_fb; + /** @funcs: plane control functions */ const struct drm_plane_funcs *funcs; + /** @properties: property tracking for this plane */ struct drm_object_properties properties; + /** @type: Type of plane, see &enum drm_plane_type for details. */ enum drm_plane_type type; /** @@ -573,6 +623,7 @@ struct drm_plane { */ unsigned index; + /** @helper_private: mid-layer private data */ const struct drm_plane_helper_funcs *helper_private; /** @@ -590,8 +641,23 @@ struct drm_plane { */ struct drm_plane_state *state; + /** + * @alpha_property: + * Optional alpha property for this plane. See + * drm_plane_create_alpha_property(). + */ struct drm_property *alpha_property; + /** + * @zpos_property: + * Optional zpos property for this plane. See + * drm_plane_create_zpos_property(). + */ struct drm_property *zpos_property; + /** + * @rotation_property: + * Optional rotation property for this plane. See + * drm_plane_create_rotation_property(). + */ struct drm_property *rotation_property; /** diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index e1a46e9991cc..767c90b654c5 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -195,6 +195,7 @@ static inline struct drm_printer drm_debug_printer(const char *prefix) #define DRM_UT_VBL 0x20 #define DRM_UT_STATE 0x40 #define DRM_UT_LEASE 0x80 +#define DRM_UT_DP 0x100 __printf(3, 4) void drm_dev_printk(const struct device *dev, const char *level, @@ -307,6 +308,11 @@ void drm_err(const char *format, ...); #define DRM_DEBUG_LEASE(fmt, ...) \ drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__) +#define DRM_DEV_DEBUG_DP(dev, fmt, ...) \ + drm_dev_dbg(dev, DRM_UT_DP, fmt, ## __VA_ARGS__) +#define DRM_DEBUG_DP(dev, fmt, ...) \ + drm_dbg(DRM_UT_DP, fmt, ## __VA_ARGS__) + #define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 1d5c0b2a8956..c030f6ccab99 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -147,10 +147,10 @@ struct drm_property { * properties are not exposed to legacy userspace. * * DRM_MODE_PROP_IMMUTABLE - * Set for properties where userspace cannot be changed by + * Set for properties whose values cannot be changed by * userspace. The kernel is allowed to update the value of these * properties. This is generally used to expose probe state to - * usersapce, e.g. the EDID, or the connector path property on DP + * userspace, e.g. the EDID, or the connector path property on DP * MST sinks. */ uint32_t flags; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index d5e52350a3aa..d43949b5bb3e 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -183,6 +183,7 @@ extern "C" { #define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 #define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 #define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 +#define DRM_FORMAT_MOD_VENDOR_ARM 0x08 /* add more to the end as needed */ #define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) @@ -485,6 +486,88 @@ extern "C" { */ #define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6) +/* + * Arm Framebuffer Compression (AFBC) modifiers + * + * AFBC is a proprietary lossless image compression protocol and format. + * It provides fine-grained random access and minimizes the amount of data + * transferred between IP blocks. + * + * AFBC has several features which may be supported and/or used, which are + * represented using bits in the modifier. Not all combinations are valid, + * and different devices or use-cases may support different combinations. + */ +#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) fourcc_mod_code(ARM, __afbc_mode) + +/* + * AFBC superblock size + * + * Indicates the superblock size(s) used for the AFBC buffer. The buffer + * size (in pixels) must be aligned to a multiple of the superblock size. + * Four lowest significant bits(LSBs) are reserved for block size. + */ +#define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf +#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) + +/* + * AFBC lossless colorspace transform + * + * Indicates that the buffer makes use of the AFBC lossless colorspace + * transform. + */ +#define AFBC_FORMAT_MOD_YTR (1ULL << 4) + +/* + * AFBC block-split + * + * Indicates that the payload of each superblock is split. The second + * half of the payload is positioned at a predefined offset from the start + * of the superblock payload. + */ +#define AFBC_FORMAT_MOD_SPLIT (1ULL << 5) + +/* + * AFBC sparse layout + * + * This flag indicates that the payload of each superblock must be stored at a + * predefined position relative to the other superblocks in the same AFBC + * buffer. This order is the same order used by the header buffer. In this mode + * each superblock is given the same amount of space as an uncompressed + * superblock of the particular format would require, rounding up to the next + * multiple of 128 bytes in size. + */ +#define AFBC_FORMAT_MOD_SPARSE (1ULL << 6) + +/* + * AFBC copy-block restrict + * + * Buffers with this flag must obey the copy-block restriction. The restriction + * is such that there are no copy-blocks referring across the border of 8x8 + * blocks. For the subsampled data the 8x8 limitation is also subsampled. + */ +#define AFBC_FORMAT_MOD_CBR (1ULL << 7) + +/* + * AFBC tiled layout + * + * The tiled layout groups superblocks in 8x8 or 4x4 tiles, where all + * superblocks inside a tile are stored together in memory. 8x8 tiles are used + * for pixel formats up to and including 32 bpp while 4x4 tiles are used for + * larger bpp formats. The order between the tiles is scan line. + * When the tiled layout is used, the buffer size (in pixels) must be aligned + * to the tile size. + */ +#define AFBC_FORMAT_MOD_TILED (1ULL << 8) + +/* + * AFBC solid color blocks + * + * Indicates that the buffer makes use of solid-color blocks, whereby bandwidth + * can be reduced if a whole superblock is a single color. + */ +#define AFBC_FORMAT_MOD_SC (1ULL << 9) + #if defined(__cplusplus) } #endif