linux/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
   4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
   5 *
   6 */
   7
   8#include <drm/drm_print.h>
   9#include <linux/clk.h>
  10#include "komeda_dev.h"
  11#include "komeda_kms.h"
  12#include "komeda_pipeline.h"
  13#include "komeda_framebuffer.h"
  14
  15static inline bool is_switching_user(void *old, void *new)
  16{
  17        if (!old || !new)
  18                return false;
  19
  20        return old != new;
  21}
  22
  23static struct komeda_pipeline_state *
  24komeda_pipeline_get_state(struct komeda_pipeline *pipe,
  25                          struct drm_atomic_state *state)
  26{
  27        struct drm_private_state *priv_st;
  28
  29        priv_st = drm_atomic_get_private_obj_state(state, &pipe->obj);
  30        if (IS_ERR(priv_st))
  31                return ERR_CAST(priv_st);
  32
  33        return priv_to_pipe_st(priv_st);
  34}
  35
  36struct komeda_pipeline_state *
  37komeda_pipeline_get_old_state(struct komeda_pipeline *pipe,
  38                              struct drm_atomic_state *state)
  39{
  40        struct drm_private_state *priv_st;
  41
  42        priv_st = drm_atomic_get_old_private_obj_state(state, &pipe->obj);
  43        if (priv_st)
  44                return priv_to_pipe_st(priv_st);
  45        return NULL;
  46}
  47
  48static struct komeda_pipeline_state *
  49komeda_pipeline_get_new_state(struct komeda_pipeline *pipe,
  50                              struct drm_atomic_state *state)
  51{
  52        struct drm_private_state *priv_st;
  53
  54        priv_st = drm_atomic_get_new_private_obj_state(state, &pipe->obj);
  55        if (priv_st)
  56                return priv_to_pipe_st(priv_st);
  57        return NULL;
  58}
  59
  60/* Assign pipeline for crtc */
  61static struct komeda_pipeline_state *
  62komeda_pipeline_get_state_and_set_crtc(struct komeda_pipeline *pipe,
  63                                       struct drm_atomic_state *state,
  64                                       struct drm_crtc *crtc)
  65{
  66        struct komeda_pipeline_state *st;
  67
  68        st = komeda_pipeline_get_state(pipe, state);
  69        if (IS_ERR(st))
  70                return st;
  71
  72        if (is_switching_user(crtc, st->crtc)) {
  73                DRM_DEBUG_ATOMIC("CRTC%d required pipeline%d is busy.\n",
  74                                 drm_crtc_index(crtc), pipe->id);
  75                return ERR_PTR(-EBUSY);
  76        }
  77
  78        /* pipeline only can be disabled when the it is free or unused */
  79        if (!crtc && st->active_comps) {
  80                DRM_DEBUG_ATOMIC("Disabling a busy pipeline:%d.\n", pipe->id);
  81                return ERR_PTR(-EBUSY);
  82        }
  83
  84        st->crtc = crtc;
  85
  86        if (crtc) {
  87                struct komeda_crtc_state *kcrtc_st;
  88
  89                kcrtc_st = to_kcrtc_st(drm_atomic_get_new_crtc_state(state,
  90                                                                     crtc));
  91
  92                kcrtc_st->active_pipes |= BIT(pipe->id);
  93                kcrtc_st->affected_pipes |= BIT(pipe->id);
  94        }
  95        return st;
  96}
  97
  98static struct komeda_component_state *
  99komeda_component_get_state(struct komeda_component *c,
 100                           struct drm_atomic_state *state)
 101{
 102        struct drm_private_state *priv_st;
 103
 104        WARN_ON(!drm_modeset_is_locked(&c->pipeline->obj.lock));
 105
 106        priv_st = drm_atomic_get_private_obj_state(state, &c->obj);
 107        if (IS_ERR(priv_st))
 108                return ERR_CAST(priv_st);
 109
 110        return priv_to_comp_st(priv_st);
 111}
 112
 113static struct komeda_component_state *
 114komeda_component_get_old_state(struct komeda_component *c,
 115                               struct drm_atomic_state *state)
 116{
 117        struct drm_private_state *priv_st;
 118
 119        priv_st = drm_atomic_get_old_private_obj_state(state, &c->obj);
 120        if (priv_st)
 121                return priv_to_comp_st(priv_st);
 122        return NULL;
 123}
 124
 125/**
 126 * komeda_component_get_state_and_set_user()
 127 *
 128 * @c: component to get state and set user
 129 * @state: global atomic state
 130 * @user: direct user, the binding user
 131 * @crtc: the CRTC user, the big boss :)
 132 *
 133 * This function accepts two users:
 134 * -   The direct user: can be plane/crtc/wb_connector depends on component
 135 * -   The big boss (CRTC)
 136 * CRTC is the big boss (the final user), because all component resources
 137 * eventually will be assigned to CRTC, like the layer will be binding to
 138 * kms_plane, but kms plane will be binding to a CRTC eventually.
 139 *
 140 * The big boss (CRTC) is for pipeline assignment, since &komeda_component isn't
 141 * independent and can be assigned to CRTC freely, but belongs to a specific
 142 * pipeline, only pipeline can be shared between crtc, and pipeline as a whole
 143 * (include all the internal components) assigned to a specific CRTC.
 144 *
 145 * So when set a user to komeda_component, need first to check the status of
 146 * component->pipeline to see if the pipeline is available on this specific
 147 * CRTC. if the pipeline is busy (assigned to another CRTC), even the required
 148 * component is free, the component still cannot be assigned to the direct user.
 149 */
 150static struct komeda_component_state *
 151komeda_component_get_state_and_set_user(struct komeda_component *c,
 152                                        struct drm_atomic_state *state,
 153                                        void *user,
 154                                        struct drm_crtc *crtc)
 155{
 156        struct komeda_pipeline_state *pipe_st;
 157        struct komeda_component_state *st;
 158
 159        /* First check if the pipeline is available */
 160        pipe_st = komeda_pipeline_get_state_and_set_crtc(c->pipeline,
 161                                                         state, crtc);
 162        if (IS_ERR(pipe_st))
 163                return ERR_CAST(pipe_st);
 164
 165        st = komeda_component_get_state(c, state);
 166        if (IS_ERR(st))
 167                return st;
 168
 169        /* check if the component has been occupied */
 170        if (is_switching_user(user, st->binding_user)) {
 171                DRM_DEBUG_ATOMIC("required %s is busy.\n", c->name);
 172                return ERR_PTR(-EBUSY);
 173        }
 174
 175        st->binding_user = user;
 176        /* mark the component as active if user is valid */
 177        if (st->binding_user)
 178                pipe_st->active_comps |= BIT(c->id);
 179
 180        return st;
 181}
 182
 183static void
 184komeda_component_add_input(struct komeda_component_state *state,
 185                           struct komeda_component_output *input,
 186                           int idx)
 187{
 188        struct komeda_component *c = state->component;
 189
 190        WARN_ON((idx < 0 || idx >= c->max_active_inputs));
 191
 192        /* since the inputs[i] is only valid when it is active. So if a input[i]
 193         * is a newly enabled input which switches from disable to enable, then
 194         * the old inputs[i] is undefined (NOT zeroed), we can not rely on
 195         * memcmp, but directly mark it changed
 196         */
 197        if (!has_bit(idx, state->affected_inputs) ||
 198            memcmp(&state->inputs[idx], input, sizeof(*input))) {
 199                memcpy(&state->inputs[idx], input, sizeof(*input));
 200                state->changed_active_inputs |= BIT(idx);
 201        }
 202        state->active_inputs |= BIT(idx);
 203        state->affected_inputs |= BIT(idx);
 204}
 205
 206static int
 207komeda_component_check_input(struct komeda_component_state *state,
 208                             struct komeda_component_output *input,
 209                             int idx)
 210{
 211        struct komeda_component *c = state->component;
 212
 213        if ((idx < 0) || (idx >= c->max_active_inputs)) {
 214                DRM_DEBUG_ATOMIC("%s required an invalid %s-input[%d].\n",
 215                                 input->component->name, c->name, idx);
 216                return -EINVAL;
 217        }
 218
 219        if (has_bit(idx, state->active_inputs)) {
 220                DRM_DEBUG_ATOMIC("%s required %s-input[%d] has been occupied already.\n",
 221                                 input->component->name, c->name, idx);
 222                return -EINVAL;
 223        }
 224
 225        return 0;
 226}
 227
 228static void
 229komeda_component_set_output(struct komeda_component_output *output,
 230                            struct komeda_component *comp,
 231                            u8 output_port)
 232{
 233        output->component = comp;
 234        output->output_port = output_port;
 235}
 236
 237static int
 238komeda_component_validate_private(struct komeda_component *c,
 239                                  struct komeda_component_state *st)
 240{
 241        int err;
 242
 243        if (!c->funcs->validate)
 244                return 0;
 245
 246        err = c->funcs->validate(c, st);
 247        if (err)
 248                DRM_DEBUG_ATOMIC("%s validate private failed.\n", c->name);
 249
 250        return err;
 251}
 252
 253/* Get current available scaler from the component->supported_outputs */
 254static struct komeda_scaler *
 255komeda_component_get_avail_scaler(struct komeda_component *c,
 256                                  struct drm_atomic_state *state)
 257{
 258        struct komeda_pipeline_state *pipe_st;
 259        u32 avail_scalers;
 260
 261        pipe_st = komeda_pipeline_get_state(c->pipeline, state);
 262        if (!pipe_st)
 263                return NULL;
 264
 265        avail_scalers = (pipe_st->active_comps & KOMEDA_PIPELINE_SCALERS) ^
 266                        KOMEDA_PIPELINE_SCALERS;
 267
 268        c = komeda_component_pickup_output(c, avail_scalers);
 269
 270        return to_scaler(c);
 271}
 272
 273static void
 274komeda_rotate_data_flow(struct komeda_data_flow_cfg *dflow, u32 rot)
 275{
 276        if (drm_rotation_90_or_270(rot)) {
 277                swap(dflow->in_h, dflow->in_w);
 278                swap(dflow->total_in_h, dflow->total_in_w);
 279        }
 280}
 281
 282static int
 283komeda_layer_check_cfg(struct komeda_layer *layer,
 284                       struct komeda_fb *kfb,
 285                       struct komeda_data_flow_cfg *dflow)
 286{
 287        u32 src_x, src_y, src_w, src_h;
 288        u32 line_sz, max_line_sz;
 289
 290        if (!komeda_fb_is_layer_supported(kfb, layer->layer_type, dflow->rot))
 291                return -EINVAL;
 292
 293        if (layer->base.id == KOMEDA_COMPONENT_WB_LAYER) {
 294                src_x = dflow->out_x;
 295                src_y = dflow->out_y;
 296                src_w = dflow->out_w;
 297                src_h = dflow->out_h;
 298        } else {
 299                src_x = dflow->in_x;
 300                src_y = dflow->in_y;
 301                src_w = dflow->in_w;
 302                src_h = dflow->in_h;
 303        }
 304
 305        if (komeda_fb_check_src_coords(kfb, src_x, src_y, src_w, src_h))
 306                return -EINVAL;
 307
 308        if (!in_range(&layer->hsize_in, src_w)) {
 309                DRM_DEBUG_ATOMIC("invalidate src_w %d.\n", src_w);
 310                return -EINVAL;
 311        }
 312
 313        if (!in_range(&layer->vsize_in, src_h)) {
 314                DRM_DEBUG_ATOMIC("invalidate src_h %d.\n", src_h);
 315                return -EINVAL;
 316        }
 317
 318        if (drm_rotation_90_or_270(dflow->rot))
 319                line_sz = dflow->in_h;
 320        else
 321                line_sz = dflow->in_w;
 322
 323        if (kfb->base.format->hsub > 1)
 324                max_line_sz = layer->yuv_line_sz;
 325        else
 326                max_line_sz = layer->line_sz;
 327
 328        if (line_sz > max_line_sz) {
 329                DRM_DEBUG_ATOMIC("Required line_sz: %d exceeds the max size %d\n",
 330                                 line_sz, max_line_sz);
 331                return -EINVAL;
 332        }
 333
 334        return 0;
 335}
 336
 337static int
 338komeda_layer_validate(struct komeda_layer *layer,
 339                      struct komeda_plane_state *kplane_st,
 340                      struct komeda_data_flow_cfg *dflow)
 341{
 342        struct drm_plane_state *plane_st = &kplane_st->base;
 343        struct drm_framebuffer *fb = plane_st->fb;
 344        struct komeda_fb *kfb = to_kfb(fb);
 345        struct komeda_component_state *c_st;
 346        struct komeda_layer_state *st;
 347        int i, err;
 348
 349        err = komeda_layer_check_cfg(layer, kfb, dflow);
 350        if (err)
 351                return err;
 352
 353        c_st = komeda_component_get_state_and_set_user(&layer->base,
 354                        plane_st->state, plane_st->plane, plane_st->crtc);
 355        if (IS_ERR(c_st))
 356                return PTR_ERR(c_st);
 357
 358        st = to_layer_st(c_st);
 359
 360        st->rot = dflow->rot;
 361
 362        if (fb->modifier) {
 363                st->hsize = kfb->aligned_w;
 364                st->vsize = kfb->aligned_h;
 365                st->afbc_crop_l = dflow->in_x;
 366                st->afbc_crop_r = kfb->aligned_w - dflow->in_x - dflow->in_w;
 367                st->afbc_crop_t = dflow->in_y;
 368                st->afbc_crop_b = kfb->aligned_h - dflow->in_y - dflow->in_h;
 369        } else {
 370                st->hsize = dflow->in_w;
 371                st->vsize = dflow->in_h;
 372                st->afbc_crop_l = 0;
 373                st->afbc_crop_r = 0;
 374                st->afbc_crop_t = 0;
 375                st->afbc_crop_b = 0;
 376        }
 377
 378        for (i = 0; i < fb->format->num_planes; i++)
 379                st->addr[i] = komeda_fb_get_pixel_addr(kfb, dflow->in_x,
 380                                                       dflow->in_y, i);
 381
 382        err = komeda_component_validate_private(&layer->base, c_st);
 383        if (err)
 384                return err;
 385
 386        /* update the data flow for the next stage */
 387        komeda_component_set_output(&dflow->input, &layer->base, 0);
 388
 389        /*
 390         * The rotation has been handled by layer, so adjusted the data flow for
 391         * the next stage.
 392         */
 393        komeda_rotate_data_flow(dflow, st->rot);
 394
 395        return 0;
 396}
 397
 398static int
 399komeda_wb_layer_validate(struct komeda_layer *wb_layer,
 400                         struct drm_connector_state *conn_st,
 401                         struct komeda_data_flow_cfg *dflow)
 402{
 403        struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
 404        struct komeda_component_state *c_st;
 405        struct komeda_layer_state *st;
 406        int i, err;
 407
 408        err = komeda_layer_check_cfg(wb_layer, kfb, dflow);
 409        if (err)
 410                return err;
 411
 412        c_st = komeda_component_get_state_and_set_user(&wb_layer->base,
 413                        conn_st->state, conn_st->connector, conn_st->crtc);
 414        if (IS_ERR(c_st))
 415                return PTR_ERR(c_st);
 416
 417        st = to_layer_st(c_st);
 418
 419        st->hsize = dflow->out_w;
 420        st->vsize = dflow->out_h;
 421
 422        for (i = 0; i < kfb->base.format->num_planes; i++)
 423                st->addr[i] = komeda_fb_get_pixel_addr(kfb, dflow->out_x,
 424                                                       dflow->out_y, i);
 425
 426        komeda_component_add_input(&st->base, &dflow->input, 0);
 427        komeda_component_set_output(&dflow->input, &wb_layer->base, 0);
 428
 429        return 0;
 430}
 431
 432static bool scaling_ratio_valid(u32 size_in, u32 size_out,
 433                                u32 max_upscaling, u32 max_downscaling)
 434{
 435        if (size_out > size_in * max_upscaling)
 436                return false;
 437        else if (size_in > size_out * max_downscaling)
 438                return false;
 439        return true;
 440}
 441
 442static int
 443komeda_scaler_check_cfg(struct komeda_scaler *scaler,
 444                        struct komeda_crtc_state *kcrtc_st,
 445                        struct komeda_data_flow_cfg *dflow)
 446{
 447        u32 hsize_in, vsize_in, hsize_out, vsize_out;
 448        u32 max_upscaling;
 449
 450        hsize_in = dflow->in_w;
 451        vsize_in = dflow->in_h;
 452        hsize_out = dflow->out_w;
 453        vsize_out = dflow->out_h;
 454
 455        if (!in_range(&scaler->hsize, hsize_in) ||
 456            !in_range(&scaler->hsize, hsize_out)) {
 457                DRM_DEBUG_ATOMIC("Invalid horizontal sizes");
 458                return -EINVAL;
 459        }
 460
 461        if (!in_range(&scaler->vsize, vsize_in) ||
 462            !in_range(&scaler->vsize, vsize_out)) {
 463                DRM_DEBUG_ATOMIC("Invalid vertical sizes");
 464                return -EINVAL;
 465        }
 466
 467        /* If input comes from compiz that means the scaling is for writeback
 468         * and scaler can not do upscaling for writeback
 469         */
 470        if (has_bit(dflow->input.component->id, KOMEDA_PIPELINE_COMPIZS))
 471                max_upscaling = 1;
 472        else
 473                max_upscaling = scaler->max_upscaling;
 474
 475        if (!scaling_ratio_valid(hsize_in, hsize_out, max_upscaling,
 476                                 scaler->max_downscaling)) {
 477                DRM_DEBUG_ATOMIC("Invalid horizontal scaling ratio");
 478                return -EINVAL;
 479        }
 480
 481        if (!scaling_ratio_valid(vsize_in, vsize_out, max_upscaling,
 482                                 scaler->max_downscaling)) {
 483                DRM_DEBUG_ATOMIC("Invalid vertical scaling ratio");
 484                return -EINVAL;
 485        }
 486
 487        if (hsize_in > hsize_out || vsize_in > vsize_out) {
 488                struct komeda_pipeline *pipe = scaler->base.pipeline;
 489                int err;
 490
 491                err = pipe->funcs->downscaling_clk_check(pipe,
 492                                        &kcrtc_st->base.adjusted_mode,
 493                                        komeda_crtc_get_aclk(kcrtc_st), dflow);
 494                if (err) {
 495                        DRM_DEBUG_ATOMIC("aclk can't satisfy the clock requirement of the downscaling\n");
 496                        return err;
 497                }
 498        }
 499
 500        return 0;
 501}
 502
 503static int
 504komeda_scaler_validate(void *user,
 505                       struct komeda_crtc_state *kcrtc_st,
 506                       struct komeda_data_flow_cfg *dflow)
 507{
 508        struct drm_atomic_state *drm_st = kcrtc_st->base.state;
 509        struct komeda_component_state *c_st;
 510        struct komeda_scaler_state *st;
 511        struct komeda_scaler *scaler;
 512        int err = 0;
 513
 514        if (!(dflow->en_scaling || dflow->en_img_enhancement))
 515                return 0;
 516
 517        scaler = komeda_component_get_avail_scaler(dflow->input.component,
 518                                                   drm_st);
 519        if (!scaler) {
 520                DRM_DEBUG_ATOMIC("No scaler available");
 521                return -EINVAL;
 522        }
 523
 524        err = komeda_scaler_check_cfg(scaler, kcrtc_st, dflow);
 525        if (err)
 526                return err;
 527
 528        c_st = komeda_component_get_state_and_set_user(&scaler->base,
 529                        drm_st, user, kcrtc_st->base.crtc);
 530        if (IS_ERR(c_st))
 531                return PTR_ERR(c_st);
 532
 533        st = to_scaler_st(c_st);
 534
 535        st->hsize_in = dflow->in_w;
 536        st->vsize_in = dflow->in_h;
 537        st->hsize_out = dflow->out_w;
 538        st->vsize_out = dflow->out_h;
 539        st->right_crop = dflow->right_crop;
 540        st->left_crop = dflow->left_crop;
 541        st->total_vsize_in = dflow->total_in_h;
 542        st->total_hsize_in = dflow->total_in_w;
 543        st->total_hsize_out = dflow->total_out_w;
 544
 545        /* Enable alpha processing if the next stage needs the pixel alpha */
 546        st->en_alpha = dflow->pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE;
 547        st->en_scaling = dflow->en_scaling;
 548        st->en_img_enhancement = dflow->en_img_enhancement;
 549        st->en_split = dflow->en_split;
 550        st->right_part = dflow->right_part;
 551
 552        komeda_component_add_input(&st->base, &dflow->input, 0);
 553        komeda_component_set_output(&dflow->input, &scaler->base, 0);
 554        return err;
 555}
 556
 557static void komeda_split_data_flow(struct komeda_scaler *scaler,
 558                                   struct komeda_data_flow_cfg *dflow,
 559                                   struct komeda_data_flow_cfg *l_dflow,
 560                                   struct komeda_data_flow_cfg *r_dflow);
 561
 562static int
 563komeda_splitter_validate(struct komeda_splitter *splitter,
 564                         struct drm_connector_state *conn_st,
 565                         struct komeda_data_flow_cfg *dflow,
 566                         struct komeda_data_flow_cfg *l_output,
 567                         struct komeda_data_flow_cfg *r_output)
 568{
 569        struct komeda_component_state *c_st;
 570        struct komeda_splitter_state *st;
 571
 572        if (!splitter) {
 573                DRM_DEBUG_ATOMIC("Current HW doesn't support splitter.\n");
 574                return -EINVAL;
 575        }
 576
 577        if (!in_range(&splitter->hsize, dflow->in_w)) {
 578                DRM_DEBUG_ATOMIC("split in_w:%d is out of the acceptable range.\n",
 579                                 dflow->in_w);
 580                return -EINVAL;
 581        }
 582
 583        if (!in_range(&splitter->vsize, dflow->in_h)) {
 584                DRM_DEBUG_ATOMIC("split in_h: %d exceeds the acceptable range.\n",
 585                                 dflow->in_h);
 586                return -EINVAL;
 587        }
 588
 589        c_st = komeda_component_get_state_and_set_user(&splitter->base,
 590                        conn_st->state, conn_st->connector, conn_st->crtc);
 591
 592        if (IS_ERR(c_st))
 593                return PTR_ERR(c_st);
 594
 595        komeda_split_data_flow(splitter->base.pipeline->scalers[0],
 596                               dflow, l_output, r_output);
 597
 598        st = to_splitter_st(c_st);
 599        st->hsize = dflow->in_w;
 600        st->vsize = dflow->in_h;
 601        st->overlap = dflow->overlap;
 602
 603        komeda_component_add_input(&st->base, &dflow->input, 0);
 604        komeda_component_set_output(&l_output->input, &splitter->base, 0);
 605        komeda_component_set_output(&r_output->input, &splitter->base, 1);
 606
 607        return 0;
 608}
 609
 610static int
 611komeda_merger_validate(struct komeda_merger *merger,
 612                       void *user,
 613                       struct komeda_crtc_state *kcrtc_st,
 614                       struct komeda_data_flow_cfg *left_input,
 615                       struct komeda_data_flow_cfg *right_input,
 616                       struct komeda_data_flow_cfg *output)
 617{
 618        struct komeda_component_state *c_st;
 619        struct komeda_merger_state *st;
 620        int err = 0;
 621
 622        if (!merger) {
 623                DRM_DEBUG_ATOMIC("No merger is available");
 624                return -EINVAL;
 625        }
 626
 627        if (!in_range(&merger->hsize_merged, output->out_w)) {
 628                DRM_DEBUG_ATOMIC("merged_w: %d is out of the accepted range.\n",
 629                                 output->out_w);
 630                return -EINVAL;
 631        }
 632
 633        if (!in_range(&merger->vsize_merged, output->out_h)) {
 634                DRM_DEBUG_ATOMIC("merged_h: %d is out of the accepted range.\n",
 635                                 output->out_h);
 636                return -EINVAL;
 637        }
 638
 639        c_st = komeda_component_get_state_and_set_user(&merger->base,
 640                        kcrtc_st->base.state, kcrtc_st->base.crtc, kcrtc_st->base.crtc);
 641
 642        if (IS_ERR(c_st))
 643                return PTR_ERR(c_st);
 644
 645        st = to_merger_st(c_st);
 646        st->hsize_merged = output->out_w;
 647        st->vsize_merged = output->out_h;
 648
 649        komeda_component_add_input(c_st, &left_input->input, 0);
 650        komeda_component_add_input(c_st, &right_input->input, 1);
 651        komeda_component_set_output(&output->input, &merger->base, 0);
 652
 653        return err;
 654}
 655
 656void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
 657                               u16 *hsize, u16 *vsize)
 658{
 659        struct drm_display_mode *m = &kcrtc_st->base.adjusted_mode;
 660
 661        if (hsize)
 662                *hsize = m->hdisplay;
 663        if (vsize)
 664                *vsize = m->vdisplay;
 665}
 666
 667static int
 668komeda_compiz_set_input(struct komeda_compiz *compiz,
 669                        struct komeda_crtc_state *kcrtc_st,
 670                        struct komeda_data_flow_cfg *dflow)
 671{
 672        struct drm_atomic_state *drm_st = kcrtc_st->base.state;
 673        struct komeda_component_state *c_st, *old_st;
 674        struct komeda_compiz_input_cfg *cin;
 675        u16 compiz_w, compiz_h;
 676        int idx = dflow->blending_zorder;
 677
 678        pipeline_composition_size(kcrtc_st, &compiz_w, &compiz_h);
 679        /* check display rect */
 680        if ((dflow->out_x + dflow->out_w > compiz_w) ||
 681            (dflow->out_y + dflow->out_h > compiz_h) ||
 682             dflow->out_w == 0 || dflow->out_h == 0) {
 683                DRM_DEBUG_ATOMIC("invalid disp rect [x=%d, y=%d, w=%d, h=%d]\n",
 684                                 dflow->out_x, dflow->out_y,
 685                                 dflow->out_w, dflow->out_h);
 686                return -EINVAL;
 687        }
 688
 689        c_st = komeda_component_get_state_and_set_user(&compiz->base, drm_st,
 690                        kcrtc_st->base.crtc, kcrtc_st->base.crtc);
 691        if (IS_ERR(c_st))
 692                return PTR_ERR(c_st);
 693
 694        if (komeda_component_check_input(c_st, &dflow->input, idx))
 695                return -EINVAL;
 696
 697        cin = &(to_compiz_st(c_st)->cins[idx]);
 698
 699        cin->hsize   = dflow->out_w;
 700        cin->vsize   = dflow->out_h;
 701        cin->hoffset = dflow->out_x;
 702        cin->voffset = dflow->out_y;
 703        cin->pixel_blend_mode = dflow->pixel_blend_mode;
 704        cin->layer_alpha = dflow->layer_alpha;
 705
 706        old_st = komeda_component_get_old_state(&compiz->base, drm_st);
 707
 708        /* compare with old to check if this input has been changed */
 709        if (WARN_ON(!old_st) ||
 710            memcmp(&(to_compiz_st(old_st)->cins[idx]), cin, sizeof(*cin)))
 711                c_st->changed_active_inputs |= BIT(idx);
 712
 713        komeda_component_add_input(c_st, &dflow->input, idx);
 714        komeda_component_set_output(&dflow->input, &compiz->base, 0);
 715
 716        return 0;
 717}
 718
 719static int
 720komeda_compiz_validate(struct komeda_compiz *compiz,
 721                       struct komeda_crtc_state *state,
 722                       struct komeda_data_flow_cfg *dflow)
 723{
 724        struct komeda_component_state *c_st;
 725        struct komeda_compiz_state *st;
 726
 727        c_st = komeda_component_get_state_and_set_user(&compiz->base,
 728                        state->base.state, state->base.crtc, state->base.crtc);
 729        if (IS_ERR(c_st))
 730                return PTR_ERR(c_st);
 731
 732        st = to_compiz_st(c_st);
 733
 734        pipeline_composition_size(state, &st->hsize, &st->vsize);
 735
 736        komeda_component_set_output(&dflow->input, &compiz->base, 0);
 737
 738        /* compiz output dflow will be fed to the next pipeline stage, prepare
 739         * the data flow configuration for the next stage
 740         */
 741        if (dflow) {
 742                dflow->in_w = st->hsize;
 743                dflow->in_h = st->vsize;
 744                dflow->out_w = dflow->in_w;
 745                dflow->out_h = dflow->in_h;
 746                /* the output data of compiz doesn't have alpha, it only can be
 747                 * used as bottom layer when blend it with master layers
 748                 */
 749                dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
 750                dflow->layer_alpha = 0xFF;
 751                dflow->blending_zorder = 0;
 752        }
 753
 754        return 0;
 755}
 756
 757static int
 758komeda_improc_validate(struct komeda_improc *improc,
 759                       struct komeda_crtc_state *kcrtc_st,
 760                       struct komeda_data_flow_cfg *dflow)
 761{
 762        struct drm_crtc *crtc = kcrtc_st->base.crtc;
 763        struct drm_crtc_state *crtc_st = &kcrtc_st->base;
 764        struct komeda_component_state *c_st;
 765        struct komeda_improc_state *st;
 766
 767        c_st = komeda_component_get_state_and_set_user(&improc->base,
 768                        kcrtc_st->base.state, crtc, crtc);
 769        if (IS_ERR(c_st))
 770                return PTR_ERR(c_st);
 771
 772        st = to_improc_st(c_st);
 773
 774        st->hsize = dflow->in_w;
 775        st->vsize = dflow->in_h;
 776
 777        if (drm_atomic_crtc_needs_modeset(crtc_st)) {
 778                u32 output_depths, output_formats;
 779                u32 avail_depths, avail_formats;
 780
 781                komeda_crtc_get_color_config(crtc_st, &output_depths,
 782                                             &output_formats);
 783
 784                avail_depths = output_depths & improc->supported_color_depths;
 785                if (avail_depths == 0) {
 786                        DRM_DEBUG_ATOMIC("No available color depths, conn depths: 0x%x & display: 0x%x\n",
 787                                         output_depths,
 788                                         improc->supported_color_depths);
 789                        return -EINVAL;
 790                }
 791
 792                avail_formats = output_formats &
 793                                improc->supported_color_formats;
 794                if (!avail_formats) {
 795                        DRM_DEBUG_ATOMIC("No available color_formats, conn formats 0x%x & display: 0x%x\n",
 796                                         output_formats,
 797                                         improc->supported_color_formats);
 798                        return -EINVAL;
 799                }
 800
 801                st->color_depth = __fls(avail_depths);
 802                st->color_format = BIT(__ffs(avail_formats));
 803        }
 804
 805        if (kcrtc_st->base.color_mgmt_changed) {
 806                drm_lut_to_fgamma_coeffs(kcrtc_st->base.gamma_lut,
 807                                         st->fgamma_coeffs);
 808                drm_ctm_to_coeffs(kcrtc_st->base.ctm, st->ctm_coeffs);
 809        }
 810
 811        komeda_component_add_input(&st->base, &dflow->input, 0);
 812        komeda_component_set_output(&dflow->input, &improc->base, 0);
 813
 814        return 0;
 815}
 816
 817static int
 818komeda_timing_ctrlr_validate(struct komeda_timing_ctrlr *ctrlr,
 819                             struct komeda_crtc_state *kcrtc_st,
 820                             struct komeda_data_flow_cfg *dflow)
 821{
 822        struct drm_crtc *crtc = kcrtc_st->base.crtc;
 823        struct komeda_timing_ctrlr_state *st;
 824        struct komeda_component_state *c_st;
 825
 826        c_st = komeda_component_get_state_and_set_user(&ctrlr->base,
 827                        kcrtc_st->base.state, crtc, crtc);
 828        if (IS_ERR(c_st))
 829                return PTR_ERR(c_st);
 830
 831        st = to_ctrlr_st(c_st);
 832
 833        komeda_component_add_input(&st->base, &dflow->input, 0);
 834        komeda_component_set_output(&dflow->input, &ctrlr->base, 0);
 835
 836        return 0;
 837}
 838
 839void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
 840                                   struct komeda_data_flow_cfg *dflow,
 841                                   struct drm_framebuffer *fb)
 842{
 843        struct komeda_scaler *scaler = layer->base.pipeline->scalers[0];
 844        u32 w = dflow->in_w;
 845        u32 h = dflow->in_h;
 846
 847        dflow->total_in_w = dflow->in_w;
 848        dflow->total_in_h = dflow->in_h;
 849        dflow->total_out_w = dflow->out_w;
 850
 851        /* if format doesn't have alpha, fix blend mode to PIXEL_NONE */
 852        if (!fb->format->has_alpha)
 853                dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
 854
 855        if (drm_rotation_90_or_270(dflow->rot))
 856                swap(w, h);
 857
 858        dflow->en_scaling = (w != dflow->out_w) || (h != dflow->out_h);
 859        dflow->is_yuv = fb->format->is_yuv;
 860
 861        /* try to enable image enhancer if data flow is a 2x+ upscaling */
 862        dflow->en_img_enhancement = dflow->out_w >= 2 * w ||
 863                                    dflow->out_h >= 2 * h;
 864
 865        /* try to enable split if scaling exceed the scaler's acceptable
 866         * input/output range.
 867         */
 868        if (dflow->en_scaling && scaler)
 869                dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
 870                                  !in_range(&scaler->hsize, dflow->out_w);
 871}
 872
 873static bool merger_is_available(struct komeda_pipeline *pipe,
 874                                struct komeda_data_flow_cfg *dflow)
 875{
 876        u32 avail_inputs = pipe->merger ?
 877                           pipe->merger->base.supported_inputs : 0;
 878
 879        return has_bit(dflow->input.component->id, avail_inputs);
 880}
 881
 882int komeda_build_layer_data_flow(struct komeda_layer *layer,
 883                                 struct komeda_plane_state *kplane_st,
 884                                 struct komeda_crtc_state *kcrtc_st,
 885                                 struct komeda_data_flow_cfg *dflow)
 886{
 887        struct drm_plane *plane = kplane_st->base.plane;
 888        struct komeda_pipeline *pipe = layer->base.pipeline;
 889        int err;
 890
 891        DRM_DEBUG_ATOMIC("%s handling [PLANE:%d:%s]: src[x/y:%d/%d, w/h:%d/%d] disp[x/y:%d/%d, w/h:%d/%d]",
 892                         layer->base.name, plane->base.id, plane->name,
 893                         dflow->in_x, dflow->in_y, dflow->in_w, dflow->in_h,
 894                         dflow->out_x, dflow->out_y, dflow->out_w, dflow->out_h);
 895
 896        err = komeda_layer_validate(layer, kplane_st, dflow);
 897        if (err)
 898                return err;
 899
 900        err = komeda_scaler_validate(plane, kcrtc_st, dflow);
 901        if (err)
 902                return err;
 903
 904        /* if split, check if can put the data flow into merger */
 905        if (dflow->en_split && merger_is_available(pipe, dflow))
 906                return 0;
 907
 908        err = komeda_compiz_set_input(pipe->compiz, kcrtc_st, dflow);
 909
 910        return err;
 911}
 912
 913/*
 914 * Split is introduced for workaround scaler's input/output size limitation.
 915 * The idea is simple, if one scaler can not fit the requirement, use two.
 916 * So split splits the big source image to two half parts (left/right) and do
 917 * the scaling by two scaler separately and independently.
 918 * But split also imports an edge problem in the middle of the image when
 919 * scaling, to avoid it, split isn't a simple half-and-half, but add an extra
 920 * pixels (overlap) to both side, after split the left/right will be:
 921 * - left: [0, src_length/2 + overlap]
 922 * - right: [src_length/2 - overlap, src_length]
 923 * The extra overlap do eliminate the edge problem, but which may also generates
 924 * unnecessary pixels when scaling, we need to crop them before scaler output
 925 * the result to the next stage. and for the how to crop, it depends on the
 926 * unneeded pixels, another words the position where overlay has been added.
 927 * - left: crop the right
 928 * - right: crop the left
 929 *
 930 * The diagram for how to do the split
 931 *
 932 *  <---------------------left->out_w ---------------->
 933 * |--------------------------------|---right_crop-----| <- left after split
 934 *  \                                \                /
 935 *   \                                \<--overlap--->/
 936 *   |-----------------|-------------|(Middle)------|-----------------| <- src
 937 *                     /<---overlap--->\                               \
 938 *                    /                 \                               \
 939 * right after split->|-----left_crop---|--------------------------------|
 940 *                    ^<------------------- right->out_w --------------->^
 941 *
 942 * NOTE: To consistent with HW the output_w always contains the crop size.
 943 */
 944
 945static void komeda_split_data_flow(struct komeda_scaler *scaler,
 946                                   struct komeda_data_flow_cfg *dflow,
 947                                   struct komeda_data_flow_cfg *l_dflow,
 948                                   struct komeda_data_flow_cfg *r_dflow)
 949{
 950        bool r90 = drm_rotation_90_or_270(dflow->rot);
 951        bool flip_h = has_flip_h(dflow->rot);
 952        u32 l_out, r_out, overlap;
 953
 954        memcpy(l_dflow, dflow, sizeof(*dflow));
 955        memcpy(r_dflow, dflow, sizeof(*dflow));
 956
 957        l_dflow->right_part = false;
 958        r_dflow->right_part = true;
 959        r_dflow->blending_zorder = dflow->blending_zorder + 1;
 960
 961        overlap = 0;
 962        if (dflow->en_scaling && scaler)
 963                overlap += scaler->scaling_split_overlap;
 964
 965        /* original dflow may fed into splitter, and which doesn't need
 966         * enhancement overlap
 967         */
 968        dflow->overlap = overlap;
 969
 970        if (dflow->en_img_enhancement && scaler)
 971                overlap += scaler->enh_split_overlap;
 972
 973        l_dflow->overlap = overlap;
 974        r_dflow->overlap = overlap;
 975
 976        /* split the origin content */
 977        /* left/right here always means the left/right part of display image,
 978         * not the source Image
 979         */
 980        /* DRM rotation is anti-clockwise */
 981        if (r90) {
 982                if (dflow->en_scaling) {
 983                        l_dflow->in_h = ALIGN(dflow->in_h, 2) / 2 + l_dflow->overlap;
 984                        r_dflow->in_h = l_dflow->in_h;
 985                } else if (dflow->en_img_enhancement) {
 986                        /* enhancer only */
 987                        l_dflow->in_h = ALIGN(dflow->in_h, 2) / 2 + l_dflow->overlap;
 988                        r_dflow->in_h = dflow->in_h / 2 + r_dflow->overlap;
 989                } else {
 990                        /* split without scaler, no overlap */
 991                        l_dflow->in_h = ALIGN(((dflow->in_h + 1) >> 1), 2);
 992                        r_dflow->in_h = dflow->in_h - l_dflow->in_h;
 993                }
 994
 995                /* Consider YUV format, after split, the split source w/h
 996                 * may not aligned to 2. we have two choices for such case.
 997                 * 1. scaler is enabled (overlap != 0), we can do a alignment
 998                 *    both left/right and crop the extra data by scaler.
 999                 * 2. scaler is not enabled, only align the split left
1000                 *    src/disp, and the rest part assign to right
1001                 */
1002                if ((overlap != 0) && dflow->is_yuv) {
1003                        l_dflow->in_h = ALIGN(l_dflow->in_h, 2);
1004                        r_dflow->in_h = ALIGN(r_dflow->in_h, 2);
1005                }
1006
1007                if (flip_h)
1008                        l_dflow->in_y = dflow->in_y + dflow->in_h - l_dflow->in_h;
1009                else
1010                        r_dflow->in_y = dflow->in_y + dflow->in_h - r_dflow->in_h;
1011        } else {
1012                if (dflow->en_scaling) {
1013                        l_dflow->in_w = ALIGN(dflow->in_w, 2) / 2 + l_dflow->overlap;
1014                        r_dflow->in_w = l_dflow->in_w;
1015                } else if (dflow->en_img_enhancement) {
1016                        l_dflow->in_w = ALIGN(dflow->in_w, 2) / 2 + l_dflow->overlap;
1017                        r_dflow->in_w = dflow->in_w / 2 + r_dflow->overlap;
1018                } else {
1019                        l_dflow->in_w = ALIGN(((dflow->in_w + 1) >> 1), 2);
1020                        r_dflow->in_w = dflow->in_w - l_dflow->in_w;
1021                }
1022
1023                /* do YUV alignment when scaler enabled */
1024                if ((overlap != 0) && dflow->is_yuv) {
1025                        l_dflow->in_w = ALIGN(l_dflow->in_w, 2);
1026                        r_dflow->in_w = ALIGN(r_dflow->in_w, 2);
1027                }
1028
1029                /* on flip_h, the left display content from the right-source */
1030                if (flip_h)
1031                        l_dflow->in_x = dflow->in_w + dflow->in_x - l_dflow->in_w;
1032                else
1033                        r_dflow->in_x = dflow->in_w + dflow->in_x - r_dflow->in_w;
1034        }
1035
1036        /* split the disp_rect */
1037        if (dflow->en_scaling || dflow->en_img_enhancement)
1038                l_dflow->out_w = ((dflow->out_w + 1) >> 1);
1039        else
1040                l_dflow->out_w = ALIGN(((dflow->out_w + 1) >> 1), 2);
1041
1042        r_dflow->out_w = dflow->out_w - l_dflow->out_w;
1043
1044        l_dflow->out_x = dflow->out_x;
1045        r_dflow->out_x = l_dflow->out_w + l_dflow->out_x;
1046
1047        /* calculate the scaling crop */
1048        /* left scaler output more data and do crop */
1049        if (r90) {
1050                l_out = (dflow->out_w * l_dflow->in_h) / dflow->in_h;
1051                r_out = (dflow->out_w * r_dflow->in_h) / dflow->in_h;
1052        } else {
1053                l_out = (dflow->out_w * l_dflow->in_w) / dflow->in_w;
1054                r_out = (dflow->out_w * r_dflow->in_w) / dflow->in_w;
1055        }
1056
1057        l_dflow->left_crop  = 0;
1058        l_dflow->right_crop = l_out - l_dflow->out_w;
1059        r_dflow->left_crop  = r_out - r_dflow->out_w;
1060        r_dflow->right_crop = 0;
1061
1062        /* out_w includes the crop length */
1063        l_dflow->out_w += l_dflow->right_crop + l_dflow->left_crop;
1064        r_dflow->out_w += r_dflow->right_crop + r_dflow->left_crop;
1065}
1066
1067/* For layer split, a plane state will be split to two data flows and handled
1068 * by two separated komeda layer input pipelines. komeda supports two types of
1069 * layer split:
1070 * - none-scaling split:
1071 *             / layer-left -> \
1072 * plane_state                  compiz-> ...
1073 *             \ layer-right-> /
1074 *
1075 * - scaling split:
1076 *             / layer-left -> scaler->\
1077 * plane_state                          merger -> compiz-> ...
1078 *             \ layer-right-> scaler->/
1079 *
1080 * Since merger only supports scaler as input, so for none-scaling split, two
1081 * layer data flows will be output to compiz directly. for scaling_split, two
1082 * data flow will be merged by merger firstly, then merger outputs one merged
1083 * data flow to compiz.
1084 */
1085int komeda_build_layer_split_data_flow(struct komeda_layer *left,
1086                                       struct komeda_plane_state *kplane_st,
1087                                       struct komeda_crtc_state *kcrtc_st,
1088                                       struct komeda_data_flow_cfg *dflow)
1089{
1090        struct drm_plane *plane = kplane_st->base.plane;
1091        struct komeda_pipeline *pipe = left->base.pipeline;
1092        struct komeda_layer *right = left->right;
1093        struct komeda_data_flow_cfg l_dflow, r_dflow;
1094        int err;
1095
1096        komeda_split_data_flow(pipe->scalers[0], dflow, &l_dflow, &r_dflow);
1097
1098        DRM_DEBUG_ATOMIC("Assign %s + %s to [PLANE:%d:%s]: "
1099                         "src[x/y:%d/%d, w/h:%d/%d] disp[x/y:%d/%d, w/h:%d/%d]",
1100                         left->base.name, right->base.name,
1101                         plane->base.id, plane->name,
1102                         dflow->in_x, dflow->in_y, dflow->in_w, dflow->in_h,
1103                         dflow->out_x, dflow->out_y, dflow->out_w, dflow->out_h);
1104
1105        err = komeda_build_layer_data_flow(left, kplane_st, kcrtc_st, &l_dflow);
1106        if (err)
1107                return err;
1108
1109        err = komeda_build_layer_data_flow(right, kplane_st, kcrtc_st, &r_dflow);
1110        if (err)
1111                return err;
1112
1113        /* The rotation has been handled by layer, so adjusted the data flow */
1114        komeda_rotate_data_flow(dflow, dflow->rot);
1115
1116        /* left and right dflow has been merged to compiz already,
1117         * no need merger to merge them anymore.
1118         */
1119        if (r_dflow.input.component == l_dflow.input.component)
1120                return 0;
1121
1122        /* line merger path */
1123        err = komeda_merger_validate(pipe->merger, plane, kcrtc_st,
1124                                     &l_dflow, &r_dflow, dflow);
1125        if (err)
1126                return err;
1127
1128        err = komeda_compiz_set_input(pipe->compiz, kcrtc_st, dflow);
1129
1130        return err;
1131}
1132
1133/* writeback data path: compiz -> scaler -> wb_layer -> memory */
1134int komeda_build_wb_data_flow(struct komeda_layer *wb_layer,
1135                              struct drm_connector_state *conn_st,
1136                              struct komeda_crtc_state *kcrtc_st,
1137                              struct komeda_data_flow_cfg *dflow)
1138{
1139        struct drm_connector *conn = conn_st->connector;
1140        int err;
1141
1142        err = komeda_scaler_validate(conn, kcrtc_st, dflow);
1143        if (err)
1144                return err;
1145
1146        return komeda_wb_layer_validate(wb_layer, conn_st, dflow);
1147}
1148
1149/* writeback scaling split data path:
1150 *                   /-> scaler ->\
1151 * compiz -> splitter              merger -> wb_layer -> memory
1152 *                   \-> scaler ->/
1153 */
1154int komeda_build_wb_split_data_flow(struct komeda_layer *wb_layer,
1155                                    struct drm_connector_state *conn_st,
1156                                    struct komeda_crtc_state *kcrtc_st,
1157                                    struct komeda_data_flow_cfg *dflow)
1158{
1159        struct komeda_pipeline *pipe = wb_layer->base.pipeline;
1160        struct drm_connector *conn = conn_st->connector;
1161        struct komeda_data_flow_cfg l_dflow, r_dflow;
1162        int err;
1163
1164        err = komeda_splitter_validate(pipe->splitter, conn_st,
1165                                       dflow, &l_dflow, &r_dflow);
1166        if (err)
1167                return err;
1168        err = komeda_scaler_validate(conn, kcrtc_st, &l_dflow);
1169        if (err)
1170                return err;
1171
1172        err = komeda_scaler_validate(conn, kcrtc_st, &r_dflow);
1173        if (err)
1174                return err;
1175
1176        err = komeda_merger_validate(pipe->merger, conn_st, kcrtc_st,
1177                                     &l_dflow, &r_dflow, dflow);
1178        if (err)
1179                return err;
1180
1181        return komeda_wb_layer_validate(wb_layer, conn_st, dflow);
1182}
1183
1184/* build display output data flow, the data path is:
1185 * compiz -> improc -> timing_ctrlr
1186 */
1187int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
1188                                   struct komeda_crtc_state *kcrtc_st)
1189{
1190        struct komeda_pipeline *master = kcrtc->master;
1191        struct komeda_pipeline *slave  = kcrtc->slave;
1192        struct komeda_data_flow_cfg m_dflow; /* master data flow */
1193        struct komeda_data_flow_cfg s_dflow; /* slave data flow */
1194        int err;
1195
1196        memset(&m_dflow, 0, sizeof(m_dflow));
1197        memset(&s_dflow, 0, sizeof(s_dflow));
1198
1199        if (slave && has_bit(slave->id, kcrtc_st->active_pipes)) {
1200                err = komeda_compiz_validate(slave->compiz, kcrtc_st, &s_dflow);
1201                if (err)
1202                        return err;
1203
1204                /* merge the slave dflow into master pipeline */
1205                err = komeda_compiz_set_input(master->compiz, kcrtc_st,
1206                                              &s_dflow);
1207                if (err)
1208                        return err;
1209        }
1210
1211        err = komeda_compiz_validate(master->compiz, kcrtc_st, &m_dflow);
1212        if (err)
1213                return err;
1214
1215        err = komeda_improc_validate(master->improc, kcrtc_st, &m_dflow);
1216        if (err)
1217                return err;
1218
1219        err = komeda_timing_ctrlr_validate(master->ctrlr, kcrtc_st, &m_dflow);
1220        if (err)
1221                return err;
1222
1223        return 0;
1224}
1225
1226static void
1227komeda_pipeline_unbound_components(struct komeda_pipeline *pipe,
1228                                   struct komeda_pipeline_state *new)
1229{
1230        struct drm_atomic_state *drm_st = new->obj.state;
1231        struct komeda_pipeline_state *old = priv_to_pipe_st(pipe->obj.state);
1232        struct komeda_component_state *c_st;
1233        struct komeda_component *c;
1234        u32 id;
1235        unsigned long disabling_comps;
1236
1237        WARN_ON(!old);
1238
1239        disabling_comps = (~new->active_comps) & old->active_comps;
1240
1241        /* unbound all disabling component */
1242        for_each_set_bit(id, &disabling_comps, 32) {
1243                c = komeda_pipeline_get_component(pipe, id);
1244                c_st = komeda_component_get_state_and_set_user(c,
1245                                drm_st, NULL, new->crtc);
1246                WARN_ON(IS_ERR(c_st));
1247        }
1248}
1249
1250/* release unclaimed pipeline resource */
1251int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe,
1252                                       struct komeda_crtc_state *kcrtc_st)
1253{
1254        struct drm_atomic_state *drm_st = kcrtc_st->base.state;
1255        struct komeda_pipeline_state *st;
1256
1257        /* ignore the pipeline which is not affected */
1258        if (!pipe || !has_bit(pipe->id, kcrtc_st->affected_pipes))
1259                return 0;
1260
1261        if (has_bit(pipe->id, kcrtc_st->active_pipes))
1262                st = komeda_pipeline_get_new_state(pipe, drm_st);
1263        else
1264                st = komeda_pipeline_get_state_and_set_crtc(pipe, drm_st, NULL);
1265
1266        if (WARN_ON(IS_ERR_OR_NULL(st)))
1267                return -EINVAL;
1268
1269        komeda_pipeline_unbound_components(pipe, st);
1270
1271        return 0;
1272}
1273
1274/* Since standalong disabled components must be disabled separately and in the
1275 * last, So a complete disable operation may needs to call pipeline_disable
1276 * twice (two phase disabling).
1277 * Phase 1: disable the common components, flush it.
1278 * Phase 2: disable the standalone disabled components, flush it.
1279 *
1280 * RETURNS:
1281 * true: disable is not complete, needs a phase 2 disable.
1282 * false: disable is complete.
1283 */
1284bool komeda_pipeline_disable(struct komeda_pipeline *pipe,
1285                             struct drm_atomic_state *old_state)
1286{
1287        struct komeda_pipeline_state *old;
1288        struct komeda_component *c;
1289        struct komeda_component_state *c_st;
1290        u32 id;
1291        unsigned long disabling_comps;
1292
1293        old = komeda_pipeline_get_old_state(pipe, old_state);
1294
1295        disabling_comps = old->active_comps &
1296                          (~pipe->standalone_disabled_comps);
1297        if (!disabling_comps)
1298                disabling_comps = old->active_comps &
1299                                  pipe->standalone_disabled_comps;
1300
1301        DRM_DEBUG_ATOMIC("PIPE%d: active_comps: 0x%x, disabling_comps: 0x%lx.\n",
1302                         pipe->id, old->active_comps, disabling_comps);
1303
1304        for_each_set_bit(id, &disabling_comps, 32) {
1305                c = komeda_pipeline_get_component(pipe, id);
1306                c_st = priv_to_comp_st(c->obj.state);
1307
1308                /*
1309                 * If we disabled a component then all active_inputs should be
1310                 * put in the list of changed_active_inputs, so they get
1311                 * re-enabled.
1312                 * This usually happens during a modeset when the pipeline is
1313                 * first disabled and then the actual state gets committed
1314                 * again.
1315                 */
1316                c_st->changed_active_inputs |= c_st->active_inputs;
1317
1318                c->funcs->disable(c);
1319        }
1320
1321        /* Update the pipeline state, if there are components that are still
1322         * active, return true for calling the phase 2 disable.
1323         */
1324        old->active_comps &= ~disabling_comps;
1325
1326        return old->active_comps ? true : false;
1327}
1328
1329void komeda_pipeline_update(struct komeda_pipeline *pipe,
1330                            struct drm_atomic_state *old_state)
1331{
1332        struct komeda_pipeline_state *new = priv_to_pipe_st(pipe->obj.state);
1333        struct komeda_pipeline_state *old;
1334        struct komeda_component *c;
1335        u32 id;
1336        unsigned long changed_comps;
1337
1338        old = komeda_pipeline_get_old_state(pipe, old_state);
1339
1340        changed_comps = new->active_comps | old->active_comps;
1341
1342        DRM_DEBUG_ATOMIC("PIPE%d: active_comps: 0x%x, changed: 0x%lx.\n",
1343                         pipe->id, new->active_comps, changed_comps);
1344
1345        for_each_set_bit(id, &changed_comps, 32) {
1346                c = komeda_pipeline_get_component(pipe, id);
1347
1348                if (new->active_comps & BIT(c->id))
1349                        c->funcs->update(c, priv_to_comp_st(c->obj.state));
1350                else
1351                        c->funcs->disable(c);
1352        }
1353}
1354