diff --git a/drivers/gpu/drm/apple/dcp-internal.h b/drivers/gpu/drm/apple/dcp-internal.h index ac355dcd2c5cc..178e29ac5e9e4 100644 --- a/drivers/gpu/drm/apple/dcp-internal.h +++ b/drivers/gpu/drm/apple/dcp-internal.h @@ -457,6 +457,8 @@ struct apple_dcp { enum dcp_firmware_version fw_compat; /* Bumped by every iomfb poweron; see afk_compact_slot(). */ u32 afk_power_gen; + /* Firmware 27.x: the method IDs of this build (iomfb_v27_methods()). */ + const struct dcp_method_entry *v27_methods; bool external; /* A desktop 26.x external processor (apple,t6041-dcpext) */ bool desktop_external; diff --git a/drivers/gpu/drm/apple/dcp.c b/drivers/gpu/drm/apple/dcp.c index bc452a840da83..3099b5fb3642a 100644 --- a/drivers/gpu/drm/apple/dcp.c +++ b/drivers/gpu/drm/apple/dcp.c @@ -5044,6 +5044,8 @@ static enum dcp_firmware_version dcp_check_firmware_version(struct device *dev) const struct dcp_v14_board *v14_board; char compat_str[DCP_FW_VERSION_STR_LEN]; char fw_str[DCP_FW_VERSION_STR_LEN]; + unsigned int num_missing; + const char *missing; int ret; /* @@ -5060,8 +5062,18 @@ static enum dcp_firmware_version dcp_check_firmware_version(struct device *dev) if (hw->firmware_compat == DCP_FIRMWARE_V_27_0) { ret = dcp_read_fw_version(dev, "apple,firmware-compat", compat_str); - if (ret < 0 || strcmp(compat_str, "27.0.0")) + if (ret < 0 || !iomfb_v27_methods(compat_str)) { + dev_err(dev, "DCP firmware-compat %s has no 27.x method table\n", + ret < 0 ? "missing" : compat_str); return DCP_FIRMWARE_UNKNOWN; + } + missing = iomfb_v27_missing_method(iomfb_v27_methods(compat_str), + &num_missing); + if (missing) { + dev_err(dev, "DCP firmware-compat %s not started: no ID known for %u methods (first: %s)\n", + compat_str, num_missing, missing); + return DCP_FIRMWARE_UNKNOWN; + } return DCP_FIRMWARE_V_27_0; } @@ -6174,6 +6186,13 @@ static int dcp_platform_probe_pipe(struct platform_device *pdev) return -ENOMEM; } } + if (fw_compat == DCP_FIRMWARE_V_27_0) { + char compat_str[DCP_FW_VERSION_STR_LEN]; + + /* Checked by dcp_check_firmware_version(). */ + dcp_read_fw_version(dev, "apple,firmware-compat", compat_str); + dcp->v27_methods = iomfb_v27_methods(compat_str); + } if (fw_compat == DCP_FIRMWARE_V_26_6_DESKTOP) { dcp->desktop = devm_kzalloc(dev, sizeof(*dcp->desktop), GFP_KERNEL); if (!dcp->desktop) diff --git a/drivers/gpu/drm/apple/iomfb-peer-runtime-v27.inc b/drivers/gpu/drm/apple/iomfb-peer-runtime-v27.inc index 5d82c88266756..2faa735d84fd4 100644 --- a/drivers/gpu/drm/apple/iomfb-peer-runtime-v27.inc +++ b/drivers/gpu/drm/apple/iomfb-peer-runtime-v27.inc @@ -83,12 +83,12 @@ static void dcp_peer_started_on_owner(struct apple_dcp *owner, void *data, void dcp_peer_swap_armed_v27(owner, id); trace_iomfb_swap_submit(owner, id); trace_iomfb_swap_submit(peer, id); - dcp_push(owner, false, &dcp_methods[dcpep_swap_submit], sizeof(owner->present_v27), + dcp_push(owner, false, &owner->v27_methods[dcpep_swap_submit], sizeof(owner->present_v27), sizeof(struct dcp_swap_submit_resp_v27), &owner->present_v27, dcp_peer_submitted, owner); if (READ_ONCE(owner->crashed)) return; - dcp_push(peer, false, &dcp_methods[dcpep_swap_submit], sizeof(owner->peer_present_v27), + dcp_push(peer, false, &peer->v27_methods[dcpep_swap_submit], sizeof(owner->peer_present_v27), sizeof(struct dcp_swap_submit_resp_v27), &owner->peer_present_v27, dcp_peer_submitted, owner); if (READ_ONCE(peer->crashed)) diff --git a/drivers/gpu/drm/apple/iomfb.h b/drivers/gpu/drm/apple/iomfb.h index 1021825209fb3..f41c6027e3e2a 100644 --- a/drivers/gpu/drm/apple/iomfb.h +++ b/drivers/gpu/drm/apple/iomfb.h @@ -212,6 +212,12 @@ struct dcp_method_entry { char tag_h17g[4]; }; +/* The IOMFB method table of a firmware 27.x build, by its compat string; NULL if unknown. */ +const struct dcp_method_entry *iomfb_v27_methods(const char *compat); +/* The first method of a firmware 27.x table that has no ID, NULL if none. */ +const char *iomfb_v27_missing_method(const struct dcp_method_entry *methods, + unsigned int *count); + #define IOMFB_MAX_CB (1000) bool iomfb_validate_callback_h17p(int tag, u32 in_len, u32 out_len); diff --git a/drivers/gpu/drm/apple/iomfb_template.c b/drivers/gpu/drm/apple/iomfb_template.c index 52235ecf334e3..6d30c09a3ab79 100644 --- a/drivers/gpu/drm/apple/iomfb_template.c +++ b/drivers/gpu/drm/apple/iomfb_template.c @@ -1706,6 +1706,11 @@ static void boot_5(struct apple_dcp *dcp, void *out, void *cookie) { #if DCP_FW_H17(DCP_FW_VER) /* H17P expects A380 right before set_display_refresh_properties */ + if (!dcp_methods[dcpep_dfb_ready_query].tag[0]) { + /* No tag is known for this firmware build: do not send one. */ + boot_5b(dcp, out, cookie); + return; + } dcp_dfb_ready_query(dcp, false, boot_5b, NULL); #else boot_5b(dcp, out, cookie); diff --git a/drivers/gpu/drm/apple/iomfb_v27.c b/drivers/gpu/drm/apple/iomfb_v27.c index 93d2fa72cc41b..2b527f2f2bf2f 100644 --- a/drivers/gpu/drm/apple/iomfb_v27.c +++ b/drivers/gpu/drm/apple/iomfb_v27.c @@ -69,7 +69,8 @@ static_assert(offsetof(struct dcp_swap_v27, brightness_update) == 0x354); static_assert(offsetof(struct dcp_swap_v27, brightness_nits) == 0x35e); static_assert(sizeof(struct dcp_swap_v27) == 0x6e0); -static const struct dcp_method_entry dcp_methods[dcpep_num_methods] = { +/* Firmware 27.0, the build Aurora's t6050-gpu table was written for. */ +static const struct dcp_method_entry dcp_methods_27_0[dcpep_num_methods] = { IOMFB_METHOD("A000", dcpep_late_init_signal), IOMFB_METHOD("A027", dcpep_setup_video_limits), IOMFB_METHOD("A136", iomfbep_a131_pmu_service_matched), @@ -113,6 +114,132 @@ static const struct dcp_method_entry dcp_methods[dcpep_num_methods] = { IOMFB_METHOD("A483", dcpep_register_dfb_surface), }; +/* + * Firmware 27.2 renumbered the AP methods: UnifiedPipeline2 grew into + * A400/A401, so IOMobileFramebufferAP moved up by 50 (start_signal A451, + * get_color_remap_mode A477), and set_create_DFB and vi_set_temperature_hint + * up by one. The UPPipe A0xx and A1xx IDs are unchanged. The firmware rejects + * an unknown tag with a panic ("link_rpc_lookup callback not found"), so + * dfb_ready_query, whose 27.2 tag has not been seen in a call, has no entry + * here and is not sent to this build (boot_5()). + */ +static const struct dcp_method_entry dcp_methods_27_2[dcpep_num_methods] = { + IOMFB_METHOD("A000", dcpep_late_init_signal), + IOMFB_METHOD("A027", dcpep_setup_video_limits), + IOMFB_METHOD("A136", iomfbep_a131_pmu_service_matched), + IOMFB_METHOD("A137", iomfbep_a132_backlight_service_matched), + IOMFB_METHOD("A390", dcpep_set_create_dfb), + IOMFB_METHOD("A391", iomfbep_a358_vi_set_temperature_hint), + IOMFB_METHOD("A451", dcpep_start_signal), + IOMFB_METHOD("A456", dcpep_swap_start), + IOMFB_METHOD("A458", dcpep_swap_submit), + IOMFB_METHOD("A461", dcpep_set_display_device), + IOMFB_METHOD("A462", dcpep_is_main_display), + IOMFB_METHOD("A463", dcpep_set_digital_out_mode), + IOMFB_METHOD("A473", iomfbep_set_matrix), + IOMFB_METHOD("A477", iomfbep_get_color_remap_mode), + IOMFB_METHOD("A500", dcpep_set_parameter_dcp), + IOMFB_METHOD("A504", dcpep_create_default_fb), + IOMFB_METHOD("A037", dcpep_get_dfb_compression_info), + IOMFB_METHOD("A036", dcpep_get_dfb_info), + IOMFB_METHOD("A103", dcpep_get_dfb_layout), + IOMFB_METHOD("A503", dcpep_get_dfb_state), + IOMFB_METHOD("A104", dcpep_set_dfb_dimensions), + IOMFB_METHOD("A105", dcpep_commit_dfb_info), + IOMFB_METHOD("A035", dcpep_dfb_query), + IOMFB_METHOD("A353", dcpep_pipe_query_353), + IOMFB_METHOD("A352", dcpep_pipe_set_352), + IOMFB_METHOD("A465", dcpep_pipe_cfg_415), + IOMFB_METHOD("A033", dcpep_pipe_cfg_031), + IOMFB_METHOD("A464", dcpep_pipe_cfg_414), + IOMFB_METHOD("A539", dcpep_pipe_query_478), + IOMFB_METHOD("A535", dcpep_pipe_query_474), + IOMFB_METHOD("A537", dcpep_pipe_set_476), + IOMFB_METHOD("A478", iomfbep_set_brightness_correction), + IOMFB_METHOD("A508", dcpep_enable_disable_video_power_savings), + IOMFB_METHOD("A516", dcpep_first_client_open), + IOMFB_METHOD("A517", iomfbep_last_client_close), + IOMFB_METHOD("A525", dcpep_set_display_refresh_properties), + IOMFB_METHOD("A528", dcpep_flush_supports_power), + IOMFB_METHOD("A529", iomfbep_abort_swaps_dcp), + IOMFB_METHOD("A534", dcpep_set_power_state), + IOMFB_METHOD("A533", dcpep_register_dfb_surface), +}; + +/* + * Firmware 27.3: only the methods seen, with the request and reply sizes this + * driver uses, in a trace of the calls the macOS 27.3 display driver makes to + * the DCP of a J716s while it starts. Three are one above their 27.2 IDs + * (set_display_refresh_properties A526, flush_supports_power A529, + * register_dfb_surface A534) and create_default_fb is still A504, so 27.3 has + * one more method somewhere between those. That trace has no display client, + * so it has no mode set, swap or power state call, and the methods it does not + * show have no entry here. Until a trace shows them the table is incomplete + * and the driver does not start this firmware (iomfb_v27_missing_method()). + */ +static const struct dcp_method_entry dcp_methods_27_3[dcpep_num_methods] = { + IOMFB_METHOD("A000", dcpep_late_init_signal), + IOMFB_METHOD("A027", dcpep_setup_video_limits), + IOMFB_METHOD("A136", iomfbep_a131_pmu_service_matched), + IOMFB_METHOD("A137", iomfbep_a132_backlight_service_matched), + IOMFB_METHOD("A390", dcpep_set_create_dfb), + IOMFB_METHOD("A391", iomfbep_a358_vi_set_temperature_hint), + IOMFB_METHOD("A451", dcpep_start_signal), + IOMFB_METHOD("A504", dcpep_create_default_fb), + IOMFB_METHOD("A037", dcpep_get_dfb_compression_info), + IOMFB_METHOD("A036", dcpep_get_dfb_info), + IOMFB_METHOD("A103", dcpep_get_dfb_layout), + IOMFB_METHOD("A503", dcpep_get_dfb_state), + IOMFB_METHOD("A104", dcpep_set_dfb_dimensions), + IOMFB_METHOD("A105", dcpep_commit_dfb_info), + IOMFB_METHOD("A035", dcpep_dfb_query), + IOMFB_METHOD("A385", dcpep_dfb_ready_query), + IOMFB_METHOD("A353", dcpep_pipe_query_353), + IOMFB_METHOD("A526", dcpep_set_display_refresh_properties), + IOMFB_METHOD("A529", dcpep_flush_supports_power), + IOMFB_METHOD("A534", dcpep_register_dfb_surface), +}; + +const struct dcp_method_entry *iomfb_v27_methods(const char *compat) +{ + if (!strcmp(compat, "27.0.0")) + return dcp_methods_27_0; + if (!strcmp(compat, "27.2.0")) + return dcp_methods_27_2; + if (!strcmp(compat, "27.3.0")) + return dcp_methods_27_3; + return NULL; +} + +/* + * The driver sends every method of the 27.0 table. dfb_ready_query is the one + * it leaves out for a build whose table has no ID for it (boot_5()). Return + * the name of the first other method @methods has no ID for, with their number + * in @count, or NULL if the table is complete. A method without an ID would go + * out with an empty tag, which the firmware answers with a panic, so a build + * with an incomplete table must not be started. + */ +const char *iomfb_v27_missing_method(const struct dcp_method_entry *methods, + unsigned int *count) +{ + const char *first = NULL; + unsigned int i; + + *count = 0; + for (i = 0; i < dcpep_num_methods; i++) { + if (!dcp_methods_27_0[i].tag[0] || methods[i].tag[0] || + i == dcpep_dfb_ready_query) + continue; + if (!first) + first = dcp_methods_27_0[i].name; + (*count)++; + } + return first; +} + +/* The template's calls resolve through the table probe chose for this build. */ +#define dcp_methods (dcp->v27_methods) + #define iomfb_modeset_h17p iomfb_modeset_v27 #define iomfb_flush_h17p iomfb_flush_v27 #define iomfb_poweron_h17p iomfb_poweron_v27