Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions drivers/gpu/drm/apple/afk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1491,13 +1491,23 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel,
}
ret = parse_epic_service_init(&ctx, &epic_name, &epic_class, &epic_unit,
ep->dcp->fw_compat == DCP_FIRMWARE_H17P);
if (ret) {
if (ret == -ENOENT &&
ep->dcp->hw.iomfb_method_profile == DCP_IOMFB_METHODS_H17G) {
/*
* M5 (H17G) announces powerlog-service with only
* ep-has-desc-mgr and interface-id; match it by the
* announced name, as for props-less announces.
*/
epic_name = NULL;
epic_class = NULL;
} else if (ret) {
dev_err(ep->dcp->dev,
"AFK[ep:%02x]: failed to extract init props: %d\n",
ep->endpoint, ret);
return;
} else {
service_name = epic_class;
}
service_name = epic_class;
} else {
service_name = name;
}
Expand Down
11 changes: 8 additions & 3 deletions drivers/gpu/drm/apple/apple_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,12 @@ static int apple_drm_fbdev_probe(struct drm_fb_helper *helper,
if (t8132_ext_crtc(crtc))
continue;
dcp = platform_get_drvdata(to_apple_crtc(crtc)->dcp);
if (dcp->fw_compat == DCP_FIRMWARE_H17P &&
dcp->hw.iomfb_method_profile != DCP_IOMFB_METHODS_H17G) {
/* H17P applies the stored fourth byte as straight alpha. */
if (dcp->fw_compat == DCP_FIRMWARE_H17P) {
/*
* H17P applies the stored fourth byte as straight alpha,
* the H17G (M5) profile too: an XRGB console with X = 0
* stays black. ARGB makes fbcon write it opaque.
*/
sizes->surface_bpp = 32;
sizes->surface_depth = 32;
break;
Expand Down Expand Up @@ -915,6 +918,8 @@ static int apple_probe_per_dcp(struct device *dev,
planes[zpos] = apple_plane_init(drm, 1U << num, surf,
supports_l10r,
supports_xrgb2101010,
dcp_data->hw.iomfb_method_profile ==
DCP_IOMFB_METHODS_H17G,
plane_type, interchange,
supports_premultiplied);
}
Expand Down
23 changes: 23 additions & 0 deletions drivers/gpu/drm/apple/dcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -4086,6 +4086,18 @@ static void __maybe_unused dcp_sleep(struct apple_dcp *dcp)

#define DCP_BL_FALLBACK_DELAY msecs_to_jiffies(2000)

/*
* H17G (M5) internal panel: a pipe stop never comes back (see
* iomfb_blank_h17p()), so DPMS blanks the panel and keeps the pipe running.
*/
static bool dcp_h17g_panel(struct apple_dcp *dcp)
{
return dcp->fw_compat == DCP_FIRMWARE_H17P &&
dcp->hw.iomfb_method_profile == DCP_IOMFB_METHODS_H17G &&
dcp->connector_type == DRM_MODE_CONNECTOR_eDP &&
dcp_has_panel(dcp);
}

static bool dcp_uses_soft_dpms(struct apple_dcp *dcp)
{
/* The 14.7 panel has its own known-level blank and restore hooks. */
Expand Down Expand Up @@ -4176,6 +4188,12 @@ void dcp_poweron(struct platform_device *pdev)
return;
}

if (dcp_h17g_panel(dcp)) {
/* The pipe never stopped; the next swap restores the level. */
dcp->brightness.update = true;
return;
}

if (dcp_is_typec_output(dcp)) {
/* This CRTC now owns the current Type-C display session. */
scoped_guard(mutex, &dcp->hpd_mutex)
Expand Down Expand Up @@ -4303,6 +4321,11 @@ void dcp_poweroff(struct platform_device *pdev)
return;
}

if (dcp_h17g_panel(dcp)) {
iomfb_blank_h17p(dcp);
return;
}

if (dcp->avep)
av_service_disconnect(dcp);

Expand Down
44 changes: 27 additions & 17 deletions drivers/gpu/drm/apple/iomfb_h17p.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,30 +168,37 @@ static u64 iomfb_nits_binary64_h17p(u32 nits)
return value;
}

void iomfb_encode_backlight_h17p(struct dcp_present_h17p *wire, u32 nits,
u32 maximum, bool update)
/* @swap is the swap record of a present; H17G sends it unserialized. */
void iomfb_encode_backlight_swap_h17p(u8 *swap, u32 nits, u32 maximum,
bool update)
{
u64 ceiling = iomfb_nits_binary64_h17p(maximum);
u64 unity = iomfb_nits_binary64_h17p(1);

/* This profile does not use the older DAC/power words. */
memset(wire->swap + 0x32f, 0, 0xd);
memset(wire->swap + 0x354, 0, 0x9a);
memset(swap + 0x32f, 0, 0xd);
memset(swap + 0x354, 0, 0x9a);
/* The ceiling pair must remain valid even on a brightness-idle frame. */
put_unaligned_le64(ceiling, wire->swap + 0x36e);
put_unaligned_le64(ceiling, wire->swap + 0x376);
put_unaligned_le64(ceiling, swap + 0x36e);
put_unaligned_le64(ceiling, swap + 0x376);
if (!update)
return;

/* Linux brightness changes and soft DPMS use the same activation bytes. */
put_unaligned_le32(1, wire->swap + 0x354);
wire->swap[0x358] = 1;
wire->swap[0x359] = 1;
wire->swap[0x35a] = 1;
put_unaligned_le16(1, wire->swap + 0x35c);
put_unaligned_le64(iomfb_nits_binary64_h17p(nits), wire->swap + 0x35e);
put_unaligned_le64(unity, wire->swap + 0x37e);
put_unaligned_le64(unity, wire->swap + 0x3e6);
put_unaligned_le32(1, swap + 0x354);
swap[0x358] = 1;
swap[0x359] = 1;
swap[0x35a] = 1;
put_unaligned_le16(1, swap + 0x35c);
put_unaligned_le64(iomfb_nits_binary64_h17p(nits), swap + 0x35e);
put_unaligned_le64(unity, swap + 0x37e);
put_unaligned_le64(unity, swap + 0x3e6);
}

void iomfb_encode_backlight_h17p(struct dcp_present_h17p *wire, u32 nits,
u32 maximum, bool update)
{
iomfb_encode_backlight_swap_h17p(wire->swap, nits, maximum, update);
}

static const struct dcp_method_entry dcp_methods[dcpep_num_methods] = {
Expand Down Expand Up @@ -308,9 +315,12 @@ static bool trampoline_get_frequency_h17p(struct apple_dcp *dcp, int tag,
static bool trampoline_analytics_h17p(struct apple_dcp *dcp, int tag,
void *out, void *in)
{
if (dcp->hw.iomfb_method_profile == DCP_IOMFB_METHODS_H17G)
return trampoline_zero(dcp, tag, out, in);

/*
* H17G (M5) needs the same empty dictionary. A zeroed reply fails the
* firmware's OSDictionary deserialization ("OSDictionary
* deserialization failed" in the DCP crash log) and the DCP panics
* with "app NMI" one hour after boot.
*/
trace_iomfb_callback(dcp, tag, __func__);
/* The dispatcher has validated the D114 reply size. */
memset(out, 0, 0x1004);
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/apple/iomfb_h17p.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ static inline struct dcp_apply_property_h17p dcp_opaque_x_property_h17p(void)
};
}

void iomfb_blank_h17p(struct apple_dcp *dcp);
void iomfb_encode_backlight_swap_h17p(u8 *swap, u32 nits, u32 maximum,
bool update);
void iomfb_encode_backlight_h17p(struct dcp_present_h17p *wire, u32 nits,
u32 maximum, bool update);

Expand Down
54 changes: 54 additions & 0 deletions drivers/gpu/drm/apple/iomfb_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -2471,6 +2471,44 @@ void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp)
dev_info(dcp->dev, "dcp_poweroff() done\n");
}

#if DCP_FW_VERSION(26, 0, 0) <= DCP_FW_VER && DCP_FW_VER < DCP_FW_VERSION(27, 0, 0)
/*
* H17G (M5) internal panel DPMS off. A pipe stop does not come back:
* setPowerState(0) times out and the next setPowerState(1) is never
* answered. Blank instead and keep the pipe running: a black,
* surface-free swap that also takes the backlight to 0 nits. The next CRTC
* enable presents the scanout and the brightness again.
*/
void DCP_FW_NAME(iomfb_blank)(struct apple_dcp *dcp)
{
struct DCP_FW_NAME(dcp_swap_start_req) swap_req = { 0 };
typeof(DCP_FW_UNION(dcp->swap)) *swap = &DCP_FW_UNION(dcp->swap);
struct dcp_swap_cookie *cookie;
unsigned long ret;

cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie)
return;
cookie->status = ~0U;
init_completion(&cookie->done);
kref_init(&cookie->refcount);
/* increase refcount to ensure the receiver has a reference */
kref_get(&cookie->refcount);

dcp_prepare_clear_swap(dcp, swap);
if (dcp_has_panel(dcp))
iomfb_encode_backlight_swap_h17p((u8 *)&swap->swap, 0,
dcp->brightness.maximum, true);

dcp_swap_start(dcp, false, &swap_req, dcp_swap_clear_started, cookie);
ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(500));
if (!ret || READ_ONCE(cookie->status))
dev_warn(dcp->dev, "%s: blank swap %s\n", __func__,
ret ? "failed" : "timed out");
kref_put(&cookie->refcount, release_swap_cookie);
}
#endif

static void last_client_closed_sleep(struct apple_dcp *dcp, void *out, void *cookie)
{
#if DCP_FW_DESKTOP_26(DCP_FW_VER)
Expand Down Expand Up @@ -3848,13 +3886,29 @@ void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, stru
dcp->hw.iomfb_method_profile == DCP_IOMFB_METHODS_H17G;
#endif
if (update_brightness) {
#if DCP_FW_H17(DCP_FW_VER)
/*
* H17G firmware ignores the DAC words and takes nits in the
* same swap bytes as H17P. Without a requested or reported
* level, send nothing rather than 0 nits.
*/
int nits = dcp->brightness.bl_dev ?
dcp->brightness.bl_dev->props.brightness :
dcp->brightness.nits;

if (nits > 0)
iomfb_encode_backlight_swap_h17p((u8 *)&req->swap, nits,
dcp->brightness.maximum,
true);
#else
#if DCP_FW_LAYOUT_14_7(DCP_FW_VER)
req->swap.bl_update = 1;
#else
req->swap.bl_unk = 1;
#endif
req->swap.bl_value = dcp->brightness.dac;
req->swap.bl_power = 0x40;
#endif
dcp->brightness.update = false;
}
#endif
Expand Down
12 changes: 11 additions & 1 deletion drivers/gpu/drm/apple/plane.c
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ struct drm_plane *apple_plane_init(struct drm_device *dev,
u32 iomfb_surf,
bool supports_l10r,
bool supports_xrgb2101010,
bool xrgb_is_alpha,
enum drm_plane_type type,
bool interchange,
bool premultiplied)
Expand All @@ -755,7 +756,16 @@ struct drm_plane *apple_plane_init(struct drm_device *dev,

switch (type) {
case DRM_PLANE_TYPE_PRIMARY:
if (supports_l10r && supports_xrgb2101010) {
if (xrgb_is_alpha) {
/*
* The firmware blends the X byte as alpha and ignores the
* opaque-X property: offer only formats with alpha, so that
* compositors write it instead of leaving whatever the
* renderer stored there.
*/
fmts = dcp_overlay_formats;
num_fmts = ARRAY_SIZE(dcp_overlay_formats);
} else if (supports_l10r && supports_xrgb2101010) {
fmts = dcp_primary_formats;
num_fmts = ARRAY_SIZE(dcp_primary_formats);
} else if (supports_l10r) {
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/apple/plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct drm_plane *apple_plane_init(struct drm_device *dev,
u32 iomfb_surf,
bool supports_l10r,
bool supports_xrgb2101010,
bool xrgb_is_alpha,
enum drm_plane_type type,
bool interchange,
bool premultiplied);
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/apple/systemep.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ static int powerlog_report(struct apple_epic_service *service, enum epic_subtype
}

dcp->brightness.nits = mnits.millinits / 1000;
/* H17G publishes no NITS property; its first report registers the device. */
if (dcp->hw.iomfb_method_profile == DCP_IOMFB_METHODS_H17G &&
dcp_has_panel(dcp) && !dcp->brightness.bl_dev && dcp->brightness.maximum > 0)
schedule_work(&dcp->bl_register_wq);

return 0;
}
Expand Down