blob: 74fec09f474028751932901c29f2bf32b2004639 [file] [log] [blame]
Rob Clark487687e2011-07-17 17:29:02 -05001/*
2 * Copyright © 2007 Red Hat, Inc.
3 * Copyright © 2008 Maarten Maathuis
4 * Copyright © 2011 Texas Instruments, Inc
5 *
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 * Authors:
27 * Dave Airlie <airlied@redhat.com>
28 * Ian Elliott <ianelliottus@yahoo.com>
29 */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
Rob Clark487687e2011-07-17 17:29:02 -050035#include "xf86DDC.h"
Dave Barnishf256ebe2013-08-22 15:05:58 +010036#include "xf86RandR12.h"
Rob Clark487687e2011-07-17 17:29:02 -050037
Rob Clark487687e2011-07-17 17:29:02 -050038#ifdef HAVE_XEXTPROTO_71
39#include <X11/extensions/dpmsconst.h>
40#else
41#define DPMS_SERVER
42#include <X11/extensions/dpms.h>
43#endif
44
Paul Gearyf8b99692013-04-15 10:55:17 +010045#include "armsoc_driver.h"
Rob Clark487687e2011-07-17 17:29:02 -050046
Rob Clark487687e2011-07-17 17:29:02 -050047#include "xf86drmMode.h"
Rob Clark687c6082012-01-08 19:33:18 -060048#include "drm_fourcc.h"
Rob Clark487687e2011-07-17 17:29:02 -050049#include "X11/Xatom.h"
50
Rob Clark487687e2011-07-17 17:29:02 -050051#include <libudev.h>
Ray Smith3c33c3d2013-03-26 16:06:37 +000052#include "drmmode_driver.h"
53
Dave Barnish2e998952013-06-11 16:31:10 +010054struct drmmode_cursor_rec {
Rob Clark687c6082012-01-08 19:33:18 -060055 /* hardware cursor: */
Paul Geary8ffd91c2013-04-11 16:03:15 +010056 struct armsoc_bo *bo;
Rob Clark687c6082012-01-08 19:33:18 -060057 int x, y;
Javier Martin4c572792013-09-11 15:08:19 +010058 /* These are used for HWCURSOR_API_PLANE */
59 drmModePlane *ovr;
60 uint32_t fb_id;
61 /* This is used for HWCURSOR_API_STANDARD */
62 uint32_t handle;
Dave Barnish2e998952013-06-11 16:31:10 +010063};
Rob Clark687c6082012-01-08 19:33:18 -060064
Dave Barnish2e998952013-06-11 16:31:10 +010065struct drmmode_rec {
Rob Clark74210d52012-01-08 17:59:08 -060066 int fd;
Rob Clark74210d52012-01-08 17:59:08 -060067 drmModeResPtr mode_res;
68 int cpp;
69 struct udev_monitor *uevent_monitor;
70 InputHandlerProc uevent_handler;
Dave Barnish2e998952013-06-11 16:31:10 +010071 struct drmmode_cursor_rec *cursor;
72};
Rob Clark487687e2011-07-17 17:29:02 -050073
Dave Barnish2e998952013-06-11 16:31:10 +010074struct drmmode_crtc_private_rec {
75 struct drmmode_rec *drmmode;
Dave Barnish6a1b31e2013-09-25 11:09:05 +010076 uint32_t crtc_id;
Stéphane Marchesinb8b35202012-10-02 20:27:40 -070077 int cursor_visible;
Dave Barnishf245da32013-08-30 12:16:58 +010078 /* settings retained on last good modeset */
79 int last_good_x;
80 int last_good_y;
81 Rotation last_good_rotation;
82 DisplayModePtr last_good_mode;
Dave Barnish2e998952013-06-11 16:31:10 +010083};
Rob Clark487687e2011-07-17 17:29:02 -050084
Dave Barnish2e998952013-06-11 16:31:10 +010085struct drmmode_prop_rec {
Rob Clark487687e2011-07-17 17:29:02 -050086 drmModePropertyPtr mode_prop;
Dave Barnish2e998952013-06-11 16:31:10 +010087 /* Index within the kernel-side property arrays for this connector. */
88 int index;
89 /* if range prop, num_atoms == 1;
90 * if enum prop, num_atoms == num_enums + 1
91 */
92 int num_atoms;
Rob Clark487687e2011-07-17 17:29:02 -050093 Atom *atoms;
Dave Barnish2e998952013-06-11 16:31:10 +010094};
Rob Clark487687e2011-07-17 17:29:02 -050095
Dave Barnish2e998952013-06-11 16:31:10 +010096struct drmmode_output_priv {
97 struct drmmode_rec *drmmode;
Rob Clark74210d52012-01-08 17:59:08 -060098 int output_id;
Dave Barnish70df8ae2013-09-26 12:44:27 +010099 drmModeConnectorPtr connector;
100 drmModeEncoderPtr *encoders;
Rob Clark74210d52012-01-08 17:59:08 -0600101 drmModePropertyBlobPtr edid_blob;
102 int num_props;
Dave Barnish2e998952013-06-11 16:31:10 +0100103 struct drmmode_prop_rec *props;
Dave Barnish70df8ae2013-09-26 12:44:27 +0100104 int enc_mask; /* encoders present (mask of encoder indices) */
105 int enc_clones; /* encoder clones possible (mask of encoder indices) */
Dave Barnish2e998952013-06-11 16:31:10 +0100106};
Rob Clark487687e2011-07-17 17:29:02 -0500107
108static void drmmode_output_dpms(xf86OutputPtr output, int mode);
Dave Barnishf245da32013-08-30 12:16:58 +0100109static Bool resize_scanout_bo(ScrnInfoPtr pScrn, int width, int height);
Rob Clark487687e2011-07-17 17:29:02 -0500110
Dave Barnish2e998952013-06-11 16:31:10 +0100111static struct drmmode_rec *
Rob Clark687c6082012-01-08 19:33:18 -0600112drmmode_from_scrn(ScrnInfoPtr pScrn)
113{
114 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
Dave Barnish2e998952013-06-11 16:31:10 +0100115 struct drmmode_crtc_private_rec *drmmode_crtc;
Rob Clark687c6082012-01-08 19:33:18 -0600116
117 drmmode_crtc = xf86_config->crtc[0]->driver_private;
118 return drmmode_crtc->drmmode;
119}
120
Rob Clark487687e2011-07-17 17:29:02 -0500121static void
122drmmode_ConvertFromKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600123 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500124{
Rob Clark74210d52012-01-08 17:59:08 -0600125 memset(mode, 0, sizeof(DisplayModeRec));
126 mode->status = MODE_OK;
Rob Clark487687e2011-07-17 17:29:02 -0500127
Rob Clark74210d52012-01-08 17:59:08 -0600128 mode->Clock = kmode->clock;
Rob Clark487687e2011-07-17 17:29:02 -0500129
Rob Clark74210d52012-01-08 17:59:08 -0600130 mode->HDisplay = kmode->hdisplay;
131 mode->HSyncStart = kmode->hsync_start;
132 mode->HSyncEnd = kmode->hsync_end;
133 mode->HTotal = kmode->htotal;
134 mode->HSkew = kmode->hskew;
Rob Clark487687e2011-07-17 17:29:02 -0500135
Rob Clark74210d52012-01-08 17:59:08 -0600136 mode->VDisplay = kmode->vdisplay;
137 mode->VSyncStart = kmode->vsync_start;
138 mode->VSyncEnd = kmode->vsync_end;
139 mode->VTotal = kmode->vtotal;
140 mode->VScan = kmode->vscan;
Rob Clark487687e2011-07-17 17:29:02 -0500141
Dave Barnish01b5c172013-04-10 11:01:17 +0100142 mode->Flags = kmode->flags;
Rob Clark74210d52012-01-08 17:59:08 -0600143 mode->name = strdup(kmode->name);
Rob Clark487687e2011-07-17 17:29:02 -0500144
Rob Clark74210d52012-01-08 17:59:08 -0600145 DEBUG_MSG("copy mode %s (%p %p)", kmode->name, mode->name, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500146
Rob Clark74210d52012-01-08 17:59:08 -0600147 if (kmode->type & DRM_MODE_TYPE_DRIVER)
148 mode->type = M_T_DRIVER;
Dave Barnish2e998952013-06-11 16:31:10 +0100149
Rob Clark74210d52012-01-08 17:59:08 -0600150 if (kmode->type & DRM_MODE_TYPE_PREFERRED)
151 mode->type |= M_T_PREFERRED;
Rob Clark487687e2011-07-17 17:29:02 -0500152
Dave Barnish2e998952013-06-11 16:31:10 +0100153 xf86SetModeCrtc(mode, pScrn->adjustFlags);
Rob Clark74210d52012-01-08 17:59:08 -0600154}
Rob Clark487687e2011-07-17 17:29:02 -0500155
156static void
157drmmode_ConvertToKMode(ScrnInfoPtr pScrn, drmModeModeInfo *kmode,
Rob Clark74210d52012-01-08 17:59:08 -0600158 DisplayModePtr mode)
Rob Clark487687e2011-07-17 17:29:02 -0500159{
Rob Clark74210d52012-01-08 17:59:08 -0600160 memset(kmode, 0, sizeof(*kmode));
Rob Clark487687e2011-07-17 17:29:02 -0500161
Rob Clark74210d52012-01-08 17:59:08 -0600162 kmode->clock = mode->Clock;
163 kmode->hdisplay = mode->HDisplay;
164 kmode->hsync_start = mode->HSyncStart;
165 kmode->hsync_end = mode->HSyncEnd;
166 kmode->htotal = mode->HTotal;
167 kmode->hskew = mode->HSkew;
Rob Clark487687e2011-07-17 17:29:02 -0500168
Rob Clark74210d52012-01-08 17:59:08 -0600169 kmode->vdisplay = mode->VDisplay;
170 kmode->vsync_start = mode->VSyncStart;
171 kmode->vsync_end = mode->VSyncEnd;
172 kmode->vtotal = mode->VTotal;
173 kmode->vscan = mode->VScan;
Rob Clark487687e2011-07-17 17:29:02 -0500174
Dave Barnish01b5c172013-04-10 11:01:17 +0100175 kmode->flags = mode->Flags;
Rob Clark74210d52012-01-08 17:59:08 -0600176 if (mode->name)
177 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
178 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
179}
Rob Clark487687e2011-07-17 17:29:02 -0500180
181static void
182drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
183{
Dave Barnish2e998952013-06-11 16:31:10 +0100184 /* TODO: MIDEGL-1431: Implement this function */
Rob Clark74210d52012-01-08 17:59:08 -0600185}
Rob Clark487687e2011-07-17 17:29:02 -0500186
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100187static int
188drmmode_revert_mode(xf86CrtcPtr crtc, uint32_t *output_ids, int output_count)
189{
190 ScrnInfoPtr pScrn = crtc->scrn;
191 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
192 uint32_t fb_id;
193 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
194 drmModeModeInfo kmode;
195
196 if (!drmmode_crtc->last_good_mode) {
197 DEBUG_MSG("No last good values to use");
198 return FALSE;
199 }
200
201 /* revert to last good settings */
202 DEBUG_MSG("Reverting to last_good values");
203 if (!resize_scanout_bo(pScrn,
204 drmmode_crtc->last_good_mode->HDisplay,
205 drmmode_crtc->last_good_mode->VDisplay)) {
206 ERROR_MSG("Could not revert to last good mode");
207 return FALSE;
208 }
209
210 fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
211 drmmode_ConvertToKMode(crtc->scrn, &kmode,
212 drmmode_crtc->last_good_mode);
213 drmModeSetCrtc(drmmode_crtc->drmmode->fd,
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100214 drmmode_crtc->crtc_id,
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100215 fb_id,
216 drmmode_crtc->last_good_x,
217 drmmode_crtc->last_good_y,
218 output_ids, output_count, &kmode);
219
220 /* let RandR know we changed things */
221 xf86RandR12TellChanged(pScrn->pScreen);
222
223 return TRUE;
224}
225
Rob Clark487687e2011-07-17 17:29:02 -0500226static Bool
227drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rob Clark74210d52012-01-08 17:59:08 -0600228 Rotation rotation, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -0500229{
230 ScrnInfoPtr pScrn = crtc->scrn;
Dave Barnish2e998952013-06-11 16:31:10 +0100231 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -0500232 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
Dave Barnish2e998952013-06-11 16:31:10 +0100233 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
234 struct drmmode_rec *drmmode = drmmode_crtc->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -0500235 uint32_t *output_ids = NULL;
236 int output_count = 0;
237 int ret = TRUE;
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100238 int err;
Rob Clark487687e2011-07-17 17:29:02 -0500239 int i;
David Garbett7171c522012-05-11 13:12:50 +0100240 uint32_t fb_id;
Rob Clark487687e2011-07-17 17:29:02 -0500241 drmModeModeInfo kmode;
Dave Barnishf256ebe2013-08-22 15:05:58 +0100242 drmModeCrtcPtr newcrtc = NULL;
Rob Clark487687e2011-07-17 17:29:02 -0500243
244 TRACE_ENTER();
245
Paul Geary8ffd91c2013-04-11 16:03:15 +0100246 fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
David Garbett7171c522012-05-11 13:12:50 +0100247
248 if (fb_id == 0) {
David Garbett7171c522012-05-11 13:12:50 +0100249 DEBUG_MSG("create framebuffer: %dx%d",
250 pScrn->virtualX, pScrn->virtualY);
251
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100252 err = armsoc_bo_add_fb(pARMSOC->scanout);
253 if (err) {
Ray Smithb4299f82013-03-13 10:08:36 +0000254 ERROR_MSG(
255 "Failed to add framebuffer to the scanout buffer");
David Garbett7171c522012-05-11 13:12:50 +0100256 return FALSE;
Ray Smithb4299f82013-03-13 10:08:36 +0000257 }
Dave Barnish523c9ff2013-03-12 10:59:03 +0000258
Paul Geary8ffd91c2013-04-11 16:03:15 +0100259 fb_id = armsoc_bo_get_fb(pARMSOC->scanout);
Paul Geary6fe52f32013-04-03 11:12:24 +0100260 if (0 == fb_id)
261 return FALSE;
David Garbett7171c522012-05-11 13:12:50 +0100262 }
Rob Clark487687e2011-07-17 17:29:02 -0500263
Rob Clark487687e2011-07-17 17:29:02 -0500264 /* Set the new mode: */
265 crtc->mode = *mode;
266 crtc->x = x;
267 crtc->y = y;
268 crtc->rotation = rotation;
269
270 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
271 if (!output_ids) {
Dave Barnishf256ebe2013-08-22 15:05:58 +0100272 ERROR_MSG(
273 "memory allocation failed in drmmode_set_mode_major()");
Rob Clark487687e2011-07-17 17:29:02 -0500274 ret = FALSE;
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100275 goto cleanup;
Rob Clark487687e2011-07-17 17:29:02 -0500276 }
277
278 for (i = 0; i < xf86_config->num_output; i++) {
279 xf86OutputPtr output = xf86_config->output[i];
Dave Barnish2e998952013-06-11 16:31:10 +0100280 struct drmmode_output_priv *drmmode_output;
Rob Clark487687e2011-07-17 17:29:02 -0500281
282 if (output->crtc != crtc)
283 continue;
284
285 drmmode_output = output->driver_private;
286 output_ids[output_count] =
Dave Barnish70df8ae2013-09-26 12:44:27 +0100287 drmmode_output->connector->connector_id;
Rob Clark487687e2011-07-17 17:29:02 -0500288 output_count++;
289 }
290
Dave Barnish2e998952013-06-11 16:31:10 +0100291 if (!xf86CrtcRotate(crtc)) {
Dave Barnishf256ebe2013-08-22 15:05:58 +0100292 ERROR_MSG(
293 "failed to assign rotation in drmmode_set_mode_major()");
Dave Barnish523c9ff2013-03-12 10:59:03 +0000294 ret = FALSE;
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100295 goto cleanup;
Dave Barnish523c9ff2013-03-12 10:59:03 +0000296 }
Rob Clark487687e2011-07-17 17:29:02 -0500297
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200298 if (crtc->funcs->gamma_set)
299 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
300 crtc->gamma_blue, crtc->gamma_size);
Rob Clark487687e2011-07-17 17:29:02 -0500301
302 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
303
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100304 err = drmModeSetCrtc(drmmode->fd, drmmode_crtc->crtc_id,
Rob Clark487687e2011-07-17 17:29:02 -0500305 fb_id, x, y, output_ids, output_count, &kmode);
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100306 if (err) {
Dave Barnishf256ebe2013-08-22 15:05:58 +0100307 ERROR_MSG(
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100308 "drm failed to set mode: %s", strerror(-err));
309
Dave Barnish523c9ff2013-03-12 10:59:03 +0000310 ret = FALSE;
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100311 if (!drmmode_revert_mode(crtc, output_ids, output_count))
312 goto cleanup;
313 else
314 goto done_setting;
Dave Barnishf256ebe2013-08-22 15:05:58 +0100315 }
316
317 /* get the actual crtc info */
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100318 newcrtc = drmModeGetCrtc(drmmode->fd, drmmode_crtc->crtc_id);
Dave Barnishf256ebe2013-08-22 15:05:58 +0100319 if (!newcrtc) {
320 ERROR_MSG("couldn't get actual mode back");
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100321
Dave Barnishf256ebe2013-08-22 15:05:58 +0100322 ret = FALSE;
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100323 if (!drmmode_revert_mode(crtc, output_ids, output_count))
324 goto cleanup;
325 else
326 goto done_setting;
Dave Barnishf256ebe2013-08-22 15:05:58 +0100327 }
328
329 if (kmode.hdisplay != newcrtc->mode.hdisplay ||
330 kmode.vdisplay != newcrtc->mode.vdisplay) {
331
Dave Barnishf256ebe2013-08-22 15:05:58 +0100332 ERROR_MSG(
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100333 "drm did not set requested mode! (requested %dx%d, actual %dx%d)",
334 kmode.hdisplay, kmode.vdisplay,
335 newcrtc->mode.hdisplay,
336 newcrtc->mode.vdisplay);
Dave Barnishf256ebe2013-08-22 15:05:58 +0100337
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100338 ret = FALSE;
339 if (!drmmode_revert_mode(crtc, output_ids, output_count))
340 goto cleanup;
341 else
342 goto done_setting;
Rob Clark487687e2011-07-17 17:29:02 -0500343 }
344
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100345 /* When called on a resize, crtc->mode already contains the
346 * resized values so we can't use this for recovery.
347 * We can't read it out of the crtc either as mode_valid is 0.
348 * Instead we save the last good mode set here & fallback to
349 * that on failure.
350 */
351 DEBUG_MSG("Saving last good values");
352 drmmode_crtc->last_good_x = crtc->x;
353 drmmode_crtc->last_good_y = crtc->y;
354 drmmode_crtc->last_good_rotation = crtc->rotation;
355 if (drmmode_crtc->last_good_mode) {
356 if (drmmode_crtc->last_good_mode->name)
357 free(drmmode_crtc->last_good_mode->name);
358 free(drmmode_crtc->last_good_mode);
359 }
360 drmmode_crtc->last_good_mode = xf86DuplicateMode(&crtc->mode);
361
362 ret = TRUE;
363
364done_setting:
Rob Clark487687e2011-07-17 17:29:02 -0500365 /* Turn on any outputs on this crtc that may have been disabled: */
366 for (i = 0; i < xf86_config->num_output; i++) {
367 xf86OutputPtr output = xf86_config->output[i];
368
369 if (output->crtc != crtc)
370 continue;
371
372 drmmode_output_dpms(output, DPMSModeOn);
373 }
374
Dave Barnishaf046152013-05-31 09:12:44 +0100375 /* if hw cursor is initialized, reload it */
Dave Barnish2e998952013-06-11 16:31:10 +0100376 if (drmmode->cursor)
Dave Barnishaf046152013-05-31 09:12:44 +0100377 xf86_reload_cursors(pScrn->pScreen);
Rob Clark487687e2011-07-17 17:29:02 -0500378
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100379cleanup:
Dave Barnishf256ebe2013-08-22 15:05:58 +0100380 if (newcrtc)
381 drmModeFreeCrtc(newcrtc);
382
Dave Barnish2e998952013-06-11 16:31:10 +0100383 if (output_ids)
Rob Clark487687e2011-07-17 17:29:02 -0500384 free(output_ids);
Dave Barnish2e998952013-06-11 16:31:10 +0100385
Dave Barnishf245da32013-08-30 12:16:58 +0100386 if (!ret && !drmmode_crtc->last_good_mode) {
Dave Barnishf256ebe2013-08-22 15:05:58 +0100387 /* If there was a problem, restore the last good mode: */
Dave Barnishf245da32013-08-30 12:16:58 +0100388 crtc->x = drmmode_crtc->last_good_x;
389 crtc->y = drmmode_crtc->last_good_y;
390 crtc->rotation = drmmode_crtc->last_good_rotation;
391 crtc->mode = *drmmode_crtc->last_good_mode;
Rob Clark487687e2011-07-17 17:29:02 -0500392 }
393
394 TRACE_EXIT();
395 return ret;
Rob Clark74210d52012-01-08 17:59:08 -0600396}
Rob Clark487687e2011-07-17 17:29:02 -0500397
398static void
Rob Clark487687e2011-07-17 17:29:02 -0500399drmmode_hide_cursor(xf86CrtcPtr crtc)
400{
Dave Barnish2e998952013-06-11 16:31:10 +0100401 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
402 struct drmmode_rec *drmmode = drmmode_crtc->drmmode;
403 struct drmmode_cursor_rec *cursor = drmmode->cursor;
Javier Martin4c572792013-09-11 15:08:19 +0100404 ScrnInfoPtr pScrn = crtc->scrn;
405 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -0500406
Rob Clark687c6082012-01-08 19:33:18 -0600407 if (!cursor)
408 return;
409
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700410 drmmode_crtc->cursor_visible = FALSE;
Rob Clark687c6082012-01-08 19:33:18 -0600411
Javier Martin4c572792013-09-11 15:08:19 +0100412 if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE) {
413 /* set plane's fb_id to 0 to disable it */
414 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100415 drmmode_crtc->crtc_id, 0, 0,
Javier Martin4c572792013-09-11 15:08:19 +0100416 0, 0, 0, 0, 0, 0, 0, 0);
417 } else { /* HWCURSOR_API_STANDARD */
418 /* set handle to 0 to disable the cursor */
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100419 drmModeSetCursor(drmmode->fd, drmmode_crtc->crtc_id,
Javier Martin4c572792013-09-11 15:08:19 +0100420 0, 0, 0);
421 }
Rob Clark74210d52012-01-08 17:59:08 -0600422}
Rob Clark487687e2011-07-17 17:29:02 -0500423
Javier Martin4c572792013-09-11 15:08:19 +0100424/*
425 * The argument "update_image" controls whether the cursor image needs
426 * to be updated by the HW or not. This is ignored by HWCURSOR_API_PLANE
427 * which doesn't allow changing the cursor possition without updating
428 * the image too.
429 */
Rob Clark487687e2011-07-17 17:29:02 -0500430static void
Javier Martin4c572792013-09-11 15:08:19 +0100431drmmode_show_cursor_image(xf86CrtcPtr crtc, Bool update_image)
Rob Clark487687e2011-07-17 17:29:02 -0500432{
Dave Barnish2e998952013-06-11 16:31:10 +0100433 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
434 struct drmmode_rec *drmmode = drmmode_crtc->drmmode;
435 struct drmmode_cursor_rec *cursor = drmmode->cursor;
Dave Barnishde45ed42013-06-05 13:47:56 +0100436 int crtc_x, crtc_y, src_x, src_y;
437 int w, h, pad;
438 ScrnInfoPtr pScrn = crtc->scrn;
Dave Barnish2e998952013-06-11 16:31:10 +0100439 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -0500440
Rob Clark687c6082012-01-08 19:33:18 -0600441 if (!cursor)
442 return;
Rob Clark487687e2011-07-17 17:29:02 -0500443
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700444 drmmode_crtc->cursor_visible = TRUE;
Rob Clark687c6082012-01-08 19:33:18 -0600445
Dave Barnishde45ed42013-06-05 13:47:56 +0100446 w = pARMSOC->drmmode_interface->cursor_width;
447 h = pARMSOC->drmmode_interface->cursor_height;
448 pad = pARMSOC->drmmode_interface->cursor_padding;
449
Dave Barnish2e998952013-06-11 16:31:10 +0100450 /* get padded width */
451 w = w + 2 * pad;
452 /* get x of padded cursor */
453 crtc_x = cursor->x - pad;
Rob Clark60f5bad2012-01-22 18:35:28 -0600454 crtc_y = cursor->y;
Rob Clark60f5bad2012-01-22 18:35:28 -0600455
Javier Martin4c572792013-09-11 15:08:19 +0100456 if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE) {
457 src_x = 0;
458 src_y = 0;
Rob Clark60f5bad2012-01-22 18:35:28 -0600459
Javier Martin4c572792013-09-11 15:08:19 +0100460 /* calculate clipped x, y, w & h if cursor is off edges */
461 if (crtc_x < 0) {
462 src_x += -crtc_x;
463 w -= -crtc_x;
464 crtc_x = 0;
465 }
Rob Clark60f5bad2012-01-22 18:35:28 -0600466
Javier Martin4c572792013-09-11 15:08:19 +0100467 if (crtc_y < 0) {
468 src_y += -crtc_y;
469 h -= -crtc_y;
470 crtc_y = 0;
471 }
Rob Clark60f5bad2012-01-22 18:35:28 -0600472
Javier Martin4c572792013-09-11 15:08:19 +0100473 if ((crtc_x + w) > crtc->mode.HDisplay)
474 w = crtc->mode.HDisplay - crtc_x;
Rob Clark60f5bad2012-01-22 18:35:28 -0600475
Javier Martin4c572792013-09-11 15:08:19 +0100476 if ((crtc_y + h) > crtc->mode.VDisplay)
477 h = crtc->mode.VDisplay - crtc_y;
478
479 /* note src coords (last 4 args) are in Q16 format */
480 drmModeSetPlane(drmmode->fd, cursor->ovr->plane_id,
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100481 drmmode_crtc->crtc_id, cursor->fb_id, 0,
Dave Barnish2e998952013-06-11 16:31:10 +0100482 crtc_x, crtc_y, w, h, src_x<<16, src_y<<16,
483 w<<16, h<<16);
Javier Martin4c572792013-09-11 15:08:19 +0100484 } else {
485 if (update_image)
486 drmModeSetCursor(drmmode->fd,
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100487 drmmode_crtc->crtc_id,
Javier Martin4c572792013-09-11 15:08:19 +0100488 cursor->handle, w, h);
489 drmModeMoveCursor(drmmode->fd,
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100490 drmmode_crtc->crtc_id,
Javier Martin4c572792013-09-11 15:08:19 +0100491 crtc_x, crtc_y);
492 }
493}
494
495static void
496drmmode_show_cursor(xf86CrtcPtr crtc)
497{
498 drmmode_show_cursor_image(crtc, TRUE);
Rob Clark687c6082012-01-08 19:33:18 -0600499}
500
501static void
502drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
503{
Dave Barnish2e998952013-06-11 16:31:10 +0100504 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
505 struct drmmode_rec *drmmode = drmmode_crtc->drmmode;
506 struct drmmode_cursor_rec *cursor = drmmode->cursor;
Rob Clark687c6082012-01-08 19:33:18 -0600507
508 if (!cursor)
509 return;
510
511 cursor->x = x;
512 cursor->y = y;
513
Javier Martin4c572792013-09-11 15:08:19 +0100514 /*
515 * Show the cursor at a different possition without updating the image
516 * when possible (HWCURSOR_API_PLANE doesn't have a way to update
517 * cursor position without updating the image too).
518 */
519 drmmode_show_cursor_image(crtc, FALSE);
Rob Clark687c6082012-01-08 19:33:18 -0600520}
521
Javier Martina7e316f2013-09-16 15:22:41 +0100522/*
523 * The cursor format is ARGB so the image can be copied straight over.
524 * Columns of CURSORPAD blank pixels are maintained down either side
525 * of the destination image. This is a workaround for a bug causing
526 * corruption when the cursor reaches the screen edges in some DRM
527 * drivers.
528 */
529static void set_cursor_image(xf86CrtcPtr crtc, uint32_t *d, CARD32 *s)
530{
531 ScrnInfoPtr pScrn = crtc->scrn;
532 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
533 int row;
534 void *dst;
535 const char *src_row;
536 char *dst_row;
537 uint32_t cursorh = pARMSOC->drmmode_interface->cursor_height;
538 uint32_t cursorw = pARMSOC->drmmode_interface->cursor_width;
539 uint32_t cursorpad = pARMSOC->drmmode_interface->cursor_padding;
540
541 dst = d;
542 for (row = 0; row < cursorh; row += 1) {
543 /* we're operating with ARGB data (4 bytes per pixel) */
544 src_row = (const char *)s + row * 4 * cursorw;
545 dst_row = (char *)dst + row * 4 * (cursorw + 2 * cursorpad);
546
547 /* set first CURSORPAD pixels in row to 0 */
548 memset(dst_row, 0, (4 * cursorpad));
549 /* copy cursor image pixel row across */
550 memcpy(dst_row + (4 * cursorpad), src_row, 4 * cursorw);
551 /* set last CURSORPAD pixels in row to 0 */
552 memset(dst_row + 4 * (cursorpad + cursorw),
553 0, (4 * cursorpad));
554 }
555}
556
Rob Clark687c6082012-01-08 19:33:18 -0600557static void
558drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
559{
Dave Barnish2e998952013-06-11 16:31:10 +0100560 uint32_t *d;
561 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
562 struct drmmode_rec *drmmode = drmmode_crtc->drmmode;
563 struct drmmode_cursor_rec *cursor = drmmode->cursor;
Rob Clark979add52012-02-21 18:35:24 -0600564 int visible;
Rob Clark687c6082012-01-08 19:33:18 -0600565
566 if (!cursor)
567 return;
568
Stéphane Marchesinb8b35202012-10-02 20:27:40 -0700569 visible = drmmode_crtc->cursor_visible;
Rob Clark979add52012-02-21 18:35:24 -0600570
571 if (visible)
Rob Clark687c6082012-01-08 19:33:18 -0600572 drmmode_hide_cursor(crtc);
573
Paul Geary8ffd91c2013-04-11 16:03:15 +0100574 d = armsoc_bo_map(cursor->bo);
Dave Barnish2e998952013-06-11 16:31:10 +0100575 if (!d) {
Paul Geary6fe52f32013-04-03 11:12:24 +0100576 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
577 "load_cursor_argb map failure\n");
578 if (visible)
Javier Martin4c572792013-09-11 15:08:19 +0100579 drmmode_show_cursor_image(crtc, TRUE);
Paul Geary6fe52f32013-04-03 11:12:24 +0100580 return;
581 }
John Rees292ae502013-03-21 16:24:35 +0000582
Javier Martina7e316f2013-09-16 15:22:41 +0100583 set_cursor_image(crtc, d, image);
Rob Clark687c6082012-01-08 19:33:18 -0600584
Rob Clark979add52012-02-21 18:35:24 -0600585 if (visible)
Javier Martin4c572792013-09-11 15:08:19 +0100586 drmmode_show_cursor_image(crtc, TRUE);
Rob Clark687c6082012-01-08 19:33:18 -0600587}
588
Javier Martin4c572792013-09-11 15:08:19 +0100589static Bool
590drmmode_cursor_init_plane(ScreenPtr pScreen)
Rob Clark687c6082012-01-08 19:33:18 -0600591{
Daniel Kurtz0361e002013-08-14 21:07:01 +0800592 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100593 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
594 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
595 struct drmmode_cursor_rec *cursor;
Rob Clark687c6082012-01-08 19:33:18 -0600596 drmModePlaneRes *plane_resources;
597 drmModePlane *ovr;
Dave Barnishde45ed42013-06-05 13:47:56 +0100598 int w, h, pad;
Rob Clark687c6082012-01-08 19:33:18 -0600599 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
600
601 if (drmmode->cursor) {
602 INFO_MSG("cursor already initialized");
603 return TRUE;
604 }
605
Dave Barnish2e998952013-06-11 16:31:10 +0100606 if (!xf86LoaderCheckSymbol("drmModeGetPlaneResources")) {
607 ERROR_MSG(
608 "HW cursor not supported (needs libdrm 2.4.30 or higher)");
Ray Smith003cf5e2013-03-19 10:44:07 +0000609 return FALSE;
610 }
Rob Clark687c6082012-01-08 19:33:18 -0600611
612 /* find an unused plane which can be used as a mouse cursor. Note
613 * that we cheat a bit, in order to not burn one overlay per crtc,
614 * and only show the mouse cursor on one crtc at a time
615 */
616 plane_resources = drmModeGetPlaneResources(drmmode->fd);
617 if (!plane_resources) {
Dave Barnish2e998952013-06-11 16:31:10 +0100618 ERROR_MSG("HW cursor: drmModeGetPlaneResources failed: %s",
619 strerror(errno));
Rob Clark687c6082012-01-08 19:33:18 -0600620 return FALSE;
621 }
622
623 if (plane_resources->count_planes < 1) {
624 ERROR_MSG("not enough planes for HW cursor");
Ray Smith003cf5e2013-03-19 10:44:07 +0000625 drmModeFreePlaneResources(plane_resources);
Rob Clark687c6082012-01-08 19:33:18 -0600626 return FALSE;
627 }
628
629 ovr = drmModeGetPlane(drmmode->fd, plane_resources->planes[0]);
630 if (!ovr) {
Dave Barnish2e998952013-06-11 16:31:10 +0100631 ERROR_MSG("HW cursor: drmModeGetPlane failed: %s",
632 strerror(errno));
Ray Smith003cf5e2013-03-19 10:44:07 +0000633 drmModeFreePlaneResources(plane_resources);
634 return FALSE;
635 }
636
Dave Barnishde45ed42013-06-05 13:47:56 +0100637 if (pARMSOC->drmmode_interface->init_plane_for_cursor &&
Dave Barnish2e998952013-06-11 16:31:10 +0100638 pARMSOC->drmmode_interface->init_plane_for_cursor(
639 drmmode->fd, ovr->plane_id)) {
Ray Smithb93cd892013-04-03 10:06:18 +0100640 ERROR_MSG("Failed driver-specific cursor initialization");
641 drmModeFreePlaneResources(plane_resources);
642 return FALSE;
643 }
644
Dave Barnish2e998952013-06-11 16:31:10 +0100645 cursor = calloc(1, sizeof(struct drmmode_cursor_rec));
Ray Smith003cf5e2013-03-19 10:44:07 +0000646 if (!cursor) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100647 ERROR_MSG("HW cursor: calloc failed");
Ray Smith003cf5e2013-03-19 10:44:07 +0000648 drmModeFreePlane(ovr);
649 drmModeFreePlaneResources(plane_resources);
Rob Clark687c6082012-01-08 19:33:18 -0600650 return FALSE;
651 }
652
653 cursor->ovr = ovr;
Dave Barnishde45ed42013-06-05 13:47:56 +0100654
655 w = pARMSOC->drmmode_interface->cursor_width;
656 h = pARMSOC->drmmode_interface->cursor_height;
657 pad = pARMSOC->drmmode_interface->cursor_padding;
658
659 /* allow for cursor padding in the bo */
Dave Barnish2e998952013-06-11 16:31:10 +0100660 cursor->bo = armsoc_bo_new_with_dim(pARMSOC->dev,
661 w + 2 * pad, h,
662 0, 32, ARMSOC_BO_SCANOUT);
Rob Clark687c6082012-01-08 19:33:18 -0600663
Ray Smith003cf5e2013-03-19 10:44:07 +0000664 if (!cursor->bo) {
Dave Barnishfd50b132013-05-16 15:00:02 +0100665 ERROR_MSG("HW cursor: buffer allocation failed");
Ray Smith003cf5e2013-03-19 10:44:07 +0000666 free(cursor);
667 drmModeFreePlane(ovr);
668 drmModeFreePlaneResources(plane_resources);
669 return FALSE;
670 }
671
Paul Geary8ffd91c2013-04-11 16:03:15 +0100672 handles[0] = armsoc_bo_handle(cursor->bo);
673 pitches[0] = armsoc_bo_pitch(cursor->bo);
Rob Clark687c6082012-01-08 19:33:18 -0600674 offsets[0] = 0;
675
Dave Barnishde45ed42013-06-05 13:47:56 +0100676 /* allow for cursor padding in the fb */
677 if (drmModeAddFB2(drmmode->fd, w + 2 * pad, h, DRM_FORMAT_ARGB8888,
Rob Clark687c6082012-01-08 19:33:18 -0600678 handles, pitches, offsets, &cursor->fb_id, 0)) {
Dave Barnish2e998952013-06-11 16:31:10 +0100679 ERROR_MSG("HW cursor: drmModeAddFB2 failed: %s",
680 strerror(errno));
Paul Geary8ffd91c2013-04-11 16:03:15 +0100681 armsoc_bo_unreference(cursor->bo);
Ray Smith003cf5e2013-03-19 10:44:07 +0000682 free(cursor);
683 drmModeFreePlane(ovr);
684 drmModeFreePlaneResources(plane_resources);
Rob Clark687c6082012-01-08 19:33:18 -0600685 return FALSE;
686 }
687
Ray Smith003cf5e2013-03-19 10:44:07 +0000688 if (!xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
689 ERROR_MSG("xf86_cursors_init() failed");
Dave Barnish2e998952013-06-11 16:31:10 +0100690 if (drmModeRmFB(drmmode->fd, cursor->fb_id))
Ray Smith003cf5e2013-03-19 10:44:07 +0000691 ERROR_MSG("drmModeRmFB() failed");
Dave Barnish2e998952013-06-11 16:31:10 +0100692
Paul Geary8ffd91c2013-04-11 16:03:15 +0100693 armsoc_bo_unreference(cursor->bo);
Ray Smith003cf5e2013-03-19 10:44:07 +0000694 free(cursor);
695 drmModeFreePlane(ovr);
696 drmModeFreePlaneResources(plane_resources);
697 return FALSE;
Rob Clark687c6082012-01-08 19:33:18 -0600698 }
699
Ray Smith003cf5e2013-03-19 10:44:07 +0000700 INFO_MSG("HW cursor initialized");
701 drmmode->cursor = cursor;
Dave Barnishfd50b132013-05-16 15:00:02 +0100702 drmModeFreePlaneResources(plane_resources);
Ray Smith003cf5e2013-03-19 10:44:07 +0000703 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -0600704}
Rob Clark487687e2011-07-17 17:29:02 -0500705
Javier Martin4c572792013-09-11 15:08:19 +0100706static Bool
707drmmode_cursor_init_standard(ScreenPtr pScreen)
708{
709 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
710 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
711 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
712 struct drmmode_cursor_rec *cursor;
713 int w, h, pad;
714
715 if (drmmode->cursor) {
716 INFO_MSG("cursor already initialized");
717 return TRUE;
718 }
719
720 if (!xf86LoaderCheckSymbol("drmModeSetCursor") ||
721 !xf86LoaderCheckSymbol("drmModeMoveCursor")) {
Dave Barnish8e9ac7b2013-09-12 14:17:33 +0100722 ERROR_MSG(
723 "Standard HW cursor not supported (needs libdrm 2.4.3 or higher)");
Javier Martin4c572792013-09-11 15:08:19 +0100724 return FALSE;
725 }
726
727 cursor = calloc(1, sizeof(struct drmmode_cursor_rec));
728 if (!cursor) {
729 ERROR_MSG("HW cursor (standard): calloc failed");
730 return FALSE;
731 }
732
733 w = pARMSOC->drmmode_interface->cursor_width;
734 h = pARMSOC->drmmode_interface->cursor_height;
735 pad = pARMSOC->drmmode_interface->cursor_padding;
736
737 /* allow for cursor padding in the bo */
738 cursor->bo = armsoc_bo_new_with_dim(pARMSOC->dev,
739 w + 2 * pad, h,
740 0, 32, ARMSOC_BO_SCANOUT);
741
742 if (!cursor->bo) {
743 ERROR_MSG("HW cursor (standard): buffer allocation failed");
744 free(cursor);
745 return FALSE;
746 }
747
748 cursor->handle = armsoc_bo_handle(cursor->bo);
749
750 if (!xf86_cursors_init(pScreen, w, h, HARDWARE_CURSOR_ARGB)) {
751 ERROR_MSG("xf86_cursors_init() failed");
752 if (drmModeRmFB(drmmode->fd, cursor->fb_id))
753 ERROR_MSG("drmModeRmFB() failed");
754
755 armsoc_bo_unreference(cursor->bo);
756 free(cursor);
757 return FALSE;
758 }
759
760 INFO_MSG("HW cursor initialized");
761 drmmode->cursor = cursor;
762 return TRUE;
763}
764
765Bool drmmode_cursor_init(ScreenPtr pScreen)
766{
767 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
768 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
769
770 INFO_MSG("HW cursor init()");
771
772 if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE)
773 return drmmode_cursor_init_plane(pScreen);
774 else /* HWCURSOR_API_STANDARD */
775 return drmmode_cursor_init_standard(pScreen);
776}
777
Dave Barnishfd50b132013-05-16 15:00:02 +0100778void drmmode_cursor_fini(ScreenPtr pScreen)
779{
Daniel Kurtz0361e002013-08-14 21:07:01 +0800780 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +0100781 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
782 struct drmmode_cursor_rec *cursor = drmmode->cursor;
Javier Martin4c572792013-09-11 15:08:19 +0100783 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Dave Barnishfd50b132013-05-16 15:00:02 +0100784
Dave Barnish2e998952013-06-11 16:31:10 +0100785 if (!cursor)
Dave Barnishfd50b132013-05-16 15:00:02 +0100786 return;
Dave Barnish2e998952013-06-11 16:31:10 +0100787
Dave Barnishfd50b132013-05-16 15:00:02 +0100788 drmmode->cursor = NULL;
789 xf86_cursors_fini(pScreen);
Javier Martin4c572792013-09-11 15:08:19 +0100790 if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE)
791 drmModeRmFB(drmmode->fd, cursor->fb_id);
Dave Barnishfd50b132013-05-16 15:00:02 +0100792 armsoc_bo_unreference(cursor->bo);
Javier Martin4c572792013-09-11 15:08:19 +0100793 if (pARMSOC->drmmode_interface->cursor_api == HWCURSOR_API_PLANE)
794 drmModeFreePlane(cursor->ovr);
Dave Barnishfd50b132013-05-16 15:00:02 +0100795 free(cursor);
796}
797
798
Dave Barnish2e998952013-06-11 16:31:10 +0100799#if 1 == ARMSOC_SUPPORT_GAMMA
Rob Clark487687e2011-07-17 17:29:02 -0500800static void
801drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue,
Rob Clark74210d52012-01-08 17:59:08 -0600802 int size)
Rob Clark487687e2011-07-17 17:29:02 -0500803{
Dave Barnish2e998952013-06-11 16:31:10 +0100804 struct drmmode_crtc_private_rec *drmmode_crtc = crtc->driver_private;
805 struct drmmode_rec *drmmode = drmmode_crtc->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -0500806 int ret;
807
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100808 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->crtc_id,
Rob Clark74210d52012-01-08 17:59:08 -0600809 size, red, green, blue);
Rob Clark487687e2011-07-17 17:29:02 -0500810 if (ret != 0) {
811 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
Rob Clark74210d52012-01-08 17:59:08 -0600812 "failed to set gamma: %s\n", strerror(-ret));
Rob Clark487687e2011-07-17 17:29:02 -0500813 }
814}
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200815#endif
Rob Clark487687e2011-07-17 17:29:02 -0500816
817static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -0600818 .dpms = drmmode_crtc_dpms,
819 .set_mode_major = drmmode_set_mode_major,
820 .set_cursor_position = drmmode_set_cursor_position,
821 .show_cursor = drmmode_show_cursor,
822 .hide_cursor = drmmode_hide_cursor,
823 .load_cursor_argb = drmmode_load_cursor_argb,
Dave Barnish2e998952013-06-11 16:31:10 +0100824#if 1 == ARMSOC_SUPPORT_GAMMA
Rob Clark74210d52012-01-08 17:59:08 -0600825 .gamma_set = drmmode_gamma_set,
Mandeep Singh Bainesc874fcb2012-09-13 15:30:00 +0200826#endif
Rob Clark487687e2011-07-17 17:29:02 -0500827};
828
829
830static void
Dave Barnish2e998952013-06-11 16:31:10 +0100831drmmode_crtc_init(ScrnInfoPtr pScrn, struct drmmode_rec *drmmode, int num)
Rob Clark487687e2011-07-17 17:29:02 -0500832{
Rob Clark74210d52012-01-08 17:59:08 -0600833 xf86CrtcPtr crtc;
Dave Barnish2e998952013-06-11 16:31:10 +0100834 struct drmmode_crtc_private_rec *drmmode_crtc;
Rob Clark487687e2011-07-17 17:29:02 -0500835
Rob Clark74210d52012-01-08 17:59:08 -0600836 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -0500837
Rob Clark74210d52012-01-08 17:59:08 -0600838 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
839 if (crtc == NULL)
840 return;
841
Dave Barnish2e998952013-06-11 16:31:10 +0100842 drmmode_crtc = xnfcalloc(sizeof(struct drmmode_crtc_private_rec), 1);
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100843 drmmode_crtc->crtc_id = drmmode->mode_res->crtcs[num];
Rob Clark74210d52012-01-08 17:59:08 -0600844 drmmode_crtc->drmmode = drmmode;
Dave Barnishf245da32013-08-30 12:16:58 +0100845 drmmode_crtc->last_good_mode = NULL;
Rob Clark74210d52012-01-08 17:59:08 -0600846
Dave Barnishf245da32013-08-30 12:16:58 +0100847 INFO_MSG("Got CRTC: %d (id: %d)",
Dave Barnish6a1b31e2013-09-25 11:09:05 +0100848 num, drmmode_crtc->crtc_id);
Rob Clark74210d52012-01-08 17:59:08 -0600849 crtc->driver_private = drmmode_crtc;
850
851 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -0500852 return;
Rob Clark74210d52012-01-08 17:59:08 -0600853}
Rob Clark487687e2011-07-17 17:29:02 -0500854
855static xf86OutputStatus
856drmmode_output_detect(xf86OutputPtr output)
857{
858 /* go to the hw and retrieve a new output struct */
Dave Barnish2e998952013-06-11 16:31:10 +0100859 struct drmmode_output_priv *drmmode_output = output->driver_private;
860 struct drmmode_rec *drmmode = drmmode_output->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -0500861 xf86OutputStatus status;
Dave Barnish70df8ae2013-09-26 12:44:27 +0100862 drmModeFreeConnector(drmmode_output->connector);
Rob Clark487687e2011-07-17 17:29:02 -0500863
Dave Barnish70df8ae2013-09-26 12:44:27 +0100864 drmmode_output->connector =
Dave Barnish2e998952013-06-11 16:31:10 +0100865 drmModeGetConnector(drmmode->fd,
866 drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -0500867
Dave Barnish70df8ae2013-09-26 12:44:27 +0100868 switch (drmmode_output->connector->connection) {
Rob Clark487687e2011-07-17 17:29:02 -0500869 case DRM_MODE_CONNECTED:
870 status = XF86OutputStatusConnected;
871 break;
872 case DRM_MODE_DISCONNECTED:
873 status = XF86OutputStatusDisconnected;
874 break;
875 default:
876 case DRM_MODE_UNKNOWNCONNECTION:
877 status = XF86OutputStatusUnknown;
878 break;
879 }
880 return status;
881}
882
883static Bool
884drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
885{
886 if (mode->type & M_T_DEFAULT)
887 /* Default modes are harmful here. */
888 return MODE_BAD;
889
890 return MODE_OK;
891}
892
893static DisplayModePtr
894drmmode_output_get_modes(xf86OutputPtr output)
895{
896 ScrnInfoPtr pScrn = output->scrn;
Dave Barnish2e998952013-06-11 16:31:10 +0100897 struct drmmode_output_priv *drmmode_output = output->driver_private;
Dave Barnish70df8ae2013-09-26 12:44:27 +0100898 drmModeConnectorPtr connector = drmmode_output->connector;
Dave Barnish2e998952013-06-11 16:31:10 +0100899 struct drmmode_rec *drmmode = drmmode_output->drmmode;
Dave Barnish0bdb7382013-06-06 12:04:04 +0100900 DisplayModePtr modes = NULL;
Daniel Kurtzb8131892012-10-17 01:39:54 +0800901 drmModePropertyPtr prop;
Rob Clark487687e2011-07-17 17:29:02 -0500902 xf86MonPtr ddc_mon = NULL;
903 int i;
904
905 /* look for an EDID property */
Dave Barnish70df8ae2013-09-26 12:44:27 +0100906 for (i = 0; i < connector->count_props; i++) {
907 prop = drmModeGetProperty(drmmode->fd, connector->props[i]);
Daniel Kurtzb8131892012-10-17 01:39:54 +0800908 if (!prop)
Rob Clark487687e2011-07-17 17:29:02 -0500909 continue;
910
Daniel Kurtzb8131892012-10-17 01:39:54 +0800911 if ((prop->flags & DRM_MODE_PROP_BLOB) &&
912 !strcmp(prop->name, "EDID")) {
Rob Clark487687e2011-07-17 17:29:02 -0500913 if (drmmode_output->edid_blob)
Dave Barnish2e998952013-06-11 16:31:10 +0100914 drmModeFreePropertyBlob(
915 drmmode_output->edid_blob);
Rob Clark487687e2011-07-17 17:29:02 -0500916 drmmode_output->edid_blob =
Rob Clark74210d52012-01-08 17:59:08 -0600917 drmModeGetPropertyBlob(drmmode->fd,
Dave Barnish70df8ae2013-09-26 12:44:27 +0100918 connector->prop_values[i]);
Rob Clark487687e2011-07-17 17:29:02 -0500919 }
Daniel Kurtzb8131892012-10-17 01:39:54 +0800920 drmModeFreeProperty(prop);
Rob Clark487687e2011-07-17 17:29:02 -0500921 }
922
923 if (drmmode_output->edid_blob)
924 ddc_mon = xf86InterpretEDID(pScrn->scrnIndex,
Rob Clark74210d52012-01-08 17:59:08 -0600925 drmmode_output->edid_blob->data);
Rob Clark487687e2011-07-17 17:29:02 -0500926
927 if (ddc_mon) {
Rob Clark487687e2011-07-17 17:29:02 -0500928 xf86OutputSetEDID(output, ddc_mon);
929 xf86SetDDCproperties(pScrn, ddc_mon);
930 }
931
Dave Barnish70df8ae2013-09-26 12:44:27 +0100932 DEBUG_MSG("count_modes: %d", connector->count_modes);
Rob Clark487687e2011-07-17 17:29:02 -0500933
934 /* modes should already be available */
Dave Barnish70df8ae2013-09-26 12:44:27 +0100935 for (i = 0; i < connector->count_modes; i++) {
Dave Barnish0bdb7382013-06-06 12:04:04 +0100936 DisplayModePtr mode = xnfalloc(sizeof(DisplayModeRec));
Rob Clark487687e2011-07-17 17:29:02 -0500937
Dave Barnish70df8ae2013-09-26 12:44:27 +0100938 drmmode_ConvertFromKMode(pScrn, &connector->modes[i], mode);
Dave Barnish0bdb7382013-06-06 12:04:04 +0100939 modes = xf86ModesAdd(modes, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500940 }
Dave Barnish0bdb7382013-06-06 12:04:04 +0100941 return modes;
Rob Clark487687e2011-07-17 17:29:02 -0500942}
943
944static void
945drmmode_output_destroy(xf86OutputPtr output)
946{
Dave Barnish2e998952013-06-11 16:31:10 +0100947 struct drmmode_output_priv *drmmode_output = output->driver_private;
Rob Clark487687e2011-07-17 17:29:02 -0500948 int i;
949
950 if (drmmode_output->edid_blob)
951 drmModeFreePropertyBlob(drmmode_output->edid_blob);
Dave Barnish70df8ae2013-09-26 12:44:27 +0100952
Rob Clark487687e2011-07-17 17:29:02 -0500953 for (i = 0; i < drmmode_output->num_props; i++) {
954 drmModeFreeProperty(drmmode_output->props[i].mode_prop);
955 free(drmmode_output->props[i].atoms);
956 }
Daniel Kurtzf5a38ad2012-10-17 02:03:34 +0800957 free(drmmode_output->props);
Dave Barnish70df8ae2013-09-26 12:44:27 +0100958
959 for (i = 0; i < drmmode_output->connector->count_encoders; i++)
960 drmModeFreeEncoder(drmmode_output->encoders[i]);
961
962 free(drmmode_output->encoders);
963
964 drmModeFreeConnector(drmmode_output->connector);
Rob Clark487687e2011-07-17 17:29:02 -0500965 free(drmmode_output);
966 output->driver_private = NULL;
967}
968
969static void
970drmmode_output_dpms(xf86OutputPtr output, int mode)
971{
Dave Barnish2e998952013-06-11 16:31:10 +0100972 struct drmmode_output_priv *drmmode_output = output->driver_private;
Dave Barnish70df8ae2013-09-26 12:44:27 +0100973 drmModeConnectorPtr connector = drmmode_output->connector;
Daniel Kurtzb8131892012-10-17 01:39:54 +0800974 drmModePropertyPtr prop;
Dave Barnish2e998952013-06-11 16:31:10 +0100975 struct drmmode_rec *drmmode = drmmode_output->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -0500976 int mode_id = -1, i;
977
Dave Barnish70df8ae2013-09-26 12:44:27 +0100978 for (i = 0; i < connector->count_props; i++) {
979 prop = drmModeGetProperty(drmmode->fd, connector->props[i]);
Daniel Kurtzb8131892012-10-17 01:39:54 +0800980 if (!prop)
981 continue;
982 if ((prop->flags & DRM_MODE_PROP_ENUM) &&
983 !strcmp(prop->name, "DPMS")) {
Dave Barnish70df8ae2013-09-26 12:44:27 +0100984 mode_id = connector->props[i];
Daniel Kurtzb8131892012-10-17 01:39:54 +0800985 drmModeFreeProperty(prop);
986 break;
Rob Clark487687e2011-07-17 17:29:02 -0500987 }
Daniel Kurtzb8131892012-10-17 01:39:54 +0800988 drmModeFreeProperty(prop);
Rob Clark487687e2011-07-17 17:29:02 -0500989 }
990
991 if (mode_id < 0)
992 return;
993
Dave Barnish70df8ae2013-09-26 12:44:27 +0100994 drmModeConnectorSetProperty(drmmode->fd, connector->connector_id,
Rob Clark74210d52012-01-08 17:59:08 -0600995 mode_id, mode);
Rob Clark487687e2011-07-17 17:29:02 -0500996}
997
998static Bool
999drmmode_property_ignore(drmModePropertyPtr prop)
1000{
1001 if (!prop)
Rob Clark74210d52012-01-08 17:59:08 -06001002 return TRUE;
Rob Clark487687e2011-07-17 17:29:02 -05001003 /* ignore blob prop */
1004 if (prop->flags & DRM_MODE_PROP_BLOB)
1005 return TRUE;
1006 /* ignore standard property */
1007 if (!strcmp(prop->name, "EDID") ||
Rob Clark74210d52012-01-08 17:59:08 -06001008 !strcmp(prop->name, "DPMS"))
Rob Clark487687e2011-07-17 17:29:02 -05001009 return TRUE;
1010
1011 return FALSE;
1012}
1013
1014static void
1015drmmode_output_create_resources(xf86OutputPtr output)
1016{
Dave Barnish2e998952013-06-11 16:31:10 +01001017 struct drmmode_output_priv *drmmode_output = output->driver_private;
Dave Barnish70df8ae2013-09-26 12:44:27 +01001018 drmModeConnectorPtr connector = drmmode_output->connector;
Dave Barnish2e998952013-06-11 16:31:10 +01001019 struct drmmode_rec *drmmode = drmmode_output->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -05001020 drmModePropertyPtr drmmode_prop;
1021 uint32_t value;
1022 int i, j, err;
1023
Dave Barnish2e998952013-06-11 16:31:10 +01001024 drmmode_output->props =
Dave Barnish70df8ae2013-09-26 12:44:27 +01001025 calloc(connector->count_props,
Dave Barnish2e998952013-06-11 16:31:10 +01001026 sizeof(struct drmmode_prop_rec));
Rob Clark487687e2011-07-17 17:29:02 -05001027 if (!drmmode_output->props)
1028 return;
1029
1030 drmmode_output->num_props = 0;
Dave Barnish70df8ae2013-09-26 12:44:27 +01001031 for (i = 0; i < connector->count_props; i++) {
Dave Barnish2e998952013-06-11 16:31:10 +01001032 drmmode_prop = drmModeGetProperty(drmmode->fd,
Dave Barnish70df8ae2013-09-26 12:44:27 +01001033 connector->props[i]);
Rob Clark487687e2011-07-17 17:29:02 -05001034 if (drmmode_property_ignore(drmmode_prop)) {
1035 drmModeFreeProperty(drmmode_prop);
1036 continue;
1037 }
Dave Barnish2e998952013-06-11 16:31:10 +01001038 drmmode_output->props[drmmode_output->num_props].mode_prop =
1039 drmmode_prop;
Dave Barnish0bdb7382013-06-06 12:04:04 +01001040 drmmode_output->props[drmmode_output->num_props].index = i;
Rob Clark487687e2011-07-17 17:29:02 -05001041 drmmode_output->num_props++;
Rob Clark487687e2011-07-17 17:29:02 -05001042 }
1043
1044 for (i = 0; i < drmmode_output->num_props; i++) {
Dave Barnish2e998952013-06-11 16:31:10 +01001045 struct drmmode_prop_rec *p = &drmmode_output->props[i];
Rob Clark487687e2011-07-17 17:29:02 -05001046 drmmode_prop = p->mode_prop;
1047
Dave Barnish70df8ae2013-09-26 12:44:27 +01001048 value = drmmode_output->connector->prop_values[p->index];
Rob Clark487687e2011-07-17 17:29:02 -05001049
1050 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1051 INT32 range[2];
1052
1053 p->num_atoms = 1;
1054 p->atoms = calloc(p->num_atoms, sizeof(Atom));
1055 if (!p->atoms)
1056 continue;
Dave Barnish2e998952013-06-11 16:31:10 +01001057 p->atoms[0] = MakeAtom(drmmode_prop->name,
1058 strlen(drmmode_prop->name),
1059 TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001060 range[0] = drmmode_prop->values[0];
1061 range[1] = drmmode_prop->values[1];
Dave Barnish2e998952013-06-11 16:31:10 +01001062 err = RRConfigureOutputProperty(output->randr_output,
1063 p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -06001064 FALSE, TRUE,
Dave Barnish2e998952013-06-11 16:31:10 +01001065 drmmode_prop->flags &
1066 DRM_MODE_PROP_IMMUTABLE ?
1067 TRUE : FALSE,
1068 2, range);
1069
1070 if (err != 0)
Rob Clark487687e2011-07-17 17:29:02 -05001071 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Dave Barnish2e998952013-06-11 16:31:10 +01001072 "RRConfigureOutputProperty error, %d\n",
1073 err);
1074
1075 err = RRChangeOutputProperty(output->randr_output,
1076 p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -06001077 XA_INTEGER, 32, PropModeReplace, 1,
1078 &value, FALSE, FALSE);
Dave Barnish2e998952013-06-11 16:31:10 +01001079 if (err != 0)
Rob Clark487687e2011-07-17 17:29:02 -05001080 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Dave Barnish2e998952013-06-11 16:31:10 +01001081 "RRChangeOutputProperty error, %d\n",
1082 err);
1083
Rob Clark487687e2011-07-17 17:29:02 -05001084 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1085 p->num_atoms = drmmode_prop->count_enums + 1;
1086 p->atoms = calloc(p->num_atoms, sizeof(Atom));
1087 if (!p->atoms)
1088 continue;
Dave Barnish2e998952013-06-11 16:31:10 +01001089 p->atoms[0] = MakeAtom(drmmode_prop->name,
1090 strlen(drmmode_prop->name),
1091 TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001092 for (j = 1; j <= drmmode_prop->count_enums; j++) {
Dave Barnish2e998952013-06-11 16:31:10 +01001093 struct drm_mode_property_enum *e =
1094 &drmmode_prop->enums[j-1];
1095 p->atoms[j] = MakeAtom(e->name,
1096 strlen(e->name), TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001097 }
Dave Barnish2e998952013-06-11 16:31:10 +01001098 err = RRConfigureOutputProperty(output->randr_output,
1099 p->atoms[0],
Rob Clark74210d52012-01-08 17:59:08 -06001100 FALSE, FALSE,
Dave Barnish2e998952013-06-11 16:31:10 +01001101 drmmode_prop->flags &
1102 DRM_MODE_PROP_IMMUTABLE ?
1103 TRUE : FALSE,
1104 p->num_atoms - 1,
1105 (INT32 *)&p->atoms[1]);
1106
1107 if (err != 0)
Rob Clark487687e2011-07-17 17:29:02 -05001108 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Dave Barnish2e998952013-06-11 16:31:10 +01001109 "RRConfigureOutputProperty error, %d\n",
1110 err);
1111
Rob Clark487687e2011-07-17 17:29:02 -05001112 for (j = 0; j < drmmode_prop->count_enums; j++)
1113 if (drmmode_prop->enums[j].value == value)
1114 break;
1115 /* there's always a matching value */
Dave Barnish2e998952013-06-11 16:31:10 +01001116 err = RRChangeOutputProperty(output->randr_output,
1117 p->atoms[0],
1118 XA_ATOM, 32, PropModeReplace, 1,
1119 &p->atoms[j+1], FALSE, FALSE);
1120 if (err != 0)
Rob Clark487687e2011-07-17 17:29:02 -05001121 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
Dave Barnish2e998952013-06-11 16:31:10 +01001122 "RRChangeOutputProperty error, %d\n",
1123 err);
Rob Clark487687e2011-07-17 17:29:02 -05001124 }
1125 }
1126}
1127
1128static Bool
1129drmmode_output_set_property(xf86OutputPtr output, Atom property,
Rob Clark74210d52012-01-08 17:59:08 -06001130 RRPropertyValuePtr value)
Rob Clark487687e2011-07-17 17:29:02 -05001131{
Dave Barnish2e998952013-06-11 16:31:10 +01001132 struct drmmode_output_priv *drmmode_output = output->driver_private;
1133 struct drmmode_rec *drmmode = drmmode_output->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -05001134 int i, ret;
1135
1136 for (i = 0; i < drmmode_output->num_props; i++) {
Dave Barnish2e998952013-06-11 16:31:10 +01001137 struct drmmode_prop_rec *p = &drmmode_output->props[i];
Rob Clark487687e2011-07-17 17:29:02 -05001138
1139 if (p->atoms[0] != property)
1140 continue;
1141
1142 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1143 uint32_t val;
1144
1145 if (value->type != XA_INTEGER || value->format != 32 ||
Rob Clark74210d52012-01-08 17:59:08 -06001146 value->size != 1)
Rob Clark487687e2011-07-17 17:29:02 -05001147 return FALSE;
1148 val = *(uint32_t *)value->data;
1149
Dave Barnish2e998952013-06-11 16:31:10 +01001150 ret = drmModeConnectorSetProperty(drmmode->fd,
1151 drmmode_output->output_id,
Rob Clark74210d52012-01-08 17:59:08 -06001152 p->mode_prop->prop_id, (uint64_t)val);
Rob Clark487687e2011-07-17 17:29:02 -05001153
1154 if (ret)
1155 return FALSE;
1156
1157 return TRUE;
1158
1159 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1160 Atom atom;
1161 const char *name;
1162 int j;
1163
Dave Barnish2e998952013-06-11 16:31:10 +01001164 if (value->type != XA_ATOM ||
1165 value->format != 32 ||
1166 value->size != 1)
Rob Clark487687e2011-07-17 17:29:02 -05001167 return FALSE;
Dave Barnish2e998952013-06-11 16:31:10 +01001168
Rob Clark487687e2011-07-17 17:29:02 -05001169 memcpy(&atom, value->data, 4);
1170 name = NameForAtom(atom);
Daniel Kurtz23148372013-03-27 20:19:45 +08001171 if (name == NULL)
1172 return FALSE;
Rob Clark487687e2011-07-17 17:29:02 -05001173
Dave Barnish2e998952013-06-11 16:31:10 +01001174 /* search for matching name string, then
1175 * set its value down
1176 */
Rob Clark487687e2011-07-17 17:29:02 -05001177 for (j = 0; j < p->mode_prop->count_enums; j++) {
Dave Barnish2e998952013-06-11 16:31:10 +01001178 if (!strcmp(p->mode_prop->enums[j].name,
1179 name)) {
1180 ret = drmModeConnectorSetProperty(
1181 drmmode->fd,
1182 drmmode_output->output_id,
1183 p->mode_prop->prop_id,
1184 p->mode_prop->enums[j].value);
Rob Clark487687e2011-07-17 17:29:02 -05001185
1186 if (ret)
1187 return FALSE;
1188
1189 return TRUE;
1190 }
1191 }
Rob Clark487687e2011-07-17 17:29:02 -05001192 return FALSE;
1193 }
1194 }
Rob Clark487687e2011-07-17 17:29:02 -05001195 return TRUE;
1196}
1197
1198static Bool
1199drmmode_output_get_property(xf86OutputPtr output, Atom property)
1200{
1201
Dave Barnish2e998952013-06-11 16:31:10 +01001202 struct drmmode_output_priv *drmmode_output = output->driver_private;
1203 struct drmmode_rec *drmmode = drmmode_output->drmmode;
Rob Clark487687e2011-07-17 17:29:02 -05001204 uint32_t value;
1205 int err, i;
1206
1207 if (output->scrn->vtSema) {
Dave Barnish70df8ae2013-09-26 12:44:27 +01001208 drmModeFreeConnector(drmmode_output->connector);
1209 drmmode_output->connector =
Dave Barnish2e998952013-06-11 16:31:10 +01001210 drmModeGetConnector(drmmode->fd,
1211 drmmode_output->output_id);
Rob Clark487687e2011-07-17 17:29:02 -05001212 }
1213
1214 for (i = 0; i < drmmode_output->num_props; i++) {
Dave Barnish2e998952013-06-11 16:31:10 +01001215 struct drmmode_prop_rec *p = &drmmode_output->props[i];
Rob Clark487687e2011-07-17 17:29:02 -05001216 if (p->atoms[0] != property)
1217 continue;
1218
Dave Barnish70df8ae2013-09-26 12:44:27 +01001219 value = drmmode_output->connector->prop_values[p->index];
Rob Clark487687e2011-07-17 17:29:02 -05001220
1221 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1222 err = RRChangeOutputProperty(output->randr_output,
Rob Clark74210d52012-01-08 17:59:08 -06001223 property, XA_INTEGER, 32,
1224 PropModeReplace, 1, &value,
1225 FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -05001226
1227 return !err;
1228 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1229 int j;
1230
Dave Barnish2e998952013-06-11 16:31:10 +01001231 /* search for matching name string, then set
1232 * its value down
1233 */
Rob Clark487687e2011-07-17 17:29:02 -05001234 for (j = 0; j < p->mode_prop->count_enums; j++) {
1235 if (p->mode_prop->enums[j].value == value)
1236 break;
1237 }
1238
Dave Barnish2e998952013-06-11 16:31:10 +01001239 err = RRChangeOutputProperty(output->randr_output,
1240 property,
1241 XA_ATOM, 32, PropModeReplace, 1,
1242 &p->atoms[j+1], FALSE, FALSE);
Rob Clark487687e2011-07-17 17:29:02 -05001243
1244 return !err;
1245 }
1246 }
1247
1248 return FALSE;
1249}
1250
1251static const xf86OutputFuncsRec drmmode_output_funcs = {
Rob Clark74210d52012-01-08 17:59:08 -06001252 .create_resources = drmmode_output_create_resources,
1253 .dpms = drmmode_output_dpms,
1254 .detect = drmmode_output_detect,
1255 .mode_valid = drmmode_output_mode_valid,
1256 .get_modes = drmmode_output_get_modes,
1257 .set_property = drmmode_output_set_property,
1258 .get_property = drmmode_output_get_property,
1259 .destroy = drmmode_output_destroy
Rob Clark487687e2011-07-17 17:29:02 -05001260};
1261
Rob Clark487687e2011-07-17 17:29:02 -05001262const char *output_names[] = { "None",
Rob Clark74210d52012-01-08 17:59:08 -06001263 "VGA",
1264 "DVI-I",
1265 "DVI-D",
1266 "DVI-A",
1267 "Composite",
1268 "SVIDEO",
1269 "LVDS",
1270 "CTV",
1271 "DIN",
1272 "DP",
1273 "HDMI",
1274 "HDMI",
1275 "TV",
1276 "eDP",
Rob Clark487687e2011-07-17 17:29:02 -05001277};
1278#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
1279
1280static void
Dave Barnish2e998952013-06-11 16:31:10 +01001281drmmode_output_init(ScrnInfoPtr pScrn, struct drmmode_rec *drmmode, int num)
Rob Clark487687e2011-07-17 17:29:02 -05001282{
Rob Clark74210d52012-01-08 17:59:08 -06001283 xf86OutputPtr output;
Dave Barnish70df8ae2013-09-26 12:44:27 +01001284 drmModeConnectorPtr connector;
1285 drmModeEncoderPtr *encoders = NULL;
Dave Barnish2e998952013-06-11 16:31:10 +01001286 struct drmmode_output_priv *drmmode_output;
Rob Clark74210d52012-01-08 17:59:08 -06001287 char name[32];
Dave Barnish70df8ae2013-09-26 12:44:27 +01001288 int i;
Rob Clark487687e2011-07-17 17:29:02 -05001289
Rob Clark74210d52012-01-08 17:59:08 -06001290 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001291
Dave Barnish70df8ae2013-09-26 12:44:27 +01001292 connector = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
1293 if (!connector)
1294 goto exit;
Rob Clark487687e2011-07-17 17:29:02 -05001295
Dave Barnish70df8ae2013-09-26 12:44:27 +01001296 encoders = calloc(sizeof(drmModeEncoderPtr), connector->count_encoders);
1297 if (!encoders)
1298 goto free_connector_exit;
1299
1300 for (i = 0; i < connector->count_encoders; i++) {
1301 encoders[i] = drmModeGetEncoder(drmmode->fd, connector->encoders[i]);
1302 if (!encoders[i])
1303 goto free_encoders_exit;
Rob Clark74210d52012-01-08 17:59:08 -06001304 }
Rob Clark487687e2011-07-17 17:29:02 -05001305
Dave Barnish70df8ae2013-09-26 12:44:27 +01001306 if (connector->connector_type >= NUM_OUTPUT_NAMES)
1307 snprintf(name, 32, "Unknown%d-%d", connector->connector_type, connector->connector_type_id);
Rob Clark74210d52012-01-08 17:59:08 -06001308 else
Dave Barnish70df8ae2013-09-26 12:44:27 +01001309 snprintf(name, 32, "%s-%d", output_names[connector->connector_type], connector->connector_type_id);
Rob Clark487687e2011-07-17 17:29:02 -05001310
Rob Clark74210d52012-01-08 17:59:08 -06001311 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
Dave Barnish70df8ae2013-09-26 12:44:27 +01001312 if (!output)
1313 goto free_encoders_exit;
Rob Clark487687e2011-07-17 17:29:02 -05001314
Dave Barnish2e998952013-06-11 16:31:10 +01001315 drmmode_output = calloc(sizeof(struct drmmode_output_priv), 1);
Rob Clark74210d52012-01-08 17:59:08 -06001316 if (!drmmode_output) {
1317 xf86OutputDestroy(output);
Dave Barnish70df8ae2013-09-26 12:44:27 +01001318 goto free_encoders_exit;
Rob Clark74210d52012-01-08 17:59:08 -06001319 }
Rob Clark487687e2011-07-17 17:29:02 -05001320
Rob Clark74210d52012-01-08 17:59:08 -06001321 drmmode_output->output_id = drmmode->mode_res->connectors[num];
Dave Barnish70df8ae2013-09-26 12:44:27 +01001322 drmmode_output->connector = connector;
1323 drmmode_output->encoders = encoders;
Rob Clark74210d52012-01-08 17:59:08 -06001324 drmmode_output->drmmode = drmmode;
Rob Clark487687e2011-07-17 17:29:02 -05001325
Dave Barnish70df8ae2013-09-26 12:44:27 +01001326 output->mm_width = connector->mmWidth;
1327 output->mm_height = connector->mmHeight;
Rob Clark74210d52012-01-08 17:59:08 -06001328 output->driver_private = drmmode_output;
Rob Clark487687e2011-07-17 17:29:02 -05001329
Dave Barnish70df8ae2013-09-26 12:44:27 +01001330 /*
1331 * Determine which crtcs are supported by all the encoders which
1332 * are valid for the connector of this output.
1333 */
1334 output->possible_crtcs = 0xffffffff;
1335 for (i = 0; i < connector->count_encoders; i++)
1336 output->possible_crtcs &= encoders[i]->possible_crtcs;
1337 /*
1338 * output->possible_crtcs is a bitmask arranged by index of crtcs for this screen while
1339 * encoders->possible_crtcs covers all crtcs supported by the drm. If we have selected
1340 * one crtc per screen, it must be at index 0.
1341 */
1342 if (ARMSOCPTR(pScrn)->crtcNum >= 0)
1343 output->possible_crtcs = (output->possible_crtcs >> (ARMSOCPTR(pScrn)->crtcNum)) & 1;
Dave Barnishf0952c12013-05-10 15:52:23 +01001344
Dave Barnish70df8ae2013-09-26 12:44:27 +01001345 output->possible_clones = 0; /* set after all outputs initialized */
Rob Clark74210d52012-01-08 17:59:08 -06001346 output->interlaceAllowed = TRUE;
Dave Barnish70df8ae2013-09-26 12:44:27 +01001347 goto exit;
Rob Clark487687e2011-07-17 17:29:02 -05001348
Dave Barnish70df8ae2013-09-26 12:44:27 +01001349free_encoders_exit:
1350 for (i = 0; i < connector->count_encoders; i++)
1351 drmModeFreeEncoder(encoders[i]);
1352
1353free_connector_exit:
1354 drmModeFreeConnector(connector);
1355
1356exit:
Rob Clark74210d52012-01-08 17:59:08 -06001357 TRACE_EXIT();
1358 return;
Dave Barnish70df8ae2013-09-26 12:44:27 +01001359
1360}
1361static void
1362drmmode_clones_init(ScrnInfoPtr pScrn, struct drmmode_rec *drmmode)
1363{
1364 int i;
1365 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1366
1367 /* For each output generate enc_mask, a mask of encoders present,
1368 * and enc_clones, a mask of possible clone encoders
1369 */
1370 for (i = 0; i < xf86_config->num_output; i++) {
1371 xf86OutputPtr output = xf86_config->output[i];
1372 struct drmmode_output_priv *drmmode_output = output->driver_private;
1373 int j;
1374
1375 drmmode_output->enc_clones = 0xffffffff;
1376 drmmode_output->enc_mask = 0;
1377
1378 for (j = 0; j < drmmode_output->connector->count_encoders; j++) {
1379 int k;
1380
1381 /* set index ordered mask of encoders on this output */
1382 for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
1383 if (drmmode->mode_res->encoders[k] == drmmode_output->encoders[j]->encoder_id)
1384 drmmode_output->enc_mask |= (1 << k);
1385 }
1386 /* set mask for encoder clones possible with all encoders on this output */
1387 drmmode_output->enc_clones &= drmmode_output->encoders[j]->possible_clones;
1388 }
1389 }
1390
1391 /* Output j is a possible clone of output i if the enc_mask for j matches the enc_clones for i */
1392 for (i = 0; i < xf86_config->num_output; i++) {
1393 xf86OutputPtr output = xf86_config->output[i];
1394 struct drmmode_output_priv *drmmode_output = output->driver_private;
1395 int j;
1396
1397 output->possible_clones = 0;
1398 if (drmmode_output->enc_clones == 0)
1399 continue;
1400
1401 for (j = 0; j < xf86_config->num_output; j++) {
1402 struct drmmode_output_priv *clone = xf86_config->output[j]->driver_private;
1403
1404 if ((i != j) &&
1405 (clone->enc_mask != 0) &&
1406 (drmmode_output->enc_clones == clone->enc_mask))
1407
1408 output->possible_clones |= (1 << j);
1409 }
1410 }
Rob Clark74210d52012-01-08 17:59:08 -06001411}
Rob Clark487687e2011-07-17 17:29:02 -05001412
Paul Geary8ffd91c2013-04-11 16:03:15 +01001413void set_scanout_bo(ScrnInfoPtr pScrn, struct armsoc_bo *bo)
David Garbett3688b332012-05-11 12:17:34 +01001414{
Dave Barnish2e998952013-06-11 16:31:10 +01001415 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
David Garbett3688b332012-05-11 12:17:34 +01001416
1417 /* It had better have a framebuffer if we're scanning it out */
Paul Geary8ffd91c2013-04-11 16:03:15 +01001418 assert(armsoc_bo_get_fb(bo));
David Garbett3688b332012-05-11 12:17:34 +01001419
Paul Geary8ffd91c2013-04-11 16:03:15 +01001420 pARMSOC->scanout = bo;
David Garbett3688b332012-05-11 12:17:34 +01001421}
1422
Dave Barnishf245da32013-08-30 12:16:58 +01001423static Bool resize_scanout_bo(ScrnInfoPtr pScrn, int width, int height)
Rob Clark487687e2011-07-17 17:29:02 -05001424{
Dave Barnish2e998952013-06-11 16:31:10 +01001425 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001426 ScreenPtr pScreen = pScrn->pScreen;
Sean Paul3e107302012-08-30 12:08:12 -07001427 uint32_t pitch;
Rob Clark487687e2011-07-17 17:29:02 -05001428
1429 TRACE_ENTER();
Dave Barnish33866052013-03-18 10:57:40 +00001430 DEBUG_MSG("Resize: %dx%d", width, height);
Rob Clark487687e2011-07-17 17:29:02 -05001431
1432 pScrn->virtualX = width;
1433 pScrn->virtualY = height;
1434
Dave Barnish2e998952013-06-11 16:31:10 +01001435 if ((width != armsoc_bo_width(pARMSOC->scanout))
Paul Geary8ffd91c2013-04-11 16:03:15 +01001436 || (height != armsoc_bo_height(pARMSOC->scanout))
Dave Barnish2e998952013-06-11 16:31:10 +01001437 || (pScrn->bitsPerPixel != armsoc_bo_bpp(pARMSOC->scanout))) {
Dave Barnish33866052013-03-18 10:57:40 +00001438 struct armsoc_bo *new_scanout;
Rob Clark487687e2011-07-17 17:29:02 -05001439
1440 /* allocate new scanout buffer */
Dave Barnish2e998952013-06-11 16:31:10 +01001441 new_scanout = armsoc_bo_new_with_dim(pARMSOC->dev,
1442 width, height,
1443 pScrn->depth, pScrn->bitsPerPixel,
1444 ARMSOC_BO_SCANOUT);
1445 if (!new_scanout) {
1446 /* Try to use the previous buffer if the new resolution
1447 * is smaller than the one on buffer creation
1448 */
1449 DEBUG_MSG(
1450 "allocate new scanout buffer failed - resizing existing bo");
Dave Barnish33866052013-03-18 10:57:40 +00001451 /* Remove the old fb from the bo */
Dave Barnish2e998952013-06-11 16:31:10 +01001452 if (armsoc_bo_rm_fb(pARMSOC->scanout))
Dave Barnish33866052013-03-18 10:57:40 +00001453 return FALSE;
Dave Barnish2e998952013-06-11 16:31:10 +01001454
Dave Barnish33866052013-03-18 10:57:40 +00001455 /* Resize the bo */
Dave Barnish2e998952013-06-11 16:31:10 +01001456 if (armsoc_bo_resize(pARMSOC->scanout, width, height)) {
Dave Barnish33866052013-03-18 10:57:40 +00001457 armsoc_bo_clear(pARMSOC->scanout);
Ray Smithb4299f82013-03-13 10:08:36 +00001458 if (armsoc_bo_add_fb(pARMSOC->scanout))
1459 ERROR_MSG(
1460 "Failed to add framebuffer to the existing scanout buffer");
Dave Barnish33866052013-03-18 10:57:40 +00001461 return FALSE;
1462 }
Ray Smithb4299f82013-03-13 10:08:36 +00001463
Dave Barnish33866052013-03-18 10:57:40 +00001464 /* Add new fb to the bo */
Ray Smithb4299f82013-03-13 10:08:36 +00001465 if (armsoc_bo_clear(pARMSOC->scanout))
Dave Barnish33866052013-03-18 10:57:40 +00001466 return FALSE;
Dave Barnish2e998952013-06-11 16:31:10 +01001467
Ray Smithb4299f82013-03-13 10:08:36 +00001468 if (armsoc_bo_add_fb(pARMSOC->scanout)) {
1469 ERROR_MSG(
1470 "Failed to add framebuffer to the existing scanout buffer");
1471 return FALSE;
1472 }
1473
Dave Barnish33866052013-03-18 10:57:40 +00001474 pitch = armsoc_bo_pitch(pARMSOC->scanout);
Dave Barnish2e998952013-06-11 16:31:10 +01001475 } else {
Dave Barnish33866052013-03-18 10:57:40 +00001476 DEBUG_MSG("allocated new scanout buffer okay");
1477 pitch = armsoc_bo_pitch(new_scanout);
1478 /* clear new BO and add FB */
Ray Smithb4299f82013-03-13 10:08:36 +00001479 if (armsoc_bo_clear(new_scanout)) {
Paul Geary8ffd91c2013-04-11 16:03:15 +01001480 armsoc_bo_unreference(new_scanout);
David Garbettae5a6362012-07-02 10:15:47 +01001481 return FALSE;
1482 }
Ray Smithb4299f82013-03-13 10:08:36 +00001483
1484 if (armsoc_bo_add_fb(new_scanout)) {
1485 ERROR_MSG(
1486 "Failed to add framebuffer to the new scanout buffer");
1487 armsoc_bo_unreference(new_scanout);
1488 return FALSE;
1489 }
1490
Dave Barnish33866052013-03-18 10:57:40 +00001491 /* Handle dma_buf fd that may be attached to old bo */
Dave Barnish2e998952013-06-11 16:31:10 +01001492 if (armsoc_bo_has_dmabuf(pARMSOC->scanout)) {
Dave Barnish33866052013-03-18 10:57:40 +00001493 int res;
1494
1495 armsoc_bo_clear_dmabuf(pARMSOC->scanout);
1496 res = armsoc_bo_set_dmabuf(new_scanout);
Dave Barnish2e998952013-06-11 16:31:10 +01001497 if (res) {
1498 ERROR_MSG(
1499 "Unable to attach dma_buf fd to new scanout buffer - %d (%s)\n",
1500 res, strerror(res));
Dave Barnish33866052013-03-18 10:57:40 +00001501 armsoc_bo_unreference(new_scanout);
1502 return FALSE;
1503 }
1504 }
1505 /* delete old scanout buffer */
1506 armsoc_bo_unreference(pARMSOC->scanout);
1507 /* use new scanout buffer */
1508 set_scanout_bo(pScrn, new_scanout);
David Garbettae5a6362012-07-02 10:15:47 +01001509 }
Daniel Kurtz34e72b02012-10-19 14:02:05 -07001510 pScrn->displayWidth = pitch / ((pScrn->bitsPerPixel + 7) / 8);
Dave Barnish2e998952013-06-11 16:31:10 +01001511 } else
Paul Geary8ffd91c2013-04-11 16:03:15 +01001512 pitch = armsoc_bo_pitch(pARMSOC->scanout);
Rob Clark487687e2011-07-17 17:29:02 -05001513
1514 if (pScreen && pScreen->ModifyPixmapHeader) {
1515 PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
Dave Barnish33866052013-03-18 10:57:40 +00001516
Rob Clark487687e2011-07-17 17:29:02 -05001517 pScreen->ModifyPixmapHeader(rootPixmap,
1518 pScrn->virtualX, pScrn->virtualY,
1519 pScrn->depth, pScrn->bitsPerPixel, pitch,
Paul Geary8ffd91c2013-04-11 16:03:15 +01001520 armsoc_bo_map(pARMSOC->scanout));
Ray Smithedccfd82013-05-31 15:57:12 +01001521
Dave Barnishe762b122013-08-12 17:13:46 +01001522 /* Bump the serial number to ensure that all existing DRI2
1523 * buffers are invalidated.
Ray Smithedccfd82013-05-31 15:57:12 +01001524 *
Dave Barnishe762b122013-08-12 17:13:46 +01001525 * This is particularly required for when the resolution is
1526 * changed and then reverted to the original size without a
1527 * DRI2 client/s getting a new buffer. Without this, the
1528 * drawable is the same size and serial number so the old
1529 * DRI2Buffer will be returned, even though the backing buffer
1530 * has been deleted.
Ray Smithedccfd82013-05-31 15:57:12 +01001531 */
1532 rootPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
Rob Clark487687e2011-07-17 17:29:02 -05001533 }
Dave Barnishf245da32013-08-30 12:16:58 +01001534 TRACE_EXIT();
1535 return TRUE;
1536}
1537
1538static Bool
1539drmmode_xf86crtc_resize(ScrnInfoPtr pScrn, int width, int height)
1540{
1541 int i;
1542 xf86CrtcConfigPtr xf86_config;
1543
1544 TRACE_ENTER();
Dave Barnishf245da32013-08-30 12:16:58 +01001545 if (!resize_scanout_bo(pScrn, width, height))
1546 return FALSE;
Rob Clark487687e2011-07-17 17:29:02 -05001547
Brian Starkeycd684422012-09-20 09:28:04 +01001548 /* Framebuffer needs to be reset on all CRTCs, not just
1549 * those that have repositioned */
1550 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1551 for (i = 0; i < xf86_config->num_crtc; i++) {
1552 xf86CrtcPtr crtc = xf86_config->crtc[i];
1553
1554 if (!crtc->enabled)
1555 continue;
1556
1557 drmmode_set_mode_major(crtc, &crtc->mode,
1558 crtc->rotation, crtc->x, crtc->y);
1559 }
1560
Rob Clark487687e2011-07-17 17:29:02 -05001561 TRACE_EXIT();
1562 return TRUE;
Rob Clark74210d52012-01-08 17:59:08 -06001563}
Rob Clark487687e2011-07-17 17:29:02 -05001564
1565static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
Daniel Kurtze81fdab2012-12-25 16:43:04 +08001566 .resize = drmmode_xf86crtc_resize
Rob Clark487687e2011-07-17 17:29:02 -05001567};
1568
1569
1570Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
1571{
Dave Barnish2e998952013-06-11 16:31:10 +01001572 struct drmmode_rec *drmmode;
Rob Clark74210d52012-01-08 17:59:08 -06001573 int i;
Rob Clark487687e2011-07-17 17:29:02 -05001574
Rob Clark74210d52012-01-08 17:59:08 -06001575 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001576
Rob Clark74210d52012-01-08 17:59:08 -06001577 drmmode = calloc(1, sizeof *drmmode);
Dave Barnish2e998952013-06-11 16:31:10 +01001578 if (!drmmode)
Paul Geary6fe52f32013-04-03 11:12:24 +01001579 return FALSE;
Paul Geary6fe52f32013-04-03 11:12:24 +01001580
Rob Clark74210d52012-01-08 17:59:08 -06001581 drmmode->fd = fd;
Rob Clark487687e2011-07-17 17:29:02 -05001582
Rob Clark74210d52012-01-08 17:59:08 -06001583 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
Rob Clark487687e2011-07-17 17:29:02 -05001584
1585
Rob Clark74210d52012-01-08 17:59:08 -06001586 drmmode->cpp = cpp;
1587 drmmode->mode_res = drmModeGetResources(drmmode->fd);
1588 if (!drmmode->mode_res) {
Paul Geary6fe52f32013-04-03 11:12:24 +01001589 free(drmmode);
Rob Clark74210d52012-01-08 17:59:08 -06001590 return FALSE;
1591 } else {
1592 DEBUG_MSG("Got KMS resources");
1593 DEBUG_MSG(" %d connectors, %d encoders",
1594 drmmode->mode_res->count_connectors,
1595 drmmode->mode_res->count_encoders);
1596 DEBUG_MSG(" %d crtcs, %d fbs",
Dave Barnish2e998952013-06-11 16:31:10 +01001597 drmmode->mode_res->count_crtcs,
1598 drmmode->mode_res->count_fbs);
Rob Clark74210d52012-01-08 17:59:08 -06001599 DEBUG_MSG(" %dx%d minimum resolution",
Dave Barnish2e998952013-06-11 16:31:10 +01001600 drmmode->mode_res->min_width,
1601 drmmode->mode_res->min_height);
Rob Clark74210d52012-01-08 17:59:08 -06001602 DEBUG_MSG(" %dx%d maximum resolution",
Dave Barnish2e998952013-06-11 16:31:10 +01001603 drmmode->mode_res->max_width,
1604 drmmode->mode_res->max_height);
Rob Clark74210d52012-01-08 17:59:08 -06001605 }
1606 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
1607 drmmode->mode_res->max_height);
Dave Barnishf0952c12013-05-10 15:52:23 +01001608
Dave Barnish2e998952013-06-11 16:31:10 +01001609 if (ARMSOCPTR(pScrn)->crtcNum == -1) {
Dave Barnishf0952c12013-05-10 15:52:23 +01001610 INFO_MSG("Adding all CRTCs");
1611 for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1612 drmmode_crtc_init(pScrn, drmmode, i);
Dave Barnish2e998952013-06-11 16:31:10 +01001613 } else if (ARMSOCPTR(pScrn)->crtcNum < drmmode->mode_res->count_crtcs) {
Dave Barnishf0952c12013-05-10 15:52:23 +01001614 drmmode_crtc_init(pScrn, drmmode, ARMSOCPTR(pScrn)->crtcNum);
1615 } else {
Dave Barnish2e998952013-06-11 16:31:10 +01001616 ERROR_MSG(
1617 "Specified more Screens in xorg.conf than there are DRM CRTCs");
Dave Barnishf0952c12013-05-10 15:52:23 +01001618 return FALSE;
1619 }
Rob Clark487687e2011-07-17 17:29:02 -05001620
Dave Barnish2e998952013-06-11 16:31:10 +01001621 if (ARMSOCPTR(pScrn)->crtcNum != -1) {
1622 if (ARMSOCPTR(pScrn)->crtcNum <
1623 drmmode->mode_res->count_connectors)
1624 drmmode_output_init(pScrn,
1625 drmmode, ARMSOCPTR(pScrn)->crtcNum);
Ray Smithc9c2faf2013-06-07 15:37:19 +01001626 else
1627 return FALSE;
1628 } else {
1629 for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1630 drmmode_output_init(pScrn, drmmode, i);
1631 }
Dave Barnish70df8ae2013-09-26 12:44:27 +01001632 drmmode_clones_init(pScrn, drmmode);
Rob Clark487687e2011-07-17 17:29:02 -05001633
Rob Clark74210d52012-01-08 17:59:08 -06001634 xf86InitialConfiguration(pScrn, TRUE);
Rob Clark487687e2011-07-17 17:29:02 -05001635
Rob Clark74210d52012-01-08 17:59:08 -06001636 TRACE_EXIT();
Rob Clark487687e2011-07-17 17:29:02 -05001637
Rob Clark74210d52012-01-08 17:59:08 -06001638 return TRUE;
1639}
Rob Clark487687e2011-07-17 17:29:02 -05001640
1641void
Cooper Yuana83caa62012-06-28 17:19:06 +02001642drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y)
Rob Clark487687e2011-07-17 17:29:02 -05001643{
1644 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
1645 xf86OutputPtr output = config->output[config->compat_output];
1646 xf86CrtcPtr crtc = output->crtc;
1647
1648 if (!crtc || !crtc->enabled)
1649 return;
1650
1651 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
1652}
1653
Rob Clark4b8f30a2011-08-28 12:51:26 -05001654/*
1655 * Page Flipping
1656 */
1657
1658static void
1659page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
Rob Clark74210d52012-01-08 17:59:08 -06001660 unsigned int tv_usec, void *user_data)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001661{
Paul Geary8ffd91c2013-04-11 16:03:15 +01001662 ARMSOCDRI2SwapComplete(user_data);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001663}
1664
1665static drmEventContext event_context = {
1666 .version = DRM_EVENT_CONTEXT_VERSION,
1667 .page_flip_handler = page_flip_handler,
1668};
1669
John Sheu022833e2012-08-15 11:40:11 -07001670int
Rob Clark4b8f30a2011-08-28 12:51:26 -05001671drmmode_page_flip(DrawablePtr draw, uint32_t fb_id, void *priv)
1672{
Daniel Kurtz0361e002013-08-14 21:07:01 +08001673 ScreenPtr pScreen = draw->pScreen;
1674 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Dave Barnish2e998952013-06-11 16:31:10 +01001675 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
Ray Smith3c33c3d2013-03-26 16:06:37 +00001676 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
Dave Barnish2e998952013-06-11 16:31:10 +01001677 struct drmmode_crtc_private_rec *crtc = config->crtc[0]->driver_private;
1678 struct drmmode_rec *mode = crtc->drmmode;
John Sheu022833e2012-08-15 11:40:11 -07001679 int ret, i, failed = 0, num_flipped = 0;
Raymond Smith16a910e2012-05-09 13:04:51 +01001680 unsigned int flags = 0;
1681
Dave Barnishde45ed42013-06-05 13:47:56 +01001682 if (pARMSOC->drmmode_interface->use_page_flip_events)
Ray Smith3c33c3d2013-03-26 16:06:37 +00001683 flags |= DRM_MODE_PAGE_FLIP_EVENT;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001684
1685 /* if we can flip, we must be fullscreen.. so flip all CRTC's.. */
1686 for (i = 0; i < config->num_crtc; i++) {
1687 crtc = config->crtc[i]->driver_private;
1688
Ray Smithe20b3812013-04-08 12:53:53 +01001689 if (!config->crtc[i]->enabled)
1690 continue;
1691
Dave Barnish6a1b31e2013-09-25 11:09:05 +01001692 ret = drmModePageFlip(mode->fd, crtc->crtc_id,
Raymond Smith16a910e2012-05-09 13:04:51 +01001693 fb_id, flags, priv);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001694 if (ret) {
Ray Smith3c33c3d2013-03-26 16:06:37 +00001695 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
Dave Barnish2e998952013-06-11 16:31:10 +01001696 "flip queue failed: %s\n",
1697 strerror(errno));
John Sheu022833e2012-08-15 11:40:11 -07001698 failed = 1;
Dave Barnish2e998952013-06-11 16:31:10 +01001699 } else
John Sheu022833e2012-08-15 11:40:11 -07001700 num_flipped += 1;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001701 }
1702
John Sheu022833e2012-08-15 11:40:11 -07001703 if (failed)
1704 return -(num_flipped + 1);
1705 else
1706 return num_flipped;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001707}
Rob Clark487687e2011-07-17 17:29:02 -05001708
1709/*
1710 * Hot Plug Event handling:
David Garbettdbecfdd2013-08-28 10:45:03 +01001711 * TODO: MIDEGL-1441: Do we need to keep this handler, which
1712 * Rob originally wrote?
Rob Clark487687e2011-07-17 17:29:02 -05001713 */
Rob Clark487687e2011-07-17 17:29:02 -05001714static void
1715drmmode_handle_uevents(int fd, void *closure)
1716{
Rob Clark74210d52012-01-08 17:59:08 -06001717 ScrnInfoPtr pScrn = closure;
Dave Barnish2e998952013-06-11 16:31:10 +01001718 struct ARMSOCRec *pARMSOC = ARMSOCPTR(pScrn);
1719 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
Rob Clark74210d52012-01-08 17:59:08 -06001720 struct udev_device *dev;
1721 const char *hotplug;
1722 struct stat s;
1723 dev_t udev_devnum;
Rob Clark487687e2011-07-17 17:29:02 -05001724
Rob Clark74210d52012-01-08 17:59:08 -06001725 dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1726 if (!dev)
1727 return;
Rob Clark487687e2011-07-17 17:29:02 -05001728
Rob Clark74210d52012-01-08 17:59:08 -06001729 /*
1730 * Check to make sure this event is directed at our
1731 * device (by comparing dev_t values), then make
1732 * sure it's a hotplug event (HOTPLUG=1)
1733 */
1734 udev_devnum = udev_device_get_devnum(dev);
David Garbettdbecfdd2013-08-28 10:45:03 +01001735 if (fstat(pARMSOC->drmFD, &s)) {
1736 ERROR_MSG("fstat failed: %s", strerror(errno));
1737 udev_device_unref(dev);
1738 return;
1739 }
Rob Clark487687e2011-07-17 17:29:02 -05001740
Rob Clark74210d52012-01-08 17:59:08 -06001741 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
Rob Clark487687e2011-07-17 17:29:02 -05001742
Rob Clark74210d52012-01-08 17:59:08 -06001743 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "hotplug=%s, match=%d\n", hotplug,
Dave Barnish2e998952013-06-11 16:31:10 +01001744 !memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)));
Rob Clark487687e2011-07-17 17:29:02 -05001745
Dave Barnish2e998952013-06-11 16:31:10 +01001746 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
Rob Clark74210d52012-01-08 17:59:08 -06001747 hotplug && atoi(hotplug) == 1) {
Daniel Kurtz0361e002013-08-14 21:07:01 +08001748 RRGetInfo(xf86ScrnToScreen(pScrn), TRUE);
Rob Clark74210d52012-01-08 17:59:08 -06001749 }
1750 udev_device_unref(dev);
1751}
Rob Clark487687e2011-07-17 17:29:02 -05001752
Rob Clark4b8f30a2011-08-28 12:51:26 -05001753static void
Rob Clark487687e2011-07-17 17:29:02 -05001754drmmode_uevent_init(ScrnInfoPtr pScrn)
1755{
Dave Barnish2e998952013-06-11 16:31:10 +01001756 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
Rob Clark74210d52012-01-08 17:59:08 -06001757 struct udev *u;
1758 struct udev_monitor *mon;
Rob Clark487687e2011-07-17 17:29:02 -05001759
Rob Clark74210d52012-01-08 17:59:08 -06001760 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001761
Rob Clark74210d52012-01-08 17:59:08 -06001762 u = udev_new();
1763 if (!u)
1764 return;
1765 mon = udev_monitor_new_from_netlink(u, "udev");
1766 if (!mon) {
1767 udev_unref(u);
1768 return;
1769 }
Rob Clark487687e2011-07-17 17:29:02 -05001770
Rob Clark74210d52012-01-08 17:59:08 -06001771 if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1772 "drm",
1773 "drm_minor") < 0 ||
1774 udev_monitor_enable_receiving(mon) < 0) {
1775 udev_monitor_unref(mon);
1776 udev_unref(u);
1777 return;
1778 }
Rob Clark487687e2011-07-17 17:29:02 -05001779
Rob Clark74210d52012-01-08 17:59:08 -06001780 drmmode->uevent_handler =
1781 xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1782 drmmode_handle_uevents, pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001783
Rob Clark74210d52012-01-08 17:59:08 -06001784 drmmode->uevent_monitor = mon;
Rob Clark487687e2011-07-17 17:29:02 -05001785
Rob Clark74210d52012-01-08 17:59:08 -06001786 TRACE_EXIT();
1787}
Rob Clark487687e2011-07-17 17:29:02 -05001788
Rob Clark4b8f30a2011-08-28 12:51:26 -05001789static void
Rob Clark487687e2011-07-17 17:29:02 -05001790drmmode_uevent_fini(ScrnInfoPtr pScrn)
1791{
Dave Barnish2e998952013-06-11 16:31:10 +01001792 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
Rob Clark487687e2011-07-17 17:29:02 -05001793
Rob Clark74210d52012-01-08 17:59:08 -06001794 TRACE_ENTER();
Rob Clark487687e2011-07-17 17:29:02 -05001795
Rob Clark74210d52012-01-08 17:59:08 -06001796 if (drmmode->uevent_handler) {
1797 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1798 xf86RemoveGeneralHandler(drmmode->uevent_handler);
Rob Clark487687e2011-07-17 17:29:02 -05001799
Rob Clark74210d52012-01-08 17:59:08 -06001800 udev_monitor_unref(drmmode->uevent_monitor);
1801 udev_unref(u);
1802 }
Rob Clark487687e2011-07-17 17:29:02 -05001803
Rob Clark74210d52012-01-08 17:59:08 -06001804 TRACE_EXIT();
1805}
Rob Clark4b8f30a2011-08-28 12:51:26 -05001806
1807static void
1808drmmode_wakeup_handler(pointer data, int err, pointer p)
1809{
Ray Smith04af9992013-06-26 13:44:54 +01001810 int fd = (int)data;
Rob Clark4b8f30a2011-08-28 12:51:26 -05001811 fd_set *read_mask = p;
1812
Ray Smith04af9992013-06-26 13:44:54 +01001813 if (err < 0)
Rob Clark4b8f30a2011-08-28 12:51:26 -05001814 return;
1815
Ray Smith04af9992013-06-26 13:44:54 +01001816 if (FD_ISSET(fd, read_mask))
1817 drmHandleEvent(fd, &event_context);
1818}
Paul Geary6fe52f32013-04-03 11:12:24 +01001819
Ray Smith04af9992013-06-26 13:44:54 +01001820void drmmode_init_wakeup_handler(int fd)
1821{
1822 AddGeneralSocket(fd);
1823 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1824 drmmode_wakeup_handler, (pointer)fd);
1825}
1826
1827void drmmode_fini_wakeup_handler(int fd)
1828{
1829 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1830 drmmode_wakeup_handler, (pointer)fd);
1831 RemoveGeneralSocket(fd);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001832}
1833
1834void
Rob Clark67b875f2012-04-20 19:13:57 -05001835drmmode_wait_for_event(ScrnInfoPtr pScrn)
1836{
Dave Barnish2e998952013-06-11 16:31:10 +01001837 struct drmmode_rec *drmmode = drmmode_from_scrn(pScrn);
Rob Clark67b875f2012-04-20 19:13:57 -05001838 drmHandleEvent(drmmode->fd, &event_context);
1839}
1840
1841void
Rob Clark4b8f30a2011-08-28 12:51:26 -05001842drmmode_screen_init(ScrnInfoPtr pScrn)
1843{
Rob Clark4b8f30a2011-08-28 12:51:26 -05001844 drmmode_uevent_init(pScrn);
Rob Clark4b8f30a2011-08-28 12:51:26 -05001845}
1846
1847void
1848drmmode_screen_fini(ScrnInfoPtr pScrn)
1849{
1850 drmmode_uevent_fini(pScrn);
1851}