static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) { struct vmw_screen_object_unit *sou; struct drm_device *dev = dev_priv->dev; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_plane *primary, *cursor; struct drm_crtc *crtc; int ret; sou = kzalloc(sizeof(*sou), GFP_KERNEL); if (!sou) return -ENOMEM; sou->base.unit = unit; crtc = &sou->base.crtc; encoder = &sou->base.encoder; connector = &sou->base.connector; primary = &sou->base.primary; cursor = &sou->base.cursor; sou->base.active_implicit = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = dev_priv->initial_width; sou->base.pref_height = dev_priv->initial_height; sou->base.pref_mode = NULL; /* * Remove this after enabling atomic because property values can * only exist in a state object */ sou->base.is_implicit = false; /* Initialize primary plane */ vmw_du_plane_reset(primary); ret = drm_universal_plane_init(dev, &sou->base.primary, 0, &vmw_sou_plane_funcs, vmw_primary_plane_formats, ARRAY_SIZE(vmw_primary_plane_formats), NULL, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) { DRM_ERROR("Failed to initialize primary plane"); goto err_free; } drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); /* Initialize cursor plane */ vmw_du_plane_reset(cursor); ret = drm_universal_plane_init(dev, &sou->base.cursor, 0, &vmw_sou_cursor_funcs, vmw_cursor_plane_formats, ARRAY_SIZE(vmw_cursor_plane_formats), NULL, DRM_PLANE_TYPE_CURSOR, NULL); if (ret) { DRM_ERROR("Failed to initialize cursor plane"); drm_plane_cleanup(&sou->base.primary); goto err_free; } drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs); vmw_du_connector_reset(connector); ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); if (ret) { DRM_ERROR("Failed to initialize connector\n"); goto err_free; } drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); connector->status = vmw_du_connector_detect(connector, true); vmw_connector_state_to_vcs(connector->state)->is_implicit = false; ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) { DRM_ERROR("Failed to initialize encoder\n"); goto err_free_connector; } (void) drm_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; ret = drm_connector_register(connector); if (ret) { DRM_ERROR("Failed to register connector\n"); goto err_free_encoder; } vmw_du_crtc_reset(crtc); ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary, &sou->base.cursor, &vmw_screen_object_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to initialize CRTC\n"); goto err_free_unregister; } drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(crtc, 256); drm_object_attach_property(&connector->base, dev_priv->hotplug_mode_update_property, 1); drm_object_attach_property(&connector->base, dev->mode_config.suggested_x_property, 0); drm_object_attach_property(&connector->base, dev->mode_config.suggested_y_property, 0); if (dev_priv->implicit_placement_property) drm_object_attach_property (&connector->base, dev_priv->implicit_placement_property, sou->base.is_implicit); return 0; err_free_unregister: drm_connector_unregister(connector); err_free_encoder: drm_encoder_cleanup(encoder); err_free_connector: drm_connector_cleanup(connector); err_free: kfree(sou); return ret; }
/** * drm_writeback_connector_init - Initialize a writeback connector and its properties * @dev: DRM device * @wb_connector: Writeback connector to initialize * @con_funcs: Connector funcs vtable * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder * @formats: Array of supported pixel formats for the writeback engine * @n_formats: Length of the formats array * * This function creates the writeback-connector-specific properties if they * have not been already created, initializes the connector as * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property * values. It will also create an internal encoder associated with the * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for * the encoder helper. * * Drivers should always use this function instead of drm_connector_init() to * set up writeback connectors. * * Returns: 0 on success, or a negative error code */ int drm_writeback_connector_init(struct drm_device *dev, struct drm_writeback_connector *wb_connector, const struct drm_connector_funcs *con_funcs, const struct drm_encoder_helper_funcs *enc_helper_funcs, const u32 *formats, int n_formats) { struct drm_property_blob *blob; struct drm_connector *connector = &wb_connector->base; struct drm_mode_config *config = &dev->mode_config; int ret = create_writeback_properties(dev); if (ret != 0) return ret; blob = drm_property_create_blob(dev, n_formats * sizeof(*formats), formats); if (IS_ERR(blob)) return PTR_ERR(blob); drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs); ret = drm_encoder_init(dev, &wb_connector->encoder, &drm_writeback_encoder_funcs, DRM_MODE_ENCODER_VIRTUAL, NULL); if (ret) goto fail; connector->interlace_allowed = 0; ret = drm_connector_init(dev, connector, con_funcs, DRM_MODE_CONNECTOR_WRITEBACK); if (ret) goto connector_fail; ret = drm_connector_attach_encoder(connector, &wb_connector->encoder); if (ret) goto attach_fail; INIT_LIST_HEAD(&wb_connector->job_queue); spin_lock_init(&wb_connector->job_lock); wb_connector->fence_context = dma_fence_context_alloc(1); spin_lock_init(&wb_connector->fence_lock); snprintf(wb_connector->timeline_name, sizeof(wb_connector->timeline_name), "CONNECTOR:%d-%s", connector->base.id, connector->name); drm_object_attach_property(&connector->base, config->writeback_out_fence_ptr_property, 0); drm_object_attach_property(&connector->base, config->writeback_fb_id_property, 0); drm_object_attach_property(&connector->base, config->writeback_pixel_formats_property, blob->base.id); wb_connector->pixel_formats_blob_ptr = blob; return 0; attach_fail: drm_connector_cleanup(connector); connector_fail: drm_encoder_cleanup(&wb_connector->encoder); fail: drm_property_blob_put(blob); return ret; }