Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2016 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 "dcn30/dcn30_hubbub.h"
0028 #include "dcn31_hubbub.h"
0029 #include "dm_services.h"
0030 #include "reg_helper.h"
0031 
0032 
0033 #define CTX \
0034     hubbub2->base.ctx
0035 #define DC_LOGGER \
0036     hubbub2->base.ctx->logger
0037 #define REG(reg)\
0038     hubbub2->regs->reg
0039 
0040 #undef FN
0041 #define FN(reg_name, field_name) \
0042     hubbub2->shifts->field_name, hubbub2->masks->field_name
0043 
0044 #ifdef NUM_VMID
0045 #undef NUM_VMID
0046 #endif
0047 #define NUM_VMID 16
0048 
0049 #define DCN31_CRB_SEGMENT_SIZE_KB 64
0050 
0051 static void dcn31_init_crb(struct hubbub *hubbub)
0052 {
0053     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0054 
0055     REG_GET(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT,
0056         &hubbub2->det0_size);
0057 
0058     REG_GET(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT,
0059         &hubbub2->det1_size);
0060 
0061     REG_GET(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT,
0062         &hubbub2->det2_size);
0063 
0064     REG_GET(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT,
0065         &hubbub2->det3_size);
0066 
0067     REG_GET(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT,
0068         &hubbub2->compbuf_size_segments);
0069 
0070     REG_SET_2(COMPBUF_RESERVED_SPACE, 0,
0071             COMPBUF_RESERVED_SPACE_64B, hubbub2->pixel_chunk_size / 32,
0072             COMPBUF_RESERVED_SPACE_ZS, hubbub2->pixel_chunk_size / 128);
0073     REG_UPDATE(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, 0x17F);
0074 }
0075 
0076 static void dcn31_program_det_size(struct hubbub *hubbub, int hubp_inst, unsigned int det_buffer_size_in_kbyte)
0077 {
0078     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0079 
0080     unsigned int det_size_segments = (det_buffer_size_in_kbyte + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB;
0081 
0082     switch (hubp_inst) {
0083     case 0:
0084         REG_UPDATE(DCHUBBUB_DET0_CTRL,
0085                     DET0_SIZE, det_size_segments);
0086         hubbub2->det0_size = det_size_segments;
0087         break;
0088     case 1:
0089         REG_UPDATE(DCHUBBUB_DET1_CTRL,
0090                     DET1_SIZE, det_size_segments);
0091         hubbub2->det1_size = det_size_segments;
0092         break;
0093     case 2:
0094         REG_UPDATE(DCHUBBUB_DET2_CTRL,
0095                     DET2_SIZE, det_size_segments);
0096         hubbub2->det2_size = det_size_segments;
0097         break;
0098     case 3:
0099         REG_UPDATE(DCHUBBUB_DET3_CTRL,
0100                     DET3_SIZE, det_size_segments);
0101         hubbub2->det3_size = det_size_segments;
0102         break;
0103     default:
0104         break;
0105     }
0106     /* Should never be hit, if it is we have an erroneous hw config*/
0107     ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size
0108             + hubbub2->det3_size + hubbub2->compbuf_size_segments <= hubbub2->crb_size_segs);
0109 }
0110 
0111 static void dcn31_program_compbuf_size(struct hubbub *hubbub, unsigned int compbuf_size_kb, bool safe_to_increase)
0112 {
0113     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0114     unsigned int compbuf_size_segments = (compbuf_size_kb + DCN31_CRB_SEGMENT_SIZE_KB - 1) / DCN31_CRB_SEGMENT_SIZE_KB;
0115 
0116     if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) {
0117         if (compbuf_size_segments > hubbub2->compbuf_size_segments) {
0118             REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100);
0119             REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100);
0120             REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100);
0121             REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100);
0122         }
0123         /* Should never be hit, if it is we have an erroneous hw config*/
0124         ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size
0125                 + hubbub2->det3_size + compbuf_size_segments <= hubbub2->crb_size_segs);
0126         REG_UPDATE(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, compbuf_size_segments);
0127         hubbub2->compbuf_size_segments = compbuf_size_segments;
0128         ASSERT(REG_GET(DCHUBBUB_COMPBUF_CTRL, CONFIG_ERROR, &compbuf_size_segments) && !compbuf_size_segments);
0129     }
0130 }
0131 
0132 static uint32_t convert_and_clamp(
0133     uint32_t wm_ns,
0134     uint32_t refclk_mhz,
0135     uint32_t clamp_value)
0136 {
0137     uint32_t ret_val = 0;
0138     ret_val = wm_ns * refclk_mhz;
0139     ret_val /= 1000;
0140 
0141     if (ret_val > clamp_value) {
0142         /* clamping WMs is abnormal, unexpected and may lead to underflow*/
0143         ASSERT(0);
0144         ret_val = clamp_value;
0145     }
0146 
0147     return ret_val;
0148 }
0149 
0150 static bool hubbub31_program_urgent_watermarks(
0151         struct hubbub *hubbub,
0152         struct dcn_watermark_set *watermarks,
0153         unsigned int refclk_mhz,
0154         bool safe_to_lower)
0155 {
0156     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0157     uint32_t prog_wm_value;
0158     bool wm_pending = false;
0159 
0160     /* Repeat for water mark set A, B, C and D. */
0161     /* clock state A */
0162     if (safe_to_lower || watermarks->a.urgent_ns > hubbub2->watermarks.a.urgent_ns) {
0163         hubbub2->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
0164         prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
0165                 refclk_mhz, 0x3fff);
0166         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
0167                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
0168 
0169         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
0170             "HW register value = 0x%x\n",
0171             watermarks->a.urgent_ns, prog_wm_value);
0172     } else if (watermarks->a.urgent_ns < hubbub2->watermarks.a.urgent_ns)
0173         wm_pending = true;
0174 
0175     /* determine the transfer time for a quantity of data for a particular requestor.*/
0176     if (safe_to_lower || watermarks->a.frac_urg_bw_flip
0177             > hubbub2->watermarks.a.frac_urg_bw_flip) {
0178         hubbub2->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip;
0179 
0180         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0,
0181                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip);
0182     } else if (watermarks->a.frac_urg_bw_flip
0183             < hubbub2->watermarks.a.frac_urg_bw_flip)
0184         wm_pending = true;
0185 
0186     if (safe_to_lower || watermarks->a.frac_urg_bw_nom
0187             > hubbub2->watermarks.a.frac_urg_bw_nom) {
0188         hubbub2->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom;
0189 
0190         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0,
0191                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom);
0192     } else if (watermarks->a.frac_urg_bw_nom
0193             < hubbub2->watermarks.a.frac_urg_bw_nom)
0194         wm_pending = true;
0195 
0196     if (safe_to_lower || watermarks->a.urgent_latency_ns > hubbub2->watermarks.a.urgent_latency_ns) {
0197         hubbub2->watermarks.a.urgent_latency_ns = watermarks->a.urgent_latency_ns;
0198         prog_wm_value = convert_and_clamp(watermarks->a.urgent_latency_ns,
0199                 refclk_mhz, 0x3fff);
0200         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, 0,
0201                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, prog_wm_value);
0202     } else if (watermarks->a.urgent_latency_ns < hubbub2->watermarks.a.urgent_latency_ns)
0203         wm_pending = true;
0204 
0205     /* clock state B */
0206     if (safe_to_lower || watermarks->b.urgent_ns > hubbub2->watermarks.b.urgent_ns) {
0207         hubbub2->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
0208         prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
0209                 refclk_mhz, 0x3fff);
0210         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
0211                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
0212 
0213         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
0214             "HW register value = 0x%x\n",
0215             watermarks->b.urgent_ns, prog_wm_value);
0216     } else if (watermarks->b.urgent_ns < hubbub2->watermarks.b.urgent_ns)
0217         wm_pending = true;
0218 
0219     /* determine the transfer time for a quantity of data for a particular requestor.*/
0220     if (safe_to_lower || watermarks->b.frac_urg_bw_flip
0221             > hubbub2->watermarks.b.frac_urg_bw_flip) {
0222         hubbub2->watermarks.b.frac_urg_bw_flip = watermarks->b.frac_urg_bw_flip;
0223 
0224         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0,
0225                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->b.frac_urg_bw_flip);
0226     } else if (watermarks->b.frac_urg_bw_flip
0227             < hubbub2->watermarks.b.frac_urg_bw_flip)
0228         wm_pending = true;
0229 
0230     if (safe_to_lower || watermarks->b.frac_urg_bw_nom
0231             > hubbub2->watermarks.b.frac_urg_bw_nom) {
0232         hubbub2->watermarks.b.frac_urg_bw_nom = watermarks->b.frac_urg_bw_nom;
0233 
0234         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0,
0235                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->b.frac_urg_bw_nom);
0236     } else if (watermarks->b.frac_urg_bw_nom
0237             < hubbub2->watermarks.b.frac_urg_bw_nom)
0238         wm_pending = true;
0239 
0240     if (safe_to_lower || watermarks->b.urgent_latency_ns > hubbub2->watermarks.b.urgent_latency_ns) {
0241         hubbub2->watermarks.b.urgent_latency_ns = watermarks->b.urgent_latency_ns;
0242         prog_wm_value = convert_and_clamp(watermarks->b.urgent_latency_ns,
0243                 refclk_mhz, 0x3fff);
0244         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, 0,
0245                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, prog_wm_value);
0246     } else if (watermarks->b.urgent_latency_ns < hubbub2->watermarks.b.urgent_latency_ns)
0247         wm_pending = true;
0248 
0249     /* clock state C */
0250     if (safe_to_lower || watermarks->c.urgent_ns > hubbub2->watermarks.c.urgent_ns) {
0251         hubbub2->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
0252         prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
0253                 refclk_mhz, 0x3fff);
0254         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
0255                 DCHUBBUB_ARB_DATA_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 < hubbub2->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->c.frac_urg_bw_flip
0265             > hubbub2->watermarks.c.frac_urg_bw_flip) {
0266         hubbub2->watermarks.c.frac_urg_bw_flip = watermarks->c.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->c.frac_urg_bw_flip);
0270     } else if (watermarks->c.frac_urg_bw_flip
0271             < hubbub2->watermarks.c.frac_urg_bw_flip)
0272         wm_pending = true;
0273 
0274     if (safe_to_lower || watermarks->c.frac_urg_bw_nom
0275             > hubbub2->watermarks.c.frac_urg_bw_nom) {
0276         hubbub2->watermarks.c.frac_urg_bw_nom = watermarks->c.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->c.frac_urg_bw_nom);
0280     } else if (watermarks->c.frac_urg_bw_nom
0281             < hubbub2->watermarks.c.frac_urg_bw_nom)
0282         wm_pending = true;
0283 
0284     if (safe_to_lower || watermarks->c.urgent_latency_ns > hubbub2->watermarks.c.urgent_latency_ns) {
0285         hubbub2->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, 0x3fff);
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 < hubbub2->watermarks.c.urgent_latency_ns)
0291         wm_pending = true;
0292 
0293     /* clock state D */
0294     if (safe_to_lower || watermarks->d.urgent_ns > hubbub2->watermarks.d.urgent_ns) {
0295         hubbub2->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
0296         prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
0297                 refclk_mhz, 0x3fff);
0298         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
0299                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
0300 
0301         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
0302             "HW register value = 0x%x\n",
0303             watermarks->d.urgent_ns, prog_wm_value);
0304     } else if (watermarks->d.urgent_ns < hubbub2->watermarks.d.urgent_ns)
0305         wm_pending = true;
0306 
0307     /* determine the transfer time for a quantity of data for a particular requestor.*/
0308     if (safe_to_lower || watermarks->d.frac_urg_bw_flip
0309             > hubbub2->watermarks.d.frac_urg_bw_flip) {
0310         hubbub2->watermarks.d.frac_urg_bw_flip = watermarks->d.frac_urg_bw_flip;
0311 
0312         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0,
0313                 DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->d.frac_urg_bw_flip);
0314     } else if (watermarks->d.frac_urg_bw_flip
0315             < hubbub2->watermarks.d.frac_urg_bw_flip)
0316         wm_pending = true;
0317 
0318     if (safe_to_lower || watermarks->d.frac_urg_bw_nom
0319             > hubbub2->watermarks.d.frac_urg_bw_nom) {
0320         hubbub2->watermarks.d.frac_urg_bw_nom = watermarks->d.frac_urg_bw_nom;
0321 
0322         REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0,
0323                 DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->d.frac_urg_bw_nom);
0324     } else if (watermarks->d.frac_urg_bw_nom
0325             < hubbub2->watermarks.d.frac_urg_bw_nom)
0326         wm_pending = true;
0327 
0328     if (safe_to_lower || watermarks->d.urgent_latency_ns > hubbub2->watermarks.d.urgent_latency_ns) {
0329         hubbub2->watermarks.d.urgent_latency_ns = watermarks->d.urgent_latency_ns;
0330         prog_wm_value = convert_and_clamp(watermarks->d.urgent_latency_ns,
0331                 refclk_mhz, 0x3fff);
0332         REG_SET(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, 0,
0333                 DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, prog_wm_value);
0334     } else if (watermarks->d.urgent_latency_ns < hubbub2->watermarks.d.urgent_latency_ns)
0335         wm_pending = true;
0336 
0337     return wm_pending;
0338 }
0339 
0340 static bool hubbub31_program_stutter_watermarks(
0341         struct hubbub *hubbub,
0342         struct dcn_watermark_set *watermarks,
0343         unsigned int refclk_mhz,
0344         bool safe_to_lower)
0345 {
0346     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0347     uint32_t prog_wm_value;
0348     bool wm_pending = false;
0349 
0350     /* clock state A */
0351     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
0352             > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
0353         hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
0354                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
0355         prog_wm_value = convert_and_clamp(
0356                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
0357                 refclk_mhz, 0xffff);
0358         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
0359                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
0360         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
0361             "HW register value = 0x%x\n",
0362             watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0363     } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
0364             < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns)
0365         wm_pending = true;
0366 
0367     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
0368             > hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns) {
0369         hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns =
0370                 watermarks->a.cstate_pstate.cstate_exit_ns;
0371         prog_wm_value = convert_and_clamp(
0372                 watermarks->a.cstate_pstate.cstate_exit_ns,
0373                 refclk_mhz, 0xffff);
0374         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
0375                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
0376         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
0377             "HW register value = 0x%x\n",
0378             watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
0379     } else if (watermarks->a.cstate_pstate.cstate_exit_ns
0380             < hubbub2->watermarks.a.cstate_pstate.cstate_exit_ns)
0381         wm_pending = true;
0382 
0383     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns
0384             > hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns) {
0385         hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns =
0386                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns;
0387         prog_wm_value = convert_and_clamp(
0388                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns,
0389                 refclk_mhz, 0xffff);
0390         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, 0,
0391                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_A, prog_wm_value);
0392         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_A calculated =%d\n"
0393             "HW register value = 0x%x\n",
0394             watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value);
0395     } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_z8_ns
0396             < hubbub2->watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns)
0397         wm_pending = true;
0398 
0399     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_z8_ns
0400             > hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns) {
0401         hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns =
0402                 watermarks->a.cstate_pstate.cstate_exit_z8_ns;
0403         prog_wm_value = convert_and_clamp(
0404                 watermarks->a.cstate_pstate.cstate_exit_z8_ns,
0405                 refclk_mhz, 0xffff);
0406         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, 0,
0407                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_A, prog_wm_value);
0408         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_A calculated =%d\n"
0409             "HW register value = 0x%x\n",
0410             watermarks->a.cstate_pstate.cstate_exit_z8_ns, prog_wm_value);
0411     } else if (watermarks->a.cstate_pstate.cstate_exit_z8_ns
0412             < hubbub2->watermarks.a.cstate_pstate.cstate_exit_z8_ns)
0413         wm_pending = true;
0414 
0415     /* clock state B */
0416     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
0417             > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
0418         hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
0419                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
0420         prog_wm_value = convert_and_clamp(
0421                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
0422                 refclk_mhz, 0xffff);
0423         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
0424                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
0425         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
0426             "HW register value = 0x%x\n",
0427             watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0428     } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
0429             < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns)
0430         wm_pending = true;
0431 
0432     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
0433             > hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns) {
0434         hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns =
0435                 watermarks->b.cstate_pstate.cstate_exit_ns;
0436         prog_wm_value = convert_and_clamp(
0437                 watermarks->b.cstate_pstate.cstate_exit_ns,
0438                 refclk_mhz, 0xffff);
0439         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
0440                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
0441         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
0442             "HW register value = 0x%x\n",
0443             watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
0444     } else if (watermarks->b.cstate_pstate.cstate_exit_ns
0445             < hubbub2->watermarks.b.cstate_pstate.cstate_exit_ns)
0446         wm_pending = true;
0447 
0448     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns
0449             > hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns) {
0450         hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns =
0451                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns;
0452         prog_wm_value = convert_and_clamp(
0453                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns,
0454                 refclk_mhz, 0xffff);
0455         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, 0,
0456                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_B, prog_wm_value);
0457         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_B calculated =%d\n"
0458             "HW register value = 0x%x\n",
0459             watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value);
0460     } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_z8_ns
0461             < hubbub2->watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns)
0462         wm_pending = true;
0463 
0464     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_z8_ns
0465             > hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns) {
0466         hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns =
0467                 watermarks->b.cstate_pstate.cstate_exit_z8_ns;
0468         prog_wm_value = convert_and_clamp(
0469                 watermarks->b.cstate_pstate.cstate_exit_z8_ns,
0470                 refclk_mhz, 0xffff);
0471         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, 0,
0472                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_B, prog_wm_value);
0473         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_B calculated =%d\n"
0474             "HW register value = 0x%x\n",
0475             watermarks->b.cstate_pstate.cstate_exit_z8_ns, prog_wm_value);
0476     } else if (watermarks->b.cstate_pstate.cstate_exit_z8_ns
0477             < hubbub2->watermarks.b.cstate_pstate.cstate_exit_z8_ns)
0478         wm_pending = true;
0479 
0480     /* clock state C */
0481     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
0482             > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
0483         hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
0484                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
0485         prog_wm_value = convert_and_clamp(
0486                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
0487                 refclk_mhz, 0xffff);
0488         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
0489                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
0490         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
0491             "HW register value = 0x%x\n",
0492             watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0493     } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
0494             < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns)
0495         wm_pending = true;
0496 
0497     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
0498             > hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns) {
0499         hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns =
0500                 watermarks->c.cstate_pstate.cstate_exit_ns;
0501         prog_wm_value = convert_and_clamp(
0502                 watermarks->c.cstate_pstate.cstate_exit_ns,
0503                 refclk_mhz, 0xffff);
0504         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
0505                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
0506         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
0507             "HW register value = 0x%x\n",
0508             watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
0509     } else if (watermarks->c.cstate_pstate.cstate_exit_ns
0510             < hubbub2->watermarks.c.cstate_pstate.cstate_exit_ns)
0511         wm_pending = true;
0512 
0513     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns
0514             > hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns) {
0515         hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns =
0516                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns;
0517         prog_wm_value = convert_and_clamp(
0518                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns,
0519                 refclk_mhz, 0xffff);
0520         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, 0,
0521                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_C, prog_wm_value);
0522         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_C calculated =%d\n"
0523             "HW register value = 0x%x\n",
0524             watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value);
0525     } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_z8_ns
0526             < hubbub2->watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns)
0527         wm_pending = true;
0528 
0529     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_z8_ns
0530             > hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns) {
0531         hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns =
0532                 watermarks->c.cstate_pstate.cstate_exit_z8_ns;
0533         prog_wm_value = convert_and_clamp(
0534                 watermarks->c.cstate_pstate.cstate_exit_z8_ns,
0535                 refclk_mhz, 0xffff);
0536         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, 0,
0537                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_C, prog_wm_value);
0538         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_C calculated =%d\n"
0539             "HW register value = 0x%x\n",
0540             watermarks->c.cstate_pstate.cstate_exit_z8_ns, prog_wm_value);
0541     } else if (watermarks->c.cstate_pstate.cstate_exit_z8_ns
0542             < hubbub2->watermarks.c.cstate_pstate.cstate_exit_z8_ns)
0543         wm_pending = true;
0544 
0545     /* clock state D */
0546     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
0547             > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
0548         hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
0549                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
0550         prog_wm_value = convert_and_clamp(
0551                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
0552                 refclk_mhz, 0xffff);
0553         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
0554                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
0555         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
0556             "HW register value = 0x%x\n",
0557             watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0558     } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
0559             < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns)
0560         wm_pending = true;
0561 
0562     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
0563             > hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns) {
0564         hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns =
0565                 watermarks->d.cstate_pstate.cstate_exit_ns;
0566         prog_wm_value = convert_and_clamp(
0567                 watermarks->d.cstate_pstate.cstate_exit_ns,
0568                 refclk_mhz, 0xffff);
0569         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
0570                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
0571         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
0572             "HW register value = 0x%x\n",
0573             watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
0574     } else if (watermarks->d.cstate_pstate.cstate_exit_ns
0575             < hubbub2->watermarks.d.cstate_pstate.cstate_exit_ns)
0576         wm_pending = true;
0577 
0578     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns
0579             > hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns) {
0580         hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns =
0581                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns;
0582         prog_wm_value = convert_and_clamp(
0583                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns,
0584                 refclk_mhz, 0xffff);
0585         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, 0,
0586                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_Z8_D, prog_wm_value);
0587         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_WATERMARK_Z8_D calculated =%d\n"
0588             "HW register value = 0x%x\n",
0589             watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns, prog_wm_value);
0590     } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_z8_ns
0591             < hubbub2->watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns)
0592         wm_pending = true;
0593 
0594     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_z8_ns
0595             > hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns) {
0596         hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns =
0597                 watermarks->d.cstate_pstate.cstate_exit_z8_ns;
0598         prog_wm_value = convert_and_clamp(
0599                 watermarks->d.cstate_pstate.cstate_exit_z8_ns,
0600                 refclk_mhz, 0xffff);
0601         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, 0,
0602                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_Z8_D, prog_wm_value);
0603         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_Z8_D calculated =%d\n"
0604             "HW register value = 0x%x\n",
0605             watermarks->d.cstate_pstate.cstate_exit_z8_ns, prog_wm_value);
0606     } else if (watermarks->d.cstate_pstate.cstate_exit_z8_ns
0607             < hubbub2->watermarks.d.cstate_pstate.cstate_exit_z8_ns)
0608         wm_pending = true;
0609 
0610     return wm_pending;
0611 }
0612 
0613 static bool hubbub31_program_pstate_watermarks(
0614         struct hubbub *hubbub,
0615         struct dcn_watermark_set *watermarks,
0616         unsigned int refclk_mhz,
0617         bool safe_to_lower)
0618 {
0619     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0620     uint32_t prog_wm_value;
0621 
0622     bool wm_pending = false;
0623 
0624     /* clock state A */
0625     if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
0626             > hubbub2->watermarks.a.cstate_pstate.pstate_change_ns) {
0627         hubbub2->watermarks.a.cstate_pstate.pstate_change_ns =
0628                 watermarks->a.cstate_pstate.pstate_change_ns;
0629         prog_wm_value = convert_and_clamp(
0630                 watermarks->a.cstate_pstate.pstate_change_ns,
0631                 refclk_mhz, 0xffff);
0632         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
0633                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
0634         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
0635             "HW register value = 0x%x\n\n",
0636             watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
0637     } else if (watermarks->a.cstate_pstate.pstate_change_ns
0638             < hubbub2->watermarks.a.cstate_pstate.pstate_change_ns)
0639         wm_pending = true;
0640 
0641     /* clock state B */
0642     if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
0643             > hubbub2->watermarks.b.cstate_pstate.pstate_change_ns) {
0644         hubbub2->watermarks.b.cstate_pstate.pstate_change_ns =
0645                 watermarks->b.cstate_pstate.pstate_change_ns;
0646         prog_wm_value = convert_and_clamp(
0647                 watermarks->b.cstate_pstate.pstate_change_ns,
0648                 refclk_mhz, 0xffff);
0649         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
0650                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
0651         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
0652             "HW register value = 0x%x\n\n",
0653             watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
0654     } else if (watermarks->b.cstate_pstate.pstate_change_ns
0655             < hubbub2->watermarks.b.cstate_pstate.pstate_change_ns)
0656         wm_pending = false;
0657 
0658     /* clock state C */
0659     if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
0660             > hubbub2->watermarks.c.cstate_pstate.pstate_change_ns) {
0661         hubbub2->watermarks.c.cstate_pstate.pstate_change_ns =
0662                 watermarks->c.cstate_pstate.pstate_change_ns;
0663         prog_wm_value = convert_and_clamp(
0664                 watermarks->c.cstate_pstate.pstate_change_ns,
0665                 refclk_mhz, 0xffff);
0666         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
0667                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
0668         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
0669             "HW register value = 0x%x\n\n",
0670             watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
0671     } else if (watermarks->c.cstate_pstate.pstate_change_ns
0672             < hubbub2->watermarks.c.cstate_pstate.pstate_change_ns)
0673         wm_pending = true;
0674 
0675     /* clock state D */
0676     if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
0677             > hubbub2->watermarks.d.cstate_pstate.pstate_change_ns) {
0678         hubbub2->watermarks.d.cstate_pstate.pstate_change_ns =
0679                 watermarks->d.cstate_pstate.pstate_change_ns;
0680         prog_wm_value = convert_and_clamp(
0681                 watermarks->d.cstate_pstate.pstate_change_ns,
0682                 refclk_mhz, 0xffff);
0683         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
0684                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
0685         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
0686             "HW register value = 0x%x\n\n",
0687             watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
0688     } else if (watermarks->d.cstate_pstate.pstate_change_ns
0689             < hubbub2->watermarks.d.cstate_pstate.pstate_change_ns)
0690         wm_pending = true;
0691 
0692     return wm_pending;
0693 }
0694 
0695 static bool hubbub31_program_watermarks(
0696         struct hubbub *hubbub,
0697         struct dcn_watermark_set *watermarks,
0698         unsigned int refclk_mhz,
0699         bool safe_to_lower)
0700 {
0701     bool wm_pending = false;
0702 
0703     if (hubbub31_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0704         wm_pending = true;
0705 
0706     if (hubbub31_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0707         wm_pending = true;
0708 
0709     if (hubbub31_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0710         wm_pending = true;
0711 
0712     /*
0713      * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric.
0714      * If the memory controller is fully utilized and the DCHub requestors are
0715      * well ahead of their amortized schedule, then it is safe to prevent the next winner
0716      * from being committed and sent to the fabric.
0717      * The utilization of the memory controller is approximated by ensuring that
0718      * the number of outstanding requests is greater than a threshold specified
0719      * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule,
0720      * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles.
0721      *
0722      * TODO: Revisit request limit after figure out right number. request limit for RM isn't decided yet, set maximum value (0x1FF)
0723      * to turn off it for now.
0724      */
0725     /*REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
0726             DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
0727     REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
0728             DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF);*/
0729 
0730     hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
0731     return wm_pending;
0732 }
0733 
0734 static void hubbub3_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height,
0735         unsigned int bytes_per_element)
0736 {
0737     /* copied from DML.  might want to refactor DML to leverage from DML */
0738     /* DML : get_blk256_size */
0739     if (bytes_per_element == 1) {
0740         *blk256_width = 16;
0741         *blk256_height = 16;
0742     } else if (bytes_per_element == 2) {
0743         *blk256_width = 16;
0744         *blk256_height = 8;
0745     } else if (bytes_per_element == 4) {
0746         *blk256_width = 8;
0747         *blk256_height = 8;
0748     } else if (bytes_per_element == 8) {
0749         *blk256_width = 8;
0750         *blk256_height = 4;
0751     }
0752 }
0753 
0754 static void hubbub31_det_request_size(
0755         unsigned int detile_buf_size,
0756         unsigned int height,
0757         unsigned int width,
0758         unsigned int bpe,
0759         bool *req128_horz_wc,
0760         bool *req128_vert_wc)
0761 {
0762     unsigned int blk256_height = 0;
0763     unsigned int blk256_width = 0;
0764     unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
0765 
0766     hubbub3_get_blk256_size(&blk256_width, &blk256_height, bpe);
0767 
0768     swath_bytes_horz_wc = width * blk256_height * bpe;
0769     swath_bytes_vert_wc = height * blk256_width * bpe;
0770 
0771     *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
0772             false : /* full 256B request */
0773             true; /* half 128b request */
0774 
0775     *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
0776             false : /* full 256B request */
0777             true; /* half 128b request */
0778 }
0779 
0780 static bool hubbub31_get_dcc_compression_cap(struct hubbub *hubbub,
0781         const struct dc_dcc_surface_param *input,
0782         struct dc_surface_dcc_cap *output)
0783 {
0784     struct dc *dc = hubbub->ctx->dc;
0785     enum dcc_control dcc_control;
0786     unsigned int bpe;
0787     enum segment_order segment_order_horz, segment_order_vert;
0788     bool req128_horz_wc, req128_vert_wc;
0789 
0790     memset(output, 0, sizeof(*output));
0791 
0792     if (dc->debug.disable_dcc == DCC_DISABLE)
0793         return false;
0794 
0795     if (!hubbub->funcs->dcc_support_pixel_format(input->format,
0796             &bpe))
0797         return false;
0798 
0799     if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
0800             &segment_order_horz, &segment_order_vert))
0801         return false;
0802 
0803     hubbub31_det_request_size(TO_DCN20_HUBBUB(hubbub)->detile_buf_size,
0804             input->surface_size.height,  input->surface_size.width,
0805             bpe, &req128_horz_wc, &req128_vert_wc);
0806 
0807     if (!req128_horz_wc && !req128_vert_wc) {
0808         dcc_control = dcc_control__256_256_xxx;
0809     } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
0810         if (!req128_horz_wc)
0811             dcc_control = dcc_control__256_256_xxx;
0812         else if (segment_order_horz == segment_order__contiguous)
0813             dcc_control = dcc_control__128_128_xxx;
0814         else
0815             dcc_control = dcc_control__256_64_64;
0816     } else if (input->scan == SCAN_DIRECTION_VERTICAL) {
0817         if (!req128_vert_wc)
0818             dcc_control = dcc_control__256_256_xxx;
0819         else if (segment_order_vert == segment_order__contiguous)
0820             dcc_control = dcc_control__128_128_xxx;
0821         else
0822             dcc_control = dcc_control__256_64_64;
0823     } else {
0824         if ((req128_horz_wc &&
0825             segment_order_horz == segment_order__non_contiguous) ||
0826             (req128_vert_wc &&
0827             segment_order_vert == segment_order__non_contiguous))
0828             /* access_dir not known, must use most constraining */
0829             dcc_control = dcc_control__256_64_64;
0830         else
0831             /* reg128 is true for either horz and vert
0832              * but segment_order is contiguous
0833              */
0834             dcc_control = dcc_control__128_128_xxx;
0835     }
0836 
0837     /* Exception for 64KB_R_X */
0838     if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X))
0839         dcc_control = dcc_control__128_128_xxx;
0840 
0841     if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
0842         dcc_control != dcc_control__256_256_xxx)
0843         return false;
0844 
0845     switch (dcc_control) {
0846     case dcc_control__256_256_xxx:
0847         output->grph.rgb.max_uncompressed_blk_size = 256;
0848         output->grph.rgb.max_compressed_blk_size = 256;
0849         output->grph.rgb.independent_64b_blks = false;
0850         output->grph.rgb.dcc_controls.dcc_256_256_unconstrained = 1;
0851         output->grph.rgb.dcc_controls.dcc_256_128_128 = 1;
0852         break;
0853     case dcc_control__128_128_xxx:
0854         output->grph.rgb.max_uncompressed_blk_size = 128;
0855         output->grph.rgb.max_compressed_blk_size = 128;
0856         output->grph.rgb.independent_64b_blks = false;
0857         output->grph.rgb.dcc_controls.dcc_128_128_uncontrained = 1;
0858         output->grph.rgb.dcc_controls.dcc_256_128_128 = 1;
0859         break;
0860     case dcc_control__256_64_64:
0861         output->grph.rgb.max_uncompressed_blk_size = 256;
0862         output->grph.rgb.max_compressed_blk_size = 64;
0863         output->grph.rgb.independent_64b_blks = true;
0864         output->grph.rgb.dcc_controls.dcc_256_64_64 = 1;
0865         break;
0866     case dcc_control__256_128_128:
0867         output->grph.rgb.max_uncompressed_blk_size = 256;
0868         output->grph.rgb.max_compressed_blk_size = 128;
0869         output->grph.rgb.independent_64b_blks = false;
0870         output->grph.rgb.dcc_controls.dcc_256_128_128 = 1;
0871         break;
0872     }
0873     output->capable = true;
0874     output->const_color_support = true;
0875 
0876     return true;
0877 }
0878 
0879 static int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub,
0880         struct dcn_hubbub_phys_addr_config *pa_config)
0881 {
0882     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0883     struct dcn_vmid_page_table_config phys_config;
0884 
0885     REG_SET(DCN_VM_FB_LOCATION_BASE, 0,
0886             FB_BASE, pa_config->system_aperture.fb_base >> 24);
0887     REG_SET(DCN_VM_FB_LOCATION_TOP, 0,
0888             FB_TOP, pa_config->system_aperture.fb_top >> 24);
0889     REG_SET(DCN_VM_FB_OFFSET, 0,
0890             FB_OFFSET, pa_config->system_aperture.fb_offset >> 24);
0891     REG_SET(DCN_VM_AGP_BOT, 0,
0892             AGP_BOT, pa_config->system_aperture.agp_bot >> 24);
0893     REG_SET(DCN_VM_AGP_TOP, 0,
0894             AGP_TOP, pa_config->system_aperture.agp_top >> 24);
0895     REG_SET(DCN_VM_AGP_BASE, 0,
0896             AGP_BASE, pa_config->system_aperture.agp_base >> 24);
0897 
0898     if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
0899         phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
0900         phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
0901         phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
0902         phys_config.depth = 0;
0903         phys_config.block_size = 0;
0904         // Init VMID 0 based on PA config
0905         dcn20_vmid_setup(&hubbub2->vmid[0], &phys_config);
0906 
0907         dcn20_vmid_setup(&hubbub2->vmid[15], &phys_config);
0908     }
0909 
0910     dcn21_dchvm_init(hubbub);
0911 
0912     return NUM_VMID;
0913 }
0914 
0915 static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub,
0916         unsigned int dccg_ref_freq_inKhz,
0917         unsigned int *dchub_ref_freq_inKhz)
0918 {
0919     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0920     uint32_t ref_div = 0;
0921     uint32_t ref_en = 0;
0922     unsigned int dc_refclk_khz = 24000;
0923 
0924     REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div,
0925             DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en);
0926 
0927     if (ref_en) {
0928         if (ref_div == 2)
0929             *dchub_ref_freq_inKhz = dc_refclk_khz / 2;
0930         else
0931             *dchub_ref_freq_inKhz = dc_refclk_khz;
0932 
0933         /*
0934          * The external Reference Clock may change based on the board or
0935          * platform requirements and the programmable integer divide must
0936          * be programmed to provide a suitable DLG RefClk frequency between
0937          * a minimum of 20MHz and maximum of 50MHz
0938          */
0939         if (*dchub_ref_freq_inKhz < 20000 || *dchub_ref_freq_inKhz > 50000)
0940             ASSERT_CRITICAL(false);
0941 
0942         return;
0943     } else {
0944         *dchub_ref_freq_inKhz = dc_refclk_khz;
0945 
0946         // HUBBUB global timer must be enabled.
0947         ASSERT_CRITICAL(false);
0948         return;
0949     }
0950 }
0951 
0952 static bool hubbub31_verify_allow_pstate_change_high(struct hubbub *hubbub)
0953 {
0954     struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
0955 
0956     /*
0957      * Pstate latency is ~20us so if we wait over 40us and pstate allow
0958      * still not asserted, we are probably stuck and going to hang
0959      */
0960     const unsigned int pstate_wait_timeout_us = 100;
0961     const unsigned int pstate_wait_expected_timeout_us = 40;
0962 
0963     static unsigned int max_sampled_pstate_wait_us; /* data collection */
0964     static bool forced_pstate_allow; /* help with revert wa */
0965 
0966     unsigned int debug_data = 0;
0967     unsigned int i;
0968 
0969     if (forced_pstate_allow) {
0970         /* we hacked to force pstate allow to prevent hang last time
0971          * we verify_allow_pstate_change_high.  so disable force
0972          * here so we can check status
0973          */
0974         REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
0975                  DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0,
0976                  DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0);
0977         forced_pstate_allow = false;
0978     }
0979 
0980     REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub2->debug_test_index_pstate);
0981 
0982     for (i = 0; i < pstate_wait_timeout_us; i++) {
0983         debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
0984 
0985         /* Debug bit is specific to ASIC. */
0986         if (debug_data & (1 << 26)) {
0987             if (i > pstate_wait_expected_timeout_us)
0988                 DC_LOG_WARNING("pstate took longer than expected ~%dus\n", i);
0989             return true;
0990         }
0991         if (max_sampled_pstate_wait_us < i)
0992             max_sampled_pstate_wait_us = i;
0993 
0994         udelay(1);
0995     }
0996 
0997     /* force pstate allow to prevent system hang
0998      * and break to debugger to investigate
0999      */
1000     REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
1001              DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1,
1002              DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1);
1003     forced_pstate_allow = true;
1004 
1005     DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
1006             debug_data);
1007 
1008     return false;
1009 }
1010 
1011 static const struct hubbub_funcs hubbub31_funcs = {
1012     .update_dchub = hubbub2_update_dchub,
1013     .init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
1014     .init_vm_ctx = hubbub2_init_vm_ctx,
1015     .dcc_support_swizzle = hubbub3_dcc_support_swizzle,
1016     .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format,
1017     .get_dcc_compression_cap = hubbub31_get_dcc_compression_cap,
1018     .wm_read_state = hubbub21_wm_read_state,
1019     .get_dchub_ref_freq = hubbub31_get_dchub_ref_freq,
1020     .program_watermarks = hubbub31_program_watermarks,
1021     .allow_self_refresh_control = hubbub1_allow_self_refresh_control,
1022     .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
1023     .verify_allow_pstate_change_high = hubbub31_verify_allow_pstate_change_high,
1024     .program_det_size = dcn31_program_det_size,
1025     .program_compbuf_size = dcn31_program_compbuf_size,
1026     .init_crb = dcn31_init_crb,
1027     .hubbub_read_state = hubbub2_read_state,
1028 };
1029 
1030 void hubbub31_construct(struct dcn20_hubbub *hubbub31,
1031     struct dc_context *ctx,
1032     const struct dcn_hubbub_registers *hubbub_regs,
1033     const struct dcn_hubbub_shift *hubbub_shift,
1034     const struct dcn_hubbub_mask *hubbub_mask,
1035     int det_size_kb,
1036     int pixel_chunk_size_kb,
1037     int config_return_buffer_size_kb)
1038 {
1039 
1040     hubbub3_construct(hubbub31, ctx, hubbub_regs, hubbub_shift, hubbub_mask);
1041     hubbub31->base.funcs = &hubbub31_funcs;
1042     hubbub31->detile_buf_size = det_size_kb * 1024;
1043     hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024;
1044     hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB;
1045 
1046     hubbub31->debug_test_index_pstate = 0x6;
1047 }
1048