linux/drivers/gpu/drm/amd/display/dc/clk_mgr/dce112/dce112_clk_mgr.c
<<
>>
Prefs
   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
  44static const struct clk_mgr_registers disp_clk_regs = {
  45                CLK_COMMON_REG_LIST_DCE_BASE()
  46};
  47
  48static const struct clk_mgr_shift disp_clk_shift = {
  49                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT)
  50};
  51
  52static const struct clk_mgr_mask disp_clk_mask = {
  53                CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
  54};
  55
  56static 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
  70int 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 *dc = clk_mgr_base->ctx->dc;
  76        struct dmcu *dmcu = 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        requested_clk_khz = max(requested_clk_khz,
  83                                clk_mgr_dce->base.dentist_vco_freq_khz / 62);
  84
  85        dce_clk_params.target_clock_frequency = requested_clk_khz;
  86        dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
  87        dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
  88
  89        bp->funcs->set_dce_clock(bp, &dce_clk_params);
  90        actual_clock = dce_clk_params.target_clock_frequency;
  91
  92        /*
  93         * from power down, we need mark the clock state as ClocksStateNominal
  94         * from HWReset, so when resume we will call pplib voltage regulator.
  95         */
  96        if (requested_clk_khz == 0)
  97                clk_mgr_dce->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
  98
  99        /*Program DP ref Clock*/
 100        /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
 101        dce_clk_params.target_clock_frequency = 0;
 102        dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
 103
 104        if (!((clk_mgr_base->ctx->asic_id.chip_family == FAMILY_AI) &&
 105               ASICREV_IS_VEGA20_P(clk_mgr_base->ctx->asic_id.hw_internal_rev)))
 106                dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
 107                        (dce_clk_params.pll_id ==
 108                                        CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
 109        else
 110                dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
 111
 112        bp->funcs->set_dce_clock(bp, &dce_clk_params);
 113
 114        if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
 115                if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
 116                        if (clk_mgr_dce->dfs_bypass_disp_clk != actual_clock)
 117                                dmcu->funcs->set_psr_wait_loop(dmcu,
 118                                                actual_clock / 1000 / 7);
 119                }
 120        }
 121
 122        clk_mgr_dce->dfs_bypass_disp_clk = actual_clock;
 123        return actual_clock;
 124}
 125
 126int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz)
 127{
 128        struct bp_set_dce_clock_parameters dce_clk_params;
 129        struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
 130        struct dc *dc = clk_mgr->base.ctx->dc;
 131        struct dmcu *dmcu = dc->res_pool->dmcu;
 132        int actual_clock = requested_clk_khz;
 133        /* Prepare to program display clock*/
 134        memset(&dce_clk_params, 0, sizeof(dce_clk_params));
 135
 136        /* Make sure requested clock isn't lower than minimum threshold*/
 137        if (requested_clk_khz > 0)
 138                requested_clk_khz = max(requested_clk_khz,
 139                                clk_mgr->base.dentist_vco_freq_khz / 62);
 140
 141        dce_clk_params.target_clock_frequency = requested_clk_khz;
 142        dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
 143        dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
 144
 145        bp->funcs->set_dce_clock(bp, &dce_clk_params);
 146        actual_clock = dce_clk_params.target_clock_frequency;
 147
 148        /*
 149         * from power down, we need mark the clock state as ClocksStateNominal
 150         * from HWReset, so when resume we will call pplib voltage regulator.
 151         */
 152        if (requested_clk_khz == 0)
 153                clk_mgr->cur_min_clks_state = DM_PP_CLOCKS_STATE_NOMINAL;
 154
 155
 156        if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
 157                if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
 158                        if (clk_mgr->dfs_bypass_disp_clk != actual_clock)
 159                                dmcu->funcs->set_psr_wait_loop(dmcu,
 160                                                actual_clock / 1000 / 7);
 161                }
 162        }
 163
 164        clk_mgr->dfs_bypass_disp_clk = actual_clock;
 165        return actual_clock;
 166
 167}
 168
 169int dce112_set_dprefclk(struct clk_mgr_internal *clk_mgr)
 170{
 171        struct bp_set_dce_clock_parameters dce_clk_params;
 172        struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
 173
 174        memset(&dce_clk_params, 0, sizeof(dce_clk_params));
 175
 176        /*Program DP ref Clock*/
 177        /*VBIOS will determine DPREFCLK frequency, so we don't set it*/
 178        dce_clk_params.target_clock_frequency = 0;
 179        dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
 180        dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
 181        if (!((clk_mgr->base.ctx->asic_id.chip_family == FAMILY_AI) &&
 182               ASICREV_IS_VEGA20_P(clk_mgr->base.ctx->asic_id.hw_internal_rev)))
 183                dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
 184                        (dce_clk_params.pll_id ==
 185                                        CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
 186        else
 187                dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
 188
 189        bp->funcs->set_dce_clock(bp, &dce_clk_params);
 190
 191        /* Returns the dp_refclk that was set */
 192        return dce_clk_params.target_clock_frequency;
 193}
 194
 195static void dce112_update_clocks(struct clk_mgr *clk_mgr_base,
 196                        struct dc_state *context,
 197                        bool safe_to_lower)
 198{
 199        struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
 200        struct dm_pp_power_level_change_request level_change_req;
 201        int patched_disp_clk = context->bw_ctx.bw.dce.dispclk_khz;
 202
 203        /*TODO: W/A for dal3 linux, investigate why this works */
 204        if (!clk_mgr_dce->dfs_bypass_active)
 205                patched_disp_clk = patched_disp_clk * 115 / 100;
 206
 207        level_change_req.power_level = dce_get_required_clocks_state(clk_mgr_base, context);
 208        /* get max clock state from PPLIB */
 209        if ((level_change_req.power_level < clk_mgr_dce->cur_min_clks_state && safe_to_lower)
 210                        || level_change_req.power_level > clk_mgr_dce->cur_min_clks_state) {
 211                if (dm_pp_apply_power_level_change_request(clk_mgr_base->ctx, &level_change_req))
 212                        clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
 213        }
 214
 215        if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr_base->clks.dispclk_khz)) {
 216                patched_disp_clk = dce112_set_clock(clk_mgr_base, patched_disp_clk);
 217                clk_mgr_base->clks.dispclk_khz = patched_disp_clk;
 218        }
 219        dce11_pplib_apply_display_requirements(clk_mgr_base->ctx->dc, context);
 220}
 221
 222static struct clk_mgr_funcs dce112_funcs = {
 223        .get_dp_ref_clk_frequency = dce_get_dp_ref_freq_khz,
 224        .update_clocks = dce112_update_clocks
 225};
 226
 227void dce112_clk_mgr_construct(
 228                struct dc_context *ctx,
 229                struct clk_mgr_internal *clk_mgr)
 230{
 231        dce_clk_mgr_construct(ctx, clk_mgr);
 232
 233        memcpy(clk_mgr->max_clks_by_state,
 234                dce112_max_clks_by_state,
 235                sizeof(dce112_max_clks_by_state));
 236
 237        clk_mgr->regs = &disp_clk_regs;
 238        clk_mgr->clk_mgr_shift = &disp_clk_shift;
 239        clk_mgr->clk_mgr_mask = &disp_clk_mask;
 240        clk_mgr->base.funcs = &dce112_funcs;
 241}
 242