summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dce120
diff options
context:
space:
mode:
authorLeo Li <sunpeng.li@amd.com>2018-11-01 18:10:18 +0300
committerAlex Deucher <alexander.deucher@amd.com>2019-01-14 23:04:41 +0300
commit508f5fcb54f0ad3b333a835f45e109feb9edf761 (patch)
treedbcd50971d2258e2e0133eda1d696dfb201edf6a /drivers/gpu/drm/amd/display/dc/dce120
parent09f609c34fc8b9cb560947ab11609259f5d42889 (diff)
downloadlinux-508f5fcb54f0ad3b333a835f45e109feb9edf761.tar.xz
drm/amd/display: Compensate for XGMI SS downspread on dprefclk
[Why] When XGMI is enabled, we need to adjust the dprefclk according to the WAFL link's spread spectrum info. This is for VG20 (DCE121) only. [How] dce_clk_mgr already stores SS info, currently being used by audio clock. Therefore, patch the clk_mgr's SS info with the xGMI SS info, if xGMI is enabled. For display clock, adjust it during dce12_update_clocks() before calling set_clock(). Since we rely on a mmhub register to reliably determine if xGMI is enabled, the patching step needs to happen after resource_construct() has initialized the hardware sequencer. Signed-off-by: Leo Li <sunpeng.li@amd.com> Reviewed-by: Hersen Wu <hersenxs.wu@amd.com> Acked-by: Harry Wentland <Harry.Wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce120')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c81
3 files changed, 90 insertions, 7 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
index eb0f5f9a973b..1ca30928025e 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c
@@ -244,6 +244,21 @@ static void dce120_update_dchub(
dh_data->dchub_info_valid = false;
}
+/**
+ * dce121_xgmi_enabled() - Check if xGMI is enabled
+ * @hws: DCE hardware sequencer object
+ *
+ * Return true if xGMI is enabled. False otherwise.
+ */
+bool dce121_xgmi_enabled(struct dce_hwseq *hws)
+{
+ uint32_t pf_max_region;
+
+ REG_GET(MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, &pf_max_region);
+ /* PF_MAX_REGION == 0 means xgmi is disabled */
+ return !!pf_max_region;
+}
+
void dce120_hw_sequencer_construct(struct dc *dc)
{
/* All registers used by dce11.2 match those in dce11 in offset and
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
index 77a6b86d7606..c51afbd0b012 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h
@@ -30,6 +30,7 @@
struct dc;
+bool dce121_xgmi_enabled(struct dce_hwseq *hws);
void dce120_hw_sequencer_construct(struct dc *dc);
#endif /* __DC_HWSS_DCE112_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
index f12696674eb0..48a210ec975b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
@@ -62,6 +62,8 @@
#include "soc15_hw_ip.h"
#include "vega10_ip_offset.h"
#include "nbio/nbio_6_1_offset.h"
+#include "mmhub/mmhub_9_4_0_offset.h"
+#include "mmhub/mmhub_9_4_0_sh_mask.h"
#include "reg_helper.h"
#include "dce100/dce100_resource.h"
@@ -139,6 +141,17 @@ static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = {
.reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
mm ## block ## id ## _ ## reg_name
+/* MMHUB */
+#define MMHUB_BASE_INNER(seg) \
+ MMHUB_BASE__INST0_SEG ## seg
+
+#define MMHUB_BASE(seg) \
+ MMHUB_BASE_INNER(seg)
+
+#define MMHUB_SR(reg_name)\
+ .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \
+ mm ## reg_name
+
/* macros to expend register list macro defined in HW object header file
* end *********************/
@@ -681,6 +694,19 @@ static const struct dce_hwseq_mask hwseq_mask = {
HWSEQ_DCE12_MASK_SH_LIST(_MASK)
};
+/* HWSEQ regs for VG20 */
+static const struct dce_hwseq_registers dce121_hwseq_reg = {
+ HWSEQ_VG20_REG_LIST()
+};
+
+static const struct dce_hwseq_shift dce121_hwseq_shift = {
+ HWSEQ_VG20_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_hwseq_mask dce121_hwseq_mask = {
+ HWSEQ_VG20_MASK_SH_LIST(_MASK)
+};
+
static struct dce_hwseq *dce120_hwseq_create(
struct dc_context *ctx)
{
@@ -695,6 +721,20 @@ static struct dce_hwseq *dce120_hwseq_create(
return hws;
}
+static struct dce_hwseq *dce121_hwseq_create(
+ struct dc_context *ctx)
+{
+ struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL);
+
+ if (hws) {
+ hws->ctx = ctx;
+ hws->regs = &dce121_hwseq_reg;
+ hws->shifts = &dce121_hwseq_shift;
+ hws->masks = &dce121_hwseq_mask;
+ }
+ return hws;
+}
+
static const struct resource_create_funcs res_create_funcs = {
.read_dce_straps = read_dce_straps,
.create_audio = create_audio,
@@ -702,6 +742,14 @@ static const struct resource_create_funcs res_create_funcs = {
.create_hwseq = dce120_hwseq_create,
};
+static const struct resource_create_funcs dce121_res_create_funcs = {
+ .read_dce_straps = read_dce_straps,
+ .create_audio = create_audio,
+ .create_stream_encoder = dce120_stream_encoder_create,
+ .create_hwseq = dce121_hwseq_create,
+};
+
+
#define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) }
static const struct dce_mem_input_registers mi_regs[] = {
mi_inst_regs(0),
@@ -911,7 +959,8 @@ static bool construct(
int j;
struct dc_context *ctx = dc->ctx;
struct irq_service_init_data irq_init_data;
- bool harvest_enabled = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev);
+ static const struct resource_create_funcs *res_funcs;
+ bool is_vg20 = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev);
uint32_t pipe_fuses;
ctx->dc_bios->regs = &bios_regs;
@@ -975,7 +1024,11 @@ static bool construct(
}
}
- pool->base.clk_mgr = dce120_clk_mgr_create(ctx);
+ if (is_vg20)
+ pool->base.clk_mgr = dce121_clk_mgr_create(ctx);
+ else
+ pool->base.clk_mgr = dce120_clk_mgr_create(ctx);
+
if (pool->base.clk_mgr == NULL) {
dm_error("DC: failed to create display clock!\n");
BREAK_TO_DEBUGGER();
@@ -1008,14 +1061,14 @@ static bool construct(
if (!pool->base.irqs)
goto irqs_create_fail;
- /* retrieve valid pipe fuses */
- if (harvest_enabled)
+ /* VG20: Pipe harvesting enabled, retrieve valid pipe fuses */
+ if (is_vg20)
pipe_fuses = read_pipe_fuses(ctx);
/* index to valid pipe resource */
j = 0;
for (i = 0; i < pool->base.pipe_count; i++) {
- if (harvest_enabled) {
+ if (is_vg20) {
if ((pipe_fuses & (1 << i)) != 0) {
dm_error("DC: skip invalid pipe %d!\n", i);
continue;
@@ -1093,10 +1146,24 @@ static bool construct(
pool->base.pipe_count = j;
pool->base.timing_generator_count = j;
- if (!resource_construct(num_virtual_links, dc, &pool->base,
- &res_create_funcs))
+ if (is_vg20)
+ res_funcs = &dce121_res_create_funcs;
+ else
+ res_funcs = &res_create_funcs;
+
+ if (!resource_construct(num_virtual_links, dc, &pool->base, res_funcs))
goto res_create_fail;
+ /*
+ * This is a bit of a hack. The xGMI enabled info is used to determine
+ * if audio and display clocks need to be adjusted with the WAFL link's
+ * SS info. This is a responsiblity of the clk_mgr. But since MMHUB is
+ * under hwseq, and the relevant register is in MMHUB, we have to do it
+ * here.
+ */
+ if (is_vg20 && dce121_xgmi_enabled(dc->hwseq))
+ dce121_clock_patch_xgmi_ss_info(pool->base.clk_mgr);
+
/* Create hardware sequencer */
if (!dce120_hw_sequencer_create(dc))
goto controller_create_fail;