linux/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
   3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
   4 */
   5
   6#include <linux/delay.h>
   7#include "dpu_hwio.h"
   8#include "dpu_hw_ctl.h"
   9#include "dpu_kms.h"
  10#include "dpu_trace.h"
  11
  12#define   CTL_LAYER(lm)                 \
  13        (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
  14#define   CTL_LAYER_EXT(lm)             \
  15        (0x40 + (((lm) - LM_0) * 0x004))
  16#define   CTL_LAYER_EXT2(lm)             \
  17        (0x70 + (((lm) - LM_0) * 0x004))
  18#define   CTL_LAYER_EXT3(lm)             \
  19        (0xA0 + (((lm) - LM_0) * 0x004))
  20#define   CTL_TOP                       0x014
  21#define   CTL_FLUSH                     0x018
  22#define   CTL_START                     0x01C
  23#define   CTL_PREPARE                   0x0d0
  24#define   CTL_SW_RESET                  0x030
  25#define   CTL_LAYER_EXTN_OFFSET         0x40
  26#define   CTL_MERGE_3D_ACTIVE           0x0E4
  27#define   CTL_WB_ACTIVE                 0x0EC
  28#define   CTL_INTF_ACTIVE               0x0F4
  29#define   CTL_MERGE_3D_FLUSH            0x100
  30#define   CTL_DSC_ACTIVE                0x0E8
  31#define   CTL_DSC_FLUSH                0x104
  32#define   CTL_WB_FLUSH                  0x108
  33#define   CTL_INTF_FLUSH                0x110
  34#define   CTL_INTF_MASTER               0x134
  35#define   CTL_FETCH_PIPE_ACTIVE         0x0FC
  36
  37#define CTL_MIXER_BORDER_OUT            BIT(24)
  38#define CTL_FLUSH_MASK_CTL              BIT(17)
  39
  40#define DPU_REG_RESET_TIMEOUT_US        2000
  41#define  MERGE_3D_IDX   23
  42#define  DSC_IDX        22
  43#define  INTF_IDX       31
  44#define WB_IDX          16
  45#define CTL_INVALID_BIT                 0xffff
  46#define CTL_DEFAULT_GROUP_ID            0xf
  47
  48static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19,
  49        CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0,
  50        1, 2, 3, CTL_INVALID_BIT, CTL_INVALID_BIT};
  51
  52static const struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl,
  53                const struct dpu_mdss_cfg *m,
  54                void __iomem *addr,
  55                struct dpu_hw_blk_reg_map *b)
  56{
  57        int i;
  58
  59        for (i = 0; i < m->ctl_count; i++) {
  60                if (ctl == m->ctl[i].id) {
  61                        b->base_off = addr;
  62                        b->blk_off = m->ctl[i].base;
  63                        b->length = m->ctl[i].len;
  64                        b->hwversion = m->hwversion;
  65                        b->log_mask = DPU_DBG_MASK_CTL;
  66                        return &m->ctl[i];
  67                }
  68        }
  69        return ERR_PTR(-ENOMEM);
  70}
  71
  72static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count,
  73                enum dpu_lm lm)
  74{
  75        int i;
  76        int stages = -EINVAL;
  77
  78        for (i = 0; i < count; i++) {
  79                if (lm == mixer[i].id) {
  80                        stages = mixer[i].sblk->maxblendstages;
  81                        break;
  82                }
  83        }
  84
  85        return stages;
  86}
  87
  88static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx)
  89{
  90        struct dpu_hw_blk_reg_map *c = &ctx->hw;
  91
  92        return DPU_REG_READ(c, CTL_FLUSH);
  93}
  94
  95static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx)
  96{
  97        trace_dpu_hw_ctl_trigger_start(ctx->pending_flush_mask,
  98                                       dpu_hw_ctl_get_flush_register(ctx));
  99        DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1);
 100}
 101
 102static inline bool dpu_hw_ctl_is_started(struct dpu_hw_ctl *ctx)
 103{
 104        return !!(DPU_REG_READ(&ctx->hw, CTL_START) & BIT(0));
 105}
 106
 107static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx)
 108{
 109        trace_dpu_hw_ctl_trigger_prepare(ctx->pending_flush_mask,
 110                                         dpu_hw_ctl_get_flush_register(ctx));
 111        DPU_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1);
 112}
 113
 114static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx)
 115{
 116        trace_dpu_hw_ctl_clear_pending_flush(ctx->pending_flush_mask,
 117                                     dpu_hw_ctl_get_flush_register(ctx));
 118        ctx->pending_flush_mask = 0x0;
 119}
 120
 121static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx,
 122                u32 flushbits)
 123{
 124        trace_dpu_hw_ctl_update_pending_flush(flushbits,
 125                                              ctx->pending_flush_mask);
 126        ctx->pending_flush_mask |= flushbits;
 127}
 128
 129static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx)
 130{
 131        return ctx->pending_flush_mask;
 132}
 133
 134static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
 135{
 136        if (ctx->pending_flush_mask & BIT(MERGE_3D_IDX))
 137                DPU_REG_WRITE(&ctx->hw, CTL_MERGE_3D_FLUSH,
 138                                ctx->pending_merge_3d_flush_mask);
 139        if (ctx->pending_flush_mask & BIT(INTF_IDX))
 140                DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH,
 141                                ctx->pending_intf_flush_mask);
 142        if (ctx->pending_flush_mask & BIT(WB_IDX))
 143                DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
 144                                ctx->pending_wb_flush_mask);
 145
 146        DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 147}
 148
 149static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx)
 150{
 151        trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask,
 152                                     dpu_hw_ctl_get_flush_register(ctx));
 153        DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 154}
 155
 156static uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx,
 157        enum dpu_sspp sspp)
 158{
 159        uint32_t flushbits = 0;
 160
 161        switch (sspp) {
 162        case SSPP_VIG0:
 163                flushbits =  BIT(0);
 164                break;
 165        case SSPP_VIG1:
 166                flushbits = BIT(1);
 167                break;
 168        case SSPP_VIG2:
 169                flushbits = BIT(2);
 170                break;
 171        case SSPP_VIG3:
 172                flushbits = BIT(18);
 173                break;
 174        case SSPP_RGB0:
 175                flushbits = BIT(3);
 176                break;
 177        case SSPP_RGB1:
 178                flushbits = BIT(4);
 179                break;
 180        case SSPP_RGB2:
 181                flushbits = BIT(5);
 182                break;
 183        case SSPP_RGB3:
 184                flushbits = BIT(19);
 185                break;
 186        case SSPP_DMA0:
 187                flushbits = BIT(11);
 188                break;
 189        case SSPP_DMA1:
 190                flushbits = BIT(12);
 191                break;
 192        case SSPP_DMA2:
 193                flushbits = BIT(24);
 194                break;
 195        case SSPP_DMA3:
 196                flushbits = BIT(25);
 197                break;
 198        case SSPP_CURSOR0:
 199                flushbits = BIT(22);
 200                break;
 201        case SSPP_CURSOR1:
 202                flushbits = BIT(23);
 203                break;
 204        default:
 205                break;
 206        }
 207
 208        return flushbits;
 209}
 210
 211static uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx,
 212        enum dpu_lm lm)
 213{
 214        uint32_t flushbits = 0;
 215
 216        switch (lm) {
 217        case LM_0:
 218                flushbits = BIT(6);
 219                break;
 220        case LM_1:
 221                flushbits = BIT(7);
 222                break;
 223        case LM_2:
 224                flushbits = BIT(8);
 225                break;
 226        case LM_3:
 227                flushbits = BIT(9);
 228                break;
 229        case LM_4:
 230                flushbits = BIT(10);
 231                break;
 232        case LM_5:
 233                flushbits = BIT(20);
 234                break;
 235        default:
 236                return -EINVAL;
 237        }
 238
 239        flushbits |= CTL_FLUSH_MASK_CTL;
 240
 241        return flushbits;
 242}
 243
 244static void dpu_hw_ctl_update_pending_flush_intf(struct dpu_hw_ctl *ctx,
 245                enum dpu_intf intf)
 246{
 247        switch (intf) {
 248        case INTF_0:
 249                ctx->pending_flush_mask |= BIT(31);
 250                break;
 251        case INTF_1:
 252                ctx->pending_flush_mask |= BIT(30);
 253                break;
 254        case INTF_2:
 255                ctx->pending_flush_mask |= BIT(29);
 256                break;
 257        case INTF_3:
 258                ctx->pending_flush_mask |= BIT(28);
 259                break;
 260        default:
 261                break;
 262        }
 263}
 264
 265static void dpu_hw_ctl_update_pending_flush_wb(struct dpu_hw_ctl *ctx,
 266                enum dpu_wb wb)
 267{
 268        switch (wb) {
 269        case WB_0:
 270        case WB_1:
 271        case WB_2:
 272                ctx->pending_flush_mask |= BIT(WB_IDX);
 273                break;
 274        default:
 275                break;
 276        }
 277}
 278
 279static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx,
 280                enum dpu_wb wb)
 281{
 282        ctx->pending_wb_flush_mask |= BIT(wb - WB_0);
 283        ctx->pending_flush_mask |= BIT(WB_IDX);
 284}
 285
 286static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
 287                enum dpu_intf intf)
 288{
 289        ctx->pending_intf_flush_mask |= BIT(intf - INTF_0);
 290        ctx->pending_flush_mask |= BIT(INTF_IDX);
 291}
 292
 293static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
 294                enum dpu_merge_3d merge_3d)
 295{
 296        ctx->pending_merge_3d_flush_mask |= BIT(merge_3d - MERGE_3D_0);
 297        ctx->pending_flush_mask |= BIT(MERGE_3D_IDX);
 298}
 299
 300static uint32_t dpu_hw_ctl_get_bitmask_dspp(struct dpu_hw_ctl *ctx,
 301        enum dpu_dspp dspp)
 302{
 303        uint32_t flushbits = 0;
 304
 305        switch (dspp) {
 306        case DSPP_0:
 307                flushbits = BIT(13);
 308                break;
 309        case DSPP_1:
 310                flushbits = BIT(14);
 311                break;
 312        case DSPP_2:
 313                flushbits = BIT(15);
 314                break;
 315        case DSPP_3:
 316                flushbits = BIT(21);
 317                break;
 318        default:
 319                return 0;
 320        }
 321
 322        return flushbits;
 323}
 324
 325static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us)
 326{
 327        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 328        ktime_t timeout;
 329        u32 status;
 330
 331        timeout = ktime_add_us(ktime_get(), timeout_us);
 332
 333        /*
 334         * it takes around 30us to have mdp finish resetting its ctl path
 335         * poll every 50us so that reset should be completed at 1st poll
 336         */
 337        do {
 338                status = DPU_REG_READ(c, CTL_SW_RESET);
 339                status &= 0x1;
 340                if (status)
 341                        usleep_range(20, 50);
 342        } while (status && ktime_compare_safe(ktime_get(), timeout) < 0);
 343
 344        return status;
 345}
 346
 347static int dpu_hw_ctl_reset_control(struct dpu_hw_ctl *ctx)
 348{
 349        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 350
 351        pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
 352        DPU_REG_WRITE(c, CTL_SW_RESET, 0x1);
 353        if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US))
 354                return -EINVAL;
 355
 356        return 0;
 357}
 358
 359static int dpu_hw_ctl_wait_reset_status(struct dpu_hw_ctl *ctx)
 360{
 361        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 362        u32 status;
 363
 364        status = DPU_REG_READ(c, CTL_SW_RESET);
 365        status &= 0x01;
 366        if (!status)
 367                return 0;
 368
 369        pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
 370        if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) {
 371                pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
 372                return -EINVAL;
 373        }
 374
 375        return 0;
 376}
 377
 378static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx)
 379{
 380        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 381        int i;
 382
 383        for (i = 0; i < ctx->mixer_count; i++) {
 384                enum dpu_lm mixer_id = ctx->mixer_hw_caps[i].id;
 385
 386                DPU_REG_WRITE(c, CTL_LAYER(mixer_id), 0);
 387                DPU_REG_WRITE(c, CTL_LAYER_EXT(mixer_id), 0);
 388                DPU_REG_WRITE(c, CTL_LAYER_EXT2(mixer_id), 0);
 389                DPU_REG_WRITE(c, CTL_LAYER_EXT3(mixer_id), 0);
 390        }
 391
 392        DPU_REG_WRITE(c, CTL_FETCH_PIPE_ACTIVE, 0);
 393}
 394
 395static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx,
 396        enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg)
 397{
 398        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 399        u32 mixercfg = 0, mixercfg_ext = 0, mix, ext;
 400        u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0;
 401        int i, j;
 402        int stages;
 403        int pipes_per_stage;
 404
 405        stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm);
 406        if (stages < 0)
 407                return;
 408
 409        if (test_bit(DPU_MIXER_SOURCESPLIT,
 410                &ctx->mixer_hw_caps->features))
 411                pipes_per_stage = PIPES_PER_STAGE;
 412        else
 413                pipes_per_stage = 1;
 414
 415        mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */
 416
 417        if (!stage_cfg)
 418                goto exit;
 419
 420        for (i = 0; i <= stages; i++) {
 421                /* overflow to ext register if 'i + 1 > 7' */
 422                mix = (i + 1) & 0x7;
 423                ext = i >= 7;
 424
 425                for (j = 0 ; j < pipes_per_stage; j++) {
 426                        enum dpu_sspp_multirect_index rect_index =
 427                                stage_cfg->multirect_index[i][j];
 428
 429                        switch (stage_cfg->stage[i][j]) {
 430                        case SSPP_VIG0:
 431                                if (rect_index == DPU_SSPP_RECT_1) {
 432                                        mixercfg_ext3 |= ((i + 1) & 0xF) << 0;
 433                                } else {
 434                                        mixercfg |= mix << 0;
 435                                        mixercfg_ext |= ext << 0;
 436                                }
 437                                break;
 438                        case SSPP_VIG1:
 439                                if (rect_index == DPU_SSPP_RECT_1) {
 440                                        mixercfg_ext3 |= ((i + 1) & 0xF) << 4;
 441                                } else {
 442                                        mixercfg |= mix << 3;
 443                                        mixercfg_ext |= ext << 2;
 444                                }
 445                                break;
 446                        case SSPP_VIG2:
 447                                if (rect_index == DPU_SSPP_RECT_1) {
 448                                        mixercfg_ext3 |= ((i + 1) & 0xF) << 8;
 449                                } else {
 450                                        mixercfg |= mix << 6;
 451                                        mixercfg_ext |= ext << 4;
 452                                }
 453                                break;
 454                        case SSPP_VIG3:
 455                                if (rect_index == DPU_SSPP_RECT_1) {
 456                                        mixercfg_ext3 |= ((i + 1) & 0xF) << 12;
 457                                } else {
 458                                        mixercfg |= mix << 26;
 459                                        mixercfg_ext |= ext << 6;
 460                                }
 461                                break;
 462                        case SSPP_RGB0:
 463                                mixercfg |= mix << 9;
 464                                mixercfg_ext |= ext << 8;
 465                                break;
 466                        case SSPP_RGB1:
 467                                mixercfg |= mix << 12;
 468                                mixercfg_ext |= ext << 10;
 469                                break;
 470                        case SSPP_RGB2:
 471                                mixercfg |= mix << 15;
 472                                mixercfg_ext |= ext << 12;
 473                                break;
 474                        case SSPP_RGB3:
 475                                mixercfg |= mix << 29;
 476                                mixercfg_ext |= ext << 14;
 477                                break;
 478                        case SSPP_DMA0:
 479                                if (rect_index == DPU_SSPP_RECT_1) {
 480                                        mixercfg_ext2 |= ((i + 1) & 0xF) << 8;
 481                                } else {
 482                                        mixercfg |= mix << 18;
 483                                        mixercfg_ext |= ext << 16;
 484                                }
 485                                break;
 486                        case SSPP_DMA1:
 487                                if (rect_index == DPU_SSPP_RECT_1) {
 488                                        mixercfg_ext2 |= ((i + 1) & 0xF) << 12;
 489                                } else {
 490                                        mixercfg |= mix << 21;
 491                                        mixercfg_ext |= ext << 18;
 492                                }
 493                                break;
 494                        case SSPP_DMA2:
 495                                if (rect_index == DPU_SSPP_RECT_1) {
 496                                        mixercfg_ext2 |= ((i + 1) & 0xF) << 16;
 497                                } else {
 498                                        mix |= (i + 1) & 0xF;
 499                                        mixercfg_ext2 |= mix << 0;
 500                                }
 501                                break;
 502                        case SSPP_DMA3:
 503                                if (rect_index == DPU_SSPP_RECT_1) {
 504                                        mixercfg_ext2 |= ((i + 1) & 0xF) << 20;
 505                                } else {
 506                                        mix |= (i + 1) & 0xF;
 507                                        mixercfg_ext2 |= mix << 4;
 508                                }
 509                                break;
 510                        case SSPP_CURSOR0:
 511                                mixercfg_ext |= ((i + 1) & 0xF) << 20;
 512                                break;
 513                        case SSPP_CURSOR1:
 514                                mixercfg_ext |= ((i + 1) & 0xF) << 26;
 515                                break;
 516                        default:
 517                                break;
 518                        }
 519                }
 520        }
 521
 522exit:
 523        DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg);
 524        DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext);
 525        DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2);
 526        DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3);
 527}
 528
 529
 530static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 531                struct dpu_hw_intf_cfg *cfg)
 532{
 533        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 534        u32 intf_active = 0;
 535        u32 wb_active = 0;
 536        u32 mode_sel = 0;
 537
 538        /* CTL_TOP[31:28] carries group_id to collate CTL paths
 539         * per VM. Explicitly disable it until VM support is
 540         * added in SW. Power on reset value is not disable.
 541         */
 542        if ((test_bit(DPU_CTL_VM_CFG, &ctx->caps->features)))
 543                mode_sel = CTL_DEFAULT_GROUP_ID  << 28;
 544
 545        if (cfg->dsc)
 546                DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, cfg->dsc);
 547
 548        if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD)
 549                mode_sel |= BIT(17);
 550
 551        intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
 552        wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
 553
 554        if (cfg->intf)
 555                intf_active |= BIT(cfg->intf - INTF_0);
 556
 557        if (cfg->wb)
 558                wb_active |= BIT(cfg->wb - WB_0);
 559
 560        DPU_REG_WRITE(c, CTL_TOP, mode_sel);
 561        DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
 562        DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
 563
 564        if (cfg->merge_3d)
 565                DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
 566                              BIT(cfg->merge_3d - MERGE_3D_0));
 567        if (cfg->dsc) {
 568                DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, DSC_IDX);
 569                DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc);
 570        }
 571}
 572
 573static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx,
 574                struct dpu_hw_intf_cfg *cfg)
 575{
 576        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 577        u32 intf_cfg = 0;
 578
 579        intf_cfg |= (cfg->intf & 0xF) << 4;
 580
 581        if (cfg->mode_3d) {
 582                intf_cfg |= BIT(19);
 583                intf_cfg |= (cfg->mode_3d - 0x1) << 20;
 584        }
 585
 586        if (cfg->wb)
 587                intf_cfg |= (cfg->wb & 0x3) + 2;
 588
 589        switch (cfg->intf_mode_sel) {
 590        case DPU_CTL_MODE_SEL_VID:
 591                intf_cfg &= ~BIT(17);
 592                intf_cfg &= ~(0x3 << 15);
 593                break;
 594        case DPU_CTL_MODE_SEL_CMD:
 595                intf_cfg |= BIT(17);
 596                intf_cfg |= ((cfg->stream_sel & 0x3) << 15);
 597                break;
 598        default:
 599                pr_err("unknown interface type %d\n", cfg->intf_mode_sel);
 600                return;
 601        }
 602
 603        DPU_REG_WRITE(c, CTL_TOP, intf_cfg);
 604}
 605
 606static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 607                struct dpu_hw_intf_cfg *cfg)
 608{
 609        struct dpu_hw_blk_reg_map *c = &ctx->hw;
 610        u32 intf_active = 0;
 611        u32 wb_active = 0;
 612        u32 merge3d_active = 0;
 613
 614        /*
 615         * This API resets each portion of the CTL path namely,
 616         * clearing the sspps staged on the lm, merge_3d block,
 617         * interfaces , writeback etc to ensure clean teardown of the pipeline.
 618         * This will be used for writeback to begin with to have a
 619         * proper teardown of the writeback session but upon further
 620         * validation, this can be extended to all interfaces.
 621         */
 622        if (cfg->merge_3d) {
 623                merge3d_active = DPU_REG_READ(c, CTL_MERGE_3D_ACTIVE);
 624                merge3d_active &= ~BIT(cfg->merge_3d - MERGE_3D_0);
 625                DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
 626                                merge3d_active);
 627        }
 628
 629        dpu_hw_ctl_clear_all_blendstages(ctx);
 630
 631        if (cfg->intf) {
 632                intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
 633                intf_active &= ~BIT(cfg->intf - INTF_0);
 634                DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
 635        }
 636
 637        if (cfg->wb) {
 638                wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
 639                wb_active &= ~BIT(cfg->wb - WB_0);
 640                DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
 641        }
 642}
 643
 644static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx,
 645        unsigned long *fetch_active)
 646{
 647        int i;
 648        u32 val = 0;
 649
 650        if (fetch_active) {
 651                for (i = 0; i < SSPP_MAX; i++) {
 652                        if (test_bit(i, fetch_active) &&
 653                                fetch_tbl[i] != CTL_INVALID_BIT)
 654                                val |= BIT(fetch_tbl[i]);
 655                }
 656        }
 657
 658        DPU_REG_WRITE(&ctx->hw, CTL_FETCH_PIPE_ACTIVE, val);
 659}
 660
 661static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
 662                unsigned long cap)
 663{
 664        if (cap & BIT(DPU_CTL_ACTIVE_CFG)) {
 665                ops->trigger_flush = dpu_hw_ctl_trigger_flush_v1;
 666                ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1;
 667                ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
 668                ops->update_pending_flush_intf =
 669                        dpu_hw_ctl_update_pending_flush_intf_v1;
 670                ops->update_pending_flush_merge_3d =
 671                        dpu_hw_ctl_update_pending_flush_merge_3d_v1;
 672                ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
 673        } else {
 674                ops->trigger_flush = dpu_hw_ctl_trigger_flush;
 675                ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg;
 676                ops->update_pending_flush_intf =
 677                        dpu_hw_ctl_update_pending_flush_intf;
 678                ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb;
 679        }
 680        ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush;
 681        ops->update_pending_flush = dpu_hw_ctl_update_pending_flush;
 682        ops->get_pending_flush = dpu_hw_ctl_get_pending_flush;
 683        ops->get_flush_register = dpu_hw_ctl_get_flush_register;
 684        ops->trigger_start = dpu_hw_ctl_trigger_start;
 685        ops->is_started = dpu_hw_ctl_is_started;
 686        ops->trigger_pending = dpu_hw_ctl_trigger_pending;
 687        ops->reset = dpu_hw_ctl_reset_control;
 688        ops->wait_reset_status = dpu_hw_ctl_wait_reset_status;
 689        ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages;
 690        ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
 691        ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
 692        ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer;
 693        ops->get_bitmask_dspp = dpu_hw_ctl_get_bitmask_dspp;
 694        if (cap & BIT(DPU_CTL_FETCH_ACTIVE))
 695                ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active;
 696};
 697
 698struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
 699                void __iomem *addr,
 700                const struct dpu_mdss_cfg *m)
 701{
 702        struct dpu_hw_ctl *c;
 703        const struct dpu_ctl_cfg *cfg;
 704
 705        c = kzalloc(sizeof(*c), GFP_KERNEL);
 706        if (!c)
 707                return ERR_PTR(-ENOMEM);
 708
 709        cfg = _ctl_offset(idx, m, addr, &c->hw);
 710        if (IS_ERR_OR_NULL(cfg)) {
 711                kfree(c);
 712                pr_err("failed to create dpu_hw_ctl %d\n", idx);
 713                return ERR_PTR(-EINVAL);
 714        }
 715
 716        c->caps = cfg;
 717        _setup_ctl_ops(&c->ops, c->caps->features);
 718        c->idx = idx;
 719        c->mixer_count = m->mixer_count;
 720        c->mixer_hw_caps = m->mixer;
 721
 722        return c;
 723}
 724
 725void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx)
 726{
 727        kfree(ctx);
 728}
 729