xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/drivers/modesetting/drmmode_display.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2007 Red Hat, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the next
12*4882a593Smuzhiyun  * paragraph) shall be included in all copies or substantial portions of the
13*4882a593Smuzhiyun  * Software.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*4882a593Smuzhiyun  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*4882a593Smuzhiyun  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*4882a593Smuzhiyun  * SOFTWARE.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Authors:
24*4882a593Smuzhiyun  *    Dave Airlie <airlied@redhat.com>
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
29*4882a593Smuzhiyun #include "dix-config.h"
30*4882a593Smuzhiyun #endif
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include <errno.h>
33*4882a593Smuzhiyun #include <sys/ioctl.h>
34*4882a593Smuzhiyun #include <sys/mman.h>
35*4882a593Smuzhiyun #include <sys/time.h>
36*4882a593Smuzhiyun #include <unistd.h>
37*4882a593Smuzhiyun #include "dumb_bo.h"
38*4882a593Smuzhiyun #include "inputstr.h"
39*4882a593Smuzhiyun #include "xf86str.h"
40*4882a593Smuzhiyun #include "X11/Xatom.h"
41*4882a593Smuzhiyun #include "mi.h"
42*4882a593Smuzhiyun #include "micmap.h"
43*4882a593Smuzhiyun #include "xf86cmap.h"
44*4882a593Smuzhiyun #include "xf86DDC.h"
45*4882a593Smuzhiyun #include <drm_fourcc.h>
46*4882a593Smuzhiyun #include <drm_mode.h>
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #include <xf86drm.h>
49*4882a593Smuzhiyun #include "xf86Crtc.h"
50*4882a593Smuzhiyun #include "drmmode_display.h"
51*4882a593Smuzhiyun #include "present.h"
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #include <cursorstr.h>
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #include <X11/extensions/dpmsconst.h>
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #include "driver.h"
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun static void drmmode_destroy_flip_fb(xf86CrtcPtr crtc);
62*4882a593Smuzhiyun static Bool drmmode_create_flip_fb(xf86CrtcPtr crtc);
63*4882a593Smuzhiyun static Bool drmmode_apply_transform(xf86CrtcPtr crtc);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob * blob)66*4882a593Smuzhiyun formats_ptr(struct drm_format_modifier_blob *blob)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun     return (uint32_t *)(((char *)blob) + blob->formats_offset);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob * blob)72*4882a593Smuzhiyun modifiers_ptr(struct drm_format_modifier_blob *blob)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun     return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static uint32_t
get_opaque_format(uint32_t format)78*4882a593Smuzhiyun get_opaque_format(uint32_t format)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun     switch (format) {
81*4882a593Smuzhiyun     case DRM_FORMAT_ARGB8888:
82*4882a593Smuzhiyun         return DRM_FORMAT_XRGB8888;
83*4882a593Smuzhiyun     case DRM_FORMAT_ARGB2101010:
84*4882a593Smuzhiyun         return DRM_FORMAT_XRGB2101010;
85*4882a593Smuzhiyun     default:
86*4882a593Smuzhiyun         return format;
87*4882a593Smuzhiyun     }
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun Bool
drmmode_is_format_supported(ScrnInfoPtr scrn,uint32_t format,uint64_t modifier)91*4882a593Smuzhiyun drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
94*4882a593Smuzhiyun     int c, i, j;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun     /* BO are imported as opaque surface, so let's pretend there is no alpha */
97*4882a593Smuzhiyun     format = get_opaque_format(format);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun     for (c = 0; c < xf86_config->num_crtc; c++) {
100*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[c];
101*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
102*4882a593Smuzhiyun         Bool found = FALSE;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun         if (!crtc->enabled)
105*4882a593Smuzhiyun             continue;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun         if (drmmode_crtc->num_formats == 0)
108*4882a593Smuzhiyun             continue;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun         for (i = 0; i < drmmode_crtc->num_formats; i++) {
111*4882a593Smuzhiyun             drmmode_format_ptr iter = &drmmode_crtc->formats[i];
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun             if (iter->format != format)
114*4882a593Smuzhiyun                 continue;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun             if (modifier == DRM_FORMAT_MOD_INVALID ||
117*4882a593Smuzhiyun                 iter->num_modifiers == 0) {
118*4882a593Smuzhiyun                 found = TRUE;
119*4882a593Smuzhiyun                 break;
120*4882a593Smuzhiyun             }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun             for (j = 0; j < iter->num_modifiers; j++) {
123*4882a593Smuzhiyun                 if (iter->modifiers[j] == modifier) {
124*4882a593Smuzhiyun                     found = TRUE;
125*4882a593Smuzhiyun                     break;
126*4882a593Smuzhiyun                 }
127*4882a593Smuzhiyun             }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun             break;
130*4882a593Smuzhiyun         }
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun         if (!found)
133*4882a593Smuzhiyun             return FALSE;
134*4882a593Smuzhiyun     }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun     return TRUE;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun #ifdef GBM_BO_WITH_MODIFIERS
140*4882a593Smuzhiyun static uint32_t
get_modifiers_set(ScrnInfoPtr scrn,uint32_t format,uint64_t ** modifiers,Bool enabled_crtc_only,Bool exclude_multiplane)141*4882a593Smuzhiyun get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
142*4882a593Smuzhiyun                   Bool enabled_crtc_only, Bool exclude_multiplane)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
145*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
146*4882a593Smuzhiyun     drmmode_ptr drmmode = &ms->drmmode;
147*4882a593Smuzhiyun     int c, i, j, k, count_modifiers = 0;
148*4882a593Smuzhiyun     uint64_t *tmp, *ret = NULL;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun     /* BOs are imported as opaque surfaces, so pretend the same thing here */
151*4882a593Smuzhiyun     format = get_opaque_format(format);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun     *modifiers = NULL;
154*4882a593Smuzhiyun     for (c = 0; c < xf86_config->num_crtc; c++) {
155*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[c];
156*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun         if (enabled_crtc_only && !crtc->enabled)
159*4882a593Smuzhiyun             continue;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun         for (i = 0; i < drmmode_crtc->num_formats; i++) {
162*4882a593Smuzhiyun             drmmode_format_ptr iter = &drmmode_crtc->formats[i];
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun             if (iter->format != format)
165*4882a593Smuzhiyun                 continue;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun             for (j = 0; j < iter->num_modifiers; j++) {
168*4882a593Smuzhiyun                 Bool found = FALSE;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		/* Don't choose multi-plane formats for our screen pixmap.
171*4882a593Smuzhiyun 		 * These will get used with frontbuffer rendering, which will
172*4882a593Smuzhiyun 		 * lead to worse-than-tearing with multi-plane formats, as the
173*4882a593Smuzhiyun 		 * primary and auxiliary planes go out of sync. */
174*4882a593Smuzhiyun 		if (exclude_multiplane &&
175*4882a593Smuzhiyun                     gbm_device_get_format_modifier_plane_count(drmmode->gbm,
176*4882a593Smuzhiyun                                                                format,
177*4882a593Smuzhiyun                                                                iter->modifiers[j]) > 1) {
178*4882a593Smuzhiyun                     continue;
179*4882a593Smuzhiyun                 }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun                 for (k = 0; k < count_modifiers; k++) {
182*4882a593Smuzhiyun                     if (iter->modifiers[j] == ret[k])
183*4882a593Smuzhiyun                         found = TRUE;
184*4882a593Smuzhiyun                 }
185*4882a593Smuzhiyun                 if (!found) {
186*4882a593Smuzhiyun                     count_modifiers++;
187*4882a593Smuzhiyun                     tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
188*4882a593Smuzhiyun                     if (!tmp) {
189*4882a593Smuzhiyun                         free(ret);
190*4882a593Smuzhiyun                         return 0;
191*4882a593Smuzhiyun                     }
192*4882a593Smuzhiyun                     ret = tmp;
193*4882a593Smuzhiyun                     ret[count_modifiers - 1] = iter->modifiers[j];
194*4882a593Smuzhiyun                 }
195*4882a593Smuzhiyun             }
196*4882a593Smuzhiyun         }
197*4882a593Smuzhiyun     }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun     *modifiers = ret;
200*4882a593Smuzhiyun     return count_modifiers;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun static Bool
get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)204*4882a593Smuzhiyun get_drawable_modifiers(DrawablePtr draw, uint32_t format,
205*4882a593Smuzhiyun                        uint32_t *num_modifiers, uint64_t **modifiers)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
208*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun     if (!present_can_window_flip((WindowPtr) draw) ||
211*4882a593Smuzhiyun         !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
212*4882a593Smuzhiyun         *num_modifiers = 0;
213*4882a593Smuzhiyun         *modifiers = NULL;
214*4882a593Smuzhiyun         return TRUE;
215*4882a593Smuzhiyun     }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun     *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
218*4882a593Smuzhiyun     return TRUE;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun #endif
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn,const char * s,char * output_name)223*4882a593Smuzhiyun drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun     char **token = xstrtokenize(s, ", \t\n\r");
226*4882a593Smuzhiyun     Bool ret = FALSE;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun     if (!token)
229*4882a593Smuzhiyun         return FALSE;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun     for (int i = 0; token[i]; i++) {
232*4882a593Smuzhiyun         if (strcmp(token[i], output_name) == 0)
233*4882a593Smuzhiyun             ret = TRUE;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun         free(token[i]);
236*4882a593Smuzhiyun     }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun     free(token);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun     return ret;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun static uint64_t
drmmode_prop_get_value(drmmode_prop_info_ptr info,drmModeObjectPropertiesPtr props,uint64_t def)244*4882a593Smuzhiyun drmmode_prop_get_value(drmmode_prop_info_ptr info,
245*4882a593Smuzhiyun                        drmModeObjectPropertiesPtr props,
246*4882a593Smuzhiyun                        uint64_t def)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun     unsigned int i;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun     if (info->prop_id == 0)
251*4882a593Smuzhiyun         return def;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun     for (i = 0; i < props->count_props; i++) {
254*4882a593Smuzhiyun         unsigned int j;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun         if (props->props[i] != info->prop_id)
257*4882a593Smuzhiyun             continue;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun         /* Simple (non-enum) types can return the value directly */
260*4882a593Smuzhiyun         if (info->num_enum_values == 0)
261*4882a593Smuzhiyun             return props->prop_values[i];
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun         /* Map from raw value to enum value */
264*4882a593Smuzhiyun         for (j = 0; j < info->num_enum_values; j++) {
265*4882a593Smuzhiyun             if (!info->enum_values[j].valid)
266*4882a593Smuzhiyun                 continue;
267*4882a593Smuzhiyun             if (info->enum_values[j].value != props->prop_values[i])
268*4882a593Smuzhiyun                 continue;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun             return j;
271*4882a593Smuzhiyun         }
272*4882a593Smuzhiyun     }
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun     return def;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun static uint32_t
drmmode_prop_info_update(drmmode_ptr drmmode,drmmode_prop_info_ptr info,unsigned int num_infos,drmModeObjectProperties * props)278*4882a593Smuzhiyun drmmode_prop_info_update(drmmode_ptr drmmode,
279*4882a593Smuzhiyun                          drmmode_prop_info_ptr info,
280*4882a593Smuzhiyun                          unsigned int num_infos,
281*4882a593Smuzhiyun                          drmModeObjectProperties *props)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun     drmModePropertyRes *prop;
284*4882a593Smuzhiyun     uint32_t valid_mask = 0;
285*4882a593Smuzhiyun     unsigned i, j;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun     assert(num_infos <= 32 && "update return type");
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun     for (i = 0; i < props->count_props; i++) {
290*4882a593Smuzhiyun         Bool props_incomplete = FALSE;
291*4882a593Smuzhiyun         unsigned int k;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun         for (j = 0; j < num_infos; j++) {
294*4882a593Smuzhiyun             if (info[j].prop_id == props->props[i])
295*4882a593Smuzhiyun                 break;
296*4882a593Smuzhiyun             if (!info[j].prop_id)
297*4882a593Smuzhiyun                 props_incomplete = TRUE;
298*4882a593Smuzhiyun         }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun         /* We've already discovered this property. */
301*4882a593Smuzhiyun         if (j != num_infos)
302*4882a593Smuzhiyun             continue;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun         /* We haven't found this property ID, but as we've already
305*4882a593Smuzhiyun          * found all known properties, we don't need to look any
306*4882a593Smuzhiyun          * further. */
307*4882a593Smuzhiyun         if (!props_incomplete)
308*4882a593Smuzhiyun             break;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun         prop = drmModeGetProperty(drmmode->fd, props->props[i]);
311*4882a593Smuzhiyun         if (!prop)
312*4882a593Smuzhiyun             continue;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun         for (j = 0; j < num_infos; j++) {
315*4882a593Smuzhiyun             if (!strcmp(prop->name, info[j].name))
316*4882a593Smuzhiyun                 break;
317*4882a593Smuzhiyun         }
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun         /* We don't know/care about this property. */
320*4882a593Smuzhiyun         if (j == num_infos) {
321*4882a593Smuzhiyun             drmModeFreeProperty(prop);
322*4882a593Smuzhiyun             continue;
323*4882a593Smuzhiyun         }
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun         info[j].prop_id = props->props[i];
326*4882a593Smuzhiyun         info[j].value = props->prop_values[i];
327*4882a593Smuzhiyun         valid_mask |= 1U << j;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun         if (info[j].num_enum_values == 0) {
330*4882a593Smuzhiyun             drmModeFreeProperty(prop);
331*4882a593Smuzhiyun             continue;
332*4882a593Smuzhiyun         }
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun         if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
335*4882a593Smuzhiyun             xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
336*4882a593Smuzhiyun                        "expected property %s to be an enum,"
337*4882a593Smuzhiyun                        " but it is not; ignoring\n", prop->name);
338*4882a593Smuzhiyun             drmModeFreeProperty(prop);
339*4882a593Smuzhiyun             continue;
340*4882a593Smuzhiyun         }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun         for (k = 0; k < info[j].num_enum_values; k++) {
343*4882a593Smuzhiyun             int l;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun             if (info[j].enum_values[k].valid)
346*4882a593Smuzhiyun                 continue;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun             for (l = 0; l < prop->count_enums; l++) {
349*4882a593Smuzhiyun                 if (!strcmp(prop->enums[l].name,
350*4882a593Smuzhiyun                             info[j].enum_values[k].name))
351*4882a593Smuzhiyun                     break;
352*4882a593Smuzhiyun             }
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun             if (l == prop->count_enums)
355*4882a593Smuzhiyun                 continue;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun             info[j].enum_values[k].valid = TRUE;
358*4882a593Smuzhiyun             info[j].enum_values[k].value = prop->enums[l].value;
359*4882a593Smuzhiyun         }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun         drmModeFreeProperty(prop);
362*4882a593Smuzhiyun     }
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun     return valid_mask;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun static Bool
drmmode_prop_info_copy(drmmode_prop_info_ptr dst,const drmmode_prop_info_rec * src,unsigned int num_props,Bool copy_prop_id)368*4882a593Smuzhiyun drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
369*4882a593Smuzhiyun 		       const drmmode_prop_info_rec *src,
370*4882a593Smuzhiyun 		       unsigned int num_props,
371*4882a593Smuzhiyun 		       Bool copy_prop_id)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun     unsigned int i;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun     memcpy(dst, src, num_props * sizeof(*dst));
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun     for (i = 0; i < num_props; i++) {
378*4882a593Smuzhiyun         unsigned int j;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun         if (copy_prop_id)
381*4882a593Smuzhiyun             dst[i].prop_id = src[i].prop_id;
382*4882a593Smuzhiyun         else
383*4882a593Smuzhiyun             dst[i].prop_id = 0;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun         if (src[i].num_enum_values == 0)
386*4882a593Smuzhiyun             continue;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun         dst[i].enum_values =
389*4882a593Smuzhiyun             malloc(src[i].num_enum_values *
390*4882a593Smuzhiyun                     sizeof(*dst[i].enum_values));
391*4882a593Smuzhiyun         if (!dst[i].enum_values)
392*4882a593Smuzhiyun             goto err;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun         memcpy(dst[i].enum_values, src[i].enum_values,
395*4882a593Smuzhiyun                 src[i].num_enum_values * sizeof(*dst[i].enum_values));
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun         for (j = 0; j < dst[i].num_enum_values; j++)
398*4882a593Smuzhiyun             dst[i].enum_values[j].valid = FALSE;
399*4882a593Smuzhiyun     }
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun     return TRUE;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun err:
404*4882a593Smuzhiyun     while (i--)
405*4882a593Smuzhiyun         free(dst[i].enum_values);
406*4882a593Smuzhiyun     return FALSE;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun static void
drmmode_prop_info_free(drmmode_prop_info_ptr info,int num_props)410*4882a593Smuzhiyun drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun     int i;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun     for (i = 0; i < num_props; i++)
415*4882a593Smuzhiyun         free(info[i].enum_values);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun static void
419*4882a593Smuzhiyun drmmode_ConvertToKMode(xf86CrtcPtr crtc,
420*4882a593Smuzhiyun                        drmModeModeInfo * kmode, DisplayModePtr mode);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun static int
plane_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_plane_property prop,uint64_t val)424*4882a593Smuzhiyun plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
425*4882a593Smuzhiyun                enum drmmode_plane_property prop, uint64_t val)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun     drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
428*4882a593Smuzhiyun     int ret;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun     if (!info)
431*4882a593Smuzhiyun         return -1;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun     ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
434*4882a593Smuzhiyun                                    info->prop_id, val);
435*4882a593Smuzhiyun     return (ret <= 0) ? -1 : 0;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun static int
plane_add_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,uint32_t fb_id,int x,int y)439*4882a593Smuzhiyun plane_add_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
440*4882a593Smuzhiyun                 uint32_t fb_id, int x, int y)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
443*4882a593Smuzhiyun     int ret = 0;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
446*4882a593Smuzhiyun                           fb_id);
447*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
448*4882a593Smuzhiyun                           fb_id ? drmmode_crtc->mode_crtc->crtc_id : 0);
449*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
450*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
451*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
452*4882a593Smuzhiyun                           crtc->mode.HDisplay << 16);
453*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
454*4882a593Smuzhiyun                           crtc->mode.VDisplay << 16);
455*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
456*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
457*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
458*4882a593Smuzhiyun                           crtc->mode.HDisplay);
459*4882a593Smuzhiyun     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
460*4882a593Smuzhiyun                           crtc->mode.VDisplay);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun     return ret;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun static int
crtc_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_crtc_property prop,uint64_t val)466*4882a593Smuzhiyun crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
467*4882a593Smuzhiyun               enum drmmode_crtc_property prop, uint64_t val)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun     drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
470*4882a593Smuzhiyun     int ret;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun     if (!info)
473*4882a593Smuzhiyun         return -1;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun     ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
476*4882a593Smuzhiyun                                    info->prop_id, val);
477*4882a593Smuzhiyun     return (ret <= 0) ? -1 : 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun static int
connector_add_prop(drmModeAtomicReq * req,drmmode_output_private_ptr drmmode_output,enum drmmode_connector_property prop,uint64_t val)481*4882a593Smuzhiyun connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
482*4882a593Smuzhiyun                    enum drmmode_connector_property prop, uint64_t val)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun     drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
485*4882a593Smuzhiyun     int ret;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun     if (!info)
488*4882a593Smuzhiyun         return -1;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun     ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
491*4882a593Smuzhiyun                                    info->prop_id, val);
492*4882a593Smuzhiyun     return (ret <= 0) ? -1 : 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun static int
drmmode_CompareKModes(drmModeModeInfo * kmode,drmModeModeInfo * other)496*4882a593Smuzhiyun drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun     return memcmp(kmode, other, sizeof(*kmode));
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun static int
drm_mode_ensure_blob(xf86CrtcPtr crtc,drmModeModeInfo mode_info)502*4882a593Smuzhiyun drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
505*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
506*4882a593Smuzhiyun     drmmode_mode_ptr mode;
507*4882a593Smuzhiyun     int ret;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun     if (drmmode_crtc->current_mode &&
510*4882a593Smuzhiyun         drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
511*4882a593Smuzhiyun         return 0;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun     mode = calloc(sizeof(drmmode_mode_rec), 1);
514*4882a593Smuzhiyun     if (!mode)
515*4882a593Smuzhiyun         return -1;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun     mode->mode_info = mode_info;
518*4882a593Smuzhiyun     ret = drmModeCreatePropertyBlob(ms->fd,
519*4882a593Smuzhiyun                                     &mode->mode_info,
520*4882a593Smuzhiyun                                     sizeof(mode->mode_info),
521*4882a593Smuzhiyun                                     &mode->blob_id);
522*4882a593Smuzhiyun     drmmode_crtc->current_mode = mode;
523*4882a593Smuzhiyun     xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun     return ret;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun static int
crtc_add_dpms_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,int new_dpms,Bool * active)529*4882a593Smuzhiyun crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
530*4882a593Smuzhiyun                     int new_dpms, Bool *active)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
533*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
534*4882a593Smuzhiyun     Bool crtc_active = FALSE;
535*4882a593Smuzhiyun     int i;
536*4882a593Smuzhiyun     int ret = 0;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
539*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
540*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output = output->driver_private;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun         if (output->crtc != crtc) {
543*4882a593Smuzhiyun             if (drmmode_output->current_crtc == crtc) {
544*4882a593Smuzhiyun                 ret |= connector_add_prop(req, drmmode_output,
545*4882a593Smuzhiyun                                           DRMMODE_CONNECTOR_CRTC_ID, 0);
546*4882a593Smuzhiyun             }
547*4882a593Smuzhiyun             continue;
548*4882a593Smuzhiyun         }
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun         if (drmmode_output->output_id == -1)
551*4882a593Smuzhiyun             continue;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun         if (new_dpms == DPMSModeOn)
554*4882a593Smuzhiyun             crtc_active = TRUE;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun         ret |= connector_add_prop(req, drmmode_output,
557*4882a593Smuzhiyun                                   DRMMODE_CONNECTOR_CRTC_ID,
558*4882a593Smuzhiyun                                   crtc_active ?
559*4882a593Smuzhiyun                                       drmmode_crtc->mode_crtc->crtc_id : 0);
560*4882a593Smuzhiyun     }
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun     if (crtc_active) {
563*4882a593Smuzhiyun         drmModeModeInfo kmode;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun         drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
566*4882a593Smuzhiyun         ret |= drm_mode_ensure_blob(crtc, kmode);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun         ret |= crtc_add_prop(req, drmmode_crtc,
569*4882a593Smuzhiyun                              DRMMODE_CRTC_ACTIVE, 1);
570*4882a593Smuzhiyun         ret |= crtc_add_prop(req, drmmode_crtc,
571*4882a593Smuzhiyun                              DRMMODE_CRTC_MODE_ID,
572*4882a593Smuzhiyun                              drmmode_crtc->current_mode->blob_id);
573*4882a593Smuzhiyun     } else {
574*4882a593Smuzhiyun         ret |= crtc_add_prop(req, drmmode_crtc,
575*4882a593Smuzhiyun                              DRMMODE_CRTC_ACTIVE, 0);
576*4882a593Smuzhiyun         ret |= crtc_add_prop(req, drmmode_crtc,
577*4882a593Smuzhiyun                              DRMMODE_CRTC_MODE_ID, 0);
578*4882a593Smuzhiyun     }
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun     if (active)
581*4882a593Smuzhiyun         *active = crtc_active;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun     return ret;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun static void
drm_mode_destroy(xf86CrtcPtr crtc,drmmode_mode_ptr mode)587*4882a593Smuzhiyun drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
590*4882a593Smuzhiyun     if (mode->blob_id)
591*4882a593Smuzhiyun         drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
592*4882a593Smuzhiyun     xorg_list_del(&mode->entry);
593*4882a593Smuzhiyun     free(mode);
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun static int
drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)597*4882a593Smuzhiyun drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun     return ms->atomic_modeset;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun static Bool
drmmode_crtc_get_fb_id(xf86CrtcPtr crtc,uint32_t * fb_id,int * x,int * y)605*4882a593Smuzhiyun drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
608*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
609*4882a593Smuzhiyun     int ret;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun     *fb_id = 0;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun     if (drmmode_crtc->prime_pixmap) {
614*4882a593Smuzhiyun         if (!drmmode->reverse_prime_offload_mode) {
615*4882a593Smuzhiyun             msPixmapPrivPtr ppriv =
616*4882a593Smuzhiyun                 msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
617*4882a593Smuzhiyun             *fb_id = ppriv->fb_id;
618*4882a593Smuzhiyun             *x = 0;
619*4882a593Smuzhiyun         } else
620*4882a593Smuzhiyun             *x = drmmode_crtc->prime_pixmap_x;
621*4882a593Smuzhiyun         *y = 0;
622*4882a593Smuzhiyun     }
623*4882a593Smuzhiyun     else if (drmmode_crtc->rotate_fb_id) {
624*4882a593Smuzhiyun         *fb_id = drmmode_crtc->rotate_fb_id;
625*4882a593Smuzhiyun         *x = *y = 0;
626*4882a593Smuzhiyun     } else {
627*4882a593Smuzhiyun         *fb_id = drmmode->fb_id;
628*4882a593Smuzhiyun         *x = crtc->x;
629*4882a593Smuzhiyun         *y = crtc->y;
630*4882a593Smuzhiyun     }
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun     if (*fb_id == 0) {
633*4882a593Smuzhiyun         ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
634*4882a593Smuzhiyun                                 &drmmode->fb_id);
635*4882a593Smuzhiyun         if (ret < 0) {
636*4882a593Smuzhiyun             ErrorF("failed to add fb %d\n", ret);
637*4882a593Smuzhiyun             return FALSE;
638*4882a593Smuzhiyun         }
639*4882a593Smuzhiyun         *fb_id = drmmode->fb_id;
640*4882a593Smuzhiyun     }
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun     return TRUE;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun void
drmmode_set_dpms(ScrnInfoPtr scrn,int dpms,int flags)646*4882a593Smuzhiyun drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
649*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
650*4882a593Smuzhiyun     drmModeAtomicReq *req = drmModeAtomicAlloc();
651*4882a593Smuzhiyun     uint32_t mode_flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
652*4882a593Smuzhiyun     int ret = 0;
653*4882a593Smuzhiyun     int i;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun     assert(ms->atomic_modeset);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun     if (!req)
658*4882a593Smuzhiyun         return;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
661*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
662*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output = output->driver_private;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun         if (output->crtc != NULL)
665*4882a593Smuzhiyun             continue;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun         ret = connector_add_prop(req, drmmode_output,
668*4882a593Smuzhiyun                                  DRMMODE_CONNECTOR_CRTC_ID, 0);
669*4882a593Smuzhiyun     }
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++) {
672*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[i];
673*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
674*4882a593Smuzhiyun         Bool active = FALSE;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun         ret |= crtc_add_dpms_props(req, crtc, dpms, &active);
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun         if (dpms == DPMSModeOn && active && drmmode_crtc->need_modeset) {
679*4882a593Smuzhiyun             uint32_t fb_id;
680*4882a593Smuzhiyun             int x, y;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun             if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
683*4882a593Smuzhiyun                 continue;
684*4882a593Smuzhiyun             ret |= plane_add_props(req, crtc, fb_id, x, y);
685*4882a593Smuzhiyun             drmmode_crtc->need_modeset = FALSE;
686*4882a593Smuzhiyun         }
687*4882a593Smuzhiyun     }
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun     if (ret == 0)
690*4882a593Smuzhiyun         drmModeAtomicCommit(ms->fd, req, mode_flags, NULL);
691*4882a593Smuzhiyun     drmModeAtomicFree(req);
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun     ms->pending_modeset = TRUE;
694*4882a593Smuzhiyun     xf86DPMSSet(scrn, dpms, flags);
695*4882a593Smuzhiyun     ms->pending_modeset = FALSE;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun static int
drmmode_output_dpms_atomic(xf86OutputPtr output,int mode)699*4882a593Smuzhiyun drmmode_output_dpms_atomic(xf86OutputPtr output, int mode)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(output->scrn);
702*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
703*4882a593Smuzhiyun     xf86CrtcPtr crtc = drmmode_output->current_crtc;
704*4882a593Smuzhiyun     drmModeAtomicReq *req;
705*4882a593Smuzhiyun     uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
706*4882a593Smuzhiyun     int ret = 0;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun     if (mode == DPMSModeOn && !crtc)
709*4882a593Smuzhiyun         return 1;
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun     assert(ms->atomic_modeset);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun     req = drmModeAtomicAlloc();
714*4882a593Smuzhiyun     if (!req)
715*4882a593Smuzhiyun         return 1;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun     if (crtc)
718*4882a593Smuzhiyun         ret |= crtc_add_dpms_props(req, crtc, mode, NULL);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun     if (mode == DPMSModeOn) {
721*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
722*4882a593Smuzhiyun         drmModeModeInfo kmode;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun         drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
725*4882a593Smuzhiyun         ret |= drm_mode_ensure_blob(crtc, kmode);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun         ret |= connector_add_prop(req, drmmode_output,
728*4882a593Smuzhiyun                                   DRMMODE_CONNECTOR_CRTC_ID,
729*4882a593Smuzhiyun                                   drmmode_crtc->mode_crtc->crtc_id);
730*4882a593Smuzhiyun         ret |= crtc_add_prop(req, drmmode_crtc,
731*4882a593Smuzhiyun                              DRMMODE_CRTC_ACTIVE, 1);
732*4882a593Smuzhiyun         ret |= crtc_add_prop(req, drmmode_crtc,
733*4882a593Smuzhiyun                              DRMMODE_CRTC_MODE_ID,
734*4882a593Smuzhiyun                              drmmode_crtc->current_mode->blob_id);
735*4882a593Smuzhiyun     } else {
736*4882a593Smuzhiyun         ret |= connector_add_prop(req, drmmode_output,
737*4882a593Smuzhiyun                                   DRMMODE_CONNECTOR_CRTC_ID, 0);
738*4882a593Smuzhiyun     }
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun     if (ret == 0)
741*4882a593Smuzhiyun         ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun     drmModeAtomicFree(req);
744*4882a593Smuzhiyun     return ret;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun static int
drmmode_crtc_disable(xf86CrtcPtr crtc)748*4882a593Smuzhiyun drmmode_crtc_disable(xf86CrtcPtr crtc)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
751*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
752*4882a593Smuzhiyun     drmModeAtomicReq *req = drmModeAtomicAlloc();
753*4882a593Smuzhiyun     uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
754*4882a593Smuzhiyun     int ret = 0;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun     assert(ms->atomic_modeset);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun     if (!req)
759*4882a593Smuzhiyun         return 1;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun     ret |= crtc_add_prop(req, drmmode_crtc,
762*4882a593Smuzhiyun                          DRMMODE_CRTC_ACTIVE, 0);
763*4882a593Smuzhiyun     ret |= crtc_add_prop(req, drmmode_crtc,
764*4882a593Smuzhiyun                          DRMMODE_CRTC_MODE_ID, 0);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun     if (ret == 0)
767*4882a593Smuzhiyun         ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun     drmModeAtomicFree(req);
770*4882a593Smuzhiyun     return ret;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun static Bool
drmmode_crtc_connected(xf86CrtcPtr crtc)774*4882a593Smuzhiyun drmmode_crtc_connected(xf86CrtcPtr crtc)
775*4882a593Smuzhiyun {
776*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
777*4882a593Smuzhiyun     int i;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
780*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
781*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
782*4882a593Smuzhiyun         drmmode_output = output->driver_private;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun         if (output->crtc != crtc)
785*4882a593Smuzhiyun             continue;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun         if (drmmode_output->status == XF86OutputStatusConnected)
788*4882a593Smuzhiyun             return TRUE;
789*4882a593Smuzhiyun     }
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun     return FALSE;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun static int
drmmode_crtc_modeset(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t x,uint32_t y,uint32_t * output_ids,int output_count,drmModeModeInfoPtr mode)795*4882a593Smuzhiyun drmmode_crtc_modeset(xf86CrtcPtr crtc, uint32_t fb_id,
796*4882a593Smuzhiyun                      uint32_t x, uint32_t y, uint32_t *output_ids,
797*4882a593Smuzhiyun                      int output_count, drmModeModeInfoPtr mode)
798*4882a593Smuzhiyun {
799*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
800*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
801*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
802*4882a593Smuzhiyun     struct dumb_bo *bo = NULL;
803*4882a593Smuzhiyun     uint32_t new_fb_id = 0;
804*4882a593Smuzhiyun     int sx, sy, sw, sh, dx, dy, dw, dh;
805*4882a593Smuzhiyun     int ret, i;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun     sx = x;
808*4882a593Smuzhiyun     sy = y;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun     if (crtc->driverIsPerformingTransform & XF86DriverTransformOutput) {
811*4882a593Smuzhiyun         struct pixman_f_vector point;
812*4882a593Smuzhiyun         int x1, y1, x2, y2;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun         point.v[2] = 1;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun         /* Convert output's area to framebuffer's area */
817*4882a593Smuzhiyun         point.v[0] = 0;
818*4882a593Smuzhiyun         point.v[1] = 0;
819*4882a593Smuzhiyun         pixman_f_transform_point(&crtc->f_crtc_to_framebuffer, &point);
820*4882a593Smuzhiyun         x2 = floor(point.v[0]);
821*4882a593Smuzhiyun         y2 = floor(point.v[1]);
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun         point.v[0] = crtc->mode.HDisplay;
824*4882a593Smuzhiyun         point.v[1] = crtc->mode.VDisplay;
825*4882a593Smuzhiyun         pixman_f_transform_point(&crtc->f_crtc_to_framebuffer, &point);
826*4882a593Smuzhiyun         x1 = floor(point.v[0]);
827*4882a593Smuzhiyun         y1 = floor(point.v[1]);
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun         sw = max(x1, x2) - sx;
830*4882a593Smuzhiyun         sh = max(y1, y2) - sy;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun         /* Convert framebuffer's area to output's area */
833*4882a593Smuzhiyun         point.v[0] = sx;
834*4882a593Smuzhiyun         point.v[1] = sy;
835*4882a593Smuzhiyun         pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &point);
836*4882a593Smuzhiyun         x1 = floor(point.v[0]);
837*4882a593Smuzhiyun         y1 = floor(point.v[1]);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun         point.v[0] = sw;
840*4882a593Smuzhiyun         point.v[1] = sh;
841*4882a593Smuzhiyun         pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &point);
842*4882a593Smuzhiyun         x2 = floor(point.v[0]);
843*4882a593Smuzhiyun         y2 = floor(point.v[1]);
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun         dx = min(x1, x2) * mode->hdisplay / crtc->mode.HDisplay;
846*4882a593Smuzhiyun         dy = min(y1, y2) * mode->vdisplay / crtc->mode.VDisplay;
847*4882a593Smuzhiyun         dw = mode->hdisplay - dx;
848*4882a593Smuzhiyun         dh = mode->vdisplay - dy;
849*4882a593Smuzhiyun     } else {
850*4882a593Smuzhiyun         sw = crtc->mode.HDisplay;
851*4882a593Smuzhiyun         sh = crtc->mode.VDisplay;
852*4882a593Smuzhiyun         dx = 0;
853*4882a593Smuzhiyun         dy = 0;
854*4882a593Smuzhiyun         dw = mode->hdisplay;
855*4882a593Smuzhiyun         dh = mode->vdisplay;
856*4882a593Smuzhiyun     }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
859*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
860*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun         if (output->crtc != crtc)
863*4882a593Smuzhiyun             continue;
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun         /* NOTE: Only use the first output's padding */
866*4882a593Smuzhiyun         drmmode_output = output->driver_private;
867*4882a593Smuzhiyun         if (!output_count || drmmode_output->output_id != output_ids[0])
868*4882a593Smuzhiyun             continue;
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun         dx += drmmode_output->padding_top;
871*4882a593Smuzhiyun         dw -= drmmode_output->padding_top;
872*4882a593Smuzhiyun         dw -= drmmode_output->padding_bottom;
873*4882a593Smuzhiyun         dy += drmmode_output->padding_left;
874*4882a593Smuzhiyun         dh -= drmmode_output->padding_left;
875*4882a593Smuzhiyun         dh -= drmmode_output->padding_right;
876*4882a593Smuzhiyun         break;
877*4882a593Smuzhiyun     }
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun     /* prefer using the original FB */
880*4882a593Smuzhiyun     ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
881*4882a593Smuzhiyun                          fb_id, x, y, output_ids, output_count, mode);
882*4882a593Smuzhiyun     if (!ret)
883*4882a593Smuzhiyun         goto set_plane;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun     /* fallback to a new dummy FB */
886*4882a593Smuzhiyun     bo = dumb_bo_create(drmmode->fd, mode->hdisplay, mode->vdisplay,
887*4882a593Smuzhiyun                         drmmode->kbpp);
888*4882a593Smuzhiyun     if (!bo)
889*4882a593Smuzhiyun         goto out;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun     ret = drmModeAddFB(drmmode->fd, mode->hdisplay, mode->vdisplay,
892*4882a593Smuzhiyun                        drmmode->scrn->depth, drmmode->kbpp,
893*4882a593Smuzhiyun                        bo->pitch, bo->handle, &new_fb_id);
894*4882a593Smuzhiyun     if (ret < 0)
895*4882a593Smuzhiyun         goto out;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun     ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
898*4882a593Smuzhiyun                          new_fb_id, 0, 0, output_ids, output_count, mode);
899*4882a593Smuzhiyun     if (ret < 0)
900*4882a593Smuzhiyun         goto out;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun set_plane:
903*4882a593Smuzhiyun     ret = drmModeSetPlane(drmmode->fd, drmmode_crtc->plane_id,
904*4882a593Smuzhiyun                           drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
905*4882a593Smuzhiyun                           dx, dy, dw, dh,
906*4882a593Smuzhiyun                           sx << 16, sy << 16, sw << 16, sh << 16);
907*4882a593Smuzhiyun     if (ret < 0)
908*4882a593Smuzhiyun         goto out;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun     ret = 0;
911*4882a593Smuzhiyun out:
912*4882a593Smuzhiyun     if (new_fb_id)
913*4882a593Smuzhiyun         drmModeRmFB(drmmode->fd, new_fb_id);
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun     if (bo)
916*4882a593Smuzhiyun         dumb_bo_destroy(drmmode->fd, bo);
917*4882a593Smuzhiyun     return ret;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun static int
drmmode_crtc_set_mode(xf86CrtcPtr crtc,Bool test_only)921*4882a593Smuzhiyun drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
924*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
925*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
926*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
927*4882a593Smuzhiyun     ScreenPtr screen = crtc->scrn->pScreen;
928*4882a593Smuzhiyun     drmModeModeInfo kmode;
929*4882a593Smuzhiyun     int output_count = 0;
930*4882a593Smuzhiyun     uint32_t *output_ids = NULL;
931*4882a593Smuzhiyun     uint32_t fb_id;
932*4882a593Smuzhiyun     int x, y;
933*4882a593Smuzhiyun     int i, ret = 0;
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun     if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
936*4882a593Smuzhiyun         return 1;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
939*4882a593Smuzhiyun     /* Make sure any pending drawing will be visible in a new scanout buffer */
940*4882a593Smuzhiyun     if (drmmode->glamor)
941*4882a593Smuzhiyun         glamor_finish(screen);
942*4882a593Smuzhiyun #endif
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun     if (ms->atomic_modeset) {
945*4882a593Smuzhiyun         drmModeAtomicReq *req = drmModeAtomicAlloc();
946*4882a593Smuzhiyun         Bool active;
947*4882a593Smuzhiyun         uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun         if (!req)
950*4882a593Smuzhiyun             return 1;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun         ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
953*4882a593Smuzhiyun         ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun         /* Orphaned CRTCs need to be disabled right now in atomic mode */
956*4882a593Smuzhiyun         for (i = 0; i < xf86_config->num_crtc; i++) {
957*4882a593Smuzhiyun             xf86CrtcPtr other_crtc = xf86_config->crtc[i];
958*4882a593Smuzhiyun             drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
959*4882a593Smuzhiyun             int lost_outputs = 0;
960*4882a593Smuzhiyun             int remaining_outputs = 0;
961*4882a593Smuzhiyun             int j;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun             if (other_crtc == crtc)
964*4882a593Smuzhiyun                 continue;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun             for (j = 0; j < xf86_config->num_output; j++) {
967*4882a593Smuzhiyun                 xf86OutputPtr output = xf86_config->output[j];
968*4882a593Smuzhiyun                 drmmode_output_private_ptr drmmode_output = output->driver_private;
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun                 if (drmmode_output->current_crtc == other_crtc) {
971*4882a593Smuzhiyun                     if (output->crtc == crtc)
972*4882a593Smuzhiyun                         lost_outputs++;
973*4882a593Smuzhiyun                     else
974*4882a593Smuzhiyun                         remaining_outputs++;
975*4882a593Smuzhiyun                 }
976*4882a593Smuzhiyun             }
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun             if (lost_outputs > 0 && remaining_outputs == 0) {
979*4882a593Smuzhiyun                 ret |= crtc_add_prop(req, other_drmmode_crtc,
980*4882a593Smuzhiyun                                      DRMMODE_CRTC_ACTIVE, 0);
981*4882a593Smuzhiyun                 ret |= crtc_add_prop(req, other_drmmode_crtc,
982*4882a593Smuzhiyun                                      DRMMODE_CRTC_MODE_ID, 0);
983*4882a593Smuzhiyun             }
984*4882a593Smuzhiyun         }
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun         if (test_only)
987*4882a593Smuzhiyun             flags |= DRM_MODE_ATOMIC_TEST_ONLY;
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun         if (ret == 0)
990*4882a593Smuzhiyun             ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun         if (ret == 0 && !test_only) {
993*4882a593Smuzhiyun             for (i = 0; i < xf86_config->num_output; i++) {
994*4882a593Smuzhiyun                 xf86OutputPtr output = xf86_config->output[i];
995*4882a593Smuzhiyun                 drmmode_output_private_ptr drmmode_output = output->driver_private;
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun                 if (output->crtc == crtc)
998*4882a593Smuzhiyun                     drmmode_output->current_crtc = crtc;
999*4882a593Smuzhiyun                 else if (drmmode_output->current_crtc == crtc)
1000*4882a593Smuzhiyun                     drmmode_output->current_crtc = NULL;
1001*4882a593Smuzhiyun             }
1002*4882a593Smuzhiyun         }
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun         drmModeAtomicFree(req);
1005*4882a593Smuzhiyun         return ret;
1006*4882a593Smuzhiyun     }
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun     output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
1009*4882a593Smuzhiyun     if (!output_ids)
1010*4882a593Smuzhiyun         return -1;
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
1013*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
1014*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun         if (output->crtc != crtc)
1017*4882a593Smuzhiyun             continue;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun         drmmode_output = output->driver_private;
1020*4882a593Smuzhiyun         if (drmmode_output->output_id == -1)
1021*4882a593Smuzhiyun             continue;
1022*4882a593Smuzhiyun         output_ids[output_count] = drmmode_output->output_id;
1023*4882a593Smuzhiyun         output_count++;
1024*4882a593Smuzhiyun     }
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun     drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun     ret = drmmode_crtc_modeset(crtc, fb_id, x, y,
1029*4882a593Smuzhiyun                                output_ids, output_count, &kmode);
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun     free(output_ids);
1032*4882a593Smuzhiyun     return ret;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun int
drmmode_crtc_flip(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t flags,void * data)1036*4882a593Smuzhiyun drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1039*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
1040*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1041*4882a593Smuzhiyun     int ret, i, sx, sy, sw, sh, dx, dy, dw, dh;
1042*4882a593Smuzhiyun     drmModeModeInfo kmode;
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun     drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun     if (fb_id == ms->drmmode.fb_id) {
1047*4882a593Smuzhiyun         /* screen FB flip */
1048*4882a593Smuzhiyun         sx = crtc->x;
1049*4882a593Smuzhiyun         sy = crtc->y;
1050*4882a593Smuzhiyun     } else {
1051*4882a593Smuzhiyun         /* single crtc FB flip */
1052*4882a593Smuzhiyun         sx = sy = 0;
1053*4882a593Smuzhiyun     }
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun     sw = crtc->mode.HDisplay;
1056*4882a593Smuzhiyun     sh = crtc->mode.VDisplay;
1057*4882a593Smuzhiyun     dx = dy = 0;
1058*4882a593Smuzhiyun     dw = kmode.hdisplay;
1059*4882a593Smuzhiyun     dh = kmode.vdisplay;
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
1062*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
1063*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun         if (output->crtc != crtc)
1066*4882a593Smuzhiyun             continue;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun         drmmode_output = output->driver_private;
1069*4882a593Smuzhiyun         if (drmmode_output->output_id == -1)
1070*4882a593Smuzhiyun             continue;
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun         /* NOTE: Only use the first output's padding */
1073*4882a593Smuzhiyun         dx += drmmode_output->padding_top;
1074*4882a593Smuzhiyun         dw -= drmmode_output->padding_top;
1075*4882a593Smuzhiyun         dw -= drmmode_output->padding_bottom;
1076*4882a593Smuzhiyun         dy += drmmode_output->padding_left;
1077*4882a593Smuzhiyun         dh -= drmmode_output->padding_left;
1078*4882a593Smuzhiyun         dh -= drmmode_output->padding_right;
1079*4882a593Smuzhiyun         break;
1080*4882a593Smuzhiyun     }
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun     ret = drmModeSetPlane(ms->fd, drmmode_crtc->plane_id,
1083*4882a593Smuzhiyun                           drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
1084*4882a593Smuzhiyun                           dx, dy, dw, dh,
1085*4882a593Smuzhiyun                           sx << 16, sy << 16, sw << 16, sh << 16);
1086*4882a593Smuzhiyun     if (ret)
1087*4882a593Smuzhiyun         return ret;
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun     return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
1090*4882a593Smuzhiyun                            fb_id, flags, data);
1091*4882a593Smuzhiyun }
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun int
drmmode_bo_destroy(drmmode_ptr drmmode,drmmode_bo * bo)1094*4882a593Smuzhiyun drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
1095*4882a593Smuzhiyun {
1096*4882a593Smuzhiyun     int ret;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1099*4882a593Smuzhiyun     if (bo->gbm) {
1100*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM_MAP
1101*4882a593Smuzhiyun         if (bo->gbm_ptr) {
1102*4882a593Smuzhiyun             gbm_bo_unmap(bo->gbm, bo->gbm_map_data);
1103*4882a593Smuzhiyun             bo->gbm_ptr = NULL;
1104*4882a593Smuzhiyun         }
1105*4882a593Smuzhiyun #endif
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun         if (bo->owned_gbm)
1108*4882a593Smuzhiyun             gbm_bo_destroy(bo->gbm);
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun         bo->gbm = NULL;
1111*4882a593Smuzhiyun     }
1112*4882a593Smuzhiyun #endif
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun     if (bo->dumb) {
1115*4882a593Smuzhiyun         ret = dumb_bo_destroy(drmmode->fd, bo->dumb);
1116*4882a593Smuzhiyun         if (ret == 0)
1117*4882a593Smuzhiyun             bo->dumb = NULL;
1118*4882a593Smuzhiyun     }
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun     return 0;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun uint32_t
drmmode_bo_get_pitch(drmmode_bo * bo)1124*4882a593Smuzhiyun drmmode_bo_get_pitch(drmmode_bo *bo)
1125*4882a593Smuzhiyun {
1126*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1127*4882a593Smuzhiyun     if (bo->gbm)
1128*4882a593Smuzhiyun         return gbm_bo_get_stride(bo->gbm);
1129*4882a593Smuzhiyun #endif
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun     return bo->dumb->pitch;
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun static Bool
drmmode_bo_has_bo(drmmode_bo * bo)1135*4882a593Smuzhiyun drmmode_bo_has_bo(drmmode_bo *bo)
1136*4882a593Smuzhiyun {
1137*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1138*4882a593Smuzhiyun     if (bo->gbm)
1139*4882a593Smuzhiyun         return TRUE;
1140*4882a593Smuzhiyun #endif
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun     return bo->dumb != NULL;
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun uint32_t
drmmode_bo_get_handle(drmmode_bo * bo)1146*4882a593Smuzhiyun drmmode_bo_get_handle(drmmode_bo *bo)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1149*4882a593Smuzhiyun     if (bo->gbm)
1150*4882a593Smuzhiyun         return gbm_bo_get_handle(bo->gbm).u32;
1151*4882a593Smuzhiyun #endif
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun     return bo->dumb->handle;
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun static void *
drmmode_bo_map(drmmode_ptr drmmode,drmmode_bo * bo)1157*4882a593Smuzhiyun drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun     int ret;
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1162*4882a593Smuzhiyun     if (bo->gbm) {
1163*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM_MAP
1164*4882a593Smuzhiyun         uint32_t stride;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun         if (bo->gbm_ptr)
1167*4882a593Smuzhiyun             return bo->gbm_ptr;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun         bo->gbm_ptr = gbm_bo_map(bo->gbm, 0, 0, bo->width, bo->height,
1170*4882a593Smuzhiyun                                  GBM_BO_TRANSFER_READ_WRITE, &stride,
1171*4882a593Smuzhiyun                                  &bo->gbm_map_data);
1172*4882a593Smuzhiyun         return bo->gbm_ptr;
1173*4882a593Smuzhiyun #else
1174*4882a593Smuzhiyun         return NULL;
1175*4882a593Smuzhiyun #endif
1176*4882a593Smuzhiyun     }
1177*4882a593Smuzhiyun #endif
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun     if (bo->dumb->ptr)
1180*4882a593Smuzhiyun         return bo->dumb->ptr;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun     ret = dumb_bo_map(drmmode->fd, bo->dumb);
1183*4882a593Smuzhiyun     if (ret)
1184*4882a593Smuzhiyun         return NULL;
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun     return bo->dumb->ptr;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun int
drmmode_bo_import(drmmode_ptr drmmode,drmmode_bo * bo,uint32_t * fb_id)1190*4882a593Smuzhiyun drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
1191*4882a593Smuzhiyun                   uint32_t *fb_id)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun #ifdef GBM_BO_WITH_MODIFIERS
1194*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(drmmode->scrn);
1195*4882a593Smuzhiyun     if (bo->gbm && ms->kms_has_modifiers &&
1196*4882a593Smuzhiyun         gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
1197*4882a593Smuzhiyun         int num_fds;
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun         num_fds = gbm_bo_get_plane_count(bo->gbm);
1200*4882a593Smuzhiyun         if (num_fds > 0) {
1201*4882a593Smuzhiyun             int i;
1202*4882a593Smuzhiyun             uint32_t format;
1203*4882a593Smuzhiyun             uint32_t handles[4];
1204*4882a593Smuzhiyun             uint32_t strides[4];
1205*4882a593Smuzhiyun             uint32_t offsets[4];
1206*4882a593Smuzhiyun             uint64_t modifiers[4];
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun             memset(handles, 0, sizeof(handles));
1209*4882a593Smuzhiyun             memset(strides, 0, sizeof(strides));
1210*4882a593Smuzhiyun             memset(offsets, 0, sizeof(offsets));
1211*4882a593Smuzhiyun             memset(modifiers, 0, sizeof(modifiers));
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun             format = gbm_bo_get_format(bo->gbm);
1214*4882a593Smuzhiyun             format = get_opaque_format(format);
1215*4882a593Smuzhiyun             for (i = 0; i < num_fds; i++) {
1216*4882a593Smuzhiyun                 handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
1217*4882a593Smuzhiyun                 strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
1218*4882a593Smuzhiyun                 offsets[i] = gbm_bo_get_offset(bo->gbm, i);
1219*4882a593Smuzhiyun                 modifiers[i] = gbm_bo_get_modifier(bo->gbm);
1220*4882a593Smuzhiyun             }
1221*4882a593Smuzhiyun 
1222*4882a593Smuzhiyun             return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
1223*4882a593Smuzhiyun                                               format, handles, strides,
1224*4882a593Smuzhiyun                                               offsets, modifiers, fb_id,
1225*4882a593Smuzhiyun                                               DRM_MODE_FB_MODIFIERS);
1226*4882a593Smuzhiyun         }
1227*4882a593Smuzhiyun     }
1228*4882a593Smuzhiyun #endif
1229*4882a593Smuzhiyun     return drmModeAddFB(drmmode->fd, bo->width, bo->height,
1230*4882a593Smuzhiyun                         drmmode->scrn->depth, drmmode->kbpp,
1231*4882a593Smuzhiyun                         drmmode_bo_get_pitch(bo),
1232*4882a593Smuzhiyun                         drmmode_bo_get_handle(bo), fb_id);
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun static Bool
drmmode_create_bo(drmmode_ptr drmmode,drmmode_bo * bo,unsigned width,unsigned height,unsigned bpp)1236*4882a593Smuzhiyun drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
1237*4882a593Smuzhiyun                   unsigned width, unsigned height, unsigned bpp)
1238*4882a593Smuzhiyun {
1239*4882a593Smuzhiyun     bo->width = width;
1240*4882a593Smuzhiyun     bo->height = height;
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1243*4882a593Smuzhiyun     if (drmmode->glamor) {
1244*4882a593Smuzhiyun         uint32_t format;
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun         switch (drmmode->scrn->depth) {
1247*4882a593Smuzhiyun         case 15:
1248*4882a593Smuzhiyun             format = GBM_FORMAT_ARGB1555;
1249*4882a593Smuzhiyun             break;
1250*4882a593Smuzhiyun         case 16:
1251*4882a593Smuzhiyun             format = GBM_FORMAT_RGB565;
1252*4882a593Smuzhiyun             break;
1253*4882a593Smuzhiyun         case 30:
1254*4882a593Smuzhiyun             format = GBM_FORMAT_ARGB2101010;
1255*4882a593Smuzhiyun             break;
1256*4882a593Smuzhiyun         default:
1257*4882a593Smuzhiyun             format = GBM_FORMAT_ARGB8888;
1258*4882a593Smuzhiyun             break;
1259*4882a593Smuzhiyun         }
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun #ifdef GBM_BO_WITH_MODIFIERS
1262*4882a593Smuzhiyun         uint32_t num_modifiers;
1263*4882a593Smuzhiyun         uint64_t *modifiers = NULL;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun         num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
1266*4882a593Smuzhiyun                                           FALSE, TRUE);
1267*4882a593Smuzhiyun         if (num_modifiers > 0 &&
1268*4882a593Smuzhiyun             !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
1269*4882a593Smuzhiyun             bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
1270*4882a593Smuzhiyun                                                    format, modifiers,
1271*4882a593Smuzhiyun                                                    num_modifiers);
1272*4882a593Smuzhiyun             free(modifiers);
1273*4882a593Smuzhiyun             if (bo->gbm) {
1274*4882a593Smuzhiyun                 bo->used_modifiers = TRUE;
1275*4882a593Smuzhiyun                 return TRUE;
1276*4882a593Smuzhiyun             }
1277*4882a593Smuzhiyun         }
1278*4882a593Smuzhiyun #endif
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun         bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
1281*4882a593Smuzhiyun                                 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
1282*4882a593Smuzhiyun         bo->gbm_ptr = NULL;
1283*4882a593Smuzhiyun         bo->used_modifiers = FALSE;
1284*4882a593Smuzhiyun         bo->owned_gbm = TRUE;
1285*4882a593Smuzhiyun         return bo->gbm != NULL;
1286*4882a593Smuzhiyun     }
1287*4882a593Smuzhiyun #endif
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun     bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp);
1290*4882a593Smuzhiyun     return bo->dumb != NULL;
1291*4882a593Smuzhiyun }
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun Bool
drmmode_SetSlaveBO(PixmapPtr ppix,drmmode_ptr drmmode,int fd_handle,int pitch,int size)1294*4882a593Smuzhiyun drmmode_SetSlaveBO(PixmapPtr ppix,
1295*4882a593Smuzhiyun                    drmmode_ptr drmmode, int fd_handle, int pitch, int size)
1296*4882a593Smuzhiyun {
1297*4882a593Smuzhiyun     msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun     if (fd_handle == -1) {
1300*4882a593Smuzhiyun         dumb_bo_destroy(drmmode->fd, ppriv->backing_bo);
1301*4882a593Smuzhiyun         ppriv->backing_bo = NULL;
1302*4882a593Smuzhiyun         return TRUE;
1303*4882a593Smuzhiyun     }
1304*4882a593Smuzhiyun 
1305*4882a593Smuzhiyun     ppriv->backing_bo =
1306*4882a593Smuzhiyun         dumb_get_bo_from_fd(drmmode->fd, fd_handle, pitch, size);
1307*4882a593Smuzhiyun     if (!ppriv->backing_bo)
1308*4882a593Smuzhiyun         return FALSE;
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun     close(fd_handle);
1311*4882a593Smuzhiyun     return TRUE;
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun 
1314*4882a593Smuzhiyun static Bool
drmmode_SharedPixmapPresent(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1315*4882a593Smuzhiyun drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
1316*4882a593Smuzhiyun                             drmmode_ptr drmmode)
1317*4882a593Smuzhiyun {
1318*4882a593Smuzhiyun     ScreenPtr master = crtc->randr_crtc->pScreen->current_master;
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun     if (master->PresentSharedPixmap(ppix)) {
1321*4882a593Smuzhiyun         /* Success, queue flip to back target */
1322*4882a593Smuzhiyun         if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
1323*4882a593Smuzhiyun             return TRUE;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
1326*4882a593Smuzhiyun                    "drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun         return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1329*4882a593Smuzhiyun     }
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun     /* Failed to present, try again on next vblank after damage */
1332*4882a593Smuzhiyun     if (master->RequestSharedPixmapNotifyDamage) {
1333*4882a593Smuzhiyun         msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun         /* Set flag first in case we are immediately notified */
1336*4882a593Smuzhiyun         ppriv->wait_for_damage = TRUE;
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun         if (master->RequestSharedPixmapNotifyDamage(ppix))
1339*4882a593Smuzhiyun             return TRUE;
1340*4882a593Smuzhiyun         else
1341*4882a593Smuzhiyun             ppriv->wait_for_damage = FALSE;
1342*4882a593Smuzhiyun     }
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun     /* Damage notification not available, just try again on vblank */
1345*4882a593Smuzhiyun     return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1346*4882a593Smuzhiyun }
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun struct vblank_event_args {
1349*4882a593Smuzhiyun     PixmapPtr frontTarget;
1350*4882a593Smuzhiyun     PixmapPtr backTarget;
1351*4882a593Smuzhiyun     xf86CrtcPtr crtc;
1352*4882a593Smuzhiyun     drmmode_ptr drmmode;
1353*4882a593Smuzhiyun     Bool flip;
1354*4882a593Smuzhiyun };
1355*4882a593Smuzhiyun static void
drmmode_SharedPixmapVBlankEventHandler(uint64_t frame,uint64_t usec,void * data)1356*4882a593Smuzhiyun drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
1357*4882a593Smuzhiyun                                        void *data)
1358*4882a593Smuzhiyun {
1359*4882a593Smuzhiyun     struct vblank_event_args *args = data;
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun     if (args->flip) {
1364*4882a593Smuzhiyun         /* frontTarget is being displayed, update crtc to reflect */
1365*4882a593Smuzhiyun         drmmode_crtc->prime_pixmap = args->frontTarget;
1366*4882a593Smuzhiyun         drmmode_crtc->prime_pixmap_back = args->backTarget;
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun         /* Safe to present on backTarget, no longer displayed */
1369*4882a593Smuzhiyun         drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
1370*4882a593Smuzhiyun     } else {
1371*4882a593Smuzhiyun         /* backTarget is still being displayed, present on frontTarget */
1372*4882a593Smuzhiyun         drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
1373*4882a593Smuzhiyun     }
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun     free(args);
1376*4882a593Smuzhiyun }
1377*4882a593Smuzhiyun 
1378*4882a593Smuzhiyun static void
drmmode_SharedPixmapVBlankEventAbort(void * data)1379*4882a593Smuzhiyun drmmode_SharedPixmapVBlankEventAbort(void *data)
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun     struct vblank_event_args *args = data;
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun     msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun     free(args);
1386*4882a593Smuzhiyun }
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun Bool
drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1389*4882a593Smuzhiyun drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
1390*4882a593Smuzhiyun                                     drmmode_ptr drmmode)
1391*4882a593Smuzhiyun {
1392*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1393*4882a593Smuzhiyun     msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1394*4882a593Smuzhiyun     struct vblank_event_args *event_args;
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun     if (ppix == drmmode_crtc->prime_pixmap)
1397*4882a593Smuzhiyun         return FALSE; /* Already flipped to this pixmap */
1398*4882a593Smuzhiyun     if (ppix != drmmode_crtc->prime_pixmap_back)
1399*4882a593Smuzhiyun         return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun     event_args = calloc(1, sizeof(*event_args));
1402*4882a593Smuzhiyun     if (!event_args)
1403*4882a593Smuzhiyun         return FALSE;
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun     event_args->frontTarget = ppix;
1406*4882a593Smuzhiyun     event_args->backTarget = drmmode_crtc->prime_pixmap;
1407*4882a593Smuzhiyun     event_args->crtc = crtc;
1408*4882a593Smuzhiyun     event_args->drmmode = drmmode;
1409*4882a593Smuzhiyun     event_args->flip = FALSE;
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun     ppriv->flip_seq =
1412*4882a593Smuzhiyun         ms_drm_queue_alloc(crtc, event_args,
1413*4882a593Smuzhiyun                            drmmode_SharedPixmapVBlankEventHandler,
1414*4882a593Smuzhiyun                            drmmode_SharedPixmapVBlankEventAbort);
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun     return ms_queue_vblank(crtc, MS_QUEUE_RELATIVE, 1, NULL, ppriv->flip_seq);
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun 
1419*4882a593Smuzhiyun Bool
drmmode_SharedPixmapFlip(PixmapPtr frontTarget,xf86CrtcPtr crtc,drmmode_ptr drmmode)1420*4882a593Smuzhiyun drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
1421*4882a593Smuzhiyun                          drmmode_ptr drmmode)
1422*4882a593Smuzhiyun {
1423*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1424*4882a593Smuzhiyun     msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun     struct vblank_event_args *event_args;
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun     event_args = calloc(1, sizeof(*event_args));
1429*4882a593Smuzhiyun     if (!event_args)
1430*4882a593Smuzhiyun         return FALSE;
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun     event_args->frontTarget = frontTarget;
1433*4882a593Smuzhiyun     event_args->backTarget = drmmode_crtc->prime_pixmap;
1434*4882a593Smuzhiyun     event_args->crtc = crtc;
1435*4882a593Smuzhiyun     event_args->drmmode = drmmode;
1436*4882a593Smuzhiyun     event_args->flip = TRUE;
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun     ppriv_front->flip_seq =
1439*4882a593Smuzhiyun         ms_drm_queue_alloc(crtc, event_args,
1440*4882a593Smuzhiyun                            drmmode_SharedPixmapVBlankEventHandler,
1441*4882a593Smuzhiyun                            drmmode_SharedPixmapVBlankEventAbort);
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun     if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1444*4882a593Smuzhiyun                         ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1445*4882a593Smuzhiyun                         (void *)(intptr_t) ppriv_front->flip_seq) < 0) {
1446*4882a593Smuzhiyun         ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
1447*4882a593Smuzhiyun         return FALSE;
1448*4882a593Smuzhiyun     }
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun     return TRUE;
1451*4882a593Smuzhiyun }
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun static Bool
drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1454*4882a593Smuzhiyun drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1455*4882a593Smuzhiyun {
1456*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun     if (!drmmode_crtc->enable_flipping)
1459*4882a593Smuzhiyun         return FALSE;
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun     if (drmmode_crtc->flipping_active)
1462*4882a593Smuzhiyun         return TRUE;
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun     drmmode_crtc->flipping_active =
1465*4882a593Smuzhiyun         drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
1466*4882a593Smuzhiyun                                     crtc, drmmode);
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun     return drmmode_crtc->flipping_active;
1469*4882a593Smuzhiyun }
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun static void
drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1472*4882a593Smuzhiyun drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1473*4882a593Smuzhiyun {
1474*4882a593Smuzhiyun     uint32_t seq;
1475*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun     if (!drmmode_crtc->flipping_active)
1478*4882a593Smuzhiyun         return;
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun     drmmode_crtc->flipping_active = FALSE;
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun     /* Abort page flip event handler on prime_pixmap */
1483*4882a593Smuzhiyun     seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
1484*4882a593Smuzhiyun     if (seq)
1485*4882a593Smuzhiyun         ms_drm_abort_seq(crtc->scrn, seq);
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun     /* Abort page flip event handler on prime_pixmap_back */
1488*4882a593Smuzhiyun     seq = msGetPixmapPriv(drmmode,
1489*4882a593Smuzhiyun                           drmmode_crtc->prime_pixmap_back)->flip_seq;
1490*4882a593Smuzhiyun     if (seq)
1491*4882a593Smuzhiyun         ms_drm_abort_seq(crtc->scrn, seq);
1492*4882a593Smuzhiyun }
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1495*4882a593Smuzhiyun                                               PixmapPtr *target);
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun Bool
drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode,PixmapPtr front,PixmapPtr back)1498*4882a593Smuzhiyun drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
1499*4882a593Smuzhiyun                                    PixmapPtr front, PixmapPtr back)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1502*4882a593Smuzhiyun     ScrnInfoPtr scrn = crtc->scrn;
1503*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
1504*4882a593Smuzhiyun 
1505*4882a593Smuzhiyun     drmmode_crtc->enable_flipping = TRUE;
1506*4882a593Smuzhiyun 
1507*4882a593Smuzhiyun     /* Set front scanout pixmap */
1508*4882a593Smuzhiyun     drmmode_crtc->enable_flipping &=
1509*4882a593Smuzhiyun         drmmode_set_target_scanout_pixmap(crtc, front,
1510*4882a593Smuzhiyun                                           &drmmode_crtc->prime_pixmap);
1511*4882a593Smuzhiyun     if (!drmmode_crtc->enable_flipping)
1512*4882a593Smuzhiyun         return FALSE;
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun     /* Set back scanout pixmap */
1515*4882a593Smuzhiyun     drmmode_crtc->enable_flipping &=
1516*4882a593Smuzhiyun         drmmode_set_target_scanout_pixmap(crtc, back,
1517*4882a593Smuzhiyun                                           &drmmode_crtc->prime_pixmap_back);
1518*4882a593Smuzhiyun     if (!drmmode_crtc->enable_flipping) {
1519*4882a593Smuzhiyun         drmmode_set_target_scanout_pixmap(crtc, NULL,
1520*4882a593Smuzhiyun                                           &drmmode_crtc->prime_pixmap);
1521*4882a593Smuzhiyun         return FALSE;
1522*4882a593Smuzhiyun     }
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun     drmmode_set_desired_modes(scrn, &ms->drmmode, TRUE, TRUE);
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun     return TRUE;
1527*4882a593Smuzhiyun }
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun void
drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1530*4882a593Smuzhiyun drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1531*4882a593Smuzhiyun {
1532*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1533*4882a593Smuzhiyun     ScrnInfoPtr scrn = crtc->scrn;
1534*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun     drmmode_crtc->enable_flipping = FALSE;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun     drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
1539*4882a593Smuzhiyun 
1540*4882a593Smuzhiyun     drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun     drmmode_set_target_scanout_pixmap(crtc, NULL,
1543*4882a593Smuzhiyun                                       &drmmode_crtc->prime_pixmap_back);
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun     drmmode_set_desired_modes(scrn, &ms->drmmode, TRUE, TRUE);
1546*4882a593Smuzhiyun }
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun static void
drmmode_ConvertFromKMode(xf86OutputPtr output,drmModeModeInfo * kmode,DisplayModePtr mode)1549*4882a593Smuzhiyun drmmode_ConvertFromKMode(xf86OutputPtr output,
1550*4882a593Smuzhiyun                          drmModeModeInfo * kmode, DisplayModePtr mode)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun     ScrnInfoPtr scrn = output->scrn;
1553*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun     memset(mode, 0, sizeof(DisplayModeRec));
1556*4882a593Smuzhiyun     mode->status = MODE_OK;
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun     mode->Clock = kmode->clock;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun     mode->HDisplay = kmode->hdisplay;
1561*4882a593Smuzhiyun     mode->HSyncStart = kmode->hsync_start;
1562*4882a593Smuzhiyun     mode->HSyncEnd = kmode->hsync_end;
1563*4882a593Smuzhiyun     mode->HTotal = kmode->htotal;
1564*4882a593Smuzhiyun     mode->HSkew = kmode->hskew;
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun     mode->VDisplay = kmode->vdisplay;
1567*4882a593Smuzhiyun     mode->VSyncStart = kmode->vsync_start;
1568*4882a593Smuzhiyun     mode->VSyncEnd = kmode->vsync_end;
1569*4882a593Smuzhiyun     mode->VTotal = kmode->vtotal;
1570*4882a593Smuzhiyun     mode->VScan = kmode->vscan;
1571*4882a593Smuzhiyun 
1572*4882a593Smuzhiyun     mode->Flags = kmode->flags; //& FLAG_BITS;
1573*4882a593Smuzhiyun     mode->name = strdup(kmode->name);
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun     if (kmode->type & DRM_MODE_TYPE_DRIVER)
1576*4882a593Smuzhiyun         mode->type = M_T_DRIVER;
1577*4882a593Smuzhiyun     if (kmode->type & DRM_MODE_TYPE_PREFERRED)
1578*4882a593Smuzhiyun         mode->type |= M_T_PREFERRED;
1579*4882a593Smuzhiyun     xf86SetModeCrtc(mode, scrn->adjustFlags);
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun     /* HACK: Use virtual size for all modes */
1582*4882a593Smuzhiyun     if (drmmode_output->virtual_width && drmmode_output->virtual_height) {
1583*4882a593Smuzhiyun         mode->HDisplay = drmmode_output->virtual_width;
1584*4882a593Smuzhiyun         mode->VDisplay = drmmode_output->virtual_height;
1585*4882a593Smuzhiyun     }
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun static void
drmmode_ConvertToKMode(xf86CrtcPtr crtc,drmModeModeInfo * kmode,DisplayModePtr mode)1589*4882a593Smuzhiyun drmmode_ConvertToKMode(xf86CrtcPtr crtc,
1590*4882a593Smuzhiyun                        drmModeModeInfo * kmode, DisplayModePtr mode)
1591*4882a593Smuzhiyun {
1592*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1593*4882a593Smuzhiyun     int i, j;
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun     /* HACK: Convert from virtual size */
1596*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
1597*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
1598*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output = output->driver_private;
1599*4882a593Smuzhiyun         drmModeConnectorPtr koutput = drmmode_output->mode_output;
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun         if (output->crtc != crtc)
1602*4882a593Smuzhiyun             continue;
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun         if (!drmmode_output->virtual_width || !drmmode_output->virtual_height)
1605*4882a593Smuzhiyun             continue;
1606*4882a593Smuzhiyun 
1607*4882a593Smuzhiyun         /* Search for original mode */
1608*4882a593Smuzhiyun         for (j = 0; j < koutput->count_modes; j++) {
1609*4882a593Smuzhiyun             drmModeModeInfoPtr scan = &koutput->modes[j];
1610*4882a593Smuzhiyun             if (scan->clock == mode->Clock &&
1611*4882a593Smuzhiyun                 scan->hsync_start == mode->HSyncStart &&
1612*4882a593Smuzhiyun                 scan->hsync_end == mode->HSyncEnd &&
1613*4882a593Smuzhiyun                 scan->htotal == mode->HTotal &&
1614*4882a593Smuzhiyun                 scan->hskew == mode->HSkew &&
1615*4882a593Smuzhiyun                 scan->vsync_start == mode->VSyncStart &&
1616*4882a593Smuzhiyun                 scan->vsync_end == mode->VSyncEnd &&
1617*4882a593Smuzhiyun                 scan->vtotal == mode->VTotal &&
1618*4882a593Smuzhiyun                 scan->vscan == mode->VScan) {
1619*4882a593Smuzhiyun                 *kmode = *scan;
1620*4882a593Smuzhiyun                 return;
1621*4882a593Smuzhiyun             }
1622*4882a593Smuzhiyun         }
1623*4882a593Smuzhiyun     }
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun     memset(kmode, 0, sizeof(*kmode));
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun     kmode->clock = mode->Clock;
1628*4882a593Smuzhiyun     kmode->hdisplay = mode->HDisplay;
1629*4882a593Smuzhiyun     kmode->hsync_start = mode->HSyncStart;
1630*4882a593Smuzhiyun     kmode->hsync_end = mode->HSyncEnd;
1631*4882a593Smuzhiyun     kmode->htotal = mode->HTotal;
1632*4882a593Smuzhiyun     kmode->hskew = mode->HSkew;
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun     kmode->vdisplay = mode->VDisplay;
1635*4882a593Smuzhiyun     kmode->vsync_start = mode->VSyncStart;
1636*4882a593Smuzhiyun     kmode->vsync_end = mode->VSyncEnd;
1637*4882a593Smuzhiyun     kmode->vtotal = mode->VTotal;
1638*4882a593Smuzhiyun     kmode->vscan = mode->VScan;
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun     kmode->flags = mode->Flags; //& FLAG_BITS;
1641*4882a593Smuzhiyun     if (mode->name)
1642*4882a593Smuzhiyun         strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
1643*4882a593Smuzhiyun     kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
1644*4882a593Smuzhiyun 
1645*4882a593Smuzhiyun }
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun static void
drmmode_crtc_dpms(xf86CrtcPtr crtc,int mode)1648*4882a593Smuzhiyun drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
1649*4882a593Smuzhiyun {
1650*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
1651*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1652*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun     /* XXX Check if DPMS mode is already the right one */
1655*4882a593Smuzhiyun 
1656*4882a593Smuzhiyun     drmmode_crtc->dpms_mode = mode;
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun     if (ms->atomic_modeset) {
1659*4882a593Smuzhiyun         if (mode != DPMSModeOn && !ms->pending_modeset)
1660*4882a593Smuzhiyun             drmmode_crtc_disable(crtc);
1661*4882a593Smuzhiyun     } else if (crtc->enabled == FALSE) {
1662*4882a593Smuzhiyun         drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1663*4882a593Smuzhiyun                        0, 0, 0, NULL, 0, NULL);
1664*4882a593Smuzhiyun     }
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun static Bool
drmmode_crtc_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode,xf86CrtcPtr crtc)1668*4882a593Smuzhiyun drmmode_crtc_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
1669*4882a593Smuzhiyun                      xf86CrtcPtr crtc)
1670*4882a593Smuzhiyun {
1671*4882a593Smuzhiyun     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1672*4882a593Smuzhiyun     PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
1673*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1674*4882a593Smuzhiyun     drmmode_prop_info_rec *props_plane = drmmode_crtc->props_plane;
1675*4882a593Smuzhiyun     drmModeObjectProperties *props;
1676*4882a593Smuzhiyun     PixmapPtr src = NULL, dst;
1677*4882a593Smuzhiyun     drmModeFBPtr fbcon;
1678*4882a593Smuzhiyun     struct dumb_bo *bo;
1679*4882a593Smuzhiyun     GCPtr gc;
1680*4882a593Smuzhiyun     int src_x, src_y, src_w, src_h, crtc_x, crtc_y, crtc_w, crtc_h;
1681*4882a593Smuzhiyun     int fbcon_id, fb_width, fb_height, fb_pitch, fb_depth, fb_bpp;
1682*4882a593Smuzhiyun     Bool ret = FALSE;
1683*4882a593Smuzhiyun 
1684*4882a593Smuzhiyun     if (!drmmode_crtc->plane_id)
1685*4882a593Smuzhiyun         return FALSE;
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun     if (!(fbcon_id = drmmode_crtc->mode_crtc->buffer_id))
1688*4882a593Smuzhiyun         return FALSE;
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun     if (fbcon_id == drmmode->fb_id) {
1691*4882a593Smuzhiyun         /* in some rare case there might be no fbcon and we might already
1692*4882a593Smuzhiyun          * be the one with the current fb to avoid a false deadlck in
1693*4882a593Smuzhiyun          * kernel ttm code just do nothing as anyway there is nothing
1694*4882a593Smuzhiyun          * to do
1695*4882a593Smuzhiyun          */
1696*4882a593Smuzhiyun         return FALSE;
1697*4882a593Smuzhiyun     }
1698*4882a593Smuzhiyun 
1699*4882a593Smuzhiyun     props = drmModeObjectGetProperties(drmmode->fd, drmmode_crtc->plane_id,
1700*4882a593Smuzhiyun                                        DRM_MODE_OBJECT_PLANE);
1701*4882a593Smuzhiyun     if (!props) {
1702*4882a593Smuzhiyun         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
1703*4882a593Smuzhiyun                    "couldn't get plane properties\n");
1704*4882a593Smuzhiyun         return FALSE;
1705*4882a593Smuzhiyun     }
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun     src_x = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_X],
1708*4882a593Smuzhiyun                                    props, 0) >> 16;
1709*4882a593Smuzhiyun     src_y = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_Y],
1710*4882a593Smuzhiyun                                    props, 0) >> 16;
1711*4882a593Smuzhiyun     src_w = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_W],
1712*4882a593Smuzhiyun                                    props, 0) >> 16;
1713*4882a593Smuzhiyun     src_h = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_H],
1714*4882a593Smuzhiyun                                    props, 0) >> 16;
1715*4882a593Smuzhiyun     crtc_x = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_X],
1716*4882a593Smuzhiyun                                     props, 0) + crtc->x;
1717*4882a593Smuzhiyun     crtc_y = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_Y],
1718*4882a593Smuzhiyun                                     props, 0) + crtc->y;
1719*4882a593Smuzhiyun     crtc_w = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_W],
1720*4882a593Smuzhiyun                                     props, 0);
1721*4882a593Smuzhiyun     crtc_h = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_H],
1722*4882a593Smuzhiyun                                     props, 0);
1723*4882a593Smuzhiyun     drmModeFreeObjectProperties(props);
1724*4882a593Smuzhiyun 
1725*4882a593Smuzhiyun     if (!src_w || !src_h || src_w != crtc_w || src_h != crtc_h ||
1726*4882a593Smuzhiyun         crtc_x + crtc_w > screen_pixmap->drawable.width ||
1727*4882a593Smuzhiyun         crtc_y + crtc_h > screen_pixmap->drawable.height)
1728*4882a593Smuzhiyun         return FALSE;
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun     fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
1731*4882a593Smuzhiyun     if (!fbcon)
1732*4882a593Smuzhiyun         return FALSE;
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun     fb_width = fbcon->width;
1735*4882a593Smuzhiyun     fb_height = fbcon->height;
1736*4882a593Smuzhiyun     fb_pitch = fbcon->pitch;
1737*4882a593Smuzhiyun     fb_depth = fbcon->depth;
1738*4882a593Smuzhiyun     fb_bpp = fbcon->bpp;
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun     bo = dumb_get_bo_from_handle(drmmode->fd, fbcon->handle, fbcon->pitch,
1741*4882a593Smuzhiyun                                  fbcon->pitch * fbcon->height);
1742*4882a593Smuzhiyun     drmModeFreeFB(fbcon);
1743*4882a593Smuzhiyun     if (!bo)
1744*4882a593Smuzhiyun         return FALSE;
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun     if (dumb_bo_map(drmmode->fd, bo) < 0)
1747*4882a593Smuzhiyun         goto out;
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun     src = drmmode_create_pixmap_header(pScreen, fb_width,
1750*4882a593Smuzhiyun                                        fb_height, fb_depth,
1751*4882a593Smuzhiyun                                        fb_bpp, fb_pitch,
1752*4882a593Smuzhiyun                                        bo->ptr);
1753*4882a593Smuzhiyun     if (!src)
1754*4882a593Smuzhiyun         goto out;
1755*4882a593Smuzhiyun 
1756*4882a593Smuzhiyun     if (drmmode->exa) {
1757*4882a593Smuzhiyun         if (!ms_exa_set_pixmap_bo(pScrn, src, bo, FALSE))
1758*4882a593Smuzhiyun             goto out;
1759*4882a593Smuzhiyun     }
1760*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
1761*4882a593Smuzhiyun     else if (drmmode->glamor) {
1762*4882a593Smuzhiyun         if (!glamor_egl_create_textured_pixmap(src, bo->handle, bo->pitch))
1763*4882a593Smuzhiyun             goto out;
1764*4882a593Smuzhiyun     }
1765*4882a593Smuzhiyun #endif
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun     dst = pScreen->GetScreenPixmap(pScreen);
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun     gc = GetScratchGC(pScrn->depth, pScreen);
1770*4882a593Smuzhiyun     ValidateGC(&dst->drawable, gc);
1771*4882a593Smuzhiyun 
1772*4882a593Smuzhiyun     (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, src_x, src_y,
1773*4882a593Smuzhiyun                          src_w, src_h, crtc_x, crtc_y);
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun     FreeScratchGC(gc);
1776*4882a593Smuzhiyun     ret = TRUE;
1777*4882a593Smuzhiyun 
1778*4882a593Smuzhiyun out:
1779*4882a593Smuzhiyun     if (src)
1780*4882a593Smuzhiyun         pScreen->DestroyPixmap(src);
1781*4882a593Smuzhiyun     if (bo)
1782*4882a593Smuzhiyun         dumb_bo_destroy(drmmode->fd, bo);
1783*4882a593Smuzhiyun     return ret;
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun 
1786*4882a593Smuzhiyun void
drmmode_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode)1787*4882a593Smuzhiyun drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1788*4882a593Smuzhiyun {
1789*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1790*4882a593Smuzhiyun     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1791*4882a593Smuzhiyun     Bool ret = FALSE;
1792*4882a593Smuzhiyun     int i;
1793*4882a593Smuzhiyun 
1794*4882a593Smuzhiyun     if (getenv("XSERVER_NO_BG_NONE"))
1795*4882a593Smuzhiyun         return;
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++)
1798*4882a593Smuzhiyun         ret |= drmmode_crtc_copy_fb(pScrn, drmmode, xf86_config->crtc[i]);
1799*4882a593Smuzhiyun 
1800*4882a593Smuzhiyun     if (!ret)
1801*4882a593Smuzhiyun         return;
1802*4882a593Smuzhiyun 
1803*4882a593Smuzhiyun     pScreen->canDoBGNoneRoot = TRUE;
1804*4882a593Smuzhiyun }
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)1807*4882a593Smuzhiyun drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
1808*4882a593Smuzhiyun                        Rotation rotation, int x, int y)
1809*4882a593Smuzhiyun {
1810*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
1811*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1812*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1813*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1814*4882a593Smuzhiyun     int saved_x, saved_y;
1815*4882a593Smuzhiyun     Rotation saved_rotation;
1816*4882a593Smuzhiyun     DisplayModeRec saved_mode;
1817*4882a593Smuzhiyun     Bool ret = TRUE;
1818*4882a593Smuzhiyun     Bool can_test;
1819*4882a593Smuzhiyun     int i;
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun     /* Ignore modeset when disconnected in hotplug reset mode */
1822*4882a593Smuzhiyun     if (drmmode->hotplug_reset && !drmmode_crtc_connected(crtc))
1823*4882a593Smuzhiyun         return 0;
1824*4882a593Smuzhiyun 
1825*4882a593Smuzhiyun     saved_mode = crtc->mode;
1826*4882a593Smuzhiyun     saved_x = crtc->x;
1827*4882a593Smuzhiyun     saved_y = crtc->y;
1828*4882a593Smuzhiyun     saved_rotation = crtc->rotation;
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun     if (mode) {
1831*4882a593Smuzhiyun         crtc->mode = *mode;
1832*4882a593Smuzhiyun         crtc->x = x;
1833*4882a593Smuzhiyun         crtc->y = y;
1834*4882a593Smuzhiyun         crtc->rotation = rotation;
1835*4882a593Smuzhiyun 
1836*4882a593Smuzhiyun         if (!drmmode_apply_transform(crtc))
1837*4882a593Smuzhiyun             goto done;
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1840*4882a593Smuzhiyun                                crtc->gamma_blue, crtc->gamma_size);
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun         can_test = drmmode_crtc_can_test_mode(crtc);
1843*4882a593Smuzhiyun         if (drmmode_crtc_set_mode(crtc, can_test)) {
1844*4882a593Smuzhiyun             xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1845*4882a593Smuzhiyun                        "failed to set mode: %s\n", strerror(errno));
1846*4882a593Smuzhiyun             ret = FALSE;
1847*4882a593Smuzhiyun             goto done;
1848*4882a593Smuzhiyun         } else
1849*4882a593Smuzhiyun             ret = TRUE;
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun         if (crtc->scrn->pScreen)
1852*4882a593Smuzhiyun             xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun         ms->pending_modeset = TRUE;
1855*4882a593Smuzhiyun         drmmode_crtc->need_modeset = FALSE;
1856*4882a593Smuzhiyun         crtc->funcs->dpms(crtc, DPMSModeOn);
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun         if (drmmode_crtc->prime_pixmap_back)
1859*4882a593Smuzhiyun             drmmode_InitSharedPixmapFlipping(crtc, drmmode);
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun         /* go through all the outputs and force DPMS them back on? */
1862*4882a593Smuzhiyun         for (i = 0; i < xf86_config->num_output; i++) {
1863*4882a593Smuzhiyun             xf86OutputPtr output = xf86_config->output[i];
1864*4882a593Smuzhiyun             drmmode_output_private_ptr drmmode_output;
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun             if (output->crtc != crtc)
1867*4882a593Smuzhiyun                 continue;
1868*4882a593Smuzhiyun 
1869*4882a593Smuzhiyun             drmmode_output = output->driver_private;
1870*4882a593Smuzhiyun             if (drmmode_output->output_id == -1)
1871*4882a593Smuzhiyun                 continue;
1872*4882a593Smuzhiyun             output->funcs->dpms(output, DPMSModeOn);
1873*4882a593Smuzhiyun         }
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun         /* if we only tested the mode previously, really set it now */
1876*4882a593Smuzhiyun         if (can_test)
1877*4882a593Smuzhiyun             drmmode_crtc_set_mode(crtc, FALSE);
1878*4882a593Smuzhiyun         ms->pending_modeset = FALSE;
1879*4882a593Smuzhiyun     }
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun  done:
1882*4882a593Smuzhiyun     if (!ret) {
1883*4882a593Smuzhiyun         crtc->x = saved_x;
1884*4882a593Smuzhiyun         crtc->y = saved_y;
1885*4882a593Smuzhiyun         crtc->rotation = saved_rotation;
1886*4882a593Smuzhiyun         crtc->mode = saved_mode;
1887*4882a593Smuzhiyun     } else
1888*4882a593Smuzhiyun         crtc->active = TRUE;
1889*4882a593Smuzhiyun 
1890*4882a593Smuzhiyun     return ret;
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun 
1893*4882a593Smuzhiyun static void
drmmode_set_cursor_colors(xf86CrtcPtr crtc,int bg,int fg)1894*4882a593Smuzhiyun drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
1895*4882a593Smuzhiyun {
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun }
1898*4882a593Smuzhiyun 
1899*4882a593Smuzhiyun static void
drmmode_set_cursor_position(xf86CrtcPtr crtc,int x,int y)1900*4882a593Smuzhiyun drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
1901*4882a593Smuzhiyun {
1902*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1903*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1904*4882a593Smuzhiyun     drmModeModeInfo kmode;
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun     drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun     x = x * crtc->mode.HDisplay / kmode.hdisplay;
1909*4882a593Smuzhiyun     y = y * crtc->mode.VDisplay / kmode.vdisplay;
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun     drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1912*4882a593Smuzhiyun }
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun static Bool
drmmode_set_cursor(xf86CrtcPtr crtc)1915*4882a593Smuzhiyun drmmode_set_cursor(xf86CrtcPtr crtc)
1916*4882a593Smuzhiyun {
1917*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1918*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1919*4882a593Smuzhiyun     uint32_t handle = drmmode_crtc->cursor_bo->handle;
1920*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
1921*4882a593Smuzhiyun     CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen);
1922*4882a593Smuzhiyun     int ret = -EINVAL;
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun     if (cursor == NullCursor)
1925*4882a593Smuzhiyun 	    return TRUE;
1926*4882a593Smuzhiyun 
1927*4882a593Smuzhiyun     ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1928*4882a593Smuzhiyun                             handle, ms->cursor_width, ms->cursor_height,
1929*4882a593Smuzhiyun                             cursor->bits->xhot, cursor->bits->yhot);
1930*4882a593Smuzhiyun 
1931*4882a593Smuzhiyun     /* -EINVAL can mean that an old kernel supports drmModeSetCursor but
1932*4882a593Smuzhiyun      * not drmModeSetCursor2, though it can mean other things too. */
1933*4882a593Smuzhiyun     if (ret == -EINVAL)
1934*4882a593Smuzhiyun         ret = drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1935*4882a593Smuzhiyun                                handle, ms->cursor_width, ms->cursor_height);
1936*4882a593Smuzhiyun 
1937*4882a593Smuzhiyun     /* -ENXIO normally means that the current drm driver supports neither
1938*4882a593Smuzhiyun      * cursor_set nor cursor_set2.  Disable hardware cursor support for
1939*4882a593Smuzhiyun      * the rest of the session in that case. */
1940*4882a593Smuzhiyun     if (ret == -ENXIO) {
1941*4882a593Smuzhiyun         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1942*4882a593Smuzhiyun         xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
1943*4882a593Smuzhiyun 
1944*4882a593Smuzhiyun         cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
1945*4882a593Smuzhiyun         drmmode_crtc->drmmode->sw_cursor = TRUE;
1946*4882a593Smuzhiyun     }
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun     if (ret)
1949*4882a593Smuzhiyun         /* fallback to swcursor */
1950*4882a593Smuzhiyun         return FALSE;
1951*4882a593Smuzhiyun     return TRUE;
1952*4882a593Smuzhiyun }
1953*4882a593Smuzhiyun 
1954*4882a593Smuzhiyun static void drmmode_hide_cursor(xf86CrtcPtr crtc);
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun /*
1957*4882a593Smuzhiyun  * The load_cursor_argb_check driver hook.
1958*4882a593Smuzhiyun  *
1959*4882a593Smuzhiyun  * Sets the hardware cursor by calling the drmModeSetCursor2 ioctl.
1960*4882a593Smuzhiyun  * On failure, returns FALSE indicating that the X server should fall
1961*4882a593Smuzhiyun  * back to software cursors.
1962*4882a593Smuzhiyun  */
1963*4882a593Smuzhiyun static Bool
drmmode_load_cursor_argb_check(xf86CrtcPtr crtc,CARD32 * image)1964*4882a593Smuzhiyun drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
1967*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1968*4882a593Smuzhiyun     int i;
1969*4882a593Smuzhiyun     uint32_t *ptr;
1970*4882a593Smuzhiyun 
1971*4882a593Smuzhiyun     /* cursor should be mapped already */
1972*4882a593Smuzhiyun     ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr);
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun     for (i = 0; i < ms->cursor_width * ms->cursor_height; i++)
1975*4882a593Smuzhiyun         ptr[i] = image[i];      // cpu_to_le32(image[i]);
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun     if (drmmode_crtc->cursor_up)
1978*4882a593Smuzhiyun         return drmmode_set_cursor(crtc);
1979*4882a593Smuzhiyun     return TRUE;
1980*4882a593Smuzhiyun }
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun static void
drmmode_hide_cursor(xf86CrtcPtr crtc)1983*4882a593Smuzhiyun drmmode_hide_cursor(xf86CrtcPtr crtc)
1984*4882a593Smuzhiyun {
1985*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
1986*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1987*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun     drmmode_crtc->cursor_up = FALSE;
1990*4882a593Smuzhiyun     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1991*4882a593Smuzhiyun                      ms->cursor_width, ms->cursor_height);
1992*4882a593Smuzhiyun }
1993*4882a593Smuzhiyun 
1994*4882a593Smuzhiyun static Bool
drmmode_show_cursor(xf86CrtcPtr crtc)1995*4882a593Smuzhiyun drmmode_show_cursor(xf86CrtcPtr crtc)
1996*4882a593Smuzhiyun {
1997*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1998*4882a593Smuzhiyun     drmmode_crtc->cursor_up = TRUE;
1999*4882a593Smuzhiyun     return drmmode_set_cursor(crtc);
2000*4882a593Smuzhiyun }
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun static void
drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)2003*4882a593Smuzhiyun drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc,
2004*4882a593Smuzhiyun                       uint16_t * red, uint16_t * green, uint16_t * blue,
2005*4882a593Smuzhiyun                       int size)
2006*4882a593Smuzhiyun {
2007*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2008*4882a593Smuzhiyun     drmmode_prop_info_ptr gamma_lut_info =
2009*4882a593Smuzhiyun         &drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT];
2010*4882a593Smuzhiyun     const uint32_t crtc_id = drmmode_crtc->mode_crtc->crtc_id;
2011*4882a593Smuzhiyun     uint32_t blob_id;
2012*4882a593Smuzhiyun     struct drm_color_lut lut[size];
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun     assert(gamma_lut_info->prop_id != 0);
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun     for (int i = 0; i < size; i++) {
2017*4882a593Smuzhiyun         lut[i].red = red[i];
2018*4882a593Smuzhiyun         lut[i].green = green[i];
2019*4882a593Smuzhiyun         lut[i].blue = blue[i];
2020*4882a593Smuzhiyun     }
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun     if (drmModeCreatePropertyBlob(drmmode->fd, lut, sizeof(lut), &blob_id))
2023*4882a593Smuzhiyun         return;
2024*4882a593Smuzhiyun 
2025*4882a593Smuzhiyun     drmModeObjectSetProperty(drmmode->fd, crtc_id, DRM_MODE_OBJECT_CRTC,
2026*4882a593Smuzhiyun                              gamma_lut_info->prop_id, blob_id);
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun     drmModeDestroyPropertyBlob(drmmode->fd, blob_id);
2029*4882a593Smuzhiyun }
2030*4882a593Smuzhiyun 
2031*4882a593Smuzhiyun static void
drmmode_crtc_gamma_set(xf86CrtcPtr crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)2032*4882a593Smuzhiyun drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
2033*4882a593Smuzhiyun                        uint16_t * blue, int size)
2034*4882a593Smuzhiyun {
2035*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2036*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun     if (drmmode_crtc->use_gamma_lut) {
2039*4882a593Smuzhiyun         drmmode_set_gamma_lut(drmmode_crtc, red, green, blue, size);
2040*4882a593Smuzhiyun     } else {
2041*4882a593Smuzhiyun         drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
2042*4882a593Smuzhiyun                             size, red, green, blue);
2043*4882a593Smuzhiyun     }
2044*4882a593Smuzhiyun }
2045*4882a593Smuzhiyun 
2046*4882a593Smuzhiyun static Bool
drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2047*4882a593Smuzhiyun drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
2048*4882a593Smuzhiyun                                       PixmapPtr *target)
2049*4882a593Smuzhiyun {
2050*4882a593Smuzhiyun     ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
2051*4882a593Smuzhiyun     PixmapPtr screenpix = screen->GetScreenPixmap(screen);
2052*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
2053*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2054*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2055*4882a593Smuzhiyun     int c, total_width = 0, max_height = 0, this_x = 0;
2056*4882a593Smuzhiyun 
2057*4882a593Smuzhiyun     if (*target) {
2058*4882a593Smuzhiyun         PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
2059*4882a593Smuzhiyun         if (drmmode->fb_id) {
2060*4882a593Smuzhiyun             drmModeRmFB(drmmode->fd, drmmode->fb_id);
2061*4882a593Smuzhiyun             drmmode->fb_id = 0;
2062*4882a593Smuzhiyun         }
2063*4882a593Smuzhiyun         drmmode_crtc->prime_pixmap_x = 0;
2064*4882a593Smuzhiyun         *target = NULL;
2065*4882a593Smuzhiyun     }
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun     if (!ppix)
2068*4882a593Smuzhiyun         return TRUE;
2069*4882a593Smuzhiyun 
2070*4882a593Smuzhiyun     /* iterate over all the attached crtcs to work out the bounding box */
2071*4882a593Smuzhiyun     for (c = 0; c < xf86_config->num_crtc; c++) {
2072*4882a593Smuzhiyun         xf86CrtcPtr iter = xf86_config->crtc[c];
2073*4882a593Smuzhiyun         if (!iter->enabled && iter != crtc)
2074*4882a593Smuzhiyun             continue;
2075*4882a593Smuzhiyun         if (iter == crtc) {
2076*4882a593Smuzhiyun             this_x = total_width;
2077*4882a593Smuzhiyun             total_width += ppix->drawable.width;
2078*4882a593Smuzhiyun             if (max_height < ppix->drawable.height)
2079*4882a593Smuzhiyun                 max_height = ppix->drawable.height;
2080*4882a593Smuzhiyun         } else {
2081*4882a593Smuzhiyun             total_width += iter->mode.HDisplay;
2082*4882a593Smuzhiyun             if (max_height < iter->mode.VDisplay)
2083*4882a593Smuzhiyun                 max_height = iter->mode.VDisplay;
2084*4882a593Smuzhiyun         }
2085*4882a593Smuzhiyun     }
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun     if (total_width != screenpix->drawable.width ||
2088*4882a593Smuzhiyun         max_height != screenpix->drawable.height) {
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun         if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
2091*4882a593Smuzhiyun             return FALSE;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun         screenpix = screen->GetScreenPixmap(screen);
2094*4882a593Smuzhiyun         screen->width = screenpix->drawable.width = total_width;
2095*4882a593Smuzhiyun         screen->height = screenpix->drawable.height = max_height;
2096*4882a593Smuzhiyun     }
2097*4882a593Smuzhiyun     drmmode_crtc->prime_pixmap_x = this_x;
2098*4882a593Smuzhiyun     PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
2099*4882a593Smuzhiyun                              RR_Rotate_0);
2100*4882a593Smuzhiyun     *target = ppix;
2101*4882a593Smuzhiyun     return TRUE;
2102*4882a593Smuzhiyun }
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun static Bool
drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2105*4882a593Smuzhiyun drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
2106*4882a593Smuzhiyun                                       PixmapPtr *target)
2107*4882a593Smuzhiyun {
2108*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2109*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2110*4882a593Smuzhiyun     msPixmapPrivPtr ppriv;
2111*4882a593Smuzhiyun     void *ptr;
2112*4882a593Smuzhiyun 
2113*4882a593Smuzhiyun     if (*target) {
2114*4882a593Smuzhiyun         ppriv = msGetPixmapPriv(drmmode, *target);
2115*4882a593Smuzhiyun         drmModeRmFB(drmmode->fd, ppriv->fb_id);
2116*4882a593Smuzhiyun         ppriv->fb_id = 0;
2117*4882a593Smuzhiyun         if (ppriv->slave_damage) {
2118*4882a593Smuzhiyun             DamageUnregister(ppriv->slave_damage);
2119*4882a593Smuzhiyun             ppriv->slave_damage = NULL;
2120*4882a593Smuzhiyun         }
2121*4882a593Smuzhiyun         *target = NULL;
2122*4882a593Smuzhiyun     }
2123*4882a593Smuzhiyun 
2124*4882a593Smuzhiyun     if (!ppix)
2125*4882a593Smuzhiyun         return TRUE;
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun     ppriv = msGetPixmapPriv(drmmode, ppix);
2128*4882a593Smuzhiyun     if (!ppriv->slave_damage) {
2129*4882a593Smuzhiyun         ppriv->slave_damage = DamageCreate(NULL, NULL,
2130*4882a593Smuzhiyun                                            DamageReportNone,
2131*4882a593Smuzhiyun                                            TRUE,
2132*4882a593Smuzhiyun                                            crtc->randr_crtc->pScreen,
2133*4882a593Smuzhiyun                                            NULL);
2134*4882a593Smuzhiyun     }
2135*4882a593Smuzhiyun     ptr = drmmode_map_slave_bo(drmmode, ppriv);
2136*4882a593Smuzhiyun     ppix->devPrivate.ptr = ptr;
2137*4882a593Smuzhiyun     DamageRegister(&ppix->drawable, ppriv->slave_damage);
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun     if (ppriv->fb_id == 0) {
2140*4882a593Smuzhiyun         drmModeAddFB(drmmode->fd, ppix->drawable.width,
2141*4882a593Smuzhiyun                      ppix->drawable.height,
2142*4882a593Smuzhiyun                      ppix->drawable.depth,
2143*4882a593Smuzhiyun                      ppix->drawable.bitsPerPixel,
2144*4882a593Smuzhiyun                      ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
2145*4882a593Smuzhiyun     }
2146*4882a593Smuzhiyun     *target = ppix;
2147*4882a593Smuzhiyun     return TRUE;
2148*4882a593Smuzhiyun }
2149*4882a593Smuzhiyun 
2150*4882a593Smuzhiyun static Bool
drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2151*4882a593Smuzhiyun drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
2152*4882a593Smuzhiyun                                   PixmapPtr *target)
2153*4882a593Smuzhiyun {
2154*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2155*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun     if (drmmode->reverse_prime_offload_mode)
2158*4882a593Smuzhiyun         return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
2159*4882a593Smuzhiyun     else
2160*4882a593Smuzhiyun         return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
2161*4882a593Smuzhiyun }
2162*4882a593Smuzhiyun 
2163*4882a593Smuzhiyun static Bool
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix)2164*4882a593Smuzhiyun drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
2165*4882a593Smuzhiyun {
2166*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun     /* Use DisableSharedPixmapFlipping before switching to single buf */
2169*4882a593Smuzhiyun     if (drmmode_crtc->enable_flipping)
2170*4882a593Smuzhiyun         return FALSE;
2171*4882a593Smuzhiyun 
2172*4882a593Smuzhiyun     return drmmode_set_target_scanout_pixmap(crtc, ppix,
2173*4882a593Smuzhiyun                                              &drmmode_crtc->prime_pixmap);
2174*4882a593Smuzhiyun }
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun static void
drmmode_clear_pixmap(PixmapPtr pixmap)2177*4882a593Smuzhiyun drmmode_clear_pixmap(PixmapPtr pixmap)
2178*4882a593Smuzhiyun {
2179*4882a593Smuzhiyun     ScreenPtr screen = pixmap->drawable.pScreen;
2180*4882a593Smuzhiyun     GCPtr gc;
2181*4882a593Smuzhiyun 
2182*4882a593Smuzhiyun     gc = GetScratchGC(pixmap->drawable.depth, screen);
2183*4882a593Smuzhiyun     if (gc) {
2184*4882a593Smuzhiyun         miClearDrawable(&pixmap->drawable, gc);
2185*4882a593Smuzhiyun         FreeScratchGC(gc);
2186*4882a593Smuzhiyun     }
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun 
2189*4882a593Smuzhiyun static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc,int width,int height)2190*4882a593Smuzhiyun drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
2191*4882a593Smuzhiyun {
2192*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2193*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2194*4882a593Smuzhiyun     int ret;
2195*4882a593Smuzhiyun 
2196*4882a593Smuzhiyun     if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
2197*4882a593Smuzhiyun                            width, height, drmmode->kbpp)) {
2198*4882a593Smuzhiyun         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
2199*4882a593Smuzhiyun                "Couldn't allocate shadow memory for rotated CRTC\n");
2200*4882a593Smuzhiyun         return NULL;
2201*4882a593Smuzhiyun     }
2202*4882a593Smuzhiyun 
2203*4882a593Smuzhiyun     ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
2204*4882a593Smuzhiyun                             &drmmode_crtc->rotate_fb_id);
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun     if (ret) {
2207*4882a593Smuzhiyun         ErrorF("failed to add rotate fb\n");
2208*4882a593Smuzhiyun         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
2209*4882a593Smuzhiyun         return NULL;
2210*4882a593Smuzhiyun     }
2211*4882a593Smuzhiyun 
2212*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
2213*4882a593Smuzhiyun     if (drmmode->gbm)
2214*4882a593Smuzhiyun         return drmmode_crtc->rotate_bo.gbm;
2215*4882a593Smuzhiyun #endif
2216*4882a593Smuzhiyun     return drmmode_crtc->rotate_bo.dumb;
2217*4882a593Smuzhiyun }
2218*4882a593Smuzhiyun 
2219*4882a593Smuzhiyun PixmapPtr
drmmode_create_pixmap_header(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)2220*4882a593Smuzhiyun drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
2221*4882a593Smuzhiyun                              int depth, int bitsPerPixel, int devKind,
2222*4882a593Smuzhiyun                              void *pPixData)
2223*4882a593Smuzhiyun {
2224*4882a593Smuzhiyun     PixmapPtr pixmap;
2225*4882a593Smuzhiyun 
2226*4882a593Smuzhiyun     /* width and height of 0 means don't allocate any pixmap data */
2227*4882a593Smuzhiyun     pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
2228*4882a593Smuzhiyun 
2229*4882a593Smuzhiyun     if (pixmap) {
2230*4882a593Smuzhiyun         if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
2231*4882a593Smuzhiyun                                            bitsPerPixel, devKind, pPixData))
2232*4882a593Smuzhiyun             return pixmap;
2233*4882a593Smuzhiyun         (*pScreen->DestroyPixmap)(pixmap);
2234*4882a593Smuzhiyun     }
2235*4882a593Smuzhiyun     return NullPixmap;
2236*4882a593Smuzhiyun }
2237*4882a593Smuzhiyun 
2238*4882a593Smuzhiyun static Bool
2239*4882a593Smuzhiyun drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc,void * data,int width,int height)2242*4882a593Smuzhiyun drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
2243*4882a593Smuzhiyun {
2244*4882a593Smuzhiyun     ScrnInfoPtr scrn = crtc->scrn;
2245*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2246*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2247*4882a593Smuzhiyun     uint32_t rotate_pitch;
2248*4882a593Smuzhiyun     PixmapPtr rotate_pixmap;
2249*4882a593Smuzhiyun     void *pPixData = NULL;
2250*4882a593Smuzhiyun 
2251*4882a593Smuzhiyun     if (!data) {
2252*4882a593Smuzhiyun         data = drmmode_shadow_allocate(crtc, width, height);
2253*4882a593Smuzhiyun         if (!data) {
2254*4882a593Smuzhiyun             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2255*4882a593Smuzhiyun                        "Couldn't allocate shadow pixmap for rotated CRTC\n");
2256*4882a593Smuzhiyun             return NULL;
2257*4882a593Smuzhiyun         }
2258*4882a593Smuzhiyun     }
2259*4882a593Smuzhiyun 
2260*4882a593Smuzhiyun     if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
2261*4882a593Smuzhiyun         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2262*4882a593Smuzhiyun                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
2263*4882a593Smuzhiyun         return NULL;
2264*4882a593Smuzhiyun     }
2265*4882a593Smuzhiyun 
2266*4882a593Smuzhiyun     pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
2267*4882a593Smuzhiyun     rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo),
2268*4882a593Smuzhiyun 
2269*4882a593Smuzhiyun     rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
2270*4882a593Smuzhiyun                                                  width, height,
2271*4882a593Smuzhiyun                                                  scrn->depth,
2272*4882a593Smuzhiyun                                                  drmmode->kbpp,
2273*4882a593Smuzhiyun                                                  rotate_pitch,
2274*4882a593Smuzhiyun                                                  pPixData);
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun     if (rotate_pixmap == NULL) {
2277*4882a593Smuzhiyun         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2278*4882a593Smuzhiyun                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
2279*4882a593Smuzhiyun         return NULL;
2280*4882a593Smuzhiyun     }
2281*4882a593Smuzhiyun 
2282*4882a593Smuzhiyun     drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
2283*4882a593Smuzhiyun 
2284*4882a593Smuzhiyun     return rotate_pixmap;
2285*4882a593Smuzhiyun }
2286*4882a593Smuzhiyun 
2287*4882a593Smuzhiyun static void
drmmode_shadow_destroy(xf86CrtcPtr crtc,PixmapPtr rotate_pixmap,void * data)2288*4882a593Smuzhiyun drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
2289*4882a593Smuzhiyun {
2290*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2291*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun     if (rotate_pixmap) {
2294*4882a593Smuzhiyun         rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
2295*4882a593Smuzhiyun     }
2296*4882a593Smuzhiyun 
2297*4882a593Smuzhiyun     if (data) {
2298*4882a593Smuzhiyun         drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
2299*4882a593Smuzhiyun         drmmode_crtc->rotate_fb_id = 0;
2300*4882a593Smuzhiyun 
2301*4882a593Smuzhiyun         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
2302*4882a593Smuzhiyun         memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
2303*4882a593Smuzhiyun     }
2304*4882a593Smuzhiyun }
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)2307*4882a593Smuzhiyun drmmode_crtc_destroy(xf86CrtcPtr crtc)
2308*4882a593Smuzhiyun {
2309*4882a593Smuzhiyun     drmmode_mode_ptr iterator, next;
2310*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2311*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(crtc->scrn);
2312*4882a593Smuzhiyun 
2313*4882a593Smuzhiyun     if (!ms->atomic_modeset)
2314*4882a593Smuzhiyun         return;
2315*4882a593Smuzhiyun 
2316*4882a593Smuzhiyun     drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2317*4882a593Smuzhiyun     xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
2318*4882a593Smuzhiyun         drm_mode_destroy(crtc, iterator);
2319*4882a593Smuzhiyun     }
2320*4882a593Smuzhiyun }
2321*4882a593Smuzhiyun 
2322*4882a593Smuzhiyun static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
2323*4882a593Smuzhiyun     .dpms = drmmode_crtc_dpms,
2324*4882a593Smuzhiyun     .set_mode_major = drmmode_set_mode_major,
2325*4882a593Smuzhiyun     .set_cursor_colors = drmmode_set_cursor_colors,
2326*4882a593Smuzhiyun     .set_cursor_position = drmmode_set_cursor_position,
2327*4882a593Smuzhiyun     .show_cursor_check = drmmode_show_cursor,
2328*4882a593Smuzhiyun     .hide_cursor = drmmode_hide_cursor,
2329*4882a593Smuzhiyun     .load_cursor_argb_check = drmmode_load_cursor_argb_check,
2330*4882a593Smuzhiyun 
2331*4882a593Smuzhiyun     .gamma_set = drmmode_crtc_gamma_set,
2332*4882a593Smuzhiyun     .destroy = drmmode_crtc_destroy,
2333*4882a593Smuzhiyun     .set_scanout_pixmap = drmmode_set_scanout_pixmap,
2334*4882a593Smuzhiyun     .shadow_allocate = drmmode_shadow_allocate,
2335*4882a593Smuzhiyun     .shadow_create = drmmode_shadow_create,
2336*4882a593Smuzhiyun     .shadow_destroy = drmmode_shadow_destroy,
2337*4882a593Smuzhiyun };
2338*4882a593Smuzhiyun 
2339*4882a593Smuzhiyun static uint32_t
drmmode_crtc_vblank_pipe(int crtc_id)2340*4882a593Smuzhiyun drmmode_crtc_vblank_pipe(int crtc_id)
2341*4882a593Smuzhiyun {
2342*4882a593Smuzhiyun     if (crtc_id > 1)
2343*4882a593Smuzhiyun         return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
2344*4882a593Smuzhiyun     else if (crtc_id > 0)
2345*4882a593Smuzhiyun         return DRM_VBLANK_SECONDARY;
2346*4882a593Smuzhiyun     else
2347*4882a593Smuzhiyun         return 0;
2348*4882a593Smuzhiyun }
2349*4882a593Smuzhiyun 
2350*4882a593Smuzhiyun static Bool
is_plane_assigned(ScrnInfoPtr scrn,int plane_id)2351*4882a593Smuzhiyun is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
2352*4882a593Smuzhiyun {
2353*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2354*4882a593Smuzhiyun     int c;
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun     for (c = 0; c < xf86_config->num_crtc; c++) {
2357*4882a593Smuzhiyun         xf86CrtcPtr iter = xf86_config->crtc[c];
2358*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
2359*4882a593Smuzhiyun         if (drmmode_crtc->plane_id == plane_id)
2360*4882a593Smuzhiyun             return TRUE;
2361*4882a593Smuzhiyun     }
2362*4882a593Smuzhiyun 
2363*4882a593Smuzhiyun     return FALSE;
2364*4882a593Smuzhiyun }
2365*4882a593Smuzhiyun 
2366*4882a593Smuzhiyun /**
2367*4882a593Smuzhiyun  * Populates the formats array, and the modifiers of each format for a drm_plane.
2368*4882a593Smuzhiyun  */
2369*4882a593Smuzhiyun static Bool
populate_format_modifiers(xf86CrtcPtr crtc,const drmModePlane * kplane,uint32_t blob_id)2370*4882a593Smuzhiyun populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
2371*4882a593Smuzhiyun                           uint32_t blob_id)
2372*4882a593Smuzhiyun {
2373*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2374*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2375*4882a593Smuzhiyun     unsigned i, j;
2376*4882a593Smuzhiyun     drmModePropertyBlobRes *blob;
2377*4882a593Smuzhiyun     struct drm_format_modifier_blob *fmt_mod_blob;
2378*4882a593Smuzhiyun     uint32_t *blob_formats;
2379*4882a593Smuzhiyun     struct drm_format_modifier *blob_modifiers;
2380*4882a593Smuzhiyun 
2381*4882a593Smuzhiyun     if (!blob_id)
2382*4882a593Smuzhiyun         return FALSE;
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun     blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
2385*4882a593Smuzhiyun     if (!blob)
2386*4882a593Smuzhiyun         return FALSE;
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun     fmt_mod_blob = blob->data;
2389*4882a593Smuzhiyun     blob_formats = formats_ptr(fmt_mod_blob);
2390*4882a593Smuzhiyun     blob_modifiers = modifiers_ptr(fmt_mod_blob);
2391*4882a593Smuzhiyun 
2392*4882a593Smuzhiyun     assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
2393*4882a593Smuzhiyun 
2394*4882a593Smuzhiyun     for (i = 0; i < fmt_mod_blob->count_formats; i++) {
2395*4882a593Smuzhiyun         uint32_t num_modifiers = 0;
2396*4882a593Smuzhiyun         uint64_t *modifiers = NULL;
2397*4882a593Smuzhiyun         uint64_t *tmp;
2398*4882a593Smuzhiyun         for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
2399*4882a593Smuzhiyun             struct drm_format_modifier *mod = &blob_modifiers[j];
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun             if ((i < mod->offset) || (i > mod->offset + 63))
2402*4882a593Smuzhiyun                 continue;
2403*4882a593Smuzhiyun             if (!(mod->formats & (1 << (i - mod->offset))))
2404*4882a593Smuzhiyun                 continue;
2405*4882a593Smuzhiyun 
2406*4882a593Smuzhiyun             if (!mod->modifier || mod->modifier == DRM_FORMAT_MOD_INVALID)
2407*4882a593Smuzhiyun                 continue;
2408*4882a593Smuzhiyun 
2409*4882a593Smuzhiyun             num_modifiers++;
2410*4882a593Smuzhiyun             tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
2411*4882a593Smuzhiyun             if (!tmp) {
2412*4882a593Smuzhiyun                 free(modifiers);
2413*4882a593Smuzhiyun                 drmModeFreePropertyBlob(blob);
2414*4882a593Smuzhiyun                 return FALSE;
2415*4882a593Smuzhiyun             }
2416*4882a593Smuzhiyun             modifiers = tmp;
2417*4882a593Smuzhiyun             modifiers[num_modifiers - 1] = mod->modifier;
2418*4882a593Smuzhiyun         }
2419*4882a593Smuzhiyun 
2420*4882a593Smuzhiyun         drmmode_crtc->formats[i].format = blob_formats[i];
2421*4882a593Smuzhiyun         drmmode_crtc->formats[i].modifiers = modifiers;
2422*4882a593Smuzhiyun         drmmode_crtc->formats[i].num_modifiers = num_modifiers;
2423*4882a593Smuzhiyun     }
2424*4882a593Smuzhiyun 
2425*4882a593Smuzhiyun     drmModeFreePropertyBlob(blob);
2426*4882a593Smuzhiyun 
2427*4882a593Smuzhiyun     return TRUE;
2428*4882a593Smuzhiyun }
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc,int num)2431*4882a593Smuzhiyun drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
2432*4882a593Smuzhiyun {
2433*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2434*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2435*4882a593Smuzhiyun     drmModePlaneRes *kplane_res;
2436*4882a593Smuzhiyun     drmModePlane *kplane, *best_kplane = NULL;
2437*4882a593Smuzhiyun     drmModeObjectProperties *props;
2438*4882a593Smuzhiyun     uint32_t i, type, blob_id;
2439*4882a593Smuzhiyun     int current_crtc, best_plane = 0;
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun     static drmmode_prop_enum_info_rec plane_type_enums[] = {
2442*4882a593Smuzhiyun         [DRMMODE_PLANE_TYPE_PRIMARY] = {
2443*4882a593Smuzhiyun             .name = "Primary",
2444*4882a593Smuzhiyun         },
2445*4882a593Smuzhiyun         [DRMMODE_PLANE_TYPE_OVERLAY] = {
2446*4882a593Smuzhiyun             .name = "Overlay",
2447*4882a593Smuzhiyun         },
2448*4882a593Smuzhiyun         [DRMMODE_PLANE_TYPE_CURSOR] = {
2449*4882a593Smuzhiyun             .name = "Cursor",
2450*4882a593Smuzhiyun         },
2451*4882a593Smuzhiyun     };
2452*4882a593Smuzhiyun     static const drmmode_prop_info_rec plane_props[] = {
2453*4882a593Smuzhiyun         [DRMMODE_PLANE_TYPE] = {
2454*4882a593Smuzhiyun             .name = "type",
2455*4882a593Smuzhiyun             .enum_values = plane_type_enums,
2456*4882a593Smuzhiyun             .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
2457*4882a593Smuzhiyun         },
2458*4882a593Smuzhiyun         [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
2459*4882a593Smuzhiyun         [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
2460*4882a593Smuzhiyun         [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
2461*4882a593Smuzhiyun         [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
2462*4882a593Smuzhiyun         [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
2463*4882a593Smuzhiyun         [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
2464*4882a593Smuzhiyun         [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
2465*4882a593Smuzhiyun         [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
2466*4882a593Smuzhiyun         [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
2467*4882a593Smuzhiyun         [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
2468*4882a593Smuzhiyun         [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
2469*4882a593Smuzhiyun     };
2470*4882a593Smuzhiyun     drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
2471*4882a593Smuzhiyun 
2472*4882a593Smuzhiyun     if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
2473*4882a593Smuzhiyun         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2474*4882a593Smuzhiyun                    "failed to copy plane property info\n");
2475*4882a593Smuzhiyun         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2476*4882a593Smuzhiyun         return;
2477*4882a593Smuzhiyun     }
2478*4882a593Smuzhiyun 
2479*4882a593Smuzhiyun     kplane_res = drmModeGetPlaneResources(drmmode->fd);
2480*4882a593Smuzhiyun     if (!kplane_res) {
2481*4882a593Smuzhiyun         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2482*4882a593Smuzhiyun                    "failed to get plane resources: %s\n", strerror(errno));
2483*4882a593Smuzhiyun         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2484*4882a593Smuzhiyun         return;
2485*4882a593Smuzhiyun     }
2486*4882a593Smuzhiyun 
2487*4882a593Smuzhiyun     for (i = 0; i < kplane_res->count_planes; i++) {
2488*4882a593Smuzhiyun         int plane_id;
2489*4882a593Smuzhiyun 
2490*4882a593Smuzhiyun         kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
2491*4882a593Smuzhiyun         if (!kplane)
2492*4882a593Smuzhiyun             continue;
2493*4882a593Smuzhiyun 
2494*4882a593Smuzhiyun         if (!(kplane->possible_crtcs & (1 << num)) ||
2495*4882a593Smuzhiyun             is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
2496*4882a593Smuzhiyun             drmModeFreePlane(kplane);
2497*4882a593Smuzhiyun             continue;
2498*4882a593Smuzhiyun         }
2499*4882a593Smuzhiyun 
2500*4882a593Smuzhiyun         plane_id = kplane->plane_id;
2501*4882a593Smuzhiyun 
2502*4882a593Smuzhiyun         props = drmModeObjectGetProperties(drmmode->fd, plane_id,
2503*4882a593Smuzhiyun                                            DRM_MODE_OBJECT_PLANE);
2504*4882a593Smuzhiyun         if (!props) {
2505*4882a593Smuzhiyun             xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2506*4882a593Smuzhiyun                     "couldn't get plane properties\n");
2507*4882a593Smuzhiyun             drmModeFreePlane(kplane);
2508*4882a593Smuzhiyun             continue;
2509*4882a593Smuzhiyun         }
2510*4882a593Smuzhiyun 
2511*4882a593Smuzhiyun         drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
2512*4882a593Smuzhiyun 
2513*4882a593Smuzhiyun         /* Only primary planes are important for atomic page-flipping */
2514*4882a593Smuzhiyun         type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
2515*4882a593Smuzhiyun                                       props, DRMMODE_PLANE_TYPE__COUNT);
2516*4882a593Smuzhiyun         if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
2517*4882a593Smuzhiyun             drmModeFreePlane(kplane);
2518*4882a593Smuzhiyun             drmModeFreeObjectProperties(props);
2519*4882a593Smuzhiyun             continue;
2520*4882a593Smuzhiyun         }
2521*4882a593Smuzhiyun 
2522*4882a593Smuzhiyun         /* Check if plane is already on this CRTC */
2523*4882a593Smuzhiyun         current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
2524*4882a593Smuzhiyun                                               props, 0);
2525*4882a593Smuzhiyun         if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
2526*4882a593Smuzhiyun             if (best_plane) {
2527*4882a593Smuzhiyun                 drmModeFreePlane(best_kplane);
2528*4882a593Smuzhiyun                 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2529*4882a593Smuzhiyun             }
2530*4882a593Smuzhiyun             best_plane = plane_id;
2531*4882a593Smuzhiyun             best_kplane = kplane;
2532*4882a593Smuzhiyun             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2533*4882a593Smuzhiyun                                              props, 0);
2534*4882a593Smuzhiyun             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2535*4882a593Smuzhiyun                                    DRMMODE_PLANE__COUNT, 1);
2536*4882a593Smuzhiyun             drmModeFreeObjectProperties(props);
2537*4882a593Smuzhiyun             break;
2538*4882a593Smuzhiyun         }
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun         if (!best_plane) {
2541*4882a593Smuzhiyun             best_plane = plane_id;
2542*4882a593Smuzhiyun             best_kplane = kplane;
2543*4882a593Smuzhiyun             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2544*4882a593Smuzhiyun                                              props, 0);
2545*4882a593Smuzhiyun             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2546*4882a593Smuzhiyun                                    DRMMODE_PLANE__COUNT, 1);
2547*4882a593Smuzhiyun         } else {
2548*4882a593Smuzhiyun             drmModeFreePlane(kplane);
2549*4882a593Smuzhiyun         }
2550*4882a593Smuzhiyun 
2551*4882a593Smuzhiyun         drmModeFreeObjectProperties(props);
2552*4882a593Smuzhiyun     }
2553*4882a593Smuzhiyun 
2554*4882a593Smuzhiyun     drmmode_crtc->plane_id = best_plane;
2555*4882a593Smuzhiyun     if (best_kplane) {
2556*4882a593Smuzhiyun         drmmode_crtc->num_formats = best_kplane->count_formats;
2557*4882a593Smuzhiyun         drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
2558*4882a593Smuzhiyun                                        best_kplane->count_formats);
2559*4882a593Smuzhiyun         if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
2560*4882a593Smuzhiyun             for (i = 0; i < best_kplane->count_formats; i++)
2561*4882a593Smuzhiyun                 drmmode_crtc->formats[i].format = best_kplane->formats[i];
2562*4882a593Smuzhiyun         }
2563*4882a593Smuzhiyun         drmModeFreePlane(best_kplane);
2564*4882a593Smuzhiyun     }
2565*4882a593Smuzhiyun 
2566*4882a593Smuzhiyun     drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2567*4882a593Smuzhiyun     drmModeFreePlaneResources(kplane_res);
2568*4882a593Smuzhiyun }
2569*4882a593Smuzhiyun 
2570*4882a593Smuzhiyun static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num)2571*4882a593Smuzhiyun drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
2572*4882a593Smuzhiyun {
2573*4882a593Smuzhiyun     xf86CrtcPtr crtc;
2574*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc;
2575*4882a593Smuzhiyun     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2576*4882a593Smuzhiyun     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
2577*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(pScrn);
2578*4882a593Smuzhiyun     drmModeObjectPropertiesPtr props;
2579*4882a593Smuzhiyun     static const drmmode_prop_info_rec crtc_props[] = {
2580*4882a593Smuzhiyun         [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
2581*4882a593Smuzhiyun         [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
2582*4882a593Smuzhiyun         [DRMMODE_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT" },
2583*4882a593Smuzhiyun         [DRMMODE_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE" },
2584*4882a593Smuzhiyun     };
2585*4882a593Smuzhiyun     int o, found = 0;
2586*4882a593Smuzhiyun 
2587*4882a593Smuzhiyun     /* only init possible crtcs for the outputs */
2588*4882a593Smuzhiyun     for (o = 0; o < config->num_output; o++) {
2589*4882a593Smuzhiyun         xf86OutputPtr output = config->output[o];
2590*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output = output->driver_private;
2591*4882a593Smuzhiyun 
2592*4882a593Smuzhiyun         if (drmmode_output->possible_crtcs & (1 << num)) {
2593*4882a593Smuzhiyun             output->possible_crtcs |= 1 << config->num_crtc;
2594*4882a593Smuzhiyun             found = 1;
2595*4882a593Smuzhiyun         }
2596*4882a593Smuzhiyun     }
2597*4882a593Smuzhiyun 
2598*4882a593Smuzhiyun     if (!found)
2599*4882a593Smuzhiyun         return 0;
2600*4882a593Smuzhiyun 
2601*4882a593Smuzhiyun     crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
2602*4882a593Smuzhiyun     if (crtc == NULL)
2603*4882a593Smuzhiyun         return 0;
2604*4882a593Smuzhiyun     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
2605*4882a593Smuzhiyun     crtc->driver_private = drmmode_crtc;
2606*4882a593Smuzhiyun     drmmode_crtc->mode_crtc =
2607*4882a593Smuzhiyun         drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
2608*4882a593Smuzhiyun     drmmode_crtc->drmmode = drmmode;
2609*4882a593Smuzhiyun     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
2610*4882a593Smuzhiyun     xorg_list_init(&drmmode_crtc->mode_list);
2611*4882a593Smuzhiyun 
2612*4882a593Smuzhiyun     if (drmmode->fb_flip_mode == DRMMODE_FB_FLIP_NONE)
2613*4882a593Smuzhiyun         drmmode_crtc->can_flip_fb = FALSE;
2614*4882a593Smuzhiyun     else
2615*4882a593Smuzhiyun         drmmode_crtc->can_flip_fb = TRUE;
2616*4882a593Smuzhiyun 
2617*4882a593Smuzhiyun     if (1 || ms->atomic_modeset) {
2618*4882a593Smuzhiyun         props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
2619*4882a593Smuzhiyun                                            DRM_MODE_OBJECT_CRTC);
2620*4882a593Smuzhiyun         if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
2621*4882a593Smuzhiyun                                               DRMMODE_CRTC__COUNT, 0)) {
2622*4882a593Smuzhiyun             xf86CrtcDestroy(crtc);
2623*4882a593Smuzhiyun             return 0;
2624*4882a593Smuzhiyun         }
2625*4882a593Smuzhiyun 
2626*4882a593Smuzhiyun         drmmode_prop_info_update(drmmode, drmmode_crtc->props,
2627*4882a593Smuzhiyun                                  DRMMODE_CRTC__COUNT, props);
2628*4882a593Smuzhiyun         drmModeFreeObjectProperties(props);
2629*4882a593Smuzhiyun         drmmode_crtc_create_planes(crtc, num);
2630*4882a593Smuzhiyun     }
2631*4882a593Smuzhiyun 
2632*4882a593Smuzhiyun     /* Hide any cursors which may be active from previous users */
2633*4882a593Smuzhiyun     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
2634*4882a593Smuzhiyun 
2635*4882a593Smuzhiyun     /* Mark num'th crtc as in use on this device. */
2636*4882a593Smuzhiyun     ms_ent->assigned_crtcs |= (1 << num);
2637*4882a593Smuzhiyun     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
2638*4882a593Smuzhiyun                    "Allocated crtc nr. %d to this screen.\n", num);
2639*4882a593Smuzhiyun 
2640*4882a593Smuzhiyun     drmmode_crtc->use_gamma_lut =
2641*4882a593Smuzhiyun         drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id &&
2642*4882a593Smuzhiyun         drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value &&
2643*4882a593Smuzhiyun         xf86ReturnOptValBool(drmmode->Options, OPTION_USE_GAMMA_LUT, TRUE);
2644*4882a593Smuzhiyun 
2645*4882a593Smuzhiyun     return 1;
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun 
2648*4882a593Smuzhiyun /*
2649*4882a593Smuzhiyun  * Update all of the property values for an output
2650*4882a593Smuzhiyun  */
2651*4882a593Smuzhiyun static void
drmmode_output_update_properties(xf86OutputPtr output)2652*4882a593Smuzhiyun drmmode_output_update_properties(xf86OutputPtr output)
2653*4882a593Smuzhiyun {
2654*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2655*4882a593Smuzhiyun     int i, j, k;
2656*4882a593Smuzhiyun     int err;
2657*4882a593Smuzhiyun     drmModeConnectorPtr koutput;
2658*4882a593Smuzhiyun 
2659*4882a593Smuzhiyun     /* Use the most recently fetched values from the kernel */
2660*4882a593Smuzhiyun     koutput = drmmode_output->mode_output;
2661*4882a593Smuzhiyun 
2662*4882a593Smuzhiyun     if (!koutput)
2663*4882a593Smuzhiyun         return;
2664*4882a593Smuzhiyun 
2665*4882a593Smuzhiyun     for (i = 0; i < drmmode_output->num_props; i++) {
2666*4882a593Smuzhiyun         drmmode_prop_ptr p = &drmmode_output->props[i];
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun         for (j = 0; koutput && j < koutput->count_props; j++) {
2669*4882a593Smuzhiyun             if (koutput->props[j] == p->mode_prop->prop_id) {
2670*4882a593Smuzhiyun 
2671*4882a593Smuzhiyun                 /* Check to see if the property value has changed */
2672*4882a593Smuzhiyun                 if (koutput->prop_values[j] != p->value) {
2673*4882a593Smuzhiyun 
2674*4882a593Smuzhiyun                     p->value = koutput->prop_values[j];
2675*4882a593Smuzhiyun 
2676*4882a593Smuzhiyun                     if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2677*4882a593Smuzhiyun                         INT32 value = p->value;
2678*4882a593Smuzhiyun 
2679*4882a593Smuzhiyun                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2680*4882a593Smuzhiyun                                                      XA_INTEGER, 32, PropModeReplace, 1,
2681*4882a593Smuzhiyun                                                      &value, FALSE, TRUE);
2682*4882a593Smuzhiyun 
2683*4882a593Smuzhiyun                         if (err != 0) {
2684*4882a593Smuzhiyun                             xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2685*4882a593Smuzhiyun                                        "RRChangeOutputProperty error, %d\n", err);
2686*4882a593Smuzhiyun                         }
2687*4882a593Smuzhiyun                     }
2688*4882a593Smuzhiyun                     else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2689*4882a593Smuzhiyun                         for (k = 0; k < p->mode_prop->count_enums; k++)
2690*4882a593Smuzhiyun                             if (p->mode_prop->enums[k].value == p->value)
2691*4882a593Smuzhiyun                                 break;
2692*4882a593Smuzhiyun                         if (k < p->mode_prop->count_enums) {
2693*4882a593Smuzhiyun                             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2694*4882a593Smuzhiyun                                                          XA_ATOM, 32, PropModeReplace, 1,
2695*4882a593Smuzhiyun                                                          &p->atoms[k + 1], FALSE, TRUE);
2696*4882a593Smuzhiyun                             if (err != 0) {
2697*4882a593Smuzhiyun                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2698*4882a593Smuzhiyun                                            "RRChangeOutputProperty error, %d\n", err);
2699*4882a593Smuzhiyun                             }
2700*4882a593Smuzhiyun                         }
2701*4882a593Smuzhiyun                     }
2702*4882a593Smuzhiyun                 }
2703*4882a593Smuzhiyun                 break;
2704*4882a593Smuzhiyun             }
2705*4882a593Smuzhiyun         }
2706*4882a593Smuzhiyun     }
2707*4882a593Smuzhiyun }
2708*4882a593Smuzhiyun 
2709*4882a593Smuzhiyun static void
drmmode_output_change_status(xf86OutputPtr output,xf86OutputStatus status)2710*4882a593Smuzhiyun drmmode_output_change_status(xf86OutputPtr output, xf86OutputStatus status)
2711*4882a593Smuzhiyun {
2712*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2713*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
2714*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc;
2715*4882a593Smuzhiyun     ScrnInfoPtr scrn = drmmode->scrn;
2716*4882a593Smuzhiyun     xf86CrtcPtr crtc = output->crtc;
2717*4882a593Smuzhiyun     Bool connected;
2718*4882a593Smuzhiyun 
2719*4882a593Smuzhiyun     if (drmmode_output->status == status)
2720*4882a593Smuzhiyun         return;
2721*4882a593Smuzhiyun 
2722*4882a593Smuzhiyun     drmmode_output->status = status;
2723*4882a593Smuzhiyun     connected = status == XF86OutputStatusConnected;
2724*4882a593Smuzhiyun 
2725*4882a593Smuzhiyun     xf86DrvMsg(scrn->scrnIndex, X_INFO,
2726*4882a593Smuzhiyun                "Output %s status changed to %s.\n", output->name,
2727*4882a593Smuzhiyun                connected ? "connected" : "disconnected");
2728*4882a593Smuzhiyun 
2729*4882a593Smuzhiyun     if (!crtc)
2730*4882a593Smuzhiyun         return;
2731*4882a593Smuzhiyun 
2732*4882a593Smuzhiyun     drmmode_crtc = crtc->driver_private;
2733*4882a593Smuzhiyun 
2734*4882a593Smuzhiyun     if (!connected) {
2735*4882a593Smuzhiyun         if (drmmode->hotplug_reset && !drmmode_crtc_connected(crtc)) {
2736*4882a593Smuzhiyun             drmmode_crtc->need_modeset = TRUE;
2737*4882a593Smuzhiyun 
2738*4882a593Smuzhiyun             drmModeSetCrtc(drmmode->fd,
2739*4882a593Smuzhiyun                            drmmode_crtc->mode_crtc->crtc_id,
2740*4882a593Smuzhiyun                            0, 0, 0, NULL, 0, NULL);
2741*4882a593Smuzhiyun         }
2742*4882a593Smuzhiyun     } else if (drmmode_crtc->need_modeset) {
2743*4882a593Smuzhiyun         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2744*4882a593Smuzhiyun                                crtc->x, crtc->y);
2745*4882a593Smuzhiyun     }
2746*4882a593Smuzhiyun }
2747*4882a593Smuzhiyun 
2748*4882a593Smuzhiyun static xf86OutputStatus
drmmode_output_detect(xf86OutputPtr output)2749*4882a593Smuzhiyun drmmode_output_detect(xf86OutputPtr output)
2750*4882a593Smuzhiyun {
2751*4882a593Smuzhiyun     /* go to the hw and retrieve a new output struct */
2752*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2753*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
2754*4882a593Smuzhiyun     xf86OutputStatus status;
2755*4882a593Smuzhiyun 
2756*4882a593Smuzhiyun     if (drmmode_output->output_id == -1)
2757*4882a593Smuzhiyun         return XF86OutputStatusDisconnected;
2758*4882a593Smuzhiyun 
2759*4882a593Smuzhiyun     drmModeFreeConnector(drmmode_output->mode_output);
2760*4882a593Smuzhiyun 
2761*4882a593Smuzhiyun     drmmode_output->mode_output =
2762*4882a593Smuzhiyun         drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
2763*4882a593Smuzhiyun 
2764*4882a593Smuzhiyun     if (!drmmode_output->mode_output) {
2765*4882a593Smuzhiyun         drmmode_output->output_id = -1;
2766*4882a593Smuzhiyun         return XF86OutputStatusDisconnected;
2767*4882a593Smuzhiyun     }
2768*4882a593Smuzhiyun 
2769*4882a593Smuzhiyun     drmmode_output_update_properties(output);
2770*4882a593Smuzhiyun 
2771*4882a593Smuzhiyun     switch (drmmode_output->mode_output->connection) {
2772*4882a593Smuzhiyun     case DRM_MODE_CONNECTED:
2773*4882a593Smuzhiyun         status = XF86OutputStatusConnected;
2774*4882a593Smuzhiyun         break;
2775*4882a593Smuzhiyun     case DRM_MODE_DISCONNECTED:
2776*4882a593Smuzhiyun         status = XF86OutputStatusDisconnected;
2777*4882a593Smuzhiyun         break;
2778*4882a593Smuzhiyun     default:
2779*4882a593Smuzhiyun     case DRM_MODE_UNKNOWNCONNECTION:
2780*4882a593Smuzhiyun         status = XF86OutputStatusUnknown;
2781*4882a593Smuzhiyun         break;
2782*4882a593Smuzhiyun     }
2783*4882a593Smuzhiyun 
2784*4882a593Smuzhiyun     drmmode_output_change_status(output, status);
2785*4882a593Smuzhiyun     return status;
2786*4882a593Smuzhiyun }
2787*4882a593Smuzhiyun 
2788*4882a593Smuzhiyun static Bool
drmmode_output_mode_valid(xf86OutputPtr output,DisplayModePtr pModes)2789*4882a593Smuzhiyun drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
2790*4882a593Smuzhiyun {
2791*4882a593Smuzhiyun     return MODE_OK;
2792*4882a593Smuzhiyun }
2793*4882a593Smuzhiyun 
2794*4882a593Smuzhiyun static int
koutput_get_prop_idx(int fd,drmModeConnectorPtr koutput,int type,const char * name)2795*4882a593Smuzhiyun koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
2796*4882a593Smuzhiyun         int type, const char *name)
2797*4882a593Smuzhiyun {
2798*4882a593Smuzhiyun     int idx = -1;
2799*4882a593Smuzhiyun 
2800*4882a593Smuzhiyun     for (int i = 0; i < koutput->count_props; i++) {
2801*4882a593Smuzhiyun         drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
2802*4882a593Smuzhiyun 
2803*4882a593Smuzhiyun         if (!prop)
2804*4882a593Smuzhiyun             continue;
2805*4882a593Smuzhiyun 
2806*4882a593Smuzhiyun         if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
2807*4882a593Smuzhiyun             idx = i;
2808*4882a593Smuzhiyun 
2809*4882a593Smuzhiyun         drmModeFreeProperty(prop);
2810*4882a593Smuzhiyun 
2811*4882a593Smuzhiyun         if (idx > -1)
2812*4882a593Smuzhiyun             break;
2813*4882a593Smuzhiyun     }
2814*4882a593Smuzhiyun 
2815*4882a593Smuzhiyun     return idx;
2816*4882a593Smuzhiyun }
2817*4882a593Smuzhiyun 
2818*4882a593Smuzhiyun static int
koutput_get_prop_id(int fd,drmModeConnectorPtr koutput,int type,const char * name)2819*4882a593Smuzhiyun koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
2820*4882a593Smuzhiyun         int type, const char *name)
2821*4882a593Smuzhiyun {
2822*4882a593Smuzhiyun     int idx = koutput_get_prop_idx(fd, koutput, type, name);
2823*4882a593Smuzhiyun 
2824*4882a593Smuzhiyun     return (idx > -1) ? koutput->props[idx] : -1;
2825*4882a593Smuzhiyun }
2826*4882a593Smuzhiyun 
2827*4882a593Smuzhiyun static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd,drmModeConnectorPtr koutput,const char * name)2828*4882a593Smuzhiyun koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
2829*4882a593Smuzhiyun {
2830*4882a593Smuzhiyun     drmModePropertyBlobPtr blob = NULL;
2831*4882a593Smuzhiyun     int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
2832*4882a593Smuzhiyun 
2833*4882a593Smuzhiyun     if (idx > -1)
2834*4882a593Smuzhiyun         blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
2835*4882a593Smuzhiyun 
2836*4882a593Smuzhiyun     return blob;
2837*4882a593Smuzhiyun }
2838*4882a593Smuzhiyun 
2839*4882a593Smuzhiyun static void
drmmode_output_attach_tile(xf86OutputPtr output)2840*4882a593Smuzhiyun drmmode_output_attach_tile(xf86OutputPtr output)
2841*4882a593Smuzhiyun {
2842*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2843*4882a593Smuzhiyun     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2844*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
2845*4882a593Smuzhiyun     struct xf86CrtcTileInfo tile_info, *set = NULL;
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun     if (!koutput) {
2848*4882a593Smuzhiyun         xf86OutputSetTile(output, NULL);
2849*4882a593Smuzhiyun         return;
2850*4882a593Smuzhiyun     }
2851*4882a593Smuzhiyun 
2852*4882a593Smuzhiyun     drmModeFreePropertyBlob(drmmode_output->tile_blob);
2853*4882a593Smuzhiyun 
2854*4882a593Smuzhiyun     /* look for a TILE property */
2855*4882a593Smuzhiyun     drmmode_output->tile_blob =
2856*4882a593Smuzhiyun         koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
2857*4882a593Smuzhiyun 
2858*4882a593Smuzhiyun     if (drmmode_output->tile_blob) {
2859*4882a593Smuzhiyun         if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
2860*4882a593Smuzhiyun             set = &tile_info;
2861*4882a593Smuzhiyun     }
2862*4882a593Smuzhiyun     xf86OutputSetTile(output, set);
2863*4882a593Smuzhiyun }
2864*4882a593Smuzhiyun 
2865*4882a593Smuzhiyun static Bool
has_panel_fitter(xf86OutputPtr output)2866*4882a593Smuzhiyun has_panel_fitter(xf86OutputPtr output)
2867*4882a593Smuzhiyun {
2868*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2869*4882a593Smuzhiyun     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2870*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
2871*4882a593Smuzhiyun     int idx;
2872*4882a593Smuzhiyun 
2873*4882a593Smuzhiyun     /* Presume that if the output supports scaling, then we have a
2874*4882a593Smuzhiyun      * panel fitter capable of adjust any mode to suit.
2875*4882a593Smuzhiyun      */
2876*4882a593Smuzhiyun     idx = koutput_get_prop_idx(drmmode->fd, koutput,
2877*4882a593Smuzhiyun             DRM_MODE_PROP_ENUM, "scaling mode");
2878*4882a593Smuzhiyun 
2879*4882a593Smuzhiyun     return (idx > -1);
2880*4882a593Smuzhiyun }
2881*4882a593Smuzhiyun 
2882*4882a593Smuzhiyun static DisplayModePtr
drmmode_output_add_gtf_modes(xf86OutputPtr output,DisplayModePtr Modes)2883*4882a593Smuzhiyun drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
2884*4882a593Smuzhiyun {
2885*4882a593Smuzhiyun     xf86MonPtr mon = output->MonInfo;
2886*4882a593Smuzhiyun     DisplayModePtr i, m, preferred = NULL;
2887*4882a593Smuzhiyun     int max_x = 0, max_y = 0;
2888*4882a593Smuzhiyun     float max_vrefresh = 0.0;
2889*4882a593Smuzhiyun 
2890*4882a593Smuzhiyun     if (mon && gtf_supported(mon))
2891*4882a593Smuzhiyun         return Modes;
2892*4882a593Smuzhiyun 
2893*4882a593Smuzhiyun     if (!has_panel_fitter(output))
2894*4882a593Smuzhiyun         return Modes;
2895*4882a593Smuzhiyun 
2896*4882a593Smuzhiyun     for (m = Modes; m; m = m->next) {
2897*4882a593Smuzhiyun         if (m->type & M_T_PREFERRED)
2898*4882a593Smuzhiyun             preferred = m;
2899*4882a593Smuzhiyun         max_x = max(max_x, m->HDisplay);
2900*4882a593Smuzhiyun         max_y = max(max_y, m->VDisplay);
2901*4882a593Smuzhiyun         max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
2902*4882a593Smuzhiyun     }
2903*4882a593Smuzhiyun 
2904*4882a593Smuzhiyun     max_vrefresh = max(max_vrefresh, 60.0);
2905*4882a593Smuzhiyun     max_vrefresh *= (1 + SYNC_TOLERANCE);
2906*4882a593Smuzhiyun 
2907*4882a593Smuzhiyun     m = xf86GetDefaultModes();
2908*4882a593Smuzhiyun     xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
2909*4882a593Smuzhiyun 
2910*4882a593Smuzhiyun     for (i = m; i; i = i->next) {
2911*4882a593Smuzhiyun         if (xf86ModeVRefresh(i) > max_vrefresh)
2912*4882a593Smuzhiyun             i->status = MODE_VSYNC;
2913*4882a593Smuzhiyun         if (preferred &&
2914*4882a593Smuzhiyun             i->HDisplay >= preferred->HDisplay &&
2915*4882a593Smuzhiyun             i->VDisplay >= preferred->VDisplay &&
2916*4882a593Smuzhiyun             xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
2917*4882a593Smuzhiyun             i->status = MODE_VSYNC;
2918*4882a593Smuzhiyun     }
2919*4882a593Smuzhiyun 
2920*4882a593Smuzhiyun     xf86PruneInvalidModes(output->scrn, &m, FALSE);
2921*4882a593Smuzhiyun 
2922*4882a593Smuzhiyun     return xf86ModesAdd(Modes, m);
2923*4882a593Smuzhiyun }
2924*4882a593Smuzhiyun 
2925*4882a593Smuzhiyun static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)2926*4882a593Smuzhiyun drmmode_output_get_modes(xf86OutputPtr output)
2927*4882a593Smuzhiyun {
2928*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2929*4882a593Smuzhiyun     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2930*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
2931*4882a593Smuzhiyun     int i;
2932*4882a593Smuzhiyun     DisplayModePtr Modes = NULL, Mode;
2933*4882a593Smuzhiyun     xf86MonPtr mon = NULL;
2934*4882a593Smuzhiyun 
2935*4882a593Smuzhiyun     if (!koutput)
2936*4882a593Smuzhiyun         return NULL;
2937*4882a593Smuzhiyun 
2938*4882a593Smuzhiyun     drmModeFreePropertyBlob(drmmode_output->edid_blob);
2939*4882a593Smuzhiyun 
2940*4882a593Smuzhiyun     /* look for an EDID property */
2941*4882a593Smuzhiyun     drmmode_output->edid_blob =
2942*4882a593Smuzhiyun         koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
2943*4882a593Smuzhiyun 
2944*4882a593Smuzhiyun     if (!xf86ReturnOptValBool(drmmode->Options, OPTION_NO_EDID, FALSE) &&
2945*4882a593Smuzhiyun         drmmode_output->edid_blob) {
2946*4882a593Smuzhiyun         mon = xf86InterpretEDID(output->scrn->scrnIndex,
2947*4882a593Smuzhiyun                                 drmmode_output->edid_blob->data);
2948*4882a593Smuzhiyun         if (mon && drmmode_output->edid_blob->length > 128)
2949*4882a593Smuzhiyun             mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
2950*4882a593Smuzhiyun     }
2951*4882a593Smuzhiyun     xf86OutputSetEDID(output, mon);
2952*4882a593Smuzhiyun 
2953*4882a593Smuzhiyun     drmmode_output_attach_tile(output);
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun     /* modes should already be available */
2956*4882a593Smuzhiyun     for (i = 0; i < koutput->count_modes; i++) {
2957*4882a593Smuzhiyun         Mode = xnfalloc(sizeof(DisplayModeRec));
2958*4882a593Smuzhiyun 
2959*4882a593Smuzhiyun         drmmode_ConvertFromKMode(output, &koutput->modes[i], Mode);
2960*4882a593Smuzhiyun         Modes = xf86ModesAdd(Modes, Mode);
2961*4882a593Smuzhiyun 
2962*4882a593Smuzhiyun     }
2963*4882a593Smuzhiyun 
2964*4882a593Smuzhiyun     return drmmode_output_add_gtf_modes(output, Modes);
2965*4882a593Smuzhiyun }
2966*4882a593Smuzhiyun 
2967*4882a593Smuzhiyun static void
drmmode_output_destroy(xf86OutputPtr output)2968*4882a593Smuzhiyun drmmode_output_destroy(xf86OutputPtr output)
2969*4882a593Smuzhiyun {
2970*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2971*4882a593Smuzhiyun     int i;
2972*4882a593Smuzhiyun 
2973*4882a593Smuzhiyun     drmModeFreePropertyBlob(drmmode_output->edid_blob);
2974*4882a593Smuzhiyun     drmModeFreePropertyBlob(drmmode_output->tile_blob);
2975*4882a593Smuzhiyun 
2976*4882a593Smuzhiyun     for (i = 0; i < drmmode_output->num_props; i++) {
2977*4882a593Smuzhiyun         drmModeFreeProperty(drmmode_output->props[i].mode_prop);
2978*4882a593Smuzhiyun         free(drmmode_output->props[i].atoms);
2979*4882a593Smuzhiyun     }
2980*4882a593Smuzhiyun     free(drmmode_output->props);
2981*4882a593Smuzhiyun     if (drmmode_output->mode_output) {
2982*4882a593Smuzhiyun         for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
2983*4882a593Smuzhiyun             drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
2984*4882a593Smuzhiyun         }
2985*4882a593Smuzhiyun         drmModeFreeConnector(drmmode_output->mode_output);
2986*4882a593Smuzhiyun     }
2987*4882a593Smuzhiyun     free(drmmode_output->mode_encoders);
2988*4882a593Smuzhiyun     free(drmmode_output);
2989*4882a593Smuzhiyun     output->driver_private = NULL;
2990*4882a593Smuzhiyun }
2991*4882a593Smuzhiyun 
2992*4882a593Smuzhiyun static void
drmmode_output_dpms(xf86OutputPtr output,int mode)2993*4882a593Smuzhiyun drmmode_output_dpms(xf86OutputPtr output, int mode)
2994*4882a593Smuzhiyun {
2995*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(output->scrn);
2996*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
2997*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
2998*4882a593Smuzhiyun     xf86CrtcPtr crtc = output->crtc;
2999*4882a593Smuzhiyun     drmModeConnectorPtr koutput = drmmode_output->mode_output;
3000*4882a593Smuzhiyun 
3001*4882a593Smuzhiyun     if (!koutput)
3002*4882a593Smuzhiyun         return;
3003*4882a593Smuzhiyun 
3004*4882a593Smuzhiyun     /* XXX Check if DPMS mode is already the right one */
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun     drmmode_output->dpms = mode;
3007*4882a593Smuzhiyun 
3008*4882a593Smuzhiyun     if (ms->atomic_modeset) {
3009*4882a593Smuzhiyun         if (!ms->pending_modeset)
3010*4882a593Smuzhiyun             drmmode_output_dpms_atomic(output, mode);
3011*4882a593Smuzhiyun     } else {
3012*4882a593Smuzhiyun         drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
3013*4882a593Smuzhiyun                                     drmmode_output->dpms_enum_id, mode);
3014*4882a593Smuzhiyun     }
3015*4882a593Smuzhiyun 
3016*4882a593Smuzhiyun     if (crtc) {
3017*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3018*4882a593Smuzhiyun 
3019*4882a593Smuzhiyun         if (mode == DPMSModeOn) {
3020*4882a593Smuzhiyun             if (drmmode_crtc->need_modeset)
3021*4882a593Smuzhiyun                 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3022*4882a593Smuzhiyun                                        crtc->x, crtc->y);
3023*4882a593Smuzhiyun 
3024*4882a593Smuzhiyun             if (drmmode_crtc->enable_flipping)
3025*4882a593Smuzhiyun                 drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
3026*4882a593Smuzhiyun         } else {
3027*4882a593Smuzhiyun             if (drmmode_crtc->enable_flipping)
3028*4882a593Smuzhiyun                 drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
3029*4882a593Smuzhiyun         }
3030*4882a593Smuzhiyun     }
3031*4882a593Smuzhiyun 
3032*4882a593Smuzhiyun     return;
3033*4882a593Smuzhiyun }
3034*4882a593Smuzhiyun 
3035*4882a593Smuzhiyun static Bool
drmmode_property_ignore(drmModePropertyPtr prop)3036*4882a593Smuzhiyun drmmode_property_ignore(drmModePropertyPtr prop)
3037*4882a593Smuzhiyun {
3038*4882a593Smuzhiyun     if (!prop)
3039*4882a593Smuzhiyun         return TRUE;
3040*4882a593Smuzhiyun     /* ignore blob prop */
3041*4882a593Smuzhiyun     if (prop->flags & DRM_MODE_PROP_BLOB)
3042*4882a593Smuzhiyun         return TRUE;
3043*4882a593Smuzhiyun     /* ignore standard property */
3044*4882a593Smuzhiyun     if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
3045*4882a593Smuzhiyun         !strcmp(prop->name, "CRTC_ID"))
3046*4882a593Smuzhiyun         return TRUE;
3047*4882a593Smuzhiyun 
3048*4882a593Smuzhiyun     return FALSE;
3049*4882a593Smuzhiyun }
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun static void
drmmode_output_create_resources(xf86OutputPtr output)3052*4882a593Smuzhiyun drmmode_output_create_resources(xf86OutputPtr output)
3053*4882a593Smuzhiyun {
3054*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
3055*4882a593Smuzhiyun     drmModeConnectorPtr mode_output = drmmode_output->mode_output;
3056*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
3057*4882a593Smuzhiyun     drmModePropertyPtr drmmode_prop;
3058*4882a593Smuzhiyun     int i, j, err;
3059*4882a593Smuzhiyun 
3060*4882a593Smuzhiyun     /* already created */
3061*4882a593Smuzhiyun     if (drmmode_output->props)
3062*4882a593Smuzhiyun         return;
3063*4882a593Smuzhiyun 
3064*4882a593Smuzhiyun     drmmode_output->props =
3065*4882a593Smuzhiyun         calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
3066*4882a593Smuzhiyun     if (!drmmode_output->props)
3067*4882a593Smuzhiyun         return;
3068*4882a593Smuzhiyun 
3069*4882a593Smuzhiyun     drmmode_output->num_props = 0;
3070*4882a593Smuzhiyun     for (i = 0, j = 0; i < mode_output->count_props; i++) {
3071*4882a593Smuzhiyun         drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
3072*4882a593Smuzhiyun         if (drmmode_property_ignore(drmmode_prop)) {
3073*4882a593Smuzhiyun             drmModeFreeProperty(drmmode_prop);
3074*4882a593Smuzhiyun             continue;
3075*4882a593Smuzhiyun         }
3076*4882a593Smuzhiyun         drmmode_output->props[j].mode_prop = drmmode_prop;
3077*4882a593Smuzhiyun         drmmode_output->props[j].value = mode_output->prop_values[i];
3078*4882a593Smuzhiyun         drmmode_output->num_props++;
3079*4882a593Smuzhiyun         j++;
3080*4882a593Smuzhiyun     }
3081*4882a593Smuzhiyun 
3082*4882a593Smuzhiyun     /* Create CONNECTOR_ID property */
3083*4882a593Smuzhiyun     {
3084*4882a593Smuzhiyun         Atom    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
3085*4882a593Smuzhiyun         INT32   value = mode_output->connector_id;
3086*4882a593Smuzhiyun 
3087*4882a593Smuzhiyun         if (name != BAD_RESOURCE) {
3088*4882a593Smuzhiyun             err = RRConfigureOutputProperty(output->randr_output, name,
3089*4882a593Smuzhiyun                                             FALSE, FALSE, TRUE,
3090*4882a593Smuzhiyun                                             1, &value);
3091*4882a593Smuzhiyun             if (err != 0) {
3092*4882a593Smuzhiyun                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3093*4882a593Smuzhiyun                            "RRConfigureOutputProperty error, %d\n", err);
3094*4882a593Smuzhiyun             }
3095*4882a593Smuzhiyun             err = RRChangeOutputProperty(output->randr_output, name,
3096*4882a593Smuzhiyun                                          XA_INTEGER, 32, PropModeReplace, 1,
3097*4882a593Smuzhiyun                                          &value, FALSE, FALSE);
3098*4882a593Smuzhiyun             if (err != 0) {
3099*4882a593Smuzhiyun                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3100*4882a593Smuzhiyun                            "RRChangeOutputProperty error, %d\n", err);
3101*4882a593Smuzhiyun             }
3102*4882a593Smuzhiyun         }
3103*4882a593Smuzhiyun     }
3104*4882a593Smuzhiyun 
3105*4882a593Smuzhiyun     for (i = 0; i < drmmode_output->num_props; i++) {
3106*4882a593Smuzhiyun         drmmode_prop_ptr p = &drmmode_output->props[i];
3107*4882a593Smuzhiyun 
3108*4882a593Smuzhiyun         drmmode_prop = p->mode_prop;
3109*4882a593Smuzhiyun 
3110*4882a593Smuzhiyun         if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
3111*4882a593Smuzhiyun             INT32 prop_range[2];
3112*4882a593Smuzhiyun             INT32 value = p->value;
3113*4882a593Smuzhiyun 
3114*4882a593Smuzhiyun             p->num_atoms = 1;
3115*4882a593Smuzhiyun             p->atoms = calloc(p->num_atoms, sizeof(Atom));
3116*4882a593Smuzhiyun             if (!p->atoms)
3117*4882a593Smuzhiyun                 continue;
3118*4882a593Smuzhiyun             p->atoms[0] =
3119*4882a593Smuzhiyun                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
3120*4882a593Smuzhiyun             prop_range[0] = drmmode_prop->values[0];
3121*4882a593Smuzhiyun             prop_range[1] = drmmode_prop->values[1];
3122*4882a593Smuzhiyun             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
3123*4882a593Smuzhiyun                                             FALSE, TRUE,
3124*4882a593Smuzhiyun                                             drmmode_prop->
3125*4882a593Smuzhiyun                                             flags & DRM_MODE_PROP_IMMUTABLE ?
3126*4882a593Smuzhiyun                                             TRUE : FALSE, 2, prop_range);
3127*4882a593Smuzhiyun             if (err != 0) {
3128*4882a593Smuzhiyun                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3129*4882a593Smuzhiyun                            "RRConfigureOutputProperty error, %d\n", err);
3130*4882a593Smuzhiyun             }
3131*4882a593Smuzhiyun             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
3132*4882a593Smuzhiyun                                          XA_INTEGER, 32, PropModeReplace, 1,
3133*4882a593Smuzhiyun                                          &value, FALSE, TRUE);
3134*4882a593Smuzhiyun             if (err != 0) {
3135*4882a593Smuzhiyun                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3136*4882a593Smuzhiyun                            "RRChangeOutputProperty error, %d\n", err);
3137*4882a593Smuzhiyun             }
3138*4882a593Smuzhiyun         }
3139*4882a593Smuzhiyun         else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
3140*4882a593Smuzhiyun             p->num_atoms = drmmode_prop->count_enums + 1;
3141*4882a593Smuzhiyun             p->atoms = calloc(p->num_atoms, sizeof(Atom));
3142*4882a593Smuzhiyun             if (!p->atoms)
3143*4882a593Smuzhiyun                 continue;
3144*4882a593Smuzhiyun             p->atoms[0] =
3145*4882a593Smuzhiyun                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
3146*4882a593Smuzhiyun             for (j = 1; j <= drmmode_prop->count_enums; j++) {
3147*4882a593Smuzhiyun                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
3148*4882a593Smuzhiyun 
3149*4882a593Smuzhiyun                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
3150*4882a593Smuzhiyun             }
3151*4882a593Smuzhiyun             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
3152*4882a593Smuzhiyun                                             FALSE, FALSE,
3153*4882a593Smuzhiyun                                             drmmode_prop->
3154*4882a593Smuzhiyun                                             flags & DRM_MODE_PROP_IMMUTABLE ?
3155*4882a593Smuzhiyun                                             TRUE : FALSE, p->num_atoms - 1,
3156*4882a593Smuzhiyun                                             (INT32 *) &p->atoms[1]);
3157*4882a593Smuzhiyun             if (err != 0) {
3158*4882a593Smuzhiyun                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3159*4882a593Smuzhiyun                            "RRConfigureOutputProperty error, %d\n", err);
3160*4882a593Smuzhiyun             }
3161*4882a593Smuzhiyun             for (j = 0; j < drmmode_prop->count_enums; j++)
3162*4882a593Smuzhiyun                 if (drmmode_prop->enums[j].value == p->value)
3163*4882a593Smuzhiyun                     break;
3164*4882a593Smuzhiyun             /* there's always a matching value */
3165*4882a593Smuzhiyun             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
3166*4882a593Smuzhiyun                                          XA_ATOM, 32, PropModeReplace, 1,
3167*4882a593Smuzhiyun                                          &p->atoms[j + 1], FALSE, TRUE);
3168*4882a593Smuzhiyun             if (err != 0) {
3169*4882a593Smuzhiyun                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3170*4882a593Smuzhiyun                            "RRChangeOutputProperty error, %d\n", err);
3171*4882a593Smuzhiyun             }
3172*4882a593Smuzhiyun         }
3173*4882a593Smuzhiyun     }
3174*4882a593Smuzhiyun }
3175*4882a593Smuzhiyun 
3176*4882a593Smuzhiyun static Bool
drmmode_output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)3177*4882a593Smuzhiyun drmmode_output_set_property(xf86OutputPtr output, Atom property,
3178*4882a593Smuzhiyun                             RRPropertyValuePtr value)
3179*4882a593Smuzhiyun {
3180*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output = output->driver_private;
3181*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_output->drmmode;
3182*4882a593Smuzhiyun     int i;
3183*4882a593Smuzhiyun 
3184*4882a593Smuzhiyun     for (i = 0; i < drmmode_output->num_props; i++) {
3185*4882a593Smuzhiyun         drmmode_prop_ptr p = &drmmode_output->props[i];
3186*4882a593Smuzhiyun 
3187*4882a593Smuzhiyun         if (p->atoms[0] != property)
3188*4882a593Smuzhiyun             continue;
3189*4882a593Smuzhiyun 
3190*4882a593Smuzhiyun         if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
3191*4882a593Smuzhiyun             uint32_t val;
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun             if (value->type != XA_INTEGER || value->format != 32 ||
3194*4882a593Smuzhiyun                 value->size != 1)
3195*4882a593Smuzhiyun                 return FALSE;
3196*4882a593Smuzhiyun             val = *(uint32_t *) value->data;
3197*4882a593Smuzhiyun 
3198*4882a593Smuzhiyun             drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
3199*4882a593Smuzhiyun                                         p->mode_prop->prop_id, (uint64_t) val);
3200*4882a593Smuzhiyun             return TRUE;
3201*4882a593Smuzhiyun         }
3202*4882a593Smuzhiyun         else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
3203*4882a593Smuzhiyun             Atom atom;
3204*4882a593Smuzhiyun             const char *name;
3205*4882a593Smuzhiyun             int j;
3206*4882a593Smuzhiyun 
3207*4882a593Smuzhiyun             if (value->type != XA_ATOM || value->format != 32 ||
3208*4882a593Smuzhiyun                 value->size != 1)
3209*4882a593Smuzhiyun                 return FALSE;
3210*4882a593Smuzhiyun             memcpy(&atom, value->data, 4);
3211*4882a593Smuzhiyun             if (!(name = NameForAtom(atom)))
3212*4882a593Smuzhiyun                 return FALSE;
3213*4882a593Smuzhiyun 
3214*4882a593Smuzhiyun             /* search for matching name string, then set its value down */
3215*4882a593Smuzhiyun             for (j = 0; j < p->mode_prop->count_enums; j++) {
3216*4882a593Smuzhiyun                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
3217*4882a593Smuzhiyun                     drmModeConnectorSetProperty(drmmode->fd,
3218*4882a593Smuzhiyun                                                 drmmode_output->output_id,
3219*4882a593Smuzhiyun                                                 p->mode_prop->prop_id,
3220*4882a593Smuzhiyun                                                 p->mode_prop->enums[j].value);
3221*4882a593Smuzhiyun                     return TRUE;
3222*4882a593Smuzhiyun                 }
3223*4882a593Smuzhiyun             }
3224*4882a593Smuzhiyun         }
3225*4882a593Smuzhiyun     }
3226*4882a593Smuzhiyun 
3227*4882a593Smuzhiyun     return TRUE;
3228*4882a593Smuzhiyun }
3229*4882a593Smuzhiyun 
3230*4882a593Smuzhiyun static Bool
drmmode_output_get_property(xf86OutputPtr output,Atom property)3231*4882a593Smuzhiyun drmmode_output_get_property(xf86OutputPtr output, Atom property)
3232*4882a593Smuzhiyun {
3233*4882a593Smuzhiyun     return TRUE;
3234*4882a593Smuzhiyun }
3235*4882a593Smuzhiyun 
3236*4882a593Smuzhiyun static const xf86OutputFuncsRec drmmode_output_funcs = {
3237*4882a593Smuzhiyun     .dpms = drmmode_output_dpms,
3238*4882a593Smuzhiyun     .create_resources = drmmode_output_create_resources,
3239*4882a593Smuzhiyun     .set_property = drmmode_output_set_property,
3240*4882a593Smuzhiyun     .get_property = drmmode_output_get_property,
3241*4882a593Smuzhiyun     .detect = drmmode_output_detect,
3242*4882a593Smuzhiyun     .mode_valid = drmmode_output_mode_valid,
3243*4882a593Smuzhiyun 
3244*4882a593Smuzhiyun     .get_modes = drmmode_output_get_modes,
3245*4882a593Smuzhiyun     .destroy = drmmode_output_destroy
3246*4882a593Smuzhiyun };
3247*4882a593Smuzhiyun 
3248*4882a593Smuzhiyun static int subpixel_conv_table[7] = {
3249*4882a593Smuzhiyun     0,
3250*4882a593Smuzhiyun     SubPixelUnknown,
3251*4882a593Smuzhiyun     SubPixelHorizontalRGB,
3252*4882a593Smuzhiyun     SubPixelHorizontalBGR,
3253*4882a593Smuzhiyun     SubPixelVerticalRGB,
3254*4882a593Smuzhiyun     SubPixelVerticalBGR,
3255*4882a593Smuzhiyun     SubPixelNone
3256*4882a593Smuzhiyun };
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun static const char *const output_names[] = {
3259*4882a593Smuzhiyun     "None",
3260*4882a593Smuzhiyun     "VGA",
3261*4882a593Smuzhiyun     "DVI-I",
3262*4882a593Smuzhiyun     "DVI-D",
3263*4882a593Smuzhiyun     "DVI-A",
3264*4882a593Smuzhiyun     "Composite",
3265*4882a593Smuzhiyun     "SVIDEO",
3266*4882a593Smuzhiyun     "LVDS",
3267*4882a593Smuzhiyun     "Component",
3268*4882a593Smuzhiyun     "DIN",
3269*4882a593Smuzhiyun     "DP",
3270*4882a593Smuzhiyun     "HDMI",
3271*4882a593Smuzhiyun     "HDMI-B",
3272*4882a593Smuzhiyun     "TV",
3273*4882a593Smuzhiyun     "eDP",
3274*4882a593Smuzhiyun     "Virtual",
3275*4882a593Smuzhiyun     "DSI",
3276*4882a593Smuzhiyun     "DPI",
3277*4882a593Smuzhiyun };
3278*4882a593Smuzhiyun 
find_output(ScrnInfoPtr pScrn,int id)3279*4882a593Smuzhiyun static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
3280*4882a593Smuzhiyun {
3281*4882a593Smuzhiyun     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3282*4882a593Smuzhiyun     int i;
3283*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
3284*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
3285*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
3286*4882a593Smuzhiyun 
3287*4882a593Smuzhiyun         drmmode_output = output->driver_private;
3288*4882a593Smuzhiyun         if (drmmode_output->output_id == id)
3289*4882a593Smuzhiyun             return output;
3290*4882a593Smuzhiyun     }
3291*4882a593Smuzhiyun     return NULL;
3292*4882a593Smuzhiyun }
3293*4882a593Smuzhiyun 
parse_path_blob(drmModePropertyBlobPtr path_blob,int * conn_base_id,char ** path)3294*4882a593Smuzhiyun static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
3295*4882a593Smuzhiyun {
3296*4882a593Smuzhiyun     char *conn;
3297*4882a593Smuzhiyun     char conn_id[5];
3298*4882a593Smuzhiyun     int id, len;
3299*4882a593Smuzhiyun     char *blob_data;
3300*4882a593Smuzhiyun 
3301*4882a593Smuzhiyun     if (!path_blob)
3302*4882a593Smuzhiyun         return -1;
3303*4882a593Smuzhiyun 
3304*4882a593Smuzhiyun     blob_data = path_blob->data;
3305*4882a593Smuzhiyun     /* we only handle MST paths for now */
3306*4882a593Smuzhiyun     if (strncmp(blob_data, "mst:", 4))
3307*4882a593Smuzhiyun         return -1;
3308*4882a593Smuzhiyun 
3309*4882a593Smuzhiyun     conn = strchr(blob_data + 4, '-');
3310*4882a593Smuzhiyun     if (!conn)
3311*4882a593Smuzhiyun         return -1;
3312*4882a593Smuzhiyun     len = conn - (blob_data + 4);
3313*4882a593Smuzhiyun     if (len + 1> 5)
3314*4882a593Smuzhiyun         return -1;
3315*4882a593Smuzhiyun     memcpy(conn_id, blob_data + 4, len);
3316*4882a593Smuzhiyun     conn_id[len] = '\0';
3317*4882a593Smuzhiyun     id = strtoul(conn_id, NULL, 10);
3318*4882a593Smuzhiyun 
3319*4882a593Smuzhiyun     *conn_base_id = id;
3320*4882a593Smuzhiyun 
3321*4882a593Smuzhiyun     *path = conn + 1;
3322*4882a593Smuzhiyun     return 0;
3323*4882a593Smuzhiyun }
3324*4882a593Smuzhiyun 
3325*4882a593Smuzhiyun static void
drmmode_create_name(ScrnInfoPtr pScrn,drmModeConnectorPtr koutput,char * name,drmModePropertyBlobPtr path_blob)3326*4882a593Smuzhiyun drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
3327*4882a593Smuzhiyun 		    drmModePropertyBlobPtr path_blob)
3328*4882a593Smuzhiyun {
3329*4882a593Smuzhiyun     int ret;
3330*4882a593Smuzhiyun     char *extra_path;
3331*4882a593Smuzhiyun     int conn_id;
3332*4882a593Smuzhiyun     xf86OutputPtr output;
3333*4882a593Smuzhiyun 
3334*4882a593Smuzhiyun     ret = parse_path_blob(path_blob, &conn_id, &extra_path);
3335*4882a593Smuzhiyun     if (ret == -1)
3336*4882a593Smuzhiyun         goto fallback;
3337*4882a593Smuzhiyun 
3338*4882a593Smuzhiyun     output = find_output(pScrn, conn_id);
3339*4882a593Smuzhiyun     if (!output)
3340*4882a593Smuzhiyun         goto fallback;
3341*4882a593Smuzhiyun 
3342*4882a593Smuzhiyun     snprintf(name, 32, "%s-%s", output->name, extra_path);
3343*4882a593Smuzhiyun     return;
3344*4882a593Smuzhiyun 
3345*4882a593Smuzhiyun  fallback:
3346*4882a593Smuzhiyun     if (koutput->connector_type >= ARRAY_SIZE(output_names))
3347*4882a593Smuzhiyun         snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
3348*4882a593Smuzhiyun     else if (pScrn->is_gpu)
3349*4882a593Smuzhiyun         snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
3350*4882a593Smuzhiyun     else
3351*4882a593Smuzhiyun         snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
3352*4882a593Smuzhiyun }
3353*4882a593Smuzhiyun 
3354*4882a593Smuzhiyun static unsigned int
drmmode_output_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num,Bool dynamic,int crtcshift)3355*4882a593Smuzhiyun drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
3356*4882a593Smuzhiyun {
3357*4882a593Smuzhiyun     xf86OutputPtr output;
3358*4882a593Smuzhiyun     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3359*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(pScrn);
3360*4882a593Smuzhiyun     drmModeConnectorPtr koutput;
3361*4882a593Smuzhiyun     drmModeEncoderPtr *kencoders = NULL;
3362*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output;
3363*4882a593Smuzhiyun     char name[32];
3364*4882a593Smuzhiyun     int i;
3365*4882a593Smuzhiyun     Bool nonDesktop = FALSE;
3366*4882a593Smuzhiyun     drmModePropertyBlobPtr path_blob = NULL;
3367*4882a593Smuzhiyun     const char *s;
3368*4882a593Smuzhiyun     drmModeObjectPropertiesPtr props;
3369*4882a593Smuzhiyun     static const drmmode_prop_info_rec connector_props[] = {
3370*4882a593Smuzhiyun         [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
3371*4882a593Smuzhiyun     };
3372*4882a593Smuzhiyun 
3373*4882a593Smuzhiyun     drmmode_prop_info_ptr crtc_info;
3374*4882a593Smuzhiyun     unsigned int current_crtc;
3375*4882a593Smuzhiyun 
3376*4882a593Smuzhiyun     koutput =
3377*4882a593Smuzhiyun         drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
3378*4882a593Smuzhiyun     if (!koutput)
3379*4882a593Smuzhiyun         return 0;
3380*4882a593Smuzhiyun 
3381*4882a593Smuzhiyun     path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
3382*4882a593Smuzhiyun     i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
3383*4882a593Smuzhiyun     if (i >= 0)
3384*4882a593Smuzhiyun         nonDesktop = koutput->prop_values[i] != 0;
3385*4882a593Smuzhiyun 
3386*4882a593Smuzhiyun     drmmode_create_name(pScrn, koutput, name, path_blob);
3387*4882a593Smuzhiyun 
3388*4882a593Smuzhiyun     if (path_blob)
3389*4882a593Smuzhiyun         drmModeFreePropertyBlob(path_blob);
3390*4882a593Smuzhiyun 
3391*4882a593Smuzhiyun     if (path_blob && dynamic) {
3392*4882a593Smuzhiyun         /* see if we have an output with this name already
3393*4882a593Smuzhiyun            and hook stuff up */
3394*4882a593Smuzhiyun         for (i = 0; i < xf86_config->num_output; i++) {
3395*4882a593Smuzhiyun             output = xf86_config->output[i];
3396*4882a593Smuzhiyun 
3397*4882a593Smuzhiyun             if (strncmp(output->name, name, 32))
3398*4882a593Smuzhiyun                 continue;
3399*4882a593Smuzhiyun 
3400*4882a593Smuzhiyun             drmmode_output = output->driver_private;
3401*4882a593Smuzhiyun             drmmode_output->output_id = mode_res->connectors[num];
3402*4882a593Smuzhiyun             drmmode_output->mode_output = koutput;
3403*4882a593Smuzhiyun             output->non_desktop = nonDesktop;
3404*4882a593Smuzhiyun             return 1;
3405*4882a593Smuzhiyun         }
3406*4882a593Smuzhiyun     }
3407*4882a593Smuzhiyun 
3408*4882a593Smuzhiyun     kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
3409*4882a593Smuzhiyun     if (!kencoders) {
3410*4882a593Smuzhiyun         goto out_free_encoders;
3411*4882a593Smuzhiyun     }
3412*4882a593Smuzhiyun 
3413*4882a593Smuzhiyun     for (i = 0; i < koutput->count_encoders; i++) {
3414*4882a593Smuzhiyun         kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
3415*4882a593Smuzhiyun         if (!kencoders[i]) {
3416*4882a593Smuzhiyun             goto out_free_encoders;
3417*4882a593Smuzhiyun         }
3418*4882a593Smuzhiyun     }
3419*4882a593Smuzhiyun 
3420*4882a593Smuzhiyun     if (xf86IsEntityShared(pScrn->entityList[0])) {
3421*4882a593Smuzhiyun         if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
3422*4882a593Smuzhiyun             if (!drmmode_zaphod_string_matches(pScrn, s, name))
3423*4882a593Smuzhiyun                 goto out_free_encoders;
3424*4882a593Smuzhiyun         } else {
3425*4882a593Smuzhiyun             if (!drmmode->is_secondary && (num != 0))
3426*4882a593Smuzhiyun                 goto out_free_encoders;
3427*4882a593Smuzhiyun             else if (drmmode->is_secondary && (num != 1))
3428*4882a593Smuzhiyun                 goto out_free_encoders;
3429*4882a593Smuzhiyun         }
3430*4882a593Smuzhiyun     }
3431*4882a593Smuzhiyun 
3432*4882a593Smuzhiyun     output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
3433*4882a593Smuzhiyun     if (!output) {
3434*4882a593Smuzhiyun         goto out_free_encoders;
3435*4882a593Smuzhiyun     }
3436*4882a593Smuzhiyun 
3437*4882a593Smuzhiyun     drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
3438*4882a593Smuzhiyun     if (!drmmode_output) {
3439*4882a593Smuzhiyun         xf86OutputDestroy(output);
3440*4882a593Smuzhiyun         goto out_free_encoders;
3441*4882a593Smuzhiyun     }
3442*4882a593Smuzhiyun 
3443*4882a593Smuzhiyun     s = xf86GetOptValString(drmmode->Options, OPTION_VIRTUAL_SIZE);
3444*4882a593Smuzhiyun     if (s)
3445*4882a593Smuzhiyun         s = strstr(s, output->name);
3446*4882a593Smuzhiyun     if (s) {
3447*4882a593Smuzhiyun         int w, h;
3448*4882a593Smuzhiyun         if (sscanf(s + strlen(output->name) + 1, "%dx%d", &w, &h) == 2 &&
3449*4882a593Smuzhiyun             w > 0 && h > 0) {
3450*4882a593Smuzhiyun             drmmode_output->virtual_width = w;
3451*4882a593Smuzhiyun             drmmode_output->virtual_height = h;
3452*4882a593Smuzhiyun             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3453*4882a593Smuzhiyun                        "Using virtual size %dx%d for connector: %s\n",
3454*4882a593Smuzhiyun                        drmmode_output->virtual_width,
3455*4882a593Smuzhiyun                        drmmode_output->virtual_height, output->name);
3456*4882a593Smuzhiyun         }
3457*4882a593Smuzhiyun     }
3458*4882a593Smuzhiyun 
3459*4882a593Smuzhiyun     s = xf86GetOptValString(drmmode->Options, OPTION_PADDING);
3460*4882a593Smuzhiyun     if (s)
3461*4882a593Smuzhiyun         s = strstr(s, output->name);
3462*4882a593Smuzhiyun     if (s) {
3463*4882a593Smuzhiyun         int top, bottom, left, right;
3464*4882a593Smuzhiyun         if (sscanf(s + strlen(output->name) + 1, "%d,%d,%d,%d",
3465*4882a593Smuzhiyun                    &top, &bottom, &left, &right) == 4) {
3466*4882a593Smuzhiyun             if (top >= 0 && bottom >= 0 && left >= 0 && right >= 0) {
3467*4882a593Smuzhiyun                 drmmode_output->padding_top = top;
3468*4882a593Smuzhiyun                 drmmode_output->padding_bottom = bottom;
3469*4882a593Smuzhiyun                 drmmode_output->padding_left = left;
3470*4882a593Smuzhiyun                 drmmode_output->padding_right = right;
3471*4882a593Smuzhiyun                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3472*4882a593Smuzhiyun                            "Using padding top:%d bottom:%d left:%d right:%d\n",
3473*4882a593Smuzhiyun                            drmmode_output->padding_top,
3474*4882a593Smuzhiyun                            drmmode_output->padding_bottom,
3475*4882a593Smuzhiyun                            drmmode_output->padding_left,
3476*4882a593Smuzhiyun                            drmmode_output->padding_right);
3477*4882a593Smuzhiyun             }
3478*4882a593Smuzhiyun         }
3479*4882a593Smuzhiyun     }
3480*4882a593Smuzhiyun 
3481*4882a593Smuzhiyun     drmmode_output->output_id = mode_res->connectors[num];
3482*4882a593Smuzhiyun     drmmode_output->mode_output = koutput;
3483*4882a593Smuzhiyun     drmmode_output->mode_encoders = kencoders;
3484*4882a593Smuzhiyun     drmmode_output->drmmode = drmmode;
3485*4882a593Smuzhiyun     output->mm_width = koutput->mmWidth;
3486*4882a593Smuzhiyun     output->mm_height = koutput->mmHeight;
3487*4882a593Smuzhiyun 
3488*4882a593Smuzhiyun     output->subpixel_order = subpixel_conv_table[koutput->subpixel];
3489*4882a593Smuzhiyun     output->interlaceAllowed = TRUE;
3490*4882a593Smuzhiyun     output->doubleScanAllowed = TRUE;
3491*4882a593Smuzhiyun     output->driver_private = drmmode_output;
3492*4882a593Smuzhiyun     output->non_desktop = nonDesktop;
3493*4882a593Smuzhiyun 
3494*4882a593Smuzhiyun     drmmode_output->possible_crtcs = 0x7f;
3495*4882a593Smuzhiyun     for (i = 0; i < koutput->count_encoders; i++) {
3496*4882a593Smuzhiyun         drmmode_output->possible_crtcs &= kencoders[i]->possible_crtcs;
3497*4882a593Smuzhiyun     }
3498*4882a593Smuzhiyun 
3499*4882a593Smuzhiyun     if (!dynamic) {
3500*4882a593Smuzhiyun         /* would be updated in crtc init */
3501*4882a593Smuzhiyun         output->possible_crtcs = 0;
3502*4882a593Smuzhiyun     } else {
3503*4882a593Smuzhiyun         output->possible_crtcs = drmmode_output->possible_crtcs;
3504*4882a593Smuzhiyun     }
3505*4882a593Smuzhiyun 
3506*4882a593Smuzhiyun     /* work out the possible clones later */
3507*4882a593Smuzhiyun     output->possible_clones = 0;
3508*4882a593Smuzhiyun 
3509*4882a593Smuzhiyun     if (!drmmode_prop_info_copy(drmmode_output->props_connector,
3510*4882a593Smuzhiyun                                 connector_props, DRMMODE_CONNECTOR__COUNT,
3511*4882a593Smuzhiyun                                 0)) {
3512*4882a593Smuzhiyun         goto out_free_encoders;
3513*4882a593Smuzhiyun     }
3514*4882a593Smuzhiyun     props = drmModeObjectGetProperties(drmmode->fd,
3515*4882a593Smuzhiyun                                        drmmode_output->output_id,
3516*4882a593Smuzhiyun                                        DRM_MODE_OBJECT_CONNECTOR);
3517*4882a593Smuzhiyun     drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
3518*4882a593Smuzhiyun                              DRMMODE_CONNECTOR__COUNT, props);
3519*4882a593Smuzhiyun     crtc_info = &drmmode_output->props_connector[DRMMODE_CONNECTOR_CRTC_ID];
3520*4882a593Smuzhiyun     current_crtc = drmmode_prop_get_value(crtc_info, props,
3521*4882a593Smuzhiyun                                           DRMMODE_PLANE_TYPE__COUNT);
3522*4882a593Smuzhiyun     drmModeFreeObjectProperties(props);
3523*4882a593Smuzhiyun 
3524*4882a593Smuzhiyun     if (xf86ReturnOptValBool(drmmode->Options, OPTION_BIND_CURRENT, TRUE)) {
3525*4882a593Smuzhiyun         for (i = 0; i < mode_res->count_crtcs; i++) {
3526*4882a593Smuzhiyun             if (current_crtc == mode_res->crtcs[i]) {
3527*4882a593Smuzhiyun                 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
3528*4882a593Smuzhiyun                                "Bind output %d to current crtc %d.\n",
3529*4882a593Smuzhiyun                                drmmode_output->output_id, current_crtc);
3530*4882a593Smuzhiyun                 drmmode_output->possible_crtcs = 1 << i;
3531*4882a593Smuzhiyun                 break;
3532*4882a593Smuzhiyun             }
3533*4882a593Smuzhiyun         }
3534*4882a593Smuzhiyun     }
3535*4882a593Smuzhiyun 
3536*4882a593Smuzhiyun     if (!ms->atomic_modeset) {
3537*4882a593Smuzhiyun         drmmode_output->dpms_enum_id =
3538*4882a593Smuzhiyun             koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
3539*4882a593Smuzhiyun                                 "DPMS");
3540*4882a593Smuzhiyun     }
3541*4882a593Smuzhiyun 
3542*4882a593Smuzhiyun     if (dynamic)
3543*4882a593Smuzhiyun         output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
3544*4882a593Smuzhiyun     return 1;
3545*4882a593Smuzhiyun 
3546*4882a593Smuzhiyun  out_free_encoders:
3547*4882a593Smuzhiyun     if (kencoders) {
3548*4882a593Smuzhiyun         for (i = 0; i < koutput->count_encoders; i++)
3549*4882a593Smuzhiyun             drmModeFreeEncoder(kencoders[i]);
3550*4882a593Smuzhiyun         free(kencoders);
3551*4882a593Smuzhiyun     }
3552*4882a593Smuzhiyun     drmModeFreeConnector(koutput);
3553*4882a593Smuzhiyun 
3554*4882a593Smuzhiyun     return 0;
3555*4882a593Smuzhiyun }
3556*4882a593Smuzhiyun 
3557*4882a593Smuzhiyun static uint32_t
find_clones(ScrnInfoPtr scrn,xf86OutputPtr output)3558*4882a593Smuzhiyun find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
3559*4882a593Smuzhiyun {
3560*4882a593Smuzhiyun     drmmode_output_private_ptr drmmode_output =
3561*4882a593Smuzhiyun         output->driver_private, clone_drmout;
3562*4882a593Smuzhiyun     int i;
3563*4882a593Smuzhiyun     xf86OutputPtr clone_output;
3564*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3565*4882a593Smuzhiyun     int index_mask = 0;
3566*4882a593Smuzhiyun 
3567*4882a593Smuzhiyun     if (drmmode_output->enc_clone_mask == 0)
3568*4882a593Smuzhiyun         return index_mask;
3569*4882a593Smuzhiyun 
3570*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
3571*4882a593Smuzhiyun         clone_output = xf86_config->output[i];
3572*4882a593Smuzhiyun         clone_drmout = clone_output->driver_private;
3573*4882a593Smuzhiyun         if (output == clone_output)
3574*4882a593Smuzhiyun             continue;
3575*4882a593Smuzhiyun 
3576*4882a593Smuzhiyun         if (clone_drmout->enc_mask == 0)
3577*4882a593Smuzhiyun             continue;
3578*4882a593Smuzhiyun         if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
3579*4882a593Smuzhiyun             index_mask |= (1 << i);
3580*4882a593Smuzhiyun     }
3581*4882a593Smuzhiyun     return index_mask;
3582*4882a593Smuzhiyun }
3583*4882a593Smuzhiyun 
3584*4882a593Smuzhiyun static void
drmmode_clones_init(ScrnInfoPtr scrn,drmmode_ptr drmmode,drmModeResPtr mode_res)3585*4882a593Smuzhiyun drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
3586*4882a593Smuzhiyun {
3587*4882a593Smuzhiyun     int i, j;
3588*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3589*4882a593Smuzhiyun 
3590*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
3591*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
3592*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
3593*4882a593Smuzhiyun 
3594*4882a593Smuzhiyun         drmmode_output = output->driver_private;
3595*4882a593Smuzhiyun         drmmode_output->enc_clone_mask = 0xff;
3596*4882a593Smuzhiyun         /* and all the possible encoder clones for this output together */
3597*4882a593Smuzhiyun         for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
3598*4882a593Smuzhiyun             int k;
3599*4882a593Smuzhiyun 
3600*4882a593Smuzhiyun             for (k = 0; k < mode_res->count_encoders; k++) {
3601*4882a593Smuzhiyun                 if (mode_res->encoders[k] ==
3602*4882a593Smuzhiyun                     drmmode_output->mode_encoders[j]->encoder_id)
3603*4882a593Smuzhiyun                     drmmode_output->enc_mask |= (1 << k);
3604*4882a593Smuzhiyun             }
3605*4882a593Smuzhiyun 
3606*4882a593Smuzhiyun             drmmode_output->enc_clone_mask &=
3607*4882a593Smuzhiyun                 drmmode_output->mode_encoders[j]->possible_clones;
3608*4882a593Smuzhiyun         }
3609*4882a593Smuzhiyun     }
3610*4882a593Smuzhiyun 
3611*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_output; i++) {
3612*4882a593Smuzhiyun         xf86OutputPtr output = xf86_config->output[i];
3613*4882a593Smuzhiyun 
3614*4882a593Smuzhiyun         output->possible_clones = find_clones(scrn, output);
3615*4882a593Smuzhiyun     }
3616*4882a593Smuzhiyun }
3617*4882a593Smuzhiyun 
3618*4882a593Smuzhiyun static Bool
drmmode_set_pixmap_bo(drmmode_ptr drmmode,PixmapPtr pixmap,drmmode_bo * bo)3619*4882a593Smuzhiyun drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
3620*4882a593Smuzhiyun {
3621*4882a593Smuzhiyun     ScrnInfoPtr scrn = drmmode->scrn;
3622*4882a593Smuzhiyun 
3623*4882a593Smuzhiyun     if (drmmode->exa)
3624*4882a593Smuzhiyun         return ms_exa_set_pixmap_bo(scrn, pixmap, bo->dumb, FALSE);
3625*4882a593Smuzhiyun 
3626*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
3627*4882a593Smuzhiyun     if (!drmmode->glamor)
3628*4882a593Smuzhiyun         return TRUE;
3629*4882a593Smuzhiyun 
3630*4882a593Smuzhiyun     if (!glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
3631*4882a593Smuzhiyun                                                        bo->used_modifiers)) {
3632*4882a593Smuzhiyun         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
3633*4882a593Smuzhiyun         return FALSE;
3634*4882a593Smuzhiyun     }
3635*4882a593Smuzhiyun     bo->owned_gbm = FALSE;
3636*4882a593Smuzhiyun #endif
3637*4882a593Smuzhiyun 
3638*4882a593Smuzhiyun     return TRUE;
3639*4882a593Smuzhiyun }
3640*4882a593Smuzhiyun 
3641*4882a593Smuzhiyun Bool
drmmode_handle_new_screen_pixmap(drmmode_ptr drmmode)3642*4882a593Smuzhiyun drmmode_handle_new_screen_pixmap(drmmode_ptr drmmode)
3643*4882a593Smuzhiyun {
3644*4882a593Smuzhiyun     ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
3645*4882a593Smuzhiyun     PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
3646*4882a593Smuzhiyun 
3647*4882a593Smuzhiyun     if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
3648*4882a593Smuzhiyun         return FALSE;
3649*4882a593Smuzhiyun 
3650*4882a593Smuzhiyun     return TRUE;
3651*4882a593Smuzhiyun }
3652*4882a593Smuzhiyun 
3653*4882a593Smuzhiyun static Bool
drmmode_xf86crtc_resize(ScrnInfoPtr scrn,int width,int height)3654*4882a593Smuzhiyun drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
3655*4882a593Smuzhiyun {
3656*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3657*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
3658*4882a593Smuzhiyun     drmmode_ptr drmmode = &ms->drmmode;
3659*4882a593Smuzhiyun     drmmode_bo old_front;
3660*4882a593Smuzhiyun     ScreenPtr screen = xf86ScrnToScreen(scrn);
3661*4882a593Smuzhiyun     uint32_t old_fb_id;
3662*4882a593Smuzhiyun     int i, pitch, old_width, old_height, old_pitch;
3663*4882a593Smuzhiyun     int cpp = (scrn->bitsPerPixel + 7) / 8;
3664*4882a593Smuzhiyun     int kcpp = (drmmode->kbpp + 7) / 8;
3665*4882a593Smuzhiyun     PixmapPtr ppix = screen->GetScreenPixmap(screen);
3666*4882a593Smuzhiyun     void *new_pixels = NULL;
3667*4882a593Smuzhiyun 
3668*4882a593Smuzhiyun     if (scrn->virtualX == width && scrn->virtualY == height)
3669*4882a593Smuzhiyun         return TRUE;
3670*4882a593Smuzhiyun 
3671*4882a593Smuzhiyun     xf86DrvMsg(scrn->scrnIndex, X_INFO,
3672*4882a593Smuzhiyun                "Allocate new frame buffer %dx%d stride\n", width, height);
3673*4882a593Smuzhiyun 
3674*4882a593Smuzhiyun     old_width = scrn->virtualX;
3675*4882a593Smuzhiyun     old_height = scrn->virtualY;
3676*4882a593Smuzhiyun     old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3677*4882a593Smuzhiyun     old_front = drmmode->front_bo;
3678*4882a593Smuzhiyun     old_fb_id = drmmode->fb_id;
3679*4882a593Smuzhiyun     drmmode->fb_id = 0;
3680*4882a593Smuzhiyun 
3681*4882a593Smuzhiyun     if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
3682*4882a593Smuzhiyun                            width, height, drmmode->kbpp))
3683*4882a593Smuzhiyun         goto fail;
3684*4882a593Smuzhiyun 
3685*4882a593Smuzhiyun     pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3686*4882a593Smuzhiyun 
3687*4882a593Smuzhiyun     scrn->virtualX = width;
3688*4882a593Smuzhiyun     scrn->virtualY = height;
3689*4882a593Smuzhiyun     scrn->displayWidth = pitch / kcpp;
3690*4882a593Smuzhiyun 
3691*4882a593Smuzhiyun     if (!drmmode->gbm && !drmmode->exa) {
3692*4882a593Smuzhiyun         new_pixels = drmmode_map_front_bo(drmmode);
3693*4882a593Smuzhiyun         if (!new_pixels)
3694*4882a593Smuzhiyun             goto fail;
3695*4882a593Smuzhiyun     }
3696*4882a593Smuzhiyun 
3697*4882a593Smuzhiyun     if (drmmode->shadow_enable) {
3698*4882a593Smuzhiyun         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3699*4882a593Smuzhiyun         new_pixels = calloc(1, size);
3700*4882a593Smuzhiyun         if (new_pixels == NULL)
3701*4882a593Smuzhiyun             goto fail;
3702*4882a593Smuzhiyun         free(drmmode->shadow_fb);
3703*4882a593Smuzhiyun         drmmode->shadow_fb = new_pixels;
3704*4882a593Smuzhiyun     }
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun     if (drmmode->shadow_enable2) {
3707*4882a593Smuzhiyun         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3708*4882a593Smuzhiyun         void *fb2 = calloc(1, size);
3709*4882a593Smuzhiyun         free(drmmode->shadow_fb2);
3710*4882a593Smuzhiyun         drmmode->shadow_fb2 = fb2;
3711*4882a593Smuzhiyun     }
3712*4882a593Smuzhiyun 
3713*4882a593Smuzhiyun     screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
3714*4882a593Smuzhiyun                                scrn->displayWidth * cpp, new_pixels);
3715*4882a593Smuzhiyun 
3716*4882a593Smuzhiyun     if (!drmmode_handle_new_screen_pixmap(drmmode))
3717*4882a593Smuzhiyun         goto fail;
3718*4882a593Smuzhiyun 
3719*4882a593Smuzhiyun     drmmode_clear_pixmap(ppix);
3720*4882a593Smuzhiyun 
3721*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++) {
3722*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[i];
3723*4882a593Smuzhiyun 
3724*4882a593Smuzhiyun         if (!crtc->enabled)
3725*4882a593Smuzhiyun             continue;
3726*4882a593Smuzhiyun 
3727*4882a593Smuzhiyun         drmmode_set_mode_major(crtc, &crtc->mode,
3728*4882a593Smuzhiyun                                crtc->rotation, crtc->x, crtc->y);
3729*4882a593Smuzhiyun     }
3730*4882a593Smuzhiyun 
3731*4882a593Smuzhiyun     if (old_fb_id)
3732*4882a593Smuzhiyun         drmModeRmFB(drmmode->fd, old_fb_id);
3733*4882a593Smuzhiyun 
3734*4882a593Smuzhiyun     drmmode_bo_destroy(drmmode, &old_front);
3735*4882a593Smuzhiyun 
3736*4882a593Smuzhiyun     return TRUE;
3737*4882a593Smuzhiyun 
3738*4882a593Smuzhiyun  fail:
3739*4882a593Smuzhiyun     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3740*4882a593Smuzhiyun     drmmode->front_bo = old_front;
3741*4882a593Smuzhiyun     scrn->virtualX = old_width;
3742*4882a593Smuzhiyun     scrn->virtualY = old_height;
3743*4882a593Smuzhiyun     scrn->displayWidth = old_pitch / kcpp;
3744*4882a593Smuzhiyun     drmmode->fb_id = old_fb_id;
3745*4882a593Smuzhiyun 
3746*4882a593Smuzhiyun     return FALSE;
3747*4882a593Smuzhiyun }
3748*4882a593Smuzhiyun 
3749*4882a593Smuzhiyun static void
drmmode_validate_leases(ScrnInfoPtr scrn)3750*4882a593Smuzhiyun drmmode_validate_leases(ScrnInfoPtr scrn)
3751*4882a593Smuzhiyun {
3752*4882a593Smuzhiyun     ScreenPtr screen = scrn->pScreen;
3753*4882a593Smuzhiyun     rrScrPrivPtr scr_priv;
3754*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
3755*4882a593Smuzhiyun     drmmode_ptr drmmode = &ms->drmmode;
3756*4882a593Smuzhiyun     drmModeLesseeListPtr lessees;
3757*4882a593Smuzhiyun     RRLeasePtr lease, next;
3758*4882a593Smuzhiyun     int l;
3759*4882a593Smuzhiyun 
3760*4882a593Smuzhiyun     /* Bail out if RandR wasn't initialized. */
3761*4882a593Smuzhiyun     if (!dixPrivateKeyRegistered(rrPrivKey))
3762*4882a593Smuzhiyun         return;
3763*4882a593Smuzhiyun 
3764*4882a593Smuzhiyun     scr_priv = rrGetScrPriv(screen);
3765*4882a593Smuzhiyun 
3766*4882a593Smuzhiyun     /* We can't talk to the kernel about leases when VT switched */
3767*4882a593Smuzhiyun     if (!scrn->vtSema)
3768*4882a593Smuzhiyun         return;
3769*4882a593Smuzhiyun 
3770*4882a593Smuzhiyun     lessees = drmModeListLessees(drmmode->fd);
3771*4882a593Smuzhiyun     if (!lessees)
3772*4882a593Smuzhiyun         return;
3773*4882a593Smuzhiyun 
3774*4882a593Smuzhiyun     xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
3775*4882a593Smuzhiyun         drmmode_lease_private_ptr lease_private = lease->devPrivate;
3776*4882a593Smuzhiyun 
3777*4882a593Smuzhiyun         for (l = 0; l < lessees->count; l++) {
3778*4882a593Smuzhiyun             if (lessees->lessees[l] == lease_private->lessee_id)
3779*4882a593Smuzhiyun                 break;
3780*4882a593Smuzhiyun         }
3781*4882a593Smuzhiyun 
3782*4882a593Smuzhiyun         /* check to see if the lease has gone away */
3783*4882a593Smuzhiyun         if (l == lessees->count) {
3784*4882a593Smuzhiyun             free(lease_private);
3785*4882a593Smuzhiyun             lease->devPrivate = NULL;
3786*4882a593Smuzhiyun             xf86CrtcLeaseTerminated(lease);
3787*4882a593Smuzhiyun         }
3788*4882a593Smuzhiyun     }
3789*4882a593Smuzhiyun 
3790*4882a593Smuzhiyun     free(lessees);
3791*4882a593Smuzhiyun }
3792*4882a593Smuzhiyun 
3793*4882a593Smuzhiyun static int
drmmode_create_lease(RRLeasePtr lease,int * fd)3794*4882a593Smuzhiyun drmmode_create_lease(RRLeasePtr lease, int *fd)
3795*4882a593Smuzhiyun {
3796*4882a593Smuzhiyun     ScreenPtr screen = lease->screen;
3797*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3798*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
3799*4882a593Smuzhiyun     drmmode_ptr drmmode = &ms->drmmode;
3800*4882a593Smuzhiyun     int ncrtc = lease->numCrtcs;
3801*4882a593Smuzhiyun     int noutput = lease->numOutputs;
3802*4882a593Smuzhiyun     int nobjects;
3803*4882a593Smuzhiyun     int c, o;
3804*4882a593Smuzhiyun     int i;
3805*4882a593Smuzhiyun     int lease_fd;
3806*4882a593Smuzhiyun     uint32_t *objects;
3807*4882a593Smuzhiyun     drmmode_lease_private_ptr   lease_private;
3808*4882a593Smuzhiyun 
3809*4882a593Smuzhiyun     nobjects = ncrtc + noutput;
3810*4882a593Smuzhiyun 
3811*4882a593Smuzhiyun     if (ms->atomic_modeset)
3812*4882a593Smuzhiyun         nobjects += ncrtc; /* account for planes as well */
3813*4882a593Smuzhiyun 
3814*4882a593Smuzhiyun     if (nobjects == 0)
3815*4882a593Smuzhiyun         return BadValue;
3816*4882a593Smuzhiyun 
3817*4882a593Smuzhiyun     lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
3818*4882a593Smuzhiyun     if (!lease_private)
3819*4882a593Smuzhiyun         return BadAlloc;
3820*4882a593Smuzhiyun 
3821*4882a593Smuzhiyun     objects = xallocarray(nobjects, sizeof (uint32_t));
3822*4882a593Smuzhiyun 
3823*4882a593Smuzhiyun     if (!objects) {
3824*4882a593Smuzhiyun         free(lease_private);
3825*4882a593Smuzhiyun         return BadAlloc;
3826*4882a593Smuzhiyun     }
3827*4882a593Smuzhiyun 
3828*4882a593Smuzhiyun     i = 0;
3829*4882a593Smuzhiyun 
3830*4882a593Smuzhiyun     /* Add CRTC and plane ids */
3831*4882a593Smuzhiyun     for (c = 0; c < ncrtc; c++) {
3832*4882a593Smuzhiyun         xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
3833*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3834*4882a593Smuzhiyun 
3835*4882a593Smuzhiyun         objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
3836*4882a593Smuzhiyun         if (ms->atomic_modeset)
3837*4882a593Smuzhiyun             objects[i++] = drmmode_crtc->plane_id;
3838*4882a593Smuzhiyun     }
3839*4882a593Smuzhiyun 
3840*4882a593Smuzhiyun     /* Add connector ids */
3841*4882a593Smuzhiyun 
3842*4882a593Smuzhiyun     for (o = 0; o < noutput; o++) {
3843*4882a593Smuzhiyun         xf86OutputPtr   output = lease->outputs[o]->devPrivate;
3844*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output = output->driver_private;
3845*4882a593Smuzhiyun 
3846*4882a593Smuzhiyun         objects[i++] = drmmode_output->mode_output->connector_id;
3847*4882a593Smuzhiyun     }
3848*4882a593Smuzhiyun 
3849*4882a593Smuzhiyun     /* call kernel to create lease */
3850*4882a593Smuzhiyun     assert (i == nobjects);
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun     lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
3853*4882a593Smuzhiyun 
3854*4882a593Smuzhiyun     free(objects);
3855*4882a593Smuzhiyun 
3856*4882a593Smuzhiyun     if (lease_fd < 0) {
3857*4882a593Smuzhiyun         free(lease_private);
3858*4882a593Smuzhiyun         return BadMatch;
3859*4882a593Smuzhiyun     }
3860*4882a593Smuzhiyun 
3861*4882a593Smuzhiyun     lease->devPrivate = lease_private;
3862*4882a593Smuzhiyun 
3863*4882a593Smuzhiyun     xf86CrtcLeaseStarted(lease);
3864*4882a593Smuzhiyun 
3865*4882a593Smuzhiyun     *fd = lease_fd;
3866*4882a593Smuzhiyun     return Success;
3867*4882a593Smuzhiyun }
3868*4882a593Smuzhiyun 
3869*4882a593Smuzhiyun static void
drmmode_terminate_lease(RRLeasePtr lease)3870*4882a593Smuzhiyun drmmode_terminate_lease(RRLeasePtr lease)
3871*4882a593Smuzhiyun {
3872*4882a593Smuzhiyun     ScreenPtr screen = lease->screen;
3873*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3874*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
3875*4882a593Smuzhiyun     drmmode_ptr drmmode = &ms->drmmode;
3876*4882a593Smuzhiyun     drmmode_lease_private_ptr lease_private = lease->devPrivate;
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun     if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
3879*4882a593Smuzhiyun         free(lease_private);
3880*4882a593Smuzhiyun         lease->devPrivate = NULL;
3881*4882a593Smuzhiyun         xf86CrtcLeaseTerminated(lease);
3882*4882a593Smuzhiyun     }
3883*4882a593Smuzhiyun }
3884*4882a593Smuzhiyun 
3885*4882a593Smuzhiyun static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
3886*4882a593Smuzhiyun     .resize = drmmode_xf86crtc_resize,
3887*4882a593Smuzhiyun     .create_lease = drmmode_create_lease,
3888*4882a593Smuzhiyun     .terminate_lease = drmmode_terminate_lease
3889*4882a593Smuzhiyun };
3890*4882a593Smuzhiyun 
3891*4882a593Smuzhiyun Bool
drmmode_pre_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int cpp)3892*4882a593Smuzhiyun drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
3893*4882a593Smuzhiyun {
3894*4882a593Smuzhiyun     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
3895*4882a593Smuzhiyun     int i;
3896*4882a593Smuzhiyun     int ret;
3897*4882a593Smuzhiyun     uint64_t value = 0;
3898*4882a593Smuzhiyun     unsigned int crtcs_needed = 0;
3899*4882a593Smuzhiyun     drmModeResPtr mode_res;
3900*4882a593Smuzhiyun     int crtcshift;
3901*4882a593Smuzhiyun 
3902*4882a593Smuzhiyun     /* check for dumb capability */
3903*4882a593Smuzhiyun     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
3904*4882a593Smuzhiyun     if (ret > 0 || value != 1) {
3905*4882a593Smuzhiyun         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3906*4882a593Smuzhiyun                    "KMS doesn't support dumb interface\n");
3907*4882a593Smuzhiyun         return FALSE;
3908*4882a593Smuzhiyun     }
3909*4882a593Smuzhiyun 
3910*4882a593Smuzhiyun     xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
3911*4882a593Smuzhiyun 
3912*4882a593Smuzhiyun     drmmode->scrn = pScrn;
3913*4882a593Smuzhiyun     drmmode->cpp = cpp;
3914*4882a593Smuzhiyun     mode_res = drmModeGetResources(drmmode->fd);
3915*4882a593Smuzhiyun     if (!mode_res)
3916*4882a593Smuzhiyun         return FALSE;
3917*4882a593Smuzhiyun 
3918*4882a593Smuzhiyun     crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
3919*4882a593Smuzhiyun     for (i = 0; i < mode_res->count_connectors; i++)
3920*4882a593Smuzhiyun         crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
3921*4882a593Smuzhiyun                                             crtcshift);
3922*4882a593Smuzhiyun 
3923*4882a593Smuzhiyun     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
3924*4882a593Smuzhiyun                    "Up to %d crtcs needed for screen.\n", crtcs_needed);
3925*4882a593Smuzhiyun 
3926*4882a593Smuzhiyun     xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
3927*4882a593Smuzhiyun                          mode_res->max_height);
3928*4882a593Smuzhiyun     for (i = 0; i < mode_res->count_crtcs; i++)
3929*4882a593Smuzhiyun         if (!xf86IsEntityShared(pScrn->entityList[0]) ||
3930*4882a593Smuzhiyun             (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
3931*4882a593Smuzhiyun             crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
3932*4882a593Smuzhiyun 
3933*4882a593Smuzhiyun     /* All ZaphodHeads outputs provided with matching crtcs? */
3934*4882a593Smuzhiyun     if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
3935*4882a593Smuzhiyun         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3936*4882a593Smuzhiyun                    "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
3937*4882a593Smuzhiyun                    crtcs_needed);
3938*4882a593Smuzhiyun 
3939*4882a593Smuzhiyun     /* workout clones */
3940*4882a593Smuzhiyun     drmmode_clones_init(pScrn, drmmode, mode_res);
3941*4882a593Smuzhiyun 
3942*4882a593Smuzhiyun     drmModeFreeResources(mode_res);
3943*4882a593Smuzhiyun     xf86ProviderSetup(pScrn, NULL, "modesetting");
3944*4882a593Smuzhiyun 
3945*4882a593Smuzhiyun     xf86InitialConfiguration(pScrn, TRUE);
3946*4882a593Smuzhiyun 
3947*4882a593Smuzhiyun     return TRUE;
3948*4882a593Smuzhiyun }
3949*4882a593Smuzhiyun 
3950*4882a593Smuzhiyun Bool
drmmode_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3951*4882a593Smuzhiyun drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3952*4882a593Smuzhiyun {
3953*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
3954*4882a593Smuzhiyun     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3955*4882a593Smuzhiyun 
3956*4882a593Smuzhiyun     if (drmmode->glamor) {
3957*4882a593Smuzhiyun         if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
3958*4882a593Smuzhiyun             return FALSE;
3959*4882a593Smuzhiyun         }
3960*4882a593Smuzhiyun #ifdef GBM_BO_WITH_MODIFIERS
3961*4882a593Smuzhiyun         glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
3962*4882a593Smuzhiyun #endif
3963*4882a593Smuzhiyun     }
3964*4882a593Smuzhiyun #endif
3965*4882a593Smuzhiyun 
3966*4882a593Smuzhiyun     return TRUE;
3967*4882a593Smuzhiyun }
3968*4882a593Smuzhiyun 
3969*4882a593Smuzhiyun void
drmmode_adjust_frame(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int x,int y)3970*4882a593Smuzhiyun drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3971*4882a593Smuzhiyun {
3972*4882a593Smuzhiyun     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3973*4882a593Smuzhiyun     xf86OutputPtr output = config->output[config->compat_output];
3974*4882a593Smuzhiyun     xf86CrtcPtr crtc = output->crtc;
3975*4882a593Smuzhiyun 
3976*4882a593Smuzhiyun     if (crtc && crtc->enabled) {
3977*4882a593Smuzhiyun         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
3978*4882a593Smuzhiyun     }
3979*4882a593Smuzhiyun }
3980*4882a593Smuzhiyun 
3981*4882a593Smuzhiyun Bool
drmmode_set_desired_modes(ScrnInfoPtr pScrn,drmmode_ptr drmmode,Bool set_hw,Bool ign_err)3982*4882a593Smuzhiyun drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
3983*4882a593Smuzhiyun                           Bool ign_err)
3984*4882a593Smuzhiyun {
3985*4882a593Smuzhiyun     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3986*4882a593Smuzhiyun     Bool success = TRUE;
3987*4882a593Smuzhiyun     int c;
3988*4882a593Smuzhiyun 
3989*4882a593Smuzhiyun     for (c = 0; c < config->num_crtc; c++) {
3990*4882a593Smuzhiyun         xf86CrtcPtr crtc = config->crtc[c];
3991*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3992*4882a593Smuzhiyun         xf86OutputPtr output = NULL;
3993*4882a593Smuzhiyun         int o;
3994*4882a593Smuzhiyun 
3995*4882a593Smuzhiyun         /* Skip disabled CRTCs */
3996*4882a593Smuzhiyun         if (!crtc->enabled) {
3997*4882a593Smuzhiyun             if (set_hw) {
3998*4882a593Smuzhiyun                 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
3999*4882a593Smuzhiyun                                0, 0, 0, NULL, 0, NULL);
4000*4882a593Smuzhiyun             }
4001*4882a593Smuzhiyun             continue;
4002*4882a593Smuzhiyun         }
4003*4882a593Smuzhiyun 
4004*4882a593Smuzhiyun         if (config->output[config->compat_output]->crtc == crtc)
4005*4882a593Smuzhiyun             output = config->output[config->compat_output];
4006*4882a593Smuzhiyun         else {
4007*4882a593Smuzhiyun             for (o = 0; o < config->num_output; o++)
4008*4882a593Smuzhiyun                 if (config->output[o]->crtc == crtc) {
4009*4882a593Smuzhiyun                     output = config->output[o];
4010*4882a593Smuzhiyun                     break;
4011*4882a593Smuzhiyun                 }
4012*4882a593Smuzhiyun         }
4013*4882a593Smuzhiyun         /* paranoia */
4014*4882a593Smuzhiyun         if (!output)
4015*4882a593Smuzhiyun             continue;
4016*4882a593Smuzhiyun 
4017*4882a593Smuzhiyun         /* Mark that we'll need to re-set the mode for sure */
4018*4882a593Smuzhiyun         memset(&crtc->mode, 0, sizeof(crtc->mode));
4019*4882a593Smuzhiyun         if (!crtc->desiredMode.CrtcHDisplay) {
4020*4882a593Smuzhiyun             DisplayModePtr mode =
4021*4882a593Smuzhiyun                 xf86OutputFindClosestMode(output, pScrn->currentMode);
4022*4882a593Smuzhiyun 
4023*4882a593Smuzhiyun             if (!mode)
4024*4882a593Smuzhiyun                 return FALSE;
4025*4882a593Smuzhiyun             crtc->desiredMode = *mode;
4026*4882a593Smuzhiyun             crtc->desiredRotation = RR_Rotate_0;
4027*4882a593Smuzhiyun             crtc->desiredX = 0;
4028*4882a593Smuzhiyun             crtc->desiredY = 0;
4029*4882a593Smuzhiyun         }
4030*4882a593Smuzhiyun 
4031*4882a593Smuzhiyun         if (set_hw) {
4032*4882a593Smuzhiyun             if (!crtc->funcs->
4033*4882a593Smuzhiyun                 set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
4034*4882a593Smuzhiyun                                crtc->desiredX, crtc->desiredY)) {
4035*4882a593Smuzhiyun                 if (!ign_err)
4036*4882a593Smuzhiyun                     return FALSE;
4037*4882a593Smuzhiyun                 else {
4038*4882a593Smuzhiyun                     success = FALSE;
4039*4882a593Smuzhiyun                     crtc->enabled = FALSE;
4040*4882a593Smuzhiyun                     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4041*4882a593Smuzhiyun                                "Failed to set the desired mode on connector %s\n",
4042*4882a593Smuzhiyun                                output->name);
4043*4882a593Smuzhiyun                 }
4044*4882a593Smuzhiyun             }
4045*4882a593Smuzhiyun         } else {
4046*4882a593Smuzhiyun             crtc->mode = crtc->desiredMode;
4047*4882a593Smuzhiyun             crtc->rotation = crtc->desiredRotation;
4048*4882a593Smuzhiyun             crtc->x = crtc->desiredX;
4049*4882a593Smuzhiyun             crtc->y = crtc->desiredY;
4050*4882a593Smuzhiyun             if (!drmmode_apply_transform(crtc))
4051*4882a593Smuzhiyun                 return FALSE;
4052*4882a593Smuzhiyun         }
4053*4882a593Smuzhiyun     }
4054*4882a593Smuzhiyun 
4055*4882a593Smuzhiyun     /* Validate leases on VT re-entry */
4056*4882a593Smuzhiyun     drmmode_validate_leases(pScrn);
4057*4882a593Smuzhiyun 
4058*4882a593Smuzhiyun     return success;
4059*4882a593Smuzhiyun }
4060*4882a593Smuzhiyun 
4061*4882a593Smuzhiyun static void
drmmode_load_palette(ScrnInfoPtr pScrn,int numColors,int * indices,LOCO * colors,VisualPtr pVisual)4062*4882a593Smuzhiyun drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
4063*4882a593Smuzhiyun                      int *indices, LOCO * colors, VisualPtr pVisual)
4064*4882a593Smuzhiyun {
4065*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4066*4882a593Smuzhiyun     uint16_t lut_r[256], lut_g[256], lut_b[256];
4067*4882a593Smuzhiyun     int index, j, i;
4068*4882a593Smuzhiyun     int c;
4069*4882a593Smuzhiyun 
4070*4882a593Smuzhiyun     for (c = 0; c < xf86_config->num_crtc; c++) {
4071*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[c];
4072*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4073*4882a593Smuzhiyun 
4074*4882a593Smuzhiyun         for (i = 0; i < 256; i++) {
4075*4882a593Smuzhiyun             lut_r[i] = drmmode_crtc->lut_r[i] << 6;
4076*4882a593Smuzhiyun             lut_g[i] = drmmode_crtc->lut_g[i] << 6;
4077*4882a593Smuzhiyun             lut_b[i] = drmmode_crtc->lut_b[i] << 6;
4078*4882a593Smuzhiyun         }
4079*4882a593Smuzhiyun 
4080*4882a593Smuzhiyun         switch (pScrn->depth) {
4081*4882a593Smuzhiyun         case 15:
4082*4882a593Smuzhiyun             for (i = 0; i < numColors; i++) {
4083*4882a593Smuzhiyun                 index = indices[i];
4084*4882a593Smuzhiyun                 for (j = 0; j < 8; j++) {
4085*4882a593Smuzhiyun                     lut_r[index * 8 + j] = colors[index].red << 6;
4086*4882a593Smuzhiyun                     lut_g[index * 8 + j] = colors[index].green << 6;
4087*4882a593Smuzhiyun                     lut_b[index * 8 + j] = colors[index].blue << 6;
4088*4882a593Smuzhiyun                 }
4089*4882a593Smuzhiyun             }
4090*4882a593Smuzhiyun             break;
4091*4882a593Smuzhiyun         case 16:
4092*4882a593Smuzhiyun             for (i = 0; i < numColors; i++) {
4093*4882a593Smuzhiyun                 index = indices[i];
4094*4882a593Smuzhiyun 
4095*4882a593Smuzhiyun                 if (i <= 31) {
4096*4882a593Smuzhiyun                     for (j = 0; j < 8; j++) {
4097*4882a593Smuzhiyun                         lut_r[index * 8 + j] = colors[index].red << 6;
4098*4882a593Smuzhiyun                         lut_b[index * 8 + j] = colors[index].blue << 6;
4099*4882a593Smuzhiyun                     }
4100*4882a593Smuzhiyun                 }
4101*4882a593Smuzhiyun 
4102*4882a593Smuzhiyun                 for (j = 0; j < 4; j++) {
4103*4882a593Smuzhiyun                     lut_g[index * 4 + j] = colors[index].green << 6;
4104*4882a593Smuzhiyun                 }
4105*4882a593Smuzhiyun             }
4106*4882a593Smuzhiyun             break;
4107*4882a593Smuzhiyun         default:
4108*4882a593Smuzhiyun             for (i = 0; i < numColors; i++) {
4109*4882a593Smuzhiyun                 index = indices[i];
4110*4882a593Smuzhiyun                 lut_r[index] = colors[index].red << 6;
4111*4882a593Smuzhiyun                 lut_g[index] = colors[index].green << 6;
4112*4882a593Smuzhiyun                 lut_b[index] = colors[index].blue << 6;
4113*4882a593Smuzhiyun             }
4114*4882a593Smuzhiyun             break;
4115*4882a593Smuzhiyun         }
4116*4882a593Smuzhiyun 
4117*4882a593Smuzhiyun         /* Make the change through RandR */
4118*4882a593Smuzhiyun         if (crtc->randr_crtc)
4119*4882a593Smuzhiyun             RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
4120*4882a593Smuzhiyun         else
4121*4882a593Smuzhiyun             crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
4122*4882a593Smuzhiyun     }
4123*4882a593Smuzhiyun }
4124*4882a593Smuzhiyun 
4125*4882a593Smuzhiyun static Bool
drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc,int num)4126*4882a593Smuzhiyun drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc, int num)
4127*4882a593Smuzhiyun {
4128*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4129*4882a593Smuzhiyun     uint64_t size;
4130*4882a593Smuzhiyun 
4131*4882a593Smuzhiyun     if (!drmmode_crtc->use_gamma_lut)
4132*4882a593Smuzhiyun         return TRUE;
4133*4882a593Smuzhiyun 
4134*4882a593Smuzhiyun     assert(drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id);
4135*4882a593Smuzhiyun 
4136*4882a593Smuzhiyun     size = drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value;
4137*4882a593Smuzhiyun 
4138*4882a593Smuzhiyun     if (size != crtc->gamma_size) {
4139*4882a593Smuzhiyun         ScrnInfoPtr pScrn = crtc->scrn;
4140*4882a593Smuzhiyun         uint16_t *gamma = malloc(3 * size * sizeof(uint16_t));
4141*4882a593Smuzhiyun 
4142*4882a593Smuzhiyun         if (gamma) {
4143*4882a593Smuzhiyun             free(crtc->gamma_red);
4144*4882a593Smuzhiyun 
4145*4882a593Smuzhiyun             crtc->gamma_size = size;
4146*4882a593Smuzhiyun             crtc->gamma_red = gamma;
4147*4882a593Smuzhiyun             crtc->gamma_green = gamma + size;
4148*4882a593Smuzhiyun             crtc->gamma_blue = gamma + size * 2;
4149*4882a593Smuzhiyun 
4150*4882a593Smuzhiyun             xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
4151*4882a593Smuzhiyun                            "Gamma ramp set to %ld entries on CRTC %d\n",
4152*4882a593Smuzhiyun                            size, num);
4153*4882a593Smuzhiyun         } else {
4154*4882a593Smuzhiyun             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4155*4882a593Smuzhiyun                        "Failed to allocate memory for %ld gamma ramp entries "
4156*4882a593Smuzhiyun                        "on CRTC %d.\n",
4157*4882a593Smuzhiyun                        size, num);
4158*4882a593Smuzhiyun             return FALSE;
4159*4882a593Smuzhiyun         }
4160*4882a593Smuzhiyun     }
4161*4882a593Smuzhiyun 
4162*4882a593Smuzhiyun     return TRUE;
4163*4882a593Smuzhiyun }
4164*4882a593Smuzhiyun 
4165*4882a593Smuzhiyun Bool
drmmode_setup_colormap(ScreenPtr pScreen,ScrnInfoPtr pScrn)4166*4882a593Smuzhiyun drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
4167*4882a593Smuzhiyun {
4168*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4169*4882a593Smuzhiyun     int i;
4170*4882a593Smuzhiyun 
4171*4882a593Smuzhiyun     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4172*4882a593Smuzhiyun               "Initializing kms color map for depth %d, %d bpc.\n",
4173*4882a593Smuzhiyun               pScrn->depth, pScrn->rgbBits);
4174*4882a593Smuzhiyun     if (!miCreateDefColormap(pScreen))
4175*4882a593Smuzhiyun         return FALSE;
4176*4882a593Smuzhiyun 
4177*4882a593Smuzhiyun     /* If the GAMMA_LUT property is available, replace the server's default
4178*4882a593Smuzhiyun      * gamma ramps with ones of the appropriate size. */
4179*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++)
4180*4882a593Smuzhiyun         if (!drmmode_crtc_upgrade_lut(xf86_config->crtc[i], i))
4181*4882a593Smuzhiyun             return FALSE;
4182*4882a593Smuzhiyun 
4183*4882a593Smuzhiyun     /* Adapt color map size and depth to color depth of screen. */
4184*4882a593Smuzhiyun     if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
4185*4882a593Smuzhiyun                              drmmode_load_palette, NULL,
4186*4882a593Smuzhiyun                              CMAP_PALETTED_TRUECOLOR |
4187*4882a593Smuzhiyun                              CMAP_RELOAD_ON_MODE_SWITCH))
4188*4882a593Smuzhiyun         return FALSE;
4189*4882a593Smuzhiyun     return TRUE;
4190*4882a593Smuzhiyun }
4191*4882a593Smuzhiyun 
4192*4882a593Smuzhiyun #define DRM_MODE_LINK_STATUS_GOOD       0
4193*4882a593Smuzhiyun #define DRM_MODE_LINK_STATUS_BAD        1
4194*4882a593Smuzhiyun 
4195*4882a593Smuzhiyun void
drmmode_update_kms_state(drmmode_ptr drmmode)4196*4882a593Smuzhiyun drmmode_update_kms_state(drmmode_ptr drmmode)
4197*4882a593Smuzhiyun {
4198*4882a593Smuzhiyun     ScrnInfoPtr scrn = drmmode->scrn;
4199*4882a593Smuzhiyun     drmModeResPtr mode_res;
4200*4882a593Smuzhiyun     xf86CrtcConfigPtr  config = XF86_CRTC_CONFIG_PTR(scrn);
4201*4882a593Smuzhiyun     int i, j;
4202*4882a593Smuzhiyun     Bool found = FALSE;
4203*4882a593Smuzhiyun     Bool changed = FALSE;
4204*4882a593Smuzhiyun 
4205*4882a593Smuzhiyun     /* Try to re-set the mode on all the connectors with a BAD link-state:
4206*4882a593Smuzhiyun      * This may happen if a link degrades and a new modeset is necessary, using
4207*4882a593Smuzhiyun      * different link-training parameters. If the kernel found that the current
4208*4882a593Smuzhiyun      * mode is not achievable anymore, it should have pruned the mode before
4209*4882a593Smuzhiyun      * sending the hotplug event. Try to re-set the currently-set mode to keep
4210*4882a593Smuzhiyun      * the display alive, this will fail if the mode has been pruned.
4211*4882a593Smuzhiyun      * In any case, we will send randr events for the Desktop Environment to
4212*4882a593Smuzhiyun      * deal with it, if it wants to.
4213*4882a593Smuzhiyun      */
4214*4882a593Smuzhiyun     for (i = 0; i < config->num_output; i++) {
4215*4882a593Smuzhiyun         xf86OutputPtr output = config->output[i];
4216*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output = output->driver_private;
4217*4882a593Smuzhiyun         xf86CrtcPtr crtc = output->crtc;
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun         if (!crtc)
4220*4882a593Smuzhiyun             continue;
4221*4882a593Smuzhiyun 
4222*4882a593Smuzhiyun         /* Update output status */
4223*4882a593Smuzhiyun         if (drmmode_output_detect(output) == XF86OutputStatusDisconnected)
4224*4882a593Smuzhiyun             continue;
4225*4882a593Smuzhiyun 
4226*4882a593Smuzhiyun         /* Get an updated view of the properties for the current connector and
4227*4882a593Smuzhiyun          * look for the link-status property
4228*4882a593Smuzhiyun          */
4229*4882a593Smuzhiyun         for (j = 0; j < drmmode_output->num_props; j++) {
4230*4882a593Smuzhiyun             drmmode_prop_ptr p = &drmmode_output->props[j];
4231*4882a593Smuzhiyun 
4232*4882a593Smuzhiyun             if (!strcmp(p->mode_prop->name, "link-status")) {
4233*4882a593Smuzhiyun                 if (p->value == DRM_MODE_LINK_STATUS_BAD) {
4234*4882a593Smuzhiyun                     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4235*4882a593Smuzhiyun                     drmmode_crtc->need_modeset = TRUE;
4236*4882a593Smuzhiyun 
4237*4882a593Smuzhiyun                     /* Delay re-set to dpms-on */
4238*4882a593Smuzhiyun                     if (drmmode_output->dpms != DPMSModeOn)
4239*4882a593Smuzhiyun                         break;
4240*4882a593Smuzhiyun 
4241*4882a593Smuzhiyun                     /* the connector got a link failure, re-set the current mode */
4242*4882a593Smuzhiyun                     drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
4243*4882a593Smuzhiyun                                            crtc->x, crtc->y);
4244*4882a593Smuzhiyun 
4245*4882a593Smuzhiyun                     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
4246*4882a593Smuzhiyun                                "hotplug event: connector %u's link-state is BAD, "
4247*4882a593Smuzhiyun                                "tried resetting the current mode. You may be left"
4248*4882a593Smuzhiyun                                "with a black screen if this fails...\n",
4249*4882a593Smuzhiyun                                drmmode_output->mode_output->connector_id);
4250*4882a593Smuzhiyun                 }
4251*4882a593Smuzhiyun                 break;
4252*4882a593Smuzhiyun             }
4253*4882a593Smuzhiyun         }
4254*4882a593Smuzhiyun     }
4255*4882a593Smuzhiyun 
4256*4882a593Smuzhiyun     mode_res = drmModeGetResources(drmmode->fd);
4257*4882a593Smuzhiyun     if (!mode_res)
4258*4882a593Smuzhiyun         goto out;
4259*4882a593Smuzhiyun 
4260*4882a593Smuzhiyun     if (mode_res->count_crtcs != config->num_crtc) {
4261*4882a593Smuzhiyun         /* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
4262*4882a593Smuzhiyun         goto out_free_res;
4263*4882a593Smuzhiyun     }
4264*4882a593Smuzhiyun 
4265*4882a593Smuzhiyun     /* figure out if we have gotten rid of any connectors
4266*4882a593Smuzhiyun        traverse old output list looking for outputs */
4267*4882a593Smuzhiyun     for (i = 0; i < config->num_output; i++) {
4268*4882a593Smuzhiyun         xf86OutputPtr output = config->output[i];
4269*4882a593Smuzhiyun         drmmode_output_private_ptr drmmode_output;
4270*4882a593Smuzhiyun 
4271*4882a593Smuzhiyun         drmmode_output = output->driver_private;
4272*4882a593Smuzhiyun         found = FALSE;
4273*4882a593Smuzhiyun         for (j = 0; j < mode_res->count_connectors; j++) {
4274*4882a593Smuzhiyun             if (mode_res->connectors[j] == drmmode_output->output_id) {
4275*4882a593Smuzhiyun                 found = TRUE;
4276*4882a593Smuzhiyun                 break;
4277*4882a593Smuzhiyun             }
4278*4882a593Smuzhiyun         }
4279*4882a593Smuzhiyun         if (found)
4280*4882a593Smuzhiyun             continue;
4281*4882a593Smuzhiyun 
4282*4882a593Smuzhiyun         drmModeFreeConnector(drmmode_output->mode_output);
4283*4882a593Smuzhiyun         drmmode_output->mode_output = NULL;
4284*4882a593Smuzhiyun         drmmode_output->output_id = -1;
4285*4882a593Smuzhiyun 
4286*4882a593Smuzhiyun         changed = TRUE;
4287*4882a593Smuzhiyun     }
4288*4882a593Smuzhiyun 
4289*4882a593Smuzhiyun     /* find new output ids we don't have outputs for */
4290*4882a593Smuzhiyun     for (i = 0; i < mode_res->count_connectors; i++) {
4291*4882a593Smuzhiyun         found = FALSE;
4292*4882a593Smuzhiyun 
4293*4882a593Smuzhiyun         for (j = 0; j < config->num_output; j++) {
4294*4882a593Smuzhiyun             xf86OutputPtr output = config->output[j];
4295*4882a593Smuzhiyun             drmmode_output_private_ptr drmmode_output;
4296*4882a593Smuzhiyun 
4297*4882a593Smuzhiyun             drmmode_output = output->driver_private;
4298*4882a593Smuzhiyun             if (mode_res->connectors[i] == drmmode_output->output_id) {
4299*4882a593Smuzhiyun                 found = TRUE;
4300*4882a593Smuzhiyun                 break;
4301*4882a593Smuzhiyun             }
4302*4882a593Smuzhiyun         }
4303*4882a593Smuzhiyun         if (found)
4304*4882a593Smuzhiyun             continue;
4305*4882a593Smuzhiyun 
4306*4882a593Smuzhiyun         changed = TRUE;
4307*4882a593Smuzhiyun         drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
4308*4882a593Smuzhiyun     }
4309*4882a593Smuzhiyun 
4310*4882a593Smuzhiyun     if (changed) {
4311*4882a593Smuzhiyun         RRSetChanged(xf86ScrnToScreen(scrn));
4312*4882a593Smuzhiyun         RRTellChanged(xf86ScrnToScreen(scrn));
4313*4882a593Smuzhiyun     }
4314*4882a593Smuzhiyun 
4315*4882a593Smuzhiyun out_free_res:
4316*4882a593Smuzhiyun 
4317*4882a593Smuzhiyun     /* Check to see if a lessee has disappeared */
4318*4882a593Smuzhiyun     drmmode_validate_leases(scrn);
4319*4882a593Smuzhiyun 
4320*4882a593Smuzhiyun     drmModeFreeResources(mode_res);
4321*4882a593Smuzhiyun out:
4322*4882a593Smuzhiyun     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
4323*4882a593Smuzhiyun }
4324*4882a593Smuzhiyun 
4325*4882a593Smuzhiyun #undef DRM_MODE_LINK_STATUS_BAD
4326*4882a593Smuzhiyun #undef DRM_MODE_LINK_STATUS_GOOD
4327*4882a593Smuzhiyun 
4328*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
4329*4882a593Smuzhiyun 
4330*4882a593Smuzhiyun static void
drmmode_handle_uevents(int fd,void * closure)4331*4882a593Smuzhiyun drmmode_handle_uevents(int fd, void *closure)
4332*4882a593Smuzhiyun {
4333*4882a593Smuzhiyun     drmmode_ptr drmmode = closure;
4334*4882a593Smuzhiyun     struct udev_device *dev;
4335*4882a593Smuzhiyun     Bool found = FALSE;
4336*4882a593Smuzhiyun 
4337*4882a593Smuzhiyun     while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
4338*4882a593Smuzhiyun         udev_device_unref(dev);
4339*4882a593Smuzhiyun         found = TRUE;
4340*4882a593Smuzhiyun     }
4341*4882a593Smuzhiyun     if (!found)
4342*4882a593Smuzhiyun         return;
4343*4882a593Smuzhiyun 
4344*4882a593Smuzhiyun     drmmode_update_kms_state(drmmode);
4345*4882a593Smuzhiyun }
4346*4882a593Smuzhiyun 
4347*4882a593Smuzhiyun #endif
4348*4882a593Smuzhiyun 
4349*4882a593Smuzhiyun void
drmmode_uevent_init(ScrnInfoPtr scrn,drmmode_ptr drmmode)4350*4882a593Smuzhiyun drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
4351*4882a593Smuzhiyun {
4352*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
4353*4882a593Smuzhiyun     struct udev *u;
4354*4882a593Smuzhiyun     struct udev_monitor *mon;
4355*4882a593Smuzhiyun 
4356*4882a593Smuzhiyun     u = udev_new();
4357*4882a593Smuzhiyun     if (!u)
4358*4882a593Smuzhiyun         return;
4359*4882a593Smuzhiyun     mon = udev_monitor_new_from_netlink(u, "udev");
4360*4882a593Smuzhiyun     if (!mon) {
4361*4882a593Smuzhiyun         udev_unref(u);
4362*4882a593Smuzhiyun         return;
4363*4882a593Smuzhiyun     }
4364*4882a593Smuzhiyun 
4365*4882a593Smuzhiyun     if (udev_monitor_filter_add_match_subsystem_devtype(mon,
4366*4882a593Smuzhiyun                                                         "drm",
4367*4882a593Smuzhiyun                                                         "drm_minor") < 0 ||
4368*4882a593Smuzhiyun         udev_monitor_enable_receiving(mon) < 0) {
4369*4882a593Smuzhiyun         udev_monitor_unref(mon);
4370*4882a593Smuzhiyun         udev_unref(u);
4371*4882a593Smuzhiyun         return;
4372*4882a593Smuzhiyun     }
4373*4882a593Smuzhiyun 
4374*4882a593Smuzhiyun     drmmode->uevent_handler =
4375*4882a593Smuzhiyun         xf86AddGeneralHandler(udev_monitor_get_fd(mon),
4376*4882a593Smuzhiyun                               drmmode_handle_uevents, drmmode);
4377*4882a593Smuzhiyun 
4378*4882a593Smuzhiyun     drmmode->uevent_monitor = mon;
4379*4882a593Smuzhiyun #endif
4380*4882a593Smuzhiyun }
4381*4882a593Smuzhiyun 
4382*4882a593Smuzhiyun void
drmmode_uevent_fini(ScrnInfoPtr scrn,drmmode_ptr drmmode)4383*4882a593Smuzhiyun drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
4384*4882a593Smuzhiyun {
4385*4882a593Smuzhiyun #ifdef CONFIG_UDEV_KMS
4386*4882a593Smuzhiyun     if (drmmode->uevent_handler) {
4387*4882a593Smuzhiyun         struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
4388*4882a593Smuzhiyun 
4389*4882a593Smuzhiyun         xf86RemoveGeneralHandler(drmmode->uevent_handler);
4390*4882a593Smuzhiyun 
4391*4882a593Smuzhiyun         udev_monitor_unref(drmmode->uevent_monitor);
4392*4882a593Smuzhiyun         udev_unref(u);
4393*4882a593Smuzhiyun     }
4394*4882a593Smuzhiyun #endif
4395*4882a593Smuzhiyun }
4396*4882a593Smuzhiyun 
4397*4882a593Smuzhiyun /* create front and cursor BOs */
4398*4882a593Smuzhiyun Bool
drmmode_create_initial_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4399*4882a593Smuzhiyun drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4400*4882a593Smuzhiyun {
4401*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(pScrn);
4402*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4403*4882a593Smuzhiyun     int width;
4404*4882a593Smuzhiyun     int height;
4405*4882a593Smuzhiyun     int bpp = ms->drmmode.kbpp;
4406*4882a593Smuzhiyun     int i;
4407*4882a593Smuzhiyun     int cpp = (bpp + 7) / 8;
4408*4882a593Smuzhiyun 
4409*4882a593Smuzhiyun     width = pScrn->virtualX;
4410*4882a593Smuzhiyun     height = pScrn->virtualY;
4411*4882a593Smuzhiyun 
4412*4882a593Smuzhiyun     if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
4413*4882a593Smuzhiyun         return FALSE;
4414*4882a593Smuzhiyun     if (drmmode_bo_import(drmmode, &drmmode->front_bo, &drmmode->fb_id) < 0)
4415*4882a593Smuzhiyun         return FALSE;
4416*4882a593Smuzhiyun     pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
4417*4882a593Smuzhiyun 
4418*4882a593Smuzhiyun     width = ms->cursor_width;
4419*4882a593Smuzhiyun     height = ms->cursor_height;
4420*4882a593Smuzhiyun     bpp = 32;
4421*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++) {
4422*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[i];
4423*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4424*4882a593Smuzhiyun 
4425*4882a593Smuzhiyun         drmmode_crtc->cursor_bo =
4426*4882a593Smuzhiyun             dumb_bo_create(drmmode->fd, width, height, bpp);
4427*4882a593Smuzhiyun     }
4428*4882a593Smuzhiyun     return TRUE;
4429*4882a593Smuzhiyun }
4430*4882a593Smuzhiyun 
4431*4882a593Smuzhiyun void *
drmmode_map_front_bo(drmmode_ptr drmmode)4432*4882a593Smuzhiyun drmmode_map_front_bo(drmmode_ptr drmmode)
4433*4882a593Smuzhiyun {
4434*4882a593Smuzhiyun     return drmmode_bo_map(drmmode, &drmmode->front_bo);
4435*4882a593Smuzhiyun }
4436*4882a593Smuzhiyun 
4437*4882a593Smuzhiyun void *
drmmode_map_slave_bo(drmmode_ptr drmmode,msPixmapPrivPtr ppriv)4438*4882a593Smuzhiyun drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
4439*4882a593Smuzhiyun {
4440*4882a593Smuzhiyun     int ret;
4441*4882a593Smuzhiyun 
4442*4882a593Smuzhiyun     if (ppriv->backing_bo->ptr)
4443*4882a593Smuzhiyun         return ppriv->backing_bo->ptr;
4444*4882a593Smuzhiyun 
4445*4882a593Smuzhiyun     ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
4446*4882a593Smuzhiyun     if (ret)
4447*4882a593Smuzhiyun         return NULL;
4448*4882a593Smuzhiyun 
4449*4882a593Smuzhiyun     return ppriv->backing_bo->ptr;
4450*4882a593Smuzhiyun }
4451*4882a593Smuzhiyun 
4452*4882a593Smuzhiyun Bool
drmmode_map_cursor_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4453*4882a593Smuzhiyun drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4454*4882a593Smuzhiyun {
4455*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4456*4882a593Smuzhiyun     int i, ret;
4457*4882a593Smuzhiyun 
4458*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++) {
4459*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[i];
4460*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4461*4882a593Smuzhiyun 
4462*4882a593Smuzhiyun         ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
4463*4882a593Smuzhiyun         if (ret)
4464*4882a593Smuzhiyun             return FALSE;
4465*4882a593Smuzhiyun     }
4466*4882a593Smuzhiyun     return TRUE;
4467*4882a593Smuzhiyun }
4468*4882a593Smuzhiyun 
4469*4882a593Smuzhiyun void
drmmode_free_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4470*4882a593Smuzhiyun drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4471*4882a593Smuzhiyun {
4472*4882a593Smuzhiyun     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4473*4882a593Smuzhiyun     int i;
4474*4882a593Smuzhiyun 
4475*4882a593Smuzhiyun     if (drmmode->fb_id) {
4476*4882a593Smuzhiyun         drmModeRmFB(drmmode->fd, drmmode->fb_id);
4477*4882a593Smuzhiyun         drmmode->fb_id = 0;
4478*4882a593Smuzhiyun     }
4479*4882a593Smuzhiyun 
4480*4882a593Smuzhiyun     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
4481*4882a593Smuzhiyun 
4482*4882a593Smuzhiyun     for (i = 0; i < xf86_config->num_crtc; i++) {
4483*4882a593Smuzhiyun         xf86CrtcPtr crtc = xf86_config->crtc[i];
4484*4882a593Smuzhiyun         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4485*4882a593Smuzhiyun 
4486*4882a593Smuzhiyun         dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
4487*4882a593Smuzhiyun         drmmode_destroy_flip_fb(crtc);
4488*4882a593Smuzhiyun     }
4489*4882a593Smuzhiyun }
4490*4882a593Smuzhiyun 
4491*4882a593Smuzhiyun /* ugly workaround to see if we can create 32bpp */
4492*4882a593Smuzhiyun void
drmmode_get_default_bpp(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int * depth,int * bpp)4493*4882a593Smuzhiyun drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
4494*4882a593Smuzhiyun                         int *bpp)
4495*4882a593Smuzhiyun {
4496*4882a593Smuzhiyun     drmModeResPtr mode_res;
4497*4882a593Smuzhiyun     uint64_t value;
4498*4882a593Smuzhiyun     struct dumb_bo *bo;
4499*4882a593Smuzhiyun     uint32_t fb_id;
4500*4882a593Smuzhiyun     int ret;
4501*4882a593Smuzhiyun 
4502*4882a593Smuzhiyun     /* 16 is fine */
4503*4882a593Smuzhiyun     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
4504*4882a593Smuzhiyun     if (!ret && (value == 16 || value == 8)) {
4505*4882a593Smuzhiyun         *depth = value;
4506*4882a593Smuzhiyun         *bpp = value;
4507*4882a593Smuzhiyun         return;
4508*4882a593Smuzhiyun     }
4509*4882a593Smuzhiyun 
4510*4882a593Smuzhiyun     *depth = 24;
4511*4882a593Smuzhiyun     mode_res = drmModeGetResources(drmmode->fd);
4512*4882a593Smuzhiyun     if (!mode_res)
4513*4882a593Smuzhiyun         return;
4514*4882a593Smuzhiyun 
4515*4882a593Smuzhiyun     if (mode_res->min_width == 0)
4516*4882a593Smuzhiyun         mode_res->min_width = 1;
4517*4882a593Smuzhiyun     if (mode_res->min_height == 0)
4518*4882a593Smuzhiyun         mode_res->min_height = 1;
4519*4882a593Smuzhiyun     /*create a bo */
4520*4882a593Smuzhiyun     bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
4521*4882a593Smuzhiyun                         32);
4522*4882a593Smuzhiyun     if (!bo) {
4523*4882a593Smuzhiyun         *bpp = 24;
4524*4882a593Smuzhiyun         goto out;
4525*4882a593Smuzhiyun     }
4526*4882a593Smuzhiyun 
4527*4882a593Smuzhiyun     ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
4528*4882a593Smuzhiyun                        24, 32, bo->pitch, bo->handle, &fb_id);
4529*4882a593Smuzhiyun 
4530*4882a593Smuzhiyun     if (ret) {
4531*4882a593Smuzhiyun         *bpp = 24;
4532*4882a593Smuzhiyun         dumb_bo_destroy(drmmode->fd, bo);
4533*4882a593Smuzhiyun         goto out;
4534*4882a593Smuzhiyun     }
4535*4882a593Smuzhiyun 
4536*4882a593Smuzhiyun     drmModeRmFB(drmmode->fd, fb_id);
4537*4882a593Smuzhiyun     *bpp = 32;
4538*4882a593Smuzhiyun 
4539*4882a593Smuzhiyun     dumb_bo_destroy(drmmode->fd, bo);
4540*4882a593Smuzhiyun  out:
4541*4882a593Smuzhiyun     drmModeFreeResources(mode_res);
4542*4882a593Smuzhiyun     return;
4543*4882a593Smuzhiyun }
4544*4882a593Smuzhiyun 
4545*4882a593Smuzhiyun /*
4546*4882a593Smuzhiyun  * We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
4547*4882a593Smuzhiyun  * is active. When a swcursor is active we disabe page-flipping.
4548*4882a593Smuzhiyun  */
4549*4882a593Smuzhiyun 
drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,ScrnInfoPtr scrn,int x,int y)4550*4882a593Smuzhiyun static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
4551*4882a593Smuzhiyun                                          ScrnInfoPtr scrn, int x, int y)
4552*4882a593Smuzhiyun {
4553*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4554*4882a593Smuzhiyun     CursorPtr cursor = sprite_priv->cursor;
4555*4882a593Smuzhiyun     Bool sprite_visible = sprite_priv->sprite_visible;
4556*4882a593Smuzhiyun 
4557*4882a593Smuzhiyun     if (cursor) {
4558*4882a593Smuzhiyun         x -= cursor->bits->xhot;
4559*4882a593Smuzhiyun         y -= cursor->bits->yhot;
4560*4882a593Smuzhiyun 
4561*4882a593Smuzhiyun         sprite_priv->sprite_visible =
4562*4882a593Smuzhiyun             x < scrn->virtualX && y < scrn->virtualY &&
4563*4882a593Smuzhiyun             (x + cursor->bits->width > 0) &&
4564*4882a593Smuzhiyun             (y + cursor->bits->height > 0);
4565*4882a593Smuzhiyun     } else {
4566*4882a593Smuzhiyun         sprite_priv->sprite_visible = FALSE;
4567*4882a593Smuzhiyun     }
4568*4882a593Smuzhiyun 
4569*4882a593Smuzhiyun     ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
4570*4882a593Smuzhiyun }
4571*4882a593Smuzhiyun 
drmmode_sprite_set_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)4572*4882a593Smuzhiyun static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4573*4882a593Smuzhiyun                                       CursorPtr pCursor, int x, int y)
4574*4882a593Smuzhiyun {
4575*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4576*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4577*4882a593Smuzhiyun     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4578*4882a593Smuzhiyun 
4579*4882a593Smuzhiyun     sprite_priv->cursor = pCursor;
4580*4882a593Smuzhiyun     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4581*4882a593Smuzhiyun 
4582*4882a593Smuzhiyun     ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
4583*4882a593Smuzhiyun }
4584*4882a593Smuzhiyun 
drmmode_sprite_move_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)4585*4882a593Smuzhiyun static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4586*4882a593Smuzhiyun                                        int x, int y)
4587*4882a593Smuzhiyun {
4588*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4589*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4590*4882a593Smuzhiyun     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4591*4882a593Smuzhiyun 
4592*4882a593Smuzhiyun     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4593*4882a593Smuzhiyun 
4594*4882a593Smuzhiyun     ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
4595*4882a593Smuzhiyun }
4596*4882a593Smuzhiyun 
drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4597*4882a593Smuzhiyun static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
4598*4882a593Smuzhiyun                                                   ScreenPtr pScreen,
4599*4882a593Smuzhiyun                                                   CursorPtr pCursor)
4600*4882a593Smuzhiyun {
4601*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4602*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4603*4882a593Smuzhiyun 
4604*4882a593Smuzhiyun     return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
4605*4882a593Smuzhiyun }
4606*4882a593Smuzhiyun 
drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4607*4882a593Smuzhiyun static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
4608*4882a593Smuzhiyun                                                     ScreenPtr pScreen,
4609*4882a593Smuzhiyun                                                     CursorPtr pCursor)
4610*4882a593Smuzhiyun {
4611*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4612*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4613*4882a593Smuzhiyun 
4614*4882a593Smuzhiyun     return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
4615*4882a593Smuzhiyun }
4616*4882a593Smuzhiyun 
drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,ScreenPtr pScreen)4617*4882a593Smuzhiyun static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
4618*4882a593Smuzhiyun                                                     ScreenPtr pScreen)
4619*4882a593Smuzhiyun {
4620*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4621*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4622*4882a593Smuzhiyun 
4623*4882a593Smuzhiyun     return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
4624*4882a593Smuzhiyun }
4625*4882a593Smuzhiyun 
drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,ScreenPtr pScreen)4626*4882a593Smuzhiyun static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
4627*4882a593Smuzhiyun                                                  ScreenPtr pScreen)
4628*4882a593Smuzhiyun {
4629*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4630*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4631*4882a593Smuzhiyun 
4632*4882a593Smuzhiyun     ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
4633*4882a593Smuzhiyun }
4634*4882a593Smuzhiyun 
4635*4882a593Smuzhiyun miPointerSpriteFuncRec drmmode_sprite_funcs = {
4636*4882a593Smuzhiyun     .RealizeCursor = drmmode_sprite_realize_realize_cursor,
4637*4882a593Smuzhiyun     .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
4638*4882a593Smuzhiyun     .SetCursor = drmmode_sprite_set_cursor,
4639*4882a593Smuzhiyun     .MoveCursor = drmmode_sprite_move_cursor,
4640*4882a593Smuzhiyun     .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
4641*4882a593Smuzhiyun     .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
4642*4882a593Smuzhiyun };
4643*4882a593Smuzhiyun 
4644*4882a593Smuzhiyun static void
drmmode_destroy_flip_fb(xf86CrtcPtr crtc)4645*4882a593Smuzhiyun drmmode_destroy_flip_fb(xf86CrtcPtr crtc)
4646*4882a593Smuzhiyun {
4647*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4648*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4649*4882a593Smuzhiyun     int i;
4650*4882a593Smuzhiyun 
4651*4882a593Smuzhiyun     for (i = 0; i < ARRAY_SIZE(drmmode_crtc->flip_fb); i++) {
4652*4882a593Smuzhiyun         drmmode_fb *fb = &drmmode_crtc->flip_fb[i];
4653*4882a593Smuzhiyun 
4654*4882a593Smuzhiyun         if (fb->fb_id)
4655*4882a593Smuzhiyun             drmModeRmFB(drmmode->fd, fb->fb_id);
4656*4882a593Smuzhiyun         fb->fb_id = 0;
4657*4882a593Smuzhiyun 
4658*4882a593Smuzhiyun         drmmode_bo_destroy(drmmode, &fb->bo);
4659*4882a593Smuzhiyun 
4660*4882a593Smuzhiyun         if (fb->pixmap)
4661*4882a593Smuzhiyun             fb->pixmap->drawable.pScreen->DestroyPixmap(fb->pixmap);
4662*4882a593Smuzhiyun         fb->pixmap = NULL;
4663*4882a593Smuzhiyun 
4664*4882a593Smuzhiyun         if (fb->damage)
4665*4882a593Smuzhiyun             DamageDestroy(fb->damage);
4666*4882a593Smuzhiyun         fb->damage = NULL;
4667*4882a593Smuzhiyun     }
4668*4882a593Smuzhiyun }
4669*4882a593Smuzhiyun 
4670*4882a593Smuzhiyun static Bool
drmmode_create_flip_fb(xf86CrtcPtr crtc)4671*4882a593Smuzhiyun drmmode_create_flip_fb(xf86CrtcPtr crtc)
4672*4882a593Smuzhiyun {
4673*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4674*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4675*4882a593Smuzhiyun     int i, width, height, bpp;
4676*4882a593Smuzhiyun 
4677*4882a593Smuzhiyun     width = crtc->mode.HDisplay;
4678*4882a593Smuzhiyun     height = crtc->mode.VDisplay;
4679*4882a593Smuzhiyun     bpp = drmmode->kbpp;
4680*4882a593Smuzhiyun 
4681*4882a593Smuzhiyun     drmmode_destroy_flip_fb(crtc);
4682*4882a593Smuzhiyun 
4683*4882a593Smuzhiyun     for (i = 0; i < ARRAY_SIZE(drmmode_crtc->flip_fb); i++) {
4684*4882a593Smuzhiyun         drmmode_fb *fb = &drmmode_crtc->flip_fb[i];
4685*4882a593Smuzhiyun 
4686*4882a593Smuzhiyun         if (!drmmode_create_bo(drmmode, &fb->bo, width, height, bpp))
4687*4882a593Smuzhiyun             goto fail;
4688*4882a593Smuzhiyun 
4689*4882a593Smuzhiyun         if (drmmode_bo_import(drmmode, &fb->bo, &fb->fb_id) < 0)
4690*4882a593Smuzhiyun             goto fail;
4691*4882a593Smuzhiyun     }
4692*4882a593Smuzhiyun 
4693*4882a593Smuzhiyun     return TRUE;
4694*4882a593Smuzhiyun 
4695*4882a593Smuzhiyun fail:
4696*4882a593Smuzhiyun     drmmode_destroy_flip_fb(crtc);
4697*4882a593Smuzhiyun     return FALSE;
4698*4882a593Smuzhiyun }
4699*4882a593Smuzhiyun 
4700*4882a593Smuzhiyun static Bool
drmmode_apply_transform(xf86CrtcPtr crtc)4701*4882a593Smuzhiyun drmmode_apply_transform(xf86CrtcPtr crtc)
4702*4882a593Smuzhiyun {
4703*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4704*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4705*4882a593Smuzhiyun     BoxRec box = {
4706*4882a593Smuzhiyun         .x1 = 0,
4707*4882a593Smuzhiyun         .y1 = 0,
4708*4882a593Smuzhiyun         .x2 = crtc->mode.HDisplay,
4709*4882a593Smuzhiyun         .y2 = crtc->mode.VDisplay,
4710*4882a593Smuzhiyun     };
4711*4882a593Smuzhiyun     int w, h;
4712*4882a593Smuzhiyun 
4713*4882a593Smuzhiyun     /* should always success */
4714*4882a593Smuzhiyun     xf86CrtcRotate(crtc);
4715*4882a593Smuzhiyun 
4716*4882a593Smuzhiyun     pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
4717*4882a593Smuzhiyun     w = box.x2 - box.x1;
4718*4882a593Smuzhiyun     h = box.y2 - box.y1;
4719*4882a593Smuzhiyun 
4720*4882a593Smuzhiyun     if ((w == crtc->mode.HDisplay && h == crtc->mode.VDisplay) ||
4721*4882a593Smuzhiyun         (w == crtc->mode.VDisplay && h == crtc->mode.HDisplay))
4722*4882a593Smuzhiyun         drmmode_crtc->is_scale = FALSE;
4723*4882a593Smuzhiyun     else
4724*4882a593Smuzhiyun         drmmode_crtc->is_scale = TRUE;
4725*4882a593Smuzhiyun 
4726*4882a593Smuzhiyun     /* fb flipping disabled or doing shared pixmap flipping */
4727*4882a593Smuzhiyun     if (!drmmode_crtc->can_flip_fb || drmmode_crtc->enable_flipping)
4728*4882a593Smuzhiyun         goto bail;
4729*4882a593Smuzhiyun 
4730*4882a593Smuzhiyun     crtc->driverIsPerformingTransform |= XF86DriverTransformOutput;
4731*4882a593Smuzhiyun 
4732*4882a593Smuzhiyun     /* should always success */
4733*4882a593Smuzhiyun     xf86CrtcRotate(crtc);
4734*4882a593Smuzhiyun 
4735*4882a593Smuzhiyun     if (!crtc->transform_in_use) {
4736*4882a593Smuzhiyun         crtc->driverIsPerformingTransform &= ~XF86DriverTransformOutput;
4737*4882a593Smuzhiyun 
4738*4882a593Smuzhiyun         if (drmmode->fb_flip_mode == DRMMODE_FB_FLIP_TRANSFORMED)
4739*4882a593Smuzhiyun             goto bail;
4740*4882a593Smuzhiyun     }
4741*4882a593Smuzhiyun 
4742*4882a593Smuzhiyun     if (!drmmode_create_flip_fb(crtc)) {
4743*4882a593Smuzhiyun         drmmode_crtc->can_flip_fb = FALSE;
4744*4882a593Smuzhiyun         goto fail;
4745*4882a593Smuzhiyun     }
4746*4882a593Smuzhiyun 
4747*4882a593Smuzhiyun     drmmode_crtc->flip_fb_enabled = TRUE;
4748*4882a593Smuzhiyun 
4749*4882a593Smuzhiyun     return TRUE;
4750*4882a593Smuzhiyun 
4751*4882a593Smuzhiyun fail:
4752*4882a593Smuzhiyun     drmmode_crtc->can_flip_fb = FALSE;
4753*4882a593Smuzhiyun 
4754*4882a593Smuzhiyun bail:
4755*4882a593Smuzhiyun     drmmode_destroy_flip_fb(crtc);
4756*4882a593Smuzhiyun     drmmode_crtc->flip_fb_enabled = FALSE;
4757*4882a593Smuzhiyun 
4758*4882a593Smuzhiyun     crtc->driverIsPerformingTransform &= ~XF86DriverTransformOutput;
4759*4882a593Smuzhiyun     return xf86CrtcRotate(crtc);
4760*4882a593Smuzhiyun }
4761*4882a593Smuzhiyun 
4762*4882a593Smuzhiyun static void
drmmode_flip_damage_destroy(DamagePtr damage,void * closure)4763*4882a593Smuzhiyun drmmode_flip_damage_destroy(DamagePtr damage, void *closure)
4764*4882a593Smuzhiyun {
4765*4882a593Smuzhiyun     drmmode_fb *fb = closure;
4766*4882a593Smuzhiyun 
4767*4882a593Smuzhiyun     if (fb->pixmap)
4768*4882a593Smuzhiyun         fb->pixmap->drawable.pScreen->DestroyPixmap(fb->pixmap);
4769*4882a593Smuzhiyun     fb->pixmap = NULL;
4770*4882a593Smuzhiyun 
4771*4882a593Smuzhiyun     fb->damage = NULL;
4772*4882a593Smuzhiyun }
4773*4882a593Smuzhiyun 
4774*4882a593Smuzhiyun static RegionPtr
drmmode_transform_region(xf86CrtcPtr crtc,RegionPtr src)4775*4882a593Smuzhiyun drmmode_transform_region(xf86CrtcPtr crtc, RegionPtr src)
4776*4882a593Smuzhiyun {
4777*4882a593Smuzhiyun #define MS_MAX_NUM_BOX 4
4778*4882a593Smuzhiyun     RegionPtr region = RegionCreate(NULL, 0);
4779*4882a593Smuzhiyun     BoxRec rects[MS_MAX_NUM_BOX];
4780*4882a593Smuzhiyun     BoxPtr box, rect;
4781*4882a593Smuzhiyun     Bool empty;
4782*4882a593Smuzhiyun     int n, i;
4783*4882a593Smuzhiyun 
4784*4882a593Smuzhiyun     if (!RegionNotEmpty(src))
4785*4882a593Smuzhiyun         return region;
4786*4882a593Smuzhiyun 
4787*4882a593Smuzhiyun     if (RegionNumRects(src) < MS_MAX_NUM_BOX) {
4788*4882a593Smuzhiyun         n = RegionNumRects(src);
4789*4882a593Smuzhiyun         box = RegionRects(src);
4790*4882a593Smuzhiyun     } else {
4791*4882a593Smuzhiyun         /* draw the extents rather than small rects */
4792*4882a593Smuzhiyun         n = 1;
4793*4882a593Smuzhiyun         box = RegionExtents(src);
4794*4882a593Smuzhiyun     }
4795*4882a593Smuzhiyun 
4796*4882a593Smuzhiyun     empty = TRUE;
4797*4882a593Smuzhiyun     for (i = 0; i < n; i++) {
4798*4882a593Smuzhiyun         rect = &rects[i];
4799*4882a593Smuzhiyun 
4800*4882a593Smuzhiyun         rect->x1 = box[i].x1 - crtc->filter_width / 2;
4801*4882a593Smuzhiyun         rect->x2 = box[i].x2 + crtc->filter_width / 2;
4802*4882a593Smuzhiyun         rect->y1 = box[i].y1 - crtc->filter_height / 2;
4803*4882a593Smuzhiyun         rect->y2 = box[i].y2 + crtc->filter_height / 2;
4804*4882a593Smuzhiyun         pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, rect);
4805*4882a593Smuzhiyun         rect->x1 = max(rect->x1, 0);
4806*4882a593Smuzhiyun         rect->y1 = max(rect->y1, 0);
4807*4882a593Smuzhiyun         rect->x2 = min(rect->x2, crtc->mode.HDisplay);
4808*4882a593Smuzhiyun         rect->y2 = min(rect->y2, crtc->mode.VDisplay);
4809*4882a593Smuzhiyun 
4810*4882a593Smuzhiyun         if (rect->x1 < rect->x2 && rect->y1 < rect->y2)
4811*4882a593Smuzhiyun             empty = FALSE;
4812*4882a593Smuzhiyun     }
4813*4882a593Smuzhiyun 
4814*4882a593Smuzhiyun     if (empty)
4815*4882a593Smuzhiyun         return region;
4816*4882a593Smuzhiyun 
4817*4882a593Smuzhiyun     RegionInitBoxes(region, rects, n);
4818*4882a593Smuzhiyun     return region;
4819*4882a593Smuzhiyun }
4820*4882a593Smuzhiyun 
4821*4882a593Smuzhiyun Bool
ms_copy_area(PixmapPtr pSrc,PixmapPtr pDst,pixman_f_transform_t * transform,RegionPtr clip)4822*4882a593Smuzhiyun ms_copy_area(PixmapPtr pSrc, PixmapPtr pDst,
4823*4882a593Smuzhiyun              pixman_f_transform_t *transform, RegionPtr clip)
4824*4882a593Smuzhiyun {
4825*4882a593Smuzhiyun     ScreenPtr screen = pSrc->drawable.pScreen;
4826*4882a593Smuzhiyun     PictFormatPtr format = PictureWindowFormat(screen->root);
4827*4882a593Smuzhiyun     PicturePtr src = NULL, dst = NULL;
4828*4882a593Smuzhiyun     pixman_transform_t t;
4829*4882a593Smuzhiyun     Bool ret = FALSE;
4830*4882a593Smuzhiyun     BoxPtr box;
4831*4882a593Smuzhiyun     int n, error;
4832*4882a593Smuzhiyun 
4833*4882a593Smuzhiyun     src = CreatePicture(None, &pSrc->drawable,
4834*4882a593Smuzhiyun                         format, 0L, NULL, serverClient, &error);
4835*4882a593Smuzhiyun     if (!src)
4836*4882a593Smuzhiyun         return FALSE;
4837*4882a593Smuzhiyun 
4838*4882a593Smuzhiyun     dst = CreatePicture(None, &pDst->drawable,
4839*4882a593Smuzhiyun                         format, 0L, NULL, serverClient, &error);
4840*4882a593Smuzhiyun     if (!dst)
4841*4882a593Smuzhiyun         goto out;
4842*4882a593Smuzhiyun 
4843*4882a593Smuzhiyun     if (transform) {
4844*4882a593Smuzhiyun         if (!pixman_transform_from_pixman_f_transform(&t, transform))
4845*4882a593Smuzhiyun             goto out;
4846*4882a593Smuzhiyun 
4847*4882a593Smuzhiyun         error = SetPictureTransform(src, &t);
4848*4882a593Smuzhiyun         if (error)
4849*4882a593Smuzhiyun             goto out;
4850*4882a593Smuzhiyun     }
4851*4882a593Smuzhiyun 
4852*4882a593Smuzhiyun     box = REGION_RECTS(clip);
4853*4882a593Smuzhiyun     n = REGION_NUM_RECTS(clip);
4854*4882a593Smuzhiyun 
4855*4882a593Smuzhiyun     while (n--) {
4856*4882a593Smuzhiyun         CompositePicture(PictOpSrc,
4857*4882a593Smuzhiyun                          src, NULL, dst,
4858*4882a593Smuzhiyun                          box->x1, box->y1, 0, 0, box->x1,
4859*4882a593Smuzhiyun                          box->y1, box->x2 - box->x1,
4860*4882a593Smuzhiyun                          box->y2 - box->y1);
4861*4882a593Smuzhiyun 
4862*4882a593Smuzhiyun         box++;
4863*4882a593Smuzhiyun     }
4864*4882a593Smuzhiyun 
4865*4882a593Smuzhiyun     ret = TRUE;
4866*4882a593Smuzhiyun out:
4867*4882a593Smuzhiyun     if (src)
4868*4882a593Smuzhiyun         FreePicture(src, None);
4869*4882a593Smuzhiyun     if (dst)
4870*4882a593Smuzhiyun         FreePicture(dst, None);
4871*4882a593Smuzhiyun 
4872*4882a593Smuzhiyun     return ret;
4873*4882a593Smuzhiyun }
4874*4882a593Smuzhiyun 
4875*4882a593Smuzhiyun static Bool
drmmode_update_fb(xf86CrtcPtr crtc,drmmode_fb * fb)4876*4882a593Smuzhiyun drmmode_update_fb(xf86CrtcPtr crtc, drmmode_fb *fb)
4877*4882a593Smuzhiyun {
4878*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4879*4882a593Smuzhiyun     ScrnInfoPtr scrn = crtc->scrn;
4880*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4881*4882a593Smuzhiyun     drmmode_ptr drmmode = &ms->drmmode;
4882*4882a593Smuzhiyun     ScreenPtr screen = xf86ScrnToScreen(scrn);
4883*4882a593Smuzhiyun     SourceValidateProcPtr SourceValidate = screen->SourceValidate;
4884*4882a593Smuzhiyun     RegionPtr dirty;
4885*4882a593Smuzhiyun     Bool ret;
4886*4882a593Smuzhiyun 
4887*4882a593Smuzhiyun     if (!fb->pixmap) {
4888*4882a593Smuzhiyun         void *data = drmmode_bo_map(&ms->drmmode, &fb->bo);
4889*4882a593Smuzhiyun         int pitch = drmmode_bo_get_pitch(&fb->bo);
4890*4882a593Smuzhiyun         fb->pixmap = drmmode_create_pixmap_header(screen,
4891*4882a593Smuzhiyun                                                   fb->bo.width,
4892*4882a593Smuzhiyun                                                   fb->bo.height,
4893*4882a593Smuzhiyun                                                   scrn->depth,
4894*4882a593Smuzhiyun                                                   ms->drmmode.kbpp,
4895*4882a593Smuzhiyun                                                   pitch, data);
4896*4882a593Smuzhiyun         if (!fb->pixmap)
4897*4882a593Smuzhiyun             return FALSE;
4898*4882a593Smuzhiyun 
4899*4882a593Smuzhiyun         if (!drmmode_set_pixmap_bo(&ms->drmmode, fb->pixmap, &fb->bo))
4900*4882a593Smuzhiyun             return FALSE;
4901*4882a593Smuzhiyun 
4902*4882a593Smuzhiyun         /* setup a damage to track dirty */
4903*4882a593Smuzhiyun         fb->damage = DamageCreate(NULL, drmmode_flip_damage_destroy,
4904*4882a593Smuzhiyun                                   DamageReportNone, TRUE, screen, fb);
4905*4882a593Smuzhiyun         DamageRegister(&screen->root->drawable, fb->damage);
4906*4882a593Smuzhiyun 
4907*4882a593Smuzhiyun         fb->need_clear = TRUE;
4908*4882a593Smuzhiyun     }
4909*4882a593Smuzhiyun 
4910*4882a593Smuzhiyun     /* scaled screens may not be able to map areas(due to precision) */
4911*4882a593Smuzhiyun     if (drmmode_crtc->is_scale && drmmode->exa)
4912*4882a593Smuzhiyun         fb->need_clear = TRUE;
4913*4882a593Smuzhiyun 
4914*4882a593Smuzhiyun     dirty = NULL;
4915*4882a593Smuzhiyun     if (fb->need_clear) {
4916*4882a593Smuzhiyun         BoxRec rect = {
4917*4882a593Smuzhiyun             .x1 = 0,
4918*4882a593Smuzhiyun             .y1 = 0,
4919*4882a593Smuzhiyun             .x2 = crtc->mode.HDisplay,
4920*4882a593Smuzhiyun             .y2 = crtc->mode.VDisplay,
4921*4882a593Smuzhiyun         };
4922*4882a593Smuzhiyun 
4923*4882a593Smuzhiyun         dirty = RegionCreate(&rect, 1);
4924*4882a593Smuzhiyun     } else {
4925*4882a593Smuzhiyun         RegionPtr region = DamageRegion(fb->damage);
4926*4882a593Smuzhiyun 
4927*4882a593Smuzhiyun         dirty = drmmode_transform_region(crtc, region);
4928*4882a593Smuzhiyun     }
4929*4882a593Smuzhiyun 
4930*4882a593Smuzhiyun     if (!RegionNotEmpty(dirty)) {
4931*4882a593Smuzhiyun         ret = TRUE;
4932*4882a593Smuzhiyun         goto out;
4933*4882a593Smuzhiyun     }
4934*4882a593Smuzhiyun 
4935*4882a593Smuzhiyun     screen->SourceValidate = miSourceValidate;
4936*4882a593Smuzhiyun     if (drmmode->exa)
4937*4882a593Smuzhiyun         ret = ms_exa_copy_area(screen->GetScreenPixmap(screen), fb->pixmap,
4938*4882a593Smuzhiyun                                &crtc->f_crtc_to_framebuffer, dirty);
4939*4882a593Smuzhiyun     else
4940*4882a593Smuzhiyun         ret = ms_copy_area(screen->GetScreenPixmap(screen), fb->pixmap,
4941*4882a593Smuzhiyun                            &crtc->f_crtc_to_framebuffer, dirty);
4942*4882a593Smuzhiyun     screen->SourceValidate = SourceValidate;
4943*4882a593Smuzhiyun 
4944*4882a593Smuzhiyun #ifdef GLAMOR_HAS_GBM
4945*4882a593Smuzhiyun     if (ms->drmmode.glamor)
4946*4882a593Smuzhiyun         glamor_finish(screen);
4947*4882a593Smuzhiyun #endif
4948*4882a593Smuzhiyun 
4949*4882a593Smuzhiyun     fb->need_clear = FALSE;
4950*4882a593Smuzhiyun     DamageEmpty(fb->damage);
4951*4882a593Smuzhiyun 
4952*4882a593Smuzhiyun     ret = TRUE;
4953*4882a593Smuzhiyun out:
4954*4882a593Smuzhiyun     RegionDestroy(dirty);
4955*4882a593Smuzhiyun     return ret;
4956*4882a593Smuzhiyun }
4957*4882a593Smuzhiyun 
4958*4882a593Smuzhiyun static void
drmmode_flip_fb_handler(modesettingPtr ms,uint64_t msc,uint64_t ust,void * data)4959*4882a593Smuzhiyun drmmode_flip_fb_handler(modesettingPtr ms, uint64_t msc,
4960*4882a593Smuzhiyun                         uint64_t ust, void *data)
4961*4882a593Smuzhiyun {
4962*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = data;
4963*4882a593Smuzhiyun 
4964*4882a593Smuzhiyun     drmmode_crtc->flipping = FALSE;
4965*4882a593Smuzhiyun }
4966*4882a593Smuzhiyun 
4967*4882a593Smuzhiyun static void
drmmode_flip_fb_abort(modesettingPtr ms,void * data)4968*4882a593Smuzhiyun drmmode_flip_fb_abort(modesettingPtr ms, void *data)
4969*4882a593Smuzhiyun {
4970*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = data;
4971*4882a593Smuzhiyun 
4972*4882a593Smuzhiyun     drmmode_crtc->flipping = FALSE;
4973*4882a593Smuzhiyun }
4974*4882a593Smuzhiyun 
4975*4882a593Smuzhiyun Bool
drmmode_flip_fb(xf86CrtcPtr crtc,int * timeout)4976*4882a593Smuzhiyun drmmode_flip_fb(xf86CrtcPtr crtc, int *timeout)
4977*4882a593Smuzhiyun {
4978*4882a593Smuzhiyun     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4979*4882a593Smuzhiyun     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4980*4882a593Smuzhiyun     ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
4981*4882a593Smuzhiyun     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
4982*4882a593Smuzhiyun     modesettingPtr ms = modesettingPTR(scrn);
4983*4882a593Smuzhiyun     drmmode_fb *fb;
4984*4882a593Smuzhiyun     struct timeval tv;
4985*4882a593Smuzhiyun     uint64_t now_ms, diff_ms;
4986*4882a593Smuzhiyun     int next_fb;
4987*4882a593Smuzhiyun 
4988*4882a593Smuzhiyun     if (!drmmode_crtc || !crtc->active || !drmmode_crtc_connected(crtc) ||
4989*4882a593Smuzhiyun         drmmode_crtc->dpms_mode != DPMSModeOn || drmmode_crtc->rotate_fb_id)
4990*4882a593Smuzhiyun         return TRUE;
4991*4882a593Smuzhiyun 
4992*4882a593Smuzhiyun     if (!drmmode_crtc->flip_fb_enabled)
4993*4882a593Smuzhiyun         return TRUE;
4994*4882a593Smuzhiyun 
4995*4882a593Smuzhiyun     gettimeofday(&tv, NULL);
4996*4882a593Smuzhiyun     now_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
4997*4882a593Smuzhiyun 
4998*4882a593Smuzhiyun     diff_ms = now_ms - drmmode_crtc->flipping_time_ms;
4999*4882a593Smuzhiyun 
5000*4882a593Smuzhiyun     /* handle flip timeout */
5001*4882a593Smuzhiyun     if (drmmode_crtc->flipping && diff_ms >= 50) {
5002*4882a593Smuzhiyun         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5003*4882a593Smuzhiyun                    "crtc-%d flip timeout!\n", drmmode_crtc->mode_crtc->crtc_id);
5004*4882a593Smuzhiyun         drmmode_crtc->flipping = FALSE;
5005*4882a593Smuzhiyun     }
5006*4882a593Smuzhiyun 
5007*4882a593Smuzhiyun     /* retry later if still flipping */
5008*4882a593Smuzhiyun     if (drmmode_crtc->flipping ||
5009*4882a593Smuzhiyun         drmmode->dri2_flipping || drmmode->present_flipping)
5010*4882a593Smuzhiyun         goto retry;
5011*4882a593Smuzhiyun 
5012*4882a593Smuzhiyun     if (drmmode_crtc->external_flipped) {
5013*4882a593Smuzhiyun         /* delay to exit external flip mode */
5014*4882a593Smuzhiyun         if (diff_ms < 100)
5015*4882a593Smuzhiyun             goto retry;
5016*4882a593Smuzhiyun     } else if (drmmode->fb_flip_rate) {
5017*4882a593Smuzhiyun         /* limit flip rate */
5018*4882a593Smuzhiyun         if (diff_ms < (1000 / drmmode->fb_flip_rate))
5019*4882a593Smuzhiyun             goto retry;
5020*4882a593Smuzhiyun     }
5021*4882a593Smuzhiyun 
5022*4882a593Smuzhiyun     /* keep the current fb if not dirty */
5023*4882a593Smuzhiyun     fb = &drmmode_crtc->flip_fb[drmmode_crtc->current_fb];
5024*4882a593Smuzhiyun     if (fb->damage && !fb->need_clear) {
5025*4882a593Smuzhiyun         RegionPtr region = DamageRegion(fb->damage);
5026*4882a593Smuzhiyun         RegionPtr dirty;
5027*4882a593Smuzhiyun         Bool ret;
5028*4882a593Smuzhiyun 
5029*4882a593Smuzhiyun         dirty = drmmode_transform_region(crtc, region);
5030*4882a593Smuzhiyun         if (dirty) {
5031*4882a593Smuzhiyun             ret = RegionNotEmpty(dirty);
5032*4882a593Smuzhiyun             RegionDestroy(dirty);
5033*4882a593Smuzhiyun             if (!ret)
5034*4882a593Smuzhiyun                 return TRUE;
5035*4882a593Smuzhiyun         }
5036*4882a593Smuzhiyun     }
5037*4882a593Smuzhiyun 
5038*4882a593Smuzhiyun     /* switch to the next fb */
5039*4882a593Smuzhiyun     next_fb = drmmode_crtc->current_fb + 1;
5040*4882a593Smuzhiyun     next_fb %= ARRAY_SIZE(drmmode_crtc->flip_fb);
5041*4882a593Smuzhiyun     fb = &drmmode_crtc->flip_fb[next_fb];
5042*4882a593Smuzhiyun     if (!drmmode_update_fb(crtc, fb)) {
5043*4882a593Smuzhiyun         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5044*4882a593Smuzhiyun                    "crtc-%d failed to update fb!\n",
5045*4882a593Smuzhiyun                    drmmode_crtc->mode_crtc->crtc_id);
5046*4882a593Smuzhiyun         return FALSE;
5047*4882a593Smuzhiyun     }
5048*4882a593Smuzhiyun 
5049*4882a593Smuzhiyun     if (!ms_do_pageflip_bo(screen, &fb->bo, drmmode_crtc,
5050*4882a593Smuzhiyun                            drmmode_crtc->vblank_pipe, crtc, ms->async_pageflip,
5051*4882a593Smuzhiyun                            drmmode_flip_fb_handler, drmmode_flip_fb_abort)) {
5052*4882a593Smuzhiyun         /* HACK: Workaround commit random interrupted case */
5053*4882a593Smuzhiyun         if (errno != EPERM) {
5054*4882a593Smuzhiyun             xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5055*4882a593Smuzhiyun                        "crtc-%d failed to flip(%s)!\n",
5056*4882a593Smuzhiyun                        drmmode_crtc->mode_crtc->crtc_id, strerror(errno));
5057*4882a593Smuzhiyun             return FALSE;
5058*4882a593Smuzhiyun         }
5059*4882a593Smuzhiyun     }
5060*4882a593Smuzhiyun 
5061*4882a593Smuzhiyun     drmmode_crtc->current_fb = next_fb;
5062*4882a593Smuzhiyun 
5063*4882a593Smuzhiyun     drmmode_crtc->flipping = TRUE;
5064*4882a593Smuzhiyun     drmmode_crtc->external_flipped = FALSE;
5065*4882a593Smuzhiyun 
5066*4882a593Smuzhiyun     /* take out FB syncing time from framerate control */
5067*4882a593Smuzhiyun     drmmode_crtc->flipping_time_ms = now_ms;
5068*4882a593Smuzhiyun 
5069*4882a593Smuzhiyun     return TRUE;
5070*4882a593Smuzhiyun 
5071*4882a593Smuzhiyun retry:
5072*4882a593Smuzhiyun     if (*timeout)
5073*4882a593Smuzhiyun         *timeout = 3;
5074*4882a593Smuzhiyun     return TRUE;
5075*4882a593Smuzhiyun }
5076