root/drivers/gpu/drm/amd/display/dc/clk_mgr/dce112/dce112_clk_mgr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dce112_set_clock
  2. dce112_set_dispclk
  3. dce112_set_dprefclk
  4. dce112_update_clocks
  5. dce112_clk_mgr_construct

   1 /*
   2  * Copyright 2012-16 Advanced Micro Devices, Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  * Authors: AMD
  23  *
  24  */
  25 
  26 #include "core_types.h"
  27 #include "clk_mgr_internal.h"
  28 
  29 #include "dce/dce_11_2_d.h"
  30 #include "dce/dce_11_2_sh_mask.h"
  31 #include "dce100/dce_clk_mgr.h"
  32 #include "dce110/dce110_clk_mgr.h"
  33 #include "dce112_clk_mgr.h"
  34 #include "dal_asic_id.h"
  35 
  36 /* set register offset */
  37 #define SR(reg_name)\
  38         .reg_name = mm ## reg_name
  39 
  40 /* set register offset with instance */
  41 #define SRI(reg_name, block, id)\
  42         .reg_name = mm ## block ## id ## _ ## reg_name
  43 
  44 static const struct clk_mgr_registers disp_clk_regs = {
  45                 CLK_COMMON_REG_LIST_DCE_BASE()
  46 };
  47 
  48 static const struct clk_mgr_shift disp_clk_shift = {
  49                 CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
  50 };
  51 
  52 static const struct clk_mgr_mask disp_clk_mask = {
  53                 CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
  54 };
  55 
  56 static const struct state_dependent_clocks dce112_max_clks_by_state[] = {
  57 /*ClocksStateInvalid - should not be used*/
  58 { .display_clk_khz = 0, .pixel_clk_khz = 0 },
  59 /*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
  60 { .display_clk_khz = 389189, .pixel_clk_khz = 346672 },
  61 /*ClocksStateLow*/
  62 { .display_clk_khz = 459000, .pixel_clk_khz = 400000 },
  63 /*ClocksStateNominal*/
  64 { .display_clk_khz = 667000, .pixel_clk_khz = 600000 },
  65 /*ClocksStatePerformance*/
  66 { .display_clk_khz = 1132000, .pixel_clk_khz = 600000 } };
  67 
  68 
  69 //TODO: remove use the two broken down functions
  70 int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz)
  71 {
  72         struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
  73         struct bp_set_dce_clock_parameters dce_clk_params;
  74         struct dc_bios *bp = clk_mgr_base->ctx->dc_bios;
  75         struct dc *core_dc = clk_mgr_base->ctx->dc;
  76         struct dmcu *dmcu = core_dc->res_pool->dmcu;
  77         int actual_clock = requested_clk_khz;
  78         /* Prepare to program display clock*/
  79         memset(&dce_clk_params, 0, sizeof(dce_clk_params));
  80 
  81         /* Make sure requested clock isn't lower than minimum threshold*/
  82         if (requested_clk_khz > 0)
  83                 requested_clk_khz = max(requested_clk_khz,
  84                                 clk_mgr_dce->dentist_vco_freq_khz / 62);
  85 
  86         dce_clk_params.target_clock_frequency = requested_clk_khz;
  87         dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
  88         dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
  89 
  90         bp->funcs->set_dce_clock(bp, &dce_clk_params);
  91         actual_clock = dce_clk_params.target_clock_frequency;
  92 
  93         /*
  94          * from power down, we need mark the clock state as ClocksStateNominal
  95          * from HWReset, so when resume we will call pplib voltage regulator.
  96          */
  97         if (requested_clk_khz == 0)
  98                 clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
  99 
 100         /*Program DP ref Clock*/
 101         /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
 102         dce_clk_params.target_clock_frequency = 0;
 103         dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
 104         if (!ASICREV_IS_VEGA20_P(clk_mgr_base->ctx->asic_id.hw_internal_rev))
 105                 dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
 106                         (dce_clk_params.pll_id ==
 107                                         CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
 108         else
 109                 dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
 110 
 111         bp->funcs->set_dce_clock(bp, &dce_clk_params);
 112 
 113         if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
 114                 if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
 115                         if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock)
 116                                 dmcu->funcs->set_psr_wait_loop(dmcu,
 117                                                 actual_clock / 1000 / 7);
 118                 }
 119         }
 120 
 121         clk_mgr_dce->dfs_bypass_disp_clk = actual_clock;
 122         return actual_clock;
 123 }
 124 
 125 int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz)
 126 {
 127         struct bp_set_dce_clock_parameters dce_clk_params;
 128         struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
 129         struct dc *core_dc = clk_mgr->base.ctx->dc;
 130         struct dmcu *dmcu = core_dc->res_pool->dmcu;
 131         int actual_clock = requested_clk_khz;
 132         /* Prepare to program display clock*/
 133         memset(&dce_clk_params, 0, sizeof(dce_clk_params));
 134 
 135         /* Make sure requested clock isn't lower than minimum threshold*/
 136         if (requested_clk_khz > 0)
 137                 requested_clk_khz = max(requested_clk_khz,
 138                                 clk_mgr->dentist_vco_freq_khz / 62);
 139 
 140         dce_clk_params.target_clock_frequency = requested_clk_khz;
 141         dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
 142         dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
 143 
 144         bp->funcs->set_dce_clock(bp, &dce_clk_params);
 145         actual_clock = dce_clk_params.target_clock_frequency;
 146 
 147         /*
 148          * from power down, we need mark the clock state as ClocksStateNominal
 149          * from HWReset, so when resume we will call pplib voltage regulator.
 150          */
 151         if (requested_clk_khz == 0)
 152                 clk_mgr->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
 153 
 154 
 155         if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
 156                 if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
 157                         if (clk_mgr->dfs_bypass_disp_clk != actual_clock)
 158                                 dmcu->funcs->set_psr_wait_loop(dmcu,
 159                                                 actual_clock / 1000 / 7);
 160                 }
 161         }
 162 
 163         clk_mgr->dfs_bypass_disp_clk = actual_clock;
 164         return actual_clock;
 165 
 166 }
 167 
 168 int dce112_set_dprefclk(struct clk_mgr_internal *clk_mgr)
 169 {
 170         struct bp_set_dce_clock_parameters dce_clk_params;
 171         struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
 172 
 173         memset(&dce_clk_params, 0, sizeof(dce_clk_params));
 174 
 175         /*Program DP ref Clock*/
 176         /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
 177         dce_clk_params.target_clock_frequency = 0;
 178         dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
 179         dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
 180         if (!ASICREV_IS_VEGA20_P(clk_mgr->base.ctx->asic_id.hw_internal_rev))
 181                 dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
 182                         (dce_clk_params.pll_id ==
 183                                         CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
 184         else
 185                 dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
 186 
 187         bp->funcs->set_dce_clock(bp, &dce_clk_params);
 188 
 189         /* Returns the dp_refclk that was set */
 190         return dce_clk_params.target_clock_frequency;
 191 }
 192 
 193 static void dce112_update_clocks(struct clk_mgr *clk_mgr_base,
 194                         struct dc_state *context,
 195                         bool safe_to_lower)
 196 {
 197         struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
 198         struct dm_pp_power_level_change_request level_change_req;
 199         int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
 200 
 201         /*TODO: W/A for dal3 linux, investigate why this works */
 202         if (!clk_mgr_dce->dfs_bypass_active)
 203                 patched_disp_clk = patched_disp_clk * 115 / 100;
 204 
 205         level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
 206         /* get max clock state from PPLIB */
 207         if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
 208                         || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
 209                 if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req))
 210                         clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
 211         }
 212 
 213         if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) {
 214                 patched_disp_clk = dce112_set_clock(clk_mgr_base, patched_disp_clk);
 215                 clk_mgr_base->clks.dispclk_khz = patched_disp_clk;
 216         }
 217         dce11_pplib_apply_display_requirements(clk_mgr_base->ctx->dc, context);
 218 }
 219 
 220 static struct clk_mgr_funcs dce112_funcs = {
 221         .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
 222         .update_clocks = dce112_update_clocks
 223 };
 224 
 225 void dce112_clk_mgr_construct(
 226                 struct dc_context *ctx,
 227                 struct clk_mgr_internal *clk_mgr)
 228 {
 229         dce_clk_mgr_construct(ctx, clk_mgr);
 230 
 231         memcpy(clk_mgr->max_clks_by_state,
 232                 dce112_max_clks_by_state,
 233                 sizeof(dce112_max_clks_by_state));
 234 
 235         clk_mgr->regs = &disp_clk_regs;
 236         clk_mgr->clk_mgr_shift = &disp_clk_shift;
 237         clk_mgr->clk_mgr_mask = &disp_clk_mask;
 238         clk_mgr->base.funcs = &dce112_funcs;
 239 }

/* [<][>][^][v][top][bottom][index][help] */