Commit fcee01b9 authored by Harry Wentland's avatar Harry Wentland Committed by Alex Deucher

drm/amd/display: Add DCN2 clk mgr

Adds support for handling of clocking relevant to the DCN2 block,
including programming of the DCCG (Display Controller Clock Generator)
block:

HW Blocks:

    +--------+       +--------+
    |  DIO   |       |  DCCG  |
    +--------+       +--------+
Signed-off-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ca4d9b3a
...@@ -73,3 +73,15 @@ AMD_DAL_CLK_MGR_DCN10 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn10/,$(CLK_MGR_DC ...@@ -73,3 +73,15 @@ AMD_DAL_CLK_MGR_DCN10 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn10/,$(CLK_MGR_DC
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN10) AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN10)
endif endif
ifdef CONFIG_DRM_AMD_DC_DCN2_0
###############################################################################
# DCN20
###############################################################################
CLK_MGR_DCN20 = dcn20_clk_mgr.o
AMD_DAL_CLK_MGR_DCN20 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn20/,$(CLK_MGR_DCN20))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN20)
endif
...@@ -34,31 +34,7 @@ ...@@ -34,31 +34,7 @@
#include "dce120/dce120_clk_mgr.h" #include "dce120/dce120_clk_mgr.h"
#include "dcn10/rv1_clk_mgr.h" #include "dcn10/rv1_clk_mgr.h"
#include "dcn10/rv2_clk_mgr.h" #include "dcn10/rv2_clk_mgr.h"
#include "dcn20/dcn20_clk_mgr.h"
int clk_mgr_helper_get_active_display_cnt(
struct dc *dc,
struct dc_state *context)
{
int i, display_count;
display_count = 0;
for (i = 0; i < context->stream_count; i++) {
const struct dc_stream_state *stream = context->streams[i];
/*
* Only notify active stream or virtual stream.
* Need to notify virtual stream to work around
* headless case. HPD does not fire when system is in
* S0i2.
*/
if (!stream->dpms_off || stream->signal == SIGNAL_TYPE_VIRTUAL)
display_count++;
}
return display_count;
}
struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *pp_smu, struct dccg *dccg) struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *pp_smu, struct dccg *dccg)
{ {
...@@ -117,6 +93,12 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p ...@@ -117,6 +93,12 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
break; break;
#endif /* Family RV */ #endif /* Family RV */
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
case FAMILY_NV:
dcn20_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
break;
#endif /* Family NV */
default: default:
ASSERT(0); /* Unknown Asic */ ASSERT(0); /* Unknown Asic */
break; break;
......
...@@ -29,28 +29,6 @@ ...@@ -29,28 +29,6 @@
#include "dc.h" #include "dc.h"
/* Starting DID for each range */
enum dentist_base_divider_id {
DENTIST_BASE_DID_1 = 0x08,
DENTIST_BASE_DID_2 = 0x40,
DENTIST_BASE_DID_3 = 0x60,
DENTIST_BASE_DID_4 = 0x7e,
DENTIST_MAX_DID = 0x7f
};
/* Starting point and step size for each divider range.*/
enum dentist_divider_range {
DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */
DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */
DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */
DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */
DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */
DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */
DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */
DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */
DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4
};
/* functions shared by other dce clk mgrs */ /* functions shared by other dce clk mgrs */
int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz); int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz);
int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base); int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base);
......
...@@ -114,6 +114,29 @@ static void ramp_up_dispclk_with_dpp(struct clk_mgr_internal *clk_mgr, struct dc ...@@ -114,6 +114,29 @@ static void ramp_up_dispclk_with_dpp(struct clk_mgr_internal *clk_mgr, struct dc
clk_mgr->base.clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz; clk_mgr->base.clks.max_supported_dppclk_khz = new_clocks->max_supported_dppclk_khz;
} }
static int get_active_display_cnt(
struct dc *dc,
struct dc_state *context)
{
int i, display_count;
display_count = 0;
for (i = 0; i < context->stream_count; i++) {
const struct dc_stream_state *stream = context->streams[i];
/*
* Only notify active stream or virtual stream.
* Need to notify virtual stream to work around
* headless case. HPD does not fire when system is in
* S0i2.
*/
if (!stream->dpms_off || stream->signal == SIGNAL_TYPE_VIRTUAL)
display_count++;
}
return display_count;
}
static void rv1_update_clocks(struct clk_mgr *clk_mgr_base, static void rv1_update_clocks(struct clk_mgr *clk_mgr_base,
struct dc_state *context, struct dc_state *context,
bool safe_to_lower) bool safe_to_lower)
...@@ -133,7 +156,7 @@ static void rv1_update_clocks(struct clk_mgr *clk_mgr_base, ...@@ -133,7 +156,7 @@ static void rv1_update_clocks(struct clk_mgr *clk_mgr_base,
pp_smu = &clk_mgr->pp_smu->rv_funcs; pp_smu = &clk_mgr->pp_smu->rv_funcs;
display_count = clk_mgr_helper_get_active_display_cnt(dc, context); display_count = get_active_display_cnt(dc, context);
if (display_count == 0) if (display_count == 0)
enter_display_off = true; enter_display_off = true;
......
...@@ -68,59 +68,57 @@ static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0 } }, ...@@ -68,59 +68,57 @@ static const struct IP_BASE MP1_BASE = { { { { 0x00016000, 0, 0, 0, 0 } },
#define VBIOSSMC_MSG_SetDispclkFreq 0x4 #define VBIOSSMC_MSG_SetDispclkFreq 0x4
#define VBIOSSMC_MSG_SetDprefclkFreq 0x5 #define VBIOSSMC_MSG_SetDprefclkFreq 0x5
int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param) int rv1_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
{ {
int actual_dispclk_set_khz = -1;
struct dc *core_dc = clk_mgr->base.ctx->dc;
struct dmcu *dmcu = core_dc->res_pool->dmcu;
/* First clear response register */ /* First clear response register */
//dm_write_reg(ctx, mmMP1_SMN_C2PMSG_91, 0);
REG_WRITE(MP1_SMN_C2PMSG_91, 0); REG_WRITE(MP1_SMN_C2PMSG_91, 0);
/* Set the parameter register for the SMU message, unit is Mhz */ /* Set the parameter register for the SMU message, unit is Mhz */
REG_WRITE(MP1_SMN_C2PMSG_83, param); //dm_write_reg(ctx, mmMP1_SMN_C2PMSG_83, requested_dispclk_khz / 1000);
REG_WRITE(MP1_SMN_C2PMSG_83, requested_dispclk_khz / 1000);
/* Trigger the message transaction by writing the message ID */ /* Trigger the message transaction by writing the message ID */
REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); //dm_write_reg(ctx, mmMP1_SMN_C2PMSG_67, VBIOSSMC_MSG_SetDispclkFreq);
REG_WRITE(MP1_SMN_C2PMSG_67, VBIOSSMC_MSG_SetDispclkFreq);
REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000); REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000);
/* Actual dispclk set is returned in the parameter register */ /* Actual dispclk set is returned in the parameter register */
return REG_READ(MP1_SMN_C2PMSG_83); actual_dispclk_set_khz = REG_READ(MP1_SMN_C2PMSG_83) * 1000;
}
int rv1_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
{
int actual_dispclk_set_mhz = -1;
struct dc *core_dc = clk_mgr->base.ctx->dc;
struct dmcu *dmcu = core_dc->res_pool->dmcu;
/* Unit of SMU msg parameter is Mhz */
actual_dispclk_set_mhz = rv1_vbios_smu_send_msg_with_param(
clk_mgr,
VBIOSSMC_MSG_SetDispclkFreq,
requested_dispclk_khz / 1000);
/* Actual dispclk set is returned in the parameter register */
actual_dispclk_set_mhz = REG_READ(MP1_SMN_C2PMSG_83) * 1000;
if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) {
if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz) if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_khz)
dmcu->funcs->set_psr_wait_loop(dmcu, dmcu->funcs->set_psr_wait_loop(dmcu,
actual_dispclk_set_mhz / 7); actual_dispclk_set_khz / 1000 / 7);
} }
} }
return actual_dispclk_set_mhz * 1000; return actual_dispclk_set_khz;
} }
int rv1_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr) int rv1_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
{ {
int actual_dprefclk_set_mhz = -1; int actual_dprefclk_set_khz = -1;
REG_WRITE(MP1_SMN_C2PMSG_91, 0);
/* Set the parameter register for the SMU message */
REG_WRITE(MP1_SMN_C2PMSG_83, clk_mgr->base.dprefclk_khz / 1000);
actual_dprefclk_set_mhz = rv1_vbios_smu_send_msg_with_param( /* Trigger the message transaction by writing the message ID */
clk_mgr, REG_WRITE(MP1_SMN_C2PMSG_67, VBIOSSMC_MSG_SetDprefclkFreq);
VBIOSSMC_MSG_SetDprefclkFreq,
clk_mgr->base.dprefclk_khz / 1000); /* Wait for SMU response */
REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000);
/* TODO: add code for programing DP DTO, currently this is down by command table */ actual_dprefclk_set_khz = REG_READ(MP1_SMN_C2PMSG_83) * 1000;
return actual_dprefclk_set_mhz * 1000; return actual_dprefclk_set_khz;
} }
This diff is collapsed.
/*
* Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __DCN20_CLK_MGR_H__
#define __DCN20_CLK_MGR_H__
void dcn2_update_clocks(struct clk_mgr *dccg,
struct dc_state *context,
bool safe_to_lower);
void dcn2_update_clocks_fpga(struct clk_mgr *clk_mgr,
struct dc_state *context,
bool safe_to_lower);
void dcn2_init_clocks(struct clk_mgr *clk_mgr);
void dcn20_clk_mgr_construct(struct dc_context *ctx,
struct clk_mgr_internal *clk_mgr,
struct pp_smu_funcs *pp_smu,
struct dccg *dccg);
#endif //__DCN20_CLK_MGR_H__
...@@ -53,6 +53,8 @@ ...@@ -53,6 +53,8 @@
#define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
#define MAX_PLL_CALC_ERROR 0xFFFFFFFF #define MAX_PLL_CALC_ERROR 0xFFFFFFFF
#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0]))
static const struct spread_spectrum_data *get_ss_data_entry( static const struct spread_spectrum_data *get_ss_data_entry(
struct dce110_clk_src *clk_src, struct dce110_clk_src *clk_src,
enum signal_type signal, enum signal_type signal,
...@@ -1000,6 +1002,95 @@ static bool get_pixel_clk_frequency_100hz( ...@@ -1000,6 +1002,95 @@ static bool get_pixel_clk_frequency_100hz(
return false; return false;
} }
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
struct pixel_rate_range_table_entry {
unsigned int range_min_khz;
unsigned int range_max_khz;
unsigned int target_pixel_rate_khz;
unsigned short mult_factor;
unsigned short div_factor;
};
static const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] = {
// /1.001 rates
{25170, 25180, 25200, 1000, 1001}, //25.2MHz -> 25.17
{59340, 59350, 59400, 1000, 1001}, //59.4Mhz -> 59.340
{74170, 74180, 74250, 1000, 1001}, //74.25Mhz -> 74.1758
{125870, 125880, 126000, 1000, 1001}, //126Mhz -> 125.87
{148350, 148360, 148500, 1000, 1001}, //148.5Mhz -> 148.3516
{167830, 167840, 168000, 1000, 1001}, //168Mhz -> 167.83
{222520, 222530, 222750, 1000, 1001}, //222.75Mhz -> 222.527
{257140, 257150, 257400, 1000, 1001}, //257.4Mhz -> 257.1429
{296700, 296710, 297000, 1000, 1001}, //297Mhz -> 296.7033
{342850, 342860, 343200, 1000, 1001}, //343.2Mhz -> 342.857
{395600, 395610, 396000, 1000, 1001}, //396Mhz -> 395.6
{409090, 409100, 409500, 1000, 1001}, //409.5Mhz -> 409.091
{445050, 445060, 445500, 1000, 1001}, //445.5Mhz -> 445.055
{467530, 467540, 468000, 1000, 1001}, //468Mhz -> 467.5325
{519230, 519240, 519750, 1000, 1001}, //519.75Mhz -> 519.231
{525970, 525980, 526500, 1000, 1001}, //526.5Mhz -> 525.974
{545450, 545460, 546000, 1000, 1001}, //546Mhz -> 545.455
{593400, 593410, 594000, 1000, 1001}, //594Mhz -> 593.4066
{623370, 623380, 624000, 1000, 1001}, //624Mhz -> 623.377
{692300, 692310, 693000, 1000, 1001}, //693Mhz -> 692.308
{701290, 701300, 702000, 1000, 1001}, //702Mhz -> 701.2987
{791200, 791210, 792000, 1000, 1001}, //792Mhz -> 791.209
{890100, 890110, 891000, 1000, 1001}, //891Mhz -> 890.1099
{1186810, 1186820, 1188000, 1000, 1001},//1188Mhz -> 1186.8131
// *1.001 rates
{27020, 27030, 27000, 1001, 1000}, //27Mhz
{54050, 54060, 54000, 1001, 1000}, //54Mhz
{108100, 108110, 108000, 1001, 1000},//108Mhz
};
static const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb(
unsigned int pixel_rate_khz)
{
int i;
for (i = 0; i < NUM_ELEMENTS(video_optimized_pixel_rates); i++) {
const struct pixel_rate_range_table_entry *e = &video_optimized_pixel_rates[i];
if (e->range_min_khz <= pixel_rate_khz && pixel_rate_khz <= e->range_max_khz) {
return e;
}
}
return NULL;
}
static bool dcn20_program_pix_clk(
struct clock_source *clock_source,
struct pixel_clk_params *pix_clk_params,
struct pll_settings *pll_settings)
{
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
const struct pixel_rate_range_table_entry *e =
look_up_in_video_optimized_rate_tlb(pll_settings->actual_pix_clk_100hz / 10);
dce112_program_pix_clk(clock_source, pix_clk_params, pll_settings);
if (e) {
/* Set DTO values: phase = target clock, modulo = reference clock */
REG_WRITE(PHASE[inst], e->target_pixel_rate_khz * e->mult_factor);
REG_WRITE(MODULO[inst], dp_dto_ref_khz * e->div_factor);
}
return true;
}
static const struct clock_source_funcs dcn20_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dcn20_program_pix_clk,
.get_pix_clk_dividers = dce112_get_pix_clk_dividers
};
#endif
/*****************************************/ /*****************************************/
/* Constructor */ /* Constructor */
/*****************************************/ /*****************************************/
...@@ -1376,3 +1467,20 @@ bool dce112_clk_src_construct( ...@@ -1376,3 +1467,20 @@ bool dce112_clk_src_construct(
return true; return true;
} }
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
bool dcn20_clk_src_construct(
struct dce110_clk_src *clk_src,
struct dc_context *ctx,
struct dc_bios *bios,
enum clock_source_id id,
const struct dce110_clk_src_regs *regs,
const struct dce110_clk_src_shift *cs_shift,
const struct dce110_clk_src_mask *cs_mask)
{
bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
clk_src->base.funcs = &dcn20_clk_src_funcs;
return ret;
}
#endif
...@@ -55,6 +55,37 @@ ...@@ -55,6 +55,37 @@
CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\
CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh) CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh)
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#define CS_COMMON_REG_LIST_DCN2_0(index, pllid) \
SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\
SRII(PHASE, DP_DTO, 0),\
SRII(PHASE, DP_DTO, 1),\
SRII(PHASE, DP_DTO, 2),\
SRII(PHASE, DP_DTO, 3),\
SRII(PHASE, DP_DTO, 4),\
SRII(PHASE, DP_DTO, 5),\
SRII(MODULO, DP_DTO, 0),\
SRII(MODULO, DP_DTO, 1),\
SRII(MODULO, DP_DTO, 2),\
SRII(MODULO, DP_DTO, 3),\
SRII(MODULO, DP_DTO, 4),\
SRII(MODULO, DP_DTO, 5),\
SRII(PIXEL_RATE_CNTL, OTG, 0),\
SRII(PIXEL_RATE_CNTL, OTG, 1),\
SRII(PIXEL_RATE_CNTL, OTG, 2),\
SRII(PIXEL_RATE_CNTL, OTG, 3),\
SRII(PIXEL_RATE_CNTL, OTG, 4),\
SRII(PIXEL_RATE_CNTL, OTG, 5)
#endif
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#define CS_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\
CS_SF(DP_DTO0_PHASE, DP_DTO0_PHASE, mask_sh),\
CS_SF(DP_DTO0_MODULO, DP_DTO0_MODULO, mask_sh),\
CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\
CS_SF(OTG0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh)
#endif
#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
#define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \ #define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \
...@@ -153,4 +184,15 @@ bool dce112_clk_src_construct( ...@@ -153,4 +184,15 @@ bool dce112_clk_src_construct(
const struct dce110_clk_src_shift *cs_shift, const struct dce110_clk_src_shift *cs_shift,
const struct dce110_clk_src_mask *cs_mask); const struct dce110_clk_src_mask *cs_mask);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
bool dcn20_clk_src_construct(
struct dce110_clk_src *clk_src,
struct dc_context *ctx,
struct dc_bios *bios,
enum clock_source_id id,
const struct dce110_clk_src_regs *regs,
const struct dce110_clk_src_shift *cs_shift,
const struct dce110_clk_src_mask *cs_mask);
#endif
#endif #endif
/*
* Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#include "reg_helper.h"
#include "core_types.h"
#include "dcn20_dccg.h"
#define TO_DCN_DCCG(dccg)\
container_of(dccg, struct dcn_dccg, base)
#define REG(reg) \
(dccg_dcn->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
#define CTX \
dccg_dcn->base.ctx
#define DC_LOGGER \
dccg->ctx->logger
void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ref_dppclk && req_dppclk) {
int ref_dppclk = dccg->ref_dppclk;
ASSERT(req_dppclk <= ref_dppclk);
/* need to clamp to 8 bits */
if (ref_dppclk > 0xff) {
int divider = (ref_dppclk + 0xfe) / 0xff;
ref_dppclk /= divider;
req_dppclk = (req_dppclk + divider - 1) / divider;
if (req_dppclk > ref_dppclk)
req_dppclk = ref_dppclk;
}
REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
DPPCLK0_DTO_PHASE, req_dppclk,
DPPCLK0_DTO_MODULO, ref_dppclk);
REG_UPDATE(DPPCLK_DTO_CTRL,
DPPCLK_DTO_ENABLE[dpp_inst], 1);
} else {
REG_UPDATE(DPPCLK_DTO_CTRL,
DPPCLK_DTO_ENABLE[dpp_inst], 0);
}
}
void dccg2_get_dccg_ref_freq(struct dccg *dccg,
unsigned int xtalin_freq_inKhz,
unsigned int *dccg_ref_freq_inKhz)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t clk_en = 0;
uint32_t clk_sel = 0;
REG_GET_2(REFCLK_CNTL, REFCLK_CLOCK_EN, &clk_en, REFCLK_SRC_SEL, &clk_sel);
if (clk_en != 0) {
// DCN20 has never been validated for non-xtalin as reference
// frequency. There's actually no way for DC to determine what
// frequency a non-xtalin source is.
ASSERT_CRITICAL(false);
}
*dccg_ref_freq_inKhz = xtalin_freq_inKhz;
return;
}
void dccg2_init(struct dccg *dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
// Fallthrough intentional to program all available dpp_dto's
switch (dccg_dcn->base.ctx->dc->res_pool->pipe_count) {
case 6:
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[5], 1);
case 5:
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[4], 1);
case 4:
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[3], 1);
case 3:
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[2], 1);
case 2:
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[1], 1);
case 1:
REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[0], 1);
break;
default:
ASSERT(false);
break;
}
}
static const struct dccg_funcs dccg2_funcs = {
.update_dpp_dto = dccg2_update_dpp_dto,
.get_dccg_ref_freq = dccg2_get_dccg_ref_freq,
.dccg_init = dccg2_init
};
struct dccg *dccg2_create(
struct dc_context *ctx,
const struct dccg_registers *regs,
const struct dccg_shift *dccg_shift,
const struct dccg_mask *dccg_mask)
{
struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
struct dccg *base;
if (dccg_dcn == NULL) {
BREAK_TO_DEBUGGER();
return NULL;
}
base = &dccg_dcn->base;
base->ctx = ctx;
base->funcs = &dccg2_funcs;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
return &dccg_dcn->base;
}
void dcn_dccg_destroy(struct dccg **dccg)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(*dccg);
kfree(dccg_dcn);
*dccg = NULL;
}
/*
* Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: AMD
*
*/
#ifndef __DCN20_DCCG_H__
#define __DCN20_DCCG_H__
#include "dccg.h"
#define DCCG_COMMON_REG_LIST_DCN_BASE() \
SR(DPPCLK_DTO_CTRL),\
DCCG_SRII(DTO_PARAM, DPPCLK, 0),\
DCCG_SRII(DTO_PARAM, DPPCLK, 1),\
DCCG_SRII(DTO_PARAM, DPPCLK, 2),\
DCCG_SRII(DTO_PARAM, DPPCLK, 3),\
SR(REFCLK_CNTL)
#define DCCG_REG_LIST_DCN2() \
DCCG_COMMON_REG_LIST_DCN_BASE(),\
DCCG_SRII(DTO_PARAM, DPPCLK, 4),\
DCCG_SRII(DTO_PARAM, DPPCLK, 5)
#define DCCG_SF(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix
#define DCCG_SFI(reg_name, field_name, field_prefix, inst, post_fix)\
.field_prefix ## _ ## field_name[inst] = reg_name ## __ ## field_prefix ## inst ## _ ## field_name ## post_fix
#define DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 1, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 1, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 2, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 2, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 3, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 3, mask_sh),\
DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\
DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\
DCCG_SF(REFCLK_CNTL, REFCLK_CLOCK_EN, mask_sh),\
DCCG_SF(REFCLK_CNTL, REFCLK_SRC_SEL, mask_sh)
#define DCCG_MASK_SH_LIST_DCN2(mask_sh) \
DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 4, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 4, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 5, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 5, mask_sh)
#define DCCG_REG_FIELD_LIST(type) \
type DPPCLK0_DTO_PHASE;\
type DPPCLK0_DTO_MODULO;\
type DPPCLK_DTO_ENABLE[6];\
type DPPCLK_DTO_DB_EN[6];\
type REFCLK_CLOCK_EN;\
type REFCLK_SRC_SEL;
struct dccg_shift {
DCCG_REG_FIELD_LIST(uint8_t)
};
struct dccg_mask {
DCCG_REG_FIELD_LIST(uint32_t)
};
struct dccg_registers {
uint32_t DPPCLK_DTO_CTRL;
uint32_t DPPCLK_DTO_PARAM[6];
uint32_t REFCLK_CNTL;
};
struct dcn_dccg {
struct dccg base;
const struct dccg_registers *regs;
const struct dccg_shift *dccg_shift;
const struct dccg_mask *dccg_mask;
};
void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk);
void dccg2_get_dccg_ref_freq(struct dccg *dccg,
unsigned int xtalin_freq_inKhz,
unsigned int *dccg_ref_freq_inKhz);
void dccg2_init(struct dccg *dccg);
struct dccg *dccg2_create(
struct dc_context *ctx,
const struct dccg_registers *regs,
const struct dccg_shift *dccg_shift,
const struct dccg_mask *dccg_mask);
void dcn_dccg_destroy(struct dccg **dccg);
#endif //__DCN20_DCCG_H__
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define __DAL_CLK_MGR_INTERNAL_H__ #define __DAL_CLK_MGR_INTERNAL_H__
#include "clk_mgr.h" #include "clk_mgr.h"
#include "dc.h"
/* /*
* only thing needed from here is MEMORY_TYPE_MULTIPLIER_CZ, which is also * only thing needed from here is MEMORY_TYPE_MULTIPLIER_CZ, which is also
...@@ -34,6 +35,29 @@ ...@@ -34,6 +35,29 @@
*/ */
#include "resource.h" #include "resource.h"
/* Starting DID for each range */
enum dentist_base_divider_id {
DENTIST_BASE_DID_1 = 0x08,
DENTIST_BASE_DID_2 = 0x40,
DENTIST_BASE_DID_3 = 0x60,
DENTIST_BASE_DID_4 = 0x7e,
DENTIST_MAX_DID = 0x7f
};
/* Starting point and step size for each divider range.*/
enum dentist_divider_range {
DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */
DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */
DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */
DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */
DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */
DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */
DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */
DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */
DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4
};
/* /*
*************************************************************************************** ***************************************************************************************
****************** Clock Manager Private Macros and Defines *************************** ****************** Clock Manager Private Macros and Defines ***************************
...@@ -65,6 +89,18 @@ ...@@ -65,6 +89,18 @@
#define CLK_COMMON_REG_LIST_DCN_BASE() \ #define CLK_COMMON_REG_LIST_DCN_BASE() \
SR(DENTIST_DISPCLK_CNTL) SR(DENTIST_DISPCLK_CNTL)
#define VBIOS_SMU_MSG_BOX_REG_LIST_RV() \
.MP1_SMN_C2PMSG_91 = mmMP1_SMN_C2PMSG_91, \
.MP1_SMN_C2PMSG_83 = mmMP1_SMN_C2PMSG_83, \
.MP1_SMN_C2PMSG_67 = mmMP1_SMN_C2PMSG_67
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
#define CLK_REG_LIST_NV10() \
SR(DENTIST_DISPCLK_CNTL), \
CLK_SRI(CLK3_CLK_PLL_REQ, CLK3, 0), \
CLK_SRI(CLK3_CLK2_DFS_CNTL, CLK3, 0)
#endif
#define CLK_SF(reg_name, field_name, post_fix)\ #define CLK_SF(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix .field_name = reg_name ## __ ## field_name ## post_fix
...@@ -82,6 +118,17 @@ ...@@ -82,6 +118,17 @@
CLK_SF(MP1_SMN_C2PMSG_83, CONTENT, mask_sh),\ CLK_SF(MP1_SMN_C2PMSG_83, CONTENT, mask_sh),\
CLK_SF(MP1_SMN_C2PMSG_91, CONTENT, mask_sh), CLK_SF(MP1_SMN_C2PMSG_91, CONTENT, mask_sh),
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
#define CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh) \
CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\
CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\
CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh)
#define CLK_MASK_SH_LIST_NV10(mask_sh) \
CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh),\
CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_int, mask_sh),\
CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_frac, mask_sh)
#endif
#define CLK_REG_FIELD_LIST(type) \ #define CLK_REG_FIELD_LIST(type) \
type DPREFCLK_SRC_SEL; \ type DPREFCLK_SRC_SEL; \
...@@ -94,21 +141,46 @@ ...@@ -94,21 +141,46 @@
****************** Clock Manager Private Structures *********************************** ****************** Clock Manager Private Structures ***********************************
*************************************************************************************** ***************************************************************************************
*/ */
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
#define CLK20_REG_FIELD_LIST(type) \
type DENTIST_DPPCLK_WDIVIDER; \
type DENTIST_DPPCLK_CHG_DONE; \
type FbMult_int; \
type FbMult_frac;
#endif
struct clk_mgr_registers { #define VBIOS_SMU_REG_FIELD_LIST(type) \
uint32_t DPREFCLK_CNTL; type CONTENT;
uint32_t DENTIST_DISPCLK_CNTL;
};
struct clk_mgr_shift { struct clk_mgr_shift {
CLK_REG_FIELD_LIST(uint8_t) CLK_REG_FIELD_LIST(uint8_t)
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
CLK20_REG_FIELD_LIST(uint8_t)
#endif
VBIOS_SMU_REG_FIELD_LIST(uint32_t)
}; };
struct clk_mgr_mask { struct clk_mgr_mask {
CLK_REG_FIELD_LIST(uint32_t) CLK_REG_FIELD_LIST(uint32_t)
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
CLK20_REG_FIELD_LIST(uint32_t)
#endif
VBIOS_SMU_REG_FIELD_LIST(uint32_t)
}; };
struct clk_mgr_registers {
uint32_t DPREFCLK_CNTL;
uint32_t DENTIST_DISPCLK_CNTL;
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
uint32_t CLK3_CLK2_DFS_CNTL;
uint32_t CLK3_CLK_PLL_REQ;
#endif
uint32_t MP1_SMN_C2PMSG_67;
uint32_t MP1_SMN_C2PMSG_83;
uint32_t MP1_SMN_C2PMSG_91;
};
struct state_dependent_clocks { struct state_dependent_clocks {
int display_clk_khz; int display_clk_khz;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment