Back to home page

OSCL-LXR

 
 

    


0001 /*
0002 * Copyright 2018 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 #include <linux/delay.h>
0026 #include "dm_services.h"
0027 #include "dcn20/dcn20_hubbub.h"
0028 #include "dcn21_hubbub.h"
0029 #include "reg_helper.h"
0030 
0031 #define REG(reg)\
0032     hubbub1->regs->reg
0033 #define DC_LOGGER \
0034     hubbub1->base.ctx->logger
0035 #define CTX \
0036     hubbub1->base.ctx
0037 
0038 #undef FN
0039 #define FN(reg_name, field_name) \
0040     hubbub1->shifts->field_name, hubbub1->masks->field_name
0041 
0042 #define REG(reg)\
0043     hubbub1->regs->reg
0044 
0045 #define CTX \
0046     hubbub1->base.ctx
0047 
0048 #undef FN
0049 #define FN(reg_name, field_name) \
0050     hubbub1->shifts->field_name, hubbub1->masks->field_name
0051 
0052 static uint32_t convert_and_clamp(
0053     uint32_t wm_ns,
0054     uint32_t refclk_mhz,
0055     uint32_t clamp_value)
0056 {
0057     uint32_t ret_val = 0;
0058     ret_val = wm_ns * refclk_mhz;
0059     ret_val /= 1000;
0060 
0061     if (ret_val > clamp_value)
0062         ret_val = clamp_value;
0063 
0064     return ret_val;
0065 }
0066 
0067 void dcn21_dchvm_init(struct hubbub *hubbub)
0068 {
0069     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0070     uint32_t riommu_active, prefetch_done;
0071     int i;
0072 
0073     REG_GET(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, &prefetch_done);
0074 
0075     if (prefetch_done) {
0076         hubbub->riommu_active = true;
0077         return;
0078     }
0079     //Init DCHVM block
0080     REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1);
0081 
0082     //Poll until RIOMMU_ACTIVE = 1
0083     for (i = 0; i < 100; i++) {
0084         REG_GET(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, &riommu_active);
0085 
0086         if (riommu_active)
0087             break;
0088         else
0089             udelay(5);
0090     }
0091 
0092     if (riommu_active) {
0093         //Reflect the power status of DCHUBBUB
0094         REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1);
0095 
0096         //Start rIOMMU prefetching
0097         REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1);
0098 
0099         // Enable dynamic clock gating
0100         REG_UPDATE_4(DCHVM_CLK_CTRL,
0101                         HVM_DISPCLK_R_GATE_DIS, 0,
0102                         HVM_DISPCLK_G_GATE_DIS, 0,
0103                         HVM_DCFCLK_R_GATE_DIS, 0,
0104                         HVM_DCFCLK_G_GATE_DIS, 0);
0105 
0106         //Poll until HOSTVM_PREFETCH_DONE = 1
0107         REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100);
0108 
0109         hubbub->riommu_active = true;
0110     }
0111 }
0112 
0113 int hubbub21_init_dchub(struct hubbub *hubbub,
0114         struct dcn_hubbub_phys_addr_config *pa_config)
0115 {
0116     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0117     struct dcn_vmid_page_table_config phys_config;
0118 
0119     REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
0120             FB_BASE, pa_config->system_aperture.fb_base >> 24);
0121     REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
0122             FB_TOP, pa_config->system_aperture.fb_top >> 24);
0123     REG_SET(DCN_VM_FB_OFFSET, 0,
0124             FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
0125     REG_SET(DCN_VM_AGP_BOT, 0,
0126             AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
0127     REG_SET(DCN_VM_AGP_TOP, 0,
0128             AGP_TOP, pa_config->system_aperture.agp_top >> 24);
0129     REG_SET(DCN_VM_AGP_BASE, 0,
0130             AGP_BASE, pa_config->system_aperture.agp_base >> 24);
0131 
0132     if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
0133         phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
0134         phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
0135         phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr | 1; //Note: hack
0136         phys_config.depth = 0;
0137         phys_config.block_size = 0;
0138         // Init VMID 0 based on PA config
0139         dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config);
0140     }
0141 
0142     dcn21_dchvm_init(hubbub);
0143 
0144     return hubbub1->num_vmid;
0145 }
0146 
0147 bool hubbub21_program_urgent_watermarks(
0148         struct hubbub *hubbub,
0149         struct dcn_watermark_set *watermarks,
0150         unsigned int refclk_mhz,
0151         bool safe_to_lower)
0152 {
0153     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0154     uint32_t prog_wm_value;
0155     bool wm_pending = false;
0156 
0157     /* Repeat for water mark set A, B, C and D. */
0158     /* clock state A */
0159     if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
0160         hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
0161         prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
0162                 refclk_mhz, 0x1fffff);
0163         REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
0164                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value,
0165                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, prog_wm_value);
0166 
0167         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
0168             "HW register value = 0x%x\n",
0169             watermarks->a.urgent_ns, prog_wm_value);
0170     } else if (watermarks->a.urgent_ns < hubbub1->watermarks.a.urgent_ns)
0171         wm_pending = true;
0172 
0173     /* determine the transfer time for a quantity of data for a particular requestor.*/
0174     if (safe_to_lower || watermarks->a.frac_urg_bw_flip
0175             > hubbub1->watermarks.a.frac_urg_bw_flip) {
0176         hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
0177 
0178         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
0179                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip);
0180     } else if (watermarks->a.frac_urg_bw_flip
0181             < hubbub1->watermarks.a.frac_urg_bw_flip)
0182         wm_pending = true;
0183 
0184     if (safe_to_lower || watermarks->a.frac_urg_bw_nom
0185             > hubbub1->watermarks.a.frac_urg_bw_nom) {
0186         hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
0187 
0188         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
0189                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom);
0190     } else if (watermarks->a.frac_urg_bw_nom
0191             < hubbub1->watermarks.a.frac_urg_bw_nom)
0192         wm_pending = true;
0193 
0194     if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub1->watermarks.a.urgent_latency_ns) {
0195         hubbub1->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
0196         prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
0197                 refclk_mhz, 0x1fffff);
0198         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
0199                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
0200     } else if (watermarks->a.urgent_latency_ns < hubbub1->watermarks.a.urgent_latency_ns)
0201         wm_pending = true;
0202 
0203     /* clock state B */
0204     if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
0205         hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
0206         prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
0207                 refclk_mhz, 0x1fffff);
0208         REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
0209                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value,
0210                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B, prog_wm_value);
0211 
0212         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
0213             "HW register value = 0x%x\n",
0214             watermarks->b.urgent_ns, prog_wm_value);
0215     } else if (watermarks->b.urgent_ns < hubbub1->watermarks.b.urgent_ns)
0216         wm_pending = true;
0217 
0218     /* determine the transfer time for a quantity of data for a particular requestor.*/
0219     if (safe_to_lower || watermarks->a.frac_urg_bw_flip
0220             > hubbub1->watermarks.a.frac_urg_bw_flip) {
0221         hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
0222 
0223         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
0224                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->a.frac_urg_bw_flip);
0225     } else if (watermarks->a.frac_urg_bw_flip
0226             < hubbub1->watermarks.a.frac_urg_bw_flip)
0227         wm_pending = true;
0228 
0229     if (safe_to_lower || watermarks->a.frac_urg_bw_nom
0230             > hubbub1->watermarks.a.frac_urg_bw_nom) {
0231         hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
0232 
0233         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
0234                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->a.frac_urg_bw_nom);
0235     } else if (watermarks->a.frac_urg_bw_nom
0236             < hubbub1->watermarks.a.frac_urg_bw_nom)
0237         wm_pending = true;
0238 
0239     if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub1->watermarks.b.urgent_latency_ns) {
0240         hubbub1->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
0241         prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
0242                 refclk_mhz, 0x1fffff);
0243         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
0244                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
0245     } else if (watermarks->b.urgent_latency_ns < hubbub1->watermarks.b.urgent_latency_ns)
0246         wm_pending = true;
0247 
0248     /* clock state C */
0249     if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
0250         hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
0251         prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
0252                 refclk_mhz, 0x1fffff);
0253         REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
0254                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value,
0255                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C, prog_wm_value);
0256 
0257         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
0258             "HW register value = 0x%x\n",
0259             watermarks->c.urgent_ns, prog_wm_value);
0260     } else if (watermarks->c.urgent_ns < hubbub1->watermarks.c.urgent_ns)
0261         wm_pending = true;
0262 
0263     /* determine the transfer time for a quantity of data for a particular requestor.*/
0264     if (safe_to_lower || watermarks->a.frac_urg_bw_flip
0265             > hubbub1->watermarks.a.frac_urg_bw_flip) {
0266         hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
0267 
0268         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0,
0269                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->a.frac_urg_bw_flip);
0270     } else if (watermarks->a.frac_urg_bw_flip
0271             < hubbub1->watermarks.a.frac_urg_bw_flip)
0272         wm_pending = true;
0273 
0274     if (safe_to_lower || watermarks->a.frac_urg_bw_nom
0275             > hubbub1->watermarks.a.frac_urg_bw_nom) {
0276         hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
0277 
0278         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0,
0279                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->a.frac_urg_bw_nom);
0280     } else if (watermarks->a.frac_urg_bw_nom
0281             < hubbub1->watermarks.a.frac_urg_bw_nom)
0282         wm_pending = true;
0283 
0284     if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub1->watermarks.c.urgent_latency_ns) {
0285         hubbub1->watermarks.c.urgent_latency_ns = watermarks->c.urgent_latency_ns;
0286         prog_wm_value = convert_and_clamp(watermarks->c.urgent_latency_ns,
0287                 refclk_mhz, 0x1fffff);
0288         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, 0,
0289                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, prog_wm_value);
0290     } else if (watermarks->c.urgent_latency_ns < hubbub1->watermarks.c.urgent_latency_ns)
0291         wm_pending = true;
0292 
0293     /* clock state D */
0294     if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
0295         hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
0296         prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
0297                 refclk_mhz, 0x1fffff);
0298         REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
0299                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value,
0300                 DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D, prog_wm_value);
0301 
0302         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
0303             "HW register value = 0x%x\n",
0304             watermarks->d.urgent_ns, prog_wm_value);
0305     } else if (watermarks->d.urgent_ns < hubbub1->watermarks.d.urgent_ns)
0306         wm_pending = true;
0307 
0308     /* determine the transfer time for a quantity of data for a particular requestor.*/
0309     if (safe_to_lower || watermarks->a.frac_urg_bw_flip
0310             > hubbub1->watermarks.a.frac_urg_bw_flip) {
0311         hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
0312 
0313         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
0314                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->a.frac_urg_bw_flip);
0315     } else if (watermarks->a.frac_urg_bw_flip
0316             < hubbub1->watermarks.a.frac_urg_bw_flip)
0317         wm_pending = true;
0318 
0319     if (safe_to_lower || watermarks->a.frac_urg_bw_nom
0320             > hubbub1->watermarks.a.frac_urg_bw_nom) {
0321         hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
0322 
0323         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
0324                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->a.frac_urg_bw_nom);
0325     } else if (watermarks->a.frac_urg_bw_nom
0326             < hubbub1->watermarks.a.frac_urg_bw_nom)
0327         wm_pending = true;
0328 
0329     if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub1->watermarks.d.urgent_latency_ns) {
0330         hubbub1->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
0331         prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
0332                 refclk_mhz, 0x1fffff);
0333         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
0334                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
0335     } else if (watermarks->d.urgent_latency_ns < hubbub1->watermarks.d.urgent_latency_ns)
0336         wm_pending = true;
0337 
0338     return wm_pending;
0339 }
0340 
0341 bool hubbub21_program_stutter_watermarks(
0342         struct hubbub *hubbub,
0343         struct dcn_watermark_set *watermarks,
0344         unsigned int refclk_mhz,
0345         bool safe_to_lower)
0346 {
0347     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0348     uint32_t prog_wm_value;
0349     bool wm_pending = false;
0350 
0351     /* clock state A */
0352     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
0353             > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
0354         hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
0355                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
0356         prog_wm_value = convert_and_clamp(
0357                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
0358                 refclk_mhz, 0x1fffff);
0359         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
0360                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value,
0361                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
0362         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
0363             "HW register value = 0x%x\n",
0364             watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0365     } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
0366             < hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns)
0367         wm_pending = true;
0368 
0369     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
0370             > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
0371         hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
0372                 watermarks->a.cstate_pstate.cstate_exit_ns;
0373         prog_wm_value = convert_and_clamp(
0374                 watermarks->a.cstate_pstate.cstate_exit_ns,
0375                 refclk_mhz, 0x1fffff);
0376         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
0377                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value,
0378                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
0379         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
0380             "HW register value = 0x%x\n",
0381             watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
0382     } else if (watermarks->a.cstate_pstate.cstate_exit_ns
0383             < hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns)
0384         wm_pending = true;
0385 
0386     /* clock state B */
0387     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
0388             > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
0389         hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
0390                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
0391         prog_wm_value = convert_and_clamp(
0392                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
0393                 refclk_mhz, 0x1fffff);
0394         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
0395                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value,
0396                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
0397         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
0398             "HW register value = 0x%x\n",
0399             watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0400     } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
0401             < hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns)
0402         wm_pending = true;
0403 
0404     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
0405             > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
0406         hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
0407                 watermarks->b.cstate_pstate.cstate_exit_ns;
0408         prog_wm_value = convert_and_clamp(
0409                 watermarks->b.cstate_pstate.cstate_exit_ns,
0410                 refclk_mhz, 0x1fffff);
0411         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
0412                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value,
0413                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
0414         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
0415             "HW register value = 0x%x\n",
0416             watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
0417     } else if (watermarks->b.cstate_pstate.cstate_exit_ns
0418             < hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns)
0419         wm_pending = true;
0420 
0421     /* clock state C */
0422     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
0423             > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
0424         hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
0425                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
0426         prog_wm_value = convert_and_clamp(
0427                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
0428                 refclk_mhz, 0x1fffff);
0429         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
0430                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value,
0431                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
0432         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
0433             "HW register value = 0x%x\n",
0434             watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0435     } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
0436             < hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns)
0437         wm_pending = true;
0438 
0439     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
0440             > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
0441         hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
0442                 watermarks->c.cstate_pstate.cstate_exit_ns;
0443         prog_wm_value = convert_and_clamp(
0444                 watermarks->c.cstate_pstate.cstate_exit_ns,
0445                 refclk_mhz, 0x1fffff);
0446         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
0447                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value,
0448                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
0449         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
0450             "HW register value = 0x%x\n",
0451             watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
0452     } else if (watermarks->c.cstate_pstate.cstate_exit_ns
0453             < hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns)
0454         wm_pending = true;
0455 
0456     /* clock state D */
0457     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
0458             > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
0459         hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
0460                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
0461         prog_wm_value = convert_and_clamp(
0462                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
0463                 refclk_mhz, 0x1fffff);
0464         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
0465                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value,
0466                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
0467         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
0468             "HW register value = 0x%x\n",
0469             watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0470     } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
0471             < hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns)
0472         wm_pending = true;
0473 
0474     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
0475             > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
0476         hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
0477                 watermarks->d.cstate_pstate.cstate_exit_ns;
0478         prog_wm_value = convert_and_clamp(
0479                 watermarks->d.cstate_pstate.cstate_exit_ns,
0480                 refclk_mhz, 0x1fffff);
0481         REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
0482                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value,
0483                 DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
0484         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
0485             "HW register value = 0x%x\n",
0486             watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
0487     } else if (watermarks->d.cstate_pstate.cstate_exit_ns
0488             < hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns)
0489         wm_pending = true;
0490 
0491     return wm_pending;
0492 }
0493 
0494 bool hubbub21_program_pstate_watermarks(
0495         struct hubbub *hubbub,
0496         struct dcn_watermark_set *watermarks,
0497         unsigned int refclk_mhz,
0498         bool safe_to_lower)
0499 {
0500     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0501     uint32_t prog_wm_value;
0502 
0503     bool wm_pending = false;
0504 
0505     /* clock state A */
0506     if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
0507             > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
0508         hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
0509                 watermarks->a.cstate_pstate.pstate_change_ns;
0510         prog_wm_value = convert_and_clamp(
0511                 watermarks->a.cstate_pstate.pstate_change_ns,
0512                 refclk_mhz, 0x1fffff);
0513         REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
0514                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value,
0515                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
0516         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
0517             "HW register value = 0x%x\n\n",
0518             watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
0519     } else if (watermarks->a.cstate_pstate.pstate_change_ns
0520             < hubbub1->watermarks.a.cstate_pstate.pstate_change_ns)
0521         wm_pending = true;
0522 
0523     /* clock state B */
0524     if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
0525             > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
0526         hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
0527                 watermarks->b.cstate_pstate.pstate_change_ns;
0528         prog_wm_value = convert_and_clamp(
0529                 watermarks->b.cstate_pstate.pstate_change_ns,
0530                 refclk_mhz, 0x1fffff);
0531         REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
0532                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value,
0533                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
0534         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
0535             "HW register value = 0x%x\n\n",
0536             watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
0537     } else if (watermarks->b.cstate_pstate.pstate_change_ns
0538             < hubbub1->watermarks.b.cstate_pstate.pstate_change_ns)
0539         wm_pending = false;
0540 
0541     /* clock state C */
0542     if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
0543             > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
0544         hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
0545                 watermarks->c.cstate_pstate.pstate_change_ns;
0546         prog_wm_value = convert_and_clamp(
0547                 watermarks->c.cstate_pstate.pstate_change_ns,
0548                 refclk_mhz, 0x1fffff);
0549         REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
0550                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value,
0551                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
0552         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
0553             "HW register value = 0x%x\n\n",
0554             watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
0555     } else if (watermarks->c.cstate_pstate.pstate_change_ns
0556             < hubbub1->watermarks.c.cstate_pstate.pstate_change_ns)
0557         wm_pending = true;
0558 
0559     /* clock state D */
0560     if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
0561             > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
0562         hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
0563                 watermarks->d.cstate_pstate.pstate_change_ns;
0564         prog_wm_value = convert_and_clamp(
0565                 watermarks->d.cstate_pstate.pstate_change_ns,
0566                 refclk_mhz, 0x1fffff);
0567         REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
0568                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value,
0569                 DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
0570         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
0571             "HW register value = 0x%x\n\n",
0572             watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
0573     } else if (watermarks->d.cstate_pstate.pstate_change_ns
0574             < hubbub1->watermarks.d.cstate_pstate.pstate_change_ns)
0575         wm_pending = true;
0576 
0577     return wm_pending;
0578 }
0579 
0580 bool hubbub21_program_watermarks(
0581         struct hubbub *hubbub,
0582         struct dcn_watermark_set *watermarks,
0583         unsigned int refclk_mhz,
0584         bool safe_to_lower)
0585 {
0586     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0587     bool wm_pending = false;
0588 
0589     if (hubbub21_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0590         wm_pending = true;
0591 
0592     if (hubbub21_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0593         wm_pending = true;
0594 
0595     if (hubbub21_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0596         wm_pending = true;
0597 
0598     /*
0599      * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
0600      * If the memory controller is fully utilized and the DCHub requestors are
0601      * well ahead of their amortized schedule, then it is safe to prevent the next winner
0602      * from being committed and sent to the fabric.
0603      * The utilization of the memory controller is approximated by ensuring that
0604      * the number of outstanding requests is greater than a threshold specified
0605      * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
0606      * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
0607      *
0608      * TODO: Revisit request limit after figure out right number. request limit for Renoir isn't decided yet, set maximum value (0x1FF)
0609      * to turn off it for now.
0610      */
0611     REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
0612             DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
0613     REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
0614             DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF,
0615             DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, 0xA);
0616     REG_UPDATE(DCHUBBUB_ARB_HOSTVM_CNTL,
0617             DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, 0xF);
0618 
0619     hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
0620 
0621     return wm_pending;
0622 }
0623 
0624 void hubbub21_wm_read_state(struct hubbub *hubbub,
0625         struct dcn_hubbub_wm *wm)
0626 {
0627     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0628     struct dcn_hubbub_wm_set *s;
0629 
0630     memset(wm, 0, sizeof(struct dcn_hubbub_wm));
0631 
0632     s = &wm->sets[0];
0633     s->wm_set = 0;
0634     REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A,
0635             DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent);
0636 
0637     REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A,
0638             DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter);
0639 
0640     REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A,
0641             DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit);
0642 
0643     REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A,
0644              DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, &s->dram_clk_chanage);
0645 
0646     s = &wm->sets[1];
0647     s->wm_set = 1;
0648     REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B,
0649             DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent);
0650 
0651     REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B,
0652             DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter);
0653 
0654     REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B,
0655             DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit);
0656 
0657     REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B,
0658             DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, &s->dram_clk_chanage);
0659 
0660     s = &wm->sets[2];
0661     s->wm_set = 2;
0662     REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C,
0663             DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent);
0664 
0665     REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C,
0666             DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter);
0667 
0668     REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C,
0669             DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit);
0670 
0671     REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C,
0672             DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, &s->dram_clk_chanage);
0673 
0674     s = &wm->sets[3];
0675     s->wm_set = 3;
0676     REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D,
0677             DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent);
0678 
0679     REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D,
0680             DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter);
0681 
0682     REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D,
0683             DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit);
0684 
0685     REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D,
0686             DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, &s->dram_clk_chanage);
0687 }
0688 
0689 static void hubbub21_apply_DEDCN21_147_wa(struct hubbub *hubbub)
0690 {
0691     struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
0692     uint32_t prog_wm_value;
0693 
0694     prog_wm_value = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
0695     REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
0696 }
0697 
0698 static const struct hubbub_funcs hubbub21_funcs = {
0699     .update_dchub = hubbub2_update_dchub,
0700     .init_dchub_sys_ctx = hubbub21_init_dchub,
0701     .init_vm_ctx = hubbub2_init_vm_ctx,
0702     .dcc_support_swizzle = hubbub2_dcc_support_swizzle,
0703     .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
0704     .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap,
0705     .wm_read_state = hubbub21_wm_read_state,
0706     .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq,
0707     .program_watermarks = hubbub21_program_watermarks,
0708     .allow_self_refresh_control = hubbub1_allow_self_refresh_control,
0709     .apply_DEDCN21_147_wa = hubbub21_apply_DEDCN21_147_wa,
0710     .hubbub_read_state = hubbub2_read_state,
0711 };
0712 
0713 void hubbub21_construct(struct dcn20_hubbub *hubbub,
0714     struct dc_context *ctx,
0715     const struct dcn_hubbub_registers *hubbub_regs,
0716     const struct dcn_hubbub_shift *hubbub_shift,
0717     const struct dcn_hubbub_mask *hubbub_mask)
0718 {
0719     hubbub->base.ctx = ctx;
0720 
0721     hubbub->base.funcs = &hubbub21_funcs;
0722 
0723     hubbub->regs = hubbub_regs;
0724     hubbub->shifts = hubbub_shift;
0725     hubbub->masks = hubbub_mask;
0726 
0727     hubbub->debug_test_index_pstate = 0xB;
0728     hubbub->detile_buf_size = 164 * 1024; /* 164KB for DCN2.0 */
0729 }