xref: /linux/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2026 Advanced Micro Devices, Inc.
4 
5 #include "dcn30/dcn30_hubbub.h"
6 #include "dcn31/dcn31_hubbub.h"
7 #include "dcn32/dcn32_hubbub.h"
8 #include "dcn35/dcn35_hubbub.h"
9 #include "dcn401/dcn401_hubbub.h"
10 #include "dcn42/dcn42_hubbub.h"
11 #include "dm_services.h"
12 #include "reg_helper.h"
13 
14 #define DCN42_CRB_SEGMENT_SIZE_KB 64
15 
16 #define CTX \
17 	hubbub2->base.ctx
18 #define DC_LOGGER \
19 	hubbub2->base.ctx->logger
20 #define REG(reg)\
21 	hubbub2->regs->reg
22 
23 #undef FN
24 #define FN(reg_name, field_name) \
25 	hubbub2->shifts->field_name, hubbub2->masks->field_name
26 
27 static bool hubbub42_program_urgent_watermarks(
28 		struct hubbub *hubbub,
29 		union dcn_watermark_set *watermarks,
30 		bool safe_to_lower)
31 {
32 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
33 	bool wm_pending = false;
34 
35 	/* Repeat for water mark set A, B, C and D. */
36 	/* clock state A */
37 	if (safe_to_lower || watermarks->dcn4x.a.urgent > hubbub2->watermarks.dcn4x.a.urgent) {
38 		hubbub2->watermarks.dcn4x.a.urgent = watermarks->dcn4x.a.urgent;
39 		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
40 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, watermarks->dcn4x.a.urgent);
41 	} else if (watermarks->dcn4x.a.urgent < hubbub2->watermarks.dcn4x.a.urgent)
42 		wm_pending = true;
43 
44 	/* determine the transfer time for a quantity of data for a particular requestor.*/
45 	if (safe_to_lower || watermarks->dcn4x.a.frac_urg_bw_flip > hubbub2->watermarks.dcn4x.a.frac_urg_bw_flip) {
46 		hubbub2->watermarks.dcn4x.a.frac_urg_bw_flip = watermarks->dcn4x.a.frac_urg_bw_flip;
47 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
48 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->dcn4x.a.frac_urg_bw_flip);
49 	} else if (watermarks->dcn4x.a.frac_urg_bw_flip < hubbub2->watermarks.dcn4x.a.frac_urg_bw_flip)
50 		wm_pending = true;
51 
52 	if (safe_to_lower || watermarks->dcn4x.a.frac_urg_bw_nom > hubbub2->watermarks.dcn4x.a.frac_urg_bw_nom) {
53 		hubbub2->watermarks.dcn4x.a.frac_urg_bw_nom = watermarks->dcn4x.a.frac_urg_bw_nom;
54 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
55 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->dcn4x.a.frac_urg_bw_nom);
56 	} else if (watermarks->dcn4x.a.frac_urg_bw_nom < hubbub2->watermarks.dcn4x.a.frac_urg_bw_nom)
57 		wm_pending = true;
58 
59 	if (safe_to_lower || watermarks->dcn4x.a.refcyc_per_trip_to_mem > hubbub2->watermarks.dcn4x.a.refcyc_per_trip_to_mem) {
60 		hubbub2->watermarks.dcn4x.a.refcyc_per_trip_to_mem = watermarks->dcn4x.a.refcyc_per_trip_to_mem;
61 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
62 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, watermarks->dcn4x.a.refcyc_per_trip_to_mem);
63 	} else if (watermarks->dcn4x.a.refcyc_per_trip_to_mem < hubbub2->watermarks.dcn4x.a.refcyc_per_trip_to_mem)
64 		wm_pending = true;
65 
66 	/* clock state B */
67 	if (safe_to_lower || watermarks->dcn4x.b.urgent > hubbub2->watermarks.dcn4x.b.urgent) {
68 		hubbub2->watermarks.dcn4x.b.urgent = watermarks->dcn4x.b.urgent;
69 		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
70 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, watermarks->dcn4x.b.urgent);
71 	} else if (watermarks->dcn4x.b.urgent < hubbub2->watermarks.dcn4x.b.urgent)
72 		wm_pending = true;
73 
74 	/* determine the transfer time for a quantity of data for a particular requestor.*/
75 	if (safe_to_lower || watermarks->dcn4x.b.frac_urg_bw_flip > hubbub2->watermarks.dcn4x.b.frac_urg_bw_flip) {
76 		hubbub2->watermarks.dcn4x.b.frac_urg_bw_flip = watermarks->dcn4x.b.frac_urg_bw_flip;
77 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
78 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->dcn4x.b.frac_urg_bw_flip);
79 	} else if (watermarks->dcn4x.b.frac_urg_bw_flip < hubbub2->watermarks.dcn4x.b.frac_urg_bw_flip)
80 		wm_pending = true;
81 
82 	if (safe_to_lower || watermarks->dcn4x.b.frac_urg_bw_nom > hubbub2->watermarks.dcn4x.b.frac_urg_bw_nom) {
83 		hubbub2->watermarks.dcn4x.b.frac_urg_bw_nom = watermarks->dcn4x.b.frac_urg_bw_nom;
84 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
85 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->dcn4x.b.frac_urg_bw_nom);
86 	} else if (watermarks->dcn4x.b.frac_urg_bw_nom < hubbub2->watermarks.dcn4x.b.frac_urg_bw_nom)
87 		wm_pending = true;
88 
89 	if (safe_to_lower || watermarks->dcn4x.b.refcyc_per_trip_to_mem > hubbub2->watermarks.dcn4x.b.refcyc_per_trip_to_mem) {
90 		hubbub2->watermarks.dcn4x.b.refcyc_per_trip_to_mem = watermarks->dcn4x.b.refcyc_per_trip_to_mem;
91 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
92 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, watermarks->dcn4x.b.refcyc_per_trip_to_mem);
93 	} else if (watermarks->dcn4x.b.refcyc_per_trip_to_mem < hubbub2->watermarks.dcn4x.b.refcyc_per_trip_to_mem)
94 		wm_pending = true;
95 
96 	/* clock state C */
97 	if (safe_to_lower || watermarks->dcn4x.c.urgent > hubbub2->watermarks.dcn4x.c.urgent) {
98 		hubbub2->watermarks.dcn4x.c.urgent = watermarks->dcn4x.c.urgent;
99 		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
100 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, watermarks->dcn4x.c.urgent);
101 	} else if (watermarks->dcn4x.c.urgent < hubbub2->watermarks.dcn4x.c.urgent)
102 		wm_pending = true;
103 
104 	/* determine the transfer time for a quantity of data for a particular requestor.*/
105 	if (safe_to_lower || watermarks->dcn4x.c.frac_urg_bw_flip > hubbub2->watermarks.dcn4x.c.frac_urg_bw_flip) {
106 		hubbub2->watermarks.dcn4x.c.frac_urg_bw_flip = watermarks->dcn4x.c.frac_urg_bw_flip;
107 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0,
108 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->dcn4x.c.frac_urg_bw_flip);
109 	} else if (watermarks->dcn4x.c.frac_urg_bw_flip < hubbub2->watermarks.dcn4x.c.frac_urg_bw_flip)
110 		wm_pending = true;
111 
112 	if (safe_to_lower || watermarks->dcn4x.c.frac_urg_bw_nom > hubbub2->watermarks.dcn4x.c.frac_urg_bw_nom) {
113 		hubbub2->watermarks.dcn4x.c.frac_urg_bw_nom = watermarks->dcn4x.c.frac_urg_bw_nom;
114 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0,
115 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->dcn4x.c.frac_urg_bw_nom);
116 	} else if (watermarks->dcn4x.c.frac_urg_bw_nom < hubbub2->watermarks.dcn4x.c.frac_urg_bw_nom)
117 		wm_pending = true;
118 
119 	if (safe_to_lower || watermarks->dcn4x.c.refcyc_per_trip_to_mem > hubbub2->watermarks.dcn4x.c.refcyc_per_trip_to_mem) {
120 		hubbub2->watermarks.dcn4x.c.refcyc_per_trip_to_mem = watermarks->dcn4x.c.refcyc_per_trip_to_mem;
121 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
122 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, watermarks->dcn4x.c.refcyc_per_trip_to_mem);
123 	} else if (watermarks->dcn4x.c.refcyc_per_trip_to_mem < hubbub2->watermarks.dcn4x.c.refcyc_per_trip_to_mem)
124 		wm_pending = true;
125 
126 	/* clock state D */
127 	if (safe_to_lower || watermarks->dcn4x.d.urgent > hubbub2->watermarks.dcn4x.d.urgent) {
128 		hubbub2->watermarks.dcn4x.d.urgent = watermarks->dcn4x.d.urgent;
129 		REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
130 				DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, watermarks->dcn4x.d.urgent);
131 	} else if (watermarks->dcn4x.d.urgent < hubbub2->watermarks.dcn4x.d.urgent)
132 		wm_pending = true;
133 
134 	/* determine the transfer time for a quantity of data for a particular requestor.*/
135 	if (safe_to_lower || watermarks->dcn4x.d.frac_urg_bw_flip > hubbub2->watermarks.dcn4x.d.frac_urg_bw_flip) {
136 		hubbub2->watermarks.dcn4x.d.frac_urg_bw_flip = watermarks->dcn4x.d.frac_urg_bw_flip;
137 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
138 				DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->dcn4x.d.frac_urg_bw_flip);
139 	} else if (watermarks->dcn4x.d.frac_urg_bw_flip < hubbub2->watermarks.dcn4x.d.frac_urg_bw_flip)
140 		wm_pending = true;
141 
142 	if (safe_to_lower || watermarks->dcn4x.d.frac_urg_bw_nom > hubbub2->watermarks.dcn4x.d.frac_urg_bw_nom) {
143 		hubbub2->watermarks.dcn4x.d.frac_urg_bw_nom = watermarks->dcn4x.d.frac_urg_bw_nom;
144 		REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
145 				DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->dcn4x.d.frac_urg_bw_nom);
146 	} else if (watermarks->dcn4x.d.frac_urg_bw_nom < hubbub2->watermarks.dcn4x.d.frac_urg_bw_nom)
147 		wm_pending = true;
148 
149 	if (safe_to_lower || watermarks->dcn4x.d.refcyc_per_trip_to_mem > hubbub2->watermarks.dcn4x.d.refcyc_per_trip_to_mem) {
150 		hubbub2->watermarks.dcn4x.d.refcyc_per_trip_to_mem = watermarks->dcn4x.d.refcyc_per_trip_to_mem;
151 		REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
152 				DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, watermarks->dcn4x.d.refcyc_per_trip_to_mem);
153 	} else if (watermarks->dcn4x.d.refcyc_per_trip_to_mem < hubbub2->watermarks.dcn4x.d.refcyc_per_trip_to_mem)
154 		wm_pending = true;
155 
156 	return wm_pending;
157 }
158 
159 static bool hubbub42_program_stutter_watermarks(
160 		struct hubbub *hubbub,
161 		union dcn_watermark_set *watermarks,
162 		bool safe_to_lower)
163 {
164 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
165 	bool wm_pending = false;
166 
167 	/* clock state A */
168 	if (safe_to_lower || watermarks->dcn4x.a.sr_enter > hubbub2->watermarks.dcn4x.a.sr_enter) {
169 		hubbub2->watermarks.dcn4x.a.sr_enter =	watermarks->dcn4x.a.sr_enter;
170 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
171 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, watermarks->dcn4x.a.sr_enter);
172 	} else if (watermarks->dcn4x.a.sr_enter < hubbub2->watermarks.dcn4x.a.sr_enter)
173 		wm_pending = true;
174 
175 	if (safe_to_lower || watermarks->dcn4x.a.sr_exit > hubbub2->watermarks.dcn4x.a.sr_exit) {
176 		hubbub2->watermarks.dcn4x.a.sr_exit = watermarks->dcn4x.a.sr_exit;
177 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
178 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, watermarks->dcn4x.a.sr_exit);
179 	} else if (watermarks->dcn4x.a.sr_exit < hubbub2->watermarks.dcn4x.a.sr_exit)
180 		wm_pending = true;
181 
182 	/* clock state B */
183 	if (safe_to_lower || watermarks->dcn4x.b.sr_enter > hubbub2->watermarks.dcn4x.b.sr_enter) {
184 		hubbub2->watermarks.dcn4x.b.sr_enter =	watermarks->dcn4x.b.sr_enter;
185 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
186 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, watermarks->dcn4x.b.sr_enter);
187 	} else if (watermarks->dcn4x.b.sr_enter < hubbub2->watermarks.dcn4x.b.sr_enter)
188 		wm_pending = true;
189 
190 	if (safe_to_lower || watermarks->dcn4x.b.sr_exit > hubbub2->watermarks.dcn4x.b.sr_exit) {
191 		hubbub2->watermarks.dcn4x.b.sr_exit = watermarks->dcn4x.b.sr_exit;
192 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
193 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, watermarks->dcn4x.b.sr_exit);
194 	} else if (watermarks->dcn4x.b.sr_exit < hubbub2->watermarks.dcn4x.b.sr_exit)
195 		wm_pending = true;
196 
197 	/* clock state C */
198 	if (safe_to_lower || watermarks->dcn4x.c.sr_enter > hubbub2->watermarks.dcn4x.c.sr_enter) {
199 		hubbub2->watermarks.dcn4x.c.sr_enter =	watermarks->dcn4x.c.sr_enter;
200 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
201 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, watermarks->dcn4x.c.sr_enter);
202 	} else if (watermarks->dcn4x.c.sr_enter < hubbub2->watermarks.dcn4x.c.sr_enter)
203 		wm_pending = true;
204 
205 	if (safe_to_lower || watermarks->dcn4x.c.sr_exit > hubbub2->watermarks.dcn4x.c.sr_exit) {
206 		hubbub2->watermarks.dcn4x.c.sr_exit = watermarks->dcn4x.c.sr_exit;
207 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
208 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, watermarks->dcn4x.c.sr_exit);
209 	} else if (watermarks->dcn4x.c.sr_exit < hubbub2->watermarks.dcn4x.c.sr_exit)
210 		wm_pending = true;
211 
212 	/* clock state D */
213 	if (safe_to_lower || watermarks->dcn4x.d.sr_enter > hubbub2->watermarks.dcn4x.d.sr_enter) {
214 		hubbub2->watermarks.dcn4x.d.sr_enter =	watermarks->dcn4x.d.sr_enter;
215 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
216 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, watermarks->dcn4x.d.sr_enter);
217 	} else if (watermarks->dcn4x.d.sr_enter < hubbub2->watermarks.dcn4x.d.sr_enter)
218 		wm_pending = true;
219 
220 	if (safe_to_lower || watermarks->dcn4x.d.sr_exit > hubbub2->watermarks.dcn4x.d.sr_exit) {
221 		hubbub2->watermarks.dcn4x.d.sr_exit = watermarks->dcn4x.d.sr_exit;
222 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
223 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, watermarks->dcn4x.d.sr_exit);
224 	} else if (watermarks->dcn4x.d.sr_exit < hubbub2->watermarks.dcn4x.d.sr_exit)
225 		wm_pending = true;
226 
227 	return wm_pending;
228 }
229 
230 static bool hubbub42_program_pstate_watermarks(
231 		struct hubbub *hubbub,
232 		union dcn_watermark_set *watermarks,
233 		bool safe_to_lower)
234 {
235 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
236 	bool wm_pending = false;
237 
238 	/* Section for UCLK_PSTATE_CHANGE_WATERMARKS */
239 	/* UCLK state A */
240 	if (safe_to_lower || watermarks->dcn4x.a.uclk_pstate > hubbub2->watermarks.dcn4x.a.uclk_pstate) {
241 		hubbub2->watermarks.dcn4x.a.uclk_pstate = watermarks->dcn4x.a.uclk_pstate;
242 		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, 0,
243 				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, watermarks->dcn4x.a.uclk_pstate);
244 	} else if (watermarks->dcn4x.a.uclk_pstate < hubbub2->watermarks.dcn4x.a.uclk_pstate)
245 		wm_pending = true;
246 
247 	/* UCLK state B */
248 	if (safe_to_lower || watermarks->dcn4x.b.uclk_pstate > hubbub2->watermarks.dcn4x.b.uclk_pstate) {
249 		hubbub2->watermarks.dcn4x.b.uclk_pstate = watermarks->dcn4x.b.uclk_pstate;
250 		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, 0,
251 				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, watermarks->dcn4x.b.uclk_pstate);
252 	} else if (watermarks->dcn4x.b.uclk_pstate < hubbub2->watermarks.dcn4x.b.uclk_pstate)
253 		wm_pending = true;
254 
255 	/* UCLK state C */
256 	if (safe_to_lower || watermarks->dcn4x.c.uclk_pstate > hubbub2->watermarks.dcn4x.c.uclk_pstate) {
257 		hubbub2->watermarks.dcn4x.c.uclk_pstate = watermarks->dcn4x.c.uclk_pstate;
258 		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, 0,
259 				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C, watermarks->dcn4x.c.uclk_pstate);
260 	} else if (watermarks->dcn4x.c.uclk_pstate < hubbub2->watermarks.dcn4x.c.uclk_pstate)
261 		wm_pending = true;
262 
263 	/* UCLK state D */
264 	if (safe_to_lower || watermarks->dcn4x.d.uclk_pstate > hubbub2->watermarks.dcn4x.d.uclk_pstate) {
265 		hubbub2->watermarks.dcn4x.d.uclk_pstate = watermarks->dcn4x.d.uclk_pstate;
266 		REG_SET(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, 0,
267 				DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D, watermarks->dcn4x.d.uclk_pstate);
268 	} else if (watermarks->dcn4x.d.uclk_pstate < hubbub2->watermarks.dcn4x.d.uclk_pstate)
269 		wm_pending = true;
270 
271 	/* Section for FCLK_PSTATE_CHANGE_WATERMARKS */
272 	/* FCLK state A */
273 	if (safe_to_lower || watermarks->dcn4x.a.fclk_pstate > hubbub2->watermarks.dcn4x.a.fclk_pstate) {
274 		hubbub2->watermarks.dcn4x.a.fclk_pstate = watermarks->dcn4x.a.fclk_pstate;
275 		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, 0,
276 				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, watermarks->dcn4x.a.fclk_pstate);
277 	} else if (watermarks->dcn4x.a.fclk_pstate < hubbub2->watermarks.dcn4x.a.fclk_pstate)
278 		wm_pending = true;
279 
280 	/* FCLK state B */
281 	if (safe_to_lower || watermarks->dcn4x.b.fclk_pstate > hubbub2->watermarks.dcn4x.b.fclk_pstate) {
282 		hubbub2->watermarks.dcn4x.b.fclk_pstate = watermarks->dcn4x.b.fclk_pstate;
283 		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, 0,
284 				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, watermarks->dcn4x.b.fclk_pstate);
285 	} else if (watermarks->dcn4x.b.fclk_pstate < hubbub2->watermarks.dcn4x.b.fclk_pstate)
286 		wm_pending = true;
287 
288 	/* FCLK state C */
289 	if (safe_to_lower || watermarks->dcn4x.c.fclk_pstate > hubbub2->watermarks.dcn4x.c.fclk_pstate) {
290 		hubbub2->watermarks.dcn4x.c.fclk_pstate = watermarks->dcn4x.c.fclk_pstate;
291 		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, 0,
292 				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C, watermarks->dcn4x.c.fclk_pstate);
293 	} else if (watermarks->dcn4x.c.fclk_pstate < hubbub2->watermarks.dcn4x.c.fclk_pstate)
294 		wm_pending = true;
295 
296 	/* FCLK state D */
297 	if (safe_to_lower || watermarks->dcn4x.d.fclk_pstate > hubbub2->watermarks.dcn4x.d.fclk_pstate) {
298 		hubbub2->watermarks.dcn4x.d.fclk_pstate = watermarks->dcn4x.d.fclk_pstate;
299 		REG_SET(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, 0,
300 				DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D, watermarks->dcn4x.d.fclk_pstate);
301 	} else if (watermarks->dcn4x.d.fclk_pstate < hubbub2->watermarks.dcn4x.d.fclk_pstate)
302 		wm_pending = true;
303 
304 	return wm_pending;
305 }
306 
307 static bool hubbub42_program_usr_watermarks(
308 		struct hubbub *hubbub,
309 		union dcn_watermark_set *watermarks,
310 		bool safe_to_lower)
311 {
312 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
313 	bool wm_pending = false;
314 
315 	/* clock state A */
316 	if (safe_to_lower || watermarks->dcn4x.a.usr > hubbub2->watermarks.dcn4x.a.usr) {
317 		hubbub2->watermarks.dcn4x.a.usr = watermarks->dcn4x.a.usr;
318 		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, 0,
319 				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A, watermarks->dcn4x.a.usr);
320 	} else if (watermarks->dcn4x.a.usr < hubbub2->watermarks.dcn4x.a.usr)
321 		wm_pending = true;
322 
323 	/* clock state B */
324 	if (safe_to_lower || watermarks->dcn4x.b.usr > hubbub2->watermarks.dcn4x.b.usr) {
325 		hubbub2->watermarks.dcn4x.b.usr = watermarks->dcn4x.b.usr;
326 		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, 0,
327 				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B, watermarks->dcn4x.b.usr);
328 	} else if (watermarks->dcn4x.b.usr < hubbub2->watermarks.dcn4x.b.usr)
329 		wm_pending = true;
330 
331 	/* clock state C */
332 	if (safe_to_lower || watermarks->dcn4x.c.usr > hubbub2->watermarks.dcn4x.c.usr) {
333 		hubbub2->watermarks.dcn4x.c.usr = watermarks->dcn4x.c.usr;
334 		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, 0,
335 				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C, watermarks->dcn4x.c.usr);
336 	} else if (watermarks->dcn4x.c.usr < hubbub2->watermarks.dcn4x.c.usr)
337 		wm_pending = true;
338 
339 	/* clock state D */
340 	if (safe_to_lower || watermarks->dcn4x.d.usr > hubbub2->watermarks.dcn4x.d.usr) {
341 		hubbub2->watermarks.dcn4x.d.usr = watermarks->dcn4x.d.usr;
342 		REG_SET(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, 0,
343 				DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D, watermarks->dcn4x.d.usr);
344 	} else if (watermarks->dcn4x.d.usr < hubbub2->watermarks.dcn4x.d.usr)
345 		wm_pending = true;
346 
347 	return wm_pending;
348 }
349 
350 static bool hubbub42_program_stutter_z8_watermarks(
351 		struct hubbub *hubbub,
352 		union dcn_watermark_set *watermarks,
353 		bool safe_to_lower)
354 {
355 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
356 	bool wm_pending = false;
357 
358 	/* clock state A */
359 	if (safe_to_lower || watermarks->dcn4x.a.sr_enter_z8 > hubbub2->watermarks.dcn4x.a.sr_enter_z8) {
360 		hubbub2->watermarks.dcn4x.a.sr_enter_z8 = watermarks->dcn4x.a.sr_enter_z8;
361 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0,
362 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, watermarks->dcn4x.a.sr_enter_z8);
363 	} else if (watermarks->dcn4x.a.sr_enter_z8 < hubbub2->watermarks.dcn4x.a.sr_enter_z8)
364 		wm_pending = true;
365 
366 	if (safe_to_lower || watermarks->dcn4x.a.sr_exit_z8 > hubbub2->watermarks.dcn4x.a.sr_exit_z8) {
367 		hubbub2->watermarks.dcn4x.a.sr_exit_z8 = watermarks->dcn4x.a.sr_exit_z8;
368 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0,
369 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, watermarks->dcn4x.a.sr_exit_z8);
370 	} else if (watermarks->dcn4x.a.sr_exit_z8 < hubbub2->watermarks.dcn4x.a.sr_exit_z8)
371 		wm_pending = true;
372 
373 	/* clock state B */
374 	if (safe_to_lower || watermarks->dcn4x.b.sr_enter_z8 > hubbub2->watermarks.dcn4x.b.sr_enter_z8) {
375 		hubbub2->watermarks.dcn4x.b.sr_enter_z8 = watermarks->dcn4x.b.sr_enter_z8;
376 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0,
377 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, watermarks->dcn4x.b.sr_enter_z8);
378 	} else if (watermarks->dcn4x.b.sr_enter_z8 < hubbub2->watermarks.dcn4x.b.sr_enter_z8)
379 		wm_pending = true;
380 
381 	if (safe_to_lower || watermarks->dcn4x.b.sr_exit_z8 > hubbub2->watermarks.dcn4x.b.sr_exit_z8) {
382 		hubbub2->watermarks.dcn4x.b.sr_exit_z8 = watermarks->dcn4x.b.sr_exit_z8;
383 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0,
384 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, watermarks->dcn4x.b.sr_exit_z8);
385 	} else if (watermarks->dcn4x.b.sr_exit_z8 < hubbub2->watermarks.dcn4x.b.sr_exit_z8)
386 		wm_pending = true;
387 
388 	/* clock state C */
389 	if (safe_to_lower || watermarks->dcn4x.c.sr_enter_z8 > hubbub2->watermarks.dcn4x.c.sr_enter_z8) {
390 		hubbub2->watermarks.dcn4x.c.sr_enter_z8 = watermarks->dcn4x.c.sr_enter_z8;
391 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0,
392 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, watermarks->dcn4x.c.sr_enter_z8);
393 	} else if (watermarks->dcn4x.c.sr_enter_z8 < hubbub2->watermarks.dcn4x.c.sr_enter_z8)
394 		wm_pending = true;
395 
396 	if (safe_to_lower || watermarks->dcn4x.c.sr_exit_z8 > hubbub2->watermarks.dcn4x.c.sr_exit_z8) {
397 		hubbub2->watermarks.dcn4x.c.sr_exit_z8 = watermarks->dcn4x.c.sr_exit_z8;
398 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0,
399 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, watermarks->dcn4x.c.sr_exit_z8);
400 	} else if (watermarks->dcn4x.c.sr_exit_z8 < hubbub2->watermarks.dcn4x.c.sr_exit_z8)
401 		wm_pending = true;
402 
403 	/* clock state D */
404 	if (safe_to_lower || watermarks->dcn4x.d.sr_enter_z8 > hubbub2->watermarks.dcn4x.d.sr_enter_z8) {
405 		hubbub2->watermarks.dcn4x.d.sr_enter_z8 = watermarks->dcn4x.d.sr_enter_z8;
406 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0,
407 				DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, watermarks->dcn4x.d.sr_enter_z8);
408 	} else if (watermarks->dcn4x.d.sr_enter_z8 < hubbub2->watermarks.dcn4x.d.sr_enter_z8)
409 		wm_pending = true;
410 
411 	if (safe_to_lower || watermarks->dcn4x.d.sr_exit_z8 > hubbub2->watermarks.dcn4x.d.sr_exit_z8) {
412 		hubbub2->watermarks.dcn4x.d.sr_exit_z8 = watermarks->dcn4x.d.sr_exit_z8;
413 		REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0,
414 				DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, watermarks->dcn4x.d.sr_exit_z8);
415 	} else if (watermarks->dcn4x.d.sr_exit_z8 < hubbub2->watermarks.dcn4x.d.sr_exit_z8)
416 		wm_pending = true;
417 
418 	return wm_pending;
419 }
420 
421 static void hubbub42_allow_self_refresh_control(struct hubbub *hubbub, bool allow)
422 {
423 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
424 
425 	/*
426 	 * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 1 means do not allow stutter
427 	 * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 means allow stutter
428 	 */
429 
430 	REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
431 			DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
432 			DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow);
433 }
434 static void hubbub42_set_sdp_control(struct hubbub *hubbub, bool dc_control)
435 {
436 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
437 
438 	REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
439 			SDPIF_PORT_CONTROL, dc_control);
440 }
441 
442 static bool hubbub42_program_watermarks(
443 		struct hubbub *hubbub,
444 		union dcn_watermark_set *watermarks,
445 		unsigned int refclk_mhz,
446 		bool safe_to_lower)
447 {
448 	bool wm_pending = false;
449 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
450 
451 	if (!safe_to_lower && hubbub->ctx->dc->debug.disable_stutter_for_wm_program) {
452 		/* before raising watermarks, SDP control give to DF, stutter must be disabled */
453 		wm_pending = true;
454 		hubbub42_set_sdp_control(hubbub, false);
455 		hubbub42_allow_self_refresh_control(hubbub, false);
456 	}
457 	if (hubbub42_program_urgent_watermarks(hubbub, watermarks, safe_to_lower))
458 		wm_pending = true;
459 
460 	if (hubbub42_program_stutter_watermarks(hubbub, watermarks, safe_to_lower))
461 		wm_pending = true;
462 
463 	if (hubbub42_program_pstate_watermarks(hubbub, watermarks, safe_to_lower))
464 		wm_pending = true;
465 
466 	if (hubbub42_program_usr_watermarks(hubbub, watermarks, safe_to_lower))
467 		wm_pending = true;
468 
469 	if (hubbub42_program_stutter_z8_watermarks(hubbub, watermarks, safe_to_lower))
470 		wm_pending = true;
471 
472 	REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
473 			DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
474 	REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
475 			DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0xFF,
476 			DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, 0xA);/*hw delta*/
477 	REG_UPDATE(DCHUBBUB_ARB_HOSTVM_CNTL, DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, 0xF);
478 
479 	if (safe_to_lower || hubbub->ctx->dc->debug.disable_stutter)
480 		hubbub42_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
481 	if (safe_to_lower && hubbub->ctx->dc->debug.disable_stutter_for_wm_program) {
482 		hubbub42_set_sdp_control(hubbub, true);
483 	}
484 	hubbub32_force_usr_retraining_allow(hubbub, hubbub->ctx->dc->debug.force_usr_allow);
485 
486 	return wm_pending;
487 }
488 
489 static void hubbub42_set_request_limit(struct hubbub *hubbub, int memory_channel_count, int words_per_channel)
490 {
491 	(void)memory_channel_count;
492 	(void)words_per_channel;
493 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
494 	uint32_t request_limit = 96; //MAX(12 * memory_channel_count, 96);
495 
496 	REG_UPDATE(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, request_limit);
497 }
498 
499 static bool dcn42_program_arbiter(struct hubbub *hubbub, struct dml2_display_arb_regs *arb_regs,
500 				  bool safe_to_lower)
501 {
502 	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
503 
504 	bool wm_pending = false;
505 	uint32_t temp;
506 
507 	/* request backpressure and outstanding return threshold (unused)*/
508 	//REG_UPDATE(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_REQ_STALL_THRESHOLD, arb_regs->req_stall_threshold);
509 
510 	/* 401 delta: do not update P-State stall threshold (handled by fw) */
511 	// REG_UPDATE(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_PSTATE_STALL_THRESHOLD, arb_regs->pstate_stall_threshold);
512 
513 	if (safe_to_lower || arb_regs->allow_sdpif_rate_limit_when_cstate_req > hubbub2->allow_sdpif_rate_limit_when_cstate_req) {
514 		hubbub2->allow_sdpif_rate_limit_when_cstate_req = arb_regs->allow_sdpif_rate_limit_when_cstate_req;
515 
516 		/* only update the required bits */
517 		REG_GET(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, &temp);
518 		if (hubbub2->allow_sdpif_rate_limit_when_cstate_req) {
519 			temp |= (1 << 5);
520 		} else {
521 			temp &= ~(1 << 5);
522 		}
523 		REG_UPDATE(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, temp);
524 	} else {
525 		wm_pending = true;
526 	}
527 
528 	return wm_pending;
529 }
530 
531 static const struct hubbub_funcs hubbub42_funcs = {
532 	.update_dchub = hubbub2_update_dchub,
533 	.init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
534 	.init_vm_ctx = hubbub2_init_vm_ctx,
535 	.dcc_support_swizzle = hubbub3_dcc_support_swizzle,
536 	.dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
537 	.get_dcc_compression_cap = hubbub3_get_dcc_compression_cap,
538 	.wm_read_state = hubbub35_wm_read_state,
539 	.get_dchub_ref_freq = hubbub35_get_dchub_ref_freq,
540 	.program_watermarks = hubbub42_program_watermarks,
541 	.allow_self_refresh_control = hubbub42_allow_self_refresh_control,
542 	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
543 	.force_wm_propagate_to_pipes = hubbub32_force_wm_propagate_to_pipes,
544 	.force_pstate_change_control = hubbub3_force_pstate_change_control,
545 	.init_watermarks = hubbub35_init_watermarks,
546 	.init_crb = dcn401_init_crb,
547 	.dchvm_init = dcn35_dchvm_init,
548 	.hubbub_read_state = hubbub2_read_state,
549 	.force_usr_retraining_allow = hubbub32_force_usr_retraining_allow,
550 	.set_request_limit = hubbub42_set_request_limit,
551 	.program_det_segments = dcn401_program_det_segments,
552 	.program_compbuf_segments = dcn401_program_compbuf_segments,
553 	.wait_for_det_update = dcn401_wait_for_det_update,
554 	.program_arbiter = dcn42_program_arbiter,
555 	.hubbub_read_reg_state = hubbub3_read_reg_state
556 };
557 
558 void hubbub42_construct(struct dcn20_hubbub *hubbub2,
559 	struct dc_context *ctx,
560 	const struct dcn_hubbub_registers *hubbub_regs,
561 	const struct dcn_hubbub_shift *hubbub_shift,
562 	const struct dcn_hubbub_mask *hubbub_mask,
563 	int det_size_kb,
564 	int pixel_chunk_size_kb,
565 	int config_return_buffer_size_kb)
566 {
567 	hubbub2->base.ctx = ctx;
568 	hubbub2->base.funcs = &hubbub42_funcs;
569 	hubbub2->regs = hubbub_regs;
570 	hubbub2->shifts = hubbub_shift;
571 	hubbub2->masks = hubbub_mask;
572 
573 	hubbub2->detile_buf_size = det_size_kb * 1024;
574 	hubbub2->pixel_chunk_size = pixel_chunk_size_kb * 1024;
575 	hubbub2->crb_size_segs = config_return_buffer_size_kb / DCN42_CRB_SEGMENT_SIZE_KB;
576 }
577