1 | /* |
2 | * Copyright 2016 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 "dcn20_hubbub.h" |
28 | #include "reg_helper.h" |
29 | #include "clk_mgr.h" |
30 | |
31 | #define REG(reg)\ |
32 | hubbub1->regs->reg |
33 | |
34 | #define CTX \ |
35 | hubbub1->base.ctx |
36 | |
37 | #undef FN |
38 | #define FN(reg_name, field_name) \ |
39 | hubbub1->shifts->field_name, hubbub1->masks->field_name |
40 | |
41 | #define REG(reg)\ |
42 | hubbub1->regs->reg |
43 | |
44 | #define CTX \ |
45 | hubbub1->base.ctx |
46 | |
47 | #undef FN |
48 | #define FN(reg_name, field_name) \ |
49 | hubbub1->shifts->field_name, hubbub1->masks->field_name |
50 | |
51 | #ifdef NUM_VMID |
52 | #undef NUM_VMID |
53 | #endif |
54 | #define NUM_VMID 16 |
55 | |
56 | bool hubbub2_dcc_support_swizzle( |
57 | enum swizzle_mode_values swizzle, |
58 | unsigned int bytes_per_element, |
59 | enum segment_order *segment_order_horz, |
60 | enum segment_order *segment_order_vert) |
61 | { |
62 | bool standard_swizzle = false; |
63 | bool display_swizzle = false; |
64 | bool render_swizzle = false; |
65 | |
66 | switch (swizzle) { |
67 | case DC_SW_4KB_S: |
68 | case DC_SW_64KB_S: |
69 | case DC_SW_VAR_S: |
70 | case DC_SW_4KB_S_X: |
71 | case DC_SW_64KB_S_X: |
72 | case DC_SW_VAR_S_X: |
73 | standard_swizzle = true; |
74 | break; |
75 | case DC_SW_64KB_R_X: |
76 | render_swizzle = true; |
77 | break; |
78 | case DC_SW_4KB_D: |
79 | case DC_SW_64KB_D: |
80 | case DC_SW_VAR_D: |
81 | case DC_SW_4KB_D_X: |
82 | case DC_SW_64KB_D_X: |
83 | case DC_SW_VAR_D_X: |
84 | display_swizzle = true; |
85 | break; |
86 | default: |
87 | break; |
88 | } |
89 | |
90 | if (standard_swizzle) { |
91 | if (bytes_per_element == 1) { |
92 | *segment_order_horz = segment_order__contiguous; |
93 | *segment_order_vert = segment_order__na; |
94 | return true; |
95 | } |
96 | if (bytes_per_element == 2) { |
97 | *segment_order_horz = segment_order__non_contiguous; |
98 | *segment_order_vert = segment_order__contiguous; |
99 | return true; |
100 | } |
101 | if (bytes_per_element == 4) { |
102 | *segment_order_horz = segment_order__non_contiguous; |
103 | *segment_order_vert = segment_order__contiguous; |
104 | return true; |
105 | } |
106 | if (bytes_per_element == 8) { |
107 | *segment_order_horz = segment_order__na; |
108 | *segment_order_vert = segment_order__contiguous; |
109 | return true; |
110 | } |
111 | } |
112 | if (render_swizzle) { |
113 | if (bytes_per_element == 2) { |
114 | *segment_order_horz = segment_order__contiguous; |
115 | *segment_order_vert = segment_order__contiguous; |
116 | return true; |
117 | } |
118 | if (bytes_per_element == 4) { |
119 | *segment_order_horz = segment_order__non_contiguous; |
120 | *segment_order_vert = segment_order__contiguous; |
121 | return true; |
122 | } |
123 | if (bytes_per_element == 8) { |
124 | *segment_order_horz = segment_order__contiguous; |
125 | *segment_order_vert = segment_order__non_contiguous; |
126 | return true; |
127 | } |
128 | } |
129 | if (display_swizzle && bytes_per_element == 8) { |
130 | *segment_order_horz = segment_order__contiguous; |
131 | *segment_order_vert = segment_order__non_contiguous; |
132 | return true; |
133 | } |
134 | |
135 | return false; |
136 | } |
137 | |
138 | bool hubbub2_dcc_support_pixel_format( |
139 | enum surface_pixel_format format, |
140 | unsigned int *bytes_per_element) |
141 | { |
142 | /* DML: get_bytes_per_element */ |
143 | switch (format) { |
144 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: |
145 | case SURFACE_PIXEL_FORMAT_GRPH_RGB565: |
146 | *bytes_per_element = 2; |
147 | return true; |
148 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: |
149 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: |
150 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: |
151 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: |
152 | case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: |
153 | case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: |
154 | case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: |
155 | case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: |
156 | case SURFACE_PIXEL_FORMAT_GRPH_RGBE: |
157 | case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA: |
158 | *bytes_per_element = 4; |
159 | return true; |
160 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: |
161 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: |
162 | case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: |
163 | case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: |
164 | *bytes_per_element = 8; |
165 | return true; |
166 | default: |
167 | return false; |
168 | } |
169 | } |
170 | |
171 | static void hubbub2_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, |
172 | unsigned int bytes_per_element) |
173 | { |
174 | /* copied from DML. might want to refactor DML to leverage from DML */ |
175 | /* DML : get_blk256_size */ |
176 | if (bytes_per_element == 1) { |
177 | *blk256_width = 16; |
178 | *blk256_height = 16; |
179 | } else if (bytes_per_element == 2) { |
180 | *blk256_width = 16; |
181 | *blk256_height = 8; |
182 | } else if (bytes_per_element == 4) { |
183 | *blk256_width = 8; |
184 | *blk256_height = 8; |
185 | } else if (bytes_per_element == 8) { |
186 | *blk256_width = 8; |
187 | *blk256_height = 4; |
188 | } |
189 | } |
190 | |
191 | static void hubbub2_det_request_size( |
192 | unsigned int detile_buf_size, |
193 | unsigned int height, |
194 | unsigned int width, |
195 | unsigned int bpe, |
196 | bool *req128_horz_wc, |
197 | bool *req128_vert_wc) |
198 | { |
199 | unsigned int blk256_height = 0; |
200 | unsigned int blk256_width = 0; |
201 | unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; |
202 | |
203 | hubbub2_get_blk256_size(blk256_width: &blk256_width, blk256_height: &blk256_height, bytes_per_element: bpe); |
204 | |
205 | swath_bytes_horz_wc = width * blk256_height * bpe; |
206 | swath_bytes_vert_wc = height * blk256_width * bpe; |
207 | |
208 | *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? |
209 | false : /* full 256B request */ |
210 | true; /* half 128b request */ |
211 | |
212 | *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? |
213 | false : /* full 256B request */ |
214 | true; /* half 128b request */ |
215 | } |
216 | |
217 | bool hubbub2_get_dcc_compression_cap(struct hubbub *hubbub, |
218 | const struct dc_dcc_surface_param *input, |
219 | struct dc_surface_dcc_cap *output) |
220 | { |
221 | struct dc *dc = hubbub->ctx->dc; |
222 | /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */ |
223 | enum dcc_control dcc_control; |
224 | unsigned int bpe; |
225 | enum segment_order segment_order_horz, segment_order_vert; |
226 | bool req128_horz_wc, req128_vert_wc; |
227 | |
228 | memset(output, 0, sizeof(*output)); |
229 | |
230 | if (dc->debug.disable_dcc == DCC_DISABLE) |
231 | return false; |
232 | |
233 | if (!hubbub->funcs->dcc_support_pixel_format(input->format, |
234 | &bpe)) |
235 | return false; |
236 | |
237 | if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe, |
238 | &segment_order_horz, &segment_order_vert)) |
239 | return false; |
240 | |
241 | hubbub2_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size, |
242 | height: input->surface_size.height, width: input->surface_size.width, |
243 | bpe, req128_horz_wc: &req128_horz_wc, req128_vert_wc: &req128_vert_wc); |
244 | |
245 | if (!req128_horz_wc && !req128_vert_wc) { |
246 | dcc_control = dcc_control__256_256_xxx; |
247 | } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { |
248 | if (!req128_horz_wc) |
249 | dcc_control = dcc_control__256_256_xxx; |
250 | else if (segment_order_horz == segment_order__contiguous) |
251 | dcc_control = dcc_control__128_128_xxx; |
252 | else |
253 | dcc_control = dcc_control__256_64_64; |
254 | } else if (input->scan == SCAN_DIRECTION_VERTICAL) { |
255 | if (!req128_vert_wc) |
256 | dcc_control = dcc_control__256_256_xxx; |
257 | else if (segment_order_vert == segment_order__contiguous) |
258 | dcc_control = dcc_control__128_128_xxx; |
259 | else |
260 | dcc_control = dcc_control__256_64_64; |
261 | } else { |
262 | if ((req128_horz_wc && |
263 | segment_order_horz == segment_order__non_contiguous) || |
264 | (req128_vert_wc && |
265 | segment_order_vert == segment_order__non_contiguous)) |
266 | /* access_dir not known, must use most constraining */ |
267 | dcc_control = dcc_control__256_64_64; |
268 | else |
269 | /* reg128 is true for either horz and vert |
270 | * but segment_order is contiguous |
271 | */ |
272 | dcc_control = dcc_control__128_128_xxx; |
273 | } |
274 | |
275 | /* Exception for 64KB_R_X */ |
276 | if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X)) |
277 | dcc_control = dcc_control__128_128_xxx; |
278 | |
279 | if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && |
280 | dcc_control != dcc_control__256_256_xxx) |
281 | return false; |
282 | |
283 | switch (dcc_control) { |
284 | case dcc_control__256_256_xxx: |
285 | output->grph.rgb.max_uncompressed_blk_size = 256; |
286 | output->grph.rgb.max_compressed_blk_size = 256; |
287 | output->grph.rgb.independent_64b_blks = false; |
288 | break; |
289 | case dcc_control__128_128_xxx: |
290 | output->grph.rgb.max_uncompressed_blk_size = 128; |
291 | output->grph.rgb.max_compressed_blk_size = 128; |
292 | output->grph.rgb.independent_64b_blks = false; |
293 | break; |
294 | case dcc_control__256_64_64: |
295 | output->grph.rgb.max_uncompressed_blk_size = 256; |
296 | output->grph.rgb.max_compressed_blk_size = 64; |
297 | output->grph.rgb.independent_64b_blks = true; |
298 | break; |
299 | default: |
300 | ASSERT(false); |
301 | break; |
302 | } |
303 | output->capable = true; |
304 | output->const_color_support = true; |
305 | |
306 | return true; |
307 | } |
308 | |
309 | static enum dcn_hubbub_page_table_depth page_table_depth_to_hw(unsigned int page_table_depth) |
310 | { |
311 | enum dcn_hubbub_page_table_depth depth = 0; |
312 | |
313 | switch (page_table_depth) { |
314 | case 1: |
315 | depth = DCN_PAGE_TABLE_DEPTH_1_LEVEL; |
316 | break; |
317 | case 2: |
318 | depth = DCN_PAGE_TABLE_DEPTH_2_LEVEL; |
319 | break; |
320 | case 3: |
321 | depth = DCN_PAGE_TABLE_DEPTH_3_LEVEL; |
322 | break; |
323 | case 4: |
324 | depth = DCN_PAGE_TABLE_DEPTH_4_LEVEL; |
325 | break; |
326 | default: |
327 | ASSERT(false); |
328 | break; |
329 | } |
330 | |
331 | return depth; |
332 | } |
333 | |
334 | static enum dcn_hubbub_page_table_block_size page_table_block_size_to_hw(unsigned int page_table_block_size) |
335 | { |
336 | enum dcn_hubbub_page_table_block_size block_size = 0; |
337 | |
338 | switch (page_table_block_size) { |
339 | case 4096: |
340 | block_size = DCN_PAGE_TABLE_BLOCK_SIZE_4KB; |
341 | break; |
342 | case 65536: |
343 | block_size = DCN_PAGE_TABLE_BLOCK_SIZE_64KB; |
344 | break; |
345 | case 32768: |
346 | block_size = DCN_PAGE_TABLE_BLOCK_SIZE_32KB; |
347 | break; |
348 | default: |
349 | ASSERT(false); |
350 | block_size = page_table_block_size; |
351 | break; |
352 | } |
353 | |
354 | return block_size; |
355 | } |
356 | |
357 | void hubbub2_init_vm_ctx(struct hubbub *hubbub, |
358 | struct dcn_hubbub_virt_addr_config *va_config, |
359 | int vmid) |
360 | { |
361 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
362 | struct dcn_vmid_page_table_config virt_config; |
363 | |
364 | virt_config.page_table_start_addr = va_config->page_table_start_addr >> 12; |
365 | virt_config.page_table_end_addr = va_config->page_table_end_addr >> 12; |
366 | virt_config.depth = page_table_depth_to_hw(page_table_depth: va_config->page_table_depth); |
367 | virt_config.block_size = page_table_block_size_to_hw(page_table_block_size: va_config->page_table_block_size); |
368 | virt_config.page_table_base_addr = va_config->page_table_base_addr; |
369 | |
370 | dcn20_vmid_setup(vmid: &hubbub1->vmid[vmid], config: &virt_config); |
371 | } |
372 | |
373 | int hubbub2_init_dchub_sys_ctx(struct hubbub *hubbub, |
374 | struct dcn_hubbub_phys_addr_config *pa_config) |
375 | { |
376 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
377 | struct dcn_vmid_page_table_config phys_config; |
378 | |
379 | REG_SET(DCN_VM_FB_LOCATION_BASE, 0, |
380 | FB_BASE, pa_config->system_aperture.fb_base >> 24); |
381 | REG_SET(DCN_VM_FB_LOCATION_TOP, 0, |
382 | FB_TOP, pa_config->system_aperture.fb_top >> 24); |
383 | REG_SET(DCN_VM_FB_OFFSET, 0, |
384 | FB_OFFSET, pa_config->system_aperture.fb_offset >> 24); |
385 | REG_SET(DCN_VM_AGP_BOT, 0, |
386 | AGP_BOT, pa_config->system_aperture.agp_bot >> 24); |
387 | REG_SET(DCN_VM_AGP_TOP, 0, |
388 | AGP_TOP, pa_config->system_aperture.agp_top >> 24); |
389 | REG_SET(DCN_VM_AGP_BASE, 0, |
390 | AGP_BASE, pa_config->system_aperture.agp_base >> 24); |
391 | |
392 | REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, 0, |
393 | DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, (pa_config->page_table_default_page_addr >> 44) & 0xF); |
394 | REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, 0, |
395 | DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, (pa_config->page_table_default_page_addr >> 12) & 0xFFFFFFFF); |
396 | |
397 | if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) { |
398 | phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12; |
399 | phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12; |
400 | phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; |
401 | phys_config.depth = 0; |
402 | phys_config.block_size = 0; |
403 | // Init VMID 0 based on PA config |
404 | dcn20_vmid_setup(vmid: &hubbub1->vmid[0], config: &phys_config); |
405 | } |
406 | |
407 | return NUM_VMID; |
408 | } |
409 | |
410 | void hubbub2_update_dchub(struct hubbub *hubbub, |
411 | struct dchub_init_data *dh_data) |
412 | { |
413 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
414 | |
415 | if (REG(DCN_VM_FB_LOCATION_TOP) == 0) |
416 | return; |
417 | |
418 | switch (dh_data->fb_mode) { |
419 | case FRAME_BUFFER_MODE_ZFB_ONLY: |
420 | /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ |
421 | REG_UPDATE(DCN_VM_FB_LOCATION_TOP, |
422 | FB_TOP, 0); |
423 | |
424 | REG_UPDATE(DCN_VM_FB_LOCATION_BASE, |
425 | FB_BASE, 0xFFFFFF); |
426 | |
427 | /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ |
428 | REG_UPDATE(DCN_VM_AGP_BASE, |
429 | AGP_BASE, dh_data->zfb_phys_addr_base >> 24); |
430 | |
431 | /*This field defines the bottom range of the AGP aperture and represents the 24*/ |
432 | /*MSBs, bits [47:24] of the 48 address bits*/ |
433 | REG_UPDATE(DCN_VM_AGP_BOT, |
434 | AGP_BOT, dh_data->zfb_mc_base_addr >> 24); |
435 | |
436 | /*This field defines the top range of the AGP aperture and represents the 24*/ |
437 | /*MSBs, bits [47:24] of the 48 address bits*/ |
438 | REG_UPDATE(DCN_VM_AGP_TOP, |
439 | AGP_TOP, (dh_data->zfb_mc_base_addr + |
440 | dh_data->zfb_size_in_byte - 1) >> 24); |
441 | break; |
442 | case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: |
443 | /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ |
444 | |
445 | /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ |
446 | REG_UPDATE(DCN_VM_AGP_BASE, |
447 | AGP_BASE, dh_data->zfb_phys_addr_base >> 24); |
448 | |
449 | /*This field defines the bottom range of the AGP aperture and represents the 24*/ |
450 | /*MSBs, bits [47:24] of the 48 address bits*/ |
451 | REG_UPDATE(DCN_VM_AGP_BOT, |
452 | AGP_BOT, dh_data->zfb_mc_base_addr >> 24); |
453 | |
454 | /*This field defines the top range of the AGP aperture and represents the 24*/ |
455 | /*MSBs, bits [47:24] of the 48 address bits*/ |
456 | REG_UPDATE(DCN_VM_AGP_TOP, |
457 | AGP_TOP, (dh_data->zfb_mc_base_addr + |
458 | dh_data->zfb_size_in_byte - 1) >> 24); |
459 | break; |
460 | case FRAME_BUFFER_MODE_LOCAL_ONLY: |
461 | /*Should not touch FB LOCATION (should be done by VBIOS)*/ |
462 | |
463 | /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ |
464 | REG_UPDATE(DCN_VM_AGP_BASE, |
465 | AGP_BASE, 0); |
466 | |
467 | /*This field defines the bottom range of the AGP aperture and represents the 24*/ |
468 | /*MSBs, bits [47:24] of the 48 address bits*/ |
469 | REG_UPDATE(DCN_VM_AGP_BOT, |
470 | AGP_BOT, 0xFFFFFF); |
471 | |
472 | /*This field defines the top range of the AGP aperture and represents the 24*/ |
473 | /*MSBs, bits [47:24] of the 48 address bits*/ |
474 | REG_UPDATE(DCN_VM_AGP_TOP, |
475 | AGP_TOP, 0); |
476 | break; |
477 | default: |
478 | break; |
479 | } |
480 | |
481 | dh_data->dchub_initialzied = true; |
482 | dh_data->dchub_info_valid = false; |
483 | } |
484 | |
485 | void hubbub2_wm_read_state(struct hubbub *hubbub, |
486 | struct dcn_hubbub_wm *wm) |
487 | { |
488 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
489 | |
490 | struct dcn_hubbub_wm_set *s; |
491 | |
492 | memset(wm, 0, sizeof(struct dcn_hubbub_wm)); |
493 | |
494 | s = &wm->sets[0]; |
495 | s->wm_set = 0; |
496 | s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A); |
497 | if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A)) |
498 | s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A); |
499 | if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { |
500 | s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A); |
501 | s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A); |
502 | } |
503 | s->dram_clk_change = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A); |
504 | |
505 | s = &wm->sets[1]; |
506 | s->wm_set = 1; |
507 | s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B); |
508 | if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B)) |
509 | s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B); |
510 | if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { |
511 | s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B); |
512 | s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B); |
513 | } |
514 | s->dram_clk_change = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B); |
515 | |
516 | s = &wm->sets[2]; |
517 | s->wm_set = 2; |
518 | s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C); |
519 | if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C)) |
520 | s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C); |
521 | if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { |
522 | s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C); |
523 | s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C); |
524 | } |
525 | s->dram_clk_change = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C); |
526 | |
527 | s = &wm->sets[3]; |
528 | s->wm_set = 3; |
529 | s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D); |
530 | if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D)) |
531 | s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D); |
532 | if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { |
533 | s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D); |
534 | s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D); |
535 | } |
536 | s->dram_clk_change = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D); |
537 | } |
538 | |
539 | void hubbub2_get_dchub_ref_freq(struct hubbub *hubbub, |
540 | unsigned int dccg_ref_freq_inKhz, |
541 | unsigned int *dchub_ref_freq_inKhz) |
542 | { |
543 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
544 | uint32_t ref_div = 0; |
545 | uint32_t ref_en = 0; |
546 | |
547 | REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div, |
548 | DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en); |
549 | |
550 | if (ref_en) { |
551 | if (ref_div == 2) |
552 | *dchub_ref_freq_inKhz = dccg_ref_freq_inKhz / 2; |
553 | else |
554 | *dchub_ref_freq_inKhz = dccg_ref_freq_inKhz; |
555 | |
556 | // DC hub reference frequency must be around 50Mhz, otherwise there may be |
557 | // overflow/underflow issues when doing HUBBUB programming |
558 | if (*dchub_ref_freq_inKhz < 40000 || *dchub_ref_freq_inKhz > 60000) |
559 | ASSERT_CRITICAL(false); |
560 | |
561 | return; |
562 | } else { |
563 | *dchub_ref_freq_inKhz = dccg_ref_freq_inKhz; |
564 | |
565 | // HUBBUB global timer must be enabled. |
566 | ASSERT_CRITICAL(false); |
567 | return; |
568 | } |
569 | } |
570 | |
571 | static bool hubbub2_program_watermarks( |
572 | struct hubbub *hubbub, |
573 | struct dcn_watermark_set *watermarks, |
574 | unsigned int refclk_mhz, |
575 | bool safe_to_lower) |
576 | { |
577 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
578 | bool wm_pending = false; |
579 | /* |
580 | * Need to clamp to max of the register values (i.e. no wrap) |
581 | * for dcn1, all wm registers are 21-bit wide |
582 | */ |
583 | if (hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) |
584 | wm_pending = true; |
585 | |
586 | if (hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower)) |
587 | wm_pending = true; |
588 | |
589 | /* |
590 | * There's a special case when going from p-state support to p-state unsupported |
591 | * here we are going to LOWER watermarks to go to dummy p-state only, but this has |
592 | * to be done prepare_bandwidth, not optimize |
593 | */ |
594 | if (hubbub1->base.ctx->dc->clk_mgr->clks.prev_p_state_change_support == true && |
595 | hubbub1->base.ctx->dc->clk_mgr->clks.p_state_change_support == false) |
596 | safe_to_lower = true; |
597 | |
598 | hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); |
599 | |
600 | REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, |
601 | DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); |
602 | REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 180); |
603 | |
604 | hubbub->funcs->allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); |
605 | return wm_pending; |
606 | } |
607 | |
608 | void hubbub2_read_state(struct hubbub *hubbub, struct dcn_hubbub_state *hubbub_state) |
609 | { |
610 | struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); |
611 | |
612 | if (REG(DCN_VM_FAULT_ADDR_MSB)) |
613 | hubbub_state->vm_fault_addr_msb = REG_READ(DCN_VM_FAULT_ADDR_MSB); |
614 | |
615 | if (REG(DCN_VM_FAULT_ADDR_LSB)) |
616 | hubbub_state->vm_fault_addr_msb = REG_READ(DCN_VM_FAULT_ADDR_LSB); |
617 | |
618 | if (REG(DCN_VM_FAULT_CNTL)) |
619 | REG_GET(DCN_VM_FAULT_CNTL, DCN_VM_ERROR_STATUS_MODE, &hubbub_state->vm_error_mode); |
620 | |
621 | if (REG(DCN_VM_FAULT_STATUS)) { |
622 | REG_GET(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_STATUS, &hubbub_state->vm_error_status); |
623 | REG_GET(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_VMID, &hubbub_state->vm_error_vmid); |
624 | REG_GET(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, &hubbub_state->vm_error_pipe); |
625 | } |
626 | |
627 | if (REG(DCHUBBUB_TEST_DEBUG_INDEX) && REG(DCHUBBUB_TEST_DEBUG_DATA)) { |
628 | REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, 0x6); |
629 | hubbub_state->test_debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA); |
630 | } |
631 | |
632 | if (REG(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL)) |
633 | hubbub_state->watermark_change_cntl = REG_READ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL); |
634 | |
635 | if (REG(DCHUBBUB_ARB_DRAM_STATE_CNTL)) |
636 | hubbub_state->dram_state_cntl = REG_READ(DCHUBBUB_ARB_DRAM_STATE_CNTL); |
637 | } |
638 | |
639 | static const struct hubbub_funcs hubbub2_funcs = { |
640 | .update_dchub = hubbub2_update_dchub, |
641 | .init_dchub_sys_ctx = hubbub2_init_dchub_sys_ctx, |
642 | .init_vm_ctx = hubbub2_init_vm_ctx, |
643 | .dcc_support_swizzle = hubbub2_dcc_support_swizzle, |
644 | .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format, |
645 | .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap, |
646 | .wm_read_state = hubbub2_wm_read_state, |
647 | .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, |
648 | .program_watermarks = hubbub2_program_watermarks, |
649 | .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, |
650 | .allow_self_refresh_control = hubbub1_allow_self_refresh_control, |
651 | .hubbub_read_state = hubbub2_read_state, |
652 | }; |
653 | |
654 | void hubbub2_construct(struct dcn20_hubbub *hubbub, |
655 | struct dc_context *ctx, |
656 | const struct dcn_hubbub_registers *hubbub_regs, |
657 | const struct dcn_hubbub_shift *hubbub_shift, |
658 | const struct dcn_hubbub_mask *hubbub_mask) |
659 | { |
660 | hubbub->base.ctx = ctx; |
661 | |
662 | hubbub->base.funcs = &hubbub2_funcs; |
663 | |
664 | hubbub->regs = hubbub_regs; |
665 | hubbub->shifts = hubbub_shift; |
666 | hubbub->masks = hubbub_mask; |
667 | |
668 | hubbub->debug_test_index_pstate = 0xB; |
669 | hubbub->detile_buf_size = 164 * 1024; /* 164KB for DCN2.0 */ |
670 | } |
671 | |