Line data Source code
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 0 : return 256 * ((pixels + 255) / 256);
68 : }
69 :
70 0 : 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 0 : uint32_t retry = 0;
76 0 : struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
77 :
78 0 : cp110->offsets = reg_offsets[crtc_inst];
79 :
80 0 : 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 0 : if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) {
85 : /* Resetting LB on VBlank */
86 0 : value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
87 0 : set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
88 0 : set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
89 0 : dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
90 :
91 0 : frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT));
92 :
93 :
94 0 : for (retry = 10000; retry > 0; retry--) {
95 0 : if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)))
96 : break;
97 0 : udelay(10);
98 : }
99 0 : if (!retry)
100 0 : dm_error("Frame count did not increase for 100ms.\n");
101 :
102 : /* Resetting LB on VBlank */
103 0 : value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
104 0 : set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
105 0 : set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
106 0 : dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
107 : }
108 0 : }
109 :
110 0 : static void wait_for_fbc_state_changed(
111 : struct dce110_compressor *cp110,
112 : bool enabled)
113 : {
114 0 : uint32_t counter = 0;
115 0 : uint32_t addr = mmFBC_STATUS;
116 : uint32_t value;
117 :
118 0 : while (counter < 1000) {
119 0 : value = dm_read_reg(cp110->base.ctx, addr);
120 0 : if (get_reg_field_value(
121 : value,
122 : FBC_STATUS,
123 0 : FBC_ENABLE_STATUS) == enabled)
124 : break;
125 0 : udelay(100);
126 0 : counter++;
127 : }
128 :
129 0 : if (counter == 1000) {
130 0 : DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied",
131 : __func__);
132 : } else {
133 0 : DC_LOG_SYNC("FBC status changed to %d", enabled);
134 : }
135 :
136 :
137 0 : }
138 :
139 0 : void dce110_compressor_power_up_fbc(struct compressor *compressor)
140 : {
141 : uint32_t value;
142 : uint32_t addr;
143 :
144 0 : addr = mmFBC_CNTL;
145 0 : value = dm_read_reg(compressor->ctx, addr);
146 0 : set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
147 0 : set_reg_field_value(value, 1, FBC_CNTL, FBC_EN);
148 0 : set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE);
149 0 : if (compressor->options.bits.CLK_GATING_DISABLED == 1) {
150 : /* HW needs to do power measurement comparison. */
151 0 : set_reg_field_value(
152 : value,
153 : 0,
154 : FBC_CNTL,
155 : FBC_COMP_CLK_GATE_EN);
156 : }
157 0 : dm_write_reg(compressor->ctx, addr, value);
158 :
159 0 : addr = mmFBC_COMP_MODE;
160 0 : value = dm_read_reg(compressor->ctx, addr);
161 0 : set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN);
162 0 : set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN);
163 0 : set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN);
164 0 : dm_write_reg(compressor->ctx, addr, value);
165 :
166 0 : addr = mmFBC_COMP_CNTL;
167 0 : value = dm_read_reg(compressor->ctx, addr);
168 0 : set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN);
169 0 : 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 0 : set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION);
175 0 : dm_write_reg(compressor->ctx, addr, value);
176 0 : compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1;
177 :
178 0 : value = 0;
179 0 : dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value);
180 :
181 0 : value = 0xFFFFFF;
182 0 : dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value);
183 0 : }
184 :
185 0 : void dce110_compressor_enable_fbc(
186 : struct compressor *compressor,
187 : struct compr_addr_and_pitch_params *params)
188 : {
189 0 : struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
190 :
191 0 : if (compressor->options.bits.FBC_SUPPORT &&
192 0 : (!dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL))) {
193 :
194 : uint32_t addr;
195 : uint32_t value, misc_value;
196 :
197 0 : addr = mmFBC_CNTL;
198 0 : value = dm_read_reg(compressor->ctx, addr);
199 0 : set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
200 : /* params->inst is valid HW CRTC instance start from 0 */
201 0 : set_reg_field_value(
202 : value,
203 : params->inst,
204 : FBC_CNTL, FBC_SRC_SEL);
205 0 : dm_write_reg(compressor->ctx, addr, value);
206 :
207 : /* Keep track of enum controller_id FBC is attached to */
208 0 : 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 0 : compressor->attached_inst = params->inst + CONTROLLER_ID_D0;
213 :
214 : /* Toggle it as there is bug in HW */
215 0 : set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
216 0 : dm_write_reg(compressor->ctx, addr, value);
217 :
218 : /* FBC usage with scatter & gather for dce110 */
219 0 : misc_value = dm_read_reg(compressor->ctx, mmFBC_MISC);
220 :
221 0 : set_reg_field_value(misc_value, 1,
222 : FBC_MISC, FBC_INVALIDATE_ON_ERROR);
223 0 : set_reg_field_value(misc_value, 1,
224 : FBC_MISC, FBC_DECOMPRESS_ERROR_CLEAR);
225 0 : set_reg_field_value(misc_value, 0x14,
226 : FBC_MISC, FBC_SLOW_REQ_INTERVAL);
227 :
228 0 : dm_write_reg(compressor->ctx, mmFBC_MISC, misc_value);
229 :
230 : /* Enable FBC */
231 0 : set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
232 0 : dm_write_reg(compressor->ctx, addr, value);
233 :
234 0 : wait_for_fbc_state_changed(cp110, true);
235 : }
236 0 : }
237 :
238 0 : void dce110_compressor_disable_fbc(struct compressor *compressor)
239 : {
240 0 : struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
241 0 : uint32_t crtc_inst = 0;
242 :
243 0 : if (compressor->options.bits.FBC_SUPPORT) {
244 0 : if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) {
245 : uint32_t reg_data;
246 : /* Turn off compression */
247 0 : reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL);
248 0 : set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
249 0 : dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data);
250 :
251 : /* Reset enum controller_id to undefined */
252 0 : compressor->attached_inst = 0;
253 0 : compressor->is_enabled = false;
254 :
255 0 : wait_for_fbc_state_changed(cp110, false);
256 : }
257 :
258 : /* Sync line buffer which fbc was attached to dce100/110 only */
259 0 : if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3)
260 0 : reset_lb_on_vblank(compressor,
261 : crtc_inst - CONTROLLER_ID_D0);
262 : }
263 0 : }
264 :
265 0 : 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 0 : value = dm_read_reg(compressor->ctx, mmFBC_STATUS);
273 0 : if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) {
274 0 : if (inst != NULL)
275 0 : *inst = compressor->attached_inst;
276 : return true;
277 : }
278 :
279 0 : value = dm_read_reg(compressor->ctx, mmFBC_MISC);
280 0 : if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) {
281 0 : value = dm_read_reg(compressor->ctx, mmFBC_CNTL);
282 :
283 0 : if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) {
284 0 : if (inst != NULL)
285 0 : *inst =
286 0 : compressor->attached_inst;
287 : return true;
288 : }
289 : }
290 : return false;
291 : }
292 :
293 :
294 0 : void dce110_compressor_program_compressed_surface_address_and_pitch(
295 : struct compressor *compressor,
296 : struct compr_addr_and_pitch_params *params)
297 : {
298 0 : struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
299 0 : uint32_t value = 0;
300 0 : uint32_t fbc_pitch = 0;
301 0 : uint32_t compressed_surf_address_low_part =
302 : compressor->compr_surface_address.addr.low_part;
303 :
304 0 : cp110->offsets = reg_offsets[params->inst];
305 :
306 : /* Clear content first. */
307 0 : dm_write_reg(
308 : compressor->ctx,
309 : DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
310 : 0);
311 0 : dm_write_reg(compressor->ctx,
312 : DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0);
313 :
314 : /* Write address, HIGH has to be first. */
315 0 : dm_write_reg(compressor->ctx,
316 : DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
317 : compressor->compr_surface_address.addr.high_part);
318 0 : dm_write_reg(compressor->ctx,
319 : DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS),
320 : compressed_surf_address_low_part);
321 :
322 0 : fbc_pitch = align_to_chunks_number_per_line(params->source_view_width);
323 :
324 0 : if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1)
325 0 : fbc_pitch = fbc_pitch / 8;
326 : else
327 0 : DC_LOG_WARNING("%s: Unexpected DCE11 compression ratio",
328 : __func__);
329 :
330 : /* Clear content first. */
331 0 : dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0);
332 :
333 : /* Write FBC Pitch. */
334 0 : set_reg_field_value(
335 : value,
336 : fbc_pitch,
337 : GRPH_COMPRESS_PITCH,
338 : GRPH_COMPRESS_PITCH);
339 0 : dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value);
340 :
341 0 : }
342 :
343 0 : 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 0 : uint32_t addr = mmFBC_CLIENT_REGION_MASK;
351 0 : uint32_t value = dm_read_reg(compressor->ctx, addr);
352 :
353 0 : set_reg_field_value(
354 : value,
355 : 0,
356 : FBC_CLIENT_REGION_MASK,
357 : FBC_MEMORY_REGION_MASK);
358 0 : 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 0 : addr = mmFBC_IDLE_FORCE_CLEAR_MASK;
385 0 : value = dm_read_reg(compressor->ctx, addr);
386 0 : set_reg_field_value(
387 : value,
388 : fbc_trigger,
389 : FBC_IDLE_FORCE_CLEAR_MASK,
390 : FBC_IDLE_FORCE_CLEAR_MASK);
391 0 : dm_write_reg(compressor->ctx, addr, value);
392 0 : }
393 :
394 0 : struct compressor *dce110_compressor_create(struct dc_context *ctx)
395 : {
396 0 : struct dce110_compressor *cp110 =
397 : kzalloc(sizeof(struct dce110_compressor), GFP_KERNEL);
398 :
399 0 : if (!cp110)
400 : return NULL;
401 :
402 0 : dce110_compressor_construct(cp110, ctx);
403 0 : return &cp110->base;
404 : }
405 :
406 0 : void dce110_compressor_destroy(struct compressor **compressor)
407 : {
408 0 : kfree(TO_DCE110_COMPRESSOR(*compressor));
409 0 : *compressor = NULL;
410 0 : }
411 :
412 0 : void get_max_support_fbc_buffersize(unsigned int *max_x, unsigned int *max_y)
413 : {
414 0 : *max_x = FBC_MAX_X;
415 0 : *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 0 : }
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 0 : void dce110_compressor_construct(struct dce110_compressor *compressor,
436 : struct dc_context *ctx)
437 : {
438 :
439 0 : compressor->base.options.raw = 0;
440 0 : compressor->base.options.bits.FBC_SUPPORT = true;
441 :
442 : /* for dce 11 always use one dram channel for lpt */
443 0 : compressor->base.lpt_channels_num = 1;
444 0 : 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 0 : compressor->base.options.bits.CLK_GATING_DISABLED = false;
453 :
454 0 : compressor->base.ctx = ctx;
455 0 : compressor->base.embedded_panel_h_size = 0;
456 0 : compressor->base.embedded_panel_v_size = 0;
457 0 : compressor->base.memory_bus_width = ctx->asic_id.vram_width;
458 0 : compressor->base.allocated_size = 0;
459 0 : compressor->base.preferred_requested_size = 0;
460 0 : compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID;
461 0 : compressor->base.banks_num = 0;
462 0 : compressor->base.raw_size = 0;
463 0 : compressor->base.channel_interleave_size = 0;
464 0 : compressor->base.dram_channels_num = 0;
465 0 : compressor->base.lpt_channels_num = 0;
466 0 : compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED;
467 0 : compressor->base.is_enabled = false;
468 0 : compressor->base.funcs = &dce110_compressor_funcs;
469 :
470 0 : }
471 :
|