diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc')
47 files changed, 1051 insertions, 970 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index 751bb614fc0e..c513ab6f3843 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -638,6 +638,7 @@ static enum bp_result get_ss_info_v4_1( { enum bp_result result = BP_RESULT_OK; struct atom_display_controller_info_v4_1 *disp_cntl_tbl = NULL; + struct atom_smu_info_v3_3 *smu_info = NULL; if (!ss_info) return BP_RESULT_BADINPUT; @@ -650,6 +651,7 @@ static enum bp_result get_ss_info_v4_1( if (!disp_cntl_tbl) return BP_RESULT_BADBIOSTABLE; + ss_info->type.STEP_AND_DELAY_INFO = false; ss_info->spread_percentage_divider = 1000; /* BIOS no longer uses target clock. Always enable for now */ @@ -688,6 +690,19 @@ static enum bp_result get_ss_info_v4_1( */ result = BP_RESULT_UNSUPPORTED; break; + case AS_SIGNAL_TYPE_XGMI: + smu_info = GET_IMAGE(struct atom_smu_info_v3_3, + DATA_TABLES(smu_info)); + if (!smu_info) + return BP_RESULT_BADBIOSTABLE; + + ss_info->spread_spectrum_percentage = + smu_info->waflclk_ss_percentage; + ss_info->spread_spectrum_range = + smu_info->gpuclk_ss_rate_10hz * 10; + if (smu_info->waflclk_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) + ss_info->type.CENTER_MODE = true; + break; default: result = BP_RESULT_UNSUPPORTED; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index 65b006ad372e..8196f3bb10c7 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -67,6 +67,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2( return true; #endif case DCE_VERSION_12_0: + case DCE_VERSION_12_1: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 3279e26c3440..5fd52094d459 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -62,6 +62,55 @@ const static char DC_BUILD_ID[] = "production-build"; +/** + * DOC: Overview + * + * DC is the OS-agnostic component of the amdgpu DC driver. + * + * DC maintains and validates a set of structs representing the state of the + * driver and writes that state to AMD hardware + * + * Main DC HW structs: + * + * struct dc - The central struct. One per driver. Created on driver load, + * destroyed on driver unload. + * + * struct dc_context - One per driver. + * Used as a backpointer by most other structs in dc. + * + * struct dc_link - One per connector (the physical DP, HDMI, miniDP, or eDP + * plugpoints). Created on driver load, destroyed on driver unload. + * + * struct dc_sink - One per display. Created on boot or hotplug. + * Destroyed on shutdown or hotunplug. A dc_link can have a local sink + * (the display directly attached). It may also have one or more remote + * sinks (in the Multi-Stream Transport case) + * + * struct resource_pool - One per driver. Represents the hw blocks not in the + * main pipeline. Not directly accessible by dm. + * + * Main dc state structs: + * + * These structs can be created and destroyed as needed. There is a full set of + * these structs in dc->current_state representing the currently programmed state. + * + * struct dc_state - The global DC state to track global state information, + * such as bandwidth values. + * + * struct dc_stream_state - Represents the hw configuration for the pipeline from + * a framebuffer to a display. Maps one-to-one with dc_sink. + * + * struct dc_plane_state - Represents a framebuffer. Each stream has at least one, + * and may have more in the Multi-Plane Overlay case. + * + * struct resource_context - Represents the programmable state of everything in + * the resource_pool. Not directly accessible by dm. + * + * struct pipe_ctx - A member of struct resource_context. Represents the + * internal hardware pipeline components. Each dc_plane_state has either + * one or two (in the pipe-split case). + */ + /******************************************************************************* * Private functions ******************************************************************************/ @@ -102,10 +151,6 @@ static bool create_links( return false; } - if (connectors_num == 0 && num_virtual_links == 0) { - dm_error("DC: Number of connectors is zero!\n"); - } - dm_output_to_console( "DC: %s: connectors_num: physical:%d, virtual:%d\n", __func__, @@ -175,6 +220,17 @@ failed_alloc: return false; } +static struct dc_perf_trace *dc_perf_trace_create(void) +{ + return kzalloc(sizeof(struct dc_perf_trace), GFP_KERNEL); +} + +static void dc_perf_trace_destroy(struct dc_perf_trace **perf_trace) +{ + kfree(*perf_trace); + *perf_trace = NULL; +} + /** ***************************************************************************** * Function: dc_stream_adjust_vmin_vmax @@ -240,7 +296,7 @@ bool dc_stream_get_crtc_position(struct dc *dc, } /** - * dc_stream_configure_crc: Configure CRC capture for the given stream. + * dc_stream_configure_crc() - Configure CRC capture for the given stream. * @dc: DC Object * @stream: The stream to configure CRC on. * @enable: Enable CRC if true, disable otherwise. @@ -292,7 +348,7 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream, } /** - * dc_stream_get_crc: Get CRC values for the given stream. + * dc_stream_get_crc() - Get CRC values for the given stream. * @dc: DC object * @stream: The DC stream state of the stream to get CRCs from. * @r_cr, g_y, b_cb: CRC values for the three channels are stored here. @@ -328,7 +384,7 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream, enum dc_dither_option option) { struct bit_depth_reduction_params params; - struct dc_link *link = stream->status.link; + struct dc_link *link = stream->sink->link; struct pipe_ctx *pipes = NULL; int i; @@ -536,6 +592,8 @@ static void destruct(struct dc *dc) if (dc->ctx->created_bios) dal_bios_parser_destroy(&dc->ctx->dc_bios); + dc_perf_trace_destroy(&dc->ctx->perf_trace); + kfree(dc->ctx); dc->ctx = NULL; @@ -659,6 +717,12 @@ static bool construct(struct dc *dc, goto fail; } + dc_ctx->perf_trace = dc_perf_trace_create(); + if (!dc_ctx->perf_trace) { + ASSERT_CRITICAL(false); + goto fail; + } + /* Create GPIO service */ dc_ctx->gpio_service = dal_gpio_service_create( dc_version, @@ -1329,6 +1393,11 @@ static enum surface_update_type check_update_surfaces_for_stream( return overall_type; } +/** + * dc_check_update_surfaces_for_stream() - Determine update type (fast, med, or full) + * + * See :c:type:`enum surface_update_type <surface_update_type>` for explanation of update types + */ enum surface_update_type dc_check_update_surfaces_for_stream( struct dc *dc, struct dc_surface_update *updates, @@ -1398,7 +1467,8 @@ static void commit_planes_do_stream_update(struct dc *dc, if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || stream_update->vrr_infopacket || - stream_update->vsc_infopacket) { + stream_update->vsc_infopacket || + stream_update->vsp_infopacket) { resource_build_info_frame(pipe_ctx); dc->hwss.update_info_frame(pipe_ctx); } @@ -1409,6 +1479,14 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->output_csc_transform) dc_stream_program_csc_matrix(dc, stream); + if (stream_update->dither_option) { + resource_build_bit_depth_reduction_params(pipe_ctx->stream, + &pipe_ctx->stream->bit_depth_params); + pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); + } + /* Full fe update*/ if (update_type == UPDATE_TYPE_FAST) continue; @@ -1492,9 +1570,6 @@ static void commit_planes_for_stream(struct dc *dc, } } - if (update_type == UPDATE_TYPE_FULL) - context_timing_trace(dc, &context->res_ctx); - // Update Type FAST, Surface updates if (update_type == UPDATE_TYPE_FAST) { /* Lock the top pipe while updating plane addrs, since freesync requires @@ -1631,6 +1706,9 @@ enum dc_irq_source dc_interrupt_to_irq_source( return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id); } +/** + * dc_interrupt_set() - Enable/disable an AMD hw interrupt source + */ bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable) { @@ -1686,6 +1764,15 @@ void dc_resume(struct dc *dc) core_link_resume(dc->links[i]); } +bool dc_is_dmcu_initialized(struct dc *dc) +{ + struct dmcu *dmcu = dc->res_pool->dmcu; + + if (dmcu) + return dmcu->funcs->is_dmcu_initialized(dmcu); + return false; +} + bool dc_submit_i2c( struct dc *dc, uint32_t link_index, @@ -1715,6 +1802,11 @@ static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink return true; } +/** + * dc_link_add_remote_sink() - Create a sink and attach it to an existing link + * + * EDID length is in bytes + */ struct dc_sink *dc_link_add_remote_sink( struct dc_link *link, const uint8_t *edid, @@ -1773,6 +1865,12 @@ fail_add_sink: return NULL; } +/** + * dc_link_remove_remote_sink() - Remove a remote sink from a dc_link + * + * Note that this just removes the struct dc_sink - it doesn't + * program hardware or alter other members of dc_link + */ void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) { int i; @@ -1810,4 +1908,4 @@ void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx info->dcfClockDeepSleep = (unsigned int)state->bw.dcn.clk.dcfclk_deep_sleep_khz; info->fClock = (unsigned int)state->bw.dcn.clk.fclk_khz; info->phyClock = (unsigned int)state->bw.dcn.clk.phyclk_khz; -}
\ No newline at end of file +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 7ee9c033acbd..52deacf39841 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -198,6 +198,13 @@ static bool program_hpd_filter( return result; } +/** + * dc_link_detect_sink() - Determine if there is a sink connected + * + * @type: Returned connection type + * Does not detect downstream devices, such as MST sinks + * or display connected through active dongles + */ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type) { uint32_t is_hpd_high = 0; @@ -208,6 +215,9 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type) return true; } + if (link->connector_signal == SIGNAL_TYPE_EDP) + link->dc->hwss.edp_wait_for_hpd_ready(link, true); + /* todo: may need to lock gpio access */ hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); if (hpd_pin == NULL) @@ -324,15 +334,15 @@ static enum signal_type get_basic_signal_type( return SIGNAL_TYPE_NONE; } -/* - * @brief - * Check whether there is a dongle on DP connector +/** + * dc_link_is_dp_sink_present() - Check if there is a native DP + * or passive DP-HDMI dongle connected */ bool dc_link_is_dp_sink_present(struct dc_link *link) { enum gpio_result gpio_result; uint32_t clock_pin = 0; - + uint8_t retry = 0; struct ddc *ddc; enum connector_id connector_id = @@ -361,11 +371,22 @@ bool dc_link_is_dp_sink_present(struct dc_link *link) return present; } - /* Read GPIO: DP sink is present if both clock and data pins are zero */ - /* [anaumov] in DAL2, there was no check for GPIO failure */ - - gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin); - ASSERT(gpio_result == GPIO_RESULT_OK); + /* + * Read GPIO: DP sink is present if both clock and data pins are zero + * + * [W/A] plug-unplug DP cable, sometimes customer board has + * one short pulse on clk_pin(1V, < 1ms). DP will be config to HDMI/DVI + * then monitor can't br light up. Add retry 3 times + * But in real passive dongle, it need additional 3ms to detect + */ + do { + gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin); + ASSERT(gpio_result == GPIO_RESULT_OK); + if (clock_pin) + udelay(1000); + else + break; + } while (retry++ < 3); present = (gpio_result == GPIO_RESULT_OK) && !clock_pin; @@ -593,6 +614,14 @@ static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid) return (memcmp(old_edid->raw_edid, new_edid->raw_edid, new_edid->length) == 0); } +/** + * dc_link_detect() - Detect if a sink is attached to a given link + * + * link->local_sink is created or destroyed as needed. + * + * This does not create remote sinks but will trigger DM + * to start MST detection if a branch is detected. + */ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) { struct dc_sink_init_data sink_init_data = { 0 }; @@ -688,12 +717,26 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) if (memcmp(&link->dpcd_caps, &prev_dpcd_caps, sizeof(struct dpcd_caps))) same_dpcd = false; } - /* Active dongle downstream unplug */ + /* Active dongle plug in without display or downstream unplug*/ if (link->type == dc_connection_active_dongle && link->dpcd_caps.sink_count. bits.SINK_COUNT == 0) { - if (prev_sink != NULL) + if (prev_sink != NULL) { + /* Downstream unplug */ dc_sink_release(prev_sink); + } else { + /* Empty dongle plug in */ + for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) { + int fail_count = 0; + + dp_verify_link_cap(link, + &link->reported_link_cap, + &fail_count); + + if (fail_count == 0) + break; + } + } return true; } @@ -1396,8 +1439,6 @@ static enum dc_status enable_link_dp( else status = DC_FAIL_DP_LINK_TRAINING; - enable_stream_features(pipe_ctx); - return status; } @@ -2175,11 +2216,11 @@ bool dc_link_set_backlight_level(const struct dc_link *link, backlight_pwm_u16_16, backlight_pwm_u16_16); if (dc_is_embedded_signal(link->connector_signal)) { - if (stream != NULL) { - for (i = 0; i < MAX_PIPES; i++) { + for (i = 0; i < MAX_PIPES; i++) { + if (core_dc->current_state->res_ctx.pipe_ctx[i].stream) { if (core_dc->current_state->res_ctx. - pipe_ctx[i].stream - == stream) + pipe_ctx[i].stream->sink->link + == link) /* DMCU -1 for all controller id values, * therefore +1 here */ @@ -2218,7 +2259,7 @@ bool dc_link_set_psr_enable(const struct dc_link *link, bool enable, bool wait) struct dc *core_dc = link->ctx->dc; struct dmcu *dmcu = core_dc->res_pool->dmcu; - if (dmcu != NULL && link->psr_enabled) + if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) && link->psr_enabled) dmcu->funcs->set_psr_enable(dmcu, enable, wait); return true; @@ -2594,6 +2635,9 @@ void core_link_enable_stream( core_dc->hwss.unblank_stream(pipe_ctx, &pipe_ctx->stream->sink->link->cur_link_settings); + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + enable_stream_features(pipe_ctx); + dc_link_set_backlight_level(pipe_ctx->stream->sink->link, pipe_ctx->stream->bl_pwm_level, 0, @@ -2606,11 +2650,11 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) { struct dc *core_dc = pipe_ctx->stream->ctx->dc; + core_dc->hwss.blank_stream(pipe_ctx); + if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx); - core_dc->hwss.blank_stream(pipe_ctx); - core_dc->hwss.disable_stream(pipe_ctx, option); disable_link(pipe_ctx->stream->sink->link, pipe_ctx->stream->signal); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index d91df5ef0cb3..0caacb60b02f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -1089,6 +1089,121 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) return max_link_cap; } +static enum dc_status read_hpd_rx_irq_data( + struct dc_link *link, + union hpd_irq_data *irq_data) +{ + static enum dc_status retval; + + /* The HW reads 16 bytes from 200h on HPD, + * but if we get an AUX_DEFER, the HW cannot retry + * and this causes the CTS tests 4.3.2.1 - 3.2.4 to + * fail, so we now explicitly read 6 bytes which is + * the req from the above mentioned test cases. + * + * For DP 1.4 we need to read those from 2002h range. + */ + if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14) + retval = core_link_read_dpcd( + link, + DP_SINK_COUNT, + irq_data->raw, + sizeof(union hpd_irq_data)); + else { + /* Read 14 bytes in a single read and then copy only the required fields. + * This is more efficient than doing it in two separate AUX reads. */ + + uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1]; + + retval = core_link_read_dpcd( + link, + DP_SINK_COUNT_ESI, + tmp, + sizeof(tmp)); + + if (retval != DC_OK) + return retval; + + irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI]; + irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI]; + irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI]; + } + + return retval; +} + +static bool hpd_rx_irq_check_link_loss_status( + struct dc_link *link, + union hpd_irq_data *hpd_irq_dpcd_data) +{ + uint8_t irq_reg_rx_power_state = 0; + enum dc_status dpcd_result = DC_ERROR_UNEXPECTED; + union lane_status lane_status; + uint32_t lane; + bool sink_status_changed; + bool return_code; + + sink_status_changed = false; + return_code = false; + + if (link->cur_link_settings.lane_count == 0) + return return_code; + + /*1. Check that Link Status changed, before re-training.*/ + + /*parse lane status*/ + for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { + /* check status of lanes 0,1 + * changed DpcdAddress_Lane01Status (0x202) + */ + lane_status.raw = get_nibble_at_index( + &hpd_irq_dpcd_data->bytes.lane01_status.raw, + lane); + + if (!lane_status.bits.CHANNEL_EQ_DONE_0 || + !lane_status.bits.CR_DONE_0 || + !lane_status.bits.SYMBOL_LOCKED_0) { + /* if one of the channel equalization, clock + * recovery or symbol lock is dropped + * consider it as (link has been + * dropped) dp sink status has changed + */ + sink_status_changed = true; + break; + } + } + + /* Check interlane align.*/ + if (sink_status_changed || + !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { + + DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__); + + return_code = true; + + /*2. Check that we can handle interrupt: Not in FS DOS, + * Not in "Display Timeout" state, Link is trained. + */ + dpcd_result = core_link_read_dpcd(link, + DP_SET_POWER, + &irq_reg_rx_power_state, + sizeof(irq_reg_rx_power_state)); + + if (dpcd_result != DC_OK) { + DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n", + __func__); + } else { + if (irq_reg_rx_power_state != DP_SET_POWER_D0) + return_code = false; + } + } + + return return_code; +} + bool dp_verify_link_cap( struct dc_link *link, struct dc_link_settings *known_limit_link_setting, @@ -1104,12 +1219,14 @@ bool dp_verify_link_cap( struct clock_source *dp_cs; enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; enum link_training_result status; + union hpd_irq_data irq_data; if (link->dc->debug.skip_detection_link_training) { link->verified_link_cap = *known_limit_link_setting; return true; } + memset(&irq_data, 0, sizeof(irq_data)); success = false; skip_link_training = false; @@ -1168,9 +1285,15 @@ bool dp_verify_link_cap( (*fail_count)++; } - if (success) + if (success) { link->verified_link_cap = *cur; - + udelay(1000); + if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK) + if (hpd_rx_irq_check_link_loss_status( + link, + &irq_data)) + (*fail_count)++; + } /* always disable the link before trying another * setting or before returning we'll enable it later * based on the actual mode we're driving @@ -1572,122 +1695,6 @@ void decide_link_settings(struct dc_stream_state *stream, } /*************************Short Pulse IRQ***************************/ - -static bool hpd_rx_irq_check_link_loss_status( - struct dc_link *link, - union hpd_irq_data *hpd_irq_dpcd_data) -{ - uint8_t irq_reg_rx_power_state = 0; - enum dc_status dpcd_result = DC_ERROR_UNEXPECTED; - union lane_status lane_status; - uint32_t lane; - bool sink_status_changed; - bool return_code; - - sink_status_changed = false; - return_code = false; - - if (link->cur_link_settings.lane_count == 0) - return return_code; - - /*1. Check that Link Status changed, before re-training.*/ - - /*parse lane status*/ - for (lane = 0; lane < link->cur_link_settings.lane_count; lane++) { - /* check status of lanes 0,1 - * changed DpcdAddress_Lane01Status (0x202) - */ - lane_status.raw = get_nibble_at_index( - &hpd_irq_dpcd_data->bytes.lane01_status.raw, - lane); - - if (!lane_status.bits.CHANNEL_EQ_DONE_0 || - !lane_status.bits.CR_DONE_0 || - !lane_status.bits.SYMBOL_LOCKED_0) { - /* if one of the channel equalization, clock - * recovery or symbol lock is dropped - * consider it as (link has been - * dropped) dp sink status has changed - */ - sink_status_changed = true; - break; - } - } - - /* Check interlane align.*/ - if (sink_status_changed || - !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.INTERLANE_ALIGN_DONE) { - - DC_LOG_HW_HPD_IRQ("%s: Link Status changed.\n", __func__); - - return_code = true; - - /*2. Check that we can handle interrupt: Not in FS DOS, - * Not in "Display Timeout" state, Link is trained. - */ - dpcd_result = core_link_read_dpcd(link, - DP_SET_POWER, - &irq_reg_rx_power_state, - sizeof(irq_reg_rx_power_state)); - - if (dpcd_result != DC_OK) { - DC_LOG_HW_HPD_IRQ("%s: DPCD read failed to obtain power state.\n", - __func__); - } else { - if (irq_reg_rx_power_state != DP_SET_POWER_D0) - return_code = false; - } - } - - return return_code; -} - -static enum dc_status read_hpd_rx_irq_data( - struct dc_link *link, - union hpd_irq_data *irq_data) -{ - static enum dc_status retval; - - /* The HW reads 16 bytes from 200h on HPD, - * but if we get an AUX_DEFER, the HW cannot retry - * and this causes the CTS tests 4.3.2.1 - 3.2.4 to - * fail, so we now explicitly read 6 bytes which is - * the req from the above mentioned test cases. - * - * For DP 1.4 we need to read those from 2002h range. - */ - if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14) - retval = core_link_read_dpcd( - link, - DP_SINK_COUNT, - irq_data->raw, - sizeof(union hpd_irq_data)); - else { - /* Read 14 bytes in a single read and then copy only the required fields. - * This is more efficient than doing it in two separate AUX reads. */ - - uint8_t tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI + 1]; - - retval = core_link_read_dpcd( - link, - DP_SINK_COUNT_ESI, - tmp, - sizeof(tmp)); - - if (retval != DC_OK) - return retval; - - irq_data->bytes.sink_cnt.raw = tmp[DP_SINK_COUNT_ESI - DP_SINK_COUNT_ESI]; - irq_data->bytes.device_service_irq.raw = tmp[DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 - DP_SINK_COUNT_ESI]; - irq_data->bytes.lane01_status.raw = tmp[DP_LANE0_1_STATUS_ESI - DP_SINK_COUNT_ESI]; - irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI]; - irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI]; - irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI]; - } - - return retval; -} - static bool allow_hpd_rx_irq(const struct dc_link *link) { /* @@ -2196,7 +2203,7 @@ static void get_active_converter_info( } if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_11) { - uint8_t det_caps[4]; + uint8_t det_caps[16]; /* CTS 4.2.2.7 expects source to read Detailed Capabilities Info : 00080h-0008F.*/ union dwnstream_port_caps_byte0 *port_caps = (union dwnstream_port_caps_byte0 *)det_caps; core_link_read_dpcd(link, DP_DOWNSTREAM_PORT_0, @@ -2240,7 +2247,8 @@ static void get_active_converter_info( translate_dpcd_max_bpc( hdmi_color_caps.bits.MAX_BITS_PER_COLOR_COMPONENT); - link->dpcd_caps.dongle_caps.extendedCapValid = true; + if (link->dpcd_caps.dongle_caps.dp_hdmi_max_pixel_clk != 0) + link->dpcd_caps.dongle_caps.extendedCapValid = true; } break; @@ -2371,11 +2379,22 @@ static bool retrieve_link_cap(struct dc_link *link) dpcd_data[DP_TRAINING_AUX_RD_INTERVAL]; if (aux_rd_interval.bits.EXT_RECIEVER_CAP_FIELD_PRESENT == 1) { - core_link_read_dpcd( + uint8_t ext_cap_data[16]; + + memset(ext_cap_data, '\0', sizeof(ext_cap_data)); + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( link, DP_DP13_DPCD_REV, - dpcd_data, - sizeof(dpcd_data)); + ext_cap_data, + sizeof(ext_cap_data)); + if (status == DC_OK) { + memcpy(dpcd_data, ext_cap_data, sizeof(dpcd_data)); + break; + } + } + if (status != DC_OK) + dm_error("%s: Read extend caps data failed, use cap from dpcd 0.\n", __func__); } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 82cd1d6e6e59..0065ec7d5330 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -96,6 +96,7 @@ void dp_enable_link_phy( link_settings, clock_source); } + link->cur_link_settings = *link_settings; dp_receiver_power_ctrl(link, true); } @@ -307,6 +308,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, link->link_enc, link_setting, pipes[i].clock_source->id); + link->cur_link_settings = *link_setting; dp_receiver_power_ctrl(link, true); @@ -316,7 +318,6 @@ void dp_retrain_link_dp_test(struct dc_link *link, skip_video_pattern, LINK_TRAINING_ATTEMPTS); - link->cur_link_settings = *link_setting; link->dc->hwss.enable_stream(&pipes[i]); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index fc65b0055167..76137df74a53 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -83,7 +83,10 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) dc_version = DCE_VERSION_11_22; break; case FAMILY_AI: - dc_version = DCE_VERSION_12_0; + if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev)) + dc_version = DCE_VERSION_12_1; + else + dc_version = DCE_VERSION_12_0; break; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case FAMILY_RV: @@ -136,6 +139,7 @@ struct resource_pool *dc_create_resource_pool( num_virtual_links, dc); break; case DCE_VERSION_12_0: + case DCE_VERSION_12_1: res_pool = dce120_create_resource_pool( num_virtual_links, dc); break; @@ -478,10 +482,29 @@ static enum pixel_format convert_pixel_format_to_dalsurface( return dal_pixel_format; } -static void rect_swap_helper(struct rect *rect) +static inline void get_vp_scan_direction( + enum dc_rotation_angle rotation, + bool horizontal_mirror, + bool *orthogonal_rotation, + bool *flip_vert_scan_dir, + bool *flip_horz_scan_dir) { - swap(rect->height, rect->width); - swap(rect->x, rect->y); + *orthogonal_rotation = false; + *flip_vert_scan_dir = false; + *flip_horz_scan_dir = false; + if (rotation == ROTATION_ANGLE_180) { + *flip_vert_scan_dir = true; + *flip_horz_scan_dir = true; + } else if (rotation == ROTATION_ANGLE_90) { + *orthogonal_rotation = true; + *flip_horz_scan_dir = true; + } else if (rotation == ROTATION_ANGLE_270) { + *orthogonal_rotation = true; + *flip_vert_scan_dir = true; + } + + if (horizontal_mirror) + *flip_horz_scan_dir = !*flip_horz_scan_dir; } static void calculate_viewport(struct pipe_ctx *pipe_ctx) @@ -490,33 +513,14 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) const struct dc_stream_state *stream = pipe_ctx->stream; struct scaler_data *data = &pipe_ctx->plane_res.scl_data; struct rect surf_src = plane_state->src_rect; - struct rect clip = { 0 }; + struct rect clip, dest; int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; bool pri_split = pipe_ctx->bottom_pipe && pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; bool sec_split = pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; - bool flip_vert_scan_dir = false, flip_horz_scan_dir = false; - - - /* - * We need take horizontal mirror into account. On an unrotated surface this means - * that the viewport offset is actually the offset from the other side of source - * image so we have to subtract the right edge of the viewport from the right edge of - * the source window. Similar to mirror we need to take into account how offset is - * affected for 270/180 rotations - */ - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) { - flip_vert_scan_dir = true; - flip_horz_scan_dir = true; - } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90) - flip_vert_scan_dir = true; - else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - flip_horz_scan_dir = true; - - if (pipe_ctx->plane_state->horizontal_mirror) - flip_horz_scan_dir = !flip_horz_scan_dir; + bool orthogonal_rotation, flip_y_start, flip_x_start; if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE || stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) { @@ -524,13 +528,10 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) sec_split = false; } - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - rect_swap_helper(&surf_src); - /* The actual clip is an intersection between stream * source and surface clip */ + dest = plane_state->dst_rect; clip.x = stream->src.x > plane_state->clip_rect.x ? stream->src.x : plane_state->clip_rect.x; @@ -547,66 +548,77 @@ static void calculate_viewport(struct pipe_ctx *pipe_ctx) stream->src.y + stream->src.height - clip.y : plane_state->clip_rect.y + plane_state->clip_rect.height - clip.y ; - /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio - * note: surf_src.ofs should be added after rotation/mirror offset direction - * adjustment since it is already in viewport space - * num_pixels = clip.num_pix * scl_ratio + /* + * Need to calculate how scan origin is shifted in vp space + * to correctly rotate clip and dst */ - data->viewport.x = (clip.x - plane_state->dst_rect.x) * - surf_src.width / plane_state->dst_rect.width; - data->viewport.width = clip.width * - surf_src.width / plane_state->dst_rect.width; - - data->viewport.y = (clip.y - plane_state->dst_rect.y) * - surf_src.height / plane_state->dst_rect.height; - data->viewport.height = clip.height * - surf_src.height / plane_state->dst_rect.height; + get_vp_scan_direction( + plane_state->rotation, + plane_state->horizontal_mirror, + &orthogonal_rotation, + &flip_y_start, + &flip_x_start); - if (flip_vert_scan_dir) - data->viewport.y = surf_src.height - data->viewport.y - data->viewport.height; - if (flip_horz_scan_dir) - data->viewport.x = surf_src.width - data->viewport.x - data->viewport.width; + if (orthogonal_rotation) { + swap(clip.x, clip.y); + swap(clip.width, clip.height); + swap(dest.x, dest.y); + swap(dest.width, dest.height); + } + if (flip_x_start) { + clip.x = dest.x + dest.width - clip.x - clip.width; + dest.x = 0; + } + if (flip_y_start) { + clip.y = dest.y + dest.height - clip.y - clip.height; + dest.y = 0; + } - data->viewport.x += surf_src.x; - data->viewport.y += surf_src.y; + /* offset = surf_src.ofs + (clip.ofs - surface->dst_rect.ofs) * scl_ratio + * num_pixels = clip.num_pix * scl_ratio + */ + data->viewport.x = surf_src.x + (clip.x - dest.x) * surf_src.width / dest.width; + data->viewport.width = clip.width * surf_src.width / dest.width; + + data->viewport.y = surf_src.y + (clip.y - dest.y) * surf_src.height / dest.height; + data->viewport.height = clip.height * surf_src.height / dest.height; + + /* Handle split */ + if (pri_split || sec_split) { + if (orthogonal_rotation) { + if (flip_y_start != pri_split) + data->viewport.height /= 2; + else { + data->viewport.y += data->viewport.height / 2; + /* Ceil offset pipe */ + data->viewport.height = (data->viewport.height + 1) / 2; + } + } else { + if (flip_x_start != pri_split) + data->viewport.width /= 2; + else { + data->viewport.x += data->viewport.width / 2; + /* Ceil offset pipe */ + data->viewport.width = (data->viewport.width + 1) / 2; + } + } + } /* Round down, compensate in init */ data->viewport_c.x = data->viewport.x / vpc_div; data->viewport_c.y = data->viewport.y / vpc_div; - data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? - dc_fixpt_half : dc_fixpt_zero; - data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? - dc_fixpt_half : dc_fixpt_zero; + data->inits.h_c = (data->viewport.x % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; + data->inits.v_c = (data->viewport.y % vpc_div) != 0 ? dc_fixpt_half : dc_fixpt_zero; + /* Round up, assume original video size always even dimensions */ data->viewport_c.width = (data->viewport.width + vpc_div - 1) / vpc_div; data->viewport_c.height = (data->viewport.height + vpc_div - 1) / vpc_div; - - /* Handle hsplit */ - if (sec_split) { - data->viewport.x += data->viewport.width / 2; - data->viewport_c.x += data->viewport_c.width / 2; - /* Ceil offset pipe */ - data->viewport.width = (data->viewport.width + 1) / 2; - data->viewport_c.width = (data->viewport_c.width + 1) / 2; - } else if (pri_split) { - if (data->viewport.width > 1) - data->viewport.width /= 2; - if (data->viewport_c.width > 1) - data->viewport_c.width /= 2; - } - - if (plane_state->rotation == ROTATION_ANGLE_90 || - plane_state->rotation == ROTATION_ANGLE_270) { - rect_swap_helper(&data->viewport_c); - rect_swap_helper(&data->viewport); - } } -static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full) +static void calculate_recout(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; const struct dc_stream_state *stream = pipe_ctx->stream; - struct rect surf_src = plane_state->src_rect; struct rect surf_clip = plane_state->clip_rect; bool pri_split = pipe_ctx->bottom_pipe && pipe_ctx->bottom_pipe->plane_state == pipe_ctx->plane_state; @@ -614,10 +626,6 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; bool top_bottom_split = stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM; - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - rect_swap_helper(&surf_src); - pipe_ctx->plane_res.scl_data.recout.x = stream->dst.x; if (stream->src.x < surf_clip.x) pipe_ctx->plane_res.scl_data.recout.x += (surf_clip.x @@ -646,7 +654,7 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full stream->dst.y + stream->dst.height - pipe_ctx->plane_res.scl_data.recout.y; - /* Handle h & vsplit */ + /* Handle h & v split, handle rotation using viewport */ if (sec_split && top_bottom_split) { pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height / 2; @@ -655,44 +663,14 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx, struct rect *recout_full (pipe_ctx->plane_res.scl_data.recout.height + 1) / 2; } else if (pri_split && top_bottom_split) pipe_ctx->plane_res.scl_data.recout.height /= 2; - else if (pri_split || sec_split) { - /* HMirror XOR Secondary_pipe XOR Rotation_180 */ - bool right_view = (sec_split != plane_state->horizontal_mirror) != - (plane_state->rotation == ROTATION_ANGLE_180); - - if (plane_state->rotation == ROTATION_ANGLE_90 - || plane_state->rotation == ROTATION_ANGLE_270) - /* Secondary_pipe XOR Rotation_270 */ - right_view = (plane_state->rotation == ROTATION_ANGLE_270) != sec_split; - - if (right_view) { - pipe_ctx->plane_res.scl_data.recout.x += - pipe_ctx->plane_res.scl_data.recout.width / 2; - /* Ceil offset pipe */ - pipe_ctx->plane_res.scl_data.recout.width = - (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2; - } else { - if (pipe_ctx->plane_res.scl_data.recout.width > 1) - pipe_ctx->plane_res.scl_data.recout.width /= 2; - } - } - /* Unclipped recout offset = stream dst offset + ((surf dst offset - stream surf_src offset) - * * 1/ stream scaling ratio) - (surf surf_src offset * 1/ full scl - * ratio) - */ - recout_full->x = stream->dst.x + (plane_state->dst_rect.x - stream->src.x) - * stream->dst.width / stream->src.width - - surf_src.x * plane_state->dst_rect.width / surf_src.width - * stream->dst.width / stream->src.width; - recout_full->y = stream->dst.y + (plane_state->dst_rect.y - stream->src.y) - * stream->dst.height / stream->src.height - - surf_src.y * plane_state->dst_rect.height / surf_src.height - * stream->dst.height / stream->src.height; - - recout_full->width = plane_state->dst_rect.width - * stream->dst.width / stream->src.width; - recout_full->height = plane_state->dst_rect.height - * stream->dst.height / stream->src.height; + else if (sec_split) { + pipe_ctx->plane_res.scl_data.recout.x += + pipe_ctx->plane_res.scl_data.recout.width / 2; + /* Ceil offset pipe */ + pipe_ctx->plane_res.scl_data.recout.width = + (pipe_ctx->plane_res.scl_data.recout.width + 1) / 2; + } else if (pri_split) + pipe_ctx->plane_res.scl_data.recout.width /= 2; } static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) @@ -705,9 +683,10 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) const int out_w = stream->dst.width; const int out_h = stream->dst.height; + /*Swap surf_src height and width since scaling ratios are in recout rotation*/ if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - rect_swap_helper(&surf_src); + swap(surf_src.height, surf_src.width); pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction( surf_src.width, @@ -744,351 +723,202 @@ static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.scl_data.ratios.vert_c, 19); } -static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx, struct rect *recout_full) +static inline void adjust_vp_and_init_for_seamless_clip( + bool flip_scan_dir, + int recout_skip, + int src_size, + int taps, + struct fixed31_32 ratio, + struct fixed31_32 *init, + int *vp_offset, + int *vp_size) { - struct scaler_data *data = &pipe_ctx->plane_res.scl_data; - struct rect src = pipe_ctx->plane_state->src_rect; - int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 - || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; - bool flip_vert_scan_dir = false, flip_horz_scan_dir = false; - - /* - * Need to calculate the scan direction for viewport to make adjustments - */ - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_180) { - flip_vert_scan_dir = true; - flip_horz_scan_dir = true; - } else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90) - flip_vert_scan_dir = true; - else if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) - flip_horz_scan_dir = true; - - if (pipe_ctx->plane_state->horizontal_mirror) - flip_horz_scan_dir = !flip_horz_scan_dir; - - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { - rect_swap_helper(&src); - rect_swap_helper(&data->viewport_c); - rect_swap_helper(&data->viewport); - } - - /* - * Init calculated according to formula: - * init = (scaling_ratio + number_of_taps + 1) / 2 - * init_bot = init + scaling_ratio - * init_c = init + truncated_vp_c_offset(from calculate viewport) - */ - data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19); - - data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19); - - data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19); - - data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( - dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); - - if (!flip_horz_scan_dir) { + if (!flip_scan_dir) { /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { - int vp_clip = src.x + src.width - data->viewport.width - data->viewport.x; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h, data->ratios.horz)); + if ((*vp_offset + *vp_size) < src_size) { + int vp_clip = src_size - *vp_size - *vp_offset; + int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); int_part = int_part > 0 ? int_part : 0; - data->viewport.width += int_part < vp_clip ? int_part : vp_clip; - } - if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) { - int vp_clip = (src.x + src.width) / vpc_div - - data->viewport_c.width - data->viewport_c.x; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.width += int_part < vp_clip ? int_part : vp_clip; + *vp_size += int_part < vp_clip ? int_part : vp_clip; } /* Adjust for non-0 viewport offset */ - if (data->viewport.x) { + if (*vp_offset) { int int_part; - data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( - data->ratios.horz, data->recout.x - recout_full->x)); - int_part = dc_fixpt_floor(data->inits.h) - data->viewport.x; - if (int_part < data->taps.h_taps) { - int int_adj = data->viewport.x >= (data->taps.h_taps - int_part) ? - (data->taps.h_taps - int_part) : data->viewport.x; - data->viewport.x -= int_adj; - data->viewport.width += int_adj; + *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); + int_part = dc_fixpt_floor(*init) - *vp_offset; + if (int_part < taps) { + int int_adj = *vp_offset >= (taps - int_part) ? + (taps - int_part) : *vp_offset; + *vp_offset -= int_adj; + *vp_size += int_adj; int_part += int_adj; - } else if (int_part > data->taps.h_taps) { - data->viewport.x += int_part - data->taps.h_taps; - data->viewport.width -= int_part - data->taps.h_taps; - int_part = data->taps.h_taps; + } else if (int_part > taps) { + *vp_offset += int_part - taps; + *vp_size -= int_part - taps; + int_part = taps; } - data->inits.h.value &= 0xffffffff; - data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); - } - - if (data->viewport_c.x) { - int int_part; - - data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( - data->ratios.horz_c, data->recout.x - recout_full->x)); - int_part = dc_fixpt_floor(data->inits.h_c) - data->viewport_c.x; - if (int_part < data->taps.h_taps_c) { - int int_adj = data->viewport_c.x >= (data->taps.h_taps_c - int_part) ? - (data->taps.h_taps_c - int_part) : data->viewport_c.x; - data->viewport_c.x -= int_adj; - data->viewport_c.width += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.h_taps_c) { - data->viewport_c.x += int_part - data->taps.h_taps_c; - data->viewport_c.width -= int_part - data->taps.h_taps_c; - int_part = data->taps.h_taps_c; - } - data->inits.h_c.value &= 0xffffffff; - data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); + init->value &= 0xffffffff; + *init = dc_fixpt_add_int(*init, int_part); } } else { /* Adjust for non-0 viewport offset */ - if (data->viewport.x) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h, data->ratios.horz)); + if (*vp_offset) { + int int_part = dc_fixpt_floor(dc_fixpt_sub(*init, ratio)); int_part = int_part > 0 ? int_part : 0; - data->viewport.width += int_part < data->viewport.x ? int_part : data->viewport.x; - data->viewport.x -= int_part < data->viewport.x ? int_part : data->viewport.x; - } - if (data->viewport_c.x) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.h_c, data->ratios.horz_c)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.width += int_part < data->viewport_c.x ? int_part : data->viewport_c.x; - data->viewport_c.x -= int_part < data->viewport_c.x ? int_part : data->viewport_c.x; + *vp_size += int_part < *vp_offset ? int_part : *vp_offset; + *vp_offset -= int_part < *vp_offset ? int_part : *vp_offset; } /* Adjust for viewport end clip-off */ - if ((data->viewport.x + data->viewport.width) < (src.x + src.width)) { - int int_part; - int end_offset = src.x + src.width - - data->viewport.x - data->viewport.width; - - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - data->inits.h = dc_fixpt_add(data->inits.h, dc_fixpt_mul_int( - data->ratios.horz, data->recout.x - recout_full->x)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, takning into account scan direction - */ - int_part = dc_fixpt_floor(data->inits.h) - end_offset; - if (int_part < data->taps.h_taps) { - int int_adj = end_offset >= (data->taps.h_taps - int_part) ? - (data->taps.h_taps - int_part) : end_offset; - data->viewport.width += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.h_taps) { - data->viewport.width += int_part - data->taps.h_taps; - int_part = data->taps.h_taps; - } - data->inits.h.value &= 0xffffffff; - data->inits.h = dc_fixpt_add_int(data->inits.h, int_part); - } - - if ((data->viewport_c.x + data->viewport_c.width) < (src.x + src.width) / vpc_div) { + if ((*vp_offset + *vp_size) < src_size) { int int_part; - int end_offset = (src.x + src.width) / vpc_div - - data->viewport_c.x - data->viewport_c.width; + int end_offset = src_size - *vp_offset - *vp_size; /* * this is init if vp had no offset, keep in mind this is from the * right side of vp due to scan direction */ - data->inits.h_c = dc_fixpt_add(data->inits.h_c, dc_fixpt_mul_int( - data->ratios.horz_c, data->recout.x - recout_full->x)); + *init = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_skip)); /* * this is the difference between first pixel of viewport available to read * and init position, takning into account scan direction */ - int_part = dc_fixpt_floor(data->inits.h_c) - end_offset; - if (int_part < data->taps.h_taps_c) { - int int_adj = end_offset >= (data->taps.h_taps_c - int_part) ? - (data->taps.h_taps_c - int_part) : end_offset; - data->viewport_c.width += int_adj; + int_part = dc_fixpt_floor(*init) - end_offset; + if (int_part < taps) { + int int_adj = end_offset >= (taps - int_part) ? + (taps - int_part) : end_offset; + *vp_size += int_adj; int_part += int_adj; - } else if (int_part > data->taps.h_taps_c) { - data->viewport_c.width += int_part - data->taps.h_taps_c; - int_part = data->taps.h_taps_c; + } else if (int_part > taps) { + *vp_size += int_part - taps; + int_part = taps; } - data->inits.h_c.value &= 0xffffffff; - data->inits.h_c = dc_fixpt_add_int(data->inits.h_c, int_part); + init->value &= 0xffffffff; + *init = dc_fixpt_add_int(*init, int_part); } - } - if (!flip_vert_scan_dir) { - /* Adjust for viewport end clip-off */ - if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) { - int vp_clip = src.y + src.height - data->viewport.height - data->viewport.y; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v, data->ratios.vert)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport.height += int_part < vp_clip ? int_part : vp_clip; - } - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) { - int vp_clip = (src.y + src.height) / vpc_div - - data->viewport_c.height - data->viewport_c.y; - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c)); - - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.height += int_part < vp_clip ? int_part : vp_clip; - } - - /* Adjust for non-0 viewport offset */ - if (data->viewport.y) { - int int_part; - - data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( - data->ratios.vert, data->recout.y - recout_full->y)); - int_part = dc_fixpt_floor(data->inits.v) - data->viewport.y; - if (int_part < data->taps.v_taps) { - int int_adj = data->viewport.y >= (data->taps.v_taps - int_part) ? - (data->taps.v_taps - int_part) : data->viewport.y; - data->viewport.y -= int_adj; - data->viewport.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps) { - data->viewport.y += int_part - data->taps.v_taps; - data->viewport.height -= int_part - data->taps.v_taps; - int_part = data->taps.v_taps; - } - data->inits.v.value &= 0xffffffff; - data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); - } - - if (data->viewport_c.y) { - int int_part; +} - data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( - data->ratios.vert_c, data->recout.y - recout_full->y)); - int_part = dc_fixpt_floor(data->inits.v_c) - data->viewport_c.y; - if (int_part < data->taps.v_taps_c) { - int int_adj = data->viewport_c.y >= (data->taps.v_taps_c - int_part) ? - (data->taps.v_taps_c - int_part) : data->viewport_c.y; - data->viewport_c.y -= int_adj; - data->viewport_c.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps_c) { - data->viewport_c.y += int_part - data->taps.v_taps_c; - data->viewport_c.height -= int_part - data->taps.v_taps_c; - int_part = data->taps.v_taps_c; - } - data->inits.v_c.value &= 0xffffffff; - data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); - } - } else { - /* Adjust for non-0 viewport offset */ - if (data->viewport.y) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v, data->ratios.vert)); +static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) +{ + const struct dc_plane_state *plane_state = pipe_ctx->plane_state; + const struct dc_stream_state *stream = pipe_ctx->stream; + struct scaler_data *data = &pipe_ctx->plane_res.scl_data; + struct rect src = pipe_ctx->plane_state->src_rect; + int recout_skip_h, recout_skip_v, surf_size_h, surf_size_v; + int vpc_div = (data->format == PIXEL_FORMAT_420BPP8 + || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1; + bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir; - int_part = int_part > 0 ? int_part : 0; - data->viewport.height += int_part < data->viewport.y ? int_part : data->viewport.y; - data->viewport.y -= int_part < data->viewport.y ? int_part : data->viewport.y; - } - if (data->viewport_c.y) { - int int_part = dc_fixpt_floor( - dc_fixpt_sub(data->inits.v_c, data->ratios.vert_c)); + /* + * Need to calculate the scan direction for viewport to make adjustments + */ + get_vp_scan_direction( + plane_state->rotation, + plane_state->horizontal_mirror, + &orthogonal_rotation, + &flip_vert_scan_dir, + &flip_horz_scan_dir); + + /* Calculate src rect rotation adjusted to recout space */ + surf_size_h = src.x + src.width; + surf_size_v = src.y + src.height; + if (flip_horz_scan_dir) + src.x = 0; + if (flip_vert_scan_dir) + src.y = 0; + if (orthogonal_rotation) { + swap(src.x, src.y); + swap(src.width, src.height); + } - int_part = int_part > 0 ? int_part : 0; - data->viewport_c.height += int_part < data->viewport_c.y ? int_part : data->viewport_c.y; - data->viewport_c.y -= int_part < data->viewport_c.y ? int_part : data->viewport_c.y; - } + /* Recout matching initial vp offset = recout_offset - (stream dst offset + + * ((surf dst offset - stream src offset) * 1/ stream scaling ratio) + * - (surf surf_src offset * 1/ full scl ratio)) + */ + recout_skip_h = data->recout.x - (stream->dst.x + (plane_state->dst_rect.x - stream->src.x) + * stream->dst.width / stream->src.width - + src.x * plane_state->dst_rect.width / src.width + * stream->dst.width / stream->src.width); + recout_skip_v = data->recout.y - (stream->dst.y + (plane_state->dst_rect.y - stream->src.y) + * stream->dst.height / stream->src.height - + src.y * plane_state->dst_rect.height / src.height + * stream->dst.height / stream->src.height); + if (orthogonal_rotation) + swap(recout_skip_h, recout_skip_v); + /* + * Init calculated according to formula: + * init = (scaling_ratio + number_of_taps + 1) / 2 + * init_bot = init + scaling_ratio + * init_c = init + truncated_vp_c_offset(from calculate viewport) + */ + data->inits.h = dc_fixpt_truncate(dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.horz, data->taps.h_taps + 1), 2), 19); - /* Adjust for viewport end clip-off */ - if ((data->viewport.y + data->viewport.height) < (src.y + src.height)) { - int int_part; - int end_offset = src.y + src.height - - data->viewport.y - data->viewport.height; + data->inits.h_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.h_c, dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.horz_c, data->taps.h_taps_c + 1), 2)), 19); - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - data->inits.v = dc_fixpt_add(data->inits.v, dc_fixpt_mul_int( - data->ratios.vert, data->recout.y - recout_full->y)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, taking into account scan direction - */ - int_part = dc_fixpt_floor(data->inits.v) - end_offset; - if (int_part < data->taps.v_taps) { - int int_adj = end_offset >= (data->taps.v_taps - int_part) ? - (data->taps.v_taps - int_part) : end_offset; - data->viewport.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps) { - data->viewport.height += int_part - data->taps.v_taps; - int_part = data->taps.v_taps; - } - data->inits.v.value &= 0xffffffff; - data->inits.v = dc_fixpt_add_int(data->inits.v, int_part); - } + data->inits.v = dc_fixpt_truncate(dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.vert, data->taps.v_taps + 1), 2), 19); - if ((data->viewport_c.y + data->viewport_c.height) < (src.y + src.height) / vpc_div) { - int int_part; - int end_offset = (src.y + src.height) / vpc_div - - data->viewport_c.y - data->viewport_c.height; + data->inits.v_c = dc_fixpt_truncate(dc_fixpt_add(data->inits.v_c, dc_fixpt_div_int( + dc_fixpt_add_int(data->ratios.vert_c, data->taps.v_taps_c + 1), 2)), 19); - /* - * this is init if vp had no offset, keep in mind this is from the - * right side of vp due to scan direction - */ - data->inits.v_c = dc_fixpt_add(data->inits.v_c, dc_fixpt_mul_int( - data->ratios.vert_c, data->recout.y - recout_full->y)); - /* - * this is the difference between first pixel of viewport available to read - * and init position, taking into account scan direction - */ - int_part = dc_fixpt_floor(data->inits.v_c) - end_offset; - if (int_part < data->taps.v_taps_c) { - int int_adj = end_offset >= (data->taps.v_taps_c - int_part) ? - (data->taps.v_taps_c - int_part) : end_offset; - data->viewport_c.height += int_adj; - int_part += int_adj; - } else if (int_part > data->taps.v_taps_c) { - data->viewport_c.height += int_part - data->taps.v_taps_c; - int_part = data->taps.v_taps_c; - } - data->inits.v_c.value &= 0xffffffff; - data->inits.v_c = dc_fixpt_add_int(data->inits.v_c, int_part); - } - } + /* + * Taps, inits and scaling ratios are in recout space need to rotate + * to viewport rotation before adjustment + */ + adjust_vp_and_init_for_seamless_clip( + flip_horz_scan_dir, + recout_skip_h, + surf_size_h, + orthogonal_rotation ? data->taps.v_taps : data->taps.h_taps, + orthogonal_rotation ? data->ratios.vert : data->ratios.horz, + orthogonal_rotation ? &data->inits.v : &data->inits.h, + &data->viewport.x, + &data->viewport.width); + adjust_vp_and_init_for_seamless_clip( + flip_horz_scan_dir, + recout_skip_h, + surf_size_h / vpc_div, + orthogonal_rotation ? data->taps.v_taps_c : data->taps.h_taps_c, + orthogonal_rotation ? data->ratios.vert_c : data->ratios.horz_c, + orthogonal_rotation ? &data->inits.v_c : &data->inits.h_c, + &data->viewport_c.x, + &data->viewport_c.width); + adjust_vp_and_init_for_seamless_clip( + flip_vert_scan_dir, + recout_skip_v, + surf_size_v, + orthogonal_rotation ? data->taps.h_taps : data->taps.v_taps, + orthogonal_rotation ? data->ratios.horz : data->ratios.vert, + orthogonal_rotation ? &data->inits.h : &data->inits.v, + &data->viewport.y, + &data->viewport.height); + adjust_vp_and_init_for_seamless_clip( + flip_vert_scan_dir, + recout_skip_v, + surf_size_v / vpc_div, + orthogonal_rotation ? data->taps.h_taps_c : data->taps.v_taps_c, + orthogonal_rotation ? data->ratios.horz_c : data->ratios.vert_c, + orthogonal_rotation ? &data->inits.h_c : &data->inits.v_c, + &data->viewport_c.y, + &data->viewport_c.height); /* Interlaced inits based on final vert inits */ data->inits.v_bot = dc_fixpt_add(data->inits.v, data->ratios.vert); data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { - rect_swap_helper(&data->viewport_c); - rect_swap_helper(&data->viewport); - } } bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - struct rect recout_full = { 0 }; bool res = false; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); /* Important: scaling ratio calculation requires pixel format, @@ -1105,7 +935,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) if (pipe_ctx->plane_res.scl_data.viewport.height < 16 || pipe_ctx->plane_res.scl_data.viewport.width < 16) return false; - calculate_recout(pipe_ctx, &recout_full); + calculate_recout(pipe_ctx); /** * Setting line buffer pixel depth to 24bpp yields banding @@ -1146,7 +976,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) if (res) /* May need to re-check lb size after this in some obscure scenario */ - calculate_inits_and_adj_vp(pipe_ctx, &recout_full); + calculate_inits_and_adj_vp(pipe_ctx); DC_LOG_SCALER( "%s: Viewport:\nheight:%d width:%d x:%d " @@ -1356,6 +1186,9 @@ bool dc_add_plane_to_context( return false; } + tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); + ASSERT(tail_pipe); + free_pipe = acquire_free_pipe_for_stream(context, pool, stream); #if defined(CONFIG_DRM_AMD_DC_DCN1_0) @@ -1373,10 +1206,6 @@ bool dc_add_plane_to_context( free_pipe->plane_state = plane_state; if (head_pipe != free_pipe) { - - tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); - ASSERT(tail_pipe); - free_pipe->stream_res.tg = tail_pipe->stream_res.tg; free_pipe->stream_res.abm = tail_pipe->stream_res.abm; free_pipe->stream_res.opp = tail_pipe->stream_res.opp; @@ -1622,6 +1451,14 @@ static bool are_stream_backends_same( return true; } +/** + * dc_is_stream_unchanged() - Compare two stream states for equivalence. + * + * Checks if there a difference between the two states + * that would require a mode change. + * + * Does not compare cursor position or attributes. + */ bool dc_is_stream_unchanged( struct dc_stream_state *old_stream, struct dc_stream_state *stream) { @@ -1632,6 +1469,9 @@ bool dc_is_stream_unchanged( return true; } +/** + * dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams. + */ bool dc_is_stream_scaling_unchanged( struct dc_stream_state *old_stream, struct dc_stream_state *stream) { @@ -1791,16 +1631,19 @@ bool resource_is_stream_unchanged( return false; } +/** + * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state. + */ enum dc_status dc_add_stream_to_ctx( struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *stream) { - struct dc_context *dc_ctx = dc->ctx; enum dc_status res; + DC_LOGGER_INIT(dc->ctx->logger); if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { - DC_ERROR("Max streams reached, can't add stream %p !\n", stream); + DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); return DC_ERROR_UNEXPECTED; } @@ -1810,11 +1653,14 @@ enum dc_status dc_add_stream_to_ctx( res = dc->res_pool->funcs->add_stream_to_ctx(dc, new_ctx, stream); if (res != DC_OK) - DC_ERROR("Adding stream %p to context failed with err %d!\n", stream, res); + DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); return res; } +/** + * dc_remove_stream_from_ctx() - Remove a stream from a dc_state. + */ enum dc_status dc_remove_stream_from_ctx( struct dc *dc, struct dc_state *new_ctx, @@ -1976,6 +1822,8 @@ enum dc_status resource_map_pool_resources( } */ + calculate_phy_pix_clks(stream); + /* acquire new resources */ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); @@ -2033,6 +1881,12 @@ enum dc_status resource_map_pool_resources( return DC_ERROR_UNEXPECTED; } +/** + * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state + * Is a shallow copy. Increments refcounts on existing streams and planes. + * @dc: copy out of dc->current_state + * @dst_ctx: copy into this + */ void dc_resource_state_copy_construct_current( const struct dc *dc, struct dc_state *dst_ctx) @@ -2048,6 +1902,14 @@ void dc_resource_state_construct( dst_ctx->dccg = dc->res_pool->clk_mgr; } +/** + * dc_validate_global_state() - Determine if HW can support a given state + * Checks HW resource availability and bandwidth requirement. + * @dc: dc struct for this driver + * @new_ctx: state to be validated + * + * Return: DC_OK if the result can be programmed. Otherwise, an error code. + */ enum dc_status dc_validate_global_state( struct dc *dc, struct dc_state *new_ctx) @@ -2375,113 +2237,15 @@ static void set_vendor_info_packet( struct dc_info_packet *info_packet, struct dc_stream_state *stream) { - uint32_t length = 0; - bool hdmi_vic_mode = false; - uint8_t checksum = 0; - uint32_t i = 0; - enum dc_timing_3d_format format; - // Can be different depending on packet content /*todo*/ - // unsigned int length = pPathMode->dolbyVision ? 24 : 5; - - info_packet->valid = false; - - format = stream->timing.timing_3d_format; - if (stream->view_format == VIEW_3D_FORMAT_NONE) - format = TIMING_3D_FORMAT_NONE; - - /* Can be different depending on packet content */ - length = 5; - - if (stream->timing.hdmi_vic != 0 - && stream->timing.h_total >= 3840 - && stream->timing.v_total >= 2160) - hdmi_vic_mode = true; - - /* According to HDMI 1.4a CTS, VSIF should be sent - * for both 3D stereo and HDMI VIC modes. - * For all other modes, there is no VSIF sent. */ + /* SPD info packet for FreeSync */ - if (format == TIMING_3D_FORMAT_NONE && !hdmi_vic_mode) + /* Check if Freesync is supported. Return if false. If true, + * set the corresponding bit in the info packet + */ + if (!stream->vsp_infopacket.valid) return; - /* 24bit IEEE Registration identifier (0x000c03). LSB first. */ - info_packet->sb[1] = 0x03; - info_packet->sb[2] = 0x0C; - info_packet->sb[3] = 0x00; - - /*PB4: 5 lower bytes = 0 (reserved). 3 higher bits = HDMI_Video_Format. - * The value for HDMI_Video_Format are: - * 0x0 (0b000) - No additional HDMI video format is presented in this - * packet - * 0x1 (0b001) - Extended resolution format present. 1 byte of HDMI_VIC - * parameter follows - * 0x2 (0b010) - 3D format indication present. 3D_Structure and - * potentially 3D_Ext_Data follows - * 0x3..0x7 (0b011..0b111) - reserved for future use */ - if (format != TIMING_3D_FORMAT_NONE) - info_packet->sb[4] = (2 << 5); - else if (hdmi_vic_mode) - info_packet->sb[4] = (1 << 5); - - /* PB5: If PB4 claims 3D timing (HDMI_Video_Format = 0x2): - * 4 lower bites = 0 (reserved). 4 higher bits = 3D_Structure. - * The value for 3D_Structure are: - * 0x0 - Frame Packing - * 0x1 - Field Alternative - * 0x2 - Line Alternative - * 0x3 - Side-by-Side (full) - * 0x4 - L + depth - * 0x5 - L + depth + graphics + graphics-depth - * 0x6 - Top-and-Bottom - * 0x7 - Reserved for future use - * 0x8 - Side-by-Side (Half) - * 0x9..0xE - Reserved for future use - * 0xF - Not used */ - switch (format) { - case TIMING_3D_FORMAT_HW_FRAME_PACKING: - case TIMING_3D_FORMAT_SW_FRAME_PACKING: - info_packet->sb[5] = (0x0 << 4); - break; - - case TIMING_3D_FORMAT_SIDE_BY_SIDE: - case TIMING_3D_FORMAT_SBS_SW_PACKED: - info_packet->sb[5] = (0x8 << 4); - length = 6; - break; - - case TIMING_3D_FORMAT_TOP_AND_BOTTOM: - case TIMING_3D_FORMAT_TB_SW_PACKED: - info_packet->sb[5] = (0x6 << 4); - break; - - default: - break; - } - - /*PB5: If PB4 is set to 0x1 (extended resolution format) - * fill PB5 with the correct HDMI VIC code */ - if (hdmi_vic_mode) - info_packet->sb[5] = stream->timing.hdmi_vic; - - /* Header */ - info_packet->hb0 = HDMI_INFOFRAME_TYPE_VENDOR; /* VSIF packet type. */ - info_packet->hb1 = 0x01; /* Version */ - - /* 4 lower bits = Length, 4 higher bits = 0 (reserved) */ - info_packet->hb2 = (uint8_t) (length); - - /* Calculate checksum */ - checksum = 0; - checksum += info_packet->hb0; - checksum += info_packet->hb1; - checksum += info_packet->hb2; - - for (i = 1; i <= length; i++) - checksum += info_packet->sb[i]; - - info_packet->sb[0] = (uint8_t) (0x100 - checksum); - - info_packet->valid = true; + *info_packet = stream->vsp_infopacket; } static void set_spd_info_packet( @@ -2537,10 +2301,6 @@ void dc_resource_state_destruct(struct dc_state *context) } } -/* - * Copy src_ctx into dst_ctx and retain all surfaces and streams referenced - * by the src_ctx - */ void dc_resource_state_copy_construct( const struct dc_state *src_ctx, struct dc_state *dst_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index e113439aaa86..66e5c4623a49 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -100,8 +100,6 @@ static void construct(struct dc_stream_state *stream, /* EDID CAP translation for HDMI 2.0 */ stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble; - stream->status.link = stream->sink->link; - update_stream_signal(stream); stream->out_transfer_func = dc_create_transfer_func(); @@ -172,7 +170,7 @@ struct dc_stream_status *dc_stream_get_status( } /** - * Update the cursor attributes and set cursor surface address + * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address */ bool dc_stream_set_cursor_attributes( struct dc_stream_state *stream, diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index d16a20c84792..4b5bbb13ce7f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -36,9 +36,10 @@ #include "inc/hw_sequencer.h" #include "inc/compressor.h" +#include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.04" +#define DC_VER "3.2.08" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -47,13 +48,6 @@ /******************************************************************************* * Display Core Interfaces ******************************************************************************/ -struct dmcu_version { - unsigned int date; - unsigned int month; - unsigned int year; - unsigned int interface_version; -}; - struct dc_versions { const char *dc_ver; struct dmcu_version dmcu_version; @@ -748,5 +742,6 @@ void dc_set_power_state( struct dc *dc, enum dc_acpi_cm_power_state power_state); void dc_resume(struct dc *dc); +bool dc_is_dmcu_initialized(struct dc *dc); #endif /* DC_INTERFACE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index fcfd50b5dba0..4842d2378bbf 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -234,14 +234,14 @@ uint32_t generic_reg_wait(const struct dc_context *ctx, if (field_value == condition_value) { if (i * delay_between_poll_us > 1000 && !IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) - dm_output_to_console("REG_WAIT taking a while: %dms in %s line:%d\n", + DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n", delay_between_poll_us * i / 1000, func_name, line); return reg_val; } } - dm_error("REG_WAIT timeout %dus * %d tries - %s line:%d\n", + DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n", delay_between_poll_us, time_out_num_tries, func_name, line); diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index 7825e4b5e97c..e72fce4eca65 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -192,7 +192,6 @@ enum surface_pixel_format { /*swaped & float*/ SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F, /*grow graphics here if necessary */ - SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888, SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr = SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, @@ -200,6 +199,7 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb, SURFACE_PIXEL_FORMAT_SUBSAMPLE_END, + SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888, SURFACE_PIXEL_FORMAT_INVALID /*grow 444 video here if necessary */ @@ -358,15 +358,16 @@ union dc_tiling_info { } gfx8; struct { + enum swizzle_mode_values swizzle; unsigned int num_pipes; - unsigned int num_banks; + unsigned int max_compressed_frags; unsigned int pipe_interleave; + + unsigned int num_banks; unsigned int num_shader_engines; unsigned int num_rb_per_se; - unsigned int max_compressed_frags; bool shaderEnable; - enum swizzle_mode_values swizzle; bool meta_linear; bool rb_aligned; bool pipe_aligned; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 8738f27a8708..29f19d57ff7a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -128,8 +128,10 @@ struct dc_link { const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link); -/* - * Return an enumerated dc_link. dc_link order is constant and determined at +/** + * dc_get_link_at_index() - Return an enumerated dc_link. + * + * dc_link order is constant and determined at * boot time. They cannot be created or destroyed. * Use dc_get_caps() to get number of links. */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index c5bd1fbb6982..be34d638e15d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -56,6 +56,7 @@ struct dc_stream_state { struct dc_crtc_timing_adjust adjust; struct dc_info_packet vrr_infopacket; struct dc_info_packet vsc_infopacket; + struct dc_info_packet vsp_infopacket; struct rect src; /* composition area */ struct rect dst; /* stream addressable area */ @@ -104,8 +105,6 @@ struct dc_stream_state { bool dpms_off; bool apply_edp_fast_boot_optimization; - struct dc_stream_status status; - struct dc_cursor_attributes cursor_attributes; struct dc_cursor_position cursor_position; uint32_t sdr_white_level; // for boosting (SDR) cursor in HDR mode @@ -131,11 +130,13 @@ struct dc_stream_update { struct dc_crtc_timing_adjust *adjust; struct dc_info_packet *vrr_infopacket; struct dc_info_packet *vsc_infopacket; + struct dc_info_packet *vsp_infopacket; bool *dpms_off; struct colorspace_transform *gamut_remap; enum dc_color_space *output_color_space; + enum dc_dither_option *dither_option; struct dc_csc_transform *output_csc_transform; diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 6e12d640d020..0b20ae23f169 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -73,10 +73,18 @@ struct hw_asic_id { void *atombios_base_address; }; +struct dc_perf_trace { + unsigned long read_count; + unsigned long write_count; + unsigned long last_entry_read; + unsigned long last_entry_write; +}; + struct dc_context { struct dc *dc; void *driver_context; /* e.g. amdgpu_device */ + struct dc_perf_trace *perf_trace; void *cgs_device; enum dce_environment dce_environment; @@ -191,7 +199,6 @@ union display_content_support { }; struct dc_panel_patch { - unsigned int disconnect_delay; unsigned int dppowerup_delay; unsigned int extra_t12_ms; }; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c index 9a28a04417d1..afd287f08bc9 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c @@ -94,7 +94,7 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStatePerformance*/ { .display_clk_khz = 1133000, .pixel_clk_khz = 600000 } }; -static int dentist_get_divider_from_did(int did) +int dentist_get_divider_from_did(int did) { if (did < DENTIST_BASE_DID_1) did = DENTIST_BASE_DID_1; @@ -277,7 +277,8 @@ static int dce_set_clock( if (requested_clk_khz == 0) clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL; - dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7); + if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) + dmcu->funcs->set_psr_wait_loop(dmcu, actual_clock / 1000 / 7); return actual_clock; } @@ -324,9 +325,11 @@ int dce112_set_clock(struct clk_mgr *clk_mgr, int requested_clk_khz) bp->funcs->set_dce_clock(bp, &dce_clk_params); if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { - if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock) - dmcu->funcs->set_psr_wait_loop(dmcu, - actual_clock / 1000 / 7); + if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { + if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock) + dmcu->funcs->set_psr_wait_loop(dmcu, + actual_clock / 1000 / 7); + } } clk_mgr_dce->dfs_bypass_disp_clk = actual_clock; @@ -588,6 +591,8 @@ static void dce11_pplib_apply_display_requirements( dc, context->bw.dce.sclk_khz); + pp_display_cfg->min_dcfclock_khz = pp_display_cfg->min_engine_clock_khz; + pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dce.sclk_deep_sleep_khz; @@ -671,6 +676,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr, { struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr); struct dm_pp_power_level_change_request level_change_req; + int unpatched_disp_clk = context->bw.dce.dispclk_khz; + + /*TODO: W/A for dal3 linux, investigate why this works */ + if (!clk_mgr_dce->dfs_bypass_active) + context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context); /* get max clock state from PPLIB */ @@ -685,6 +695,8 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr, clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz; } dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context); + + context->bw.dce.dispclk_khz = unpatched_disp_clk; } static void dce12_update_clocks(struct clk_mgr *clk_mgr, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h index 046077797416..3bceb31d910d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h @@ -165,4 +165,6 @@ struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx); void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr); +int dentist_get_divider_from_did(int did); + #endif /* _DCE_CLK_MGR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index c47c81883d3c..cce0d18f91da 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -908,7 +908,6 @@ static void dce110_stream_encoder_dp_blank( struct stream_encoder *enc) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); - uint32_t retries = 0; uint32_t reg1 = 0; uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; @@ -926,30 +925,28 @@ static void dce110_stream_encoder_dp_blank( * (2 = start of the next vertical blank) */ REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, 2); /* Larger delay to wait until VBLANK - use max retry of - * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + - * a little more because we may not trust delay accuracy. - */ + * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + + * a little more because we may not trust delay accuracy. + */ max_retries = DP_BLANK_MAX_RETRY * 150; /* disable DP stream */ REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0); /* the encoder stops sending the video stream - * at the start of the vertical blanking. - * Poll for DP_VID_STREAM_STATUS == 0 - */ + * at the start of the vertical blanking. + * Poll for DP_VID_STREAM_STATUS == 0 + */ REG_WAIT(DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, 0, 10, max_retries); - ASSERT(retries <= max_retries); - /* Tell the DP encoder to ignore timing from CRTC, must be done after - * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is - * complete, stream status will be stuck in video stream enabled state, - * i.e. DP_VID_STREAM_STATUS stuck at 1. - */ + * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is + * complete, stream status will be stuck in video stream enabled state, + * i.e. DP_VID_STREAM_STATUS stuck at 1. + */ REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, true); } diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c index bc50a8e25f4f..87771676acac 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c @@ -117,6 +117,18 @@ void dce100_prepare_bandwidth( false); } +void dce100_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); + + dc->res_pool->clk_mgr->funcs->update_clocks( + dc->res_pool->clk_mgr, + context, + true); +} + /**************************************************************************/ void dce100_hw_sequencer_construct(struct dc *dc) @@ -125,6 +137,6 @@ void dce100_hw_sequencer_construct(struct dc *dc) dc->hwss.enable_display_power_gating = dce100_enable_display_power_gating; dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth; - dc->hwss.optimize_bandwidth = dce100_prepare_bandwidth; + dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index 1f7f25013217..52d50e24a995 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -64,65 +64,37 @@ static const struct dce110_compressor_reg_offsets reg_offsets[] = { static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600; -enum fbc_idle_force { - /* Bit 0 - Display registers updated */ - FBC_IDLE_FORCE_DISPLAY_REGISTER_UPDATE = 0x00000001, - - /* Bit 2 - FBC_GRPH_COMP_EN register updated */ - FBC_IDLE_FORCE_GRPH_COMP_EN = 0x00000002, - /* Bit 3 - FBC_SRC_SEL register updated */ - FBC_IDLE_FORCE_SRC_SEL_CHANGE = 0x00000004, - /* Bit 4 - FBC_MIN_COMPRESSION register updated */ - FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE = 0x00000008, - /* Bit 5 - FBC_ALPHA_COMP_EN register updated */ - FBC_IDLE_FORCE_ALPHA_COMP_EN = 0x00000010, - /* Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated */ - FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN = 0x00000020, - /* Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated */ - FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF = 0x00000040, - - /* Bit 24 - Memory write to region 0 defined by MC registers. */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION0 = 0x01000000, - /* Bit 25 - Memory write to region 1 defined by MC registers */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION1 = 0x02000000, - /* Bit 26 - Memory write to region 2 defined by MC registers */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION2 = 0x04000000, - /* Bit 27 - Memory write to region 3 defined by MC registers. */ - FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION3 = 0x08000000, - - /* Bit 28 - Memory write from any client other than MCIF */ - FBC_IDLE_FORCE_MEMORY_WRITE_OTHER_THAN_MCIF = 0x10000000, - /* Bit 29 - CG statics screen signal is inactive */ - FBC_IDLE_FORCE_CG_STATIC_SCREEN_IS_INACTIVE = 0x20000000, -}; - - static uint32_t align_to_chunks_number_per_line(uint32_t pixels) { return 256 * ((pixels + 255) / 256); } -static void reset_lb_on_vblank(struct dc_context *ctx) +static void reset_lb_on_vblank(struct compressor *compressor, uint32_t crtc_inst) { - uint32_t value, frame_count; + uint32_t value; + uint32_t frame_count; + uint32_t status_pos; uint32_t retry = 0; - uint32_t status_pos = - dm_read_reg(ctx, mmCRTC_STATUS_POSITION); + struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); + + cp110->offsets = reg_offsets[crtc_inst]; + + status_pos = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION)); /* Only if CRTC is enabled and counter is moving we wait for one frame. */ - if (status_pos != dm_read_reg(ctx, mmCRTC_STATUS_POSITION)) { + if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) { /* Resetting LB on VBlank */ - value = dm_read_reg(ctx, mmLB_SYNC_RESET_SEL); + value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL)); set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL); set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2); - dm_write_reg(ctx, mmLB_SYNC_RESET_SEL, value); + dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value); - frame_count = dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT); + frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)); for (retry = 10000; retry > 0; retry--) { - if (frame_count != dm_read_reg(ctx, mmCRTC_STATUS_FRAME_COUNT)) + if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT))) break; udelay(10); } @@ -130,13 +102,11 @@ static void reset_lb_on_vblank(struct dc_context *ctx) dm_error("Frame count did not increase for 100ms.\n"); /* Resetting LB on VBlank */ - value = dm_read_reg(ctx, mmLB_SYNC_RESET_SEL); + value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL)); set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL); set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2); - dm_write_reg(ctx, mmLB_SYNC_RESET_SEL, value); - + dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value); } - } static void wait_for_fbc_state_changed( @@ -226,10 +196,10 @@ void dce110_compressor_enable_fbc( uint32_t addr; uint32_t value, misc_value; - addr = mmFBC_CNTL; value = dm_read_reg(compressor->ctx, addr); set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); + /* params->inst is valid HW CRTC instance start from 0 */ set_reg_field_value( value, params->inst, @@ -238,8 +208,10 @@ void dce110_compressor_enable_fbc( /* Keep track of enum controller_id FBC is attached to */ compressor->is_enabled = true; - compressor->attached_inst = params->inst; - cp110->offsets = reg_offsets[params->inst]; + /* attached_inst is SW CRTC instance start from 1 + * 0 = CONTROLLER_ID_UNDEFINED means not attached crtc + */ + compressor->attached_inst = params->inst + CONTROLLER_ID_D0; /* Toggle it as there is bug in HW */ set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); @@ -268,9 +240,10 @@ void dce110_compressor_enable_fbc( void dce110_compressor_disable_fbc(struct compressor *compressor) { struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); + uint32_t crtc_inst = 0; if (compressor->options.bits.FBC_SUPPORT) { - if (dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL)) { + if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) { uint32_t reg_data; /* Turn off compression */ reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL); @@ -284,8 +257,10 @@ void dce110_compressor_disable_fbc(struct compressor *compressor) wait_for_fbc_state_changed(cp110, false); } - /* Sync line buffer - dce100/110 only*/ - reset_lb_on_vblank(compressor->ctx); + /* Sync line buffer which fbc was attached to dce100/110 only */ + if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3) + reset_lb_on_vblank(compressor, + crtc_inst - CONTROLLER_ID_D0); } } @@ -328,6 +303,8 @@ void dce110_compressor_program_compressed_surface_address_and_pitch( uint32_t compressed_surf_address_low_part = compressor->compr_surface_address.addr.low_part; + cp110->offsets = reg_offsets[params->inst]; + /* Clear content first. */ dm_write_reg( compressor->ctx, @@ -410,13 +387,7 @@ void dce110_compressor_set_fbc_invalidation_triggers( value = dm_read_reg(compressor->ctx, addr); set_reg_field_value( value, - fbc_trigger | - FBC_IDLE_FORCE_GRPH_COMP_EN | - FBC_IDLE_FORCE_SRC_SEL_CHANGE | - FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE | - FBC_IDLE_FORCE_ALPHA_COMP_EN | - FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN | - FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF, + fbc_trigger, FBC_IDLE_FORCE_CLEAR_MASK, FBC_IDLE_FORCE_CLEAR_MASK); dm_write_reg(compressor->ctx, addr, value); @@ -549,7 +520,7 @@ void dce110_compressor_construct(struct dce110_compressor *compressor, compressor->base.channel_interleave_size = 0; compressor->base.dram_channels_num = 0; compressor->base.lpt_channels_num = 0; - compressor->base.attached_inst = 0; + compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED; compressor->base.is_enabled = false; compressor->base.funcs = &dce110_compressor_funcs; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 9724a17e352b..4bf24758217f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1267,10 +1267,19 @@ static void program_scaler(const struct dc *dc, pipe_ctx->plane_res.scl_data.lb_params.depth, &pipe_ctx->stream->bit_depth_params); - if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) + if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) { + /* + * The way 420 is packed, 2 channels carry Y component, 1 channel + * alternate between Cb and Cr, so both channels need the pixel + * value for Y + */ + if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + color.color_r_cr = color.color_g_y; + pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color( pipe_ctx->stream_res.tg, &color); + } pipe_ctx->plane_res.xfm->funcs->transform_set_scaler(pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data); @@ -1766,12 +1775,13 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx, * Check if FBC can be enabled */ static bool should_enable_fbc(struct dc *dc, - struct dc_state *context, - uint32_t *pipe_idx) + struct dc_state *context, + uint32_t *pipe_idx) { uint32_t i; struct pipe_ctx *pipe_ctx = NULL; struct resource_context *res_ctx = &context->res_ctx; + unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; ASSERT(dc->fbc_compressor); @@ -1786,14 +1796,28 @@ static bool should_enable_fbc(struct dc *dc, for (i = 0; i < dc->res_pool->pipe_count; i++) { if (res_ctx->pipe_ctx[i].stream) { + pipe_ctx = &res_ctx->pipe_ctx[i]; - *pipe_idx = i; - break; + + if (!pipe_ctx) + continue; + + /* fbc not applicable on underlay pipe */ + if (pipe_ctx->pipe_idx != underlay_idx) { + *pipe_idx = i; + break; + } } } - /* Pipe context should be found */ - ASSERT(pipe_ctx); + if (i == dc->res_pool->pipe_count) + return false; + + if (!pipe_ctx->stream->sink) + return false; + + if (!pipe_ctx->stream->sink->link) + return false; /* Only supports eDP */ if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP) @@ -1817,8 +1841,9 @@ static bool should_enable_fbc(struct dc *dc, /* * Enable FBC */ -static void enable_fbc(struct dc *dc, - struct dc_state *context) +static void enable_fbc( + struct dc *dc, + struct dc_state *context) { uint32_t pipe_idx = 0; @@ -1828,10 +1853,9 @@ static void enable_fbc(struct dc *dc, struct compressor *compr = dc->fbc_compressor; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx]; - params.source_view_width = pipe_ctx->stream->timing.h_addressable; params.source_view_height = pipe_ctx->stream->timing.v_addressable; - + params.inst = pipe_ctx->stream_res.tg->inst; compr->compr_surface_address.quad_part = dc->ctx->fbc_gpu_addr; compr->funcs->surface_address_and_pitch(compr, ¶ms); @@ -2046,10 +2070,10 @@ enum dc_status dce110_apply_ctx_to_hw( return status; } - dcb->funcs->set_scratch_critical_state(dcb, false); - if (dc->fbc_compressor) - enable_fbc(dc, context); + enable_fbc(dc, dc->current_state); + + dcb->funcs->set_scratch_critical_state(dcb, false); return DC_OK; } @@ -2282,7 +2306,7 @@ static void dce110_enable_per_frame_crtc_position_reset( int i; gsl_params.gsl_group = 0; - gsl_params.gsl_master = grouped_pipes[0]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst; + gsl_params.gsl_master = 0; for (i = 0; i < group_size; i++) grouped_pipes[i]->stream_res.tg->funcs->setup_global_swap_lock( @@ -2408,7 +2432,6 @@ static void dce110_program_front_end_for_pipe( struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct xfm_grph_csc_adjustment adjust; struct out_csc_color_matrix tbl_entry; - unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; unsigned int i; DC_LOGGER_INIT(); memset(&tbl_entry, 0, sizeof(tbl_entry)); @@ -2449,15 +2472,6 @@ static void dce110_program_front_end_for_pipe( program_scaler(dc, pipe_ctx); - /* fbc not applicable on Underlay pipe */ - if (dc->fbc_compressor && old_pipe->stream && - pipe_ctx->pipe_idx != underlay_idx) { - if (plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL) - dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); - else - enable_fbc(dc, dc->current_state); - } - mi->funcs->mem_input_program_surface_config( mi, plane_state->format, @@ -2534,6 +2548,9 @@ static void dce110_apply_ctx_for_surface( if (num_planes == 0) return; + if (dc->fbc_compressor) + dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor); + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -2576,6 +2593,9 @@ static void dce110_apply_ctx_for_surface( (pipe_ctx->plane_state || old_pipe_ctx->plane_state)) dc->hwss.pipe_control_lock(dc, pipe_ctx, false); } + + if (dc->fbc_compressor) + enable_fbc(dc, dc->current_state); } static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 6d40b3d54ac1..cdd1d6b7b9f2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -41,7 +41,6 @@ #include "dce/dce_mem_input.h" #include "dce/dce_link_encoder.h" #include "dce/dce_stream_encoder.h" -#include "dce/dce_mem_input.h" #include "dce/dce_ipp.h" #include "dce/dce_transform.h" #include "dce/dce_opp.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c index 20f531d27e2b..54abedbf1b43 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c @@ -223,7 +223,7 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, &dc->res_pool->pp_smu_req; struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; - struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; + uint32_t requested_dcf_clock_in_khz = 0; bool send_request_to_increase = false; bool send_request_to_lower = false; int display_count; @@ -263,8 +263,6 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, // F Clock if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) { clk_mgr->clks.fclk_khz = new_clocks->fclk_khz; - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_FCLK; - clock_voltage_req.clocks_in_khz = new_clocks->fclk_khz; smu_req.hard_min_fclk_mhz = new_clocks->fclk_khz / 1000; notify_hard_min_fclk_to_smu(pp_smu, new_clocks->fclk_khz); @@ -293,10 +291,9 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, */ if (send_request_to_increase) { /*use dcfclk to request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); - notify_hard_min_dcfclk_to_smu(pp_smu, clock_voltage_req.clocks_in_khz); + notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz); if (pp_smu->set_display_requirement) pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); @@ -317,10 +314,9 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, if (!send_request_to_increase && send_request_to_lower) { /*use dcfclk to request voltage*/ - clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DCFCLK; - clock_voltage_req.clocks_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); + requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); - notify_hard_min_dcfclk_to_smu(pp_smu, clock_voltage_req.clocks_in_khz); + notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz); if (pp_smu->set_display_requirement) pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); @@ -332,12 +328,10 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, *smu_req_cur = smu_req; } - static const struct clk_mgr_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = dcn1_update_clocks }; - struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx) { struct dc_debug_options *debug = &ctx->dc->debug; @@ -377,3 +371,5 @@ struct clk_mgr *dcn1_clk_mgr_create(struct dc_context *ctx) return &clk_mgr_dce->base; } + + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h index 9dbaf6578006..a995eda443a3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.h @@ -28,6 +28,12 @@ #include "../dce/dce_clk_mgr.h" +struct clk_bypass { + uint32_t dcfclk_bypass; + uint32_t dispclk_pypass; + uint32_t dprefclk_bypass; +}; + void dcn1_pplib_apply_display_requirements( struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index 3eea44092a04..7469333a2c8a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -324,7 +324,7 @@ bool cm_helper_translate_curve_to_hw_format( if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) return false; - PERF_TRACE(); + PERF_TRACE_CTX(output_tf->ctx); corner_points = lut_params->corner_points; rgb_resulted = lut_params->rgb_resulted; @@ -513,7 +513,7 @@ bool cm_helper_translate_curve_to_degamma_hw_format( if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) return false; - PERF_TRACE(); + PERF_TRACE_CTX(output_tf->ctx); corner_points = lut_params->corner_points; rgb_resulted = lut_params->rgb_resulted; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index 4254e7e1a509..c7d1e678ebf5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -100,7 +100,7 @@ bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable); - return true ? false : enable; + return enable ? true : false; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 74132a1f3046..345af015d061 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -99,6 +99,14 @@ static unsigned int hubp1_get_underflow_status(struct hubp *hubp) return hubp_underflow; } + +void hubp1_clear_underflow(struct hubp *hubp) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, 1); +} + static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); @@ -565,19 +573,6 @@ void hubp1_program_deadline( REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler, DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler); - if (REG(PREFETCH_SETTINS)) - REG_SET_2(PREFETCH_SETTINS, 0, - DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, - VRATIO_PREFETCH, dlg_attr->vratio_prefetch); - else - REG_SET_2(PREFETCH_SETTINGS, 0, - DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, - VRATIO_PREFETCH, dlg_attr->vratio_prefetch); - - REG_SET_2(VBLANK_PARAMETERS_0, 0, - DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, - DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); - REG_SET(REF_FREQ_TO_PIX_FREQ, 0, REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq); @@ -585,9 +580,6 @@ void hubp1_program_deadline( REG_SET(VBLANK_PARAMETERS_1, 0, REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l); - REG_SET(VBLANK_PARAMETERS_3, 0, - REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); - if (REG(NOM_PARAMETERS_0)) REG_SET(NOM_PARAMETERS_0, 0, DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l); @@ -602,27 +594,13 @@ void hubp1_program_deadline( REG_SET(NOM_PARAMETERS_5, 0, REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l); - REG_SET_2(PER_LINE_DELIVERY_PRE, 0, - REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, - REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); - REG_SET_2(PER_LINE_DELIVERY, 0, REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l, REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c); - if (REG(PREFETCH_SETTINS_C)) - REG_SET(PREFETCH_SETTINS_C, 0, - VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); - else - REG_SET(PREFETCH_SETTINGS_C, 0, - VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); - REG_SET(VBLANK_PARAMETERS_2, 0, REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c); - REG_SET(VBLANK_PARAMETERS_4, 0, - REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); - if (REG(NOM_PARAMETERS_2)) REG_SET(NOM_PARAMETERS_2, 0, DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c); @@ -642,10 +620,6 @@ void hubp1_program_deadline( QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm, QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm); - REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, - MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, - QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); - /* TTU - per luma/chroma */ /* Assumed surf0 is luma and 1 is chroma */ @@ -654,25 +628,15 @@ void hubp1_program_deadline( QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l); - REG_SET(DCN_SURF0_TTU_CNTL1, 0, - REFCYC_PER_REQ_DELIVERY_PRE, - ttu_attr->refcyc_per_req_delivery_pre_l); - REG_SET_3(DCN_SURF1_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c); - REG_SET(DCN_SURF1_TTU_CNTL1, 0, - REFCYC_PER_REQ_DELIVERY_PRE, - ttu_attr->refcyc_per_req_delivery_pre_c); - REG_SET_3(DCN_CUR0_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_cur0, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_cur0); - REG_SET(DCN_CUR0_TTU_CNTL1, 0, - REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0); } static void hubp1_setup( @@ -690,6 +654,48 @@ static void hubp1_setup( hubp1_vready_workaround(hubp, pipe_dest); } +static void hubp1_setup_interdependent( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_SET_2(PREFETCH_SETTINS, 0, + DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, dlg_attr->vratio_prefetch); + + REG_SET(PREFETCH_SETTINS_C, 0, + VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); + + REG_SET_2(VBLANK_PARAMETERS_0, 0, + DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, + DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); + + REG_SET(VBLANK_PARAMETERS_3, 0, + REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); + + REG_SET(VBLANK_PARAMETERS_4, 0, + REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); + + REG_SET_2(PER_LINE_DELIVERY_PRE, 0, + REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); + + REG_SET(DCN_SURF0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_l); + REG_SET(DCN_SURF1_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_c); + REG_SET(DCN_CUR0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0); + + REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, + MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, + QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); +} + bool hubp1_is_flip_pending(struct hubp *hubp) { uint32_t flip_pending = 0; @@ -1178,6 +1184,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = { hubp1_program_surface_config, .hubp_is_flip_pending = hubp1_is_flip_pending, .hubp_setup = hubp1_setup, + .hubp_setup_interdependent = hubp1_setup_interdependent, .hubp_set_vm_system_aperture_settings = hubp1_set_vm_system_aperture_settings, .hubp_set_vm_context0_settings = hubp1_set_vm_context0_settings, .set_blank = hubp1_set_blank, @@ -1190,6 +1197,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = { .hubp_clk_cntl = hubp1_clk_cntl, .hubp_vtg_sel = hubp1_vtg_sel, .hubp_read_state = hubp1_read_state, + .hubp_clear_underflow = hubp1_clear_underflow, .hubp_disable_control = hubp1_disable_control, .hubp_get_underflow_status = hubp1_get_underflow_status, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h index 4890273b632b..62d4232e7796 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -251,6 +251,7 @@ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE, mask_sh),\ @@ -435,6 +436,7 @@ type HUBP_NO_OUTSTANDING_REQ;\ type HUBP_VTG_SEL;\ type HUBP_UNDERFLOW_STATUS;\ + type HUBP_UNDERFLOW_CLEAR;\ type NUM_PIPES;\ type NUM_BANKS;\ type PIPE_INTERLEAVE;\ @@ -739,6 +741,7 @@ void dcn10_hubp_construct( const struct dcn_mi_mask *hubp_mask); void hubp1_read_state(struct hubp *hubp); +void hubp1_clear_underflow(struct hubp *hubp); enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 87495dea45ec..91e015e14355 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1227,7 +1227,8 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, tf = plane_state->in_transfer_func; if (plane_state->gamma_correction && - !plane_state->gamma_correction->is_identity + !dpp_base->ctx->dc->debug.always_use_regamma + && !plane_state->gamma_correction->is_identity && dce_use_lut(plane_state->format)) dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); @@ -1400,7 +1401,7 @@ static void dcn10_enable_per_frame_crtc_position_reset( if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset) grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( grouped_pipes[i]->stream_res.tg, - grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, + 0, &grouped_pipes[i]->stream->triggered_crtc_reset); DC_SYNC_INFO("Waiting for trigger\n"); @@ -1770,7 +1771,7 @@ bool is_rgb_cspace(enum dc_color_space output_color_space) } } -static void dcn10_get_surface_visual_confirm_color( +void dcn10_get_surface_visual_confirm_color( const struct pipe_ctx *pipe_ctx, struct tg_color *color) { @@ -1806,7 +1807,7 @@ static void dcn10_get_surface_visual_confirm_color( } } -static void dcn10_get_hdr_visual_confirm_color( +void dcn10_get_hdr_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color) { @@ -2067,6 +2068,10 @@ void update_dchubp_dpp( &pipe_ctx->ttu_regs, &pipe_ctx->rq_regs, &pipe_ctx->pipe_dlg_param); + hubp->funcs->hubp_setup_interdependent( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); } size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport; @@ -2154,6 +2159,15 @@ static void dcn10_blank_pixel_data( color_space = stream->output_color_space; color_space_to_black_color(dc, color_space, &black_color); + /* + * The way 420 is packed, 2 channels carry Y component, 1 channel + * alternate between Cb and Cr, so both channels need the pixel + * value for Y + */ + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + black_color.color_r_cr = black_color.color_g_y; + + if (stream_res->tg->funcs->set_blank_color) stream_res->tg->funcs->set_blank_color( stream_res->tg, @@ -2337,6 +2351,34 @@ static void dcn10_apply_ctx_for_surface( dcn10_pipe_control_lock(dc, top_pipe_to_program, false); + if (top_pipe_to_program->plane_state && + top_pipe_to_program->plane_state->update_flags.bits.full_update) + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Skip inactive pipes and ones already updated */ + if (!pipe_ctx->stream || pipe_ctx->stream == stream + || !pipe_ctx->plane_state) + continue; + + pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); + + pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( + pipe_ctx->plane_res.hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->stream || pipe_ctx->stream == stream + || !pipe_ctx->plane_state) + continue; + + dcn10_pipe_control_lock(dc, pipe_ctx, false); + } + if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); @@ -2710,6 +2752,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .set_avmute = dce110_set_avmute, .log_hw_state = dcn10_log_hw_state, .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, .edp_backlight_control = hwss_edp_backlight_control, .edp_power_control = hwss_edp_power_control, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index 5e5610c9e600..f8eea10e4c64 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -51,6 +51,8 @@ void dcn10_get_hw_state( char *pBuf, unsigned int bufSize, unsigned int mask); +void dcn10_clear_status_bits(struct dc *dc, unsigned int mask); + bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx); bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx); @@ -61,6 +63,14 @@ void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp); void set_hdr_multiplier(struct pipe_ctx *pipe_ctx); +void dcn10_get_surface_visual_confirm_color( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color); + +void dcn10_get_hdr_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); + void update_dchubp_dpp( struct dc *dc, struct pipe_ctx *pipe_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 64158900730f..cd469014baa3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -44,6 +44,7 @@ #include "dcn10_hubp.h" #include "dcn10_hubbub.h" #include "dcn10_cm_common.h" +#include "dcn10_clk_mgr.h" static unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...) { @@ -454,12 +455,6 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int remaining_buffer -= chars_printed; pBuf += chars_printed; - - // Clear underflow for debug purposes - // We want to keep underflow sticky bit on for the longevity tests outside of test environment. - // This function is called only from Windows or Diags test environment, hence it's safe to clear - // it from here without affecting the original intent. - tg->funcs->clear_optc_underflow(tg); } } @@ -469,19 +464,75 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int static unsigned int dcn10_get_clock_states(struct dc *dc, char *pBuf, unsigned int bufSize) { unsigned int chars_printed = 0; + unsigned int remaining_buffer = bufSize; - chars_printed = snprintf_count(pBuf, bufSize, "dcfclk_khz,dcfclk_deep_sleep_khz,dispclk_khz," - "dppclk_khz,max_supported_dppclk_khz,fclk_khz,socclk_khz\n" - "%d,%d,%d,%d,%d,%d,%d\n", + chars_printed = snprintf_count(pBuf, bufSize, "dcfclk,dcfclk_deep_sleep,dispclk," + "dppclk,fclk,socclk\n" + "%d,%d,%d,%d,%d,%d\n", dc->current_state->bw.dcn.clk.dcfclk_khz, dc->current_state->bw.dcn.clk.dcfclk_deep_sleep_khz, dc->current_state->bw.dcn.clk.dispclk_khz, dc->current_state->bw.dcn.clk.dppclk_khz, - dc->current_state->bw.dcn.clk.max_supported_dppclk_khz, dc->current_state->bw.dcn.clk.fclk_khz, dc->current_state->bw.dcn.clk.socclk_khz); - return chars_printed; + remaining_buffer -= chars_printed; + pBuf += chars_printed; + + return bufSize - remaining_buffer; +} + +static void dcn10_clear_otpc_underflow(struct dc *dc) +{ + struct resource_pool *pool = dc->res_pool; + int i; + + for (i = 0; i < pool->timing_generator_count; i++) { + struct timing_generator *tg = pool->timing_generators[i]; + struct dcn_otg_state s = {0}; + + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + if (s.otg_enabled & 1) + tg->funcs->clear_optc_underflow(tg); + } +} + +static void dcn10_clear_hubp_underflow(struct dc *dc) +{ + struct resource_pool *pool = dc->res_pool; + int i; + + for (i = 0; i < pool->pipe_count; i++) { + struct hubp *hubp = pool->hubps[i]; + struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state); + + hubp->funcs->hubp_read_state(hubp); + + if (!s->blank_en) + hubp->funcs->hubp_clear_underflow(hubp); + } +} + +void dcn10_clear_status_bits(struct dc *dc, unsigned int mask) +{ + /* + * Mask Format + * Bit 0 - 31: Status bit to clear + * + * Mask = 0x0 means clear all status bits + */ + const unsigned int DC_HW_STATE_MASK_HUBP_UNDERFLOW = 0x1; + const unsigned int DC_HW_STATE_MASK_OTPC_UNDERFLOW = 0x2; + + if (mask == 0x0) + mask = 0xFFFFFFFF; + + if (mask & DC_HW_STATE_MASK_HUBP_UNDERFLOW) + dcn10_clear_hubp_underflow(dc); + + if (mask & DC_HW_STATE_MASK_OTPC_UNDERFLOW) + dcn10_clear_otpc_underflow(dc); } void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask) @@ -491,16 +542,16 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne * Bit 0 - 15: Hardware block mask * Bit 15: 1 = Invariant Only, 0 = All */ - const unsigned int DC_HW_STATE_MASK_HUBBUB = 0x1; - const unsigned int DC_HW_STATE_MASK_HUBP = 0x2; - const unsigned int DC_HW_STATE_MASK_RQ = 0x4; - const unsigned int DC_HW_STATE_MASK_DLG = 0x8; - const unsigned int DC_HW_STATE_MASK_TTU = 0x10; - const unsigned int DC_HW_STATE_MASK_CM = 0x20; - const unsigned int DC_HW_STATE_MASK_MPCC = 0x40; - const unsigned int DC_HW_STATE_MASK_OTG = 0x80; - const unsigned int DC_HW_STATE_MASK_CLOCKS = 0x100; - const unsigned int DC_HW_STATE_INVAR_ONLY = 0x8000; + const unsigned int DC_HW_STATE_MASK_HUBBUB = 0x1; + const unsigned int DC_HW_STATE_MASK_HUBP = 0x2; + const unsigned int DC_HW_STATE_MASK_RQ = 0x4; + const unsigned int DC_HW_STATE_MASK_DLG = 0x8; + const unsigned int DC_HW_STATE_MASK_TTU = 0x10; + const unsigned int DC_HW_STATE_MASK_CM = 0x20; + const unsigned int DC_HW_STATE_MASK_MPCC = 0x40; + const unsigned int DC_HW_STATE_MASK_OTG = 0x80; + const unsigned int DC_HW_STATE_MASK_CLOCKS = 0x100; + const unsigned int DC_HW_STATE_INVAR_ONLY = 0x8000; unsigned int chars_printed = 0; unsigned int remaining_buf_size = bufSize; @@ -556,6 +607,9 @@ void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigne remaining_buf_size -= chars_printed; } - if ((mask & DC_HW_STATE_MASK_CLOCKS) && remaining_buf_size > 0) + if ((mask & DC_HW_STATE_MASK_CLOCKS) && remaining_buf_size > 0) { chars_printed = dcn10_get_clock_states(dc, pBuf, remaining_buf_size); + pBuf += chars_printed; + remaining_buf_size -= chars_printed; + } } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 7d1f66797cb3..7c138615f17d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -335,9 +335,8 @@ void optc1_program_timing( /* Enable stereo - only when we need to pack 3D frame. Other types * of stereo handled in explicit call */ - h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ? - 1 : 0; + h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, h_div_2); @@ -360,20 +359,19 @@ void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enab static void optc1_unblank_crtc(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t vertical_interrupt_enable = 0; - - REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, - OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable); - - /* temporary work around for vertical interrupt, once vertical interrupt enabled, - * this check will be removed. - */ - if (vertical_interrupt_enable) - optc1_set_blank_data_double_buffer(optc, true); REG_UPDATE_2(OTG_BLANK_CONTROL, OTG_BLANK_DATA_EN, 0, OTG_BLANK_DE_MODE, 0); + + /* W/A for automated testing + * Automated testing will fail underflow test as there + * sporadic underflows which occur during the optc blank + * sequence. As a w/a, clear underflow on unblank. + * This prevents the failure, but will not mask actual + * underflow that affect real use cases. + */ + optc1_clear_optc_underflow(optc); } /** @@ -1422,3 +1420,9 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_h_sync_width = 8; optc1->min_v_sync_width = 1; } + +bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index c1b114209fe8..8bacf0b6e27e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -565,4 +565,6 @@ bool optc1_configure_crc(struct timing_generator *optc, bool optc1_get_crc(struct timing_generator *optc, uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb); +bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); + #endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 47dbe4bb294a..5d4772dec0ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -202,7 +202,6 @@ enum dcn10_clk_src_array_id { #define MMHUB_SR(reg_name)\ .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ mm ## reg_name - /* macros to expend register list macro defined in HW object header file * end *********************/ @@ -436,7 +435,6 @@ static const struct dcn_optc_mask tg_mask = { TG_COMMON_MASK_SH_LIST_DCN1_0(_MASK) }; - static const struct bios_registers bios_regs = { NBIO_SR(BIOS_SCRATCH_0), NBIO_SR(BIOS_SCRATCH_3), @@ -497,7 +495,6 @@ static const struct dce110_clk_src_mask cs_mask = { CS_COMMON_MASK_SH_LIST_DCN1_0(_MASK) }; - static const struct resource_caps res_cap = { .num_timing_generator = 4, .num_opp = 4, @@ -1277,7 +1274,6 @@ static bool construct( goto fail; } } - pool->base.clk_mgr = dcn1_clk_mgr_create(ctx); if (pool->base.clk_mgr == NULL) { dm_error("DC: failed to create display clock!\n"); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index 6f9078f3c4d3..b8b5525a389a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -766,7 +766,6 @@ void enc1_stream_encoder_dp_blank( struct stream_encoder *enc) { struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - uint32_t retries = 0; uint32_t reg1 = 0; uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; @@ -803,8 +802,6 @@ void enc1_stream_encoder_dp_blank( 0, 10, max_retries); - ASSERT(retries <= max_retries); - /* Tell the DP encoder to ignore timing from CRTC, must be done after * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is * complete, stream status will be stuck in video stream enabled state, diff --git a/drivers/gpu/drm/amd/display/dc/dm_event_log.h b/drivers/gpu/drm/amd/display/dc/dm_event_log.h index 34a701ca879e..65663f4d93e1 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_event_log.h +++ b/drivers/gpu/drm/amd/display/dc/dm_event_log.h @@ -33,6 +33,7 @@ #define EVENT_LOG_AUX_REQ(ddc, type, action, address, len, data) #define EVENT_LOG_AUX_REP(ddc, type, replyStatus, len, data) +#define EVENT_LOG_CUST_MSG(tag, a, ...) #endif diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index beb08fd12b1d..0029a39efb1c 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -102,7 +102,7 @@ struct pp_smu_funcs_rv { */ void (*set_display_count)(struct pp_smu *pp, int count); - /* which SMU message? are reader and writer WM separate SMU msg? */ + /* reader and writer WM's are sent together as part of one table*/ /* * PPSMC_MSG_SetDriverDramAddrHigh * PPSMC_MSG_SetDriverDramAddrLow diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 28128c02de00..1961cc6d9143 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -31,6 +31,8 @@ #define __DM_SERVICES_H__ +#include "amdgpu_dm_trace.h" + /* TODO: remove when DC is complete. */ #include "dm_services_types.h" #include "logger_interface.h" @@ -70,6 +72,7 @@ static inline uint32_t dm_read_reg_func( } #endif value = cgs_read_register(ctx->cgs_device, address); + trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value); return value; } @@ -90,6 +93,7 @@ static inline void dm_write_reg_func( } #endif cgs_write_register(ctx->cgs_device, address, value); + trace_amdgpu_dc_wreg(&ctx->perf_trace->write_count, address, value); } static inline uint32_t dm_read_index_reg( @@ -351,8 +355,12 @@ unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, /* * performance tracing */ -void dm_perf_trace_timestamp(const char *func_name, unsigned int line); -#define PERF_TRACE() dm_perf_trace_timestamp(__func__, __LINE__) +#define PERF_TRACE() trace_amdgpu_dc_performance(CTX->perf_trace->read_count,\ + CTX->perf_trace->write_count, &CTX->perf_trace->last_entry_read,\ + &CTX->perf_trace->last_entry_write, __func__, __LINE__) +#define PERF_TRACE_CTX(__CTX) trace_amdgpu_dc_performance(__CTX->perf_trace->read_count,\ + __CTX->perf_trace->write_count, &__CTX->perf_trace->last_entry_read,\ + &__CTX->perf_trace->last_entry_write, __func__, __LINE__) /* diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index f20161c5706d..dada04296025 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -56,7 +56,6 @@ struct gpio_service *dal_gpio_service_create( struct dc_context *ctx) { struct gpio_service *service; - uint32_t index_of_id; service = kzalloc(sizeof(struct gpio_service), GFP_KERNEL); @@ -78,44 +77,33 @@ struct gpio_service *dal_gpio_service_create( goto failure_1; } - /* allocate and initialize business storage */ + /* allocate and initialize busyness storage */ { - const uint32_t bits_per_uint = sizeof(uint32_t) << 3; - index_of_id = 0; service->ctx = ctx; do { uint32_t number_of_bits = service->factory.number_of_pins[index_of_id]; + uint32_t i = 0; - uint32_t number_of_uints = - (number_of_bits + bits_per_uint - 1) / - bits_per_uint; - - uint32_t *slot; - - if (number_of_bits) { - uint32_t index_of_uint = 0; + if (number_of_bits) { + service->busyness[index_of_id] = + kcalloc(number_of_bits, sizeof(char), + GFP_KERNEL); - slot = kcalloc(number_of_uints, - sizeof(uint32_t), - GFP_KERNEL); - - if (!slot) { + if (!service->busyness[index_of_id]) { BREAK_TO_DEBUGGER(); goto failure_2; } do { - slot[index_of_uint] = 0; - - ++index_of_uint; - } while (index_of_uint < number_of_uints); - } else - slot = NULL; - - service->busyness[index_of_id] = slot; + service->busyness[index_of_id][i] = 0; + ++i; + } while (i < number_of_bits); + } else { + service->busyness[index_of_id] = NULL; + } ++index_of_id; } while (index_of_id < GPIO_ID_COUNT); @@ -125,13 +113,8 @@ struct gpio_service *dal_gpio_service_create( failure_2: while (index_of_id) { - uint32_t *slot; - --index_of_id; - - slot = service->busyness[index_of_id]; - - kfree(slot); + kfree(service->busyness[index_of_id]); } failure_1: @@ -169,9 +152,7 @@ void dal_gpio_service_destroy( uint32_t index_of_id = 0; do { - uint32_t *slot = (*ptr)->busyness[index_of_id]; - - kfree(slot); + kfree((*ptr)->busyness[index_of_id]); ++index_of_id; } while (index_of_id < GPIO_ID_COUNT); @@ -192,11 +173,7 @@ static bool is_pin_busy( enum gpio_id id, uint32_t en) { - const uint32_t bits_per_uint = sizeof(uint32_t) << 3; - - const uint32_t *slot = service->busyness[id] + (en / bits_per_uint); - - return 0 != (*slot & (1 << (en % bits_per_uint))); + return service->busyness[id][en]; } static void set_pin_busy( @@ -204,10 +181,7 @@ static void set_pin_busy( enum gpio_id id, uint32_t en) { - const uint32_t bits_per_uint = sizeof(uint32_t) << 3; - - service->busyness[id][en / bits_per_uint] |= - (1 << (en % bits_per_uint)); + service->busyness[id][en] = true; } static void set_pin_free( @@ -215,10 +189,7 @@ static void set_pin_free( enum gpio_id id, uint32_t en) { - const uint32_t bits_per_uint = sizeof(uint32_t) << 3; - - service->busyness[id][en / bits_per_uint] &= - ~(1 << (en % bits_per_uint)); + service->busyness[id][en] = false; } enum gpio_result dal_gpio_service_open( diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h index c7f3081f59cc..1d501a43d13b 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h @@ -36,10 +36,9 @@ struct gpio_service { /* * @brief * Business storage. - * For each member of 'enum gpio_id', - * store array of bits (packed into uint32_t slots), - * index individual bit by 'en' value */ - uint32_t *busyness[GPIO_ID_COUNT]; + * one byte For each member of 'enum gpio_id' + */ + char *busyness[GPIO_ID_COUNT]; }; enum gpio_result dal_gpio_service_open( diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index a683f4102e65..c2028c4744a6 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -79,6 +79,7 @@ bool dal_hw_factory_init( dal_hw_factory_dce110_init(factory); return true; case DCE_VERSION_12_0: + case DCE_VERSION_12_1: dal_hw_factory_dce120_init(factory); return true; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 096f45628630..236ca28784a9 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -76,6 +76,7 @@ bool dal_hw_translate_init( dal_hw_translate_dce110_init(translate); return true; case DCE_VERSION_12_0: + case DCE_VERSION_12_1: dal_hw_translate_dce120_init(translate); return true; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c index e56093f26eed..1ad6e49102ff 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c @@ -90,6 +90,7 @@ struct i2caux *dal_i2caux_create( case DCE_VERSION_10_0: return dal_i2caux_dce100_create(ctx); case DCE_VERSION_12_0: + case DCE_VERSION_12_1: return dal_i2caux_dce120_create(ctx); #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: diff --git a/drivers/gpu/drm/amd/display/dc/inc/compressor.h b/drivers/gpu/drm/amd/display/dc/inc/compressor.h index bcb18f5e1e60..7a147a9762a0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/compressor.h +++ b/drivers/gpu/drm/amd/display/dc/inc/compressor.h @@ -77,6 +77,7 @@ struct compressor_funcs { }; struct compressor { struct dc_context *ctx; + /* CONTROLLER_ID_D0 + instance, CONTROLLER_ID_UNDEFINED = 0 */ uint32_t attached_inst; bool is_enabled; const struct compressor_funcs *funcs; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index e3ee96afa60e..b168a5e9dd9d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -272,6 +272,17 @@ union bw_context { struct dce_bw_output dce; }; +/** + * struct dc_state - The full description of a state requested by a user + * + * @streams: Stream properties + * @stream_status: The planes on a given stream + * @res_ctx: Persistent state of resources + * @bw: The output from bandwidth and watermark calculations + * @pp_display_cfg: PowerPlay clocks and settings + * @dcn_bw_vars: non-stack memory to support bandwidth calculations + * + */ struct dc_state { struct dc_stream_state *streams[MAX_PIPES]; struct dc_stream_status stream_status[MAX_PIPES]; @@ -279,7 +290,6 @@ struct dc_state { struct resource_context res_ctx; - /* The output from BW and WM calculations. */ union bw_context bw; /* Note: these are big structures, do *not* put on stack! */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index 4550747fb61c..cb85eaa9857f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -32,6 +32,13 @@ enum dmcu_state { DMCU_RUNNING = 1 }; +struct dmcu_version { + unsigned int date; + unsigned int month; + unsigned int year; + unsigned int interface_version; +}; + struct dmcu { struct dc_context *ctx; const struct dmcu_funcs *funcs; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 334c48cdafdc..04c6989aac58 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -63,6 +63,11 @@ struct hubp_funcs { struct _vcs_dpi_display_rq_regs_st *rq_regs, struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest); + void (*hubp_setup_interdependent)( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_regs, + struct _vcs_dpi_display_ttu_regs_st *ttu_regs); + void (*dcc_control)(struct hubp *hubp, bool enable, bool independent_64b_blks); void (*mem_program_viewport)( @@ -121,6 +126,7 @@ struct hubp_funcs { void (*hubp_clk_cntl)(struct hubp *hubp, bool enable); void (*hubp_vtg_sel)(struct hubp *hubp, uint32_t otg_inst); void (*hubp_read_state)(struct hubp *hubp); + void (*hubp_clear_underflow)(struct hubp *hubp); void (*hubp_disable_control)(struct hubp *hubp, bool disable_hubp); unsigned int (*hubp_get_underflow_status)(struct hubp *hubp); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index e9b702ce02dd..d6a85f48b6d1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -200,6 +200,7 @@ struct hw_sequencer_funcs { void (*log_hw_state)(struct dc *dc, struct dc_log_buffer_ctx *log_ctx); void (*get_hw_state)(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask); + void (*clear_status_bits)(struct dc *dc, unsigned int mask); void (*wait_for_mpcc_disconnect)(struct dc *dc, struct resource_pool *res_pool, |