linux/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
<<
>>
Prefs
   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 "reg_helper.h"
  27#include "core_types.h"
  28#include "dcn31_dccg.h"
  29
  30#define TO_DCN_DCCG(dccg)\
  31        container_of(dccg, struct dcn_dccg, base)
  32
  33#define REG(reg) \
  34        (dccg_dcn->regs->reg)
  35
  36#undef FN
  37#define FN(reg_name, field_name) \
  38        dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
  39
  40#define CTX \
  41        dccg_dcn->base.ctx
  42#define DC_LOGGER \
  43        dccg->ctx->logger
  44
  45void dccg31_set_physymclk(
  46                struct dccg *dccg,
  47                int phy_inst,
  48                enum physymclk_clock_source clk_src,
  49                bool force_enable)
  50{
  51        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
  52
  53        /* Force PHYSYMCLK on and Select phyd32clk as the source of clock which is output to PHY through DCIO */
  54        switch (phy_inst) {
  55        case 0:
  56                if (force_enable)
  57                        REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
  58                                        PHYASYMCLK_FORCE_EN, 1,
  59                                        PHYASYMCLK_FORCE_SRC_SEL, clk_src);
  60                else
  61                        REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
  62                                        PHYASYMCLK_FORCE_EN, 0,
  63                                        PHYASYMCLK_FORCE_SRC_SEL, 0);
  64                break;
  65        case 1:
  66                if (force_enable)
  67                        REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
  68                                        PHYBSYMCLK_FORCE_EN, 1,
  69                                        PHYBSYMCLK_FORCE_SRC_SEL, clk_src);
  70                else
  71                        REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
  72                                        PHYBSYMCLK_FORCE_EN, 0,
  73                                        PHYBSYMCLK_FORCE_SRC_SEL, 0);
  74                break;
  75        case 2:
  76                if (force_enable)
  77                        REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
  78                                        PHYCSYMCLK_FORCE_EN, 1,
  79                                        PHYCSYMCLK_FORCE_SRC_SEL, clk_src);
  80                else
  81                        REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
  82                                        PHYCSYMCLK_FORCE_EN, 0,
  83                                        PHYCSYMCLK_FORCE_SRC_SEL, 0);
  84                break;
  85        case 3:
  86                if (force_enable)
  87                        REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
  88                                        PHYDSYMCLK_FORCE_EN, 1,
  89                                        PHYDSYMCLK_FORCE_SRC_SEL, clk_src);
  90                else
  91                        REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
  92                                        PHYDSYMCLK_FORCE_EN, 0,
  93                                        PHYDSYMCLK_FORCE_SRC_SEL, 0);
  94                break;
  95        case 4:
  96                if (force_enable)
  97                        REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
  98                                        PHYESYMCLK_FORCE_EN, 1,
  99                                        PHYESYMCLK_FORCE_SRC_SEL, clk_src);
 100                else
 101                        REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
 102                                        PHYESYMCLK_FORCE_EN, 0,
 103                                        PHYESYMCLK_FORCE_SRC_SEL, 0);
 104                break;
 105        default:
 106                BREAK_TO_DEBUGGER();
 107                return;
 108        }
 109}
 110
 111/* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */
 112void dccg31_set_dtbclk_dto(
 113                struct dccg *dccg,
 114                int dtbclk_inst,
 115                int req_dtbclk_khz,
 116                int num_odm_segments,
 117                const struct dc_crtc_timing *timing)
 118{
 119        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 120        uint32_t dtbdto_div;
 121
 122        /* Mode                 DTBDTO Rate       DTBCLK_DTO<x>_DIV Register
 123         * ODM 4:1 combine      pixel rate/4      2
 124         * ODM 2:1 combine      pixel rate/2      4
 125         * non-DSC 4:2:0 mode   pixel rate/2      4
 126         * DSC native 4:2:0     pixel rate/2      4
 127         * DSC native 4:2:2     pixel rate/2      4
 128         * Other modes          pixel rate        8
 129         */
 130        if (num_odm_segments == 4) {
 131                dtbdto_div = 2;
 132                req_dtbclk_khz = req_dtbclk_khz / 4;
 133        } else if ((num_odm_segments == 2) ||
 134                        (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ||
 135                        (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
 136                                        && !timing->dsc_cfg.ycbcr422_simple)) {
 137                dtbdto_div = 4;
 138                req_dtbclk_khz = req_dtbclk_khz / 2;
 139        } else
 140                dtbdto_div = 8;
 141
 142        if (dccg->ref_dtbclk_khz && req_dtbclk_khz) {
 143                uint32_t modulo, phase;
 144
 145                // phase / modulo = dtbclk / dtbclk ref
 146                modulo = dccg->ref_dtbclk_khz * 1000;
 147                phase = div_u64((((unsigned long long)modulo * req_dtbclk_khz) + dccg->ref_dtbclk_khz - 1),
 148                        dccg->ref_dtbclk_khz);
 149
 150                REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
 151                                DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div);
 152
 153                REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], modulo);
 154                REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], phase);
 155
 156                REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
 157                                DTBCLK_DTO_ENABLE[dtbclk_inst], 1);
 158
 159                REG_WAIT(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
 160                                DTBCLKDTO_ENABLE_STATUS[dtbclk_inst], 1,
 161                                1, 100);
 162
 163                /* The recommended programming sequence to enable DTBCLK DTO to generate
 164                 * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should
 165                 * be set only after DTO is enabled
 166                 */
 167                REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
 168                                PIPE_DTO_SRC_SEL[dtbclk_inst], 1);
 169
 170                dccg->dtbclk_khz[dtbclk_inst] = req_dtbclk_khz;
 171        } else {
 172                REG_UPDATE_3(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
 173                                DTBCLK_DTO_ENABLE[dtbclk_inst], 0,
 174                                PIPE_DTO_SRC_SEL[dtbclk_inst], 0,
 175                                DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div);
 176
 177                REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], 0);
 178                REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], 0);
 179
 180                dccg->dtbclk_khz[dtbclk_inst] = 0;
 181        }
 182}
 183
 184void dccg31_set_audio_dtbclk_dto(
 185                struct dccg *dccg,
 186                uint32_t req_audio_dtbclk_khz)
 187{
 188        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 189
 190        if (dccg->ref_dtbclk_khz && req_audio_dtbclk_khz) {
 191                uint32_t modulo, phase;
 192
 193                // phase / modulo = dtbclk / dtbclk ref
 194                modulo = dccg->ref_dtbclk_khz * 1000;
 195                phase = div_u64((((unsigned long long)modulo * req_audio_dtbclk_khz) + dccg->ref_dtbclk_khz - 1),
 196                        dccg->ref_dtbclk_khz);
 197
 198
 199                REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, modulo);
 200                REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, phase);
 201
 202                //REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
 203                //              DCCG_AUDIO_DTBCLK_DTO_USE_512FBR_DTO, 1);
 204
 205                REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
 206                                DCCG_AUDIO_DTO_SEL, 4);  //  04 - DCCG_AUDIO_DTO_SEL_AUDIO_DTO_DTBCLK
 207
 208                dccg->audio_dtbclk_khz = req_audio_dtbclk_khz;
 209        } else {
 210                REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, 0);
 211                REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, 0);
 212
 213                REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
 214                                DCCG_AUDIO_DTO_SEL, 3);  //  03 - DCCG_AUDIO_DTO_SEL_NO_AUDIO_DTO
 215
 216                dccg->audio_dtbclk_khz = 0;
 217        }
 218}
 219
 220static void dccg31_get_dccg_ref_freq(struct dccg *dccg,
 221                unsigned int xtalin_freq_inKhz,
 222                unsigned int *dccg_ref_freq_inKhz)
 223{
 224        /*
 225         * Assume refclk is sourced from xtalin
 226         * expect 24MHz
 227         */
 228        *dccg_ref_freq_inKhz = xtalin_freq_inKhz;
 229        return;
 230}
 231
 232static void dccg31_set_dispclk_change_mode(
 233        struct dccg *dccg,
 234        enum dentist_dispclk_change_mode change_mode)
 235{
 236        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 237
 238        REG_UPDATE(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_MODE,
 239                   change_mode == DISPCLK_CHANGE_MODE_RAMPING ? 2 : 0);
 240}
 241
 242void dccg31_init(struct dccg *dccg)
 243{
 244}
 245
 246static const struct dccg_funcs dccg31_funcs = {
 247        .update_dpp_dto = dccg2_update_dpp_dto,
 248        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
 249        .dccg_init = dccg31_init,
 250        .set_physymclk = dccg31_set_physymclk,
 251        .set_dtbclk_dto = dccg31_set_dtbclk_dto,
 252        .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,
 253        .set_dispclk_change_mode = dccg31_set_dispclk_change_mode,
 254};
 255
 256struct dccg *dccg31_create(
 257        struct dc_context *ctx,
 258        const struct dccg_registers *regs,
 259        const struct dccg_shift *dccg_shift,
 260        const struct dccg_mask *dccg_mask)
 261{
 262        struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
 263        struct dccg *base;
 264
 265        if (dccg_dcn == NULL) {
 266                BREAK_TO_DEBUGGER();
 267                return NULL;
 268        }
 269
 270        base = &dccg_dcn->base;
 271        base->ctx = ctx;
 272        base->funcs = &dccg31_funcs;
 273
 274        dccg_dcn->regs = regs;
 275        dccg_dcn->dccg_shift = dccg_shift;
 276        dccg_dcn->dccg_mask = dccg_mask;
 277
 278        return &dccg_dcn->base;
 279}
 280