diff options
Diffstat (limited to 'drivers/gpu/drm/drm_connector.c')
| -rw-r--r-- | drivers/gpu/drm/drm_connector.c | 102 | 
1 files changed, 102 insertions, 0 deletions
| diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index ec9ad3f8a83f..ec3973e8963c 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -28,6 +28,7 @@  #include <drm/drm_print.h>  #include <drm/drm_drv.h>  #include <drm/drm_file.h> +#include <drm/drm_privacy_screen_consumer.h>  #include <drm/drm_sysfs.h>  #include <linux/uaccess.h> @@ -462,6 +463,11 @@ void drm_connector_cleanup(struct drm_connector *connector)  		    DRM_CONNECTOR_REGISTERED))  		drm_connector_unregister(connector); +	if (connector->privacy_screen) { +		drm_privacy_screen_put(connector->privacy_screen); +		connector->privacy_screen = NULL; +	} +  	if (connector->tile_group) {  		drm_mode_put_tile_group(dev, connector->tile_group);  		connector->tile_group = NULL; @@ -543,6 +549,10 @@ int drm_connector_register(struct drm_connector *connector)  	/* Let userspace know we have a new connector */  	drm_sysfs_hotplug_event(connector->dev); +	if (connector->privacy_screen) +		drm_privacy_screen_register_notifier(connector->privacy_screen, +					   &connector->privacy_screen_notifier); +  	mutex_lock(&connector_list_lock);  	list_add_tail(&connector->global_connector_list_entry, &connector_list);  	mutex_unlock(&connector_list_lock); @@ -578,6 +588,11 @@ void drm_connector_unregister(struct drm_connector *connector)  	list_del_init(&connector->global_connector_list_entry);  	mutex_unlock(&connector_list_lock); +	if (connector->privacy_screen) +		drm_privacy_screen_unregister_notifier( +					connector->privacy_screen, +					&connector->privacy_screen_notifier); +  	if (connector->funcs->early_unregister)  		connector->funcs->early_unregister(connector); @@ -2466,6 +2481,93 @@ drm_connector_attach_privacy_screen_properties(struct drm_connector *connector)  }  EXPORT_SYMBOL(drm_connector_attach_privacy_screen_properties); +static void drm_connector_update_privacy_screen_properties( +	struct drm_connector *connector, bool set_sw_state) +{ +	enum drm_privacy_screen_status sw_state, hw_state; + +	drm_privacy_screen_get_state(connector->privacy_screen, +				     &sw_state, &hw_state); + +	if (set_sw_state) +		connector->state->privacy_screen_sw_state = sw_state; +	drm_object_property_set_value(&connector->base, +			connector->privacy_screen_hw_state_property, hw_state); +} + +static int drm_connector_privacy_screen_notifier( +	struct notifier_block *nb, unsigned long action, void *data) +{ +	struct drm_connector *connector = +		container_of(nb, struct drm_connector, privacy_screen_notifier); +	struct drm_device *dev = connector->dev; + +	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); +	drm_connector_update_privacy_screen_properties(connector, true); +	drm_modeset_unlock(&dev->mode_config.connection_mutex); + +	drm_sysfs_connector_status_event(connector, +				connector->privacy_screen_sw_state_property); +	drm_sysfs_connector_status_event(connector, +				connector->privacy_screen_hw_state_property); + +	return NOTIFY_DONE; +} + +/** + * drm_connector_attach_privacy_screen_provider - attach a privacy-screen to + *    the connector + * @connector: connector to attach the privacy-screen to + * @priv: drm_privacy_screen to attach + * + * Create and attach the standard privacy-screen properties and register + * a generic notifier for generating sysfs-connector-status-events + * on external changes to the privacy-screen status. + * This function takes ownership of the passed in drm_privacy_screen and will + * call drm_privacy_screen_put() on it when the connector is destroyed. + */ +void drm_connector_attach_privacy_screen_provider( +	struct drm_connector *connector, struct drm_privacy_screen *priv) +{ +	connector->privacy_screen = priv; +	connector->privacy_screen_notifier.notifier_call = +		drm_connector_privacy_screen_notifier; + +	drm_connector_create_privacy_screen_properties(connector); +	drm_connector_update_privacy_screen_properties(connector, true); +	drm_connector_attach_privacy_screen_properties(connector); +} +EXPORT_SYMBOL(drm_connector_attach_privacy_screen_provider); + +/** + * drm_connector_update_privacy_screen - update connector's privacy-screen sw-state + * @connector_state: connector-state to update the privacy-screen for + * + * This function calls drm_privacy_screen_set_sw_state() on the connector's + * privacy-screen. + * + * If the connector has no privacy-screen, then this is a no-op. + */ +void drm_connector_update_privacy_screen(const struct drm_connector_state *connector_state) +{ +	struct drm_connector *connector = connector_state->connector; +	int ret; + +	if (!connector->privacy_screen) +		return; + +	ret = drm_privacy_screen_set_sw_state(connector->privacy_screen, +					      connector_state->privacy_screen_sw_state); +	if (ret) { +		drm_err(connector->dev, "Error updating privacy-screen sw_state\n"); +		return; +	} + +	/* The hw_state property value may have changed, update it. */ +	drm_connector_update_privacy_screen_properties(connector, false); +} +EXPORT_SYMBOL(drm_connector_update_privacy_screen); +  int drm_connector_set_obj_prop(struct drm_mode_object *obj,  				    struct drm_property *property,  				    uint64_t value) | 
