1 /* 2 * Copyright 2012-15 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 #include "dm_services.h" 27 28 #include "dce/dce_11_0_d.h" 29 #include "dce/dce_11_0_sh_mask.h" 30 #include "gmc/gmc_8_2_sh_mask.h" 31 #include "gmc/gmc_8_2_d.h" 32 33 #include "include/logger_interface.h" 34 35 #include "dce110_compressor.h" 36 37 #define DC_LOGGER \ 38 cp110->base.ctx->logger 39 #define DCP_REG(reg)\ 40 (reg + cp110->offsets.dcp_offset) 41 #define DMIF_REG(reg)\ 42 (reg + cp110->offsets.dmif_offset) 43 44 static const struct dce110_compressor_reg_offsets reg_offsets[] = { 45 { 46 .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), 47 .dmif_offset = 48 (mmDMIF_PG0_DPG_PIPE_DPM_CONTROL 49 - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), 50 }, 51 { 52 .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), 53 .dmif_offset = 54 (mmDMIF_PG1_DPG_PIPE_DPM_CONTROL 55 - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), 56 }, 57 { 58 .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL), 59 .dmif_offset = 60 (mmDMIF_PG2_DPG_PIPE_DPM_CONTROL 61 - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL), 62 } 63 }; 64 65 static uint32_t align_to_chunks_number_per_line(uint32_t pixels) 66 { 67 return 256 * ((pixels + 255) / 256); 68 } 69 70 static void reset_lb_on_vblank(struct compressor *compressor, uint32_t crtc_inst) 71 { 72 uint32_t value; 73 uint32_t frame_count; 74 uint32_t status_pos; 75 uint32_t retry = 0; 76 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 77 78 cp110->offsets = reg_offsets[crtc_inst]; 79 80 status_pos = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION)); 81 82 83 /* Only if CRTC is enabled and counter is moving we wait for one frame. */ 84 if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) { 85 /* Resetting LB on VBlank */ 86 value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL)); 87 set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL); 88 set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2); 89 dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value); 90 91 frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)); 92 93 94 for (retry = 10000; retry > 0; retry--) { 95 if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT))) 96 break; 97 udelay(10); 98 } 99 if (!retry) 100 dm_error("Frame count did not increase for 100ms.\n"); 101 102 /* Resetting LB on VBlank */ 103 value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL)); 104 set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL); 105 set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2); 106 dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value); 107 } 108 } 109 110 static void wait_for_fbc_state_changed( 111 struct dce110_compressor *cp110, 112 bool enabled) 113 { 114 uint32_t counter = 0; 115 uint32_t addr = mmFBC_STATUS; 116 uint32_t value; 117 118 while (counter < 1000) { 119 value = dm_read_reg(cp110->base.ctx, addr); 120 if (get_reg_field_value( 121 value, 122 FBC_STATUS, 123 FBC_ENABLE_STATUS) == enabled) 124 break; 125 udelay(100); 126 counter++; 127 } 128 129 if (counter == 1000) { 130 DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", 131 __func__); 132 } else { 133 DC_LOG_SYNC("FBC status changed to %d", enabled); 134 } 135 136 137 } 138 139 void dce110_compressor_power_up_fbc(struct compressor *compressor) 140 { 141 uint32_t value; 142 uint32_t addr; 143 144 addr = mmFBC_CNTL; 145 value = dm_read_reg(compressor->ctx, addr); 146 set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); 147 set_reg_field_value(value, 1, FBC_CNTL, FBC_EN); 148 set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE); 149 if (compressor->options.bits.CLK_GATING_DISABLED == 1) { 150 /* HW needs to do power measurement comparison. */ 151 set_reg_field_value( 152 value, 153 0, 154 FBC_CNTL, 155 FBC_COMP_CLK_GATE_EN); 156 } 157 dm_write_reg(compressor->ctx, addr, value); 158 159 addr = mmFBC_COMP_MODE; 160 value = dm_read_reg(compressor->ctx, addr); 161 set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN); 162 set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN); 163 set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN); 164 dm_write_reg(compressor->ctx, addr, value); 165 166 addr = mmFBC_COMP_CNTL; 167 value = dm_read_reg(compressor->ctx, addr); 168 set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN); 169 dm_write_reg(compressor->ctx, addr, value); 170 /*FBC_MIN_COMPRESSION 0 ==> 2:1 */ 171 /* 1 ==> 4:1 */ 172 /* 2 ==> 8:1 */ 173 /* 0xF ==> 1:1 */ 174 set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION); 175 dm_write_reg(compressor->ctx, addr, value); 176 compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1; 177 178 value = 0; 179 dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value); 180 181 value = 0xFFFFFF; 182 dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value); 183 } 184 185 void dce110_compressor_enable_fbc( 186 struct compressor *compressor, 187 struct compr_addr_and_pitch_params *params) 188 { 189 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 190 191 if (compressor->options.bits.FBC_SUPPORT && 192 (!dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL))) { 193 194 uint32_t addr; 195 uint32_t value, misc_value; 196 197 addr = mmFBC_CNTL; 198 value = dm_read_reg(compressor->ctx, addr); 199 set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); 200 /* params->inst is valid HW CRTC instance start from 0 */ 201 set_reg_field_value( 202 value, 203 params->inst, 204 FBC_CNTL, FBC_SRC_SEL); 205 dm_write_reg(compressor->ctx, addr, value); 206 207 /* Keep track of enum controller_id FBC is attached to */ 208 compressor->is_enabled = true; 209 /* attached_inst is SW CRTC instance start from 1 210 * 0 = CONTROLLER_ID_UNDEFINED means not attached crtc 211 */ 212 compressor->attached_inst = params->inst + CONTROLLER_ID_D0; 213 214 /* Toggle it as there is bug in HW */ 215 set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN); 216 dm_write_reg(compressor->ctx, addr, value); 217 218 /* FBC usage with scatter & gather for dce110 */ 219 misc_value = dm_read_reg(compressor->ctx, mmFBC_MISC); 220 221 set_reg_field_value(misc_value, 1, 222 FBC_MISC, FBC_INVALIDATE_ON_ERROR); 223 set_reg_field_value(misc_value, 1, 224 FBC_MISC, FBC_DECOMPRESS_ERROR_CLEAR); 225 set_reg_field_value(misc_value, 0x14, 226 FBC_MISC, FBC_SLOW_REQ_INTERVAL); 227 228 dm_write_reg(compressor->ctx, mmFBC_MISC, misc_value); 229 230 /* Enable FBC */ 231 set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN); 232 dm_write_reg(compressor->ctx, addr, value); 233 234 wait_for_fbc_state_changed(cp110, true); 235 } 236 } 237 238 void dce110_compressor_disable_fbc(struct compressor *compressor) 239 { 240 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 241 uint32_t crtc_inst = 0; 242 243 if (compressor->options.bits.FBC_SUPPORT) { 244 if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) { 245 uint32_t reg_data; 246 /* Turn off compression */ 247 reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL); 248 set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN); 249 dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data); 250 251 /* Reset enum controller_id to undefined */ 252 compressor->attached_inst = 0; 253 compressor->is_enabled = false; 254 255 wait_for_fbc_state_changed(cp110, false); 256 } 257 258 /* Sync line buffer which fbc was attached to dce100/110 only */ 259 if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3) 260 reset_lb_on_vblank(compressor, 261 crtc_inst - CONTROLLER_ID_D0); 262 } 263 } 264 265 bool dce110_compressor_is_fbc_enabled_in_hw( 266 struct compressor *compressor, 267 uint32_t *inst) 268 { 269 /* Check the hardware register */ 270 uint32_t value; 271 272 value = dm_read_reg(compressor->ctx, mmFBC_STATUS); 273 if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) { 274 if (inst != NULL) 275 *inst = compressor->attached_inst; 276 return true; 277 } 278 279 value = dm_read_reg(compressor->ctx, mmFBC_MISC); 280 if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) { 281 value = dm_read_reg(compressor->ctx, mmFBC_CNTL); 282 283 if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) { 284 if (inst != NULL) 285 *inst = 286 compressor->attached_inst; 287 return true; 288 } 289 } 290 return false; 291 } 292 293 294 void dce110_compressor_program_compressed_surface_address_and_pitch( 295 struct compressor *compressor, 296 struct compr_addr_and_pitch_params *params) 297 { 298 struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor); 299 uint32_t value = 0; 300 uint32_t fbc_pitch = 0; 301 uint32_t compressed_surf_address_low_part = 302 compressor->compr_surface_address.addr.low_part; 303 304 cp110->offsets = reg_offsets[params->inst]; 305 306 /* Clear content first. */ 307 dm_write_reg( 308 compressor->ctx, 309 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH), 310 0); 311 dm_write_reg(compressor->ctx, 312 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0); 313 314 /* Write address, HIGH has to be first. */ 315 dm_write_reg(compressor->ctx, 316 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH), 317 compressor->compr_surface_address.addr.high_part); 318 dm_write_reg(compressor->ctx, 319 DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 320 compressed_surf_address_low_part); 321 322 fbc_pitch = align_to_chunks_number_per_line(params->source_view_width); 323 324 if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1) 325 fbc_pitch = fbc_pitch / 8; 326 else 327 DC_LOG_WARNING("%s: Unexpected DCE11 compression ratio", 328 __func__); 329 330 /* Clear content first. */ 331 dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0); 332 333 /* Write FBC Pitch. */ 334 set_reg_field_value( 335 value, 336 fbc_pitch, 337 GRPH_COMPRESS_PITCH, 338 GRPH_COMPRESS_PITCH); 339 dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value); 340 341 } 342 343 void dce110_compressor_set_fbc_invalidation_triggers( 344 struct compressor *compressor, 345 uint32_t fbc_trigger) 346 { 347 /* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19) 348 * for DCE 11 regions cannot be used - does not work with S/G 349 */ 350 uint32_t addr = mmFBC_CLIENT_REGION_MASK; 351 uint32_t value = dm_read_reg(compressor->ctx, addr); 352 353 set_reg_field_value( 354 value, 355 0, 356 FBC_CLIENT_REGION_MASK, 357 FBC_MEMORY_REGION_MASK); 358 dm_write_reg(compressor->ctx, addr, value); 359 360 /* Setup events when to clear all CSM entries (effectively marking 361 * current compressed data invalid) 362 * For DCE 11 CSM metadata 11111 means - "Not Compressed" 363 * Used as the initial value of the metadata sent to the compressor 364 * after invalidation, to indicate that the compressor should attempt 365 * to compress all chunks on the current pass. Also used when the chunk 366 * is not successfully written to memory. 367 * When this CSM value is detected, FBC reads from the uncompressed 368 * buffer. Set events according to passed in value, these events are 369 * valid for DCE11: 370 * - bit 0 - display register updated 371 * - bit 28 - memory write from any client except from MCIF 372 * - bit 29 - CG static screen signal is inactive 373 * In addition, DCE11.1 also needs to set new DCE11.1 specific events 374 * that are used to trigger invalidation on certain register changes, 375 * for example enabling of Alpha Compression may trigger invalidation of 376 * FBC once bit is set. These events are as follows: 377 * - Bit 2 - FBC_GRPH_COMP_EN register updated 378 * - Bit 3 - FBC_SRC_SEL register updated 379 * - Bit 4 - FBC_MIN_COMPRESSION register updated 380 * - Bit 5 - FBC_ALPHA_COMP_EN register updated 381 * - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated 382 * - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated 383 */ 384 addr = mmFBC_IDLE_FORCE_CLEAR_MASK; 385 value = dm_read_reg(compressor->ctx, addr); 386 set_reg_field_value( 387 value, 388 fbc_trigger, 389 FBC_IDLE_FORCE_CLEAR_MASK, 390 FBC_IDLE_FORCE_CLEAR_MASK); 391 dm_write_reg(compressor->ctx, addr, value); 392 } 393 394 struct compressor *dce110_compressor_create(struct dc_context *ctx) 395 { 396 struct dce110_compressor *cp110 = 397 kzalloc(sizeof(struct dce110_compressor), GFP_KERNEL); 398 399 if (!cp110) 400 return NULL; 401 402 dce110_compressor_construct(cp110, ctx); 403 return &cp110->base; 404 } 405 406 void dce110_compressor_destroy(struct compressor **compressor) 407 { 408 kfree(TO_DCE110_COMPRESSOR(*compressor)); 409 *compressor = NULL; 410 } 411 412 void get_max_support_fbc_buffersize(unsigned int *max_x, unsigned int *max_y) 413 { 414 *max_x = FBC_MAX_X; 415 *max_y = FBC_MAX_Y; 416 417 /* if (m_smallLocalFrameBufferMemory == 1) 418 * { 419 * *max_x = FBC_MAX_X_SG; 420 * *max_y = FBC_MAX_Y_SG; 421 * } 422 */ 423 } 424 425 static const struct compressor_funcs dce110_compressor_funcs = { 426 .power_up_fbc = dce110_compressor_power_up_fbc, 427 .enable_fbc = dce110_compressor_enable_fbc, 428 .disable_fbc = dce110_compressor_disable_fbc, 429 .set_fbc_invalidation_triggers = dce110_compressor_set_fbc_invalidation_triggers, 430 .surface_address_and_pitch = dce110_compressor_program_compressed_surface_address_and_pitch, 431 .is_fbc_enabled_in_hw = dce110_compressor_is_fbc_enabled_in_hw 432 }; 433 434 435 void dce110_compressor_construct(struct dce110_compressor *compressor, 436 struct dc_context *ctx) 437 { 438 439 compressor->base.options.raw = 0; 440 compressor->base.options.bits.FBC_SUPPORT = true; 441 442 /* for dce 11 always use one dram channel for lpt */ 443 compressor->base.lpt_channels_num = 1; 444 compressor->base.options.bits.DUMMY_BACKEND = false; 445 446 /* 447 * check if this system has more than 1 dram channel; if only 1 then lpt 448 * should not be supported 449 */ 450 451 452 compressor->base.options.bits.CLK_GATING_DISABLED = false; 453 454 compressor->base.ctx = ctx; 455 compressor->base.embedded_panel_h_size = 0; 456 compressor->base.embedded_panel_v_size = 0; 457 compressor->base.memory_bus_width = ctx->asic_id.vram_width; 458 compressor->base.allocated_size = 0; 459 compressor->base.preferred_requested_size = 0; 460 compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID; 461 compressor->base.banks_num = 0; 462 compressor->base.raw_size = 0; 463 compressor->base.channel_interleave_size = 0; 464 compressor->base.dram_channels_num = 0; 465 compressor->base.lpt_channels_num = 0; 466 compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED; 467 compressor->base.is_enabled = false; 468 compressor->base.funcs = &dce110_compressor_funcs; 469 470 } 471 472