drm/amd/display: break up plane disable and disconnect in set mode
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / dc / core / dc.c
index 47870a6..7921880 100644 (file)
@@ -94,7 +94,7 @@ static bool create_links(
 
        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 */
@@ -111,7 +111,7 @@ static bool create_links(
        }
 
        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) {
@@ -121,7 +121,7 @@ static bool create_links(
 
                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;
@@ -137,7 +137,7 @@ static bool create_links(
                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++;
        }
@@ -221,6 +221,29 @@ static bool set_gamut_remap(struct dc *dc, const struct dc_stream *stream)
        return ret;
 }
 
+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;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               if (core_dc->current_context->res_ctx.pipe_ctx[i].stream
+                               == core_stream) {
+
+                       pipes = &core_dc->current_context->res_ctx.pipe_ctx[i];
+                       core_dc->hwss.program_csc_matrix(pipes,
+                       core_stream->public.output_color_space,
+                       core_stream->public.csc_color_matrix.matrix);
+                       ret = true;
+               }
+       }
+
+       return ret;
+}
+
 static void set_static_screen_events(struct dc *dc,
                const struct dc_stream **stream,
                int num_streams,
@@ -255,14 +278,14 @@ 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,
@@ -274,22 +297,17 @@ 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)
@@ -304,7 +322,7 @@ static void disable_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,
@@ -324,9 +342,8 @@ void set_dither_option(const struct dc_stream *dc_stream,
 {
        struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream);
        struct bit_depth_reduction_params params;
-       struct core_link *core_link = DC_LINK_TO_CORE(stream->status.link);
-       struct pipe_ctx *pipes =
-                       core_link->dc->current_context->res_ctx.pipe_ctx;
+       struct dc_link *link = stream->status.link;
+       struct pipe_ctx *pipes = link->dc->current_context->res_ctx.pipe_ctx;
 
        memset(&params, 0, sizeof(params));
        if (!stream)
@@ -373,6 +390,9 @@ static void allocate_dc_stream_funcs(struct core_dc *core_dc)
        core_dc->public.stream_funcs.set_gamut_remap =
                        set_gamut_remap;
 
+       core_dc->public.stream_funcs.program_csc_matrix =
+                       program_csc_matrix;
+
        core_dc->public.stream_funcs.set_dither_option =
                        set_dither_option;
 
@@ -397,7 +417,8 @@ static void allocate_dc_stream_funcs(struct core_dc *core_dc)
 
 static void destruct(struct core_dc *dc)
 {
-       dc_resource_validate_ctx_destruct(dc->current_context);
+       dc_release_validate_context(dc->current_context);
+       dc->current_context = NULL;
 
        destroy_links(dc);
 
@@ -415,9 +436,6 @@ static void destruct(struct core_dc *dc)
        if (dc->ctx->logger)
                dal_logger_destroy(&dc->ctx->logger);
 
-       dm_free(dc->current_context);
-       dc->current_context = NULL;
-
        dm_free(dc->ctx);
        dc->ctx = NULL;
 }
@@ -441,6 +459,8 @@ static bool construct(struct core_dc *dc,
                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;
@@ -628,7 +648,8 @@ static bool is_validation_required(
                        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;
@@ -656,6 +677,8 @@ struct validate_context *dc_get_validate_context(
        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;
@@ -671,8 +694,7 @@ context_alloc_fail:
                                __func__,
                                result);
 
-               dc_resource_validate_ctx_destruct(context);
-               dm_free(context);
+               dc_release_validate_context(context);
                context = NULL;
        }
 
@@ -693,6 +715,8 @@ bool dc_validate_resources(
        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);
 
@@ -704,8 +728,7 @@ context_alloc_fail:
                                result);
        }
 
-       dc_resource_validate_ctx_destruct(context);
-       dm_free(context);
+       dc_release_validate_context(context);
        context = NULL;
 
        return result == DC_OK;
@@ -723,11 +746,12 @@ 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);
 
-       dc_resource_validate_ctx_destruct(context);
-       dm_free(context);
+       dc_release_validate_context(context);
 
 context_alloc_fail:
        if (result != DC_OK) {
@@ -814,6 +838,23 @@ static void program_timing_sync(
        }
 }
 
+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[],
@@ -832,17 +873,151 @@ static bool streams_changed(
        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);
+
+#ifdef ENABLE_FBC
+       struct compressor *fbc_compressor = core_dc->fbc_compressor;
+#endif
+
+       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);
+               }
+       }
+
+#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);
+
+#endif
+       return ret;
+}
+
+
+/*
+ * 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};
+
+       for (i = 0; i < context->stream_count; i++)
+               dc_streams[i] =  &context->streams[i]->public;
+
+       if (!dcb->funcs->is_accelerated_mode(dcb))
+               core_dc->hwss.enable_accelerated_mode(core_dc);
+
+       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 dc_sink *sink = context->streams[i]->sink;
+
+               for (j = 0; j < context->stream_status[i].surface_count; j++) {
+                       const struct dc_surface *surface =
+                                       context->stream_status[i].surfaces[j];
+
+                       core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context);
+
+                       /*
+                        * 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];
+
+                               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);
+                               }
+                       }
+               }
+
+               CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
+                               context->streams[i]->public.timing.h_addressable,
+                               context->streams[i]->public.timing.v_addressable,
+                               context->streams[i]->public.timing.h_total,
+                               context->streams[i]->public.timing.v_total,
+                               context->streams[i]->public.timing.pix_clk_khz);
+       }
+
+       dc_enable_stereo(dc, context, dc_streams, context->stream_count);
+
+       dc_release_validate_context(core_dc->current_context);
+
+       core_dc->current_context = context;
+
+       dc_retain_validate_context(core_dc->current_context);
+
+       return (result == DC_OK);
+}
+
+bool dc_commit_context(struct dc *dc, struct validate_context *context)
+{
+       enum dc_status result = DC_ERROR_UNEXPECTED;
+       struct core_dc *core_dc = DC_TO_CORE(dc);
+       int i;
+
+       if (false == context_changed(core_dc, context))
+               return DC_OK;
+
+       dm_logger_write(core_dc->ctx->logger, LOG_DC, "%s: %d streams\n",
+                               __func__, context->stream_count);
+
+       for (i = 0; i < context->stream_count; i++) {
+               const struct dc_stream *stream = &context->streams[i]->public;
+
+               dc_stream_log(stream,
+                               core_dc->ctx->logger,
+                               LOG_DC);
+       }
+
+       result = dc_commit_context_no_check(dc, context);
+
+       return (result == DC_OK);
+}
+
+
+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, j;
+       int i;
 
        if (false == streams_changed(core_dc, streams, stream_count))
                return DC_OK;
@@ -873,6 +1048,8 @@ bool dc_commit_streams(
        if (context == NULL)
                goto context_alloc_fail;
 
+       ++context->ref_count;
+
        result = core_dc->res_pool->funcs->validate_with_context(
                        core_dc, set, stream_count, context, core_dc->current_context);
        if (result != DC_OK){
@@ -881,61 +1058,18 @@ bool dc_commit_streams(
                                        __func__,
                                        result);
                BREAK_TO_DEBUGGER();
-               dc_resource_validate_ctx_destruct(context);
                goto fail;
        }
 
-       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);
-       }
-
-       program_timing_sync(core_dc, context);
-
-       for (i = 0; i < context->stream_count; i++) {
-               const struct core_sink *sink = context->streams[i]->sink;
-
-               for (j = 0; j < context->stream_status[i].surface_count; j++) {
-                       struct core_surface *surface =
-                                       DC_SURFACE_TO_CORE(context->stream_status[i].surfaces[j]);
-
-                       core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context);
-               }
-
-               CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
-                               context->streams[i]->public.timing.h_addressable,
-                               context->streams[i]->public.timing.v_addressable,
-                               context->streams[i]->public.timing.h_total,
-                               context->streams[i]->public.timing.v_total,
-                               context->streams[i]->public.timing.pix_clk_khz);
-       }
-
-       dc_resource_validate_ctx_destruct(core_dc->current_context);
-       dm_free(core_dc->current_context);
-
-       core_dc->current_context = context;
-
-       return (result == DC_OK);
+       result = dc_commit_context_no_check(dc, context);
 
 fail:
-       dm_free(context);
+       dc_release_validate_context(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)
-{
-       return true;
-}
-
 bool dc_post_update_surfaces_to_stream(struct dc *dc)
 {
        int i;
@@ -945,20 +1079,22 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
        post_surface_trace(dc);
 
        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].pipe_idx = i;
-                       core_dc->hwss.power_down_front_end(
-                                       core_dc, &context->res_ctx.pipe_ctx[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);
-
+#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)
 {
@@ -967,7 +1103,6 @@ bool dc_commit_surfaces_to_stream(
        struct dc_plane_info plane_info[MAX_SURFACES];
        struct dc_scaling_info scaling_info[MAX_SURFACES];
        int i;
-       bool ret;
        struct dc_stream_update *stream_update =
                        dm_alloc(sizeof(struct dc_stream_update));
 
@@ -983,11 +1118,13 @@ bool dc_commit_surfaces_to_stream(
 
        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;
@@ -1016,10 +1153,27 @@ bool dc_commit_surfaces_to_stream(
                        new_surface_count,
                        dc_stream, stream_update);
 
-       ret = dc_post_update_surfaces_to_stream(dc);
+       dc_post_update_surfaces_to_stream(dc);
 
        dm_free(stream_update);
-       return ret;
+       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(
@@ -1031,7 +1185,7 @@ static bool is_surface_in_context(
        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;
                }
        }
@@ -1069,11 +1223,14 @@ static enum surface_update_type get_plane_info_update_type(
                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.
@@ -1090,10 +1247,6 @@ static enum surface_update_type get_plane_info_update_type(
        temp_plane_info.stereo_format = u->surface->stereo_format;
        temp_plane_info.tiling_info = u->surface->tiling_info;
 
-       /* Special Validation parameters */
-       temp_plane_info.format = u->plane_info->format;
-       temp_plane_info.per_pixel_alpha = u->plane_info->per_pixel_alpha;
-
        if (surface_index == 0)
                temp_plane_info.visible = u->plane_info->visible;
        else
@@ -1196,14 +1349,6 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
        return overall_type;
 }
 
-void dc_update_surfaces_for_stream(struct dc *dc,
-               struct dc_surface_update *surface_updates, int surface_count,
-               const struct dc_stream *dc_stream)
-{
-       dc_update_surfaces_and_stream(dc, surface_updates, surface_count,
-                       dc_stream, NULL);
-}
-
 enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
 
 void dc_update_surfaces_and_stream(struct dc *dc,
@@ -1217,12 +1362,29 @@ void dc_update_surfaces_and_stream(struct dc *dc,
        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 */
@@ -1237,17 +1399,12 @@ void dc_update_surfaces_and_stream(struct dc *dc,
 
                if (stream_update->out_transfer_func &&
                                stream_update->out_transfer_func !=
-                               dc_stream->out_transfer_func) {
-                       if (stream_update->out_transfer_func->type !=
-                                       TF_TYPE_UNKNOWN) {
-                               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;
-                       }
+                                               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;
                }
        }
 
@@ -1271,13 +1428,18 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                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] = srf_updates[i].surface;
 
                /* initialize scratch memory for building context */
                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);
 
@@ -1292,46 +1454,45 @@ void dc_update_surfaces_and_stream(struct dc *dc,
 
        /* save update parameters into surface */
        for (i = 0; i < surface_count; i++) {
-               struct core_surface *surface =
-                               DC_SURFACE_TO_CORE(srf_updates[i].surface);
+               struct dc_surface *surface = srf_updates[i].surface;
 
                if (srf_updates[i].flip_addr) {
-                       surface->public.address = srf_updates[i].flip_addr->address;
-                       surface->public.flip_immediate =
+                       surface->address = srf_updates[i].flip_addr->address;
+                       surface->flip_immediate =
                                        srf_updates[i].flip_addr->flip_immediate;
                }
 
                if (srf_updates[i].scaling_info) {
-                       surface->public.scaling_quality =
+                       surface->scaling_quality =
                                        srf_updates[i].scaling_info->scaling_quality;
-                       surface->public.dst_rect =
+                       surface->dst_rect =
                                        srf_updates[i].scaling_info->dst_rect;
-                       surface->public.src_rect =
+                       surface->src_rect =
                                        srf_updates[i].scaling_info->src_rect;
-                       surface->public.clip_rect =
+                       surface->clip_rect =
                                        srf_updates[i].scaling_info->clip_rect;
                }
 
                if (srf_updates[i].plane_info) {
-                       surface->public.color_space =
+                       surface->color_space =
                                        srf_updates[i].plane_info->color_space;
-                       surface->public.format =
+                       surface->format =
                                        srf_updates[i].plane_info->format;
-                       surface->public.plane_size =
+                       surface->plane_size =
                                        srf_updates[i].plane_info->plane_size;
-                       surface->public.rotation =
+                       surface->rotation =
                                        srf_updates[i].plane_info->rotation;
-                       surface->public.horizontal_mirror =
+                       surface->horizontal_mirror =
                                        srf_updates[i].plane_info->horizontal_mirror;
-                       surface->public.stereo_format =
+                       surface->stereo_format =
                                        srf_updates[i].plane_info->stereo_format;
-                       surface->public.tiling_info =
+                       surface->tiling_info =
                                        srf_updates[i].plane_info->tiling_info;
-                       surface->public.visible =
+                       surface->visible =
                                        srf_updates[i].plane_info->visible;
-                       surface->public.per_pixel_alpha =
+                       surface->per_pixel_alpha =
                                        srf_updates[i].plane_info->per_pixel_alpha;
-                       surface->public.dcc =
+                       surface->dcc =
                                        srf_updates[i].plane_info->dcc;
                }
 
@@ -1347,31 +1508,29 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                }
 
                if (srf_updates[i].gamma &&
-                       srf_updates[i].gamma != surface->public.gamma_correction) {
-                       if (surface->public.gamma_correction != NULL)
-                               dc_gamma_release(&surface->public.
-                                               gamma_correction);
+                       srf_updates[i].gamma != surface->gamma_correction) {
+                       if (surface->gamma_correction != NULL)
+                               dc_gamma_release(&surface->gamma_correction);
 
                        dc_gamma_retain(srf_updates[i].gamma);
-                       surface->public.gamma_correction =
-                                               srf_updates[i].gamma;
+                       surface->gamma_correction = srf_updates[i].gamma;
                }
 
                if (srf_updates[i].in_transfer_func &&
-                       srf_updates[i].in_transfer_func != surface->public.in_transfer_func) {
-                       if (surface->public.in_transfer_func != NULL)
+                       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(
                                        srf_updates[i].in_transfer_func);
-                       surface->public.in_transfer_func =
+                       surface->in_transfer_func =
                                        srf_updates[i].in_transfer_func;
                }
 
                if (srf_updates[i].hdr_static_metadata)
-                       surface->public.hdr_static_ctx =
+                       surface->hdr_static_ctx =
                                *(srf_updates[i].hdr_static_metadata);
        }
 
@@ -1385,18 +1544,29 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                }
        }
 
-       if (!surface_count)  /* reset */
+       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 == 0)
                core_dc->hwss.apply_ctx_for_surface(core_dc, NULL, context);
 
-       /* Lock pipes for provided surfaces */
+       /* 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(srf_updates[i].surface);
+               struct dc_surface *surface = srf_updates[i].surface;
 
                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)
+                       if (update_type != UPDATE_TYPE_FULL && pipe_ctx->surface != 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,
@@ -1404,22 +1574,49 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                                                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);
+
+               /* 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 core_surface *surface = DC_SURFACE_TO_CORE(srf_updates[i].surface);
+               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);
-                               context_timing_trace(dc, &context->res_ctx);
-               }
+               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];
-                       struct pipe_ctx *cur_pipe_ctx;
-                       bool is_new_pipe_surface = true;
 
                        if (pipe_ctx->surface != surface)
                                continue;
@@ -1430,19 +1627,12 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                        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 ||
-                                       srf_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 ||
-                               (stream_update != NULL &&
-                                       stream_update->out_transfer_func !=
-                                                       NULL)) {
+                       if (stream_update != NULL &&
+                                       stream_update->out_transfer_func != NULL) {
                                core_dc->hwss.set_output_transfer_func(
                                                pipe_ctx, pipe_ctx->stream);
                        }
@@ -1459,29 +1649,33 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
 
                for (j = 0; j < surface_count; j++) {
-                       if (srf_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) {
-               dc_resource_validate_ctx_destruct(core_dc->current_context);
-               dm_free(core_dc->current_context);
-
+               dc_release_validate_context(core_dc->current_context);
                core_dc->current_context = context;
        }
        return;
 
 fail:
-       dc_resource_validate_ctx_destruct(context);
-       dm_free(context);
+       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)
@@ -1498,10 +1692,10 @@ struct dc_stream *dc_get_stream_at_index(const struct dc *dc, uint8_t i)
        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(
@@ -1515,7 +1709,7 @@ 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)
@@ -1555,6 +1749,7 @@ void dc_set_power_state(
        enum dc_acpi_cm_power_state power_state)
 {
        struct core_dc *core_dc = DC_TO_CORE(dc);
+       int ref_count;
 
        switch (power_state) {
        case DC_ACPI_CM_POWER_STATE_D0:
@@ -1568,8 +1763,13 @@ void dc_set_power_state(
                 * 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->ref_count = ref_count;
 
                break;
        }
@@ -1595,9 +1795,9 @@ bool dc_read_aux_dpcd(
 {
        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->public.ddc,
+                       link->ddc,
                        false,
                        I2C_MOT_UNDEF,
                        address,
@@ -1614,10 +1814,10 @@ bool dc_write_aux_dpcd(
                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->public.ddc,
+                       link->ddc,
                        false,
                        I2C_MOT_UNDEF,
                        address,
@@ -1636,9 +1836,9 @@ bool dc_read_aux_i2c(
 {
        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->public.ddc,
+                       link->ddc,
                        true,
                        mot,
                        address,
@@ -1656,10 +1856,10 @@ bool dc_write_aux_i2c(
                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->public.ddc,
+                       link->ddc,
                        true,
                        mot,
                        address,
@@ -1679,10 +1879,10 @@ bool dc_query_ddc_data(
 
        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];
 
        bool result = dal_ddc_service_query_ddc_data(
-                       link->public.ddc,
+                       link->ddc,
                        address,
                        write_buf,
                        write_size,
@@ -1699,8 +1899,8 @@ bool dc_submit_i2c(
 {
        struct core_dc *core_dc = DC_TO_CORE(dc);
 
-       struct core_link *link = core_dc->links[link_index];
-       struct ddc_service *ddc = link->public.ddc;
+       struct dc_link *link = core_dc->links[link_index];
+       struct ddc_service *ddc = link->ddc;
 
        return dal_i2caux_submit_i2c_command(
                ddc->ctx->i2caux,
@@ -1708,10 +1908,8 @@ bool dc_submit_i2c(
                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;
@@ -1726,14 +1924,13 @@ static bool link_add_remote_sink_helper(struct core_link *core_link, struct dc_s
 }
 
 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");
@@ -1759,12 +1956,12 @@ struct dc_sink *dc_link_add_remote_sink(
        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);
 
@@ -1779,43 +1976,38 @@ fail_add_sink:
        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->remote_sinks[i] = NULL;
-                       dc_link->sink_count--;
+                       link->remote_sinks[i] = NULL;
+                       link->sink_count--;
                        return;
                }
        }
@@ -1838,13 +2030,20 @@ bool dc_init_dchub(struct dc *dc, struct dchub_init_data *dh_data)
                return false;
        }
 
-       if (mi->funcs->mem_input_update_dchub)
-               mi->funcs->mem_input_update_dchub(mi, dh_data);
+       if (core_dc->hwss.update_dchub)
+               core_dc->hwss.update_dchub(core_dc->hwseq, dh_data);
        else
-               ASSERT(mi->funcs->mem_input_update_dchub);
+               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);
+}