1 // SPDX-License-Identifier: GPL-2.0-only 2 /************************************************************************** 3 * Copyright (c) 2007-2011, Intel Corporation. 4 * All Rights Reserved. 5 * 6 **************************************************************************/ 7 8 #include <drm/drm_framebuffer.h> 9 #include <drm/drm_gem_framebuffer_helper.h> 10 #include <drm/drm_modeset_helper.h> 11 12 #include "framebuffer.h" 13 #include "psb_drv.h" 14 15 static const struct drm_framebuffer_funcs psb_fb_funcs = { 16 .destroy = drm_gem_fb_destroy, 17 .create_handle = drm_gem_fb_create_handle, 18 }; 19 20 /** 21 * psb_framebuffer_init - initialize a framebuffer 22 * @dev: our DRM device 23 * @fb: framebuffer to set up 24 * @mode_cmd: mode description 25 * @obj: backing object 26 * 27 * Configure and fill in the boilerplate for our frame buffer. Return 28 * 0 on success or an error code if we fail. 29 */ 30 static int psb_framebuffer_init(struct drm_device *dev, 31 struct drm_framebuffer *fb, 32 const struct drm_format_info *info, 33 const struct drm_mode_fb_cmd2 *mode_cmd, 34 struct drm_gem_object *obj) 35 { 36 int ret; 37 38 /* 39 * Reject unknown formats, YUV formats, and formats with more than 40 * 4 bytes per pixel. 41 */ 42 if (!info->depth || info->cpp[0] > 4) 43 return -EINVAL; 44 45 if (mode_cmd->pitches[0] & 63) 46 return -EINVAL; 47 48 drm_helper_mode_fill_fb_struct(dev, fb, info, mode_cmd); 49 fb->obj[0] = obj; 50 ret = drm_framebuffer_init(dev, fb, &psb_fb_funcs); 51 if (ret) { 52 dev_err(dev->dev, "framebuffer init failed: %d\n", ret); 53 return ret; 54 } 55 return 0; 56 } 57 58 /** 59 * psb_framebuffer_create - create a framebuffer backed by gt 60 * @dev: our DRM device 61 * @info: pixel format information 62 * @mode_cmd: the description of the requested mode 63 * @obj: the backing object 64 * 65 * Create a framebuffer object backed by the gt, and fill in the 66 * boilerplate required 67 * 68 * TODO: review object references 69 */ 70 struct drm_framebuffer *psb_framebuffer_create(struct drm_device *dev, 71 const struct drm_format_info *info, 72 const struct drm_mode_fb_cmd2 *mode_cmd, 73 struct drm_gem_object *obj) 74 { 75 struct drm_framebuffer *fb; 76 int ret; 77 78 fb = kzalloc(sizeof(*fb), GFP_KERNEL); 79 if (!fb) 80 return ERR_PTR(-ENOMEM); 81 82 ret = psb_framebuffer_init(dev, fb, info, mode_cmd, obj); 83 if (ret) { 84 kfree(fb); 85 return ERR_PTR(ret); 86 } 87 return fb; 88 } 89 90 /** 91 * psb_user_framebuffer_create - create framebuffer 92 * @dev: our DRM device 93 * @filp: client file 94 * @cmd: mode request 95 * 96 * Create a new framebuffer backed by a userspace GEM object 97 */ 98 static struct drm_framebuffer *psb_user_framebuffer_create 99 (struct drm_device *dev, struct drm_file *filp, 100 const struct drm_format_info *info, 101 const struct drm_mode_fb_cmd2 *cmd) 102 { 103 struct drm_gem_object *obj; 104 struct drm_framebuffer *fb; 105 106 /* 107 * Find the GEM object and thus the gtt range object that is 108 * to back this space 109 */ 110 obj = drm_gem_object_lookup(filp, cmd->handles[0]); 111 if (obj == NULL) 112 return ERR_PTR(-ENOENT); 113 114 /* Let the core code do all the work */ 115 fb = psb_framebuffer_create(dev, info, cmd, obj); 116 if (IS_ERR(fb)) 117 drm_gem_object_put(obj); 118 119 return fb; 120 } 121 122 static const struct drm_mode_config_funcs psb_mode_funcs = { 123 .fb_create = psb_user_framebuffer_create, 124 }; 125 126 static void psb_setup_outputs(struct drm_device *dev) 127 { 128 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 129 struct drm_connector_list_iter conn_iter; 130 struct drm_connector *connector; 131 132 drm_mode_create_scaling_mode_property(dev); 133 134 /* It is ok for this to fail - we just don't get backlight control */ 135 if (!dev_priv->backlight_property) 136 dev_priv->backlight_property = drm_property_create_range(dev, 0, 137 "backlight", 0, 100); 138 dev_priv->ops->output_init(dev); 139 140 drm_connector_list_iter_begin(dev, &conn_iter); 141 drm_for_each_connector_iter(connector, &conn_iter) { 142 struct gma_encoder *gma_encoder = gma_attached_encoder(connector); 143 struct drm_encoder *encoder = &gma_encoder->base; 144 int crtc_mask = 0, clone_mask = 0; 145 146 /* valid crtcs */ 147 switch (gma_encoder->type) { 148 case INTEL_OUTPUT_ANALOG: 149 crtc_mask = (1 << 0); 150 clone_mask = (1 << INTEL_OUTPUT_ANALOG); 151 break; 152 case INTEL_OUTPUT_SDVO: 153 crtc_mask = dev_priv->ops->sdvo_mask; 154 clone_mask = 0; 155 break; 156 case INTEL_OUTPUT_LVDS: 157 crtc_mask = dev_priv->ops->lvds_mask; 158 clone_mask = 0; 159 break; 160 case INTEL_OUTPUT_MIPI: 161 crtc_mask = (1 << 0); 162 clone_mask = 0; 163 break; 164 case INTEL_OUTPUT_MIPI2: 165 crtc_mask = (1 << 2); 166 clone_mask = 0; 167 break; 168 case INTEL_OUTPUT_HDMI: 169 crtc_mask = dev_priv->ops->hdmi_mask; 170 clone_mask = (1 << INTEL_OUTPUT_HDMI); 171 break; 172 case INTEL_OUTPUT_DISPLAYPORT: 173 crtc_mask = (1 << 0) | (1 << 1); 174 clone_mask = 0; 175 break; 176 case INTEL_OUTPUT_EDP: 177 crtc_mask = (1 << 1); 178 clone_mask = 0; 179 } 180 encoder->possible_crtcs = crtc_mask; 181 encoder->possible_clones = 182 gma_connector_clones(dev, clone_mask); 183 } 184 drm_connector_list_iter_end(&conn_iter); 185 } 186 187 void psb_modeset_init(struct drm_device *dev) 188 { 189 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 190 struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; 191 int i; 192 193 if (drmm_mode_config_init(dev)) 194 return; 195 196 dev->mode_config.min_width = 0; 197 dev->mode_config.min_height = 0; 198 199 dev->mode_config.funcs = &psb_mode_funcs; 200 201 /* num pipes is 2 for PSB but 1 for Mrst */ 202 for (i = 0; i < dev_priv->num_pipe; i++) 203 psb_intel_crtc_init(dev, i, mode_dev); 204 205 dev->mode_config.max_width = 4096; 206 dev->mode_config.max_height = 4096; 207 208 psb_setup_outputs(dev); 209 210 if (dev_priv->ops->errata) 211 dev_priv->ops->errata(dev); 212 213 dev_priv->modeset = true; 214 } 215 216 void psb_modeset_cleanup(struct drm_device *dev) 217 { 218 struct drm_psb_private *dev_priv = to_drm_psb_private(dev); 219 if (dev_priv->modeset) { 220 drm_kms_helper_poll_fini(dev); 221 } 222 } 223