1/* $NetBSD: amdgpu_dce110_compressor.c,v 1.3 2021/12/19 10:59:02 riastradh Exp $ */ 2 3/* 4 * Copyright 2012-15 Advanced Micro Devices, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: AMD 25 * 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: amdgpu_dce110_compressor.c,v 1.3 2021/12/19 10:59:02 riastradh Exp $"); 30 31#include <linux/delay.h> 32#include <linux/slab.h> 33 34#include "dm_services.h" 35 36#include "dce/dce_11_0_d.h" 37#include "dce/dce_11_0_sh_mask.h" 38#include "gmc/gmc_8_2_sh_mask.h" 39#include "gmc/gmc_8_2_d.h" 40 41#include "include/logger_interface.h" 42 43#include "dce110_compressor.h" 44 45#define DC_LOGGER \ 46 cp110->base.ctx->logger 47#define DCP_REG(reg)\ 48 (reg + cp110->offsets.dcp_offset) 49#define DMIF_REG(reg)\ 50 (reg + cp110->offsets.dmif_offset) 51 52static const struct dce110_compressor_reg_offsets reg_offsets[] = { 53{ 54 .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), 55 .dmif_offset = 56 (mmDMIF_PG0_DPG_PIPE_DPM_CONTROL 57 - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), 58}, 59{ 60 .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), 61 .dmif_offset = 62 (mmDMIF_PG1_DPG_PIPE_DPM_CONTROL 63 - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), 64}, 65{ 66 .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), 67 .dmif_offset = 68 (mmDMIF_PG2_DPG_PIPE_DPM_CONTROL 69 - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), 70} 71}; 72 73static uint32_t align_to_chunks_number_per_line(uint32_t pixels) 74{ 75 return 256 * ((pixels + 255) / 256); 76} 77 78static void reset_lb_on_vblank(struct compressor *compressor, uint32_t crtc_inst) 79{ 80 uint32_t value; 81 uint32_t frame_count; 82 uint32_t status_pos; 83 uint32_t retry = 0; 84 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 85 86 cp110->offsets = reg_offsets[crtc_inst]; 87 88 status_pos = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION)); 89 90 91 /* Only if CRTC is enabled and counter is moving we wait for one frame. */ 92 if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) { 93 /* Resetting LB on VBlank */ 94 value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL)); 95 set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL); 96 set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2); 97 dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value); 98 99 frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)); 100 101 102 for (retry = 10000; retry > 0; retry--) { 103 if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT))) 104 break; 105 udelay(10); 106 } 107 if (!retry) 108 dm_error("Frame count did not increase for 100ms.\n"); 109 110 /* Resetting LB on VBlank */ 111 value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL)); 112 set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL); 113 set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2); 114 dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value); 115 } 116} 117 118static void wait_for_fbc_state_changed( 119 struct dce110_compressor *cp110, 120 bool enabled) 121{ 122 uint32_t counter = 0; 123 uint32_t addr = mmFBC_STATUS; 124 uint32_t value; 125 126 while (counter < 1000) { 127 value = dm_read_reg(cp110->base.ctx, addr); 128 if (get_reg_field_value( 129 value, 130 FBC_STATUS, 131 FBC_ENABLE_STATUS) == enabled) 132 break; 133 udelay(100); 134 counter++; 135 } 136 137 if (counter == 1000) { 138 DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", 139 __func__); 140 } else { 141 DC_LOG_SYNC("FBC status changed to %d", enabled); 142 } 143 144 145} 146 147void dce110_compressor_power_up_fbc(struct compressor *compressor) 148{ 149 uint32_t value; 150 uint32_t addr; 151 152 addr = mmFBC_CNTL; 153 value = dm_read_reg(compressor->ctx, addr); 154 set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); 155 set_reg_field_value(value, 1, FBC_CNTL, FBC_EN); 156 set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE); 157 if (compressor->options.bits.CLK_GATING_DISABLED == 1) { 158 /* HW needs to do power measurement comparison. */ 159 set_reg_field_value( 160 value, 161 0, 162 FBC_CNTL, 163 FBC_COMP_CLK_GATE_EN); 164 } 165 dm_write_reg(compressor->ctx, addr, value); 166 167 addr = mmFBC_COMP_MODE; 168 value = dm_read_reg(compressor->ctx, addr); 169 set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN); 170 set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN); 171 set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN); 172 dm_write_reg(compressor->ctx, addr, value); 173 174 addr = mmFBC_COMP_CNTL; 175 value = dm_read_reg(compressor->ctx, addr); 176 set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN); 177 dm_write_reg(compressor->ctx, addr, value); 178 /*FBC_MIN_COMPRESSION 0 ==> 2:1 */ 179 /* 1 ==> 4:1 */ 180 /* 2 ==> 8:1 */ 181 /* 0xF ==> 1:1 */ 182 set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION); 183 dm_write_reg(compressor->ctx, addr, value); 184 compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1; 185 186 value = 0; 187 dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value); 188 189 value = 0xFFFFFF; 190 dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value); 191} 192 193void dce110_compressor_enable_fbc( 194 struct compressor *compressor, 195 struct compr_addr_and_pitch_params *params) 196{ 197 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 198 199 if (compressor->options.bits.FBC_SUPPORT && 200 (!dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL))) { 201 202 uint32_t addr; 203 uint32_t value, misc_value; 204 205 addr = mmFBC_CNTL; 206 value = dm_read_reg(compressor->ctx, addr); 207 set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); 208 /* params->inst is valid HW CRTC instance start from 0 */ 209 set_reg_field_value( 210 value, 211 params->inst, 212 FBC_CNTL, FBC_SRC_SEL); 213 dm_write_reg(compressor->ctx, addr, value); 214 215 /* Keep track of enum controller_id FBC is attached to */ 216 compressor->is_enabled = true; 217 /* attached_inst is SW CRTC instance start from 1 218 * 0 = CONTROLLER_ID_UNDEFINED means not attached crtc 219 */ 220 compressor->attached_inst = params->inst + CONTROLLER_ID_D0; 221 222 /* Toggle it as there is bug in HW */ 223 set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); 224 dm_write_reg(compressor->ctx, addr, value); 225 226 /* FBC usage with scatter & gather for dce110 */ 227 misc_value = dm_read_reg(compressor->ctx, mmFBC_MISC); 228 229 set_reg_field_value(misc_value, 1, 230 FBC_MISC, FBC_INVALIDATE_ON_ERROR); 231 set_reg_field_value(misc_value, 1, 232 FBC_MISC, FBC_DECOMPRESS_ERROR_CLEAR); 233 set_reg_field_value(misc_value, 0x14, 234 FBC_MISC, FBC_SLOW_REQ_INTERVAL); 235 236 dm_write_reg(compressor->ctx, mmFBC_MISC, misc_value); 237 238 /* Enable FBC */ 239 set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); 240 dm_write_reg(compressor->ctx, addr, value); 241 242 wait_for_fbc_state_changed(cp110, true); 243 } 244} 245 246void dce110_compressor_disable_fbc(struct compressor *compressor) 247{ 248 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 249 uint32_t crtc_inst = 0; 250 251 if (compressor->options.bits.FBC_SUPPORT) { 252 if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) { 253 uint32_t reg_data; 254 /* Turn off compression */ 255 reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL); 256 set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN); 257 dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data); 258 259 /* Reset enum controller_id to undefined */ 260 compressor->attached_inst = 0; 261 compressor->is_enabled = false; 262 263 wait_for_fbc_state_changed(cp110, false); 264 } 265 266 /* Sync line buffer which fbc was attached to dce100/110 only */ 267 if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3) 268 reset_lb_on_vblank(compressor, 269 crtc_inst - CONTROLLER_ID_D0); 270 } 271} 272 273bool dce110_compressor_is_fbc_enabled_in_hw( 274 struct compressor *compressor, 275 uint32_t *inst) 276{ 277 /* Check the hardware register */ 278 uint32_t value; 279 280 value = dm_read_reg(compressor->ctx, mmFBC_STATUS); 281 if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) { 282 if (inst != NULL) 283 *inst = compressor->attached_inst; 284 return true; 285 } 286 287 value = dm_read_reg(compressor->ctx, mmFBC_MISC); 288 if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) { 289 value = dm_read_reg(compressor->ctx, mmFBC_CNTL); 290 291 if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) { 292 if (inst != NULL) 293 *inst = 294 compressor->attached_inst; 295 return true; 296 } 297 } 298 return false; 299} 300 301 302void dce110_compressor_program_compressed_surface_address_and_pitch( 303 struct compressor *compressor, 304 struct compr_addr_and_pitch_params *params) 305{ 306 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 307 uint32_t value = 0; 308 uint32_t fbc_pitch = 0; 309 uint32_t compressed_surf_address_low_part = 310 compressor->compr_surface_address.addr.low_part; 311 312 cp110->offsets = reg_offsets[params->inst]; 313 314 /* Clear content first. */ 315 dm_write_reg( 316 compressor->ctx, 317 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH), 318 0); 319 dm_write_reg(compressor->ctx, 320 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0); 321 322 /* Write address, HIGH has to be first. */ 323 dm_write_reg(compressor->ctx, 324 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH), 325 compressor->compr_surface_address.addr.high_part); 326 dm_write_reg(compressor->ctx, 327 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 328 compressed_surf_address_low_part); 329 330 fbc_pitch = align_to_chunks_number_per_line(params->source_view_width); 331 332 if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1) 333 fbc_pitch = fbc_pitch / 8; 334 else 335 DC_LOG_WARNING("%s: Unexpected DCE11 compression ratio", 336 __func__); 337 338 /* Clear content first. */ 339 dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0); 340 341 /* Write FBC Pitch. */ 342 set_reg_field_value( 343 value, 344 fbc_pitch, 345 GRPH_COMPRESS_PITCH, 346 GRPH_COMPRESS_PITCH); 347 dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value); 348 349} 350 351void dce110_compressor_set_fbc_invalidation_triggers( 352 struct compressor *compressor, 353 uint32_t fbc_trigger) 354{ 355 /* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19) 356 * for DCE 11 regions cannot be used - does not work with S/G 357 */ 358 uint32_t addr = mmFBC_CLIENT_REGION_MASK; 359 uint32_t value = dm_read_reg(compressor->ctx, addr); 360 361 set_reg_field_value( 362 value, 363 0, 364 FBC_CLIENT_REGION_MASK, 365 FBC_MEMORY_REGION_MASK); 366 dm_write_reg(compressor->ctx, addr, value); 367 368 /* Setup events when to clear all CSM entries (effectively marking 369 * current compressed data invalid) 370 * For DCE 11 CSM metadata 11111 means - "Not Compressed" 371 * Used as the initial value of the metadata sent to the compressor 372 * after invalidation, to indicate that the compressor should attempt 373 * to compress all chunks on the current pass. Also used when the chunk 374 * is not successfully written to memory. 375 * When this CSM value is detected, FBC reads from the uncompressed 376 * buffer. Set events according to passed in value, these events are 377 * valid for DCE11: 378 * - bit 0 - display register updated 379 * - bit 28 - memory write from any client except from MCIF 380 * - bit 29 - CG static screen signal is inactive 381 * In addition, DCE11.1 also needs to set new DCE11.1 specific events 382 * that are used to trigger invalidation on certain register changes, 383 * for example enabling of Alpha Compression may trigger invalidation of 384 * FBC once bit is set. These events are as follows: 385 * - Bit 2 - FBC_GRPH_COMP_EN register updated 386 * - Bit 3 - FBC_SRC_SEL register updated 387 * - Bit 4 - FBC_MIN_COMPRESSION register updated 388 * - Bit 5 - FBC_ALPHA_COMP_EN register updated 389 * - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated 390 * - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated 391 */ 392 addr = mmFBC_IDLE_FORCE_CLEAR_MASK; 393 value = dm_read_reg(compressor->ctx, addr); 394 set_reg_field_value( 395 value, 396 fbc_trigger, 397 FBC_IDLE_FORCE_CLEAR_MASK, 398 FBC_IDLE_FORCE_CLEAR_MASK); 399 dm_write_reg(compressor->ctx, addr, value); 400} 401 402struct compressor *dce110_compressor_create(struct dc_context *ctx) 403{ 404 struct dce110_compressor *cp110 = 405 kzalloc(sizeof(struct dce110_compressor), GFP_KERNEL); 406 407 if (!cp110) 408 return NULL; 409 410 dce110_compressor_construct(cp110, ctx); 411 return &cp110->base; 412} 413 414void dce110_compressor_destroy(struct compressor **compressor) 415{ 416 kfree(TO_DCE110_COMPRESSOR(*compressor)); 417 *compressor = NULL; 418} 419 420static __unused 421bool dce110_get_required_compressed_surfacesize(struct fbc_input_info fbc_input_info, 422 struct fbc_requested_compressed_size size) 423{ 424 bool result = false; 425 426 unsigned int max_x = FBC_MAX_X, max_y = FBC_MAX_Y; 427 428 get_max_support_fbc_buffersize(&max_x, &max_y); 429 430 if (fbc_input_info.dynamic_fbc_buffer_alloc == 0) { 431 /* 432 * For DCE11 here use Max HW supported size: HW Support up to 3840x2400 resolution 433 * or 18000 chunks. 434 */ 435 size.preferred_size = size.min_size = align_to_chunks_number_per_line(max_x) * max_y * 4; /* (For FBC when LPT not supported). */ 436 size.preferred_size_alignment = size.min_size_alignment = 0x100; /* For FBC when LPT not supported */ 437 size.bits.preferred_must_be_framebuffer_pool = 1; 438 size.bits.min_must_be_framebuffer_pool = 1; 439 440 result = true; 441 } 442 /* 443 * Maybe to add registry key support with optional size here to override above 444 * for debugging purposes 445 */ 446 447 return result; 448} 449 450 451void get_max_support_fbc_buffersize(unsigned int *max_x, unsigned int *max_y) 452{ 453 *max_x = FBC_MAX_X; 454 *max_y = FBC_MAX_Y; 455 456 /* if (m_smallLocalFrameBufferMemory == 1) 457 * { 458 * *max_x = FBC_MAX_X_SG; 459 * *max_y = FBC_MAX_Y_SG; 460 * } 461 */ 462} 463 464 465static __unused 466unsigned int controller_id_to_index(enum controller_id controller_id) 467{ 468 unsigned int index = 0; 469 470 switch (controller_id) { 471 case CONTROLLER_ID_D0: 472 index = 0; 473 break; 474 case CONTROLLER_ID_D1: 475 index = 1; 476 break; 477 case CONTROLLER_ID_D2: 478 index = 2; 479 break; 480 case CONTROLLER_ID_D3: 481 index = 3; 482 break; 483 default: 484 break; 485 } 486 return index; 487} 488 489 490static const struct compressor_funcs dce110_compressor_funcs = { 491 .power_up_fbc = dce110_compressor_power_up_fbc, 492 .enable_fbc = dce110_compressor_enable_fbc, 493 .disable_fbc = dce110_compressor_disable_fbc, 494 .set_fbc_invalidation_triggers = dce110_compressor_set_fbc_invalidation_triggers, 495 .surface_address_and_pitch = dce110_compressor_program_compressed_surface_address_and_pitch, 496 .is_fbc_enabled_in_hw = dce110_compressor_is_fbc_enabled_in_hw 497}; 498 499 500void dce110_compressor_construct(struct dce110_compressor *compressor, 501 struct dc_context *ctx) 502{ 503 504 compressor->base.options.raw = 0; 505 compressor->base.options.bits.FBC_SUPPORT = true; 506 507 /* for dce 11 always use one dram channel for lpt */ 508 compressor->base.lpt_channels_num = 1; 509 compressor->base.options.bits.DUMMY_BACKEND = false; 510 511 /* 512 * check if this system has more than 1 dram channel; if only 1 then lpt 513 * should not be supported 514 */ 515 516 517 compressor->base.options.bits.CLK_GATING_DISABLED = false; 518 519 compressor->base.ctx = ctx; 520 compressor->base.embedded_panel_h_size = 0; 521 compressor->base.embedded_panel_v_size = 0; 522 compressor->base.memory_bus_width = ctx->asic_id.vram_width; 523 compressor->base.allocated_size = 0; 524 compressor->base.preferred_requested_size = 0; 525 compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID; 526 compressor->base.banks_num = 0; 527 compressor->base.raw_size = 0; 528 compressor->base.channel_interleave_size = 0; 529 compressor->base.dram_channels_num = 0; 530 compressor->base.lpt_channels_num = 0; 531 compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED; 532 compressor->base.is_enabled = false; 533 compressor->base.funcs = &dce110_compressor_funcs; 534 535} 536 537