diff --git a/drivers/gpu/drm/apple/apple_drv.c b/drivers/gpu/drm/apple/apple_drv.c index 345bcf4eb769fe..c7232f4916d055 100644 --- a/drivers/gpu/drm/apple/apple_drv.c +++ b/drivers/gpu/drm/apple/apple_drv.c @@ -507,6 +507,19 @@ static int apple_probe_per_dcp(struct device *dev, crtc->dcp = dcp; dcp_link(dcp, crtc, connector); + // gnome wants to see BT2020_RGB + u32 supported_colorspaces = + BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) | + BIT(DRM_MODE_COLORIMETRY_BT2020_RGB); + + // allow userspace to signal the color space used + if (!drm_mode_create_dp_colorspace_property(&connector->base, supported_colorspaces)) + drm_connector_attach_colorspace_property(&connector->base); + + // allow userspace to expose hdr output metadata. + // this indicates "hey i am rendering hdr content now" + drm_connector_attach_hdr_output_metadata_property(&connector->base); + return drm_connector_attach_encoder(&connector->base, &enc->base); } diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index 2c31d2a8cef09d..757a4fda223b14 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -91,6 +91,7 @@ struct dcp_brightness { struct backlight_device *bl_dev; u32 maximum; u32 dac; + u32 dac_hdr_restore; int nits; int scale; bool update; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index 72b6d0fd7460d7..99b99148370ea5 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -55,6 +55,19 @@ static bool unstable_edid = true; module_param(unstable_edid, bool, 0644); MODULE_PARM_DESC(unstable_edid, "Enable unstable EDID retrival support"); +u32 swap_hdr_colorspace = DCP_COLORSPACE_BG_BT2020; +module_param(swap_hdr_colorspace, uint, 0644); +MODULE_PARM_DESC(swap_hdr_colorspace, "Colorspace to use for primary swap with hdr"); + +u32 swap_hdr_transferfunc = DCP_XFER_FUNC_HDR; +module_param(swap_hdr_transferfunc, uint, 0644); +MODULE_PARM_DESC(swap_hdr_transferfunc, "Transfer function to use for primary swap with hdr"); + +u32 swap_hdr_brightness = 0x98FFFFC0; // max brightness observed with hdr content +module_param(swap_hdr_brightness, uint, 0644); +MODULE_PARM_DESC(swap_hdr_brightness, "Force the display into this brightness when in hdr mode"); + + /* copied and simplified from drm_vblank.c */ static void send_vblank_event(struct drm_device *dev, struct drm_pending_vblank_event *e, diff --git a/drivers/gpu/drm/apple/iomfb.c b/drivers/gpu/drm/apple/iomfb.c index 5b0f97253e3fc0..ebd01edca3be06 100644 --- a/drivers/gpu/drm/apple/iomfb.c +++ b/drivers/gpu/drm/apple/iomfb.c @@ -357,7 +357,22 @@ struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect) .h = drm_rect_height(rect) }; } -u32 drm_format_to_dcp(u32 drm) +u32 rgb2101010_dcp_format = fourcc_code('r', '0', '1', 'l'); +module_param(rgb2101010_dcp_format, uint, 0644); +MODULE_PARM_DESC(rgb2101010_dcp_format, "dcp color format for DRM_FORMAT_XRGB2101010 in hdr"); + +u32 drm_format_to_dcp_hdr(u32 drm) +{ + switch (drm) { + case DRM_FORMAT_XRGB2101010: + return rgb2101010_dcp_format; + } + + pr_warn("DRM format %X not supported in DCP with HDR\n", drm); + return 0; +} + +u32 drm_format_to_dcp_sdr(u32 drm) { switch (drm) { case DRM_FORMAT_XRGB8888: @@ -372,7 +387,7 @@ u32 drm_format_to_dcp(u32 drm) return fourcc_code('r', '0', '3', 'w'); } - pr_warn("DRM format %X not supported in DCP\n", drm); + pr_warn("DRM format %X not supported in DCP with SDR\n", drm); return 0; } @@ -408,6 +423,41 @@ int dcp_get_modes(struct drm_connector *connector) apple_connector->drm_edid = edid; } } + + if (!apple_connector->drm_edid && dcp->nr_modes && dcp_has_panel(dcp)) { + // HACK: fake some edid entry for the iinternal panel. This value here is actually for a + // totally different screen, but it has the hdr property set. that property is required + // for gnome and kde to display the "enable hdr" toggle. + static const u8 edidbuf[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x34, 0xa9, 0x1c, 0xd1, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x19, 0x01, 0x03, 0x80, 0xdd, 0x7d, 0x78, + 0x0a, 0x06, 0x12, 0xaf, 0x51, 0x4e, 0xad, 0x24, 0x0b, 0x4c, 0x51, 0x20, + 0x08, 0x00, 0xa9, 0xc0, 0xa9, 0x40, 0x90, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xe8, 0x00, 0x30, 0xf2, 0x70, + 0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x1c, 0x00, 0x74, 0x00, 0x00, 0x1e, + 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, + 0x1c, 0x00, 0x74, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x45, + 0x54, 0x2d, 0x4d, 0x44, 0x4e, 0x48, 0x4d, 0x31, 0x30, 0x0a, 0x20, 0x20, + 0x00, 0x00, 0x00, 0xfd, 0x00, 0x17, 0x79, 0x0f, 0x96, 0x3c, 0x00, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x75, 0x02, 0x03, 0x41, 0xb1, + 0x57, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x66, 0x65, 0x64, 0x63, 0x62, 0x3f, + 0x10, 0x1f, 0x05, 0x14, 0x22, 0x21, 0x20, 0x04, 0x13, 0x02, 0x11, 0x01, + 0xe3, 0x05, 0xe0, 0x00, 0x6e, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x38, 0x3c, + 0x20, 0x08, 0x80, 0x01, 0x02, 0x03, 0x04, 0x67, 0xd8, 0x5d, 0xc4, 0x01, + 0x78, 0x80, 0x03, 0xe2, 0x00, 0xff, 0xe2, 0x0f, 0x63, 0xe3, 0x06, 0x0d, + 0x01, 0x28, 0x3c, 0x80, 0xa0, 0x70, 0xb0, 0x23, 0x40, 0x30, 0x20, 0x36, + 0x00, 0x66, 0x00, 0x64, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x5a + }; + + pr_info("injecting fake edid buf\n"); + const struct drm_edid *edid = drm_edid_alloc(edidbuf, sizeof(edidbuf)); + drm_connector_update_edid_property(&dcp->connector->base, drm_edid_raw(edid)); + } + if (dcp->nr_modes && apple_connector->drm_edid) drm_edid_connector_update(connector, apple_connector->drm_edid); diff --git a/drivers/gpu/drm/apple/iomfb_internal.h b/drivers/gpu/drm/apple/iomfb_internal.h index 09f8857d30c341..0866436fe99163 100644 --- a/drivers/gpu/drm/apple/iomfb_internal.h +++ b/drivers/gpu/drm/apple/iomfb_internal.h @@ -116,7 +116,8 @@ void dcp_ack(struct apple_dcp *dcp, enum dcp_context_id context); */ struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect); -u32 drm_format_to_dcp(u32 drm); +u32 drm_format_to_dcp_sdr(u32 drm); +u32 drm_format_to_dcp_hdr(u32 drm); /* The user may own drm_display_mode, so we need to search for our copy */ struct dcp_display_mode *lookup_mode(struct apple_dcp *dcp, diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 0a1b9495128562..fec552df49bdb1 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1264,6 +1264,24 @@ int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, return 0; } +extern u32 swap_hdr_colorspace; +extern u32 swap_hdr_transferfunc; +extern u32 swap_hdr_brightness; + +static bool drm_format_maybe_hdr(u32 format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return false; + + default: + return true; + } +} + void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_plane *plane; @@ -1374,11 +1392,47 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru if (obj) req->surf_iova[l] = obj->dma_addr + fb->offsets[0]; + u32 format = drm_format_to_dcp_sdr(fb->format->format); + u32 colorspace = DCP_COLORSPACE_NATIVE; + u32 transferfunc = DCP_XFER_FUNC_SDR; + + if (plane->type == DRM_PLANE_TYPE_PRIMARY && drm_format_maybe_hdr(fb->format->format)) { + if (dcp->connector->base.state->hdr_output_metadata) { + // HACK: hard code the values kwin & mutter use: + // DCP_COLORSPACE_BT2020 + // DCP_XFER_FUNC_HDR # looks like PQ + // + // TODO need to pick the current colorspace and + // the transfer function from the drm properties + // (colorspace + HDR_OUTPUT_METADATA). + // + // For testing: You can set swap_hdr_colorspace + // and swap_hdr_transferfunc as parameters from + // userspace to try out different values. + // + colorspace = swap_hdr_colorspace; + transferfunc = swap_hdr_transferfunc; + format = drm_format_to_dcp_hdr(fb->format->format); + + // force brightness to full for now. + if (!dcp->brightness.dac_hdr_restore && swap_hdr_brightness) { + dcp->brightness.dac_hdr_restore = dcp->brightness.dac; + dcp->brightness.dac = swap_hdr_brightness; + dcp->brightness.update = true; + } + } else if (dcp->brightness.dac_hdr_restore) { + // restore pre hdr brightness + dcp->brightness.dac = dcp->brightness.dac_hdr_restore; + dcp->brightness.dac_hdr_restore = 0; + dcp->brightness.update = true; + } + } + req->surf[l] = (struct DCP_FW_NAME(dcp_surface)){ .is_premultiplied = is_premultiplied, - .format = drm_format_to_dcp(fb->format->format), - .xfer_func = DCP_XFER_FUNC_SDR, - .colorspace = DCP_COLORSPACE_NATIVE, + .format = format, + .xfer_func = transferfunc, + .colorspace = colorspace, .stride = fb->pitches[0], .width = fb->width, .height = fb->height,