root/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c

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

DEFINITIONS

This source file includes following definitions.
  1. dccg2_update_dpp_dto
  2. dccg2_get_dccg_ref_freq
  3. dccg2_init
  4. dccg2_create
  5. dcn_dccg_destroy

   1 /*
   2  * Copyright 2018 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 <linux/slab.h>
  27 
  28 #include "reg_helper.h"
  29 #include "core_types.h"
  30 #include "dcn20_dccg.h"
  31 
  32 #define TO_DCN_DCCG(dccg)\
  33         container_of(dccg, struct dcn_dccg, base)
  34 
  35 #define REG(reg) \
  36         (dccg_dcn->regs->reg)
  37 
  38 #undef FN
  39 #define FN(reg_name, field_name) \
  40         dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
  41 
  42 #define CTX \
  43         dccg_dcn->base.ctx
  44 #define DC_LOGGER \
  45         dccg->ctx->logger
  46 
  47 void dccg2_update_dpp_dto(struct dccg *dccg,
  48                 int dpp_inst,
  49                 int req_dppclk,
  50                 bool reduce_divider_only)
  51 {
  52         struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
  53 
  54         if (dccg->ref_dppclk && req_dppclk) {
  55                 int ref_dppclk = dccg->ref_dppclk;
  56                 int current_phase, current_modulo;
  57 
  58                 ASSERT(req_dppclk <= ref_dppclk);
  59                 /* need to clamp to 8 bits */
  60                 if (ref_dppclk > 0xff) {
  61                         int divider = (ref_dppclk + 0xfe) / 0xff;
  62 
  63                         ref_dppclk /= divider;
  64                         req_dppclk = (req_dppclk + divider - 1) / divider;
  65                         if (req_dppclk > ref_dppclk)
  66                                 req_dppclk = ref_dppclk;
  67                 }
  68 
  69                 REG_GET_2(DPPCLK_DTO_PARAM[dpp_inst],
  70                                 DPPCLK0_DTO_PHASE, &current_phase,
  71                                 DPPCLK0_DTO_MODULO, &current_modulo);
  72 
  73                 if (reduce_divider_only) {
  74                         // requested phase/modulo greater than current
  75                         if (req_dppclk * current_modulo >= current_phase * ref_dppclk) {
  76                                 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
  77                                                 DPPCLK0_DTO_PHASE, req_dppclk,
  78                                                 DPPCLK0_DTO_MODULO, ref_dppclk);
  79                         } else {
  80                                 REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
  81                                                 DPPCLK0_DTO_PHASE, current_phase,
  82                                                 DPPCLK0_DTO_MODULO, current_modulo);
  83                         }
  84                 } else {
  85                         REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
  86                                         DPPCLK0_DTO_PHASE, req_dppclk,
  87                                         DPPCLK0_DTO_MODULO, ref_dppclk);
  88                 }
  89 
  90                 REG_UPDATE(DPPCLK_DTO_CTRL,
  91                                 DPPCLK_DTO_ENABLE[dpp_inst], 1);
  92         } else {
  93                 REG_UPDATE(DPPCLK_DTO_CTRL,
  94                                 DPPCLK_DTO_ENABLE[dpp_inst], 0);
  95         }
  96 }
  97 
  98 void dccg2_get_dccg_ref_freq(struct dccg *dccg,
  99                 unsigned int xtalin_freq_inKhz,
 100                 unsigned int *dccg_ref_freq_inKhz)
 101 {
 102         struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 103         uint32_t clk_en = 0;
 104         uint32_t clk_sel = 0;
 105 
 106         REG_GET_2(REFCLK_CNTL, REFCLK_CLOCK_EN, &clk_en, REFCLK_SRC_SEL, &clk_sel);
 107 
 108         if (clk_en != 0) {
 109                 // DCN20 has never been validated for non-xtalin as reference
 110                 // frequency.  There's actually no way for DC to determine what
 111                 // frequency a non-xtalin source is.
 112                 ASSERT_CRITICAL(false);
 113         }
 114 
 115         *dccg_ref_freq_inKhz = xtalin_freq_inKhz;
 116 
 117         return;
 118 }
 119 
 120 void dccg2_init(struct dccg *dccg)
 121 {
 122         struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 123 
 124         // Fallthrough intentional to program all available dpp_dto's
 125         switch (dccg_dcn->base.ctx->dc->res_pool->pipe_count) {
 126         case 6:
 127                 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[5], 1);
 128                 /* Fall through */
 129         case 5:
 130                 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[4], 1);
 131                 /* Fall through */
 132         case 4:
 133                 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[3], 1);
 134                 /* Fall through */
 135         case 3:
 136                 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[2], 1);
 137                 /* Fall through */
 138         case 2:
 139                 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[1], 1);
 140                 /* Fall through */
 141         case 1:
 142                 REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[0], 1);
 143                 break;
 144         default:
 145                 ASSERT(false);
 146                 break;
 147         }
 148 }
 149 
 150 static const struct dccg_funcs dccg2_funcs = {
 151         .update_dpp_dto = dccg2_update_dpp_dto,
 152         .get_dccg_ref_freq = dccg2_get_dccg_ref_freq,
 153         .dccg_init = dccg2_init
 154 };
 155 
 156 struct dccg *dccg2_create(
 157         struct dc_context *ctx,
 158         const struct dccg_registers *regs,
 159         const struct dccg_shift *dccg_shift,
 160         const struct dccg_mask *dccg_mask)
 161 {
 162         struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
 163         struct dccg *base;
 164 
 165         if (dccg_dcn == NULL) {
 166                 BREAK_TO_DEBUGGER();
 167                 return NULL;
 168         }
 169 
 170         base = &dccg_dcn->base;
 171         base->ctx = ctx;
 172         base->funcs = &dccg2_funcs;
 173 
 174         dccg_dcn->regs = regs;
 175         dccg_dcn->dccg_shift = dccg_shift;
 176         dccg_dcn->dccg_mask = dccg_mask;
 177 
 178         return &dccg_dcn->base;
 179 }
 180 
 181 void dcn_dccg_destroy(struct dccg **dccg)
 182 {
 183         struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(*dccg);
 184 
 185         kfree(dccg_dcn);
 186         *dccg = NULL;
 187 }

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