Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2020 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 
0027 #include "dm_services.h"
0028 #include "reg_helper.h"
0029 #include "dcn30_hubbub.h"
0030 
0031 
0032 #define CTX \
0033     hubbub1->base.ctx
0034 #define DC_LOGGER \
0035     hubbub1->base.ctx->logger
0036 #define REG(reg)\
0037     hubbub1->regs->reg
0038 
0039 #undef FN
0040 #define FN(reg_name, field_name) \
0041     hubbub1->shifts->field_name, hubbub1->masks->field_name
0042 
0043 #ifdef NUM_VMID
0044 #undef NUM_VMID
0045 #endif
0046 #define NUM_VMID 16
0047 
0048 
0049 static uint32_t convert_and_clamp(
0050     uint32_t wm_ns,
0051     uint32_t refclk_mhz,
0052     uint32_t clamp_value)
0053 {
0054     uint32_t ret_val = 0;
0055     ret_val = wm_ns * refclk_mhz;
0056     ret_val /= 1000;
0057 
0058     if (ret_val > clamp_value)
0059         ret_val = clamp_value;
0060 
0061     return ret_val;
0062 }
0063 
0064 int hubbub3_init_dchub_sys_ctx(struct hubbub *hubbub,
0065         struct dcn_hubbub_phys_addr_config *pa_config)
0066 {
0067     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0068     struct dcn_vmid_page_table_config phys_config;
0069 
0070     REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
0071             FB_BASE, pa_config->system_aperture.fb_base >> 24);
0072     REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
0073             FB_TOP, pa_config->system_aperture.fb_top >> 24);
0074     REG_SET(DCN_VM_FB_OFFSET, 0,
0075             FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
0076     REG_SET(DCN_VM_AGP_BOT, 0,
0077             AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
0078     REG_SET(DCN_VM_AGP_TOP, 0,
0079             AGP_TOP, pa_config->system_aperture.agp_top >> 24);
0080     REG_SET(DCN_VM_AGP_BASE, 0,
0081             AGP_BASE, pa_config->system_aperture.agp_base >> 24);
0082 
0083     if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
0084         phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
0085         phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
0086         phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
0087         phys_config.depth = 0;
0088         phys_config.block_size = 0;
0089         // Init VMID 0 based on PA config
0090         dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config);
0091     }
0092 
0093     return NUM_VMID;
0094 }
0095 
0096 bool hubbub3_program_watermarks(
0097         struct hubbub *hubbub,
0098         struct dcn_watermark_set *watermarks,
0099         unsigned int refclk_mhz,
0100         bool safe_to_lower)
0101 {
0102     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0103     bool wm_pending = false;
0104 
0105     if (hubbub21_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0106         wm_pending = true;
0107 
0108     if (hubbub21_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0109         wm_pending = true;
0110 
0111     if (hubbub21_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0112         wm_pending = true;
0113 
0114     /*
0115      * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
0116      * If the memory controller is fully utilized and the DCHub requestors are
0117      * well ahead of their amortized schedule, then it is safe to prevent the next winner
0118      * from being committed and sent to the fabric.
0119      * The utilization of the memory controller is approximated by ensuring that
0120      * the number of outstanding requests is greater than a threshold specified
0121      * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
0122      * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
0123      *
0124      * TODO: Revisit request limit after figure out right number. request limit for Renoir isn't decided yet, set maximum value (0x1FF)
0125      * to turn off it for now.
0126      */
0127     REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
0128             DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
0129     REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
0130             DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);
0131 
0132     hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
0133 
0134     return wm_pending;
0135 }
0136 
0137 bool hubbub3_dcc_support_swizzle(
0138         enum swizzle_mode_values swizzle,
0139         unsigned int bytes_per_element,
0140         enum segment_order *segment_order_horz,
0141         enum segment_order *segment_order_vert)
0142 {
0143     bool standard_swizzle = false;
0144     bool display_swizzle = false;
0145     bool render_swizzle = false;
0146 
0147     switch (swizzle) {
0148     case DC_SW_4KB_S:
0149     case DC_SW_64KB_S:
0150     case DC_SW_VAR_S:
0151     case DC_SW_4KB_S_X:
0152     case DC_SW_64KB_S_X:
0153     case DC_SW_VAR_S_X:
0154         standard_swizzle = true;
0155         break;
0156     case DC_SW_4KB_R:
0157     case DC_SW_64KB_R:
0158     case DC_SW_VAR_R:
0159     case DC_SW_4KB_R_X:
0160     case DC_SW_64KB_R_X:
0161     case DC_SW_VAR_R_X:
0162         render_swizzle = true;
0163         break;
0164     case DC_SW_4KB_D:
0165     case DC_SW_64KB_D:
0166     case DC_SW_VAR_D:
0167     case DC_SW_4KB_D_X:
0168     case DC_SW_64KB_D_X:
0169     case DC_SW_VAR_D_X:
0170         display_swizzle = true;
0171         break;
0172     default:
0173         break;
0174     }
0175 
0176     if (standard_swizzle) {
0177         if (bytes_per_element == 1) {
0178             *segment_order_horz = segment_order__contiguous;
0179             *segment_order_vert = segment_order__na;
0180             return true;
0181         }
0182         if (bytes_per_element == 2) {
0183             *segment_order_horz = segment_order__non_contiguous;
0184             *segment_order_vert = segment_order__contiguous;
0185             return true;
0186         }
0187         if (bytes_per_element == 4) {
0188             *segment_order_horz = segment_order__non_contiguous;
0189             *segment_order_vert = segment_order__contiguous;
0190             return true;
0191         }
0192         if (bytes_per_element == 8) {
0193             *segment_order_horz = segment_order__na;
0194             *segment_order_vert = segment_order__contiguous;
0195             return true;
0196         }
0197     }
0198     if (render_swizzle) {
0199         if (bytes_per_element == 1) {
0200             *segment_order_horz = segment_order__contiguous;
0201             *segment_order_vert = segment_order__na;
0202             return true;
0203         }
0204         if (bytes_per_element == 2) {
0205             *segment_order_horz = segment_order__non_contiguous;
0206             *segment_order_vert = segment_order__contiguous;
0207             return true;
0208         }
0209         if (bytes_per_element == 4) {
0210             *segment_order_horz = segment_order__contiguous;
0211             *segment_order_vert = segment_order__non_contiguous;
0212             return true;
0213         }
0214         if (bytes_per_element == 8) {
0215             *segment_order_horz = segment_order__contiguous;
0216             *segment_order_vert = segment_order__non_contiguous;
0217             return true;
0218         }
0219     }
0220     if (display_swizzle && bytes_per_element == 8) {
0221         *segment_order_horz = segment_order__contiguous;
0222         *segment_order_vert = segment_order__non_contiguous;
0223         return true;
0224     }
0225 
0226     return false;
0227 }
0228 
0229 static void hubbub3_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height,
0230         unsigned int bytes_per_element)
0231 {
0232     /* copied from DML.  might want to refactor DML to leverage from DML */
0233     /* DML : get_blk256_size */
0234     if (bytes_per_element == 1) {
0235         *blk256_width = 16;
0236         *blk256_height = 16;
0237     } else if (bytes_per_element == 2) {
0238         *blk256_width = 16;
0239         *blk256_height = 8;
0240     } else if (bytes_per_element == 4) {
0241         *blk256_width = 8;
0242         *blk256_height = 8;
0243     } else if (bytes_per_element == 8) {
0244         *blk256_width = 8;
0245         *blk256_height = 4;
0246     }
0247 }
0248 
0249 static void hubbub3_det_request_size(
0250         unsigned int detile_buf_size,
0251         unsigned int height,
0252         unsigned int width,
0253         unsigned int bpe,
0254         bool *req128_horz_wc,
0255         bool *req128_vert_wc)
0256 {
0257     unsigned int blk256_height = 0;
0258     unsigned int blk256_width = 0;
0259     unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
0260 
0261     hubbub3_get_blk256_size(&blk256_width, &blk256_height, bpe);
0262 
0263     swath_bytes_horz_wc = width * blk256_height * bpe;
0264     swath_bytes_vert_wc = height * blk256_width * bpe;
0265 
0266     *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
0267             false : /* full 256B request */
0268             true; /* half 128b request */
0269 
0270     *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
0271             false : /* full 256B request */
0272             true; /* half 128b request */
0273 }
0274 
0275 bool hubbub3_get_dcc_compression_cap(struct hubbub *hubbub,
0276         const struct dc_dcc_surface_param *input,
0277         struct dc_surface_dcc_cap *output)
0278 {
0279     struct dc *dc = hubbub->ctx->dc;
0280     /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */
0281     enum dcc_control dcc_control;
0282     unsigned int bpe;
0283     enum segment_order segment_order_horz, segment_order_vert;
0284     bool req128_horz_wc, req128_vert_wc;
0285 
0286     memset(output, 0, sizeof(*output));
0287 
0288     if (dc->debug.disable_dcc == DCC_DISABLE)
0289         return false;
0290 
0291     if (!hubbub->funcs->dcc_support_pixel_format(input->format,
0292             &bpe))
0293         return false;
0294 
0295     if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
0296             &segment_order_horz, &segment_order_vert))
0297         return false;
0298 
0299     hubbub3_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size,
0300             input->surface_size.height,  input->surface_size.width,
0301             bpe, &req128_horz_wc, &req128_vert_wc);
0302 
0303     if (!req128_horz_wc && !req128_vert_wc) {
0304         dcc_control = dcc_control__256_256_xxx;
0305     } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
0306         if (!req128_horz_wc)
0307             dcc_control = dcc_control__256_256_xxx;
0308         else if (segment_order_horz == segment_order__contiguous)
0309             dcc_control = dcc_control__128_128_xxx;
0310         else
0311             dcc_control = dcc_control__256_64_64;
0312     } else if (input->scan == SCAN_DIRECTION_VERTICAL) {
0313         if (!req128_vert_wc)
0314             dcc_control = dcc_control__256_256_xxx;
0315         else if (segment_order_vert == segment_order__contiguous)
0316             dcc_control = dcc_control__128_128_xxx;
0317         else
0318             dcc_control = dcc_control__256_64_64;
0319     } else {
0320         if ((req128_horz_wc &&
0321             segment_order_horz == segment_order__non_contiguous) ||
0322             (req128_vert_wc &&
0323             segment_order_vert == segment_order__non_contiguous))
0324             /* access_dir not known, must use most constraining */
0325             dcc_control = dcc_control__256_64_64;
0326         else
0327             /* reg128 is true for either horz and vert
0328              * but segment_order is contiguous
0329              */
0330             dcc_control = dcc_control__128_128_xxx;
0331     }
0332 
0333     /* Exception for 64KB_R_X */
0334     if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X))
0335         dcc_control = dcc_control__128_128_xxx;
0336 
0337     if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
0338         dcc_control != dcc_control__256_256_xxx)
0339         return false;
0340 
0341     switch (dcc_control) {
0342     case dcc_control__256_256_xxx:
0343         output->grph.rgb.max_uncompressed_blk_size = 256;
0344         output->grph.rgb.max_compressed_blk_size = 256;
0345         output->grph.rgb.independent_64b_blks = false;
0346         output->grph.rgb.dcc_controls.dcc_256_256_unconstrained = 1;
0347         output->grph.rgb.dcc_controls.dcc_256_128_128 = 1;
0348         break;
0349     case dcc_control__128_128_xxx:
0350         output->grph.rgb.max_uncompressed_blk_size = 128;
0351         output->grph.rgb.max_compressed_blk_size = 128;
0352         output->grph.rgb.independent_64b_blks = false;
0353         output->grph.rgb.dcc_controls.dcc_128_128_uncontrained = 1;
0354         output->grph.rgb.dcc_controls.dcc_256_128_128 = 1;
0355         break;
0356     case dcc_control__256_64_64:
0357         output->grph.rgb.max_uncompressed_blk_size = 256;
0358         output->grph.rgb.max_compressed_blk_size = 64;
0359         output->grph.rgb.independent_64b_blks = true;
0360         output->grph.rgb.dcc_controls.dcc_256_64_64 = 1;
0361         break;
0362     case dcc_control__256_128_128:
0363         output->grph.rgb.max_uncompressed_blk_size = 256;
0364         output->grph.rgb.max_compressed_blk_size = 128;
0365         output->grph.rgb.independent_64b_blks = false;
0366         output->grph.rgb.dcc_controls.dcc_256_128_128 = 1;
0367         break;
0368     }
0369     output->capable = true;
0370     output->const_color_support = true;
0371 
0372     return true;
0373 }
0374 
0375 void hubbub3_force_wm_propagate_to_pipes(struct hubbub *hubbub)
0376 {
0377     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0378     uint32_t refclk_mhz = hubbub->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
0379     uint32_t prog_wm_value = convert_and_clamp(hubbub1->watermarks.a.urgent_ns,
0380             refclk_mhz, 0x1fffff);
0381 
0382     REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
0383             DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value,
0384             DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, prog_wm_value);
0385 }
0386 
0387 void hubbub3_force_pstate_change_control(struct hubbub *hubbub,
0388         bool force, bool allow)
0389 {
0390     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0391 
0392     REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
0393             DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, allow,
0394             DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, force);
0395 }
0396 
0397 /* Copy values from WM set A to all other sets */
0398 void hubbub3_init_watermarks(struct hubbub *hubbub)
0399 {
0400     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0401     uint32_t reg;
0402 
0403     reg = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
0404     REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, reg);
0405     REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, reg);
0406     REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, reg);
0407 
0408     reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A);
0409     REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, reg);
0410     REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, reg);
0411     REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, reg);
0412 
0413     reg = REG_READ(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A);
0414     REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, reg);
0415     REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, reg);
0416     REG_WRITE(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, reg);
0417 
0418     reg = REG_READ(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A);
0419     REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, reg);
0420     REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, reg);
0421     REG_WRITE(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, reg);
0422 
0423     reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
0424     REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, reg);
0425     REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, reg);
0426     REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, reg);
0427 
0428     reg = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
0429     REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, reg);
0430     REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, reg);
0431     REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, reg);
0432 
0433     reg = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
0434     REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, reg);
0435     REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, reg);
0436     REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, reg);
0437 }
0438 
0439 static const struct hubbub_funcs hubbub30_funcs = {
0440     .update_dchub = hubbub2_update_dchub,
0441     .init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx,
0442     .init_vm_ctx = hubbub2_init_vm_ctx,
0443     .dcc_support_swizzle = hubbub3_dcc_support_swizzle,
0444     .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
0445     .get_dcc_compression_cap = hubbub3_get_dcc_compression_cap,
0446     .wm_read_state = hubbub21_wm_read_state,
0447     .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
0448     .program_watermarks = hubbub3_program_watermarks,
0449     .allow_self_refresh_control = hubbub1_allow_self_refresh_control,
0450     .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
0451     .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
0452     .force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
0453     .force_pstate_change_control = hubbub3_force_pstate_change_control,
0454     .init_watermarks = hubbub3_init_watermarks,
0455     .hubbub_read_state = hubbub2_read_state,
0456 };
0457 
0458 void hubbub3_construct(struct dcn20_hubbub *hubbub3,
0459     struct dc_context *ctx,
0460     const struct dcn_hubbub_registers *hubbub_regs,
0461     const struct dcn_hubbub_shift *hubbub_shift,
0462     const struct dcn_hubbub_mask *hubbub_mask)
0463 {
0464     hubbub3->base.ctx = ctx;
0465     hubbub3->base.funcs = &hubbub30_funcs;
0466     hubbub3->regs = hubbub_regs;
0467     hubbub3->shifts = hubbub_shift;
0468     hubbub3->masks = hubbub_mask;
0469 
0470     hubbub3->debug_test_index_pstate = 0xB;
0471     hubbub3->detile_buf_size = 184 * 1024; /* 184KB for DCN3 */
0472 }
0473