Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dm_services.h"
0027 
0028 #include "dce/dce_11_0_d.h"
0029 #include "dce/dce_11_0_sh_mask.h"
0030 #include "gmc/gmc_8_2_sh_mask.h"
0031 #include "gmc/gmc_8_2_d.h"
0032 
0033 #include "include/logger_interface.h"
0034 
0035 #include "dce110_compressor.h"
0036 
0037 #define DC_LOGGER \
0038         cp110->base.ctx->logger
0039 #define DCP_REG(reg)\
0040     (reg + cp110->offsets.dcp_offset)
0041 #define DMIF_REG(reg)\
0042     (reg + cp110->offsets.dmif_offset)
0043 
0044 static const struct dce110_compressor_reg_offsets reg_offsets[] = {
0045 {
0046     .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
0047     .dmif_offset =
0048         (mmDMIF_PG0_DPG_PIPE_DPM_CONTROL
0049             - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
0050 },
0051 {
0052     .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
0053     .dmif_offset =
0054         (mmDMIF_PG1_DPG_PIPE_DPM_CONTROL
0055             - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
0056 },
0057 {
0058     .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
0059     .dmif_offset =
0060         (mmDMIF_PG2_DPG_PIPE_DPM_CONTROL
0061             - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
0062 }
0063 };
0064 
0065 static uint32_t align_to_chunks_number_per_line(uint32_t pixels)
0066 {
0067     return 256 * ((pixels + 255) / 256);
0068 }
0069 
0070 static void reset_lb_on_vblank(struct compressor *compressor, uint32_t crtc_inst)
0071 {
0072     uint32_t value;
0073     uint32_t frame_count;
0074     uint32_t status_pos;
0075     uint32_t retry = 0;
0076     struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
0077 
0078     cp110->offsets = reg_offsets[crtc_inst];
0079 
0080     status_pos = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION));
0081 
0082 
0083     /* Only if CRTC is enabled and counter is moving we wait for one frame. */
0084     if (status_pos != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_POSITION))) {
0085         /* Resetting LB on VBlank */
0086         value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
0087         set_reg_field_value(value, 3, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
0088         set_reg_field_value(value, 1, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
0089         dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
0090 
0091         frame_count = dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT));
0092 
0093 
0094         for (retry = 10000; retry > 0; retry--) {
0095             if (frame_count != dm_read_reg(compressor->ctx, DCP_REG(mmCRTC_STATUS_FRAME_COUNT)))
0096                 break;
0097             udelay(10);
0098         }
0099         if (!retry)
0100             dm_error("Frame count did not increase for 100ms.\n");
0101 
0102         /* Resetting LB on VBlank */
0103         value = dm_read_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL));
0104         set_reg_field_value(value, 2, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL);
0105         set_reg_field_value(value, 0, LB_SYNC_RESET_SEL, LB_SYNC_RESET_SEL2);
0106         dm_write_reg(compressor->ctx, DCP_REG(mmLB_SYNC_RESET_SEL), value);
0107     }
0108 }
0109 
0110 static void wait_for_fbc_state_changed(
0111     struct dce110_compressor *cp110,
0112     bool enabled)
0113 {
0114     uint32_t counter = 0;
0115     uint32_t addr = mmFBC_STATUS;
0116     uint32_t value;
0117 
0118     while (counter < 1000) {
0119         value = dm_read_reg(cp110->base.ctx, addr);
0120         if (get_reg_field_value(
0121             value,
0122             FBC_STATUS,
0123             FBC_ENABLE_STATUS) == enabled)
0124             break;
0125         udelay(100);
0126         counter++;
0127     }
0128 
0129     if (counter == 1000) {
0130         DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied",
0131             __func__);
0132     } else {
0133         DC_LOG_SYNC("FBC status changed to %d", enabled);
0134     }
0135 
0136 
0137 }
0138 
0139 void dce110_compressor_power_up_fbc(struct compressor *compressor)
0140 {
0141     uint32_t value;
0142     uint32_t addr;
0143 
0144     addr = mmFBC_CNTL;
0145     value = dm_read_reg(compressor->ctx, addr);
0146     set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
0147     set_reg_field_value(value, 1, FBC_CNTL, FBC_EN);
0148     set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE);
0149     if (compressor->options.bits.CLK_GATING_DISABLED == 1) {
0150         /* HW needs to do power measurement comparison. */
0151         set_reg_field_value(
0152             value,
0153             0,
0154             FBC_CNTL,
0155             FBC_COMP_CLK_GATE_EN);
0156     }
0157     dm_write_reg(compressor->ctx, addr, value);
0158 
0159     addr = mmFBC_COMP_MODE;
0160     value = dm_read_reg(compressor->ctx, addr);
0161     set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN);
0162     set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN);
0163     set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN);
0164     dm_write_reg(compressor->ctx, addr, value);
0165 
0166     addr = mmFBC_COMP_CNTL;
0167     value = dm_read_reg(compressor->ctx, addr);
0168     set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN);
0169     dm_write_reg(compressor->ctx, addr, value);
0170     /*FBC_MIN_COMPRESSION 0 ==> 2:1 */
0171     /*                    1 ==> 4:1 */
0172     /*                    2 ==> 8:1 */
0173     /*                  0xF ==> 1:1 */
0174     set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION);
0175     dm_write_reg(compressor->ctx, addr, value);
0176     compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1;
0177 
0178     value = 0;
0179     dm_write_reg(compressor->ctx, mmFBC_IND_LUT0, value);
0180 
0181     value = 0xFFFFFF;
0182     dm_write_reg(compressor->ctx, mmFBC_IND_LUT1, value);
0183 }
0184 
0185 void dce110_compressor_enable_fbc(
0186     struct compressor *compressor,
0187     struct compr_addr_and_pitch_params *params)
0188 {
0189     struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
0190 
0191     if (compressor->options.bits.FBC_SUPPORT &&
0192         (!dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL))) {
0193 
0194         uint32_t addr;
0195         uint32_t value, misc_value;
0196 
0197         addr = mmFBC_CNTL;
0198         value = dm_read_reg(compressor->ctx, addr);
0199         set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
0200         /* params->inst is valid HW CRTC instance start from 0 */
0201         set_reg_field_value(
0202             value,
0203             params->inst,
0204             FBC_CNTL, FBC_SRC_SEL);
0205         dm_write_reg(compressor->ctx, addr, value);
0206 
0207         /* Keep track of enum controller_id FBC is attached to */
0208         compressor->is_enabled = true;
0209         /* attached_inst is SW CRTC instance start from 1
0210          * 0 = CONTROLLER_ID_UNDEFINED means not attached crtc
0211          */
0212         compressor->attached_inst = params->inst + CONTROLLER_ID_D0;
0213 
0214         /* Toggle it as there is bug in HW */
0215         set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
0216         dm_write_reg(compressor->ctx, addr, value);
0217 
0218         /* FBC usage with scatter & gather for dce110 */
0219         misc_value = dm_read_reg(compressor->ctx, mmFBC_MISC);
0220 
0221         set_reg_field_value(misc_value, 1,
0222                 FBC_MISC, FBC_INVALIDATE_ON_ERROR);
0223         set_reg_field_value(misc_value, 1,
0224                 FBC_MISC, FBC_DECOMPRESS_ERROR_CLEAR);
0225         set_reg_field_value(misc_value, 0x14,
0226                 FBC_MISC, FBC_SLOW_REQ_INTERVAL);
0227 
0228         dm_write_reg(compressor->ctx, mmFBC_MISC, misc_value);
0229 
0230         /* Enable FBC */
0231         set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
0232         dm_write_reg(compressor->ctx, addr, value);
0233 
0234         wait_for_fbc_state_changed(cp110, true);
0235     }
0236 }
0237 
0238 void dce110_compressor_disable_fbc(struct compressor *compressor)
0239 {
0240     struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
0241     uint32_t crtc_inst = 0;
0242 
0243     if (compressor->options.bits.FBC_SUPPORT) {
0244         if (dce110_compressor_is_fbc_enabled_in_hw(compressor, &crtc_inst)) {
0245             uint32_t reg_data;
0246             /* Turn off compression */
0247             reg_data = dm_read_reg(compressor->ctx, mmFBC_CNTL);
0248             set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
0249             dm_write_reg(compressor->ctx, mmFBC_CNTL, reg_data);
0250 
0251             /* Reset enum controller_id to undefined */
0252             compressor->attached_inst = 0;
0253             compressor->is_enabled = false;
0254 
0255             wait_for_fbc_state_changed(cp110, false);
0256         }
0257 
0258         /* Sync line buffer which fbc was attached to dce100/110 only */
0259         if (crtc_inst > CONTROLLER_ID_UNDEFINED && crtc_inst < CONTROLLER_ID_D3)
0260             reset_lb_on_vblank(compressor,
0261                     crtc_inst - CONTROLLER_ID_D0);
0262     }
0263 }
0264 
0265 bool dce110_compressor_is_fbc_enabled_in_hw(
0266     struct compressor *compressor,
0267     uint32_t *inst)
0268 {
0269     /* Check the hardware register */
0270     uint32_t value;
0271 
0272     value = dm_read_reg(compressor->ctx, mmFBC_STATUS);
0273     if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) {
0274         if (inst != NULL)
0275             *inst = compressor->attached_inst;
0276         return true;
0277     }
0278 
0279     value = dm_read_reg(compressor->ctx, mmFBC_MISC);
0280     if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) {
0281         value = dm_read_reg(compressor->ctx, mmFBC_CNTL);
0282 
0283         if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) {
0284             if (inst != NULL)
0285                 *inst =
0286                     compressor->attached_inst;
0287             return true;
0288         }
0289     }
0290     return false;
0291 }
0292 
0293 
0294 void dce110_compressor_program_compressed_surface_address_and_pitch(
0295     struct compressor *compressor,
0296     struct compr_addr_and_pitch_params *params)
0297 {
0298     struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
0299     uint32_t value = 0;
0300     uint32_t fbc_pitch = 0;
0301     uint32_t compressed_surf_address_low_part =
0302         compressor->compr_surface_address.addr.low_part;
0303 
0304     cp110->offsets = reg_offsets[params->inst];
0305 
0306     /* Clear content first. */
0307     dm_write_reg(
0308         compressor->ctx,
0309         DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
0310         0);
0311     dm_write_reg(compressor->ctx,
0312         DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0);
0313 
0314     /* Write address, HIGH has to be first. */
0315     dm_write_reg(compressor->ctx,
0316         DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
0317         compressor->compr_surface_address.addr.high_part);
0318     dm_write_reg(compressor->ctx,
0319         DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS),
0320         compressed_surf_address_low_part);
0321 
0322     fbc_pitch = align_to_chunks_number_per_line(params->source_view_width);
0323 
0324     if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1)
0325         fbc_pitch = fbc_pitch / 8;
0326     else
0327         DC_LOG_WARNING("%s: Unexpected DCE11 compression ratio",
0328             __func__);
0329 
0330     /* Clear content first. */
0331     dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0);
0332 
0333     /* Write FBC Pitch. */
0334     set_reg_field_value(
0335         value,
0336         fbc_pitch,
0337         GRPH_COMPRESS_PITCH,
0338         GRPH_COMPRESS_PITCH);
0339     dm_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value);
0340 
0341 }
0342 
0343 void dce110_compressor_set_fbc_invalidation_triggers(
0344     struct compressor *compressor,
0345     uint32_t fbc_trigger)
0346 {
0347     /* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19)
0348      * for DCE 11 regions cannot be used - does not work with S/G
0349      */
0350     uint32_t addr = mmFBC_CLIENT_REGION_MASK;
0351     uint32_t value = dm_read_reg(compressor->ctx, addr);
0352 
0353     set_reg_field_value(
0354         value,
0355         0,
0356         FBC_CLIENT_REGION_MASK,
0357         FBC_MEMORY_REGION_MASK);
0358     dm_write_reg(compressor->ctx, addr, value);
0359 
0360     /* Setup events when to clear all CSM entries (effectively marking
0361      * current compressed data invalid)
0362      * For DCE 11 CSM metadata 11111 means - "Not Compressed"
0363      * Used as the initial value of the metadata sent to the compressor
0364      * after invalidation, to indicate that the compressor should attempt
0365      * to compress all chunks on the current pass.  Also used when the chunk
0366      * is not successfully written to memory.
0367      * When this CSM value is detected, FBC reads from the uncompressed
0368      * buffer. Set events according to passed in value, these events are
0369      * valid for DCE11:
0370      *     - bit  0 - display register updated
0371      *     - bit 28 - memory write from any client except from MCIF
0372      *     - bit 29 - CG static screen signal is inactive
0373      * In addition, DCE11.1 also needs to set new DCE11.1 specific events
0374      * that are used to trigger invalidation on certain register changes,
0375      * for example enabling of Alpha Compression may trigger invalidation of
0376      * FBC once bit is set. These events are as follows:
0377      *      - Bit 2 - FBC_GRPH_COMP_EN register updated
0378      *      - Bit 3 - FBC_SRC_SEL register updated
0379      *      - Bit 4 - FBC_MIN_COMPRESSION register updated
0380      *      - Bit 5 - FBC_ALPHA_COMP_EN register updated
0381      *      - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated
0382      *      - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated
0383      */
0384     addr = mmFBC_IDLE_FORCE_CLEAR_MASK;
0385     value = dm_read_reg(compressor->ctx, addr);
0386     set_reg_field_value(
0387         value,
0388         fbc_trigger,
0389         FBC_IDLE_FORCE_CLEAR_MASK,
0390         FBC_IDLE_FORCE_CLEAR_MASK);
0391     dm_write_reg(compressor->ctx, addr, value);
0392 }
0393 
0394 struct compressor *dce110_compressor_create(struct dc_context *ctx)
0395 {
0396     struct dce110_compressor *cp110 =
0397         kzalloc(sizeof(struct dce110_compressor), GFP_KERNEL);
0398 
0399     if (!cp110)
0400         return NULL;
0401 
0402     dce110_compressor_construct(cp110, ctx);
0403     return &cp110->base;
0404 }
0405 
0406 void dce110_compressor_destroy(struct compressor **compressor)
0407 {
0408     kfree(TO_DCE110_COMPRESSOR(*compressor));
0409     *compressor = NULL;
0410 }
0411 
0412 void get_max_support_fbc_buffersize(unsigned int *max_x, unsigned int *max_y)
0413 {
0414     *max_x = FBC_MAX_X;
0415     *max_y = FBC_MAX_Y;
0416 
0417     /* if (m_smallLocalFrameBufferMemory == 1)
0418      * {
0419      *  *max_x = FBC_MAX_X_SG;
0420      *  *max_y = FBC_MAX_Y_SG;
0421      * }
0422      */
0423 }
0424 
0425 static const struct compressor_funcs dce110_compressor_funcs = {
0426     .power_up_fbc = dce110_compressor_power_up_fbc,
0427     .enable_fbc = dce110_compressor_enable_fbc,
0428     .disable_fbc = dce110_compressor_disable_fbc,
0429     .set_fbc_invalidation_triggers = dce110_compressor_set_fbc_invalidation_triggers,
0430     .surface_address_and_pitch = dce110_compressor_program_compressed_surface_address_and_pitch,
0431     .is_fbc_enabled_in_hw = dce110_compressor_is_fbc_enabled_in_hw
0432 };
0433 
0434 
0435 void dce110_compressor_construct(struct dce110_compressor *compressor,
0436     struct dc_context *ctx)
0437 {
0438 
0439     compressor->base.options.raw = 0;
0440     compressor->base.options.bits.FBC_SUPPORT = true;
0441 
0442     /* for dce 11 always use one dram channel for lpt */
0443     compressor->base.lpt_channels_num = 1;
0444     compressor->base.options.bits.DUMMY_BACKEND = false;
0445 
0446     /*
0447      * check if this system has more than 1 dram channel; if only 1 then lpt
0448      * should not be supported
0449      */
0450 
0451 
0452     compressor->base.options.bits.CLK_GATING_DISABLED = false;
0453 
0454     compressor->base.ctx = ctx;
0455     compressor->base.embedded_panel_h_size = 0;
0456     compressor->base.embedded_panel_v_size = 0;
0457     compressor->base.memory_bus_width = ctx->asic_id.vram_width;
0458     compressor->base.allocated_size = 0;
0459     compressor->base.preferred_requested_size = 0;
0460     compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID;
0461     compressor->base.banks_num = 0;
0462     compressor->base.raw_size = 0;
0463     compressor->base.channel_interleave_size = 0;
0464     compressor->base.dram_channels_num = 0;
0465     compressor->base.lpt_channels_num = 0;
0466     compressor->base.attached_inst = CONTROLLER_ID_UNDEFINED;
0467     compressor->base.is_enabled = false;
0468     compressor->base.funcs = &dce110_compressor_funcs;
0469 
0470 }
0471