0001
0002
0003
0004
0005
0006
0007
0008 #include <drm/drm_print.h>
0009 #include <linux/clk.h>
0010 #include "komeda_dev.h"
0011 #include "komeda_kms.h"
0012 #include "komeda_pipeline.h"
0013 #include "komeda_framebuffer.h"
0014
0015 static inline bool is_switching_user(void *old, void *new)
0016 {
0017 if (!old || !new)
0018 return false;
0019
0020 return old != new;
0021 }
0022
0023 static struct komeda_pipeline_state *
0024 komeda_pipeline_get_state(struct komeda_pipeline *pipe,
0025 struct drm_atomic_state *state)
0026 {
0027 struct drm_private_state *priv_st;
0028
0029 priv_st = drm_atomic_get_private_obj_state(state, &pipe->obj);
0030 if (IS_ERR(priv_st))
0031 return ERR_CAST(priv_st);
0032
0033 return priv_to_pipe_st(priv_st);
0034 }
0035
0036 struct komeda_pipeline_state *
0037 komeda_pipeline_get_old_state(struct komeda_pipeline *pipe,
0038 struct drm_atomic_state *state)
0039 {
0040 struct drm_private_state *priv_st;
0041
0042 priv_st = drm_atomic_get_old_private_obj_state(state, &pipe->obj);
0043 if (priv_st)
0044 return priv_to_pipe_st(priv_st);
0045 return NULL;
0046 }
0047
0048 static struct komeda_pipeline_state *
0049 komeda_pipeline_get_new_state(struct komeda_pipeline *pipe,
0050 struct drm_atomic_state *state)
0051 {
0052 struct drm_private_state *priv_st;
0053
0054 priv_st = drm_atomic_get_new_private_obj_state(state, &pipe->obj);
0055 if (priv_st)
0056 return priv_to_pipe_st(priv_st);
0057 return NULL;
0058 }
0059
0060
0061 static struct komeda_pipeline_state *
0062 komeda_pipeline_get_state_and_set_crtc(struct komeda_pipeline *pipe,
0063 struct drm_atomic_state *state,
0064 struct drm_crtc *crtc)
0065 {
0066 struct komeda_pipeline_state *st;
0067
0068 st = komeda_pipeline_get_state(pipe, state);
0069 if (IS_ERR(st))
0070 return st;
0071
0072 if (is_switching_user(crtc, st->crtc)) {
0073 DRM_DEBUG_ATOMIC("CRTC%d required pipeline%d is busy.\n",
0074 drm_crtc_index(crtc), pipe->id);
0075 return ERR_PTR(-EBUSY);
0076 }
0077
0078
0079 if (!crtc && st->active_comps) {
0080 DRM_DEBUG_ATOMIC("Disabling a busy pipeline:%d.\n", pipe->id);
0081 return ERR_PTR(-EBUSY);
0082 }
0083
0084 st->crtc = crtc;
0085
0086 if (crtc) {
0087 struct komeda_crtc_state *kcrtc_st;
0088
0089 kcrtc_st = to_kcrtc_st(drm_atomic_get_new_crtc_state(state,
0090 crtc));
0091
0092 kcrtc_st->active_pipes |= BIT(pipe->id);
0093 kcrtc_st->affected_pipes |= BIT(pipe->id);
0094 }
0095 return st;
0096 }
0097
0098 static struct komeda_component_state *
0099 komeda_component_get_state(struct komeda_component *c,
0100 struct drm_atomic_state *state)
0101 {
0102 struct drm_private_state *priv_st;
0103
0104 WARN_ON(!drm_modeset_is_locked(&c->pipeline->obj.lock));
0105
0106 priv_st = drm_atomic_get_private_obj_state(state, &c->obj);
0107 if (IS_ERR(priv_st))
0108 return ERR_CAST(priv_st);
0109
0110 return priv_to_comp_st(priv_st);
0111 }
0112
0113 static struct komeda_component_state *
0114 komeda_component_get_old_state(struct komeda_component *c,
0115 struct drm_atomic_state *state)
0116 {
0117 struct drm_private_state *priv_st;
0118
0119 priv_st = drm_atomic_get_old_private_obj_state(state, &c->obj);
0120 if (priv_st)
0121 return priv_to_comp_st(priv_st);
0122 return NULL;
0123 }
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 static struct komeda_component_state *
0151 komeda_component_get_state_and_set_user(struct komeda_component *c,
0152 struct drm_atomic_state *state,
0153 void *user,
0154 struct drm_crtc *crtc)
0155 {
0156 struct komeda_pipeline_state *pipe_st;
0157 struct komeda_component_state *st;
0158
0159
0160 pipe_st = komeda_pipeline_get_state_and_set_crtc(c->pipeline,
0161 state, crtc);
0162 if (IS_ERR(pipe_st))
0163 return ERR_CAST(pipe_st);
0164
0165 st = komeda_component_get_state(c, state);
0166 if (IS_ERR(st))
0167 return st;
0168
0169
0170 if (is_switching_user(user, st->binding_user)) {
0171 DRM_DEBUG_ATOMIC("required %s is busy.\n", c->name);
0172 return ERR_PTR(-EBUSY);
0173 }
0174
0175 st->binding_user = user;
0176
0177 if (st->binding_user)
0178 pipe_st->active_comps |= BIT(c->id);
0179
0180 return st;
0181 }
0182
0183 static void
0184 komeda_component_add_input(struct komeda_component_state *state,
0185 struct komeda_component_output *input,
0186 int idx)
0187 {
0188 struct komeda_component *c = state->component;
0189
0190 WARN_ON((idx < 0 || idx >= c->max_active_inputs));
0191
0192
0193
0194
0195
0196
0197 if (!has_bit(idx, state->affected_inputs) ||
0198 memcmp(&state->inputs[idx], input, sizeof(*input))) {
0199 memcpy(&state->inputs[idx], input, sizeof(*input));
0200 state->changed_active_inputs |= BIT(idx);
0201 }
0202 state->active_inputs |= BIT(idx);
0203 state->affected_inputs |= BIT(idx);
0204 }
0205
0206 static int
0207 komeda_component_check_input(struct komeda_component_state *state,
0208 struct komeda_component_output *input,
0209 int idx)
0210 {
0211 struct komeda_component *c = state->component;
0212
0213 if ((idx < 0) || (idx >= c->max_active_inputs)) {
0214 DRM_DEBUG_ATOMIC("%s required an invalid %s-input[%d].\n",
0215 input->component->name, c->name, idx);
0216 return -EINVAL;
0217 }
0218
0219 if (has_bit(idx, state->active_inputs)) {
0220 DRM_DEBUG_ATOMIC("%s required %s-input[%d] has been occupied already.\n",
0221 input->component->name, c->name, idx);
0222 return -EINVAL;
0223 }
0224
0225 return 0;
0226 }
0227
0228 static void
0229 komeda_component_set_output(struct komeda_component_output *output,
0230 struct komeda_component *comp,
0231 u8 output_port)
0232 {
0233 output->component = comp;
0234 output->output_port = output_port;
0235 }
0236
0237 static int
0238 komeda_component_validate_private(struct komeda_component *c,
0239 struct komeda_component_state *st)
0240 {
0241 int err;
0242
0243 if (!c->funcs->validate)
0244 return 0;
0245
0246 err = c->funcs->validate(c, st);
0247 if (err)
0248 DRM_DEBUG_ATOMIC("%s validate private failed.\n", c->name);
0249
0250 return err;
0251 }
0252
0253
0254 static struct komeda_scaler *
0255 komeda_component_get_avail_scaler(struct komeda_component *c,
0256 struct drm_atomic_state *state)
0257 {
0258 struct komeda_pipeline_state *pipe_st;
0259 u32 avail_scalers;
0260
0261 pipe_st = komeda_pipeline_get_state(c->pipeline, state);
0262 if (!pipe_st)
0263 return NULL;
0264
0265 avail_scalers = (pipe_st->active_comps & KOMEDA_PIPELINE_SCALERS) ^
0266 KOMEDA_PIPELINE_SCALERS;
0267
0268 c = komeda_component_pickup_output(c, avail_scalers);
0269
0270 return to_scaler(c);
0271 }
0272
0273 static void
0274 komeda_rotate_data_flow(struct komeda_data_flow_cfg *dflow, u32 rot)
0275 {
0276 if (drm_rotation_90_or_270(rot)) {
0277 swap(dflow->in_h, dflow->in_w);
0278 swap(dflow->total_in_h, dflow->total_in_w);
0279 }
0280 }
0281
0282 static int
0283 komeda_layer_check_cfg(struct komeda_layer *layer,
0284 struct komeda_fb *kfb,
0285 struct komeda_data_flow_cfg *dflow)
0286 {
0287 u32 src_x, src_y, src_w, src_h;
0288 u32 line_sz, max_line_sz;
0289
0290 if (!komeda_fb_is_layer_supported(kfb, layer->layer_type, dflow->rot))
0291 return -EINVAL;
0292
0293 if (layer->base.id == KOMEDA_COMPONENT_WB_LAYER) {
0294 src_x = dflow->out_x;
0295 src_y = dflow->out_y;
0296 src_w = dflow->out_w;
0297 src_h = dflow->out_h;
0298 } else {
0299 src_x = dflow->in_x;
0300 src_y = dflow->in_y;
0301 src_w = dflow->in_w;
0302 src_h = dflow->in_h;
0303 }
0304
0305 if (komeda_fb_check_src_coords(kfb, src_x, src_y, src_w, src_h))
0306 return -EINVAL;
0307
0308 if (!in_range(&layer->hsize_in, src_w)) {
0309 DRM_DEBUG_ATOMIC("invalidate src_w %d.\n", src_w);
0310 return -EINVAL;
0311 }
0312
0313 if (!in_range(&layer->vsize_in, src_h)) {
0314 DRM_DEBUG_ATOMIC("invalidate src_h %d.\n", src_h);
0315 return -EINVAL;
0316 }
0317
0318 if (drm_rotation_90_or_270(dflow->rot))
0319 line_sz = dflow->in_h;
0320 else
0321 line_sz = dflow->in_w;
0322
0323 if (kfb->base.format->hsub > 1)
0324 max_line_sz = layer->yuv_line_sz;
0325 else
0326 max_line_sz = layer->line_sz;
0327
0328 if (line_sz > max_line_sz) {
0329 DRM_DEBUG_ATOMIC("Required line_sz: %d exceeds the max size %d\n",
0330 line_sz, max_line_sz);
0331 return -EINVAL;
0332 }
0333
0334 return 0;
0335 }
0336
0337 static int
0338 komeda_layer_validate(struct komeda_layer *layer,
0339 struct komeda_plane_state *kplane_st,
0340 struct komeda_data_flow_cfg *dflow)
0341 {
0342 struct drm_plane_state *plane_st = &kplane_st->base;
0343 struct drm_framebuffer *fb = plane_st->fb;
0344 struct komeda_fb *kfb = to_kfb(fb);
0345 struct komeda_component_state *c_st;
0346 struct komeda_layer_state *st;
0347 int i, err;
0348
0349 err = komeda_layer_check_cfg(layer, kfb, dflow);
0350 if (err)
0351 return err;
0352
0353 c_st = komeda_component_get_state_and_set_user(&layer->base,
0354 plane_st->state, plane_st->plane, plane_st->crtc);
0355 if (IS_ERR(c_st))
0356 return PTR_ERR(c_st);
0357
0358 st = to_layer_st(c_st);
0359
0360 st->rot = dflow->rot;
0361
0362 if (fb->modifier) {
0363 st->hsize = kfb->aligned_w;
0364 st->vsize = kfb->aligned_h;
0365 st->afbc_crop_l = dflow->in_x;
0366 st->afbc_crop_r = kfb->aligned_w - dflow->in_x - dflow->in_w;
0367 st->afbc_crop_t = dflow->in_y;
0368 st->afbc_crop_b = kfb->aligned_h - dflow->in_y - dflow->in_h;
0369 } else {
0370 st->hsize = dflow->in_w;
0371 st->vsize = dflow->in_h;
0372 st->afbc_crop_l = 0;
0373 st->afbc_crop_r = 0;
0374 st->afbc_crop_t = 0;
0375 st->afbc_crop_b = 0;
0376 }
0377
0378 for (i = 0; i < fb->format->num_planes; i++)
0379 st->addr[i] = komeda_fb_get_pixel_addr(kfb, dflow->in_x,
0380 dflow->in_y, i);
0381
0382 err = komeda_component_validate_private(&layer->base, c_st);
0383 if (err)
0384 return err;
0385
0386
0387 komeda_component_set_output(&dflow->input, &layer->base, 0);
0388
0389
0390
0391
0392
0393 komeda_rotate_data_flow(dflow, st->rot);
0394
0395 return 0;
0396 }
0397
0398 static int
0399 komeda_wb_layer_validate(struct komeda_layer *wb_layer,
0400 struct drm_connector_state *conn_st,
0401 struct komeda_data_flow_cfg *dflow)
0402 {
0403 struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
0404 struct komeda_component_state *c_st;
0405 struct komeda_layer_state *st;
0406 int i, err;
0407
0408 err = komeda_layer_check_cfg(wb_layer, kfb, dflow);
0409 if (err)
0410 return err;
0411
0412 c_st = komeda_component_get_state_and_set_user(&wb_layer->base,
0413 conn_st->state, conn_st->connector, conn_st->crtc);
0414 if (IS_ERR(c_st))
0415 return PTR_ERR(c_st);
0416
0417 st = to_layer_st(c_st);
0418
0419 st->hsize = dflow->out_w;
0420 st->vsize = dflow->out_h;
0421
0422 for (i = 0; i < kfb->base.format->num_planes; i++)
0423 st->addr[i] = komeda_fb_get_pixel_addr(kfb, dflow->out_x,
0424 dflow->out_y, i);
0425
0426 komeda_component_add_input(&st->base, &dflow->input, 0);
0427 komeda_component_set_output(&dflow->input, &wb_layer->base, 0);
0428
0429 return 0;
0430 }
0431
0432 static bool scaling_ratio_valid(u32 size_in, u32 size_out,
0433 u32 max_upscaling, u32 max_downscaling)
0434 {
0435 if (size_out > size_in * max_upscaling)
0436 return false;
0437 else if (size_in > size_out * max_downscaling)
0438 return false;
0439 return true;
0440 }
0441
0442 static int
0443 komeda_scaler_check_cfg(struct komeda_scaler *scaler,
0444 struct komeda_crtc_state *kcrtc_st,
0445 struct komeda_data_flow_cfg *dflow)
0446 {
0447 u32 hsize_in, vsize_in, hsize_out, vsize_out;
0448 u32 max_upscaling;
0449
0450 hsize_in = dflow->in_w;
0451 vsize_in = dflow->in_h;
0452 hsize_out = dflow->out_w;
0453 vsize_out = dflow->out_h;
0454
0455 if (!in_range(&scaler->hsize, hsize_in) ||
0456 !in_range(&scaler->hsize, hsize_out)) {
0457 DRM_DEBUG_ATOMIC("Invalid horizontal sizes");
0458 return -EINVAL;
0459 }
0460
0461 if (!in_range(&scaler->vsize, vsize_in) ||
0462 !in_range(&scaler->vsize, vsize_out)) {
0463 DRM_DEBUG_ATOMIC("Invalid vertical sizes");
0464 return -EINVAL;
0465 }
0466
0467
0468
0469
0470 if (has_bit(dflow->input.component->id, KOMEDA_PIPELINE_COMPIZS))
0471 max_upscaling = 1;
0472 else
0473 max_upscaling = scaler->max_upscaling;
0474
0475 if (!scaling_ratio_valid(hsize_in, hsize_out, max_upscaling,
0476 scaler->max_downscaling)) {
0477 DRM_DEBUG_ATOMIC("Invalid horizontal scaling ratio");
0478 return -EINVAL;
0479 }
0480
0481 if (!scaling_ratio_valid(vsize_in, vsize_out, max_upscaling,
0482 scaler->max_downscaling)) {
0483 DRM_DEBUG_ATOMIC("Invalid vertical scaling ratio");
0484 return -EINVAL;
0485 }
0486
0487 if (hsize_in > hsize_out || vsize_in > vsize_out) {
0488 struct komeda_pipeline *pipe = scaler->base.pipeline;
0489 int err;
0490
0491 err = pipe->funcs->downscaling_clk_check(pipe,
0492 &kcrtc_st->base.adjusted_mode,
0493 komeda_crtc_get_aclk(kcrtc_st), dflow);
0494 if (err) {
0495 DRM_DEBUG_ATOMIC("aclk can't satisfy the clock requirement of the downscaling\n");
0496 return err;
0497 }
0498 }
0499
0500 return 0;
0501 }
0502
0503 static int
0504 komeda_scaler_validate(void *user,
0505 struct komeda_crtc_state *kcrtc_st,
0506 struct komeda_data_flow_cfg *dflow)
0507 {
0508 struct drm_atomic_state *drm_st = kcrtc_st->base.state;
0509 struct komeda_component_state *c_st;
0510 struct komeda_scaler_state *st;
0511 struct komeda_scaler *scaler;
0512 int err = 0;
0513
0514 if (!(dflow->en_scaling || dflow->en_img_enhancement))
0515 return 0;
0516
0517 scaler = komeda_component_get_avail_scaler(dflow->input.component,
0518 drm_st);
0519 if (!scaler) {
0520 DRM_DEBUG_ATOMIC("No scaler available");
0521 return -EINVAL;
0522 }
0523
0524 err = komeda_scaler_check_cfg(scaler, kcrtc_st, dflow);
0525 if (err)
0526 return err;
0527
0528 c_st = komeda_component_get_state_and_set_user(&scaler->base,
0529 drm_st, user, kcrtc_st->base.crtc);
0530 if (IS_ERR(c_st))
0531 return PTR_ERR(c_st);
0532
0533 st = to_scaler_st(c_st);
0534
0535 st->hsize_in = dflow->in_w;
0536 st->vsize_in = dflow->in_h;
0537 st->hsize_out = dflow->out_w;
0538 st->vsize_out = dflow->out_h;
0539 st->right_crop = dflow->right_crop;
0540 st->left_crop = dflow->left_crop;
0541 st->total_vsize_in = dflow->total_in_h;
0542 st->total_hsize_in = dflow->total_in_w;
0543 st->total_hsize_out = dflow->total_out_w;
0544
0545
0546 st->en_alpha = dflow->pixel_blend_mode != DRM_MODE_BLEND_PIXEL_NONE;
0547 st->en_scaling = dflow->en_scaling;
0548 st->en_img_enhancement = dflow->en_img_enhancement;
0549 st->en_split = dflow->en_split;
0550 st->right_part = dflow->right_part;
0551
0552 komeda_component_add_input(&st->base, &dflow->input, 0);
0553 komeda_component_set_output(&dflow->input, &scaler->base, 0);
0554 return err;
0555 }
0556
0557 static void komeda_split_data_flow(struct komeda_scaler *scaler,
0558 struct komeda_data_flow_cfg *dflow,
0559 struct komeda_data_flow_cfg *l_dflow,
0560 struct komeda_data_flow_cfg *r_dflow);
0561
0562 static int
0563 komeda_splitter_validate(struct komeda_splitter *splitter,
0564 struct drm_connector_state *conn_st,
0565 struct komeda_data_flow_cfg *dflow,
0566 struct komeda_data_flow_cfg *l_output,
0567 struct komeda_data_flow_cfg *r_output)
0568 {
0569 struct komeda_component_state *c_st;
0570 struct komeda_splitter_state *st;
0571
0572 if (!splitter) {
0573 DRM_DEBUG_ATOMIC("Current HW doesn't support splitter.\n");
0574 return -EINVAL;
0575 }
0576
0577 if (!in_range(&splitter->hsize, dflow->in_w)) {
0578 DRM_DEBUG_ATOMIC("split in_w:%d is out of the acceptable range.\n",
0579 dflow->in_w);
0580 return -EINVAL;
0581 }
0582
0583 if (!in_range(&splitter->vsize, dflow->in_h)) {
0584 DRM_DEBUG_ATOMIC("split in_h: %d exceeds the acceptable range.\n",
0585 dflow->in_h);
0586 return -EINVAL;
0587 }
0588
0589 c_st = komeda_component_get_state_and_set_user(&splitter->base,
0590 conn_st->state, conn_st->connector, conn_st->crtc);
0591
0592 if (IS_ERR(c_st))
0593 return PTR_ERR(c_st);
0594
0595 komeda_split_data_flow(splitter->base.pipeline->scalers[0],
0596 dflow, l_output, r_output);
0597
0598 st = to_splitter_st(c_st);
0599 st->hsize = dflow->in_w;
0600 st->vsize = dflow->in_h;
0601 st->overlap = dflow->overlap;
0602
0603 komeda_component_add_input(&st->base, &dflow->input, 0);
0604 komeda_component_set_output(&l_output->input, &splitter->base, 0);
0605 komeda_component_set_output(&r_output->input, &splitter->base, 1);
0606
0607 return 0;
0608 }
0609
0610 static int
0611 komeda_merger_validate(struct komeda_merger *merger,
0612 void *user,
0613 struct komeda_crtc_state *kcrtc_st,
0614 struct komeda_data_flow_cfg *left_input,
0615 struct komeda_data_flow_cfg *right_input,
0616 struct komeda_data_flow_cfg *output)
0617 {
0618 struct komeda_component_state *c_st;
0619 struct komeda_merger_state *st;
0620 int err = 0;
0621
0622 if (!merger) {
0623 DRM_DEBUG_ATOMIC("No merger is available");
0624 return -EINVAL;
0625 }
0626
0627 if (!in_range(&merger->hsize_merged, output->out_w)) {
0628 DRM_DEBUG_ATOMIC("merged_w: %d is out of the accepted range.\n",
0629 output->out_w);
0630 return -EINVAL;
0631 }
0632
0633 if (!in_range(&merger->vsize_merged, output->out_h)) {
0634 DRM_DEBUG_ATOMIC("merged_h: %d is out of the accepted range.\n",
0635 output->out_h);
0636 return -EINVAL;
0637 }
0638
0639 c_st = komeda_component_get_state_and_set_user(&merger->base,
0640 kcrtc_st->base.state, kcrtc_st->base.crtc, kcrtc_st->base.crtc);
0641
0642 if (IS_ERR(c_st))
0643 return PTR_ERR(c_st);
0644
0645 st = to_merger_st(c_st);
0646 st->hsize_merged = output->out_w;
0647 st->vsize_merged = output->out_h;
0648
0649 komeda_component_add_input(c_st, &left_input->input, 0);
0650 komeda_component_add_input(c_st, &right_input->input, 1);
0651 komeda_component_set_output(&output->input, &merger->base, 0);
0652
0653 return err;
0654 }
0655
0656 void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
0657 u16 *hsize, u16 *vsize)
0658 {
0659 struct drm_display_mode *m = &kcrtc_st->base.adjusted_mode;
0660
0661 if (hsize)
0662 *hsize = m->hdisplay;
0663 if (vsize)
0664 *vsize = m->vdisplay;
0665 }
0666
0667 static int
0668 komeda_compiz_set_input(struct komeda_compiz *compiz,
0669 struct komeda_crtc_state *kcrtc_st,
0670 struct komeda_data_flow_cfg *dflow)
0671 {
0672 struct drm_atomic_state *drm_st = kcrtc_st->base.state;
0673 struct komeda_component_state *c_st, *old_st;
0674 struct komeda_compiz_input_cfg *cin;
0675 u16 compiz_w, compiz_h;
0676 int idx = dflow->blending_zorder;
0677
0678 pipeline_composition_size(kcrtc_st, &compiz_w, &compiz_h);
0679
0680 if ((dflow->out_x + dflow->out_w > compiz_w) ||
0681 (dflow->out_y + dflow->out_h > compiz_h) ||
0682 dflow->out_w == 0 || dflow->out_h == 0) {
0683 DRM_DEBUG_ATOMIC("invalid disp rect [x=%d, y=%d, w=%d, h=%d]\n",
0684 dflow->out_x, dflow->out_y,
0685 dflow->out_w, dflow->out_h);
0686 return -EINVAL;
0687 }
0688
0689 c_st = komeda_component_get_state_and_set_user(&compiz->base, drm_st,
0690 kcrtc_st->base.crtc, kcrtc_st->base.crtc);
0691 if (IS_ERR(c_st))
0692 return PTR_ERR(c_st);
0693
0694 if (komeda_component_check_input(c_st, &dflow->input, idx))
0695 return -EINVAL;
0696
0697 cin = &(to_compiz_st(c_st)->cins[idx]);
0698
0699 cin->hsize = dflow->out_w;
0700 cin->vsize = dflow->out_h;
0701 cin->hoffset = dflow->out_x;
0702 cin->voffset = dflow->out_y;
0703 cin->pixel_blend_mode = dflow->pixel_blend_mode;
0704 cin->layer_alpha = dflow->layer_alpha;
0705
0706 old_st = komeda_component_get_old_state(&compiz->base, drm_st);
0707
0708
0709 if (WARN_ON(!old_st) ||
0710 memcmp(&(to_compiz_st(old_st)->cins[idx]), cin, sizeof(*cin)))
0711 c_st->changed_active_inputs |= BIT(idx);
0712
0713 komeda_component_add_input(c_st, &dflow->input, idx);
0714 komeda_component_set_output(&dflow->input, &compiz->base, 0);
0715
0716 return 0;
0717 }
0718
0719 static int
0720 komeda_compiz_validate(struct komeda_compiz *compiz,
0721 struct komeda_crtc_state *state,
0722 struct komeda_data_flow_cfg *dflow)
0723 {
0724 struct komeda_component_state *c_st;
0725 struct komeda_compiz_state *st;
0726
0727 c_st = komeda_component_get_state_and_set_user(&compiz->base,
0728 state->base.state, state->base.crtc, state->base.crtc);
0729 if (IS_ERR(c_st))
0730 return PTR_ERR(c_st);
0731
0732 st = to_compiz_st(c_st);
0733
0734 pipeline_composition_size(state, &st->hsize, &st->vsize);
0735
0736 komeda_component_set_output(&dflow->input, &compiz->base, 0);
0737
0738
0739
0740
0741 if (dflow) {
0742 dflow->in_w = st->hsize;
0743 dflow->in_h = st->vsize;
0744 dflow->out_w = dflow->in_w;
0745 dflow->out_h = dflow->in_h;
0746
0747
0748
0749 dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
0750 dflow->layer_alpha = 0xFF;
0751 dflow->blending_zorder = 0;
0752 }
0753
0754 return 0;
0755 }
0756
0757 static int
0758 komeda_improc_validate(struct komeda_improc *improc,
0759 struct komeda_crtc_state *kcrtc_st,
0760 struct komeda_data_flow_cfg *dflow)
0761 {
0762 struct drm_crtc *crtc = kcrtc_st->base.crtc;
0763 struct drm_crtc_state *crtc_st = &kcrtc_st->base;
0764 struct komeda_component_state *c_st;
0765 struct komeda_improc_state *st;
0766
0767 c_st = komeda_component_get_state_and_set_user(&improc->base,
0768 kcrtc_st->base.state, crtc, crtc);
0769 if (IS_ERR(c_st))
0770 return PTR_ERR(c_st);
0771
0772 st = to_improc_st(c_st);
0773
0774 st->hsize = dflow->in_w;
0775 st->vsize = dflow->in_h;
0776
0777 if (drm_atomic_crtc_needs_modeset(crtc_st)) {
0778 u32 output_depths, output_formats;
0779 u32 avail_depths, avail_formats;
0780
0781 komeda_crtc_get_color_config(crtc_st, &output_depths,
0782 &output_formats);
0783
0784 avail_depths = output_depths & improc->supported_color_depths;
0785 if (avail_depths == 0) {
0786 DRM_DEBUG_ATOMIC("No available color depths, conn depths: 0x%x & display: 0x%x\n",
0787 output_depths,
0788 improc->supported_color_depths);
0789 return -EINVAL;
0790 }
0791
0792 avail_formats = output_formats &
0793 improc->supported_color_formats;
0794 if (!avail_formats) {
0795 DRM_DEBUG_ATOMIC("No available color_formats, conn formats 0x%x & display: 0x%x\n",
0796 output_formats,
0797 improc->supported_color_formats);
0798 return -EINVAL;
0799 }
0800
0801 st->color_depth = __fls(avail_depths);
0802 st->color_format = BIT(__ffs(avail_formats));
0803 }
0804
0805 if (kcrtc_st->base.color_mgmt_changed) {
0806 drm_lut_to_fgamma_coeffs(kcrtc_st->base.gamma_lut,
0807 st->fgamma_coeffs);
0808 drm_ctm_to_coeffs(kcrtc_st->base.ctm, st->ctm_coeffs);
0809 }
0810
0811 komeda_component_add_input(&st->base, &dflow->input, 0);
0812 komeda_component_set_output(&dflow->input, &improc->base, 0);
0813
0814 return 0;
0815 }
0816
0817 static int
0818 komeda_timing_ctrlr_validate(struct komeda_timing_ctrlr *ctrlr,
0819 struct komeda_crtc_state *kcrtc_st,
0820 struct komeda_data_flow_cfg *dflow)
0821 {
0822 struct drm_crtc *crtc = kcrtc_st->base.crtc;
0823 struct komeda_timing_ctrlr_state *st;
0824 struct komeda_component_state *c_st;
0825
0826 c_st = komeda_component_get_state_and_set_user(&ctrlr->base,
0827 kcrtc_st->base.state, crtc, crtc);
0828 if (IS_ERR(c_st))
0829 return PTR_ERR(c_st);
0830
0831 st = to_ctrlr_st(c_st);
0832
0833 komeda_component_add_input(&st->base, &dflow->input, 0);
0834 komeda_component_set_output(&dflow->input, &ctrlr->base, 0);
0835
0836 return 0;
0837 }
0838
0839 void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
0840 struct komeda_data_flow_cfg *dflow,
0841 struct drm_framebuffer *fb)
0842 {
0843 struct komeda_scaler *scaler = layer->base.pipeline->scalers[0];
0844 u32 w = dflow->in_w;
0845 u32 h = dflow->in_h;
0846
0847 dflow->total_in_w = dflow->in_w;
0848 dflow->total_in_h = dflow->in_h;
0849 dflow->total_out_w = dflow->out_w;
0850
0851
0852 if (!fb->format->has_alpha)
0853 dflow->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
0854
0855 if (drm_rotation_90_or_270(dflow->rot))
0856 swap(w, h);
0857
0858 dflow->en_scaling = (w != dflow->out_w) || (h != dflow->out_h);
0859 dflow->is_yuv = fb->format->is_yuv;
0860
0861
0862 dflow->en_img_enhancement = dflow->out_w >= 2 * w ||
0863 dflow->out_h >= 2 * h;
0864
0865
0866
0867
0868 if (dflow->en_scaling && scaler)
0869 dflow->en_split = !in_range(&scaler->hsize, dflow->in_w) ||
0870 !in_range(&scaler->hsize, dflow->out_w);
0871 }
0872
0873 static bool merger_is_available(struct komeda_pipeline *pipe,
0874 struct komeda_data_flow_cfg *dflow)
0875 {
0876 u32 avail_inputs = pipe->merger ?
0877 pipe->merger->base.supported_inputs : 0;
0878
0879 return has_bit(dflow->input.component->id, avail_inputs);
0880 }
0881
0882 int komeda_build_layer_data_flow(struct komeda_layer *layer,
0883 struct komeda_plane_state *kplane_st,
0884 struct komeda_crtc_state *kcrtc_st,
0885 struct komeda_data_flow_cfg *dflow)
0886 {
0887 struct drm_plane *plane = kplane_st->base.plane;
0888 struct komeda_pipeline *pipe = layer->base.pipeline;
0889 int err;
0890
0891 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]",
0892 layer->base.name, plane->base.id, plane->name,
0893 dflow->in_x, dflow->in_y, dflow->in_w, dflow->in_h,
0894 dflow->out_x, dflow->out_y, dflow->out_w, dflow->out_h);
0895
0896 err = komeda_layer_validate(layer, kplane_st, dflow);
0897 if (err)
0898 return err;
0899
0900 err = komeda_scaler_validate(plane, kcrtc_st, dflow);
0901 if (err)
0902 return err;
0903
0904
0905 if (dflow->en_split && merger_is_available(pipe, dflow))
0906 return 0;
0907
0908 err = komeda_compiz_set_input(pipe->compiz, kcrtc_st, dflow);
0909
0910 return err;
0911 }
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945 static void komeda_split_data_flow(struct komeda_scaler *scaler,
0946 struct komeda_data_flow_cfg *dflow,
0947 struct komeda_data_flow_cfg *l_dflow,
0948 struct komeda_data_flow_cfg *r_dflow)
0949 {
0950 bool r90 = drm_rotation_90_or_270(dflow->rot);
0951 bool flip_h = has_flip_h(dflow->rot);
0952 u32 l_out, r_out, overlap;
0953
0954 memcpy(l_dflow, dflow, sizeof(*dflow));
0955 memcpy(r_dflow, dflow, sizeof(*dflow));
0956
0957 l_dflow->right_part = false;
0958 r_dflow->right_part = true;
0959 r_dflow->blending_zorder = dflow->blending_zorder + 1;
0960
0961 overlap = 0;
0962 if (dflow->en_scaling && scaler)
0963 overlap += scaler->scaling_split_overlap;
0964
0965
0966
0967
0968 dflow->overlap = overlap;
0969
0970 if (dflow->en_img_enhancement && scaler)
0971 overlap += scaler->enh_split_overlap;
0972
0973 l_dflow->overlap = overlap;
0974 r_dflow->overlap = overlap;
0975
0976
0977
0978
0979
0980
0981 if (r90) {
0982 if (dflow->en_scaling) {
0983 l_dflow->in_h = ALIGN(dflow->in_h, 2) / 2 + l_dflow->overlap;
0984 r_dflow->in_h = l_dflow->in_h;
0985 } else if (dflow->en_img_enhancement) {
0986
0987 l_dflow->in_h = ALIGN(dflow->in_h, 2) / 2 + l_dflow->overlap;
0988 r_dflow->in_h = dflow->in_h / 2 + r_dflow->overlap;
0989 } else {
0990
0991 l_dflow->in_h = ALIGN(((dflow->in_h + 1) >> 1), 2);
0992 r_dflow->in_h = dflow->in_h - l_dflow->in_h;
0993 }
0994
0995
0996
0997
0998
0999
1000
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
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
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
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
1048
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
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
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 int 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
1114 komeda_rotate_data_flow(dflow, dflow->rot);
1115
1116
1117
1118
1119 if (r_dflow.input.component == l_dflow.input.component)
1120 return 0;
1121
1122
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
1134 int 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
1150
1151
1152
1153
1154 int 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
1185
1186
1187 int 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;
1193 struct komeda_data_flow_cfg s_dflow;
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
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
1226 static void
1227 komeda_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
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
1251 int 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
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
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284 bool 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
1310
1311
1312
1313
1314
1315
1316 c_st->changed_active_inputs |= c_st->active_inputs;
1317
1318 c->funcs->disable(c);
1319 }
1320
1321
1322
1323
1324 old->active_comps &= ~disabling_comps;
1325
1326 return old->active_comps ? true : false;
1327 }
1328
1329 void 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 }