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 #include "dm_services.h"
0027 #include "dcn10_hubp.h"
0028 #include "dcn10_hubbub.h"
0029 #include "reg_helper.h"
0030 
0031 #define CTX \
0032     hubbub1->base.ctx
0033 #define DC_LOGGER \
0034     hubbub1->base.ctx->logger
0035 #define REG(reg)\
0036     hubbub1->regs->reg
0037 
0038 #undef FN
0039 #define FN(reg_name, field_name) \
0040     hubbub1->shifts->field_name, hubbub1->masks->field_name
0041 
0042 void hubbub1_wm_read_state(struct hubbub *hubbub,
0043         struct dcn_hubbub_wm *wm)
0044 {
0045     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0046     struct dcn_hubbub_wm_set *s;
0047 
0048     memset(wm, 0, sizeof(struct dcn_hubbub_wm));
0049 
0050     s = &wm->sets[0];
0051     s->wm_set = 0;
0052     s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
0053     s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A);
0054     if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
0055         s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
0056         s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
0057     }
0058     s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
0059 
0060     s = &wm->sets[1];
0061     s->wm_set = 1;
0062     s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B);
0063     s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B);
0064     if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
0065         s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B);
0066         s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B);
0067     }
0068     s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B);
0069 
0070     s = &wm->sets[2];
0071     s->wm_set = 2;
0072     s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C);
0073     s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C);
0074     if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
0075         s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C);
0076         s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C);
0077     }
0078     s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C);
0079 
0080     s = &wm->sets[3];
0081     s->wm_set = 3;
0082     s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D);
0083     s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D);
0084     if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
0085         s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D);
0086         s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D);
0087     }
0088     s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
0089 }
0090 
0091 void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow)
0092 {
0093     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0094     /*
0095      * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 1 means do not allow stutter
0096      * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 means allow stutter
0097      */
0098 
0099     REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
0100             DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
0101             DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow);
0102 }
0103 
0104 bool hubbub1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
0105 {
0106     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0107     uint32_t enable = 0;
0108 
0109     REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL,
0110             DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable);
0111 
0112     return enable ? true : false;
0113 }
0114 
0115 
0116 bool hubbub1_verify_allow_pstate_change_high(
0117     struct hubbub *hubbub)
0118 {
0119     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0120 
0121     /* pstate latency is ~20us so if we wait over 40us and pstate allow
0122      * still not asserted, we are probably stuck and going to hang
0123      *
0124      * TODO: Figure out why it takes ~100us on linux
0125      * pstate takes around ~100us (up to 200us) on linux. Unknown currently
0126      * as to why it takes that long on linux
0127      */
0128     const unsigned int pstate_wait_timeout_us = 200;
0129     const unsigned int pstate_wait_expected_timeout_us = 180;
0130     static unsigned int max_sampled_pstate_wait_us; /* data collection */
0131     static bool forced_pstate_allow; /* help with revert wa */
0132 
0133     unsigned int debug_data;
0134     unsigned int i;
0135 
0136     if (forced_pstate_allow) {
0137         /* we hacked to force pstate allow to prevent hang last time
0138          * we verify_allow_pstate_change_high.  so disable force
0139          * here so we can check status
0140          */
0141         REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
0142                  DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0,
0143                  DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0);
0144         forced_pstate_allow = false;
0145     }
0146 
0147     /* The following table only applies to DCN1 and DCN2,
0148      * for newer DCNs, need to consult with HW IP folks to read RTL
0149      * HUBBUB:DCHUBBUB_TEST_ARB_DEBUG10 DCHUBBUBDEBUGIND:0xB
0150      * description
0151      * 0:     Pipe0 Plane0 Allow Pstate Change
0152      * 1:     Pipe0 Plane1 Allow Pstate Change
0153      * 2:     Pipe0 Cursor0 Allow Pstate Change
0154      * 3:     Pipe0 Cursor1 Allow Pstate Change
0155      * 4:     Pipe1 Plane0 Allow Pstate Change
0156      * 5:     Pipe1 Plane1 Allow Pstate Change
0157      * 6:     Pipe1 Cursor0 Allow Pstate Change
0158      * 7:     Pipe1 Cursor1 Allow Pstate Change
0159      * 8:     Pipe2 Plane0 Allow Pstate Change
0160      * 9:     Pipe2 Plane1 Allow Pstate Change
0161      * 10:    Pipe2 Cursor0 Allow Pstate Change
0162      * 11:    Pipe2 Cursor1 Allow Pstate Change
0163      * 12:    Pipe3 Plane0 Allow Pstate Change
0164      * 13:    Pipe3 Plane1 Allow Pstate Change
0165      * 14:    Pipe3 Cursor0 Allow Pstate Change
0166      * 15:    Pipe3 Cursor1 Allow Pstate Change
0167      * 16:    Pipe4 Plane0 Allow Pstate Change
0168      * 17:    Pipe4 Plane1 Allow Pstate Change
0169      * 18:    Pipe4 Cursor0 Allow Pstate Change
0170      * 19:    Pipe4 Cursor1 Allow Pstate Change
0171      * 20:    Pipe5 Plane0 Allow Pstate Change
0172      * 21:    Pipe5 Plane1 Allow Pstate Change
0173      * 22:    Pipe5 Cursor0 Allow Pstate Change
0174      * 23:    Pipe5 Cursor1 Allow Pstate Change
0175      * 24:    Pipe6 Plane0 Allow Pstate Change
0176      * 25:    Pipe6 Plane1 Allow Pstate Change
0177      * 26:    Pipe6 Cursor0 Allow Pstate Change
0178      * 27:    Pipe6 Cursor1 Allow Pstate Change
0179      * 28:    WB0 Allow Pstate Change
0180      * 29:    WB1 Allow Pstate Change
0181      * 30:    Arbiter's allow_pstate_change
0182      * 31:    SOC pstate change request
0183      */
0184 
0185     REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub1->debug_test_index_pstate);
0186 
0187     for (i = 0; i < pstate_wait_timeout_us; i++) {
0188         debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
0189 
0190         if (debug_data & (1 << 30)) {
0191 
0192             if (i > pstate_wait_expected_timeout_us)
0193                 DC_LOG_WARNING("pstate took longer than expected ~%dus\n",
0194                         i);
0195 
0196             return true;
0197         }
0198         if (max_sampled_pstate_wait_us < i)
0199             max_sampled_pstate_wait_us = i;
0200 
0201         udelay(1);
0202     }
0203 
0204     /* force pstate allow to prevent system hang
0205      * and break to debugger to investigate
0206      */
0207     REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
0208              DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1,
0209              DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1);
0210     forced_pstate_allow = true;
0211 
0212     DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
0213             debug_data);
0214 
0215     return false;
0216 }
0217 
0218 static uint32_t convert_and_clamp(
0219     uint32_t wm_ns,
0220     uint32_t refclk_mhz,
0221     uint32_t clamp_value)
0222 {
0223     uint32_t ret_val = 0;
0224     ret_val = wm_ns * refclk_mhz;
0225     ret_val /= 1000;
0226 
0227     if (ret_val > clamp_value)
0228         ret_val = clamp_value;
0229 
0230     return ret_val;
0231 }
0232 
0233 
0234 void hubbub1_wm_change_req_wa(struct hubbub *hubbub)
0235 {
0236     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0237 
0238     REG_UPDATE_SEQ_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
0239             DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0,
0240             DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
0241 }
0242 
0243 bool hubbub1_program_urgent_watermarks(
0244         struct hubbub *hubbub,
0245         struct dcn_watermark_set *watermarks,
0246         unsigned int refclk_mhz,
0247         bool safe_to_lower)
0248 {
0249     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0250     uint32_t prog_wm_value;
0251     bool wm_pending = false;
0252 
0253     /* Repeat for water mark set A, B, C and D. */
0254     /* clock state A */
0255     if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) {
0256         hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
0257         prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
0258                 refclk_mhz, 0x1fffff);
0259         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0,
0260                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
0261 
0262         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
0263             "HW register value = 0x%x\n",
0264             watermarks->a.urgent_ns, prog_wm_value);
0265     } else if (watermarks->a.urgent_ns < hubbub1->watermarks.a.urgent_ns)
0266         wm_pending = true;
0267 
0268     if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) {
0269         hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns;
0270         prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
0271                 refclk_mhz, 0x1fffff);
0272         REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
0273         DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
0274             "HW register value = 0x%x\n",
0275             watermarks->a.pte_meta_urgent_ns, prog_wm_value);
0276     } else if (watermarks->a.pte_meta_urgent_ns < hubbub1->watermarks.a.pte_meta_urgent_ns)
0277         wm_pending = true;
0278 
0279     /* clock state B */
0280     if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) {
0281         hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
0282         prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
0283                 refclk_mhz, 0x1fffff);
0284         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0,
0285                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
0286 
0287         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
0288             "HW register value = 0x%x\n",
0289             watermarks->b.urgent_ns, prog_wm_value);
0290     } else if (watermarks->b.urgent_ns < hubbub1->watermarks.b.urgent_ns)
0291         wm_pending = true;
0292 
0293     if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) {
0294         hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns;
0295         prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns,
0296                 refclk_mhz, 0x1fffff);
0297         REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
0298         DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
0299             "HW register value = 0x%x\n",
0300             watermarks->b.pte_meta_urgent_ns, prog_wm_value);
0301     } else if (watermarks->b.pte_meta_urgent_ns < hubbub1->watermarks.b.pte_meta_urgent_ns)
0302         wm_pending = true;
0303 
0304     /* clock state C */
0305     if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) {
0306         hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
0307         prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
0308                 refclk_mhz, 0x1fffff);
0309         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0,
0310                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
0311 
0312         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
0313             "HW register value = 0x%x\n",
0314             watermarks->c.urgent_ns, prog_wm_value);
0315     } else if (watermarks->c.urgent_ns < hubbub1->watermarks.c.urgent_ns)
0316         wm_pending = true;
0317 
0318     if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) {
0319         hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns;
0320         prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns,
0321                 refclk_mhz, 0x1fffff);
0322         REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
0323         DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
0324             "HW register value = 0x%x\n",
0325             watermarks->c.pte_meta_urgent_ns, prog_wm_value);
0326     } else if (watermarks->c.pte_meta_urgent_ns < hubbub1->watermarks.c.pte_meta_urgent_ns)
0327         wm_pending = true;
0328 
0329     /* clock state D */
0330     if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) {
0331         hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
0332         prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
0333                 refclk_mhz, 0x1fffff);
0334         REG_SET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0,
0335                 DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
0336 
0337         DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
0338             "HW register value = 0x%x\n",
0339             watermarks->d.urgent_ns, prog_wm_value);
0340     } else if (watermarks->d.urgent_ns < hubbub1->watermarks.d.urgent_ns)
0341         wm_pending = true;
0342 
0343     if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) {
0344         hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns;
0345         prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns,
0346                 refclk_mhz, 0x1fffff);
0347         REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
0348         DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
0349             "HW register value = 0x%x\n",
0350             watermarks->d.pte_meta_urgent_ns, prog_wm_value);
0351     } else if (watermarks->d.pte_meta_urgent_ns < hubbub1->watermarks.d.pte_meta_urgent_ns)
0352         wm_pending = true;
0353 
0354     return wm_pending;
0355 }
0356 
0357 bool hubbub1_program_stutter_watermarks(
0358         struct hubbub *hubbub,
0359         struct dcn_watermark_set *watermarks,
0360         unsigned int refclk_mhz,
0361         bool safe_to_lower)
0362 {
0363     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0364     uint32_t prog_wm_value;
0365     bool wm_pending = false;
0366 
0367     /* clock state A */
0368     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
0369             > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
0370         hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
0371                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
0372         prog_wm_value = convert_and_clamp(
0373                 watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
0374                 refclk_mhz, 0x1fffff);
0375         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0,
0376                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
0377         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
0378             "HW register value = 0x%x\n",
0379             watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0380     } else if (watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
0381             < hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns)
0382         wm_pending = true;
0383 
0384     if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
0385             > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) {
0386         hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns =
0387                 watermarks->a.cstate_pstate.cstate_exit_ns;
0388         prog_wm_value = convert_and_clamp(
0389                 watermarks->a.cstate_pstate.cstate_exit_ns,
0390                 refclk_mhz, 0x1fffff);
0391         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0,
0392                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
0393         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
0394             "HW register value = 0x%x\n",
0395             watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
0396     } else if (watermarks->a.cstate_pstate.cstate_exit_ns
0397             < hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns)
0398         wm_pending = true;
0399 
0400     /* clock state B */
0401     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
0402             > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
0403         hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
0404                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
0405         prog_wm_value = convert_and_clamp(
0406                 watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
0407                 refclk_mhz, 0x1fffff);
0408         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0,
0409                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
0410         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
0411             "HW register value = 0x%x\n",
0412             watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0413     } else if (watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
0414             < hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns)
0415         wm_pending = true;
0416 
0417     if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
0418             > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) {
0419         hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns =
0420                 watermarks->b.cstate_pstate.cstate_exit_ns;
0421         prog_wm_value = convert_and_clamp(
0422                 watermarks->b.cstate_pstate.cstate_exit_ns,
0423                 refclk_mhz, 0x1fffff);
0424         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0,
0425                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
0426         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
0427             "HW register value = 0x%x\n",
0428             watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
0429     } else if (watermarks->b.cstate_pstate.cstate_exit_ns
0430             < hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns)
0431         wm_pending = true;
0432 
0433     /* clock state C */
0434     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
0435             > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
0436         hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
0437                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
0438         prog_wm_value = convert_and_clamp(
0439                 watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
0440                 refclk_mhz, 0x1fffff);
0441         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0,
0442                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
0443         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
0444             "HW register value = 0x%x\n",
0445             watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0446     } else if (watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
0447             < hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns)
0448         wm_pending = true;
0449 
0450     if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
0451             > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) {
0452         hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns =
0453                 watermarks->c.cstate_pstate.cstate_exit_ns;
0454         prog_wm_value = convert_and_clamp(
0455                 watermarks->c.cstate_pstate.cstate_exit_ns,
0456                 refclk_mhz, 0x1fffff);
0457         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0,
0458                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
0459         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
0460             "HW register value = 0x%x\n",
0461             watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
0462     } else if (watermarks->c.cstate_pstate.cstate_exit_ns
0463             < hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns)
0464         wm_pending = true;
0465 
0466     /* clock state D */
0467     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
0468             > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
0469         hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
0470                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
0471         prog_wm_value = convert_and_clamp(
0472                 watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
0473                 refclk_mhz, 0x1fffff);
0474         REG_SET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0,
0475                 DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
0476         DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
0477             "HW register value = 0x%x\n",
0478             watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
0479     } else if (watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
0480             < hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns)
0481         wm_pending = true;
0482 
0483     if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
0484             > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) {
0485         hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns =
0486                 watermarks->d.cstate_pstate.cstate_exit_ns;
0487         prog_wm_value = convert_and_clamp(
0488                 watermarks->d.cstate_pstate.cstate_exit_ns,
0489                 refclk_mhz, 0x1fffff);
0490         REG_SET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0,
0491                 DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
0492         DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
0493             "HW register value = 0x%x\n",
0494             watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
0495     } else if (watermarks->d.cstate_pstate.cstate_exit_ns
0496             < hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns)
0497         wm_pending = true;
0498 
0499     return wm_pending;
0500 }
0501 
0502 bool hubbub1_program_pstate_watermarks(
0503         struct hubbub *hubbub,
0504         struct dcn_watermark_set *watermarks,
0505         unsigned int refclk_mhz,
0506         bool safe_to_lower)
0507 {
0508     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0509     uint32_t prog_wm_value;
0510     bool wm_pending = false;
0511 
0512     /* clock state A */
0513     if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
0514             > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) {
0515         hubbub1->watermarks.a.cstate_pstate.pstate_change_ns =
0516                 watermarks->a.cstate_pstate.pstate_change_ns;
0517         prog_wm_value = convert_and_clamp(
0518                 watermarks->a.cstate_pstate.pstate_change_ns,
0519                 refclk_mhz, 0x1fffff);
0520         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0,
0521                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
0522         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
0523             "HW register value = 0x%x\n\n",
0524             watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
0525     } else if (watermarks->a.cstate_pstate.pstate_change_ns
0526             < hubbub1->watermarks.a.cstate_pstate.pstate_change_ns)
0527         wm_pending = true;
0528 
0529     /* clock state B */
0530     if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
0531             > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) {
0532         hubbub1->watermarks.b.cstate_pstate.pstate_change_ns =
0533                 watermarks->b.cstate_pstate.pstate_change_ns;
0534         prog_wm_value = convert_and_clamp(
0535                 watermarks->b.cstate_pstate.pstate_change_ns,
0536                 refclk_mhz, 0x1fffff);
0537         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0,
0538                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
0539         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
0540             "HW register value = 0x%x\n\n",
0541             watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
0542     } else if (watermarks->b.cstate_pstate.pstate_change_ns
0543             < hubbub1->watermarks.b.cstate_pstate.pstate_change_ns)
0544         wm_pending = true;
0545 
0546     /* clock state C */
0547     if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
0548             > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) {
0549         hubbub1->watermarks.c.cstate_pstate.pstate_change_ns =
0550                 watermarks->c.cstate_pstate.pstate_change_ns;
0551         prog_wm_value = convert_and_clamp(
0552                 watermarks->c.cstate_pstate.pstate_change_ns,
0553                 refclk_mhz, 0x1fffff);
0554         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0,
0555                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
0556         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
0557             "HW register value = 0x%x\n\n",
0558             watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
0559     } else if (watermarks->c.cstate_pstate.pstate_change_ns
0560             < hubbub1->watermarks.c.cstate_pstate.pstate_change_ns)
0561         wm_pending = true;
0562 
0563     /* clock state D */
0564     if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
0565             > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) {
0566         hubbub1->watermarks.d.cstate_pstate.pstate_change_ns =
0567                 watermarks->d.cstate_pstate.pstate_change_ns;
0568         prog_wm_value = convert_and_clamp(
0569                 watermarks->d.cstate_pstate.pstate_change_ns,
0570                 refclk_mhz, 0x1fffff);
0571         REG_SET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0,
0572                 DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
0573         DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
0574             "HW register value = 0x%x\n\n",
0575             watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
0576     } else if (watermarks->d.cstate_pstate.pstate_change_ns
0577             < hubbub1->watermarks.d.cstate_pstate.pstate_change_ns)
0578         wm_pending = true;
0579 
0580     return wm_pending;
0581 }
0582 
0583 bool hubbub1_program_watermarks(
0584         struct hubbub *hubbub,
0585         struct dcn_watermark_set *watermarks,
0586         unsigned int refclk_mhz,
0587         bool safe_to_lower)
0588 {
0589     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0590     bool wm_pending = false;
0591     /*
0592      * Need to clamp to max of the register values (i.e. no wrap)
0593      * for dcn1, all wm registers are 21-bit wide
0594      */
0595     if (hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0596         wm_pending = true;
0597 
0598     if (hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0599         wm_pending = true;
0600 
0601     if (hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower))
0602         wm_pending = true;
0603 
0604     REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL,
0605             DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
0606     REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
0607             DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68);
0608 
0609     hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
0610 
0611 #if 0
0612     REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
0613             DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, 1,
0614             DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
0615 #endif
0616     return wm_pending;
0617 }
0618 
0619 void hubbub1_update_dchub(
0620     struct hubbub *hubbub,
0621     struct dchub_init_data *dh_data)
0622 {
0623     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0624 
0625     if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) {
0626         ASSERT(false);
0627         /*should not come here*/
0628         return;
0629     }
0630     /* TODO: port code from dal2 */
0631     switch (dh_data->fb_mode) {
0632     case FRAME_BUFFER_MODE_ZFB_ONLY:
0633         /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
0634         REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP,
0635                 SDPIF_FB_TOP, 0);
0636 
0637         REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE,
0638                 SDPIF_FB_BASE, 0x0FFFF);
0639 
0640         REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
0641                 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
0642 
0643         REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
0644                 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
0645 
0646         REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
0647                 SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
0648                         dh_data->zfb_size_in_byte - 1) >> 22);
0649         break;
0650     case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
0651         /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
0652 
0653         REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
0654                 SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
0655 
0656         REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
0657                 SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
0658 
0659         REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
0660                 SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
0661                         dh_data->zfb_size_in_byte - 1) >> 22);
0662         break;
0663     case FRAME_BUFFER_MODE_LOCAL_ONLY:
0664         /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
0665         REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
0666                 SDPIF_AGP_BASE, 0);
0667 
0668         REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
0669                 SDPIF_AGP_BOT, 0X03FFFF);
0670 
0671         REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
0672                 SDPIF_AGP_TOP, 0);
0673         break;
0674     default:
0675         break;
0676     }
0677 
0678     dh_data->dchub_initialzied = true;
0679     dh_data->dchub_info_valid = false;
0680 }
0681 
0682 void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
0683 {
0684     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0685 
0686     uint32_t watermark_change_req;
0687 
0688     REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
0689             DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req);
0690 
0691     if (watermark_change_req)
0692         watermark_change_req = 0;
0693     else
0694         watermark_change_req = 1;
0695 
0696     REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
0697             DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req);
0698 }
0699 
0700 void hubbub1_soft_reset(struct hubbub *hubbub, bool reset)
0701 {
0702     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0703 
0704     uint32_t reset_en = reset ? 1 : 0;
0705 
0706     REG_UPDATE(DCHUBBUB_SOFT_RESET,
0707             DCHUBBUB_GLOBAL_SOFT_RESET, reset_en);
0708 }
0709 
0710 static bool hubbub1_dcc_support_swizzle(
0711         enum swizzle_mode_values swizzle,
0712         unsigned int bytes_per_element,
0713         enum segment_order *segment_order_horz,
0714         enum segment_order *segment_order_vert)
0715 {
0716     bool standard_swizzle = false;
0717     bool display_swizzle = false;
0718 
0719     switch (swizzle) {
0720     case DC_SW_4KB_S:
0721     case DC_SW_64KB_S:
0722     case DC_SW_VAR_S:
0723     case DC_SW_4KB_S_X:
0724     case DC_SW_64KB_S_X:
0725     case DC_SW_VAR_S_X:
0726         standard_swizzle = true;
0727         break;
0728     case DC_SW_4KB_D:
0729     case DC_SW_64KB_D:
0730     case DC_SW_VAR_D:
0731     case DC_SW_4KB_D_X:
0732     case DC_SW_64KB_D_X:
0733     case DC_SW_VAR_D_X:
0734         display_swizzle = true;
0735         break;
0736     default:
0737         break;
0738     }
0739 
0740     if (bytes_per_element == 1 && standard_swizzle) {
0741         *segment_order_horz = segment_order__contiguous;
0742         *segment_order_vert = segment_order__na;
0743         return true;
0744     }
0745     if (bytes_per_element == 2 && standard_swizzle) {
0746         *segment_order_horz = segment_order__non_contiguous;
0747         *segment_order_vert = segment_order__contiguous;
0748         return true;
0749     }
0750     if (bytes_per_element == 4 && standard_swizzle) {
0751         *segment_order_horz = segment_order__non_contiguous;
0752         *segment_order_vert = segment_order__contiguous;
0753         return true;
0754     }
0755     if (bytes_per_element == 8 && standard_swizzle) {
0756         *segment_order_horz = segment_order__na;
0757         *segment_order_vert = segment_order__contiguous;
0758         return true;
0759     }
0760     if (bytes_per_element == 8 && display_swizzle) {
0761         *segment_order_horz = segment_order__contiguous;
0762         *segment_order_vert = segment_order__non_contiguous;
0763         return true;
0764     }
0765 
0766     return false;
0767 }
0768 
0769 static bool hubbub1_dcc_support_pixel_format(
0770         enum surface_pixel_format format,
0771         unsigned int *bytes_per_element)
0772 {
0773     /* DML: get_bytes_per_element */
0774     switch (format) {
0775     case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
0776     case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
0777         *bytes_per_element = 2;
0778         return true;
0779     case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
0780     case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
0781     case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
0782     case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
0783         *bytes_per_element = 4;
0784         return true;
0785     case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
0786     case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
0787     case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
0788     case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
0789         *bytes_per_element = 8;
0790         return true;
0791     default:
0792         return false;
0793     }
0794 }
0795 
0796 static void hubbub1_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height,
0797         unsigned int bytes_per_element)
0798 {
0799     /* copied from DML.  might want to refactor DML to leverage from DML */
0800     /* DML : get_blk256_size */
0801     if (bytes_per_element == 1) {
0802         *blk256_width = 16;
0803         *blk256_height = 16;
0804     } else if (bytes_per_element == 2) {
0805         *blk256_width = 16;
0806         *blk256_height = 8;
0807     } else if (bytes_per_element == 4) {
0808         *blk256_width = 8;
0809         *blk256_height = 8;
0810     } else if (bytes_per_element == 8) {
0811         *blk256_width = 8;
0812         *blk256_height = 4;
0813     }
0814 }
0815 
0816 static void hubbub1_det_request_size(
0817         unsigned int height,
0818         unsigned int width,
0819         unsigned int bpe,
0820         bool *req128_horz_wc,
0821         bool *req128_vert_wc)
0822 {
0823     unsigned int detile_buf_size = 164 * 1024;  /* 164KB for DCN1.0 */
0824 
0825     unsigned int blk256_height = 0;
0826     unsigned int blk256_width = 0;
0827     unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
0828 
0829     hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
0830 
0831     swath_bytes_horz_wc = width * blk256_height * bpe;
0832     swath_bytes_vert_wc = height * blk256_width * bpe;
0833 
0834     *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
0835             false : /* full 256B request */
0836             true; /* half 128b request */
0837 
0838     *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
0839             false : /* full 256B request */
0840             true; /* half 128b request */
0841 }
0842 
0843 static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub,
0844         const struct dc_dcc_surface_param *input,
0845         struct dc_surface_dcc_cap *output)
0846 {
0847     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0848     struct dc *dc = hubbub1->base.ctx->dc;
0849 
0850     /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */
0851     enum dcc_control dcc_control;
0852     unsigned int bpe;
0853     enum segment_order segment_order_horz, segment_order_vert;
0854     bool req128_horz_wc, req128_vert_wc;
0855 
0856     memset(output, 0, sizeof(*output));
0857 
0858     if (dc->debug.disable_dcc == DCC_DISABLE)
0859         return false;
0860 
0861     if (!hubbub1->base.funcs->dcc_support_pixel_format(input->format, &bpe))
0862         return false;
0863 
0864     if (!hubbub1->base.funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
0865             &segment_order_horz, &segment_order_vert))
0866         return false;
0867 
0868     hubbub1_det_request_size(input->surface_size.height,  input->surface_size.width,
0869             bpe, &req128_horz_wc, &req128_vert_wc);
0870 
0871     if (!req128_horz_wc && !req128_vert_wc) {
0872         dcc_control = dcc_control__256_256_xxx;
0873     } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
0874         if (!req128_horz_wc)
0875             dcc_control = dcc_control__256_256_xxx;
0876         else if (segment_order_horz == segment_order__contiguous)
0877             dcc_control = dcc_control__128_128_xxx;
0878         else
0879             dcc_control = dcc_control__256_64_64;
0880     } else if (input->scan == SCAN_DIRECTION_VERTICAL) {
0881         if (!req128_vert_wc)
0882             dcc_control = dcc_control__256_256_xxx;
0883         else if (segment_order_vert == segment_order__contiguous)
0884             dcc_control = dcc_control__128_128_xxx;
0885         else
0886             dcc_control = dcc_control__256_64_64;
0887     } else {
0888         if ((req128_horz_wc &&
0889             segment_order_horz == segment_order__non_contiguous) ||
0890             (req128_vert_wc &&
0891             segment_order_vert == segment_order__non_contiguous))
0892             /* access_dir not known, must use most constraining */
0893             dcc_control = dcc_control__256_64_64;
0894         else
0895             /* reg128 is true for either horz and vert
0896              * but segment_order is contiguous
0897              */
0898             dcc_control = dcc_control__128_128_xxx;
0899     }
0900 
0901     if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
0902         dcc_control != dcc_control__256_256_xxx)
0903         return false;
0904 
0905     switch (dcc_control) {
0906     case dcc_control__256_256_xxx:
0907         output->grph.rgb.max_uncompressed_blk_size = 256;
0908         output->grph.rgb.max_compressed_blk_size = 256;
0909         output->grph.rgb.independent_64b_blks = false;
0910         break;
0911     case dcc_control__128_128_xxx:
0912         output->grph.rgb.max_uncompressed_blk_size = 128;
0913         output->grph.rgb.max_compressed_blk_size = 128;
0914         output->grph.rgb.independent_64b_blks = false;
0915         break;
0916     case dcc_control__256_64_64:
0917         output->grph.rgb.max_uncompressed_blk_size = 256;
0918         output->grph.rgb.max_compressed_blk_size = 64;
0919         output->grph.rgb.independent_64b_blks = true;
0920         break;
0921     default:
0922         ASSERT(false);
0923         break;
0924     }
0925 
0926     output->capable = true;
0927     output->const_color_support = false;
0928 
0929     return true;
0930 }
0931 
0932 static const struct hubbub_funcs hubbub1_funcs = {
0933     .update_dchub = hubbub1_update_dchub,
0934     .dcc_support_swizzle = hubbub1_dcc_support_swizzle,
0935     .dcc_support_pixel_format = hubbub1_dcc_support_pixel_format,
0936     .get_dcc_compression_cap = hubbub1_get_dcc_compression_cap,
0937     .wm_read_state = hubbub1_wm_read_state,
0938     .program_watermarks = hubbub1_program_watermarks,
0939     .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
0940     .allow_self_refresh_control = hubbub1_allow_self_refresh_control,
0941     .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
0942 };
0943 
0944 void hubbub1_construct(struct hubbub *hubbub,
0945     struct dc_context *ctx,
0946     const struct dcn_hubbub_registers *hubbub_regs,
0947     const struct dcn_hubbub_shift *hubbub_shift,
0948     const struct dcn_hubbub_mask *hubbub_mask)
0949 {
0950     struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub);
0951 
0952     hubbub1->base.ctx = ctx;
0953 
0954     hubbub1->base.funcs = &hubbub1_funcs;
0955 
0956     hubbub1->regs = hubbub_regs;
0957     hubbub1->shifts = hubbub_shift;
0958     hubbub1->masks = hubbub_mask;
0959 
0960     hubbub1->debug_test_index_pstate = 0x7;
0961     if (ctx->dce_version == DCN_VERSION_1_01)
0962         hubbub1->debug_test_index_pstate = 0xB;
0963 }
0964