]> Git Repo - J-linux.git/blob - drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpu / drm / amd / display / dc / dce110 / dce110_compressor.c
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
This page took 0.056537 seconds and 4 git commands to generate.