File Index
Files and directories
Sign in
FILE

dcn32_hubbub.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/hubbub/dcn32/dcn32_hubbub.c C
   1/*
   2 * Copyright 2021 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
  27#include "dcn30/dcn30_hubbub.h"
  28#include "dcn32_hubbub.h"
  29#include "dm_services.h"
  30#include "reg_helper.h"
  31#include "dal_asic_id.h"
  32
  33
  34#define CTX \
  35	hubbub2->base.ctx
  36#define DC_LOGGER \
  37	hubbub2->base.ctx->logger
  38#define REG(reg)\
  39	hubbub2->regs->reg
  40
  41#undef FN
  42#define FN(reg_name, field_name) \
  43	hubbub2->shifts->field_name, hubbub2->masks->field_name
  44
  45/**
  46 * DCN32_CRB_SEGMENT_SIZE_KB: Maximum Configurable Return Buffer size for
  47 *                            DCN32
  48 */
  49#define DCN32_CRB_SEGMENT_SIZE_KB 64
  50
  51static void dcn32_init_crb(struct hubbub *hubbub)
  52{
  53	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
  54
  55	REG_GET(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT,
  56		&hubbub2->det0_size);
  57
  58	REG_GET(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT,
  59		&hubbub2->det1_size);
  60
  61	REG_GET(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT,
  62		&hubbub2->det2_size);
  63
  64	REG_GET(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT,
  65		&hubbub2->det3_size);
  66
  67	REG_GET(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT,
  68		&hubbub2->compbuf_size_segments);
  69
  70	REG_SET_2(COMPBUF_RESERVED_SPACE, 0,
  71			COMPBUF_RESERVED_SPACE_64B, hubbub2->pixel_chunk_size / 32,
  72			COMPBUF_RESERVED_SPACE_ZS, hubbub2->pixel_chunk_size / 128);
  73	REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x47F);
  74}
  75
  76static void hubbub32_set_sdp_control(struct hubbub *hubbub, bool dc_control)
  77{
  78	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
  79
  80	REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
  81			SDPIF_PORT_CONTROL, dc_control);
  82}
  83
  84void hubbub32_set_request_limit(struct hubbub *hubbub, int memory_channel_count, int words_per_channel)
  85{
  86	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
  87
  88	uint32_t request_limit = 3 * memory_channel_count * words_per_channel / 4;
  89
  90	ASSERT((request_limit & (~0xFFF)) == 0); //field is only 24 bits long
  91	ASSERT(request_limit > 0); //field is only 24 bits long
  92
  93	if (request_limit > 0xFFF)
  94		request_limit = 0xFFF;
  95
  96	if (request_limit > 0)
  97		REG_UPDATE(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, request_limit);
  98}
  99
 100
 101void dcn32_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte)
 102{
 103	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 104
 105	unsigned int det_size_segments = (det_buffer_size_in_kbyte + DCN32_CRB_SEGMENT_SIZE_KB - 1) / DCN32_CRB_SEGMENT_SIZE_KB;
 106
 107	switch (hubp_inst) {
 108	case 0:
 109		REG_UPDATE(DCHUBBUB_DET0_CTRL,
 110					DET0_SIZE, det_size_segments);
 111		hubbub2->det0_size = det_size_segments;
 112		break;
 113	case 1:
 114		REG_UPDATE(DCHUBBUB_DET1_CTRL,
 115					DET1_SIZE, det_size_segments);
 116		hubbub2->det1_size = det_size_segments;
 117		break;
 118	case 2:
 119		REG_UPDATE(DCHUBBUB_DET2_CTRL,
 120					DET2_SIZE, det_size_segments);
 121		hubbub2->det2_size = det_size_segments;
 122		break;
 123	case 3:
 124		REG_UPDATE(DCHUBBUB_DET3_CTRL,
 125					DET3_SIZE, det_size_segments);
 126		hubbub2->det3_size = det_size_segments;
 127		break;
 128	default:
 129		break;
 130	}
 131	if (hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size
 132			+ hubbub2->det3_size + hubbub2->compbuf_size_segments > hubbub2->crb_size_segs) {
 133		/* This may happen during seamless transition from ODM 2:1 to ODM4:1 */
 134		DC_LOG_WARNING("CRB Config Warning: DET size (%d,%d,%d,%d) + Compbuf size (%d) >  CRB segments (%d)\n",
 135						hubbub2->det0_size, hubbub2->det1_size, hubbub2->det2_size, hubbub2->det3_size,
 136						hubbub2->compbuf_size_segments, hubbub2->crb_size_segs);
 137	}
 138}
 139
 140void dcn32_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase)
 141{
 142	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 143	unsigned int compbuf_size_segments = (compbuf_size_kb + DCN32_CRB_SEGMENT_SIZE_KB - 1) / DCN32_CRB_SEGMENT_SIZE_KB;
 144
 145	if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) {
 146		if (compbuf_size_segments > hubbub2->compbuf_size_segments) {
 147			REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100);
 148			REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100);
 149			REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100);
 150			REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100);
 151		}
 152		/* Should never be hit, if it is we have an erroneous hw config*/
 153		ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size
 154				+ hubbub2->det3_size + compbuf_size_segments <= hubbub2->crb_size_segs);
 155		REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_segments);
 156		hubbub2->compbuf_size_segments = compbuf_size_segments;
 157		ASSERT(REG_GET(DCHUBBUB_COMPBUF_CTRL, CONFIG_ERROR, &compbuf_size_segments) && !compbuf_size_segments);
 158	}
 159}
 160
 161static uint32_t convert_and_clamp(
 162	uint32_t wm_ns,
 163	uint32_t refclk_mhz,
 164	uint32_t clamp_value)
 165{
 166	uint32_t ret_val = 0;
 167	ret_val = wm_ns * refclk_mhz;
 168
 169	ret_val /= 1000;
 170
 171	if (ret_val > clamp_value)
 172		ret_val = clamp_value;
 173
 174	return ret_val;
 175}
 176
 177bool hubbub32_program_urgent_watermarks(
 178		struct hubbub *hubbub,
 179		union dcn_watermark_set *watermarks,
 180		unsigned int refclk_mhz,
 181		bool safe_to_lower)
 182{
 183	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 184	uint32_t prog_wm_value;
 185	bool wm_pending = false;
 186
 187	/* Repeat for water mark set A, B, C and D. */
 188	/* clock state A */
 189	if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) {
 190		hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
 191		prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
 192				refclk_mhz, 0x3fff);
 193		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
 194				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
 195
 196		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
 197			"HW register value = 0x%x\n",
 198			watermarks->a.urgent_ns, prog_wm_value);
 199	} else if (watermarks->a.urgent_ns < hubbub2->watermarks.a.urgent_ns)
 200		wm_pending = true;
 201
 202	/* determine the transfer time for a quantity of data for a particular requestor.*/
 203	if (safe_to_lower || watermarks->a.frac_urg_bw_flip
 204			> hubbub2->watermarks.a.frac_urg_bw_flip) {
 205		hubbub2->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
 206
 207		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
 208				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip);
 209	} else if (watermarks->a.frac_urg_bw_flip
 210			< hubbub2->watermarks.a.frac_urg_bw_flip)
 211		wm_pending = true;
 212
 213	if (safe_to_lower || watermarks->a.frac_urg_bw_nom
 214			> hubbub2->watermarks.a.frac_urg_bw_nom) {
 215		hubbub2->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
 216
 217		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
 218				DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom);
 219	} else if (watermarks->a.frac_urg_bw_nom
 220			< hubbub2->watermarks.a.frac_urg_bw_nom)
 221		wm_pending = true;
 222
 223	if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) {
 224		hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
 225		prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
 226				refclk_mhz, 0x3fff);
 227		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
 228				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
 229	} else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns)
 230		wm_pending = true;
 231
 232	/* clock state B */
 233	if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) {
 234		hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
 235		prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
 236				refclk_mhz, 0x3fff);
 237		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
 238				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
 239
 240		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
 241			"HW register value = 0x%x\n",
 242			watermarks->b.urgent_ns, prog_wm_value);
 243	} else if (watermarks->b.urgent_ns < hubbub2->watermarks.b.urgent_ns)
 244		wm_pending = true;
 245
 246	/* determine the transfer time for a quantity of data for a particular requestor.*/
 247	if (safe_to_lower || watermarks->b.frac_urg_bw_flip
 248			> hubbub2->watermarks.b.frac_urg_bw_flip) {
 249		hubbub2->watermarks.b.frac_urg_bw_flip = watermarks->b.frac_urg_bw_flip;
 250
 251		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
 252				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->b.frac_urg_bw_flip);
 253	} else if (watermarks->b.frac_urg_bw_flip
 254			< hubbub2->watermarks.b.frac_urg_bw_flip)
 255		wm_pending = true;
 256
 257	if (safe_to_lower || watermarks->b.frac_urg_bw_nom
 258			> hubbub2->watermarks.b.frac_urg_bw_nom) {
 259		hubbub2->watermarks.b.frac_urg_bw_nom = watermarks->b.frac_urg_bw_nom;
 260
 261		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
 262				DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->b.frac_urg_bw_nom);
 263	} else if (watermarks->b.frac_urg_bw_nom
 264			< hubbub2->watermarks.b.frac_urg_bw_nom)
 265		wm_pending = true;
 266
 267	if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) {
 268		hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
 269		prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
 270				refclk_mhz, 0x3fff);
 271		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
 272				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
 273	} else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns)
 274		wm_pending = true;
 275
 276	/* clock state C */
 277	if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) {
 278		hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
 279		prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
 280				refclk_mhz, 0x3fff);
 281		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
 282				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
 283
 284		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
 285			"HW register value = 0x%x\n",
 286			watermarks->c.urgent_ns, prog_wm_value);
 287	} else if (watermarks->c.urgent_ns < hubbub2->watermarks.c.urgent_ns)
 288		wm_pending = true;
 289
 290	/* determine the transfer time for a quantity of data for a particular requestor.*/
 291	if (safe_to_lower || watermarks->c.frac_urg_bw_flip
 292			> hubbub2->watermarks.c.frac_urg_bw_flip) {
 293		hubbub2->watermarks.c.frac_urg_bw_flip = watermarks->c.frac_urg_bw_flip;
 294
 295		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0,
 296				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->c.frac_urg_bw_flip);
 297	} else if (watermarks->c.frac_urg_bw_flip
 298			< hubbub2->watermarks.c.frac_urg_bw_flip)
 299		wm_pending = true;
 300
 301	if (safe_to_lower || watermarks->c.frac_urg_bw_nom
 302			> hubbub2->watermarks.c.frac_urg_bw_nom) {
 303		hubbub2->watermarks.c.frac_urg_bw_nom = watermarks->c.frac_urg_bw_nom;
 304
 305		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0,
 306				DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->c.frac_urg_bw_nom);
 307	} else if (watermarks->c.frac_urg_bw_nom
 308			< hubbub2->watermarks.c.frac_urg_bw_nom)
 309		wm_pending = true;
 310
 311	if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) {
 312		hubbub2->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
 313		prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
 314				refclk_mhz, 0x3fff);
 315		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
 316				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
 317	} else if (watermarks->c.urgent_latency_ns < hubbub2->watermarks.c.urgent_latency_ns)
 318		wm_pending = true;
 319
 320	/* clock state D */
 321	if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) {
 322		hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
 323		prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
 324				refclk_mhz, 0x3fff);
 325		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
 326				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
 327
 328		DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
 329			"HW register value = 0x%x\n",
 330			watermarks->d.urgent_ns, prog_wm_value);
 331	} else if (watermarks->d.urgent_ns < hubbub2->watermarks.d.urgent_ns)
 332		wm_pending = true;
 333
 334	/* determine the transfer time for a quantity of data for a particular requestor.*/
 335	if (safe_to_lower || watermarks->d.frac_urg_bw_flip
 336			> hubbub2->watermarks.d.frac_urg_bw_flip) {
 337		hubbub2->watermarks.d.frac_urg_bw_flip = watermarks->d.frac_urg_bw_flip;
 338
 339		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
 340				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->d.frac_urg_bw_flip);
 341	} else if (watermarks->d.frac_urg_bw_flip
 342			< hubbub2->watermarks.d.frac_urg_bw_flip)
 343		wm_pending = true;
 344
 345	if (safe_to_lower || watermarks->d.frac_urg_bw_nom
 346			> hubbub2->watermarks.d.frac_urg_bw_nom) {
 347		hubbub2->watermarks.d.frac_urg_bw_nom = watermarks->d.frac_urg_bw_nom;
 348
 349		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
 350				DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->d.frac_urg_bw_nom);
 351	} else if (watermarks->d.frac_urg_bw_nom
 352			< hubbub2->watermarks.d.frac_urg_bw_nom)
 353		wm_pending = true;
 354
 355	if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) {
 356		hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
 357		prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
 358				refclk_mhz, 0x3fff);
 359		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
 360				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
 361	} else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns)
 362		wm_pending = true;
 363
 364	return wm_pending;
 365}
 366
 367bool hubbub32_program_stutter_watermarks(
 368		struct hubbub *hubbub,
 369		union dcn_watermark_set *watermarks,
 370		unsigned int refclk_mhz,
 371		bool safe_to_lower)
 372{
 373	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 374	uint32_t prog_wm_value;
 375	bool wm_pending = false;
 376
 377	/* clock state A */
 378	if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
 379			> hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
 380		hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
 381				watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
 382		prog_wm_value = convert_and_clamp(
 383				watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
 384				refclk_mhz, 0xffff);
 385		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
 386				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
 387		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
 388			"HW register value = 0x%x\n",
 389			watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 390	} else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
 391			< hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns)
 392		wm_pending = true;
 393
 394	if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
 395			> hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) {
 396		hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns =
 397				watermarks->a.cstate_pstate.cstate_exit_ns;
 398		prog_wm_value = convert_and_clamp(
 399				watermarks->a.cstate_pstate.cstate_exit_ns,
 400				refclk_mhz, 0xffff);
 401		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
 402				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
 403		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
 404			"HW register value = 0x%x\n",
 405			watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
 406	} else if (watermarks->a.cstate_pstate.cstate_exit_ns
 407			< hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns)
 408		wm_pending = true;
 409
 410	/* clock state B */
 411	if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
 412			> hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
 413		hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
 414				watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
 415		prog_wm_value = convert_and_clamp(
 416				watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
 417				refclk_mhz, 0xffff);
 418		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
 419				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
 420		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
 421			"HW register value = 0x%x\n",
 422			watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 423	} else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
 424			< hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns)
 425		wm_pending = true;
 426
 427	if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
 428			> hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) {
 429		hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns =
 430				watermarks->b.cstate_pstate.cstate_exit_ns;
 431		prog_wm_value = convert_and_clamp(
 432				watermarks->b.cstate_pstate.cstate_exit_ns,
 433				refclk_mhz, 0xffff);
 434		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
 435				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
 436		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
 437			"HW register value = 0x%x\n",
 438			watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
 439	} else if (watermarks->b.cstate_pstate.cstate_exit_ns
 440			< hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns)
 441		wm_pending = true;
 442
 443	/* clock state C */
 444	if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
 445			> hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
 446		hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
 447				watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
 448		prog_wm_value = convert_and_clamp(
 449				watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
 450				refclk_mhz, 0xffff);
 451		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
 452				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
 453		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
 454			"HW register value = 0x%x\n",
 455			watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 456	} else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
 457			< hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns)
 458		wm_pending = true;
 459
 460	if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
 461			> hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) {
 462		hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns =
 463				watermarks->c.cstate_pstate.cstate_exit_ns;
 464		prog_wm_value = convert_and_clamp(
 465				watermarks->c.cstate_pstate.cstate_exit_ns,
 466				refclk_mhz, 0xffff);
 467		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
 468				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
 469		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
 470			"HW register value = 0x%x\n",
 471			watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
 472	} else if (watermarks->c.cstate_pstate.cstate_exit_ns
 473			< hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns)
 474		wm_pending = true;
 475
 476	/* clock state D */
 477	if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
 478			> hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
 479		hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
 480				watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
 481		prog_wm_value = convert_and_clamp(
 482				watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
 483				refclk_mhz, 0xffff);
 484		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
 485				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
 486		DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
 487			"HW register value = 0x%x\n",
 488			watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 489	} else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
 490			< hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns)
 491		wm_pending = true;
 492
 493	if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
 494			> hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) {
 495		hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns =
 496				watermarks->d.cstate_pstate.cstate_exit_ns;
 497		prog_wm_value = convert_and_clamp(
 498				watermarks->d.cstate_pstate.cstate_exit_ns,
 499				refclk_mhz, 0xffff);
 500		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
 501				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
 502		DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
 503			"HW register value = 0x%x\n",
 504			watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
 505	} else if (watermarks->d.cstate_pstate.cstate_exit_ns
 506			< hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns)
 507		wm_pending = true;
 508
 509	return wm_pending;
 510}
 511
 512
 513bool hubbub32_program_pstate_watermarks(
 514		struct hubbub *hubbub,
 515		union dcn_watermark_set *watermarks,
 516		unsigned int refclk_mhz,
 517		bool safe_to_lower)
 518{
 519	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 520	uint32_t prog_wm_value;
 521
 522	bool wm_pending = false;
 523
 524	/* Section for UCLK_PSTATE_CHANGE_WATERMARKS */
 525	/* clock state A */
 526	if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
 527			> hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) {
 528		hubbub2->watermarks.a.cstate_pstate.pstate_change_ns =
 529				watermarks->a.cstate_pstate.pstate_change_ns;
 530		prog_wm_value = convert_and_clamp(
 531				watermarks->a.cstate_pstate.pstate_change_ns,
 532				refclk_mhz, 0xffff);
 533		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, 0,
 534				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, prog_wm_value);
 535		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
 536			"HW register value = 0x%x\n\n",
 537			watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
 538	} else if (watermarks->a.cstate_pstate.pstate_change_ns
 539			< hubbub2->watermarks.a.cstate_pstate.pstate_change_ns)
 540		wm_pending = true;
 541
 542	/* clock state B */
 543	if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
 544			> hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) {
 545		hubbub2->watermarks.b.cstate_pstate.pstate_change_ns =
 546				watermarks->b.cstate_pstate.pstate_change_ns;
 547		prog_wm_value = convert_and_clamp(
 548				watermarks->b.cstate_pstate.pstate_change_ns,
 549				refclk_mhz, 0xffff);
 550		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, 0,
 551				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, prog_wm_value);
 552		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
 553			"HW register value = 0x%x\n\n",
 554			watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
 555	} else if (watermarks->b.cstate_pstate.pstate_change_ns
 556			< hubbub2->watermarks.b.cstate_pstate.pstate_change_ns)
 557		wm_pending = true;
 558
 559	/* clock state C */
 560	if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
 561			> hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) {
 562		hubbub2->watermarks.c.cstate_pstate.pstate_change_ns =
 563				watermarks->c.cstate_pstate.pstate_change_ns;
 564		prog_wm_value = convert_and_clamp(
 565				watermarks->c.cstate_pstate.pstate_change_ns,
 566				refclk_mhz, 0xffff);
 567		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, 0,
 568				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, prog_wm_value);
 569		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
 570			"HW register value = 0x%x\n\n",
 571			watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
 572	} else if (watermarks->c.cstate_pstate.pstate_change_ns
 573			< hubbub2->watermarks.c.cstate_pstate.pstate_change_ns)
 574		wm_pending = true;
 575
 576	/* clock state D */
 577	if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
 578			> hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) {
 579		hubbub2->watermarks.d.cstate_pstate.pstate_change_ns =
 580				watermarks->d.cstate_pstate.pstate_change_ns;
 581		prog_wm_value = convert_and_clamp(
 582				watermarks->d.cstate_pstate.pstate_change_ns,
 583				refclk_mhz, 0xffff);
 584		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, 0,
 585				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, prog_wm_value);
 586		DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
 587			"HW register value = 0x%x\n\n",
 588			watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
 589	} else if (watermarks->d.cstate_pstate.pstate_change_ns
 590			< hubbub2->watermarks.d.cstate_pstate.pstate_change_ns)
 591		wm_pending = true;
 592
 593	/* Section for FCLK_PSTATE_CHANGE_WATERMARKS */
 594	/* clock state A */
 595	if (safe_to_lower || watermarks->a.cstate_pstate.fclk_pstate_change_ns
 596			> hubbub2->watermarks.a.cstate_pstate.fclk_pstate_change_ns) {
 597		hubbub2->watermarks.a.cstate_pstate.fclk_pstate_change_ns =
 598				watermarks->a.cstate_pstate.fclk_pstate_change_ns;
 599		prog_wm_value = convert_and_clamp(
 600				watermarks->a.cstate_pstate.fclk_pstate_change_ns,
 601				refclk_mhz, 0xffff);
 602		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, 0,
 603				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, prog_wm_value);
 604		DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_A calculated =%d\n"
 605			"HW register value = 0x%x\n\n",
 606			watermarks->a.cstate_pstate.fclk_pstate_change_ns, prog_wm_value);
 607	} else if (watermarks->a.cstate_pstate.fclk_pstate_change_ns
 608			< hubbub2->watermarks.a.cstate_pstate.fclk_pstate_change_ns)
 609		wm_pending = true;
 610
 611	/* clock state B */
 612	if (safe_to_lower || watermarks->b.cstate_pstate.fclk_pstate_change_ns
 613			> hubbub2->watermarks.b.cstate_pstate.fclk_pstate_change_ns) {
 614		hubbub2->watermarks.b.cstate_pstate.fclk_pstate_change_ns =
 615				watermarks->b.cstate_pstate.fclk_pstate_change_ns;
 616		prog_wm_value = convert_and_clamp(
 617				watermarks->b.cstate_pstate.fclk_pstate_change_ns,
 618				refclk_mhz, 0xffff);
 619		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, 0,
 620				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, prog_wm_value);
 621		DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_B calculated =%d\n"
 622			"HW register value = 0x%x\n\n",
 623			watermarks->b.cstate_pstate.fclk_pstate_change_ns, prog_wm_value);
 624	} else if (watermarks->b.cstate_pstate.fclk_pstate_change_ns
 625			< hubbub2->watermarks.b.cstate_pstate.fclk_pstate_change_ns)
 626		wm_pending = true;
 627
 628	/* clock state C */
 629	if (safe_to_lower || watermarks->c.cstate_pstate.fclk_pstate_change_ns
 630			> hubbub2->watermarks.c.cstate_pstate.fclk_pstate_change_ns) {
 631		hubbub2->watermarks.c.cstate_pstate.fclk_pstate_change_ns =
 632				watermarks->c.cstate_pstate.fclk_pstate_change_ns;
 633		prog_wm_value = convert_and_clamp(
 634				watermarks->c.cstate_pstate.fclk_pstate_change_ns,
 635				refclk_mhz, 0xffff);
 636		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, 0,
 637				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, prog_wm_value);
 638		DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_C calculated =%d\n"
 639			"HW register value = 0x%x\n\n",
 640			watermarks->c.cstate_pstate.fclk_pstate_change_ns, prog_wm_value);
 641	} else if (watermarks->c.cstate_pstate.fclk_pstate_change_ns
 642			< hubbub2->watermarks.c.cstate_pstate.fclk_pstate_change_ns)
 643		wm_pending = true;
 644
 645	/* clock state D */
 646	if (safe_to_lower || watermarks->d.cstate_pstate.fclk_pstate_change_ns
 647			> hubbub2->watermarks.d.cstate_pstate.fclk_pstate_change_ns) {
 648		hubbub2->watermarks.d.cstate_pstate.fclk_pstate_change_ns =
 649				watermarks->d.cstate_pstate.fclk_pstate_change_ns;
 650		prog_wm_value = convert_and_clamp(
 651				watermarks->d.cstate_pstate.fclk_pstate_change_ns,
 652				refclk_mhz, 0xffff);
 653		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, 0,
 654				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, prog_wm_value);
 655		DC_LOG_BANDWIDTH_CALCS("FCLK_CHANGE_WATERMARK_D calculated =%d\n"
 656			"HW register value = 0x%x\n\n",
 657			watermarks->d.cstate_pstate.fclk_pstate_change_ns, prog_wm_value);
 658	} else if (watermarks->d.cstate_pstate.fclk_pstate_change_ns
 659			< hubbub2->watermarks.d.cstate_pstate.fclk_pstate_change_ns)
 660		wm_pending = true;
 661
 662	return wm_pending;
 663}
 664
 665
 666bool hubbub32_program_usr_watermarks(
 667		struct hubbub *hubbub,
 668		union dcn_watermark_set *watermarks,
 669		unsigned int refclk_mhz,
 670		bool safe_to_lower)
 671{
 672	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 673	uint32_t prog_wm_value;
 674
 675	bool wm_pending = false;
 676
 677	/* clock state A */
 678	if (safe_to_lower || watermarks->a.usr_retraining_ns
 679			> hubbub2->watermarks.a.usr_retraining_ns) {
 680		hubbub2->watermarks.a.usr_retraining_ns = watermarks->a.usr_retraining_ns;
 681		prog_wm_value = convert_and_clamp(
 682				watermarks->a.usr_retraining_ns,
 683				refclk_mhz, 0x3fff);
 684		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, 0,
 685				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, prog_wm_value);
 686		DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_A calculated =%d\n"
 687			"HW register value = 0x%x\n\n",
 688			watermarks->a.usr_retraining_ns, prog_wm_value);
 689	} else if (watermarks->a.usr_retraining_ns
 690			< hubbub2->watermarks.a.usr_retraining_ns)
 691		wm_pending = true;
 692
 693	/* clock state B */
 694	if (safe_to_lower || watermarks->b.usr_retraining_ns
 695			> hubbub2->watermarks.b.usr_retraining_ns) {
 696		hubbub2->watermarks.b.usr_retraining_ns = watermarks->b.usr_retraining_ns;
 697		prog_wm_value = convert_and_clamp(
 698				watermarks->b.usr_retraining_ns,
 699				refclk_mhz, 0x3fff);
 700		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, 0,
 701				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, prog_wm_value);
 702		DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_B calculated =%d\n"
 703			"HW register value = 0x%x\n\n",
 704			watermarks->b.usr_retraining_ns, prog_wm_value);
 705	} else if (watermarks->b.usr_retraining_ns
 706			< hubbub2->watermarks.b.usr_retraining_ns)
 707		wm_pending = true;
 708
 709	/* clock state C */
 710	if (safe_to_lower || watermarks->c.usr_retraining_ns
 711			> hubbub2->watermarks.c.usr_retraining_ns) {
 712		hubbub2->watermarks.c.usr_retraining_ns =
 713				watermarks->c.usr_retraining_ns;
 714		prog_wm_value = convert_and_clamp(
 715				watermarks->c.usr_retraining_ns,
 716				refclk_mhz, 0x3fff);
 717		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, 0,
 718				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, prog_wm_value);
 719		DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_C calculated =%d\n"
 720			"HW register value = 0x%x\n\n",
 721			watermarks->c.usr_retraining_ns, prog_wm_value);
 722	} else if (watermarks->c.usr_retraining_ns
 723			< hubbub2->watermarks.c.usr_retraining_ns)
 724		wm_pending = true;
 725
 726	/* clock state D */
 727	if (safe_to_lower || watermarks->d.usr_retraining_ns
 728			> hubbub2->watermarks.d.usr_retraining_ns) {
 729		hubbub2->watermarks.d.usr_retraining_ns =
 730				watermarks->d.usr_retraining_ns;
 731		prog_wm_value = convert_and_clamp(
 732				watermarks->d.usr_retraining_ns,
 733				refclk_mhz, 0x3fff);
 734		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, 0,
 735				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, prog_wm_value);
 736		DC_LOG_BANDWIDTH_CALCS("USR_RETRAINING_WATERMARK_D calculated =%d\n"
 737			"HW register value = 0x%x\n\n",
 738			watermarks->d.usr_retraining_ns, prog_wm_value);
 739	} else if (watermarks->d.usr_retraining_ns
 740			< hubbub2->watermarks.d.usr_retraining_ns)
 741		wm_pending = true;
 742
 743	return wm_pending;
 744}
 745
 746void hubbub32_force_usr_retraining_allow(struct hubbub *hubbub, bool allow)
 747{
 748	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 749
 750	/*
 751	 * DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_ENABLE = 1 means enabling forcing value
 752	 * DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_VALUE = 1 or 0,  means value to be forced when force enable
 753	 */
 754
 755	REG_UPDATE_2(DCHUBBUB_ARB_USR_RETRAINING_CNTL,
 756			DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_VALUE, allow,
 757			DCHUBBUB_ARB_ALLOW_USR_RETRAINING_FORCE_ENABLE, allow);
 758}
 759
 760static bool hubbub32_program_watermarks(
 761		struct hubbub *hubbub,
 762		union dcn_watermark_set *watermarks,
 763		unsigned int refclk_mhz,
 764		bool safe_to_lower)
 765{
 766	struct dc *dc = hubbub->ctx->dc;
 767	bool wm_pending = false;
 768
 769	if (!safe_to_lower && dc->debug.disable_stutter_for_wm_program &&
 770			(ASICREV_IS_GC_11_0_0(dc->ctx->asic_id.hw_internal_rev) ||
 771			ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev))) {
 772		/* before raising watermarks, SDP control give to DF, stutter must be disabled */
 773		wm_pending = true;
 774		hubbub32_set_sdp_control(hubbub, false);
 775		hubbub1_allow_self_refresh_control(hubbub, false);
 776	}
 777
 778	if (hubbub32_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
 779		wm_pending = true;
 780
 781	if (hubbub32_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
 782		wm_pending = true;
 783
 784	if (hubbub32_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
 785		wm_pending = true;
 786
 787	if (hubbub32_program_usr_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
 788		wm_pending = true;
 789
 790	/*
 791	 * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
 792	 * If the memory controller is fully utilized and the DCHub requestors are
 793	 * well ahead of their amortized schedule, then it is safe to prevent the next winner
 794	 * from being committed and sent to the fabric.
 795	 * The utilization of the memory controller is approximated by ensuring that
 796	 * the number of outstanding requests is greater than a threshold specified
 797	 * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
 798	 * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
 799	 *
 800	 * TODO: Revisit request limit after figure out right number. request limit for RM isn't decided yet, set maximum value (0x1FF)
 801	 * to turn off it for now.
 802	 */
 803	/*REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
 804			DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
 805	REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
 806			DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);*/
 807
 808	if (safe_to_lower) {
 809		/* after lowering watermarks, stutter setting is restored, SDP control given to DC */
 810		hubbub1_allow_self_refresh_control(hubbub, !dc->debug.disable_stutter);
 811
 812		if (dc->debug.disable_stutter_for_wm_program &&
 813				(ASICREV_IS_GC_11_0_0(dc->ctx->asic_id.hw_internal_rev) ||
 814				ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev))) {
 815			hubbub32_set_sdp_control(hubbub, true);
 816		}
 817	} else if (dc->debug.disable_stutter) {
 818		hubbub1_allow_self_refresh_control(hubbub, !dc->debug.disable_stutter);
 819	}
 820
 821	hubbub32_force_usr_retraining_allow(hubbub, dc->debug.force_usr_allow);
 822
 823	return wm_pending;
 824}
 825
 826/* Copy values from WM set A to all other sets */
 827static void hubbub32_init_watermarks(struct hubbub *hubbub)
 828{
 829	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 830	uint32_t reg;
 831
 832	reg = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
 833	REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, reg);
 834	REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, reg);
 835	REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, reg);
 836
 837	reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A);
 838	REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, reg);
 839	REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, reg);
 840	REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, reg);
 841
 842	reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A);
 843	REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, reg);
 844	REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, reg);
 845	REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, reg);
 846
 847	reg = REG_READ(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A);
 848	REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, reg);
 849	REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, reg);
 850	REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, reg);
 851
 852	reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
 853	REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, reg);
 854	REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, reg);
 855	REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, reg);
 856
 857	reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
 858	REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, reg);
 859	REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, reg);
 860	REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, reg);
 861
 862	reg = REG_READ(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A);
 863	REG_WRITE(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, reg);
 864	REG_WRITE(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, reg);
 865	REG_WRITE(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, reg);
 866
 867	reg = REG_READ(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A);
 868	REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, reg);
 869	REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, reg);
 870	REG_WRITE(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, reg);
 871
 872	reg = REG_READ(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A);
 873	REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, reg);
 874	REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, reg);
 875	REG_WRITE(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, reg);
 876}
 877
 878static void hubbub32_wm_read_state(struct hubbub *hubbub,
 879		struct dcn_hubbub_wm *wm)
 880{
 881	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 882	struct dcn_hubbub_wm_set *s;
 883
 884	memset(wm, 0, sizeof(struct dcn_hubbub_wm));
 885
 886	s = &wm->sets[0];
 887	s->wm_set = 0;
 888	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A,
 889			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent);
 890
 891	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A,
 892			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter);
 893
 894	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A,
 895			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit);
 896
 897	REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A,
 898			 DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, &s->dram_clk_change);
 899
 900	REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A,
 901			 DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, &s->usr_retrain);
 902
 903	REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A,
 904			 DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, &s->fclk_pstate_change);
 905
 906	s = &wm->sets[1];
 907	s->wm_set = 1;
 908	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B,
 909			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent);
 910
 911	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B,
 912			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter);
 913
 914	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B,
 915			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit);
 916
 917	REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B,
 918			DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, &s->dram_clk_change);
 919
 920	REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B,
 921			 DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, &s->usr_retrain);
 922
 923	REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B,
 924			DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, &s->fclk_pstate_change);
 925
 926	s = &wm->sets[2];
 927	s->wm_set = 2;
 928	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C,
 929			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent);
 930
 931	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C,
 932			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter);
 933
 934	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C,
 935			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit);
 936
 937	REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C,
 938			DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, &s->dram_clk_change);
 939
 940	REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C,
 941			 DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, &s->usr_retrain);
 942
 943	REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C,
 944			DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, &s->fclk_pstate_change);
 945
 946	s = &wm->sets[3];
 947	s->wm_set = 3;
 948	REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D,
 949			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent);
 950
 951	REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D,
 952			DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter);
 953
 954	REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D,
 955			DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit);
 956
 957	REG_GET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D,
 958			DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, &s->dram_clk_change);
 959
 960	REG_GET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D,
 961			 DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, &s->usr_retrain);
 962
 963	REG_GET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D,
 964			DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, &s->fclk_pstate_change);
 965}
 966
 967void hubbub32_force_wm_propagate_to_pipes(struct hubbub *hubbub)
 968{
 969	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 970	uint32_t refclk_mhz = hubbub->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
 971	uint32_t prog_wm_value = convert_and_clamp(hubbub2->watermarks.a.urgent_ns,
 972			refclk_mhz, 0x3fff);
 973
 974	REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
 975			DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
 976}
 977
 978void hubbub32_get_mall_en(struct hubbub *hubbub, unsigned int *mall_in_use)
 979{
 980	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 981	uint32_t prefetch_complete, mall_en;
 982
 983	REG_GET_2(DCHUBBUB_ARB_MALL_CNTL, MALL_IN_USE, &mall_en,
 984			  MALL_PREFETCH_COMPLETE, &prefetch_complete);
 985
 986	*mall_in_use = prefetch_complete && mall_en;
 987}
 988
 989void hubbub32_init(struct hubbub *hubbub)
 990{
 991	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
 992
 993	/* Enable clock gate*/
 994	if (hubbub->ctx->dc->debug.disable_clock_gate) {
 995		/*done in hwseq*/
 996		/*REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);*/
 997
 998		REG_UPDATE_2(DCHUBBUB_CLOCK_CNTL,
 999			DISPCLK_R_DCHUBBUB_GATE_DIS, 1,
1000			DCFCLK_R_DCHUBBUB_GATE_DIS, 1);
1001	}
1002	/*
1003	ignore the "df_pre_cstate_req" from the SDP port control.
1004	only the DCN will determine when to connect the SDP port
1005	*/
1006	hubbub32_set_sdp_control(hubbub, true);
1007	/*Set SDP's max outstanding request to 512
1008	must set the register back to 0 (max outstanding = 256) in zero frame buffer mode*/
1009	REG_UPDATE(DCHUBBUB_SDPIF_CFG1,
1010			SDPIF_MAX_NUM_OUTSTANDING, 1);
1011	/*must set the registers back to 256 in zero frame buffer mode*/
1012	REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
1013			DCHUBBUB_ARB_MAX_REQ_OUTSTAND, 512,
1014			DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 512);
1015}
1016
1017static const struct hubbub_funcs hubbub32_funcs = {
1018	.update_dchub = hubbub2_update_dchub,
1019	.init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx,
1020	.init_vm_ctx = hubbub2_init_vm_ctx,
1021	.dcc_support_swizzle = hubbub3_dcc_support_swizzle,
1022	.dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
1023	.get_dcc_compression_cap = hubbub3_get_dcc_compression_cap,
1024	.wm_read_state = hubbub32_wm_read_state,
1025	.get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
1026	.program_watermarks = hubbub32_program_watermarks,
1027	.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
1028	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
1029	.verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
1030	.force_wm_propagate_to_pipes = hubbub32_force_wm_propagate_to_pipes,
1031	.force_pstate_change_control = hubbub3_force_pstate_change_control,
1032	.init_watermarks = hubbub32_init_watermarks,
1033	.program_det_size = dcn32_program_det_size,
1034	.program_compbuf_size = dcn32_program_compbuf_size,
1035	.init_crb = dcn32_init_crb,
1036	.hubbub_read_state = hubbub2_read_state,
1037	.force_usr_retraining_allow = hubbub32_force_usr_retraining_allow,
1038	.set_request_limit = hubbub32_set_request_limit,
1039	.get_mall_en = hubbub32_get_mall_en,
1040	.hubbub_read_reg_state = hubbub3_read_reg_state
1041};
1042
1043void hubbub32_construct(struct dcn20_hubbub *hubbub2,
1044	struct dc_context *ctx,
1045	const struct dcn_hubbub_registers *hubbub_regs,
1046	const struct dcn_hubbub_shift *hubbub_shift,
1047	const struct dcn_hubbub_mask *hubbub_mask,
1048	int det_size_kb,
1049	int pixel_chunk_size_kb,
1050	int config_return_buffer_size_kb)
1051{
1052	hubbub2->base.ctx = ctx;
1053	hubbub2->base.funcs = &hubbub32_funcs;
1054	hubbub2->regs = hubbub_regs;
1055	hubbub2->shifts = hubbub_shift;
1056	hubbub2->masks = hubbub_mask;
1057
1058	hubbub2->debug_test_index_pstate = 0xB;
1059	hubbub2->detile_buf_size = det_size_kb * 1024;
1060	hubbub2->pixel_chunk_size = pixel_chunk_size_kb * 1024;
1061	hubbub2->crb_size_segs = config_return_buffer_size_kb / DCN32_CRB_SEGMENT_SIZE_KB;
1062}
~/ Read-only file preview.