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