// SPDX-License-Identifier: GPL-2.0-only /************************************************************************** * Copyright (c) 2007-2011, Intel Corporation. * All Rights Reserved. * **************************************************************************/ #include #include #include #include "framebuffer.h" #include "psb_drv.h" static const struct drm_framebuffer_funcs psb_fb_funcs = { .destroy = drm_gem_fb_destroy, .create_handle = drm_gem_fb_create_handle, }; /** * psb_framebuffer_init - initialize a framebuffer * @dev: our DRM device * @fb: framebuffer to set up * @mode_cmd: mode description * @obj: backing object * * Configure and fill in the boilerplate for our frame buffer. Return * 0 on success or an error code if we fail. */ static int psb_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { const struct drm_format_info *info; int ret; /* * Reject unknown formats, YUV formats, and formats with more than * 4 bytes per pixel. */ info = drm_get_format_info(dev, mode_cmd); if (!info || !info->depth || info->cpp[0] > 4) return -EINVAL; if (mode_cmd->pitches[0] & 63) return -EINVAL; drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); fb->obj[0] = obj; ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs); if (ret) { dev_err(dev->dev, "framebuffer init failed: %d\n", ret); return ret; } return 0; } /** * psb_framebuffer_create - create a framebuffer backed by gt * @dev: our DRM device * @mode_cmd: the description of the requested mode * @obj: the backing object * * Create a framebuffer object backed by the gt, and fill in the * boilerplate required * * TODO: review object references */ struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { struct drm_framebuffer *fb; int ret; fb = kzalloc(sizeof(*fb), GFP_KERNEL); if (!fb) return ERR_PTR(-ENOMEM); ret = psb_framebuffer_init(dev, fb, mode_cmd, obj); if (ret) { kfree(fb); return ERR_PTR(ret); } return fb; } /** * psb_user_framebuffer_create - create framebuffer * @dev: our DRM device * @filp: client file * @cmd: mode request * * Create a new framebuffer backed by a userspace GEM object */ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, const struct drm_mode_fb_cmd2 *cmd) { struct drm_gem_object *obj; struct drm_framebuffer *fb; /* * Find the GEM object and thus the gtt range object that is * to back this space */ obj = drm_gem_object_lookup(filp, cmd->handles[0]); if (obj == NULL) return ERR_PTR(-ENOENT); /* Let the core code do all the work */ fb = psb_framebuffer_create(dev, cmd, obj); if (IS_ERR(fb)) drm_gem_object_put(obj); return fb; } static const struct drm_mode_config_funcs psb_mode_funcs = { .fb_create = psb_user_framebuffer_create, }; static void psb_setup_outputs(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct drm_connector_list_iter conn_iter; struct drm_connector *connector; drm_mode_create_scaling_mode_property(dev); /* It is ok for this to fail - we just don't get backlight control */ if (!dev_priv->backlight_property) dev_priv->backlight_property = drm_property_create_range(dev, 0, "backlight", 0, 100); dev_priv->ops->output_init(dev); drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { struct gma_encoder *gma_encoder = gma_attached_encoder(connector); struct drm_encoder *encoder = &gma_encoder->base; int crtc_mask = 0, clone_mask = 0; /* valid crtcs */ switch (gma_encoder->type) { case INTEL_OUTPUT_ANALOG: crtc_mask = (1 << 0); clone_mask = (1 << INTEL_OUTPUT_ANALOG); break; case INTEL_OUTPUT_SDVO: crtc_mask = dev_priv->ops->sdvo_mask; clone_mask = 0; break; case INTEL_OUTPUT_LVDS: crtc_mask = dev_priv->ops->lvds_mask; clone_mask = 0; break; case INTEL_OUTPUT_MIPI: crtc_mask = (1 << 0); clone_mask = 0; break; case INTEL_OUTPUT_MIPI2: crtc_mask = (1 << 2); clone_mask = 0; break; case INTEL_OUTPUT_HDMI: crtc_mask = dev_priv->ops->hdmi_mask; clone_mask = (1 << INTEL_OUTPUT_HDMI); break; case INTEL_OUTPUT_DISPLAYPORT: crtc_mask = (1 << 0) | (1 << 1); clone_mask = 0; break; case INTEL_OUTPUT_EDP: crtc_mask = (1 << 1); clone_mask = 0; } encoder->possible_crtcs = crtc_mask; encoder->possible_clones = gma_connector_clones(dev, clone_mask); } drm_connector_list_iter_end(&conn_iter); } void psb_modeset_init(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int i; if (drmm_mode_config_init(dev)) return; dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; dev->mode_config.funcs = &psb_mode_funcs; /* num pipes is 2 for PSB but 1 for Mrst */ for (i = 0; i < dev_priv->num_pipe; i++) psb_intel_crtc_init(dev, i, mode_dev); dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; psb_setup_outputs(dev); if (dev_priv->ops->errata) dev_priv->ops->errata(dev); dev_priv->modeset = true; } void psb_modeset_cleanup(struct drm_device *dev) { struct drm_psb_private *dev_priv = to_drm_psb_private(dev); if (dev_priv->modeset) { drm_kms_helper_poll_fini(dev); } }