Skip to content

Commit b7a6357

Browse files
committed
drm: apple: Add preliminary VRR support
DCP supports VRR/Adaptive Sync, with its enormous firmware blob handling the low-level details for us. Display refresh rate is determined by the swap timing values provided to DCP on each swap request. VRR is activated by setting IOMFBadaptive_sync_parameter::minRR and then requesting a modeset. Wire up all of the required KMS properties to expose VRR to userspace, and tell DCP to enable it when supported. This enables VRR *unconditionally* for supported sinks, which will be fixed in a future commit. Signed-off-by: James Calligeros <[email protected]>
1 parent 9e24a01 commit b7a6357

5 files changed

Lines changed: 79 additions & 6 deletions

File tree

drivers/gpu/drm/apple/apple_drv.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,10 @@ static int apple_probe_per_dcp(struct device *dev,
335335
if (ret)
336336
return ret;
337337

338+
ret = drm_connector_attach_vrr_capable_property(&connector->base);
339+
if (ret)
340+
return ret;
341+
338342
connector->base.polled = DRM_CONNECTOR_POLL_HPD;
339343
connector->connected = false;
340344
connector->dcp = dcp;

drivers/gpu/drm/apple/iomfb.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ void dcp_hotplug(struct work_struct *work)
244244

245245
if (!connector->connected) {
246246
drm_edid_free(connector->drm_edid);
247+
drm_connector_set_vrr_capable_property(&connector->base, false);
247248
connector->drm_edid = NULL;
248249
}
249250

drivers/gpu/drm/apple/iomfb_template.c

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,9 @@ static u8 dcpep_cb_prop_chunk(struct apple_dcp *dcp,
546546
static bool dcpep_process_chunks(struct apple_dcp *dcp,
547547
struct dcp_set_dcpav_prop_end_req *req)
548548
{
549+
struct apple_connector *connector = dcp->connector;
549550
struct dcp_parse_ctx ctx;
550-
int ret;
551+
int ret, i;
551552

552553
if (!dcp->chunks.data) {
553554
dev_warn(dcp->dev, "ignoring spurious end\n");
@@ -589,6 +590,15 @@ static bool dcpep_process_chunks(struct apple_dcp *dcp,
589590
dcp_set_dimensions(dcp);
590591
}
591592

593+
if (connector) {
594+
for (i = 0; i < dcp->nr_modes; i++) {
595+
if (dcp->modes[i].vrr) {
596+
drm_connector_set_vrr_capable_property(&connector->base, true);
597+
break;
598+
}
599+
}
600+
}
601+
592602
return true;
593603
}
594604

@@ -1171,6 +1181,33 @@ static void complete_set_digital_out_mode(struct apple_dcp *dcp, void *data,
11711181
}
11721182
}
11731183

1184+
/* Changes to Adaptive Sync require a trip through set_digital_out_mode */
1185+
static void dcp_on_set_adaptive_sync(struct apple_dcp *dcp, void *out, void *cookie)
1186+
{
1187+
dcp_set_digital_out_mode(dcp, false, &dcp->mode,
1188+
complete_set_digital_out_mode, cookie);
1189+
}
1190+
1191+
static void dcp_set_adaptive_sync(struct apple_dcp *dcp, u32 rate, void *cookie)
1192+
{
1193+
struct dcp_set_parameter_dcp param = {
1194+
.param = IOMFBPARAM_ADAPTIVE_SYNC,
1195+
.value = {
1196+
rate, /* minRR */
1197+
0, /* mediaTargetRate */
1198+
0, /* Fractional Rate (?) */
1199+
0, /* unused */
1200+
},
1201+
#if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0)
1202+
.count = 3,
1203+
#else
1204+
.count = 1,
1205+
#endif
1206+
};
1207+
1208+
dcp_set_parameter_dcp(dcp, false, &param, dcp_on_set_adaptive_sync, cookie);
1209+
}
1210+
11741211
int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp,
11751212
struct drm_crtc_state *crtc_state)
11761213
{
@@ -1225,8 +1262,11 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp,
12251262

12261263
dcp->during_modeset = true;
12271264

1228-
dcp_set_digital_out_mode(dcp, false, &dcp->mode,
1229-
complete_set_digital_out_mode, cookie);
1265+
if (mode->vrr)
1266+
dcp_set_adaptive_sync(dcp, mode->min_vrr, cookie);
1267+
else
1268+
dcp_set_digital_out_mode(dcp, false, &dcp->mode,
1269+
complete_set_digital_out_mode, cookie);
12301270

12311271
/*
12321272
* The DCP firmware has an internal timeout of ~8 seconds for

drivers/gpu/drm/apple/parser.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,26 @@ static int parse_int(struct dcp_parse_ctx *handle, s64 *value)
194194
return 0;
195195
}
196196

197+
/*
198+
* DCP stores VRR refresh rates in 64-bit regions, however the number is actually an
199+
* unsigned Q16.16 with the high 32 bits unused.
200+
*/
201+
static int parse_q1616(struct dcp_parse_ctx *handle, u32 *value)
202+
{
203+
s64 dcp_int;
204+
u32 in;
205+
int ret;
206+
207+
ret = parse_int(handle, &dcp_int);
208+
if (ret)
209+
return ret;
210+
211+
in = dcp_int & 0xffffffff;
212+
213+
memcpy(value, &in, sizeof(*value));
214+
return 0;
215+
}
216+
197217
static int parse_bool(struct dcp_parse_ctx *handle, bool *b)
198218
{
199219
const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL);
@@ -454,6 +474,10 @@ static int parse_mode(struct dcp_parse_ctx *handle,
454474
ret = parse_dimension(it.handle, &horiz);
455475
else if (!strcmp(key, "VerticalAttributes"))
456476
ret = parse_dimension(it.handle, &vert);
477+
else if (!strcmp(key, "MinimumVariableRefreshRate"))
478+
ret = parse_q1616(it.handle, &out->min_vrr);
479+
else if (!strcmp(key, "MaximumVariableRefreshRate"))
480+
ret = parse_q1616(it.handle, &out->max_vrr);
457481
else if (!strcmp(key, "ColorModes"))
458482
ret = parse_color_modes(it.handle, out);
459483
else if (!strcmp(key, "ID"))
@@ -502,15 +526,17 @@ static int parse_mode(struct dcp_parse_ctx *handle,
502526
/*
503527
* HACK:
504528
* Mark the 120 Hz mode on j314/j316 (identified by resolution) as vrr.
505-
* We still do not know how to drive VRR but at least seetinng timestamps
506-
* in the the swap_surface message to non-zero values drives the display
507-
* at 120 fps.
529+
* Setting timestamps in the the swap_surface message to non-zero
530+
* values drives the display at 120 fps.
508531
*/
509532
if (vert.precise_sync_rate >> 16 == 120 &&
510533
((horiz.active == 3024 && vert.active == 1964) ||
511534
(horiz.active == 3456 && vert.active == 2234)))
512535
out->vrr = true;
513536

537+
if (out->min_vrr && out->max_vrr)
538+
out->vrr = true;
539+
514540
vert.active -= notch_height;
515541
vert.sync_width += notch_height;
516542

drivers/gpu/drm/apple/parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ struct dcp_display_mode {
9292
struct dcp_color_mode sdr;
9393
struct dcp_color_mode best;
9494
bool vrr;
95+
u32 min_vrr;
96+
u32 max_vrr;
9597
};
9698

9799
struct dimension {

0 commit comments

Comments
 (0)