linux/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
<<
>>
Prefs
   1/*
   2 * Copyright 2016 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  23 *
  24 */
  25
  26#include "dm_services.h"
  27#include "dcn10_hubp.h"
  28#include "dcn10_hubbub.h"
  29#include "reg_helper.h"
  30
  31#define CTX \
  32        hubbub->ctx
  33#define DC_LOGGER \
  34        hubbub->ctx->logger
  35#define REG(reg)\
  36        hubbub->regs->reg
  37
  38#undef FN
  39#define FN(reg_name, field_name) \
  40        hubbub->shifts->field_name, hubbub->masks->field_name
  41
  42void hubbub1_wm_read_state(struct hubbub *hubbub,
  43                struct dcn_hubbub_wm *wm)
  44{
  45        struct dcn_hubbub_wm_set *s;
  46
  47        memset(wm, 0, sizeof(struct dcn_hubbub_wm));
  48
  49        s = &wm->sets[0];
  50        s->wm_set = 0;
  51        s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A);
  52        s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A);
  53        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
  54                s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A);
  55                s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A);
  56        }
  57        s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A);
  58
  59        s = &wm->sets[1];
  60        s->wm_set = 1;
  61        s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B);
  62        s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B);
  63        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
  64                s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B);
  65                s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B);
  66        }
  67        s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B);
  68
  69        s = &wm->sets[2];
  70        s->wm_set = 2;
  71        s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C);
  72        s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C);
  73        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
  74                s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C);
  75                s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C);
  76        }
  77        s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C);
  78
  79        s = &wm->sets[3];
  80        s->wm_set = 3;
  81        s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D);
  82        s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D);
  83        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
  84                s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D);
  85                s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D);
  86        }
  87        s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D);
  88}
  89
  90void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub)
  91{
  92        REG_UPDATE(DCHUBBUB_ARB_DRAM_STATE_CNTL,
  93                        DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, 0);
  94}
  95
  96bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub)
  97{
  98        uint32_t enable = 0;
  99
 100        REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL,
 101                        DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, &enable);
 102
 103        return enable ? true : false;
 104}
 105
 106
 107bool hubbub1_verify_allow_pstate_change_high(
 108        struct hubbub *hubbub)
 109{
 110        /* pstate latency is ~20us so if we wait over 40us and pstate allow
 111         * still not asserted, we are probably stuck and going to hang
 112         *
 113         * TODO: Figure out why it takes ~100us on linux
 114         * pstate takes around ~100us on linux. Unknown currently as to
 115         * why it takes that long on linux
 116         */
 117        static unsigned int pstate_wait_timeout_us = 200;
 118        static unsigned int pstate_wait_expected_timeout_us = 40;
 119        static unsigned int max_sampled_pstate_wait_us; /* data collection */
 120        static bool forced_pstate_allow; /* help with revert wa */
 121
 122        unsigned int debug_data;
 123        unsigned int i;
 124
 125        if (forced_pstate_allow) {
 126                /* we hacked to force pstate allow to prevent hang last time
 127                 * we verify_allow_pstate_change_high.  so disable force
 128                 * here so we can check status
 129                 */
 130                REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
 131                             DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0,
 132                             DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0);
 133                forced_pstate_allow = false;
 134        }
 135
 136        /* RV2:
 137         * dchubbubdebugind, at: 0xB
 138         * description
 139         * 0:     Pipe0 Plane0 Allow Pstate Change
 140         * 1:     Pipe0 Plane1 Allow Pstate Change
 141         * 2:     Pipe0 Cursor0 Allow Pstate Change
 142         * 3:     Pipe0 Cursor1 Allow Pstate Change
 143         * 4:     Pipe1 Plane0 Allow Pstate Change
 144         * 5:     Pipe1 Plane1 Allow Pstate Change
 145         * 6:     Pipe1 Cursor0 Allow Pstate Change
 146         * 7:     Pipe1 Cursor1 Allow Pstate Change
 147         * 8:     Pipe2 Plane0 Allow Pstate Change
 148         * 9:     Pipe2 Plane1 Allow Pstate Change
 149         * 10:    Pipe2 Cursor0 Allow Pstate Change
 150         * 11:    Pipe2 Cursor1 Allow Pstate Change
 151         * 12:    Pipe3 Plane0 Allow Pstate Change
 152         * 13:    Pipe3 Plane1 Allow Pstate Change
 153         * 14:    Pipe3 Cursor0 Allow Pstate Change
 154         * 15:    Pipe3 Cursor1 Allow Pstate Change
 155         * 16:    Pipe4 Plane0 Allow Pstate Change
 156         * 17:    Pipe4 Plane1 Allow Pstate Change
 157         * 18:    Pipe4 Cursor0 Allow Pstate Change
 158         * 19:    Pipe4 Cursor1 Allow Pstate Change
 159         * 20:    Pipe5 Plane0 Allow Pstate Change
 160         * 21:    Pipe5 Plane1 Allow Pstate Change
 161         * 22:    Pipe5 Cursor0 Allow Pstate Change
 162         * 23:    Pipe5 Cursor1 Allow Pstate Change
 163         * 24:    Pipe6 Plane0 Allow Pstate Change
 164         * 25:    Pipe6 Plane1 Allow Pstate Change
 165         * 26:    Pipe6 Cursor0 Allow Pstate Change
 166         * 27:    Pipe6 Cursor1 Allow Pstate Change
 167         * 28:    WB0 Allow Pstate Change
 168         * 29:    WB1 Allow Pstate Change
 169         * 30:    Arbiter's allow_pstate_change
 170         * 31:    SOC pstate change request"
 171         *
 172         * RV1:
 173         * dchubbubdebugind, at: 0x7
 174         * description "3-0:   Pipe0 cursor0 QOS
 175         * 7-4:   Pipe1 cursor0 QOS
 176         * 11-8:  Pipe2 cursor0 QOS
 177         * 15-12: Pipe3 cursor0 QOS
 178         * 16:    Pipe0 Plane0 Allow Pstate Change
 179         * 17:    Pipe1 Plane0 Allow Pstate Change
 180         * 18:    Pipe2 Plane0 Allow Pstate Change
 181         * 19:    Pipe3 Plane0 Allow Pstate Change
 182         * 20:    Pipe0 Plane1 Allow Pstate Change
 183         * 21:    Pipe1 Plane1 Allow Pstate Change
 184         * 22:    Pipe2 Plane1 Allow Pstate Change
 185         * 23:    Pipe3 Plane1 Allow Pstate Change
 186         * 24:    Pipe0 cursor0 Allow Pstate Change
 187         * 25:    Pipe1 cursor0 Allow Pstate Change
 188         * 26:    Pipe2 cursor0 Allow Pstate Change
 189         * 27:    Pipe3 cursor0 Allow Pstate Change
 190         * 28:    WB0 Allow Pstate Change
 191         * 29:    WB1 Allow Pstate Change
 192         * 30:    Arbiter's allow_pstate_change
 193         * 31:    SOC pstate change request
 194         */
 195
 196        REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub->debug_test_index_pstate);
 197
 198        for (i = 0; i < pstate_wait_timeout_us; i++) {
 199                debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
 200
 201                if (debug_data & (1 << 30)) {
 202
 203                        if (i > pstate_wait_expected_timeout_us)
 204                                DC_LOG_WARNING("pstate took longer than expected ~%dus\n",
 205                                                i);
 206
 207                        return true;
 208                }
 209                if (max_sampled_pstate_wait_us < i)
 210                        max_sampled_pstate_wait_us = i;
 211
 212                udelay(1);
 213        }
 214
 215        /* force pstate allow to prevent system hang
 216         * and break to debugger to investigate
 217         */
 218        REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
 219                     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1,
 220                     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1);
 221        forced_pstate_allow = true;
 222
 223        DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
 224                        debug_data);
 225
 226        return false;
 227}
 228
 229static uint32_t convert_and_clamp(
 230        uint32_t wm_ns,
 231        uint32_t refclk_mhz,
 232        uint32_t clamp_value)
 233{
 234        uint32_t ret_val = 0;
 235        ret_val = wm_ns * refclk_mhz;
 236        ret_val /= 1000;
 237
 238        if (ret_val > clamp_value)
 239                ret_val = clamp_value;
 240
 241        return ret_val;
 242}
 243
 244
 245void hubbub1_wm_change_req_wa(struct hubbub *hubbub)
 246{
 247        REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
 248                        DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1);
 249}
 250
 251void hubbub1_program_watermarks(
 252                struct hubbub *hubbub,
 253                struct dcn_watermark_set *watermarks,
 254                unsigned int refclk_mhz,
 255                bool safe_to_lower)
 256{
 257        uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0;
 258        /*
 259         * Need to clamp to max of the register values (i.e. no wrap)
 260         * for dcn1, all wm registers are 21-bit wide
 261         */
 262        uint32_t prog_wm_value;
 263
 264
 265        /* Repeat for water mark set A, B, C and D. */
 266        /* clock state A */
 267        if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) {
 268                hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns;
 269                prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns,
 270                                refclk_mhz, 0x1fffff);
 271                REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value);
 272
 273                DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n"
 274                        "HW register value = 0x%x\n",
 275                        watermarks->a.urgent_ns, prog_wm_value);
 276        }
 277
 278        if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) {
 279                hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns;
 280                prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns,
 281                                refclk_mhz, 0x1fffff);
 282                REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value);
 283                DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n"
 284                        "HW register value = 0x%x\n",
 285                        watermarks->a.pte_meta_urgent_ns, prog_wm_value);
 286        }
 287
 288        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) {
 289                if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns
 290                                > hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) {
 291                        hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
 292                                        watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns;
 293                        prog_wm_value = convert_and_clamp(
 294                                        watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns,
 295                                        refclk_mhz, 0x1fffff);
 296                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value);
 297                        DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n"
 298                                "HW register value = 0x%x\n",
 299                                watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 300                }
 301
 302                if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns
 303                                > hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) {
 304                        hubbub->watermarks.a.cstate_pstate.cstate_exit_ns =
 305                                        watermarks->a.cstate_pstate.cstate_exit_ns;
 306                        prog_wm_value = convert_and_clamp(
 307                                        watermarks->a.cstate_pstate.cstate_exit_ns,
 308                                        refclk_mhz, 0x1fffff);
 309                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value);
 310                        DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n"
 311                                "HW register value = 0x%x\n",
 312                                watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value);
 313                }
 314        }
 315
 316        if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns
 317                        > hubbub->watermarks.a.cstate_pstate.pstate_change_ns) {
 318                hubbub->watermarks.a.cstate_pstate.pstate_change_ns =
 319                                watermarks->a.cstate_pstate.pstate_change_ns;
 320                prog_wm_value = convert_and_clamp(
 321                                watermarks->a.cstate_pstate.pstate_change_ns,
 322                                refclk_mhz, 0x1fffff);
 323                REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value);
 324                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n"
 325                        "HW register value = 0x%x\n\n",
 326                        watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value);
 327        }
 328
 329        /* clock state B */
 330        if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) {
 331                hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns;
 332                prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns,
 333                                refclk_mhz, 0x1fffff);
 334                REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value);
 335
 336                DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n"
 337                        "HW register value = 0x%x\n",
 338                        watermarks->b.urgent_ns, prog_wm_value);
 339        }
 340
 341        if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) {
 342                hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns;
 343                prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns,
 344                                refclk_mhz, 0x1fffff);
 345                REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value);
 346                DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n"
 347                        "HW register value = 0x%x\n",
 348                        watermarks->b.pte_meta_urgent_ns, prog_wm_value);
 349        }
 350
 351        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) {
 352                if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns
 353                                > hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) {
 354                        hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns =
 355                                        watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns;
 356                        prog_wm_value = convert_and_clamp(
 357                                        watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns,
 358                                        refclk_mhz, 0x1fffff);
 359                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value);
 360                        DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n"
 361                                "HW register value = 0x%x\n",
 362                                watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 363                }
 364
 365                if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns
 366                                > hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) {
 367                        hubbub->watermarks.b.cstate_pstate.cstate_exit_ns =
 368                                        watermarks->b.cstate_pstate.cstate_exit_ns;
 369                        prog_wm_value = convert_and_clamp(
 370                                        watermarks->b.cstate_pstate.cstate_exit_ns,
 371                                        refclk_mhz, 0x1fffff);
 372                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value);
 373                        DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n"
 374                                "HW register value = 0x%x\n",
 375                                watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value);
 376                }
 377        }
 378
 379        if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns
 380                        > hubbub->watermarks.b.cstate_pstate.pstate_change_ns) {
 381                hubbub->watermarks.b.cstate_pstate.pstate_change_ns =
 382                                watermarks->b.cstate_pstate.pstate_change_ns;
 383                prog_wm_value = convert_and_clamp(
 384                                watermarks->b.cstate_pstate.pstate_change_ns,
 385                                refclk_mhz, 0x1fffff);
 386                REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value);
 387                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n"
 388                        "HW register value = 0x%x\n\n",
 389                        watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value);
 390        }
 391
 392        /* clock state C */
 393        if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) {
 394                hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns;
 395                prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns,
 396                                refclk_mhz, 0x1fffff);
 397                REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value);
 398
 399                DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n"
 400                        "HW register value = 0x%x\n",
 401                        watermarks->c.urgent_ns, prog_wm_value);
 402        }
 403
 404        if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) {
 405                hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns;
 406                prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns,
 407                                refclk_mhz, 0x1fffff);
 408                REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value);
 409                DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n"
 410                        "HW register value = 0x%x\n",
 411                        watermarks->c.pte_meta_urgent_ns, prog_wm_value);
 412        }
 413
 414        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) {
 415                if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns
 416                                > hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) {
 417                        hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns =
 418                                        watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns;
 419                        prog_wm_value = convert_and_clamp(
 420                                        watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns,
 421                                        refclk_mhz, 0x1fffff);
 422                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value);
 423                        DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n"
 424                                "HW register value = 0x%x\n",
 425                                watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 426                }
 427
 428                if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns
 429                                > hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) {
 430                        hubbub->watermarks.c.cstate_pstate.cstate_exit_ns =
 431                                        watermarks->c.cstate_pstate.cstate_exit_ns;
 432                        prog_wm_value = convert_and_clamp(
 433                                        watermarks->c.cstate_pstate.cstate_exit_ns,
 434                                        refclk_mhz, 0x1fffff);
 435                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value);
 436                        DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n"
 437                                "HW register value = 0x%x\n",
 438                                watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value);
 439                }
 440        }
 441
 442        if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns
 443                        > hubbub->watermarks.c.cstate_pstate.pstate_change_ns) {
 444                hubbub->watermarks.c.cstate_pstate.pstate_change_ns =
 445                                watermarks->c.cstate_pstate.pstate_change_ns;
 446                prog_wm_value = convert_and_clamp(
 447                                watermarks->c.cstate_pstate.pstate_change_ns,
 448                                refclk_mhz, 0x1fffff);
 449                REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value);
 450                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n"
 451                        "HW register value = 0x%x\n\n",
 452                        watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value);
 453        }
 454
 455        /* clock state D */
 456        if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) {
 457                hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns;
 458                prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns,
 459                                refclk_mhz, 0x1fffff);
 460                REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value);
 461
 462                DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n"
 463                        "HW register value = 0x%x\n",
 464                        watermarks->d.urgent_ns, prog_wm_value);
 465        }
 466
 467        if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) {
 468                hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns;
 469                prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns,
 470                                refclk_mhz, 0x1fffff);
 471                REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value);
 472                DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n"
 473                        "HW register value = 0x%x\n",
 474                        watermarks->d.pte_meta_urgent_ns, prog_wm_value);
 475        }
 476
 477        if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) {
 478                if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns
 479                                > hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) {
 480                        hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns =
 481                                        watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns;
 482                        prog_wm_value = convert_and_clamp(
 483                                        watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns,
 484                                        refclk_mhz, 0x1fffff);
 485                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value);
 486                        DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n"
 487                                "HW register value = 0x%x\n",
 488                                watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value);
 489                }
 490
 491                if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns
 492                                > hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) {
 493                        hubbub->watermarks.d.cstate_pstate.cstate_exit_ns =
 494                                        watermarks->d.cstate_pstate.cstate_exit_ns;
 495                        prog_wm_value = convert_and_clamp(
 496                                        watermarks->d.cstate_pstate.cstate_exit_ns,
 497                                        refclk_mhz, 0x1fffff);
 498                        REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value);
 499                        DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n"
 500                                "HW register value = 0x%x\n",
 501                                watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value);
 502                }
 503        }
 504
 505        if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns
 506                        > hubbub->watermarks.d.cstate_pstate.pstate_change_ns) {
 507                hubbub->watermarks.d.cstate_pstate.pstate_change_ns =
 508                                watermarks->d.cstate_pstate.pstate_change_ns;
 509                prog_wm_value = convert_and_clamp(
 510                                watermarks->d.cstate_pstate.pstate_change_ns,
 511                                refclk_mhz, 0x1fffff);
 512                REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value);
 513                DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n"
 514                        "HW register value = 0x%x\n\n",
 515                        watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value);
 516        }
 517
 518        REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL,
 519                        DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz);
 520        REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND,
 521                        DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68);
 522
 523        REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
 524                        DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
 525                        DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en);
 526
 527#if 0
 528        REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
 529                        DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, 1,
 530                        DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1);
 531#endif
 532}
 533
 534void hubbub1_update_dchub(
 535        struct hubbub *hubbub,
 536        struct dchub_init_data *dh_data)
 537{
 538        if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) {
 539                ASSERT(false);
 540                /*should not come here*/
 541                return;
 542        }
 543        /* TODO: port code from dal2 */
 544        switch (dh_data->fb_mode) {
 545        case FRAME_BUFFER_MODE_ZFB_ONLY:
 546                /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/
 547                REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP,
 548                                SDPIF_FB_TOP, 0);
 549
 550                REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE,
 551                                SDPIF_FB_BASE, 0x0FFFF);
 552
 553                REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
 554                                SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
 555
 556                REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
 557                                SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
 558
 559                REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
 560                                SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
 561                                                dh_data->zfb_size_in_byte - 1) >> 22);
 562                break;
 563        case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL:
 564                /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
 565
 566                REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
 567                                SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22);
 568
 569                REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
 570                                SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22);
 571
 572                REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
 573                                SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr +
 574                                                dh_data->zfb_size_in_byte - 1) >> 22);
 575                break;
 576        case FRAME_BUFFER_MODE_LOCAL_ONLY:
 577                /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/
 578                REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE,
 579                                SDPIF_AGP_BASE, 0);
 580
 581                REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT,
 582                                SDPIF_AGP_BOT, 0X03FFFF);
 583
 584                REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP,
 585                                SDPIF_AGP_TOP, 0);
 586                break;
 587        default:
 588                break;
 589        }
 590
 591        dh_data->dchub_initialzied = true;
 592        dh_data->dchub_info_valid = false;
 593}
 594
 595void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub)
 596{
 597        uint32_t watermark_change_req;
 598
 599        REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
 600                        DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req);
 601
 602        if (watermark_change_req)
 603                watermark_change_req = 0;
 604        else
 605                watermark_change_req = 1;
 606
 607        REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL,
 608                        DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req);
 609}
 610
 611void hubbub1_soft_reset(struct hubbub *hubbub, bool reset)
 612{
 613        uint32_t reset_en = reset ? 1 : 0;
 614
 615        REG_UPDATE(DCHUBBUB_SOFT_RESET,
 616                        DCHUBBUB_GLOBAL_SOFT_RESET, reset_en);
 617}
 618
 619static bool hubbub1_dcc_support_swizzle(
 620                enum swizzle_mode_values swizzle,
 621                unsigned int bytes_per_element,
 622                enum segment_order *segment_order_horz,
 623                enum segment_order *segment_order_vert)
 624{
 625        bool standard_swizzle = false;
 626        bool display_swizzle = false;
 627
 628        switch (swizzle) {
 629        case DC_SW_4KB_S:
 630        case DC_SW_64KB_S:
 631        case DC_SW_VAR_S:
 632        case DC_SW_4KB_S_X:
 633        case DC_SW_64KB_S_X:
 634        case DC_SW_VAR_S_X:
 635                standard_swizzle = true;
 636                break;
 637        case DC_SW_4KB_D:
 638        case DC_SW_64KB_D:
 639        case DC_SW_VAR_D:
 640        case DC_SW_4KB_D_X:
 641        case DC_SW_64KB_D_X:
 642        case DC_SW_VAR_D_X:
 643                display_swizzle = true;
 644                break;
 645        default:
 646                break;
 647        }
 648
 649        if (bytes_per_element == 1 && standard_swizzle) {
 650                *segment_order_horz = segment_order__contiguous;
 651                *segment_order_vert = segment_order__na;
 652                return true;
 653        }
 654        if (bytes_per_element == 2 && standard_swizzle) {
 655                *segment_order_horz = segment_order__non_contiguous;
 656                *segment_order_vert = segment_order__contiguous;
 657                return true;
 658        }
 659        if (bytes_per_element == 4 && standard_swizzle) {
 660                *segment_order_horz = segment_order__non_contiguous;
 661                *segment_order_vert = segment_order__contiguous;
 662                return true;
 663        }
 664        if (bytes_per_element == 8 && standard_swizzle) {
 665                *segment_order_horz = segment_order__na;
 666                *segment_order_vert = segment_order__contiguous;
 667                return true;
 668        }
 669        if (bytes_per_element == 8 && display_swizzle) {
 670                *segment_order_horz = segment_order__contiguous;
 671                *segment_order_vert = segment_order__non_contiguous;
 672                return true;
 673        }
 674
 675        return false;
 676}
 677
 678static bool hubbub1_dcc_support_pixel_format(
 679                enum surface_pixel_format format,
 680                unsigned int *bytes_per_element)
 681{
 682        /* DML: get_bytes_per_element */
 683        switch (format) {
 684        case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
 685        case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
 686                *bytes_per_element = 2;
 687                return true;
 688        case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
 689        case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
 690        case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
 691        case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
 692                *bytes_per_element = 4;
 693                return true;
 694        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
 695        case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
 696        case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
 697                *bytes_per_element = 8;
 698                return true;
 699        default:
 700                return false;
 701        }
 702}
 703
 704static void hubbub1_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height,
 705                unsigned int bytes_per_element)
 706{
 707        /* copied from DML.  might want to refactor DML to leverage from DML */
 708        /* DML : get_blk256_size */
 709        if (bytes_per_element == 1) {
 710                *blk256_width = 16;
 711                *blk256_height = 16;
 712        } else if (bytes_per_element == 2) {
 713                *blk256_width = 16;
 714                *blk256_height = 8;
 715        } else if (bytes_per_element == 4) {
 716                *blk256_width = 8;
 717                *blk256_height = 8;
 718        } else if (bytes_per_element == 8) {
 719                *blk256_width = 8;
 720                *blk256_height = 4;
 721        }
 722}
 723
 724static void hubbub1_det_request_size(
 725                unsigned int height,
 726                unsigned int width,
 727                unsigned int bpe,
 728                bool *req128_horz_wc,
 729                bool *req128_vert_wc)
 730{
 731        unsigned int detile_buf_size = 164 * 1024;  /* 164KB for DCN1.0 */
 732
 733        unsigned int blk256_height = 0;
 734        unsigned int blk256_width = 0;
 735        unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc;
 736
 737        hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
 738
 739        swath_bytes_horz_wc = height * blk256_height * bpe;
 740        swath_bytes_vert_wc = width * blk256_width * bpe;
 741
 742        *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
 743                        false : /* full 256B request */
 744                        true; /* half 128b request */
 745
 746        *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ?
 747                        false : /* full 256B request */
 748                        true; /* half 128b request */
 749}
 750
 751static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub,
 752                const struct dc_dcc_surface_param *input,
 753                struct dc_surface_dcc_cap *output)
 754{
 755        struct dc *dc = hubbub->ctx->dc;
 756        /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */
 757        enum dcc_control dcc_control;
 758        unsigned int bpe;
 759        enum segment_order segment_order_horz, segment_order_vert;
 760        bool req128_horz_wc, req128_vert_wc;
 761
 762        memset(output, 0, sizeof(*output));
 763
 764        if (dc->debug.disable_dcc == DCC_DISABLE)
 765                return false;
 766
 767        if (!hubbub->funcs->dcc_support_pixel_format(input->format, &bpe))
 768                return false;
 769
 770        if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe,
 771                        &segment_order_horz, &segment_order_vert))
 772                return false;
 773
 774        hubbub1_det_request_size(input->surface_size.height,  input->surface_size.width,
 775                        bpe, &req128_horz_wc, &req128_vert_wc);
 776
 777        if (!req128_horz_wc && !req128_vert_wc) {
 778                dcc_control = dcc_control__256_256_xxx;
 779        } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) {
 780                if (!req128_horz_wc)
 781                        dcc_control = dcc_control__256_256_xxx;
 782                else if (segment_order_horz == segment_order__contiguous)
 783                        dcc_control = dcc_control__128_128_xxx;
 784                else
 785                        dcc_control = dcc_control__256_64_64;
 786        } else if (input->scan == SCAN_DIRECTION_VERTICAL) {
 787                if (!req128_vert_wc)
 788                        dcc_control = dcc_control__256_256_xxx;
 789                else if (segment_order_vert == segment_order__contiguous)
 790                        dcc_control = dcc_control__128_128_xxx;
 791                else
 792                        dcc_control = dcc_control__256_64_64;
 793        } else {
 794                if ((req128_horz_wc &&
 795                        segment_order_horz == segment_order__non_contiguous) ||
 796                        (req128_vert_wc &&
 797                        segment_order_vert == segment_order__non_contiguous))
 798                        /* access_dir not known, must use most constraining */
 799                        dcc_control = dcc_control__256_64_64;
 800                else
 801                        /* reg128 is true for either horz and vert
 802                         * but segment_order is contiguous
 803                         */
 804                        dcc_control = dcc_control__128_128_xxx;
 805        }
 806
 807        if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE &&
 808                dcc_control != dcc_control__256_256_xxx)
 809                return false;
 810
 811        switch (dcc_control) {
 812        case dcc_control__256_256_xxx:
 813                output->grph.rgb.max_uncompressed_blk_size = 256;
 814                output->grph.rgb.max_compressed_blk_size = 256;
 815                output->grph.rgb.independent_64b_blks = false;
 816                break;
 817        case dcc_control__128_128_xxx:
 818                output->grph.rgb.max_uncompressed_blk_size = 128;
 819                output->grph.rgb.max_compressed_blk_size = 128;
 820                output->grph.rgb.independent_64b_blks = false;
 821                break;
 822        case dcc_control__256_64_64:
 823                output->grph.rgb.max_uncompressed_blk_size = 256;
 824                output->grph.rgb.max_compressed_blk_size = 64;
 825                output->grph.rgb.independent_64b_blks = true;
 826                break;
 827        }
 828
 829        output->capable = true;
 830        output->const_color_support = false;
 831
 832        return true;
 833}
 834
 835static const struct hubbub_funcs hubbub1_funcs = {
 836        .update_dchub = hubbub1_update_dchub,
 837        .dcc_support_swizzle = hubbub1_dcc_support_swizzle,
 838        .dcc_support_pixel_format = hubbub1_dcc_support_pixel_format,
 839        .get_dcc_compression_cap = hubbub1_get_dcc_compression_cap,
 840};
 841
 842void hubbub1_construct(struct hubbub *hubbub,
 843        struct dc_context *ctx,
 844        const struct dcn_hubbub_registers *hubbub_regs,
 845        const struct dcn_hubbub_shift *hubbub_shift,
 846        const struct dcn_hubbub_mask *hubbub_mask)
 847{
 848        hubbub->ctx = ctx;
 849
 850        hubbub->funcs = &hubbub1_funcs;
 851
 852        hubbub->regs = hubbub_regs;
 853        hubbub->shifts = hubbub_shift;
 854        hubbub->masks = hubbub_mask;
 855
 856        hubbub->debug_test_index_pstate = 0x7;
 857#if defined(CONFIG_DRM_AMD_DC_DCN1_01)
 858        if (ctx->dce_version == DCN_VERSION_1_01)
 859                hubbub->debug_test_index_pstate = 0xB;
 860#endif
 861}
 862
 863