drm/amd/disply/dc: add resource support for DCE8 APUs (v2)
authorAlex Deucher <alexdeucher@gmail.com>
Thu, 10 Aug 2017 18:39:51 +0000 (14:39 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 26 Sep 2017 22:16:33 +0000 (18:16 -0400)
Add the appropriate resources for APUs:
KV:    4 pipes, 7 dig, 3 PPLLs
KB/ML: 2 pipes, 6 dig, 2 PPLLs

v2: rebase changes

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h

index ee7a393b2b001f7db6eb8cdd34a811d76da4b65e..56a85c80131d8cf4d1cb65e6acca0e8d07d8f23f 100644 (file)
@@ -101,9 +101,15 @@ struct resource_pool *dc_create_resource_pool(
 
        switch (dc_version) {
        case DCE_VERSION_8_0:
+               res_pool = dce80_create_resource_pool(
+                       num_virtual_links, dc);
+               break;
        case DCE_VERSION_8_1:
+               res_pool = dce81_create_resource_pool(
+                       num_virtual_links, dc);
+               break;
        case DCE_VERSION_8_3:
-               res_pool = dce80_create_resource_pool(
+               res_pool = dce83_create_resource_pool(
                        num_virtual_links, dc);
                break;
        case DCE_VERSION_10_0:
index 40a9591833aaed3211ddd47b99ce0281fbaa626c..132117e8bb778a66d72575593f0e72b937082c98 100644 (file)
@@ -350,6 +350,20 @@ static const struct resource_caps res_cap = {
                .num_pll = 3,
 };
 
+static const struct resource_caps res_cap_81 = {
+               .num_timing_generator = 4,
+               .num_audio = 7,
+               .num_stream_encoder = 7,
+               .num_pll = 3,
+};
+
+static const struct resource_caps res_cap_83 = {
+               .num_timing_generator = 2,
+               .num_audio = 6,
+               .num_stream_encoder = 6,
+               .num_pll = 2,
+};
+
 #define CTX  ctx
 #define REG(reg) mm ## reg
 
@@ -829,7 +843,7 @@ static const struct resource_funcs dce80_res_pool_funcs = {
        .validate_plane = dce100_validate_plane
 };
 
-static bool construct(
+static bool dce80_construct(
        uint8_t num_virtual_links,
        struct core_dc *dc,
        struct dce110_resource_pool *pool)
@@ -987,10 +1001,335 @@ struct resource_pool *dce80_create_resource_pool(
        if (!pool)
                return NULL;
 
-       if (construct(num_virtual_links, dc, pool))
+       if (dce80_construct(num_virtual_links, dc, pool))
                return &pool->base;
 
        BREAK_TO_DEBUGGER();
        return NULL;
 }
 
+static bool dce81_construct(
+       uint8_t num_virtual_links,
+       struct core_dc *dc,
+       struct dce110_resource_pool *pool)
+{
+       unsigned int i;
+       struct dc_context *ctx = dc->ctx;
+       struct dc_firmware_info info;
+       struct dc_bios *bp;
+       struct dm_pp_static_clock_info static_clk_info = {0};
+
+       ctx->dc_bios->regs = &bios_regs;
+
+       pool->base.res_cap = &res_cap_81;
+       pool->base.funcs = &dce80_res_pool_funcs;
+
+
+       /*************************************************
+        *  Resource + asic cap harcoding                *
+        *************************************************/
+       pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;
+       pool->base.pipe_count = res_cap_81.num_timing_generator;
+       dc->public.caps.max_downscale_ratio = 200;
+       dc->public.caps.i2c_speed_in_khz = 40;
+       dc->public.caps.max_cursor_size = 128;
+
+       /*************************************************
+        *  Create resources                             *
+        *************************************************/
+
+       bp = ctx->dc_bios;
+
+       if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) &&
+               info.external_clock_source_frequency_for_dp != 0) {
+               pool->base.dp_clock_source =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true);
+
+               pool->base.clock_sources[0] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false);
+               pool->base.clock_sources[1] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false);
+               pool->base.clock_sources[2] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false);
+               pool->base.clk_src_count = 3;
+
+       } else {
+               pool->base.dp_clock_source =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true);
+
+               pool->base.clock_sources[0] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false);
+               pool->base.clock_sources[1] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false);
+               pool->base.clk_src_count = 2;
+       }
+
+       if (pool->base.dp_clock_source == NULL) {
+               dm_error("DC: failed to create dp clock source!\n");
+               BREAK_TO_DEBUGGER();
+               goto res_create_fail;
+       }
+
+       for (i = 0; i < pool->base.clk_src_count; i++) {
+               if (pool->base.clock_sources[i] == NULL) {
+                       dm_error("DC: failed to create clock sources!\n");
+                       BREAK_TO_DEBUGGER();
+                       goto res_create_fail;
+               }
+       }
+
+       pool->base.display_clock = dce_disp_clk_create(ctx,
+                       &disp_clk_regs,
+                       &disp_clk_shift,
+                       &disp_clk_mask);
+       if (pool->base.display_clock == NULL) {
+               dm_error("DC: failed to create display clock!\n");
+               BREAK_TO_DEBUGGER();
+               goto res_create_fail;
+       }
+
+
+       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
+               pool->base.display_clock->max_clks_state =
+                                       static_clk_info.max_clocks_state;
+
+       {
+               struct irq_service_init_data init_data;
+               init_data.ctx = dc->ctx;
+               pool->base.irqs = dal_irq_service_dce80_create(&init_data);
+               if (!pool->base.irqs)
+                       goto res_create_fail;
+       }
+
+       for (i = 0; i < pool->base.pipe_count; i++) {
+               pool->base.timing_generators[i] = dce80_timing_generator_create(
+                               ctx, i, &dce80_tg_offsets[i]);
+               if (pool->base.timing_generators[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create tg!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.mis[i] = dce80_mem_input_create(ctx, i);
+               if (pool->base.mis[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create memory input!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.ipps[i] = dce80_ipp_create(ctx, i);
+               if (pool->base.ipps[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create input pixel processor!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.transforms[i] = dce80_transform_create(ctx, i);
+               if (pool->base.transforms[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create transform!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.opps[i] = dce80_opp_create(ctx, i);
+               if (pool->base.opps[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create output pixel processor!\n");
+                       goto res_create_fail;
+               }
+       }
+
+       dc->public.caps.max_planes =  pool->base.pipe_count;
+
+       if (!resource_construct(num_virtual_links, dc, &pool->base,
+                       &res_create_funcs))
+               goto res_create_fail;
+
+       /* Create hardware sequencer */
+       if (!dce80_hw_sequencer_construct(dc))
+               goto res_create_fail;
+
+       return true;
+
+res_create_fail:
+       destruct(pool);
+       return false;
+}
+
+struct resource_pool *dce81_create_resource_pool(
+       uint8_t num_virtual_links,
+       struct core_dc *dc)
+{
+       struct dce110_resource_pool *pool =
+               dm_alloc(sizeof(struct dce110_resource_pool));
+
+       if (!pool)
+               return NULL;
+
+       if (dce81_construct(num_virtual_links, dc, pool))
+               return &pool->base;
+
+       BREAK_TO_DEBUGGER();
+       return NULL;
+}
+
+static bool dce83_construct(
+       uint8_t num_virtual_links,
+       struct core_dc *dc,
+       struct dce110_resource_pool *pool)
+{
+       unsigned int i;
+       struct dc_context *ctx = dc->ctx;
+       struct dc_firmware_info info;
+       struct dc_bios *bp;
+       struct dm_pp_static_clock_info static_clk_info = {0};
+
+       ctx->dc_bios->regs = &bios_regs;
+
+       pool->base.res_cap = &res_cap_83;
+       pool->base.funcs = &dce80_res_pool_funcs;
+
+
+       /*************************************************
+        *  Resource + asic cap harcoding                *
+        *************************************************/
+       pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;
+       pool->base.pipe_count = res_cap_83.num_timing_generator;
+       dc->public.caps.max_downscale_ratio = 200;
+       dc->public.caps.i2c_speed_in_khz = 40;
+       dc->public.caps.max_cursor_size = 128;
+
+       /*************************************************
+        *  Create resources                             *
+        *************************************************/
+
+       bp = ctx->dc_bios;
+
+       if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) &&
+               info.external_clock_source_frequency_for_dp != 0) {
+               pool->base.dp_clock_source =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true);
+
+               pool->base.clock_sources[0] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], false);
+               pool->base.clock_sources[1] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false);
+               pool->base.clk_src_count = 2;
+
+       } else {
+               pool->base.dp_clock_source =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], true);
+
+               pool->base.clock_sources[0] =
+                               dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false);
+               pool->base.clk_src_count = 1;
+       }
+
+       if (pool->base.dp_clock_source == NULL) {
+               dm_error("DC: failed to create dp clock source!\n");
+               BREAK_TO_DEBUGGER();
+               goto res_create_fail;
+       }
+
+       for (i = 0; i < pool->base.clk_src_count; i++) {
+               if (pool->base.clock_sources[i] == NULL) {
+                       dm_error("DC: failed to create clock sources!\n");
+                       BREAK_TO_DEBUGGER();
+                       goto res_create_fail;
+               }
+       }
+
+       pool->base.display_clock = dce_disp_clk_create(ctx,
+                       &disp_clk_regs,
+                       &disp_clk_shift,
+                       &disp_clk_mask);
+       if (pool->base.display_clock == NULL) {
+               dm_error("DC: failed to create display clock!\n");
+               BREAK_TO_DEBUGGER();
+               goto res_create_fail;
+       }
+
+
+       if (dm_pp_get_static_clocks(ctx, &static_clk_info))
+               pool->base.display_clock->max_clks_state =
+                                       static_clk_info.max_clocks_state;
+
+       {
+               struct irq_service_init_data init_data;
+               init_data.ctx = dc->ctx;
+               pool->base.irqs = dal_irq_service_dce80_create(&init_data);
+               if (!pool->base.irqs)
+                       goto res_create_fail;
+       }
+
+       for (i = 0; i < pool->base.pipe_count; i++) {
+               pool->base.timing_generators[i] = dce80_timing_generator_create(
+                               ctx, i, &dce80_tg_offsets[i]);
+               if (pool->base.timing_generators[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create tg!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.mis[i] = dce80_mem_input_create(ctx, i);
+               if (pool->base.mis[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create memory input!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.ipps[i] = dce80_ipp_create(ctx, i);
+               if (pool->base.ipps[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create input pixel processor!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.transforms[i] = dce80_transform_create(ctx, i);
+               if (pool->base.transforms[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create transform!\n");
+                       goto res_create_fail;
+               }
+
+               pool->base.opps[i] = dce80_opp_create(ctx, i);
+               if (pool->base.opps[i] == NULL) {
+                       BREAK_TO_DEBUGGER();
+                       dm_error("DC: failed to create output pixel processor!\n");
+                       goto res_create_fail;
+               }
+       }
+
+       dc->public.caps.max_planes =  pool->base.pipe_count;
+
+       if (!resource_construct(num_virtual_links, dc, &pool->base,
+                       &res_create_funcs))
+               goto res_create_fail;
+
+       /* Create hardware sequencer */
+       if (!dce80_hw_sequencer_construct(dc))
+               goto res_create_fail;
+
+       return true;
+
+res_create_fail:
+       destruct(pool);
+       return false;
+}
+
+struct resource_pool *dce83_create_resource_pool(
+       uint8_t num_virtual_links,
+       struct core_dc *dc)
+{
+       struct dce110_resource_pool *pool =
+               dm_alloc(sizeof(struct dce110_resource_pool));
+
+       if (!pool)
+               return NULL;
+
+       if (dce83_construct(num_virtual_links, dc, pool))
+               return &pool->base;
+
+       BREAK_TO_DEBUGGER();
+       return NULL;
+}
index 2a0cdccddeaf41827634be0c27dd0b6e04a313b5..04f0cfe24ef280447b87ae72fcfd979a9b7d0310 100644 (file)
@@ -35,5 +35,13 @@ struct resource_pool *dce80_create_resource_pool(
        uint8_t num_virtual_links,
        struct core_dc *dc);
 
+struct resource_pool *dce81_create_resource_pool(
+       uint8_t num_virtual_links,
+       struct core_dc *dc);
+
+struct resource_pool *dce83_create_resource_pool(
+       uint8_t num_virtual_links,
+       struct core_dc *dc);
+
 #endif /* __DC_RESOURCE_DCE80_H__ */