Skip to content

Commit 049e881

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. This will *not* trigger a full modeset, and instead merely activates VRR if it is supported by the sink. 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 adf1383 commit 049e881

5 files changed

Lines changed: 59 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

@@ -1172,6 +1182,33 @@ static void complete_set_digital_out_mode(struct apple_dcp *dcp, void *data,
11721182
}
11731183
}
11741184

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

12271264
dcp->during_modeset = true;
12281265

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

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

drivers/gpu/drm/apple/parser.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,10 @@ static int parse_mode(struct dcp_parse_ctx *handle,
454454
ret = parse_dimension(it.handle, &horiz);
455455
else if (!strcmp(key, "VerticalAttributes"))
456456
ret = parse_dimension(it.handle, &vert);
457+
else if (!strcmp(key, "MinimumVariableRefreshRate"))
458+
ret = parse_int(it.handle, &out->min_vrr);
459+
else if (!strcmp(key, "MaximumVariableRefreshRate"))
460+
ret = parse_int(it.handle, &out->max_vrr);
457461
else if (!strcmp(key, "ColorModes"))
458462
ret = parse_color_modes(it.handle, out);
459463
else if (!strcmp(key, "ID"))
@@ -502,15 +506,17 @@ static int parse_mode(struct dcp_parse_ctx *handle,
502506
/*
503507
* HACK:
504508
* 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.
509+
* Setting timestamps in the the swap_surface message to non-zero
510+
* values drives the display at 120 fps.
508511
*/
509512
if (vert.precise_sync_rate >> 16 == 120 &&
510513
((horiz.active == 3024 && vert.active == 1964) ||
511514
(horiz.active == 3456 && vert.active == 2234)))
512515
out->vrr = true;
513516

517+
if (out->min_vrr && out->max_vrr)
518+
out->vrr = true;
519+
514520
vert.active -= notch_height;
515521
vert.sync_width += notch_height;
516522

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+
s64 min_vrr;
96+
s64 max_vrr;
9597
};
9698

9799
struct dimension {

0 commit comments

Comments
 (0)