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 90a3150..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++;
        }
@@ -278,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,
@@ -297,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)
@@ -327,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,
@@ -347,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)
@@ -423,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);
 
@@ -441,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;
 }
@@ -467,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;
@@ -683,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;
@@ -698,8 +694,7 @@ context_alloc_fail:
                                __func__,
                                result);
 
-               dc_resource_validate_ctx_destruct(context);
-               dm_free(context);
+               dc_release_validate_context(context);
                context = NULL;
        }
 
@@ -720,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);
 
@@ -731,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;
@@ -750,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) {
@@ -913,47 +910,40 @@ bool dc_enable_stereo(
        return ret;
 }
 
-/* TODO operate on validation set (or something like it) */
-bool dc_commit_context(struct dc *dc, struct validate_context *context)
+
+/*
+ * 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};
 
-       if (!context)
-               dm_logger_write(core_dc->ctx->logger, LOG_ERROR,
-                               "%s: dc_commit_context with no context!\n",
-                               __func__);
-
-       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);
-       }
+       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 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++) {
-                       struct core_surface *surface =
-                                       DC_SURFACE_TO_CORE(context->stream_status[i].surfaces[j]);
+                       const struct dc_surface *surface =
+                                       context->stream_status[i].surfaces[j];
 
                        core_dc->hwss.apply_ctx_for_surface(core_dc, surface, context);
 
@@ -981,22 +971,53 @@ bool dc_commit_context(struct dc *dc, struct validate_context *context)
                                context->streams[i]->public.timing.pix_clk_khz);
        }
 
-       dc_resource_validate_ctx_copy_construct(context, core_dc->current_context);
+       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);
-       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;
+       int i;
 
        if (false == streams_changed(core_dc, streams, stream_count))
                return DC_OK;
@@ -1027,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){
@@ -1035,52 +1058,13 @@ 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, "{%ux%u, %ux%u@%u, %ux%u@%uKhz}",
-                               context->streams[i]->public.src.width,
-                               context->streams[i]->public.src.height,
-                               context->streams[i]->public.timing.h_addressable,
-                               context->streams[i]->public.timing.v_addressable,
-                               context->streams[i]->public.timing.pix_clk_khz * 1000 /
-                                       context->streams[i]->public.timing.h_total /
-                                       context->streams[i]->public.timing.v_total, // Refresh rate
-                               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, streams, stream_count);
-       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);
@@ -1110,7 +1094,7 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
 
 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)
 {
@@ -1134,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;
@@ -1173,6 +1159,23 @@ bool dc_commit_surfaces_to_stream(
        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(
                const struct validate_context *context,
                const struct dc_surface *surface)
@@ -1182,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;
                }
        }
@@ -1359,6 +1362,17 @@ 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);
@@ -1414,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);
 
@@ -1435,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;
                }
 
@@ -1490,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);
        }
 
@@ -1528,12 +1544,20 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                }
        }
 
+       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, 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];
@@ -1585,7 +1609,7 @@ void dc_update_surfaces_and_stream(struct dc *dc,
 
        /* 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(
@@ -1603,10 +1627,7 @@ void dc_update_surfaces_and_stream(struct dc *dc,
                        if (update_type == UPDATE_TYPE_FAST)
                                continue;
 
-                       /* TODO find out why check is false */
-                       /* TODO with this still not programming some color stuff... panel is dark-ish */
-                       /*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);
 
@@ -1629,7 +1650,7 @@ void dc_update_surfaces_and_stream(struct dc *dc,
 
                for (j = 0; j < surface_count; j++) {
                        if (update_type != UPDATE_TYPE_FULL &&
-                                       srf_updates[j].surface != &pipe_ctx->surface->public)
+                           srf_updates[j].surface != pipe_ctx->surface)
                                continue;
                        if (!pipe_ctx->surface || pipe_ctx->top_pipe)
                                continue;
@@ -1645,16 +1666,16 @@ void dc_update_surfaces_and_stream(struct dc *dc,
        }
 
        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)
@@ -1671,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(
@@ -1688,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)
@@ -1728,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:
@@ -1741,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;
        }
@@ -1768,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,
@@ -1787,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,
@@ -1809,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,
@@ -1829,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,
@@ -1852,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,
@@ -1872,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,
@@ -1881,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;
@@ -1899,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");
@@ -1932,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);
 
@@ -1952,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;
                }
        }
@@ -2011,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);
+}