#include "clock_source.h"
#include "dc_bios_types.h"
-#include "bandwidth_calcs.h"
+#include "dce_calcs.h"
#include "bios_parser_interface.h"
#include "include/irq_service_interface.h"
#include "transform.h"
for (i = 0; i < connectors_num; i++) {
struct link_init_data link_init_params = {0};
- struct core_link *link;
+ struct dc_link *link;
link_init_params.ctx = dc->ctx;
+ /* next BIOS object table connector */
link_init_params.connector_index = i;
link_init_params.link_index = dc->link_count;
link_init_params.dc = dc;
dc->links[dc->link_count] = link;
link->dc = dc;
++dc->link_count;
- } else {
- dm_error("DC: failed to create link!\n");
}
}
for (i = 0; i < num_virtual_links; i++) {
- struct core_link *link = dm_alloc(sizeof(*link));
+ struct dc_link *link = dm_alloc(sizeof(*link));
struct encoder_init_data enc_init = {0};
if (link == NULL) {
link->ctx = dc->ctx;
link->dc = dc;
- link->public.connector_signal = SIGNAL_TYPE_VIRTUAL;
+ link->connector_signal = SIGNAL_TYPE_VIRTUAL;
link->link_id.type = OBJECT_TYPE_CONNECTOR;
link->link_id.id = CONNECTOR_ID_VIRTUAL;
link->link_id.enum_id = ENUM_ID_1;
enc_init.encoder.enum_id = ENUM_ID_1;
virtual_link_encoder_construct(link->link_enc, &enc_init);
- link->public.link_index = dc->link_count;
+ link->link_index = dc->link_count;
dc->links[dc->link_count] = link;
dc->link_count++;
}
return ret;
}
-
-static bool set_gamut_remap(struct dc *dc,
- const struct dc_stream **stream, int num_streams)
+static bool stream_get_crtc_position(struct dc *dc,
+ const struct dc_stream **stream, int num_streams,
+ unsigned int *v_pos, unsigned int *nom_v_pos)
{
+ /* TODO: Support multiple streams */
struct core_dc *core_dc = DC_TO_CORE(dc);
struct core_stream *core_stream = DC_STREAM_TO_CORE(stream[0]);
int i = 0;
bool ret = false;
- struct pipe_ctx *pipes;
+ struct crtc_position position;
for (i = 0; i < MAX_PIPES; i++) {
- if (core_dc->current_context->res_ctx.pipe_ctx[i].stream
- == core_stream) {
+ struct pipe_ctx *pipe =
+ &core_dc->current_context->res_ctx.pipe_ctx[i];
- pipes = &core_dc->current_context->res_ctx.pipe_ctx[i];
- core_dc->hwss.set_plane_config(core_dc, pipes,
- &core_dc->current_context->res_ctx);
+ if (pipe->stream == core_stream && pipe->stream_enc) {
+ core_dc->hwss.get_position(&pipe, 1, &position);
+
+ *v_pos = position.vertical_count;
+ *nom_v_pos = position.nominal_vcount;
ret = true;
}
}
-
return ret;
}
-/* This function is not expected to fail, proper implementation of
- * validation will prevent this from ever being called for unsupported
- * configurations.
- */
-static void stream_update_scaling(
- const struct dc *dc,
- const struct dc_stream *dc_stream,
- const struct rect *src,
- const struct rect *dst)
+static bool set_gamut_remap(struct dc *dc, const struct dc_stream *stream)
{
- struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
struct core_dc *core_dc = DC_TO_CORE(dc);
- struct validate_context *cur_ctx = core_dc->current_context;
- int i;
-
- if (src)
- stream->public.src = *src;
-
- if (dst)
- stream->public.dst = *dst;
-
- for (i = 0; i < cur_ctx->stream_count; i++) {
- struct core_stream *cur_stream = cur_ctx->streams[i];
-
- if (stream == cur_stream) {
- struct dc_stream_status *status = &cur_ctx->stream_status[i];
+ struct core_stream *core_stream = DC_STREAM_TO_CORE(stream);
+ int i = 0;
+ bool ret = false;
+ struct pipe_ctx *pipes;
- if (status->surface_count)
- if (!dc_commit_surfaces_to_stream(
- &core_dc->public,
- status->surfaces,
- status->surface_count,
- &cur_stream->public))
- /* Need to debug validation */
- BREAK_TO_DEBUGGER();
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (core_dc->current_context->res_ctx.pipe_ctx[i].stream
+ == core_stream) {
- return;
+ pipes = &core_dc->current_context->res_ctx.pipe_ctx[i];
+ core_dc->hwss.program_gamut_remap(pipes);
+ ret = true;
}
}
-}
-
-static bool set_psr_enable(struct dc *dc, bool enable)
-{
- struct core_dc *core_dc = DC_TO_CORE(dc);
- int i;
-
- for (i = 0; i < core_dc->link_count; i++)
- dc_link_set_psr_enable(&core_dc->links[i]->public,
- enable);
- return true;
+ return ret;
}
-
-static bool setup_psr(struct dc *dc, const struct dc_stream *stream)
+static bool program_csc_matrix(struct dc *dc, const struct dc_stream *stream)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
struct core_stream *core_stream = DC_STREAM_TO_CORE(stream);
+ int i = 0;
+ bool ret = false;
struct pipe_ctx *pipes;
- int i;
- unsigned int underlay_idx = core_dc->res_pool->underlay_pipe_index;
-
- for (i = 0; i < core_dc->link_count; i++) {
- if (core_stream->sink->link == core_dc->links[i])
- dc_link_setup_psr(&core_dc->links[i]->public,
- stream);
- }
for (i = 0; i < MAX_PIPES; i++) {
if (core_dc->current_context->res_ctx.pipe_ctx[i].stream
- == core_stream && i != underlay_idx) {
+ == core_stream) {
+
pipes = &core_dc->current_context->res_ctx.pipe_ctx[i];
- core_dc->hwss.set_static_screen_control(&pipes, 1,
- 0x182);
+ core_dc->hwss.program_csc_matrix(pipes,
+ core_stream->public.output_color_space,
+ core_stream->public.csc_color_matrix.matrix);
+ ret = true;
}
}
- return true;
+ return ret;
+}
+
+static void set_static_screen_events(struct dc *dc,
+ const struct dc_stream **stream,
+ int num_streams,
+ const struct dc_static_screen_events *events)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+ int i = 0;
+ int j = 0;
+ struct pipe_ctx *pipes_affected[MAX_PIPES];
+ int num_pipes_affected = 0;
+
+ for (i = 0; i < num_streams; i++) {
+ struct core_stream *core_stream = DC_STREAM_TO_CORE(stream[i]);
+
+ for (j = 0; j < MAX_PIPES; j++) {
+ if (core_dc->current_context->res_ctx.pipe_ctx[j].stream
+ == core_stream) {
+ pipes_affected[num_pipes_affected++] =
+ &core_dc->current_context->res_ctx.pipe_ctx[j];
+ }
+ }
+ }
+
+ core_dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, events);
}
static void set_drive_settings(struct dc *dc,
int i;
for (i = 0; i < core_dc->link_count; i++) {
- if (&core_dc->links[i]->public == link)
+ if (core_dc->links[i] == link)
break;
}
if (i >= core_dc->link_count)
ASSERT_CRITICAL(false);
- dc_link_dp_set_drive_settings(&core_dc->links[i]->public, lt_settings);
+ dc_link_dp_set_drive_settings(core_dc->links[i], lt_settings);
}
static void perform_link_training(struct dc *dc,
for (i = 0; i < core_dc->link_count; i++)
dc_link_dp_perform_link_training(
- &core_dc->links[i]->public,
+ core_dc->links[i],
link_setting,
skip_video_pattern);
}
static void set_preferred_link_settings(struct dc *dc,
struct dc_link_settings *link_setting,
- const struct dc_link *link)
+ struct dc_link *link)
{
- struct core_link *core_link = DC_LINK_TO_CORE(link);
-
- core_link->public.verified_link_cap.lane_count =
- link_setting->lane_count;
- core_link->public.verified_link_cap.link_rate =
- link_setting->link_rate;
- dp_retrain_link_dp_test(core_link, link_setting, false);
+ link->preferred_link_setting = *link_setting;
+ dp_retrain_link_dp_test(link, link_setting, false);
}
static void enable_hpd(const struct dc_link *link)
static void set_test_pattern(
- const struct dc_link *link,
+ struct dc_link *link,
enum dp_test_pattern test_pattern,
const struct link_training_settings *p_link_settings,
const unsigned char *p_custom_pattern,
cust_pattern_size);
}
+void set_dither_option(const struct dc_stream *dc_stream,
+ enum dc_dither_option option)
+{
+ struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
+ struct bit_depth_reduction_params params;
+ struct dc_link *link = stream->status.link;
+ struct pipe_ctx *pipes = link->dc->current_context->res_ctx.pipe_ctx;
+
+ memset(¶ms, 0, sizeof(params));
+ if (!stream)
+ return;
+ if (option > DITHER_OPTION_MAX)
+ return;
+ if (option == DITHER_OPTION_DEFAULT) {
+ switch (stream->public.timing.display_color_depth) {
+ case COLOR_DEPTH_666:
+ stream->public.dither_option = DITHER_OPTION_SPATIAL6;
+ break;
+ case COLOR_DEPTH_888:
+ stream->public.dither_option = DITHER_OPTION_SPATIAL8;
+ break;
+ case COLOR_DEPTH_101010:
+ stream->public.dither_option = DITHER_OPTION_SPATIAL10;
+ break;
+ default:
+ option = DITHER_OPTION_DISABLE;
+ }
+ } else {
+ stream->public.dither_option = option;
+ }
+ resource_build_bit_depth_reduction_params(stream,
+ ¶ms);
+ stream->bit_depth_params = params;
+ pipes->opp->funcs->
+ opp_program_bit_depth_reduction(pipes->opp, ¶ms);
+}
+
static void allocate_dc_stream_funcs(struct core_dc *core_dc)
{
- core_dc->public.stream_funcs.stream_update_scaling = stream_update_scaling;
if (core_dc->hwss.set_drr != NULL) {
core_dc->public.stream_funcs.adjust_vmin_vmax =
stream_adjust_vmin_vmax;
}
+ core_dc->public.stream_funcs.set_static_screen_events =
+ set_static_screen_events;
+
+ core_dc->public.stream_funcs.get_crtc_position =
+ stream_get_crtc_position;
+
core_dc->public.stream_funcs.set_gamut_remap =
set_gamut_remap;
- core_dc->public.stream_funcs.set_psr_enable =
- set_psr_enable;
+ core_dc->public.stream_funcs.program_csc_matrix =
+ program_csc_matrix;
- core_dc->public.stream_funcs.setup_psr =
- setup_psr;
+ core_dc->public.stream_funcs.set_dither_option =
+ set_dither_option;
core_dc->public.link_funcs.set_drive_settings =
set_drive_settings;
static void destruct(struct core_dc *dc)
{
- resource_validate_ctx_destruct(dc->current_context);
+ dc_release_validate_context(dc->current_context);
+ dc->current_context = NULL;
destroy_links(dc);
if (dc->ctx->logger)
dal_logger_destroy(&dc->ctx->logger);
- dm_free(dc->current_context);
- dc->current_context = NULL;
- dm_free(dc->temp_flip_context);
- dc->temp_flip_context = NULL;
- dm_free(dc->scratch_val_ctx);
- dc->scratch_val_ctx = NULL;
-
dm_free(dc->ctx);
dc->ctx = NULL;
}
}
dc->current_context = dm_alloc(sizeof(*dc->current_context));
- dc->temp_flip_context = dm_alloc(sizeof(*dc->temp_flip_context));
- dc->scratch_val_ctx = dm_alloc(sizeof(*dc->scratch_val_ctx));
- if (!dc->current_context || !dc->temp_flip_context) {
+ if (!dc->current_context) {
dm_error("%s: failed to create validate ctx\n", __func__);
goto val_ctx_fail;
}
+ dc->current_context->ref_count++;
+
dc_ctx->cgs_device = init_params->cgs_device;
dc_ctx->driver_context = init_params->driver;
dc_ctx->dc = &dc->public;
else {
/* Create BIOS parser */
struct bp_init_data bp_init_data;
+
bp_init_data.ctx = dc_ctx;
bp_init_data.bios = init_params->asic_id.atombios_base_address;
}
dc_ctx->created_bios = true;
- }
+ }
/* Create I2C AUX */
dc_ctx->i2caux = dal_i2caux_create(dc_ctx);
return true;
for (j = 0; j < set[i].surface_count; j++) {
- struct dc_surface temp_surf = { 0 };
+ struct dc_surface temp_surf;
+ memset(&temp_surf, 0, sizeof(temp_surf));
temp_surf = *context->stream_status[i].surfaces[j];
temp_surf.clip_rect = set[i].surfaces[j]->clip_rect;
return false;
}
-bool dc_validate_resources(
+struct validate_context *dc_get_validate_context(
const struct dc *dc,
const struct dc_validation_set set[],
uint8_t set_count)
enum dc_status result = DC_ERROR_UNEXPECTED;
struct validate_context *context;
- if (!is_validation_required(core_dc, set, set_count))
- return true;
-
context = dm_alloc(sizeof(struct validate_context));
- if(context == NULL)
+ if (context == NULL)
goto context_alloc_fail;
+ ++context->ref_count;
+
+ if (!is_validation_required(core_dc, set, set_count)) {
+ dc_resource_validate_ctx_copy_construct(core_dc->current_context, context);
+ return context;
+ }
+
result = core_dc->res_pool->funcs->validate_with_context(
- core_dc, set, set_count, context);
+ core_dc, set, set_count, context, core_dc->current_context);
- resource_validate_ctx_destruct(context);
- dm_free(context);
+context_alloc_fail:
+ if (result != DC_OK) {
+ dm_logger_write(core_dc->ctx->logger, LOG_WARNING,
+ "%s:resource validation failed, dc_status:%d\n",
+ __func__,
+ result);
+
+ dc_release_validate_context(context);
+ context = NULL;
+ }
+
+ return context;
+
+}
+
+bool dc_validate_resources(
+ const struct dc *dc,
+ const struct dc_validation_set set[],
+ uint8_t set_count)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+ enum dc_status result = DC_ERROR_UNEXPECTED;
+ struct validate_context *context;
+
+ context = dm_alloc(sizeof(struct validate_context));
+ if (context == NULL)
+ goto context_alloc_fail;
+
+ ++context->ref_count;
+
+ result = core_dc->res_pool->funcs->validate_with_context(
+ core_dc, set, set_count, context, NULL);
context_alloc_fail:
if (result != DC_OK) {
result);
}
- return (result == DC_OK);
+ dc_release_validate_context(context);
+ context = NULL;
+ return result == DC_OK;
}
bool dc_validate_guaranteed(
if (context == NULL)
goto context_alloc_fail;
+ ++context->ref_count;
+
result = core_dc->res_pool->funcs->validate_guaranteed(
core_dc, stream, context);
- resource_validate_ctx_destruct(context);
- dm_free(context);
+ dc_release_validate_context(context);
context_alloc_fail:
if (result != DC_OK) {
{
int i, j;
int group_index = 0;
- int pipe_count = ctx->res_ctx.pool->pipe_count;
+ int pipe_count = core_dc->res_pool->pipe_count;
struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL };
for (i = 0; i < pipe_count; i++) {
}
}
+static bool context_changed(
+ struct core_dc *dc,
+ struct validate_context *context)
+{
+ uint8_t i;
+
+ if (context->stream_count != dc->current_context->stream_count)
+ return true;
+
+ for (i = 0; i < dc->current_context->stream_count; i++) {
+ if (&dc->current_context->streams[i]->public != &context->streams[i]->public)
+ return true;
+ }
+
+ return false;
+}
+
static bool streams_changed(
struct core_dc *dc,
const struct dc_stream *streams[],
return false;
}
-bool dc_commit_streams(
+bool dc_enable_stereo(
struct dc *dc,
+ struct validate_context *context,
const struct dc_stream *streams[],
uint8_t stream_count)
{
+ bool ret = true;
+ int i, j;
+ struct pipe_ctx *pipe;
struct core_dc *core_dc = DC_TO_CORE(dc);
- struct dc_bios *dcb = core_dc->ctx->dc_bios;
- enum dc_status result = DC_ERROR_UNEXPECTED;
- struct validate_context *context;
- struct dc_validation_set set[MAX_STREAMS] = { {0, {0} } };
- int i, j, k;
-
- if (false == streams_changed(core_dc, streams, stream_count))
- return DC_OK;
- dm_logger_write(core_dc->ctx->logger, LOG_DC, "%s: %d streams\n",
- __func__, stream_count);
-
- for (i = 0; i < stream_count; i++) {
- const struct dc_stream *stream = streams[i];
- const struct dc_stream_status *status = dc_stream_get_status(stream);
- int j;
+#ifdef ENABLE_FBC
+ struct compressor *fbc_compressor = core_dc->fbc_compressor;
+#endif
- dc_stream_log(stream,
- core_dc->ctx->logger,
- LOG_DC);
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (context != NULL)
+ pipe = &context->res_ctx.pipe_ctx[i];
+ else
+ pipe = &core_dc->current_context->res_ctx.pipe_ctx[i];
+ for (j = 0 ; pipe && j < stream_count; j++) {
+ if (streams[j] && streams[j] == &pipe->stream->public &&
+ core_dc->hwss.setup_stereo)
+ core_dc->hwss.setup_stereo(pipe, core_dc);
+ }
+ }
- set[i].stream = stream;
+#ifdef ENABLE_FBC
+ if (fbc_compressor != NULL &&
+ fbc_compressor->funcs->is_fbc_enabled_in_hw(core_dc->fbc_compressor,
+ &pipe->tg->inst))
+ fbc_compressor->funcs->disable_fbc(fbc_compressor);
- if (status) {
- set[i].surface_count = status->surface_count;
- for (j = 0; j < status->surface_count; j++)
- set[i].surfaces[j] = status->surfaces[j];
- }
+#endif
+ return ret;
+}
- }
- context = dm_alloc(sizeof(struct validate_context));
- if (context == NULL)
- goto context_alloc_fail;
+/*
+ * Applies given context to HW and copy it into current context.
+ * It's up to the user to release the src context afterwards.
+ */
+static bool dc_commit_context_no_check(struct dc *dc, struct validate_context *context)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+ struct dc_bios *dcb = core_dc->ctx->dc_bios;
+ enum dc_status result = DC_ERROR_UNEXPECTED;
+ struct pipe_ctx *pipe;
+ int i, j, k, l;
+ const struct dc_stream *dc_streams[MAX_STREAMS] = {0};
- result = core_dc->res_pool->funcs->validate_with_context(core_dc, set, stream_count, context);
- if (result != DC_OK){
- dm_logger_write(core_dc->ctx->logger, LOG_ERROR,
- "%s: Context validation failed! dc_status:%d\n",
- __func__,
- result);
- BREAK_TO_DEBUGGER();
- resource_validate_ctx_destruct(context);
- goto fail;
- }
+ for (i = 0; i < context->stream_count; i++)
+ dc_streams[i] = &context->streams[i]->public;
- if (!dcb->funcs->is_accelerated_mode(dcb)) {
+ if (!dcb->funcs->is_accelerated_mode(dcb))
core_dc->hwss.enable_accelerated_mode(core_dc);
- }
- if (result == DC_OK) {
- result = core_dc->hwss.apply_ctx_to_hw(core_dc, context);
+ for (i = 0; i < core_dc->res_pool->pipe_count; i++) {
+ pipe = &context->res_ctx.pipe_ctx[i];
+ core_dc->hwss.wait_for_mpcc_disconnect(core_dc, core_dc->res_pool, pipe);
}
+ result = core_dc->hwss.apply_ctx_to_hw(core_dc, context);
program_timing_sync(core_dc, context);
for (i = 0; i < context->stream_count; i++) {
- const struct core_sink *sink = context->streams[i]->sink;
+ const struct dc_sink *sink = context->streams[i]->sink;
for (j = 0; j < context->stream_status[i].surface_count; j++) {
- const struct dc_surface *dc_surface =
+ const struct dc_surface *surface =
context->stream_status[i].surfaces[j];
- for (k = 0; k < context->res_ctx.pool->pipe_count; k++) {
- struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[k];
+ core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context);
- if (dc_surface != &pipe->surface->public
- || !dc_surface->visible)
- continue;
+ /*
+ * enable stereo
+ * TODO rework dc_enable_stereo call to work with validation sets?
+ */
+ for (k = 0; k < MAX_PIPES; k++) {
+ pipe = &context->res_ctx.pipe_ctx[k];
- pipe->tg->funcs->set_blank(pipe->tg, false);
+ for (l = 0 ; pipe && l < context->stream_count; l++) {
+ if (context->streams[l] &&
+ context->streams[l] == pipe->stream &&
+ core_dc->hwss.setup_stereo)
+ core_dc->hwss.setup_stereo(pipe, core_dc);
+ }
}
}
context->streams[i]->public.timing.pix_clk_khz);
}
- resource_validate_ctx_destruct(core_dc->current_context);
+ dc_enable_stereo(dc, context, dc_streams, context->stream_count);
- if (core_dc->temp_flip_context != core_dc->current_context) {
- dm_free(core_dc->temp_flip_context);
- core_dc->temp_flip_context = core_dc->current_context;
- }
- core_dc->current_context = context;
- memset(core_dc->temp_flip_context, 0, sizeof(*core_dc->temp_flip_context));
+ dc_release_validate_context(core_dc->current_context);
- return (result == DC_OK);
+ core_dc->current_context = context;
-fail:
- dm_free(context);
+ dc_retain_validate_context(core_dc->current_context);
-context_alloc_fail:
return (result == DC_OK);
}
-bool dc_pre_update_surfaces_to_stream(
- struct dc *dc,
- const struct dc_surface *const *new_surfaces,
- uint8_t new_surface_count,
- const struct dc_stream *dc_stream)
+bool dc_commit_context(struct dc *dc, struct validate_context *context)
{
- int i, j;
+ enum dc_status result = DC_ERROR_UNEXPECTED;
struct core_dc *core_dc = DC_TO_CORE(dc);
- struct dc_stream_status *stream_status = NULL;
- struct validate_context *context;
- bool ret = true;
+ int i;
- pre_surface_trace(dc, new_surfaces, new_surface_count);
+ if (false == context_changed(core_dc, context))
+ return DC_OK;
- if (core_dc->current_context->stream_count == 0)
- return false;
+ dm_logger_write(core_dc->ctx->logger, LOG_DC, "%s: %d streams\n",
+ __func__, context->stream_count);
- /* Cannot commit surface to a stream that is not commited */
- for (i = 0; i < core_dc->current_context->stream_count; i++)
- if (dc_stream == &core_dc->current_context->streams[i]->public)
- break;
+ for (i = 0; i < context->stream_count; i++) {
+ const struct dc_stream *stream = &context->streams[i]->public;
- if (i == core_dc->current_context->stream_count)
- return false;
+ dc_stream_log(stream,
+ core_dc->ctx->logger,
+ LOG_DC);
+ }
- stream_status = &core_dc->current_context->stream_status[i];
+ result = dc_commit_context_no_check(dc, context);
- if (new_surface_count == stream_status->surface_count) {
- bool skip_pre = true;
+ return (result == DC_OK);
+}
- for (i = 0; i < stream_status->surface_count; i++) {
- struct dc_surface temp_surf = { 0 };
- temp_surf = *stream_status->surfaces[i];
- temp_surf.clip_rect = new_surfaces[i]->clip_rect;
- temp_surf.dst_rect.x = new_surfaces[i]->dst_rect.x;
- temp_surf.dst_rect.y = new_surfaces[i]->dst_rect.y;
+bool dc_commit_streams(
+ struct dc *dc,
+ const struct dc_stream *streams[],
+ uint8_t stream_count)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+ enum dc_status result = DC_ERROR_UNEXPECTED;
+ struct validate_context *context;
+ struct dc_validation_set set[MAX_STREAMS] = { {0, {0} } };
+ int i;
- if (memcmp(&temp_surf, new_surfaces[i], sizeof(temp_surf)) != 0) {
- skip_pre = false;
- break;
- }
- }
+ if (false == streams_changed(core_dc, streams, stream_count))
+ return DC_OK;
- if (skip_pre)
- return true;
- }
+ dm_logger_write(core_dc->ctx->logger, LOG_DC, "%s: %d streams\n",
+ __func__, stream_count);
- context = dm_alloc(sizeof(struct validate_context));
+ for (i = 0; i < stream_count; i++) {
+ const struct dc_stream *stream = streams[i];
+ const struct dc_stream_status *status = dc_stream_get_status(stream);
+ int j;
- if (!context) {
- dm_error("%s: failed to create validate ctx\n", __func__);
- ret = false;
- goto val_ctx_fail;
- }
+ dc_stream_log(stream,
+ core_dc->ctx->logger,
+ LOG_DC);
- resource_validate_ctx_copy_construct(core_dc->current_context, context);
+ set[i].stream = stream;
- dm_logger_write(core_dc->ctx->logger, LOG_DC,
- "%s: commit %d surfaces to stream 0x%x\n",
- __func__,
- new_surface_count,
- dc_stream);
+ if (status) {
+ set[i].surface_count = status->surface_count;
+ for (j = 0; j < status->surface_count; j++)
+ set[i].surfaces[j] = status->surfaces[j];
+ }
- if (!resource_attach_surfaces_to_context(
- new_surfaces, new_surface_count, dc_stream, context)) {
- BREAK_TO_DEBUGGER();
- ret = false;
- goto unexpected_fail;
}
- for (i = 0; i < new_surface_count; i++)
- for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
- if (context->res_ctx.pipe_ctx[j].surface !=
- DC_SURFACE_TO_CORE(new_surfaces[i]))
- continue;
+ context = dm_alloc(sizeof(struct validate_context));
+ if (context == NULL)
+ goto context_alloc_fail;
- resource_build_scaling_params(
- new_surfaces[i], &context->res_ctx.pipe_ctx[j]);
- }
+ ++context->ref_count;
- if (!core_dc->res_pool->funcs->validate_bandwidth(core_dc, context)) {
+ result = core_dc->res_pool->funcs->validate_with_context(
+ core_dc, set, stream_count, context, core_dc->current_context);
+ if (result != DC_OK){
+ dm_logger_write(core_dc->ctx->logger, LOG_ERROR,
+ "%s: Context validation failed! dc_status:%d\n",
+ __func__,
+ result);
BREAK_TO_DEBUGGER();
- ret = false;
- goto unexpected_fail;
+ goto fail;
}
- core_dc->hwss.set_bandwidth(core_dc, context, false);
+ result = dc_commit_context_no_check(dc, context);
- for (i = 0; i < new_surface_count; i++)
- for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
- if (context->res_ctx.pipe_ctx[j].surface !=
- DC_SURFACE_TO_CORE(new_surfaces[i]))
- continue;
-
- core_dc->hwss.prepare_pipe_for_context(
- core_dc,
- &context->res_ctx.pipe_ctx[j],
- context);
- }
-
-unexpected_fail:
- resource_validate_ctx_destruct(context);
- dm_free(context);
-val_ctx_fail:
+fail:
+ dc_release_validate_context(context);
- return ret;
+context_alloc_fail:
+ return (result == DC_OK);
}
bool dc_post_update_surfaces_to_stream(struct dc *dc)
{
int i;
struct core_dc *core_dc = DC_TO_CORE(dc);
- struct validate_context *context = dm_alloc(sizeof(struct validate_context));
-
- if (!context) {
- dm_error("%s: failed to create validate ctx\n", __func__);
- return false;
- }
- resource_validate_ctx_copy_construct(core_dc->current_context, context);
+ struct validate_context *context = core_dc->current_context;
post_surface_trace(dc);
- for (i = 0; i < context->res_ctx.pool->pipe_count; i++)
- if (context->res_ctx.pipe_ctx[i].stream == NULL) {
- context->res_ctx.pipe_ctx[i].pipe_idx = i;
- core_dc->hwss.power_down_front_end(
- core_dc, &context->res_ctx.pipe_ctx[i]);
- }
- if (!core_dc->res_pool->funcs->validate_bandwidth(core_dc, context)) {
- BREAK_TO_DEBUGGER();
- return false;
- }
+ for (i = 0; i < core_dc->res_pool->pipe_count; i++)
+ if (context->res_ctx.pipe_ctx[i].stream == NULL
+ || context->res_ctx.pipe_ctx[i].surface == NULL)
+ core_dc->hwss.power_down_front_end(core_dc, i);
+ /* 3rd param should be true, temp w/a for RV*/
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+ core_dc->hwss.set_bandwidth(core_dc, context, core_dc->ctx->dce_version != DCN_VERSION_1_0);
+#else
core_dc->hwss.set_bandwidth(core_dc, context, true);
-
- resource_validate_ctx_destruct(core_dc->current_context);
- core_dc->current_context = context;
-
+#endif
return true;
}
bool dc_commit_surfaces_to_stream(
struct dc *dc,
- const struct dc_surface **new_surfaces,
+ struct dc_surface **new_surfaces,
uint8_t new_surface_count,
const struct dc_stream *dc_stream)
{
struct dc_plane_info plane_info[MAX_SURFACES];
struct dc_scaling_info scaling_info[MAX_SURFACES];
int i;
+ struct dc_stream_update *stream_update =
+ dm_alloc(sizeof(struct dc_stream_update));
- if (!dc_pre_update_surfaces_to_stream(
- dc, new_surfaces, new_surface_count, dc_stream))
+ if (!stream_update) {
+ BREAK_TO_DEBUGGER();
return false;
+ }
memset(updates, 0, sizeof(updates));
memset(flip_addr, 0, sizeof(flip_addr));
memset(plane_info, 0, sizeof(plane_info));
memset(scaling_info, 0, sizeof(scaling_info));
+ stream_update->src = dc_stream->src;
+ stream_update->dst = dc_stream->dst;
+ stream_update->out_transfer_func = dc_stream->out_transfer_func;
+
for (i = 0; i < new_surface_count; i++) {
updates[i].surface = new_surfaces[i];
updates[i].gamma =
(struct dc_gamma *)new_surfaces[i]->gamma_correction;
+ updates[i].in_transfer_func = new_surfaces[i]->in_transfer_func;
flip_addr[i].address = new_surfaces[i]->address;
flip_addr[i].flip_immediate = new_surfaces[i]->flip_immediate;
plane_info[i].color_space = new_surfaces[i]->color_space;
plane_info[i].stereo_format = new_surfaces[i]->stereo_format;
plane_info[i].tiling_info = new_surfaces[i]->tiling_info;
plane_info[i].visible = new_surfaces[i]->visible;
+ plane_info[i].per_pixel_alpha = new_surfaces[i]->per_pixel_alpha;
plane_info[i].dcc = new_surfaces[i]->dcc;
scaling_info[i].scaling_quality = new_surfaces[i]->scaling_quality;
scaling_info[i].src_rect = new_surfaces[i]->src_rect;
updates[i].plane_info = &plane_info[i];
updates[i].scaling_info = &scaling_info[i];
}
- dc_update_surfaces_for_stream(dc, updates, new_surface_count, dc_stream);
- return dc_post_update_surfaces_to_stream(dc);
+ dc_update_surfaces_and_stream(
+ dc,
+ updates,
+ new_surface_count,
+ dc_stream, stream_update);
+
+ dc_post_update_surfaces_to_stream(dc);
+
+ dm_free(stream_update);
+ return true;
+}
+
+void dc_retain_validate_context(struct validate_context *context)
+{
+ ASSERT(context->ref_count > 0);
+ ++context->ref_count;
+}
+
+void dc_release_validate_context(struct validate_context *context)
+{
+ ASSERT(context->ref_count > 0);
+ --context->ref_count;
+
+ if (context->ref_count == 0) {
+ dc_resource_validate_ctx_destruct(context);
+ dm_free(context);
+ }
}
static bool is_surface_in_context(
{
int j;
- for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
+ for (j = 0; j < MAX_PIPES; j++) {
const struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
- if (surface == &pipe_ctx->surface->public) {
+ if (surface == pipe_ctx->surface) {
return true;
}
}
static unsigned int pixel_format_to_bpp(enum surface_pixel_format format)
{
switch (format) {
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
+ return 12;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
return 16;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
}
static enum surface_update_type get_plane_info_update_type(
- const struct dc_surface_update *u)
+ const struct dc_surface_update *u,
+ int surface_index)
{
- struct dc_plane_info temp_plane_info = { { { { 0 } } } };
+ struct dc_plane_info temp_plane_info;
+ memset(&temp_plane_info, 0, sizeof(temp_plane_info));
if (!u->plane_info)
return UPDATE_TYPE_FAST;
+ temp_plane_info = *u->plane_info;
+
/* Copy all parameters that will cause a full update
* from current surface, the rest of the parameters
* from provided plane configuration.
temp_plane_info.rotation = u->surface->rotation;
temp_plane_info.stereo_format = u->surface->stereo_format;
temp_plane_info.tiling_info = u->surface->tiling_info;
- temp_plane_info.visible = u->surface->visible;
- /* Special Validation parameters */
- temp_plane_info.format = u->plane_info->format;
+ if (surface_index == 0)
+ temp_plane_info.visible = u->plane_info->visible;
+ else
+ temp_plane_info.visible = u->surface->visible;
if (memcmp(u->plane_info, &temp_plane_info,
sizeof(struct dc_plane_info)) != 0)
static enum surface_update_type get_scaling_info_update_type(
const struct dc_surface_update *u)
{
- struct dc_scaling_info temp_scaling_info = { { 0 } };
-
if (!u->scaling_info)
return UPDATE_TYPE_FAST;
- /* Copy all parameters that will cause a full update
- * from current surface, the rest of the parameters
- * from provided plane configuration.
- * Perform memory compare and special validation
- * for those that can cause fast/medium updates
- */
-
- /* Full Update Parameters */
- temp_scaling_info.dst_rect = u->surface->dst_rect;
- temp_scaling_info.src_rect = u->surface->src_rect;
- temp_scaling_info.scaling_quality = u->surface->scaling_quality;
-
- /* Special validation required */
- temp_scaling_info.clip_rect = u->scaling_info->clip_rect;
-
- if (memcmp(u->scaling_info, &temp_scaling_info,
- sizeof(struct dc_scaling_info)) != 0)
+ if (u->scaling_info->src_rect.width != u->surface->src_rect.width
+ || u->scaling_info->src_rect.height != u->surface->src_rect.height
+ || u->scaling_info->clip_rect.width != u->surface->clip_rect.width
+ || u->scaling_info->clip_rect.height != u->surface->clip_rect.height
+ || u->scaling_info->dst_rect.width != u->surface->dst_rect.width
+ || u->scaling_info->dst_rect.height != u->surface->dst_rect.height)
return UPDATE_TYPE_FULL;
- /* Check Clip rectangles if not equal
- * difference is in offsets == > UPDATE_TYPE_FAST
- * difference is in dimensions == > UPDATE_TYPE_FULL
- */
- if (memcmp(&u->scaling_info->clip_rect,
- &u->surface->clip_rect, sizeof(struct rect)) != 0) {
- if ((u->scaling_info->clip_rect.height ==
- u->surface->clip_rect.height) &&
- (u->scaling_info->clip_rect.width ==
- u->surface->clip_rect.width)) {
- return UPDATE_TYPE_FAST;
- } else {
- return UPDATE_TYPE_FULL;
- }
- }
+ if (u->scaling_info->src_rect.x != u->surface->src_rect.x
+ || u->scaling_info->src_rect.y != u->surface->src_rect.y
+ || u->scaling_info->clip_rect.x != u->surface->clip_rect.x
+ || u->scaling_info->clip_rect.y != u->surface->clip_rect.y
+ || u->scaling_info->dst_rect.x != u->surface->dst_rect.x
+ || u->scaling_info->dst_rect.y != u->surface->dst_rect.y)
+ return UPDATE_TYPE_MED;
return UPDATE_TYPE_FAST;
}
static enum surface_update_type det_surface_update(
const struct core_dc *dc,
- const struct dc_surface_update *u)
+ const struct dc_surface_update *u,
+ int surface_index)
{
const struct validate_context *context = dc->current_context;
enum surface_update_type type = UPDATE_TYPE_FAST;
if (!is_surface_in_context(context, u->surface))
return UPDATE_TYPE_FULL;
- type = get_plane_info_update_type(u);
+ type = get_plane_info_update_type(u, surface_index);
if (overall_type < type)
overall_type = type;
overall_type = type;
if (u->in_transfer_func ||
- u->out_transfer_func ||
u->hdr_static_metadata) {
if (overall_type < UPDATE_TYPE_MED)
overall_type = UPDATE_TYPE_MED;
struct dc *dc,
struct dc_surface_update *updates,
int surface_count,
+ struct dc_stream_update *stream_update,
const struct dc_stream_status *stream_status)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
int i;
enum surface_update_type overall_type = UPDATE_TYPE_FAST;
- if (stream_status->surface_count != surface_count)
+ if (stream_status == NULL || stream_status->surface_count != surface_count)
+ return UPDATE_TYPE_FULL;
+
+ if (stream_update)
return UPDATE_TYPE_FULL;
for (i = 0 ; i < surface_count; i++) {
enum surface_update_type type =
- det_surface_update(core_dc, &updates[i]);
+ det_surface_update(core_dc, &updates[i], i);
if (type == UPDATE_TYPE_FULL)
return type;
enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
-void dc_update_surfaces_for_stream(struct dc *dc,
- struct dc_surface_update *updates, int surface_count,
- const struct dc_stream *dc_stream)
+void dc_update_surfaces_and_stream(struct dc *dc,
+ struct dc_surface_update *srf_updates, int surface_count,
+ const struct dc_stream *dc_stream,
+ struct dc_stream_update *stream_update)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
struct validate_context *context;
int i, j;
-
enum surface_update_type update_type;
const struct dc_stream_status *stream_status;
+ struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
+ struct dc_context *dc_ctx = core_dc->ctx;
+
+ /* Currently this function do not result in any HW programming
+ * when called with 0 surface. But proceeding will cause
+ * SW state to be updated in validate_context. So we might as
+ * well make it not do anything at all until the hw programming
+ * is implemented properly to handle 0 surface case.
+ * TODO: fix hw programming then remove this early return
+ */
+ if (surface_count == 0)
+ return;
stream_status = dc_stream_get_status(dc_stream);
ASSERT(stream_status);
if (!stream_status)
return; /* Cannot commit surface to stream that is not committed */
+#ifdef ENABLE_FBC
+ if (srf_updates->flip_addr) {
+ if (srf_updates->flip_addr->address.grph.addr.low_part == 0)
+ ASSERT(0);
+ }
+#endif
+ context = core_dc->current_context;
+
+ /* update current stream with the new updates */
+ if (stream_update) {
+ if ((stream_update->src.height != 0) &&
+ (stream_update->src.width != 0))
+ stream->public.src = stream_update->src;
+
+ if ((stream_update->dst.height != 0) &&
+ (stream_update->dst.width != 0))
+ stream->public.dst = stream_update->dst;
+
+ if (stream_update->out_transfer_func &&
+ stream_update->out_transfer_func !=
+ dc_stream->out_transfer_func) {
+ if (dc_stream->out_transfer_func != NULL)
+ dc_transfer_func_release(dc_stream->out_transfer_func);
+ dc_transfer_func_retain(stream_update->out_transfer_func);
+ stream->public.out_transfer_func =
+ stream_update->out_transfer_func;
+ }
+ }
+
+ /* do not perform surface update if surface has invalid dimensions
+ * (all zero) and no scaling_info is provided
+ */
+ if (surface_count > 0 &&
+ srf_updates->surface->src_rect.width == 0 &&
+ srf_updates->surface->src_rect.height == 0 &&
+ srf_updates->surface->dst_rect.width == 0 &&
+ srf_updates->surface->dst_rect.height == 0 &&
+ !srf_updates->scaling_info) {
+ ASSERT(false);
+ return;
+ }
+
update_type = dc_check_update_surfaces_for_stream(
- dc, updates, surface_count, stream_status);
+ dc, srf_updates, surface_count, stream_update, stream_status);
if (update_type >= update_surface_trace_level)
- update_surface_trace(dc, updates, surface_count);
+ update_surface_trace(dc, srf_updates, surface_count);
if (update_type >= UPDATE_TYPE_FULL) {
- const struct dc_surface *new_surfaces[MAX_SURFACES] = { 0 };
+ struct dc_surface *new_surfaces[MAX_SURFACES] = {0};
for (i = 0; i < surface_count; i++)
- new_surfaces[i] = updates[i].surface;
+ new_surfaces[i] = srf_updates[i].surface;
/* initialize scratch memory for building context */
- context = core_dc->temp_flip_context;
- resource_validate_ctx_copy_construct(
+ context = dm_alloc(sizeof(*context));
+ if (context == NULL)
+ goto context_alloc_fail;
+
+ ++context->ref_count;
+
+ dc_resource_validate_ctx_copy_construct(
core_dc->current_context, context);
/* add surface to context */
if (!resource_attach_surfaces_to_context(
- new_surfaces, surface_count, dc_stream, context)) {
+ new_surfaces, surface_count, dc_stream,
+ context, core_dc->res_pool)) {
BREAK_TO_DEBUGGER();
- return;
+ goto fail;
}
- } else {
- context = core_dc->current_context;
}
+
+ /* save update parameters into surface */
for (i = 0; i < surface_count; i++) {
- /* save update param into surface */
- struct core_surface *surface = DC_SURFACE_TO_CORE(updates[i].surface);
- struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
-
- if (updates[i].flip_addr) {
- surface->public.address = updates[i].flip_addr->address;
- surface->public.flip_immediate =
- updates[i].flip_addr->flip_immediate;
+ struct dc_surface *surface = srf_updates[i].surface;
+
+ if (srf_updates[i].flip_addr) {
+ surface->address = srf_updates[i].flip_addr->address;
+ surface->flip_immediate =
+ srf_updates[i].flip_addr->flip_immediate;
}
- if (updates[i].scaling_info) {
- surface->public.scaling_quality =
- updates[i].scaling_info->scaling_quality;
- surface->public.dst_rect =
- updates[i].scaling_info->dst_rect;
- surface->public.src_rect =
- updates[i].scaling_info->src_rect;
- surface->public.clip_rect =
- updates[i].scaling_info->clip_rect;
+ if (srf_updates[i].scaling_info) {
+ surface->scaling_quality =
+ srf_updates[i].scaling_info->scaling_quality;
+ surface->dst_rect =
+ srf_updates[i].scaling_info->dst_rect;
+ surface->src_rect =
+ srf_updates[i].scaling_info->src_rect;
+ surface->clip_rect =
+ srf_updates[i].scaling_info->clip_rect;
}
- if (updates[i].plane_info) {
- surface->public.color_space =
- updates[i].plane_info->color_space;
- surface->public.format =
- updates[i].plane_info->format;
- surface->public.plane_size =
- updates[i].plane_info->plane_size;
- surface->public.rotation =
- updates[i].plane_info->rotation;
- surface->public.horizontal_mirror =
- updates[i].plane_info->horizontal_mirror;
- surface->public.stereo_format =
- updates[i].plane_info->stereo_format;
- surface->public.tiling_info =
- updates[i].plane_info->tiling_info;
- surface->public.visible =
- updates[i].plane_info->visible;
- surface->public.dcc =
- updates[i].plane_info->dcc;
+ if (srf_updates[i].plane_info) {
+ surface->color_space =
+ srf_updates[i].plane_info->color_space;
+ surface->format =
+ srf_updates[i].plane_info->format;
+ surface->plane_size =
+ srf_updates[i].plane_info->plane_size;
+ surface->rotation =
+ srf_updates[i].plane_info->rotation;
+ surface->horizontal_mirror =
+ srf_updates[i].plane_info->horizontal_mirror;
+ surface->stereo_format =
+ srf_updates[i].plane_info->stereo_format;
+ surface->tiling_info =
+ srf_updates[i].plane_info->tiling_info;
+ surface->visible =
+ srf_updates[i].plane_info->visible;
+ surface->per_pixel_alpha =
+ srf_updates[i].plane_info->per_pixel_alpha;
+ surface->dcc =
+ srf_updates[i].plane_info->dcc;
}
- /* not sure if we still need this */
- if (update_type == UPDATE_TYPE_FULL) {
- for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
+ if (update_type >= UPDATE_TYPE_MED) {
+ for (j = 0; j < core_dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
if (pipe_ctx->surface != surface)
continue;
- resource_build_scaling_params(updates[i].surface, pipe_ctx);
+ resource_build_scaling_params(pipe_ctx);
}
}
- if (updates[i].gamma &&
- updates[i].gamma != surface->public.gamma_correction) {
- if (surface->public.gamma_correction != NULL)
- dc_gamma_release(&surface->public.
- gamma_correction);
+ if (srf_updates[i].gamma &&
+ srf_updates[i].gamma != surface->gamma_correction) {
+ if (surface->gamma_correction != NULL)
+ dc_gamma_release(&surface->gamma_correction);
- dc_gamma_retain(updates[i].gamma);
- surface->public.gamma_correction =
- updates[i].gamma;
+ dc_gamma_retain(srf_updates[i].gamma);
+ surface->gamma_correction = srf_updates[i].gamma;
}
- if (updates[i].in_transfer_func &&
- updates[i].in_transfer_func != surface->public.in_transfer_func) {
- if (surface->public.in_transfer_func != NULL)
+ if (srf_updates[i].in_transfer_func &&
+ srf_updates[i].in_transfer_func != surface->in_transfer_func) {
+ if (surface->in_transfer_func != NULL)
dc_transfer_func_release(
- surface->public.
+ surface->
in_transfer_func);
dc_transfer_func_retain(
- updates[i].in_transfer_func);
- surface->public.in_transfer_func =
- updates[i].in_transfer_func;
+ srf_updates[i].in_transfer_func);
+ surface->in_transfer_func =
+ srf_updates[i].in_transfer_func;
}
- if (updates[i].out_transfer_func &&
- updates[i].out_transfer_func != dc_stream->out_transfer_func) {
- if (dc_stream->out_transfer_func != NULL)
- dc_transfer_func_release(dc_stream->out_transfer_func);
- dc_transfer_func_retain(updates[i].out_transfer_func);
- stream->public.out_transfer_func = updates[i].out_transfer_func;
+ if (srf_updates[i].hdr_static_metadata)
+ surface->hdr_static_ctx =
+ *(srf_updates[i].hdr_static_metadata);
+ }
+
+ if (update_type == UPDATE_TYPE_FULL) {
+ if (!core_dc->res_pool->funcs->validate_bandwidth(core_dc, context)) {
+ BREAK_TO_DEBUGGER();
+ goto fail;
+ } else {
+ core_dc->hwss.set_bandwidth(core_dc, context, false);
+ context_clock_trace(dc, context);
}
- if (updates[i].hdr_static_metadata)
- surface->public.hdr_static_ctx =
- *(updates[i].hdr_static_metadata);
}
- if (update_type == UPDATE_TYPE_FULL &&
- !core_dc->res_pool->funcs->validate_bandwidth(core_dc, context)) {
- BREAK_TO_DEBUGGER();
- return;
+ if (update_type > UPDATE_TYPE_FAST) {
+ for (j = 0; j < core_dc->res_pool->pipe_count; j++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+
+ core_dc->hwss.wait_for_mpcc_disconnect(core_dc, core_dc->res_pool, pipe_ctx);
+ }
}
- if (!surface_count) /* reset */
+ if (surface_count == 0)
core_dc->hwss.apply_ctx_for_surface(core_dc, NULL, context);
+ /* Lock pipes for provided surfaces, or all active if full update*/
for (i = 0; i < surface_count; i++) {
- struct core_surface *surface = DC_SURFACE_TO_CORE(updates[i].surface);
+ struct dc_surface *surface = srf_updates[i].surface;
- for (j = 0; j < context->res_ctx.pool->pipe_count; j++) {
+ for (j = 0; j < core_dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
- struct pipe_ctx *cur_pipe_ctx;
- bool is_new_pipe_surface = true;
- if (pipe_ctx->surface != surface)
+ if (update_type != UPDATE_TYPE_FULL && pipe_ctx->surface != surface)
+ continue;
+ if (!pipe_ctx->surface || pipe_ctx->top_pipe)
continue;
-
- if (update_type >= UPDATE_TYPE_MED) {
- /* only apply for top pipe */
- if (!pipe_ctx->top_pipe) {
- core_dc->hwss.apply_ctx_for_surface(core_dc,
- surface, context);
- context_timing_trace(dc, &context->res_ctx);
- }
- }
if (!pipe_ctx->tg->funcs->is_blanked(pipe_ctx->tg)) {
core_dc->hwss.pipe_control_lock(
pipe_ctx,
true);
}
+ }
+ if (update_type == UPDATE_TYPE_FULL)
+ break;
+ }
+
+ /* Full fe update*/
+ for (j = 0; j < core_dc->res_pool->pipe_count; j++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+ struct pipe_ctx *cur_pipe_ctx = &core_dc->current_context->res_ctx.pipe_ctx[j];
+ bool is_new_pipe_surface = cur_pipe_ctx->surface != pipe_ctx->surface;
+ struct dc_cursor_position position = { 0 };
+
+ if (update_type != UPDATE_TYPE_FULL || !pipe_ctx->surface)
+ continue;
+
+ if (!pipe_ctx->top_pipe)
+ core_dc->hwss.apply_ctx_for_surface(
+ core_dc, pipe_ctx->surface, context);
- if (updates[i].flip_addr)
+ /* TODO: this is a hack w/a for switching from mpo to pipe split */
+ dc_stream_set_cursor_position(&pipe_ctx->stream->public, &position);
+
+ if (is_new_pipe_surface) {
+ core_dc->hwss.update_plane_addr(core_dc, pipe_ctx);
+ core_dc->hwss.set_input_transfer_func(
+ pipe_ctx, pipe_ctx->surface);
+ core_dc->hwss.set_output_transfer_func(
+ pipe_ctx, pipe_ctx->stream);
+ }
+ }
+
+ if (update_type > UPDATE_TYPE_FAST)
+ context_timing_trace(dc, &context->res_ctx);
+
+ /* Perform requested Updates */
+ for (i = 0; i < surface_count; i++) {
+ struct dc_surface *surface = srf_updates[i].surface;
+
+ if (update_type == UPDATE_TYPE_MED)
+ core_dc->hwss.apply_ctx_for_surface(
+ core_dc, surface, context);
+
+ for (j = 0; j < core_dc->res_pool->pipe_count; j++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
+
+ if (pipe_ctx->surface != surface)
+ continue;
+
+ if (srf_updates[i].flip_addr)
core_dc->hwss.update_plane_addr(core_dc, pipe_ctx);
if (update_type == UPDATE_TYPE_FAST)
continue;
- cur_pipe_ctx = &core_dc->current_context->res_ctx.pipe_ctx[j];
- if (cur_pipe_ctx->surface == pipe_ctx->surface)
- is_new_pipe_surface = false;
-
- if (is_new_pipe_surface ||
- updates[i].in_transfer_func)
+ if (srf_updates[i].in_transfer_func)
core_dc->hwss.set_input_transfer_func(
pipe_ctx, pipe_ctx->surface);
- if (is_new_pipe_surface ||
- updates[i].out_transfer_func)
+ if (stream_update != NULL &&
+ stream_update->out_transfer_func != NULL) {
core_dc->hwss.set_output_transfer_func(
- pipe_ctx,
- pipe_ctx->surface,
- pipe_ctx->stream);
+ pipe_ctx, pipe_ctx->stream);
+ }
- if (updates[i].hdr_static_metadata) {
+ if (srf_updates[i].hdr_static_metadata) {
resource_build_info_frame(pipe_ctx);
core_dc->hwss.update_info_frame(pipe_ctx);
}
}
}
- for (i = context->res_ctx.pool->pipe_count - 1; i >= 0; i--) {
+ /* Unlock pipes */
+ for (i = core_dc->res_pool->pipe_count - 1; i >= 0; i--) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
for (j = 0; j < surface_count; j++) {
- if (updates[j].surface == &pipe_ctx->surface->public) {
- if (!pipe_ctx->tg->funcs->is_blanked(pipe_ctx->tg)) {
- core_dc->hwss.pipe_control_lock(
- core_dc,
- pipe_ctx,
- false);
- }
- break;
+ if (update_type != UPDATE_TYPE_FULL &&
+ srf_updates[j].surface != pipe_ctx->surface)
+ continue;
+ if (!pipe_ctx->surface || pipe_ctx->top_pipe)
+ continue;
+
+ if (!pipe_ctx->tg->funcs->is_blanked(pipe_ctx->tg)) {
+ core_dc->hwss.pipe_control_lock(
+ core_dc,
+ pipe_ctx,
+ false);
}
+ break;
}
}
if (core_dc->current_context != context) {
- resource_validate_ctx_destruct(core_dc->current_context);
- core_dc->temp_flip_context = core_dc->current_context;
-
+ dc_release_validate_context(core_dc->current_context);
core_dc->current_context = context;
}
+ return;
+
+fail:
+ dc_release_validate_context(context);
+
+context_alloc_fail:
+ DC_ERROR("Failed to allocate new validate context!\n");
}
uint8_t dc_get_current_stream_count(const struct dc *dc)
return NULL;
}
-const struct dc_link *dc_get_link_at_index(const struct dc *dc, uint32_t link_index)
+struct dc_link *dc_get_link_at_index(const struct dc *dc, uint32_t link_index)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
- return &core_dc->links[link_index]->public;
+ return core_dc->links[link_index];
}
const struct graphics_object_id dc_get_link_id_at_index(
return core_dc->links[link_index]->link_id;
}
-const struct ddc_service *dc_get_ddc_at_index(
- struct dc *dc, uint32_t link_index)
-{
- struct core_dc *core_dc = DC_TO_CORE(dc);
- return core_dc->links[link_index]->ddc;
-}
-
enum dc_irq_source dc_get_hpd_irq_source_at_index(
struct dc *dc, uint32_t link_index)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
- return core_dc->links[link_index]->public.irq_source_hpd;
+ return core_dc->links[link_index]->irq_source_hpd;
}
const struct audio **dc_get_audios(struct dc *dc)
return (const struct audio **)core_dc->res_pool->audios;
}
-void dc_flip_surface_addrs(
- struct dc *dc,
- const struct dc_surface *const surfaces[],
- struct dc_flip_addrs flip_addrs[],
- uint32_t count)
-{
- struct core_dc *core_dc = DC_TO_CORE(dc);
- int i, j;
-
- for (i = 0; i < count; i++) {
- struct core_surface *surface = DC_SURFACE_TO_CORE(surfaces[i]);
-
- surface->public.address = flip_addrs[i].address;
- surface->public.flip_immediate = flip_addrs[i].flip_immediate;
-
- for (j = 0; j < core_dc->res_pool->pipe_count; j++) {
- struct pipe_ctx *pipe_ctx = &core_dc->current_context->res_ctx.pipe_ctx[j];
-
- if (pipe_ctx->surface != surface)
- continue;
-
- core_dc->hwss.update_plane_addr(core_dc, pipe_ctx);
- }
- }
-}
-
enum dc_irq_source dc_interrupt_to_irq_source(
struct dc *dc,
uint32_t src_id,
void dc_interrupt_set(const struct dc *dc, enum dc_irq_source src, bool enable)
{
- struct core_dc *core_dc = DC_TO_CORE(dc);
+ struct core_dc *core_dc;
+
+ if (dc == NULL)
+ return;
+ core_dc = DC_TO_CORE(dc);
+
dal_irq_service_set(core_dc->res_pool->irqs, src, enable);
}
void dc_set_power_state(
struct dc *dc,
- enum dc_acpi_cm_power_state power_state,
- enum dc_video_power_state video_power_state)
+ enum dc_acpi_cm_power_state power_state)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
-
- core_dc->previous_power_state = core_dc->current_power_state;
- core_dc->current_power_state = video_power_state;
+ int ref_count;
switch (power_state) {
case DC_ACPI_CM_POWER_STATE_D0:
core_dc->hwss.init_hw(core_dc);
break;
default:
- /* NULL means "reset/release all DC streams" */
- dc_commit_streams(dc, NULL, 0);
core_dc->hwss.power_down(core_dc);
* clean state, and dc hw programming optimizations will not
* cause any trouble.
*/
+
+ /* Preserve refcount */
+ ref_count = core_dc->current_context->ref_count;
+ dc_resource_validate_ctx_destruct(core_dc->current_context);
memset(core_dc->current_context, 0,
sizeof(*core_dc->current_context));
-
- core_dc->current_context->res_ctx.pool = core_dc->res_pool;
+ core_dc->current_context->ref_count = ref_count;
break;
}
core_link_resume(core_dc->links[i]);
}
-bool dc_read_dpcd(
+bool dc_read_aux_dpcd(
struct dc *dc,
uint32_t link_index,
uint32_t address,
{
struct core_dc *core_dc = DC_TO_CORE(dc);
- struct core_link *link = core_dc->links[link_index];
+ struct dc_link *link = core_dc->links[link_index];
enum ddc_result r = dal_ddc_service_read_dpcd_data(
link->ddc,
+ false,
+ I2C_MOT_UNDEF,
address,
data,
size);
return r == DDC_RESULT_SUCESSFULL;
}
-bool dc_query_ddc_data(
+bool dc_write_aux_dpcd(
struct dc *dc,
uint32_t link_index,
uint32_t address,
- uint8_t *write_buf,
- uint32_t write_size,
- uint8_t *read_buf,
- uint32_t read_size) {
-
+ const uint8_t *data,
+ uint32_t size)
+{
struct core_dc *core_dc = DC_TO_CORE(dc);
+ struct dc_link *link = core_dc->links[link_index];
- struct core_link *link = core_dc->links[link_index];
-
- bool result = dal_ddc_service_query_ddc_data(
+ enum ddc_result r = dal_ddc_service_write_dpcd_data(
link->ddc,
+ false,
+ I2C_MOT_UNDEF,
address,
- write_buf,
- write_size,
- read_buf,
- read_size);
-
- return result;
+ data,
+ size);
+ return r == DDC_RESULT_SUCESSFULL;
}
+bool dc_read_aux_i2c(
+ struct dc *dc,
+ uint32_t link_index,
+ enum i2c_mot_mode mot,
+ uint32_t address,
+ uint8_t *data,
+ uint32_t size)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+
+ struct dc_link *link = core_dc->links[link_index];
+ enum ddc_result r = dal_ddc_service_read_dpcd_data(
+ link->ddc,
+ true,
+ mot,
+ address,
+ data,
+ size);
+ return r == DDC_RESULT_SUCESSFULL;
+}
-bool dc_write_dpcd(
+bool dc_write_aux_i2c(
struct dc *dc,
uint32_t link_index,
+ enum i2c_mot_mode mot,
uint32_t address,
const uint8_t *data,
uint32_t size)
{
struct core_dc *core_dc = DC_TO_CORE(dc);
-
- struct core_link *link = core_dc->links[link_index];
+ struct dc_link *link = core_dc->links[link_index];
enum ddc_result r = dal_ddc_service_write_dpcd_data(
link->ddc,
+ true,
+ mot,
address,
data,
size);
return r == DDC_RESULT_SUCESSFULL;
}
+bool dc_query_ddc_data(
+ struct dc *dc,
+ uint32_t link_index,
+ uint32_t address,
+ uint8_t *write_buf,
+ uint32_t write_size,
+ uint8_t *read_buf,
+ uint32_t read_size) {
+
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+
+ struct dc_link *link = core_dc->links[link_index];
+
+ bool result = dal_ddc_service_query_ddc_data(
+ link->ddc,
+ address,
+ write_buf,
+ write_size,
+ read_buf,
+ read_size);
+
+ return result;
+}
+
bool dc_submit_i2c(
struct dc *dc,
uint32_t link_index,
{
struct core_dc *core_dc = DC_TO_CORE(dc);
- struct core_link *link = core_dc->links[link_index];
+ struct dc_link *link = core_dc->links[link_index];
struct ddc_service *ddc = link->ddc;
return dal_i2caux_submit_i2c_command(
cmd);
}
-static bool link_add_remote_sink_helper(struct core_link *core_link, struct dc_sink *sink)
+static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink)
{
- struct dc_link *dc_link = &core_link->public;
-
if (dc_link->sink_count >= MAX_SINKS_PER_LINK) {
BREAK_TO_DEBUGGER();
return false;
}
struct dc_sink *dc_link_add_remote_sink(
- const struct dc_link *link,
+ struct dc_link *link,
const uint8_t *edid,
int len,
struct dc_sink_init_data *init_data)
{
struct dc_sink *dc_sink;
enum dc_edid_status edid_status;
- struct core_link *core_link = DC_LINK_TO_LINK(link);
if (len > MAX_EDID_BUFFER_SIZE) {
dm_error("Max EDID buffer size breached!\n");
dc_sink->dc_edid.length = len;
if (!link_add_remote_sink_helper(
- core_link,
+ link,
dc_sink))
goto fail_add_sink;
edid_status = dm_helpers_parse_edid_caps(
- core_link->ctx,
+ link->ctx,
&dc_sink->dc_edid,
&dc_sink->edid_caps);
return NULL;
}
-void dc_link_set_sink(const struct dc_link *link, struct dc_sink *sink)
+void dc_link_set_sink(struct dc_link *link, struct dc_sink *sink)
{
- struct core_link *core_link = DC_LINK_TO_LINK(link);
- struct dc_link *dc_link = &core_link->public;
-
- dc_link->local_sink = sink;
+ link->local_sink = sink;
if (sink == NULL) {
- dc_link->type = dc_connection_none;
+ link->type = dc_connection_none;
} else {
- dc_link->type = dc_connection_single;
+ link->type = dc_connection_single;
}
}
-void dc_link_remove_remote_sink(const struct dc_link *link, const struct dc_sink *sink)
+void dc_link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink)
{
int i;
- struct core_link *core_link = DC_LINK_TO_LINK(link);
- struct dc_link *dc_link = &core_link->public;
if (!link->sink_count) {
BREAK_TO_DEBUGGER();
return;
}
- for (i = 0; i < dc_link->sink_count; i++) {
- if (dc_link->remote_sinks[i] == sink) {
+ for (i = 0; i < link->sink_count; i++) {
+ if (link->remote_sinks[i] == sink) {
dc_sink_release(sink);
- dc_link->remote_sinks[i] = NULL;
+ link->remote_sinks[i] = NULL;
/* shrink array to remove empty place */
- while (i < dc_link->sink_count - 1) {
- dc_link->remote_sinks[i] = dc_link->remote_sinks[i+1];
+ while (i < link->sink_count - 1) {
+ link->remote_sinks[i] = link->remote_sinks[i+1];
i++;
}
-
- dc_link->sink_count--;
+ link->remote_sinks[i] = NULL;
+ link->sink_count--;
return;
}
}
}
+bool dc_init_dchub(struct dc *dc, struct dchub_init_data *dh_data)
+{
+ int i;
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+ struct mem_input *mi = NULL;
+
+ for (i = 0; i < core_dc->res_pool->pipe_count; i++) {
+ if (core_dc->res_pool->mis[i] != NULL) {
+ mi = core_dc->res_pool->mis[i];
+ break;
+ }
+ }
+ if (mi == NULL) {
+ dm_error("no mem_input!\n");
+ return false;
+ }
+
+ if (core_dc->hwss.update_dchub)
+ core_dc->hwss.update_dchub(core_dc->hwseq, dh_data);
+ else
+ ASSERT(core_dc->hwss.update_dchub);
+
+
+ return true;
+
+}
+
+void dc_log_hw_state(struct dc *dc)
+{
+ struct core_dc *core_dc = DC_TO_CORE(dc);
+
+ if (core_dc->hwss.log_hw_state)
+ core_dc->hwss.log_hw_state(core_dc);
+}