Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Add handling for DC power mode

[Why]
Future implementations will require a distinction between AC power and
DC power (wall power and battery power, respectively). To accomplish this,
adding a power mode parameter to certain dc interfaces, and adding a
separate DML2 instance for DC mode validation. Default behaviour unchanged.

Reviewed-by: Jun Lei <jun.lei@amd.com>
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Acked-by: Roman Li <roman.li@amd.com>
Signed-off-by: Joshua Aberback <joshua.aberback@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Joshua Aberback and committed by
Alex Deucher
e779f458 cc263c3a

+120 -43
+12 -5
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
··· 2629 2629 int i; 2630 2630 struct dc_stream_state *del_streams[MAX_PIPES]; 2631 2631 int del_streams_count = 0; 2632 + struct dc_commit_streams_params params = {}; 2632 2633 2633 2634 memset(del_streams, 0, sizeof(del_streams)); 2634 2635 ··· 2656 2655 goto fail; 2657 2656 } 2658 2657 2659 - res = dc_commit_streams(dc, context->streams, context->stream_count); 2658 + params.streams = context->streams; 2659 + params.stream_count = context->stream_count; 2660 + res = dc_commit_streams(dc, &params); 2660 2661 2661 2662 fail: 2662 2663 dc_state_release(context); ··· 2880 2877 struct dc_state *dc_state; 2881 2878 int i, r, j, ret; 2882 2879 bool need_hotplug = false; 2880 + struct dc_commit_streams_params commit_params = {}; 2883 2881 2884 2882 if (dm->dc->caps.ips_support) { 2885 2883 dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false); ··· 2930 2926 dc_enable_dmub_outbox(adev->dm.dc); 2931 2927 } 2932 2928 2933 - WARN_ON(!dc_commit_streams(dm->dc, dc_state->streams, dc_state->stream_count)); 2929 + commit_params.streams = dc_state->streams; 2930 + commit_params.stream_count = dc_state->stream_count; 2931 + WARN_ON(!dc_commit_streams(dm->dc, &commit_params)); 2934 2932 2935 2933 dm_gpureset_commit_state(dm->cached_dc_state, dm); 2936 2934 ··· 2949 2943 } 2950 2944 /* Recreate dc_state - DC invalidates it when setting power state to S3. */ 2951 2945 dc_state_release(dm_state->context); 2952 - dm_state->context = dc_state_create(dm->dc); 2946 + dm_state->context = dc_state_create(dm->dc, NULL); 2953 2947 /* TODO: Remove dc_state->dccg, use dc->dccg directly. */ 2954 2948 2955 2949 /* Before powering on DC we need to re-initialize DMUB. */ ··· 6808 6802 if (!dc_plane_state) 6809 6803 goto cleanup; 6810 6804 6811 - dc_state = dc_state_create(dc); 6805 + dc_state = dc_state_create(dc, NULL); 6812 6806 if (!dc_state) 6813 6807 goto cleanup; 6814 6808 ··· 8863 8857 struct drm_connector *connector; 8864 8858 bool mode_set_reset_required = false; 8865 8859 u32 i; 8860 + struct dc_commit_streams_params params = {dc_state->streams, dc_state->stream_count}; 8866 8861 8867 8862 /* Disable writeback */ 8868 8863 for_each_old_connector_in_state(state, connector, old_con_state, i) { ··· 9000 8993 9001 8994 dm_enable_per_frame_crtc_master_sync(dc_state); 9002 8995 mutex_lock(&dm->dc_lock); 9003 - WARN_ON(!dc_commit_streams(dm->dc, dc_state->streams, dc_state->stream_count)); 8996 + WARN_ON(!dc_commit_streams(dm->dc, &params)); 9004 8997 9005 8998 /* Allow idle optimization when vblank count is 0 for display off */ 9006 8999 if (dm->active_vblank_irq_count == 0)
+20 -17
drivers/gpu/drm/amd/display/dc/core/dc.c
··· 1089 1089 * is initialized in dc_create_resource_pool because 1090 1090 * on creation it copies the contents of dc->dml 1091 1091 */ 1092 - 1093 - dc->current_state = dc_state_create(dc); 1092 + dc->current_state = dc_state_create(dc, NULL); 1094 1093 1095 1094 if (!dc->current_state) { 1096 1095 dm_error("%s: failed to create validate ctx\n", __func__); ··· 2134 2135 * Return DC_OK if everything work as expected, otherwise, return a dc_status 2135 2136 * code. 2136 2137 */ 2137 - enum dc_status dc_commit_streams(struct dc *dc, 2138 - struct dc_stream_state *streams[], 2139 - uint8_t stream_count) 2138 + enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params *params) 2140 2139 { 2141 2140 int i, j; 2142 2141 struct dc_state *context; ··· 2143 2146 struct pipe_ctx *pipe; 2144 2147 bool handle_exit_odm2to1 = false; 2145 2148 2149 + if (!params) 2150 + return DC_ERROR_UNEXPECTED; 2151 + 2146 2152 if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW) 2147 2153 return res; 2148 2154 2149 - if (!streams_changed(dc, streams, stream_count)) 2155 + if (!streams_changed(dc, params->streams, params->stream_count) && 2156 + dc->current_state->power_source == params->power_source) 2150 2157 return res; 2151 2158 2152 2159 dc_exit_ips_for_hw_access(dc); 2153 2160 2154 - DC_LOG_DC("%s: %d streams\n", __func__, stream_count); 2161 + DC_LOG_DC("%s: %d streams\n", __func__, params->stream_count); 2155 2162 2156 - for (i = 0; i < stream_count; i++) { 2157 - struct dc_stream_state *stream = streams[i]; 2163 + for (i = 0; i < params->stream_count; i++) { 2164 + struct dc_stream_state *stream = params->streams[i]; 2158 2165 struct dc_stream_status *status = dc_stream_get_status(stream); 2159 2166 2160 2167 dc_stream_log(dc, stream); ··· 2176 2175 * scenario, it uses extra pipes than needed to reduce power consumption 2177 2176 * We need to switch off this feature to make room for new streams. 2178 2177 */ 2179 - if (stream_count > dc->current_state->stream_count && 2178 + if (params->stream_count > dc->current_state->stream_count && 2180 2179 dc->current_state->stream_count == 1) { 2181 2180 for (i = 0; i < dc->res_pool->pipe_count; i++) { 2182 2181 pipe = &dc->current_state->res_ctx.pipe_ctx[i]; ··· 2192 2191 if (!context) 2193 2192 goto context_alloc_fail; 2194 2193 2195 - res = dc_validate_with_context(dc, set, stream_count, context, false); 2194 + context->power_source = params->power_source; 2195 + 2196 + res = dc_validate_with_context(dc, set, params->stream_count, context, false); 2196 2197 if (res != DC_OK) { 2197 2198 BREAK_TO_DEBUGGER(); 2198 2199 goto fail; ··· 2202 2199 2203 2200 res = dc_commit_state_no_check(dc, context); 2204 2201 2205 - for (i = 0; i < stream_count; i++) { 2202 + for (i = 0; i < params->stream_count; i++) { 2206 2203 for (j = 0; j < context->stream_count; j++) { 2207 - if (streams[i]->stream_id == context->streams[j]->stream_id) 2208 - streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst; 2204 + if (params->streams[i]->stream_id == context->streams[j]->stream_id) 2205 + params->streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst; 2209 2206 2210 - if (dc_is_embedded_signal(streams[i]->signal)) { 2211 - struct dc_stream_status *status = dc_state_get_stream_status(context, streams[i]); 2207 + if (dc_is_embedded_signal(params->streams[i]->signal)) { 2208 + struct dc_stream_status *status = dc_state_get_stream_status(context, params->streams[i]); 2212 2209 2213 2210 if (dc->hwss.is_abm_supported) 2214 - status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, streams[i]); 2211 + status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, params->streams[i]); 2215 2212 else 2216 2213 status->is_abm_supported = true; 2217 2214 }
+26 -3
drivers/gpu/drm/amd/display/dc/core/dc_state.c
··· 188 188 } 189 189 190 190 /* Public dc_state functions */ 191 - struct dc_state *dc_state_create(struct dc *dc) 191 + struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params) 192 192 { 193 + #ifdef CONFIG_DRM_AMD_DC_FP 194 + struct dml2_configuration_options dml2_opt = dc->dml2_options; 195 + #endif 193 196 struct dc_state *state = kvzalloc(sizeof(struct dc_state), 194 197 GFP_KERNEL); 195 198 ··· 201 198 202 199 init_state(dc, state); 203 200 dc_state_construct(dc, state); 201 + state->power_source = params ? params->power_source : DC_POWER_SOURCE_AC; 204 202 205 203 #ifdef CONFIG_DRM_AMD_DC_FP 206 - if (dc->debug.using_dml2) 207 - dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2); 204 + if (dc->debug.using_dml2) { 205 + dml2_opt.use_clock_dc_limits = false; 206 + dml2_create(dc, &dml2_opt, &state->bw_ctx.dml2); 207 + 208 + dml2_opt.use_clock_dc_limits = true; 209 + dml2_create(dc, &dml2_opt, &state->bw_ctx.dml2_dc_power_source); 210 + } 208 211 #endif 209 212 210 213 kref_init(&state->refcount); ··· 223 214 struct kref refcount = dst_state->refcount; 224 215 #ifdef CONFIG_DRM_AMD_DC_FP 225 216 struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2; 217 + struct dml2_context *dst_dml2_dc_power_source = dst_state->bw_ctx.dml2_dc_power_source; 226 218 #endif 227 219 228 220 dc_state_copy_internal(dst_state, src_state); ··· 232 222 dst_state->bw_ctx.dml2 = dst_dml2; 233 223 if (src_state->bw_ctx.dml2) 234 224 dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2); 225 + 226 + dst_state->bw_ctx.dml2_dc_power_source = dst_dml2_dc_power_source; 227 + if (src_state->bw_ctx.dml2_dc_power_source) 228 + dml2_copy(dst_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source); 235 229 #endif 236 230 237 231 /* context refcount should not be overridden */ ··· 256 242 #ifdef CONFIG_DRM_AMD_DC_FP 257 243 if (src_state->bw_ctx.dml2 && 258 244 !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) { 245 + dc_state_release(new_state); 246 + return NULL; 247 + } 248 + 249 + if (src_state->bw_ctx.dml2_dc_power_source && 250 + !dml2_create_copy(&new_state->bw_ctx.dml2_dc_power_source, src_state->bw_ctx.dml2_dc_power_source)) { 259 251 dc_state_release(new_state); 260 252 return NULL; 261 253 } ··· 346 326 #ifdef CONFIG_DRM_AMD_DC_FP 347 327 dml2_destroy(state->bw_ctx.dml2); 348 328 state->bw_ctx.dml2 = 0; 329 + 330 + dml2_destroy(state->bw_ctx.dml2_dc_power_source); 331 + state->bw_ctx.dml2_dc_power_source = 0; 349 332 #endif 350 333 351 334 kvfree(state);
+9 -4
drivers/gpu/drm/amd/display/dc/dc.h
··· 1504 1504 bool dc_resource_is_dsc_encoding_supported(const struct dc *dc); 1505 1505 void get_audio_check(struct audio_info *aud_modes, 1506 1506 struct audio_check *aud_chk); 1507 - 1508 - enum dc_status dc_commit_streams(struct dc *dc, 1509 - struct dc_stream_state *streams[], 1510 - uint8_t stream_count); 1507 + /* 1508 + * Set up streams and links associated to drive sinks 1509 + * The streams parameter is an absolute set of all active streams. 1510 + * 1511 + * After this call: 1512 + * Phy, Encoder, Timing Generator are programmed and enabled. 1513 + * New streams are enabled with blank stream; no memory read. 1514 + */ 1515 + enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params *params); 1511 1516 1512 1517 1513 1518 struct dc_plane_state *dc_get_surface_for_mpcc(struct dc *dc,
+1 -1
drivers/gpu/drm/amd/display/dc/dc_state.h
··· 29 29 #include "dc.h" 30 30 #include "inc/core_status.h" 31 31 32 - struct dc_state *dc_state_create(struct dc *dc); 32 + struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params); 33 33 void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state); 34 34 struct dc_state *dc_state_create_copy(struct dc_state *src_state); 35 35 void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state);
-8
drivers/gpu/drm/amd/display/dc/dc_stream.h
··· 428 428 enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream); 429 429 430 430 /* 431 - * Set up streams and links associated to drive sinks 432 - * The streams parameter is an absolute set of all active streams. 433 - * 434 - * After this call: 435 - * Phy, Encoder, Timing Generator are programmed and enabled. 436 - * New streams are enabled with blank stream; no memory read. 437 - */ 438 - /* 439 431 * Enable stereo when commit_streams is not required, 440 432 * for example, frame alternate. 441 433 */
+16
drivers/gpu/drm/amd/display/dc/dc_types.h
··· 1175 1175 SUBVP_MAIN, // subvp in use, this stream is main stream 1176 1176 SUBVP_PHANTOM, // subvp in use, this stream is a phantom stream 1177 1177 }; 1178 + 1179 + enum dc_power_source_type { 1180 + DC_POWER_SOURCE_AC, // wall power 1181 + DC_POWER_SOURCE_DC, // battery power 1182 + }; 1183 + 1184 + struct dc_state_create_params { 1185 + enum dc_power_source_type power_source; 1186 + }; 1187 + 1188 + struct dc_commit_streams_params { 1189 + struct dc_stream_state **streams; 1190 + uint8_t stream_count; 1191 + enum dc_power_source_type power_source; 1192 + }; 1193 + 1178 1194 #endif /* DC_TYPES_H_ */
+2
drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h
··· 215 215 unsigned int max_segments_per_hubp; 216 216 unsigned int det_segment_size; 217 217 bool map_dc_pipes_with_callbacks; 218 + 219 + bool use_clock_dc_limits; 218 220 }; 219 221 220 222 /*
+3
drivers/gpu/drm/amd/display/dc/inc/core_types.h
··· 518 518 union bw_output bw; 519 519 struct display_mode_lib dml; 520 520 struct dml2_context *dml2; 521 + struct dml2_context *dml2_dc_power_source; 521 522 }; 522 523 523 524 struct dc_dmub_cmd { ··· 607 606 struct { 608 607 unsigned int stutter_period_us; 609 608 } perf_params; 609 + 610 + enum dc_power_source_type power_source; 610 611 }; 611 612 612 613 struct replay_context {
+14 -2
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
··· 1799 1799 bool out = false; 1800 1800 1801 1801 if (dc->debug.using_dml2) 1802 - out = dml2_validate(dc, context, context->bw_ctx.dml2, fast_validate); 1802 + out = dml2_validate(dc, context, 1803 + context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, 1804 + fast_validate); 1803 1805 else 1804 1806 out = dml1_validate(dc, context, fast_validate); 1805 1807 return out; ··· 1999 1997 2000 1998 static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) 2001 1999 { 2000 + struct dml2_configuration_options dml2_opt = dc->dml2_options; 2001 + 2002 2002 DC_FP_START(); 2003 + 2003 2004 dcn32_update_bw_bounding_box_fpu(dc, bw_params); 2005 + 2006 + dml2_opt.use_clock_dc_limits = false; 2004 2007 if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2) 2005 - dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2); 2008 + dml2_reinit(dc, &dml2_opt, &dc->current_state->bw_ctx.dml2); 2009 + 2010 + dml2_opt.use_clock_dc_limits = true; 2011 + if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2_dc_power_source) 2012 + dml2_reinit(dc, &dml2_opt, &dc->current_state->bw_ctx.dml2_dc_power_source); 2013 + 2006 2014 DC_FP_END(); 2007 2015 } 2008 2016
+11 -1
drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
··· 1579 1579 1580 1580 static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) 1581 1581 { 1582 + struct dml2_configuration_options dml2_opt = dc->dml2_options; 1583 + 1582 1584 DC_FP_START(); 1585 + 1583 1586 dcn321_update_bw_bounding_box_fpu(dc, bw_params); 1587 + 1588 + dml2_opt.use_clock_dc_limits = false; 1584 1589 if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2) 1585 - dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2); 1590 + dml2_reinit(dc, &dml2_opt, &dc->current_state->bw_ctx.dml2); 1591 + 1592 + dml2_opt.use_clock_dc_limits = true; 1593 + if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2_dc_power_source) 1594 + dml2_reinit(dc, &dml2_opt, &dc->current_state->bw_ctx.dml2_dc_power_source); 1595 + 1586 1596 DC_FP_END(); 1587 1597 } 1588 1598
+3 -1
drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c
··· 1734 1734 { 1735 1735 bool out = false; 1736 1736 1737 - out = dml2_validate(dc, context, context->bw_ctx.dml2, fast_validate); 1737 + out = dml2_validate(dc, context, 1738 + context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, 1739 + fast_validate); 1738 1740 1739 1741 if (fast_validate) 1740 1742 return out;
+3 -1
drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c
··· 1714 1714 { 1715 1715 bool out = false; 1716 1716 1717 - out = dml2_validate(dc, context, context->bw_ctx.dml2, fast_validate); 1717 + out = dml2_validate(dc, context, 1718 + context->power_source == DC_POWER_SOURCE_DC ? context->bw_ctx.dml2_dc_power_source : context->bw_ctx.dml2, 1719 + fast_validate); 1718 1720 1719 1721 if (fast_validate) 1720 1722 return out;