0001
0002
0003
0004
0005
0006 #include <linux/dma-mapping.h>
0007 #include <linux/iommu.h>
0008 #include <linux/interconnect.h>
0009
0010 #include <drm/drm_atomic.h>
0011 #include <drm/drm_atomic_helper.h>
0012 #include <drm/drm_fourcc.h>
0013 #include <drm/drm_framebuffer.h>
0014 #include <drm/drm_gem_atomic_helper.h>
0015 #include <drm/drm_plane_helper.h>
0016
0017 #include "dc.h"
0018 #include "plane.h"
0019
0020 static void tegra_plane_destroy(struct drm_plane *plane)
0021 {
0022 struct tegra_plane *p = to_tegra_plane(plane);
0023
0024 drm_plane_cleanup(plane);
0025 kfree(p);
0026 }
0027
0028 static void tegra_plane_reset(struct drm_plane *plane)
0029 {
0030 struct tegra_plane *p = to_tegra_plane(plane);
0031 struct tegra_plane_state *state;
0032 unsigned int i;
0033
0034 if (plane->state)
0035 __drm_atomic_helper_plane_destroy_state(plane->state);
0036
0037 kfree(plane->state);
0038 plane->state = NULL;
0039
0040 state = kzalloc(sizeof(*state), GFP_KERNEL);
0041 if (state) {
0042 plane->state = &state->base;
0043 plane->state->plane = plane;
0044 plane->state->zpos = p->index;
0045 plane->state->normalized_zpos = p->index;
0046
0047 for (i = 0; i < 3; i++)
0048 state->iova[i] = DMA_MAPPING_ERROR;
0049 }
0050 }
0051
0052 static struct drm_plane_state *
0053 tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
0054 {
0055 struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
0056 struct tegra_plane_state *copy;
0057 unsigned int i;
0058
0059 copy = kmalloc(sizeof(*copy), GFP_KERNEL);
0060 if (!copy)
0061 return NULL;
0062
0063 __drm_atomic_helper_plane_duplicate_state(plane, ©->base);
0064 copy->tiling = state->tiling;
0065 copy->format = state->format;
0066 copy->swap = state->swap;
0067 copy->reflect_x = state->reflect_x;
0068 copy->reflect_y = state->reflect_y;
0069 copy->opaque = state->opaque;
0070 copy->total_peak_memory_bandwidth = state->total_peak_memory_bandwidth;
0071 copy->peak_memory_bandwidth = state->peak_memory_bandwidth;
0072 copy->avg_memory_bandwidth = state->avg_memory_bandwidth;
0073
0074 for (i = 0; i < 2; i++)
0075 copy->blending[i] = state->blending[i];
0076
0077 for (i = 0; i < 3; i++) {
0078 copy->iova[i] = DMA_MAPPING_ERROR;
0079 copy->map[i] = NULL;
0080 }
0081
0082 return ©->base;
0083 }
0084
0085 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
0086 struct drm_plane_state *state)
0087 {
0088 __drm_atomic_helper_plane_destroy_state(state);
0089 kfree(state);
0090 }
0091
0092 static bool tegra_plane_supports_sector_layout(struct drm_plane *plane)
0093 {
0094 struct drm_crtc *crtc;
0095
0096 drm_for_each_crtc(crtc, plane->dev) {
0097 if (plane->possible_crtcs & drm_crtc_mask(crtc)) {
0098 struct tegra_dc *dc = to_tegra_dc(crtc);
0099
0100 if (!dc->soc->supports_sector_layout)
0101 return false;
0102 }
0103 }
0104
0105 return true;
0106 }
0107
0108 static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
0109 uint32_t format,
0110 uint64_t modifier)
0111 {
0112 const struct drm_format_info *info = drm_format_info(format);
0113
0114 if (modifier == DRM_FORMAT_MOD_LINEAR)
0115 return true;
0116
0117
0118 if (fourcc_mod_is_vendor(modifier, NVIDIA)) {
0119 if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) {
0120 if (!tegra_plane_supports_sector_layout(plane))
0121 return false;
0122 }
0123 }
0124
0125 if (info->num_planes == 1)
0126 return true;
0127
0128 return false;
0129 }
0130
0131 const struct drm_plane_funcs tegra_plane_funcs = {
0132 .update_plane = drm_atomic_helper_update_plane,
0133 .disable_plane = drm_atomic_helper_disable_plane,
0134 .destroy = tegra_plane_destroy,
0135 .reset = tegra_plane_reset,
0136 .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
0137 .atomic_destroy_state = tegra_plane_atomic_destroy_state,
0138 .format_mod_supported = tegra_plane_format_mod_supported,
0139 };
0140
0141 static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
0142 {
0143 unsigned int i;
0144 int err;
0145
0146 for (i = 0; i < state->base.fb->format->num_planes; i++) {
0147 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
0148 struct host1x_bo_mapping *map;
0149
0150 map = host1x_bo_pin(dc->dev, &bo->base, DMA_TO_DEVICE, &dc->client.cache);
0151 if (IS_ERR(map)) {
0152 err = PTR_ERR(map);
0153 goto unpin;
0154 }
0155
0156 if (!dc->client.group) {
0157
0158
0159
0160
0161
0162
0163 if (map->chunks > 1) {
0164 err = -EINVAL;
0165 goto unpin;
0166 }
0167
0168 state->iova[i] = map->phys;
0169 } else {
0170 state->iova[i] = bo->iova;
0171 }
0172
0173 state->map[i] = map;
0174 }
0175
0176 return 0;
0177
0178 unpin:
0179 dev_err(dc->dev, "failed to map plane %u: %d\n", i, err);
0180
0181 while (i--) {
0182 host1x_bo_unpin(state->map[i]);
0183 state->iova[i] = DMA_MAPPING_ERROR;
0184 state->map[i] = NULL;
0185 }
0186
0187 return err;
0188 }
0189
0190 static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state)
0191 {
0192 unsigned int i;
0193
0194 for (i = 0; i < state->base.fb->format->num_planes; i++) {
0195 host1x_bo_unpin(state->map[i]);
0196 state->iova[i] = DMA_MAPPING_ERROR;
0197 state->map[i] = NULL;
0198 }
0199 }
0200
0201 int tegra_plane_prepare_fb(struct drm_plane *plane,
0202 struct drm_plane_state *state)
0203 {
0204 struct tegra_dc *dc = to_tegra_dc(state->crtc);
0205 int err;
0206
0207 if (!state->fb)
0208 return 0;
0209
0210 err = drm_gem_plane_helper_prepare_fb(plane, state);
0211 if (err < 0)
0212 return err;
0213
0214 return tegra_dc_pin(dc, to_tegra_plane_state(state));
0215 }
0216
0217 void tegra_plane_cleanup_fb(struct drm_plane *plane,
0218 struct drm_plane_state *state)
0219 {
0220 struct tegra_dc *dc = to_tegra_dc(state->crtc);
0221
0222 if (dc)
0223 tegra_dc_unpin(dc, to_tegra_plane_state(state));
0224 }
0225
0226 static int tegra_plane_calculate_memory_bandwidth(struct drm_plane_state *state)
0227 {
0228 struct tegra_plane_state *tegra_state = to_tegra_plane_state(state);
0229 unsigned int i, bpp, dst_w, dst_h, src_w, src_h, mul;
0230 const struct tegra_dc_soc_info *soc;
0231 const struct drm_format_info *fmt;
0232 struct drm_crtc_state *crtc_state;
0233 u64 avg_bandwidth, peak_bandwidth;
0234
0235 if (!state->visible)
0236 return 0;
0237
0238 crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
0239 if (!crtc_state)
0240 return -EINVAL;
0241
0242 src_w = drm_rect_width(&state->src) >> 16;
0243 src_h = drm_rect_height(&state->src) >> 16;
0244 dst_w = drm_rect_width(&state->dst);
0245 dst_h = drm_rect_height(&state->dst);
0246
0247 fmt = state->fb->format;
0248 soc = to_tegra_dc(state->crtc)->soc;
0249
0250
0251
0252
0253
0254
0255
0256 for (i = 0, bpp = 0; i < fmt->num_planes; i++) {
0257 unsigned int bpp_plane = fmt->cpp[i] * 8;
0258
0259
0260
0261
0262
0263
0264 if (i > 0)
0265 bpp_plane /= fmt->hsub;
0266
0267 bpp += bpp_plane;
0268 }
0269
0270
0271 avg_bandwidth = min(src_w, dst_w) * min(src_h, dst_h);
0272 avg_bandwidth *= drm_mode_vrefresh(&crtc_state->adjusted_mode);
0273 avg_bandwidth = DIV_ROUND_UP(avg_bandwidth * bpp, 8) + 999;
0274 do_div(avg_bandwidth, 1000);
0275
0276
0277 peak_bandwidth = DIV_ROUND_UP(crtc_state->adjusted_mode.clock * bpp, 8);
0278
0279
0280
0281
0282
0283
0284
0285 if (soc->plane_tiled_memory_bandwidth_x2 &&
0286 tegra_state->tiling.mode == TEGRA_BO_TILING_MODE_TILED)
0287 mul = 2;
0288 else
0289 mul = 1;
0290
0291
0292 tegra_state->peak_memory_bandwidth = kBps_to_icc(peak_bandwidth) * mul;
0293 tegra_state->avg_memory_bandwidth = kBps_to_icc(avg_bandwidth) * mul;
0294
0295 return 0;
0296 }
0297
0298 int tegra_plane_state_add(struct tegra_plane *plane,
0299 struct drm_plane_state *state)
0300 {
0301 struct drm_crtc_state *crtc_state;
0302 struct tegra_dc_state *tegra;
0303 int err;
0304
0305
0306 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
0307 if (IS_ERR(crtc_state))
0308 return PTR_ERR(crtc_state);
0309
0310
0311 err = drm_atomic_helper_check_plane_state(state, crtc_state,
0312 0, INT_MAX, true, true);
0313 if (err < 0)
0314 return err;
0315
0316 err = tegra_plane_calculate_memory_bandwidth(state);
0317 if (err < 0)
0318 return err;
0319
0320 tegra = to_dc_state(crtc_state);
0321
0322 tegra->planes |= WIN_A_ACT_REQ << plane->index;
0323
0324 return 0;
0325 }
0326
0327 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
0328 {
0329
0330 if (swap)
0331 *swap = BYTE_SWAP_NOSWAP;
0332
0333 switch (fourcc) {
0334 case DRM_FORMAT_ARGB4444:
0335 *format = WIN_COLOR_DEPTH_B4G4R4A4;
0336 break;
0337
0338 case DRM_FORMAT_ARGB1555:
0339 *format = WIN_COLOR_DEPTH_B5G5R5A1;
0340 break;
0341
0342 case DRM_FORMAT_RGB565:
0343 *format = WIN_COLOR_DEPTH_B5G6R5;
0344 break;
0345
0346 case DRM_FORMAT_RGBA5551:
0347 *format = WIN_COLOR_DEPTH_A1B5G5R5;
0348 break;
0349
0350 case DRM_FORMAT_ARGB8888:
0351 *format = WIN_COLOR_DEPTH_B8G8R8A8;
0352 break;
0353
0354 case DRM_FORMAT_ABGR8888:
0355 *format = WIN_COLOR_DEPTH_R8G8B8A8;
0356 break;
0357
0358 case DRM_FORMAT_ABGR4444:
0359 *format = WIN_COLOR_DEPTH_R4G4B4A4;
0360 break;
0361
0362 case DRM_FORMAT_ABGR1555:
0363 *format = WIN_COLOR_DEPTH_R5G5B5A;
0364 break;
0365
0366 case DRM_FORMAT_BGRA5551:
0367 *format = WIN_COLOR_DEPTH_AR5G5B5;
0368 break;
0369
0370 case DRM_FORMAT_XRGB1555:
0371 *format = WIN_COLOR_DEPTH_B5G5R5X1;
0372 break;
0373
0374 case DRM_FORMAT_RGBX5551:
0375 *format = WIN_COLOR_DEPTH_X1B5G5R5;
0376 break;
0377
0378 case DRM_FORMAT_XBGR1555:
0379 *format = WIN_COLOR_DEPTH_R5G5B5X1;
0380 break;
0381
0382 case DRM_FORMAT_BGRX5551:
0383 *format = WIN_COLOR_DEPTH_X1R5G5B5;
0384 break;
0385
0386 case DRM_FORMAT_BGR565:
0387 *format = WIN_COLOR_DEPTH_R5G6B5;
0388 break;
0389
0390 case DRM_FORMAT_BGRA8888:
0391 *format = WIN_COLOR_DEPTH_A8R8G8B8;
0392 break;
0393
0394 case DRM_FORMAT_RGBA8888:
0395 *format = WIN_COLOR_DEPTH_A8B8G8R8;
0396 break;
0397
0398 case DRM_FORMAT_XRGB8888:
0399 *format = WIN_COLOR_DEPTH_B8G8R8X8;
0400 break;
0401
0402 case DRM_FORMAT_XBGR8888:
0403 *format = WIN_COLOR_DEPTH_R8G8B8X8;
0404 break;
0405
0406 case DRM_FORMAT_UYVY:
0407 *format = WIN_COLOR_DEPTH_YCbCr422;
0408 break;
0409
0410 case DRM_FORMAT_YUYV:
0411 if (!swap)
0412 return -EINVAL;
0413
0414 *format = WIN_COLOR_DEPTH_YCbCr422;
0415 *swap = BYTE_SWAP_SWAP2;
0416 break;
0417
0418 case DRM_FORMAT_YVYU:
0419 if (!swap)
0420 return -EINVAL;
0421
0422 *format = WIN_COLOR_DEPTH_YCbCr422;
0423 *swap = BYTE_SWAP_SWAP4;
0424 break;
0425
0426 case DRM_FORMAT_VYUY:
0427 if (!swap)
0428 return -EINVAL;
0429
0430 *format = WIN_COLOR_DEPTH_YCbCr422;
0431 *swap = BYTE_SWAP_SWAP4HW;
0432 break;
0433
0434 case DRM_FORMAT_YUV420:
0435 *format = WIN_COLOR_DEPTH_YCbCr420P;
0436 break;
0437
0438 case DRM_FORMAT_YUV422:
0439 *format = WIN_COLOR_DEPTH_YCbCr422P;
0440 break;
0441
0442 case DRM_FORMAT_YUV444:
0443 *format = WIN_COLOR_DEPTH_YCbCr444P;
0444 break;
0445
0446 case DRM_FORMAT_NV12:
0447 *format = WIN_COLOR_DEPTH_YCbCr420SP;
0448 break;
0449
0450 case DRM_FORMAT_NV21:
0451 *format = WIN_COLOR_DEPTH_YCrCb420SP;
0452 break;
0453
0454 case DRM_FORMAT_NV16:
0455 *format = WIN_COLOR_DEPTH_YCbCr422SP;
0456 break;
0457
0458 case DRM_FORMAT_NV61:
0459 *format = WIN_COLOR_DEPTH_YCrCb422SP;
0460 break;
0461
0462 case DRM_FORMAT_NV24:
0463 *format = WIN_COLOR_DEPTH_YCbCr444SP;
0464 break;
0465
0466 case DRM_FORMAT_NV42:
0467 *format = WIN_COLOR_DEPTH_YCrCb444SP;
0468 break;
0469
0470 default:
0471 return -EINVAL;
0472 }
0473
0474 return 0;
0475 }
0476
0477 bool tegra_plane_format_is_indexed(unsigned int format)
0478 {
0479 switch (format) {
0480 case WIN_COLOR_DEPTH_P1:
0481 case WIN_COLOR_DEPTH_P2:
0482 case WIN_COLOR_DEPTH_P4:
0483 case WIN_COLOR_DEPTH_P8:
0484 return true;
0485 }
0486
0487 return false;
0488 }
0489
0490 bool tegra_plane_format_is_yuv(unsigned int format, unsigned int *planes, unsigned int *bpc)
0491 {
0492 switch (format) {
0493 case WIN_COLOR_DEPTH_YCbCr422:
0494 case WIN_COLOR_DEPTH_YUV422:
0495 if (planes)
0496 *planes = 1;
0497
0498 if (bpc)
0499 *bpc = 8;
0500
0501 return true;
0502
0503 case WIN_COLOR_DEPTH_YCbCr420P:
0504 case WIN_COLOR_DEPTH_YUV420P:
0505 case WIN_COLOR_DEPTH_YCbCr422P:
0506 case WIN_COLOR_DEPTH_YUV422P:
0507 case WIN_COLOR_DEPTH_YCbCr422R:
0508 case WIN_COLOR_DEPTH_YUV422R:
0509 case WIN_COLOR_DEPTH_YCbCr422RA:
0510 case WIN_COLOR_DEPTH_YUV422RA:
0511 case WIN_COLOR_DEPTH_YCbCr444P:
0512 if (planes)
0513 *planes = 3;
0514
0515 if (bpc)
0516 *bpc = 8;
0517
0518 return true;
0519
0520 case WIN_COLOR_DEPTH_YCrCb420SP:
0521 case WIN_COLOR_DEPTH_YCbCr420SP:
0522 case WIN_COLOR_DEPTH_YCrCb422SP:
0523 case WIN_COLOR_DEPTH_YCbCr422SP:
0524 case WIN_COLOR_DEPTH_YCrCb444SP:
0525 case WIN_COLOR_DEPTH_YCbCr444SP:
0526 if (planes)
0527 *planes = 2;
0528
0529 if (bpc)
0530 *bpc = 8;
0531
0532 return true;
0533 }
0534
0535 if (planes)
0536 *planes = 1;
0537
0538 return false;
0539 }
0540
0541 static bool __drm_format_has_alpha(u32 format)
0542 {
0543 switch (format) {
0544 case DRM_FORMAT_ARGB1555:
0545 case DRM_FORMAT_RGBA5551:
0546 case DRM_FORMAT_ABGR8888:
0547 case DRM_FORMAT_ARGB8888:
0548 return true;
0549 }
0550
0551 return false;
0552 }
0553
0554 static int tegra_plane_format_get_alpha(unsigned int opaque,
0555 unsigned int *alpha)
0556 {
0557 if (tegra_plane_format_is_yuv(opaque, NULL, NULL)) {
0558 *alpha = opaque;
0559 return 0;
0560 }
0561
0562 switch (opaque) {
0563 case WIN_COLOR_DEPTH_B5G5R5X1:
0564 *alpha = WIN_COLOR_DEPTH_B5G5R5A1;
0565 return 0;
0566
0567 case WIN_COLOR_DEPTH_X1B5G5R5:
0568 *alpha = WIN_COLOR_DEPTH_A1B5G5R5;
0569 return 0;
0570
0571 case WIN_COLOR_DEPTH_R8G8B8X8:
0572 *alpha = WIN_COLOR_DEPTH_R8G8B8A8;
0573 return 0;
0574
0575 case WIN_COLOR_DEPTH_B8G8R8X8:
0576 *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
0577 return 0;
0578
0579 case WIN_COLOR_DEPTH_B5G6R5:
0580 *alpha = opaque;
0581 return 0;
0582 }
0583
0584 return -EINVAL;
0585 }
0586
0587
0588
0589
0590
0591 static int tegra_plane_setup_opacity(struct tegra_plane *tegra,
0592 struct tegra_plane_state *state)
0593 {
0594 unsigned int format;
0595 int err;
0596
0597 switch (state->format) {
0598 case WIN_COLOR_DEPTH_B5G5R5A1:
0599 case WIN_COLOR_DEPTH_A1B5G5R5:
0600 case WIN_COLOR_DEPTH_R8G8B8A8:
0601 case WIN_COLOR_DEPTH_B8G8R8A8:
0602 state->opaque = false;
0603 break;
0604
0605 default:
0606 err = tegra_plane_format_get_alpha(state->format, &format);
0607 if (err < 0)
0608 return err;
0609
0610 state->format = format;
0611 state->opaque = true;
0612 break;
0613 }
0614
0615 return 0;
0616 }
0617
0618 static int tegra_plane_check_transparency(struct tegra_plane *tegra,
0619 struct tegra_plane_state *state)
0620 {
0621 struct drm_plane_state *old, *plane_state;
0622 struct drm_plane *plane;
0623
0624 old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base);
0625
0626
0627 if (old->normalized_zpos == state->base.normalized_zpos &&
0628 to_tegra_plane_state(old)->opaque == state->opaque)
0629 return 0;
0630
0631
0632 drm_for_each_plane(plane, tegra->base.dev) {
0633 struct tegra_plane *p = to_tegra_plane(plane);
0634
0635
0636 if (p == tegra || p->dc != tegra->dc)
0637 continue;
0638
0639 plane_state = drm_atomic_get_plane_state(state->base.state,
0640 plane);
0641 if (IS_ERR(plane_state))
0642 return PTR_ERR(plane_state);
0643 }
0644
0645 return 1;
0646 }
0647
0648 static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
0649 struct tegra_plane *other)
0650 {
0651 unsigned int index = 0, i;
0652
0653 WARN_ON(plane == other);
0654
0655 for (i = 0; i < 3; i++) {
0656 if (i == plane->index)
0657 continue;
0658
0659 if (i == other->index)
0660 break;
0661
0662 index++;
0663 }
0664
0665 return index;
0666 }
0667
0668 static void tegra_plane_update_transparency(struct tegra_plane *tegra,
0669 struct tegra_plane_state *state)
0670 {
0671 struct drm_plane_state *new;
0672 struct drm_plane *plane;
0673 unsigned int i;
0674
0675 for_each_new_plane_in_state(state->base.state, plane, new, i) {
0676 struct tegra_plane *p = to_tegra_plane(plane);
0677 unsigned index;
0678
0679
0680 if (p == tegra || p->dc != tegra->dc)
0681 continue;
0682
0683 index = tegra_plane_get_overlap_index(tegra, p);
0684
0685 if (new->fb && __drm_format_has_alpha(new->fb->format->format))
0686 state->blending[index].alpha = true;
0687 else
0688 state->blending[index].alpha = false;
0689
0690 if (new->normalized_zpos > state->base.normalized_zpos)
0691 state->blending[index].top = true;
0692 else
0693 state->blending[index].top = false;
0694
0695
0696
0697
0698
0699
0700
0701 if (!new->fb)
0702 state->blending[index].top = (index == 1);
0703 }
0704 }
0705
0706 static int tegra_plane_setup_transparency(struct tegra_plane *tegra,
0707 struct tegra_plane_state *state)
0708 {
0709 struct tegra_plane_state *tegra_state;
0710 struct drm_plane_state *new;
0711 struct drm_plane *plane;
0712 int err;
0713
0714
0715
0716
0717
0718
0719 err = tegra_plane_check_transparency(tegra, state);
0720 if (err <= 0)
0721 return err;
0722
0723
0724
0725
0726
0727 drm_for_each_plane(plane, tegra->base.dev) {
0728 struct tegra_plane *p = to_tegra_plane(plane);
0729
0730
0731 if (p->dc != tegra->dc)
0732 continue;
0733
0734 new = drm_atomic_get_new_plane_state(state->base.state, plane);
0735 tegra_state = to_tegra_plane_state(new);
0736
0737
0738
0739
0740
0741 if (new->fb)
0742 tegra_plane_update_transparency(p, tegra_state);
0743 }
0744
0745 return 0;
0746 }
0747
0748 int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
0749 struct tegra_plane_state *state)
0750 {
0751 int err;
0752
0753 err = tegra_plane_setup_opacity(tegra, state);
0754 if (err < 0)
0755 return err;
0756
0757 err = tegra_plane_setup_transparency(tegra, state);
0758 if (err < 0)
0759 return err;
0760
0761 return 0;
0762 }
0763
0764 static const char * const tegra_plane_icc_names[TEGRA_DC_LEGACY_PLANES_NUM] = {
0765 "wina", "winb", "winc", NULL, NULL, NULL, "cursor",
0766 };
0767
0768 int tegra_plane_interconnect_init(struct tegra_plane *plane)
0769 {
0770 const char *icc_name = tegra_plane_icc_names[plane->index];
0771 struct device *dev = plane->dc->dev;
0772 struct tegra_dc *dc = plane->dc;
0773 int err;
0774
0775 if (WARN_ON(plane->index >= TEGRA_DC_LEGACY_PLANES_NUM) ||
0776 WARN_ON(!tegra_plane_icc_names[plane->index]))
0777 return -EINVAL;
0778
0779 plane->icc_mem = devm_of_icc_get(dev, icc_name);
0780 err = PTR_ERR_OR_ZERO(plane->icc_mem);
0781 if (err) {
0782 dev_err_probe(dev, err, "failed to get %s interconnect\n",
0783 icc_name);
0784 return err;
0785 }
0786
0787
0788 if (plane->index == 1 && dc->soc->has_win_b_vfilter_mem_client) {
0789 plane->icc_mem_vfilter = devm_of_icc_get(dev, "winb-vfilter");
0790 err = PTR_ERR_OR_ZERO(plane->icc_mem_vfilter);
0791 if (err) {
0792 dev_err_probe(dev, err, "failed to get %s interconnect\n",
0793 "winb-vfilter");
0794 return err;
0795 }
0796 }
0797
0798 return 0;
0799 }