162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
762306a36Sopenharmony_ci#include <linux/iommu.h>
862306a36Sopenharmony_ci#include <linux/interconnect.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <drm/drm_atomic.h>
1162306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
1262306a36Sopenharmony_ci#include <drm/drm_fourcc.h>
1362306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
1462306a36Sopenharmony_ci#include <drm/drm_gem_atomic_helper.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "dc.h"
1762306a36Sopenharmony_ci#include "plane.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void tegra_plane_destroy(struct drm_plane *plane)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct tegra_plane *p = to_tegra_plane(plane);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	drm_plane_cleanup(plane);
2462306a36Sopenharmony_ci	kfree(p);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void tegra_plane_reset(struct drm_plane *plane)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct tegra_plane *p = to_tegra_plane(plane);
3062306a36Sopenharmony_ci	struct tegra_plane_state *state;
3162306a36Sopenharmony_ci	unsigned int i;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (plane->state)
3462306a36Sopenharmony_ci		__drm_atomic_helper_plane_destroy_state(plane->state);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	kfree(plane->state);
3762306a36Sopenharmony_ci	plane->state = NULL;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	state = kzalloc(sizeof(*state), GFP_KERNEL);
4062306a36Sopenharmony_ci	if (state) {
4162306a36Sopenharmony_ci		plane->state = &state->base;
4262306a36Sopenharmony_ci		plane->state->plane = plane;
4362306a36Sopenharmony_ci		plane->state->zpos = p->index;
4462306a36Sopenharmony_ci		plane->state->normalized_zpos = p->index;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		for (i = 0; i < 3; i++)
4762306a36Sopenharmony_ci			state->iova[i] = DMA_MAPPING_ERROR;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic struct drm_plane_state *
5262306a36Sopenharmony_citegra_plane_atomic_duplicate_state(struct drm_plane *plane)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
5562306a36Sopenharmony_ci	struct tegra_plane_state *copy;
5662306a36Sopenharmony_ci	unsigned int i;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
5962306a36Sopenharmony_ci	if (!copy)
6062306a36Sopenharmony_ci		return NULL;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
6362306a36Sopenharmony_ci	copy->tiling = state->tiling;
6462306a36Sopenharmony_ci	copy->format = state->format;
6562306a36Sopenharmony_ci	copy->swap = state->swap;
6662306a36Sopenharmony_ci	copy->reflect_x = state->reflect_x;
6762306a36Sopenharmony_ci	copy->reflect_y = state->reflect_y;
6862306a36Sopenharmony_ci	copy->opaque = state->opaque;
6962306a36Sopenharmony_ci	copy->total_peak_memory_bandwidth = state->total_peak_memory_bandwidth;
7062306a36Sopenharmony_ci	copy->peak_memory_bandwidth = state->peak_memory_bandwidth;
7162306a36Sopenharmony_ci	copy->avg_memory_bandwidth = state->avg_memory_bandwidth;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	for (i = 0; i < 2; i++)
7462306a36Sopenharmony_ci		copy->blending[i] = state->blending[i];
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
7762306a36Sopenharmony_ci		copy->iova[i] = DMA_MAPPING_ERROR;
7862306a36Sopenharmony_ci		copy->map[i] = NULL;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return &copy->base;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
8562306a36Sopenharmony_ci					     struct drm_plane_state *state)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	__drm_atomic_helper_plane_destroy_state(state);
8862306a36Sopenharmony_ci	kfree(state);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic bool tegra_plane_supports_sector_layout(struct drm_plane *plane)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct drm_crtc *crtc;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	drm_for_each_crtc(crtc, plane->dev) {
9662306a36Sopenharmony_ci		if (plane->possible_crtcs & drm_crtc_mask(crtc)) {
9762306a36Sopenharmony_ci			struct tegra_dc *dc = to_tegra_dc(crtc);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci			if (!dc->soc->supports_sector_layout)
10062306a36Sopenharmony_ci				return false;
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return true;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic bool tegra_plane_format_mod_supported(struct drm_plane *plane,
10862306a36Sopenharmony_ci					     uint32_t format,
10962306a36Sopenharmony_ci					     uint64_t modifier)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	const struct drm_format_info *info = drm_format_info(format);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (modifier == DRM_FORMAT_MOD_LINEAR)
11462306a36Sopenharmony_ci		return true;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* check for the sector layout bit */
11762306a36Sopenharmony_ci	if (fourcc_mod_is_vendor(modifier, NVIDIA)) {
11862306a36Sopenharmony_ci		if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) {
11962306a36Sopenharmony_ci			if (!tegra_plane_supports_sector_layout(plane))
12062306a36Sopenharmony_ci				return false;
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (info->num_planes == 1)
12562306a36Sopenharmony_ci		return true;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return false;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciconst struct drm_plane_funcs tegra_plane_funcs = {
13162306a36Sopenharmony_ci	.update_plane = drm_atomic_helper_update_plane,
13262306a36Sopenharmony_ci	.disable_plane = drm_atomic_helper_disable_plane,
13362306a36Sopenharmony_ci	.destroy = tegra_plane_destroy,
13462306a36Sopenharmony_ci	.reset = tegra_plane_reset,
13562306a36Sopenharmony_ci	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
13662306a36Sopenharmony_ci	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
13762306a36Sopenharmony_ci	.format_mod_supported = tegra_plane_format_mod_supported,
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	unsigned int i;
14362306a36Sopenharmony_ci	int err;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	for (i = 0; i < state->base.fb->format->num_planes; i++) {
14662306a36Sopenharmony_ci		struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
14762306a36Sopenharmony_ci		struct host1x_bo_mapping *map;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		map = host1x_bo_pin(dc->dev, &bo->base, DMA_TO_DEVICE, &dc->client.cache);
15062306a36Sopenharmony_ci		if (IS_ERR(map)) {
15162306a36Sopenharmony_ci			err = PTR_ERR(map);
15262306a36Sopenharmony_ci			goto unpin;
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		if (!dc->client.group) {
15662306a36Sopenharmony_ci			/*
15762306a36Sopenharmony_ci			 * The display controller needs contiguous memory, so
15862306a36Sopenharmony_ci			 * fail if the buffer is discontiguous and we fail to
15962306a36Sopenharmony_ci			 * map its SG table to a single contiguous chunk of
16062306a36Sopenharmony_ci			 * I/O virtual memory.
16162306a36Sopenharmony_ci			 */
16262306a36Sopenharmony_ci			if (map->chunks > 1) {
16362306a36Sopenharmony_ci				err = -EINVAL;
16462306a36Sopenharmony_ci				goto unpin;
16562306a36Sopenharmony_ci			}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci			state->iova[i] = map->phys;
16862306a36Sopenharmony_ci		} else {
16962306a36Sopenharmony_ci			state->iova[i] = bo->iova;
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		state->map[i] = map;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 0;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciunpin:
17862306a36Sopenharmony_ci	dev_err(dc->dev, "failed to map plane %u: %d\n", i, err);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	while (i--) {
18162306a36Sopenharmony_ci		host1x_bo_unpin(state->map[i]);
18262306a36Sopenharmony_ci		state->iova[i] = DMA_MAPPING_ERROR;
18362306a36Sopenharmony_ci		state->map[i] = NULL;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return err;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	unsigned int i;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	for (i = 0; i < state->base.fb->format->num_planes; i++) {
19462306a36Sopenharmony_ci		host1x_bo_unpin(state->map[i]);
19562306a36Sopenharmony_ci		state->iova[i] = DMA_MAPPING_ERROR;
19662306a36Sopenharmony_ci		state->map[i] = NULL;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ciint tegra_plane_prepare_fb(struct drm_plane *plane,
20162306a36Sopenharmony_ci			   struct drm_plane_state *state)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct tegra_dc *dc = to_tegra_dc(state->crtc);
20462306a36Sopenharmony_ci	int err;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (!state->fb)
20762306a36Sopenharmony_ci		return 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	err = drm_gem_plane_helper_prepare_fb(plane, state);
21062306a36Sopenharmony_ci	if (err < 0)
21162306a36Sopenharmony_ci		return err;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return tegra_dc_pin(dc, to_tegra_plane_state(state));
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_civoid tegra_plane_cleanup_fb(struct drm_plane *plane,
21762306a36Sopenharmony_ci			    struct drm_plane_state *state)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct tegra_dc *dc = to_tegra_dc(state->crtc);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (dc)
22262306a36Sopenharmony_ci		tegra_dc_unpin(dc, to_tegra_plane_state(state));
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int tegra_plane_calculate_memory_bandwidth(struct drm_plane_state *state)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct tegra_plane_state *tegra_state = to_tegra_plane_state(state);
22862306a36Sopenharmony_ci	unsigned int i, bpp, dst_w, dst_h, src_w, src_h, mul;
22962306a36Sopenharmony_ci	const struct tegra_dc_soc_info *soc;
23062306a36Sopenharmony_ci	const struct drm_format_info *fmt;
23162306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
23262306a36Sopenharmony_ci	u64 avg_bandwidth, peak_bandwidth;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (!state->visible)
23562306a36Sopenharmony_ci		return 0;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
23862306a36Sopenharmony_ci	if (!crtc_state)
23962306a36Sopenharmony_ci		return -EINVAL;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	src_w = drm_rect_width(&state->src) >> 16;
24262306a36Sopenharmony_ci	src_h = drm_rect_height(&state->src) >> 16;
24362306a36Sopenharmony_ci	dst_w = drm_rect_width(&state->dst);
24462306a36Sopenharmony_ci	dst_h = drm_rect_height(&state->dst);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	fmt = state->fb->format;
24762306a36Sopenharmony_ci	soc = to_tegra_dc(state->crtc)->soc;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/*
25062306a36Sopenharmony_ci	 * Note that real memory bandwidth vary depending on format and
25162306a36Sopenharmony_ci	 * memory layout, we are not taking that into account because small
25262306a36Sopenharmony_ci	 * estimation error isn't important since bandwidth is rounded up
25362306a36Sopenharmony_ci	 * anyway.
25462306a36Sopenharmony_ci	 */
25562306a36Sopenharmony_ci	for (i = 0, bpp = 0; i < fmt->num_planes; i++) {
25662306a36Sopenharmony_ci		unsigned int bpp_plane = fmt->cpp[i] * 8;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		/*
25962306a36Sopenharmony_ci		 * Sub-sampling is relevant for chroma planes only and vertical
26062306a36Sopenharmony_ci		 * readouts are not cached, hence only horizontal sub-sampling
26162306a36Sopenharmony_ci		 * matters.
26262306a36Sopenharmony_ci		 */
26362306a36Sopenharmony_ci		if (i > 0)
26462306a36Sopenharmony_ci			bpp_plane /= fmt->hsub;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		bpp += bpp_plane;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* average bandwidth in kbytes/sec */
27062306a36Sopenharmony_ci	avg_bandwidth  = min(src_w, dst_w) * min(src_h, dst_h);
27162306a36Sopenharmony_ci	avg_bandwidth *= drm_mode_vrefresh(&crtc_state->adjusted_mode);
27262306a36Sopenharmony_ci	avg_bandwidth  = DIV_ROUND_UP(avg_bandwidth * bpp, 8) + 999;
27362306a36Sopenharmony_ci	do_div(avg_bandwidth, 1000);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* mode.clock in kHz, peak bandwidth in kbytes/sec */
27662306a36Sopenharmony_ci	peak_bandwidth = DIV_ROUND_UP(crtc_state->adjusted_mode.clock * bpp, 8);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/*
27962306a36Sopenharmony_ci	 * Tegra30/114 Memory Controller can't interleave DC memory requests
28062306a36Sopenharmony_ci	 * for the tiled windows because DC uses 16-bytes atom, while DDR3
28162306a36Sopenharmony_ci	 * uses 32-bytes atom.  Hence there is x2 memory overfetch for tiled
28262306a36Sopenharmony_ci	 * framebuffer and DDR3 on these SoCs.
28362306a36Sopenharmony_ci	 */
28462306a36Sopenharmony_ci	if (soc->plane_tiled_memory_bandwidth_x2 &&
28562306a36Sopenharmony_ci	    tegra_state->tiling.mode == TEGRA_BO_TILING_MODE_TILED)
28662306a36Sopenharmony_ci		mul = 2;
28762306a36Sopenharmony_ci	else
28862306a36Sopenharmony_ci		mul = 1;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* ICC bandwidth in kbytes/sec */
29162306a36Sopenharmony_ci	tegra_state->peak_memory_bandwidth = kBps_to_icc(peak_bandwidth) * mul;
29262306a36Sopenharmony_ci	tegra_state->avg_memory_bandwidth  = kBps_to_icc(avg_bandwidth)  * mul;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return 0;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ciint tegra_plane_state_add(struct tegra_plane *plane,
29862306a36Sopenharmony_ci			  struct drm_plane_state *state)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
30162306a36Sopenharmony_ci	struct tegra_dc_state *tegra;
30262306a36Sopenharmony_ci	int err;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/* Propagate errors from allocation or locking failures. */
30562306a36Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
30662306a36Sopenharmony_ci	if (IS_ERR(crtc_state))
30762306a36Sopenharmony_ci		return PTR_ERR(crtc_state);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Check plane state for visibility and calculate clipping bounds */
31062306a36Sopenharmony_ci	err = drm_atomic_helper_check_plane_state(state, crtc_state,
31162306a36Sopenharmony_ci						  0, INT_MAX, true, true);
31262306a36Sopenharmony_ci	if (err < 0)
31362306a36Sopenharmony_ci		return err;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	err = tegra_plane_calculate_memory_bandwidth(state);
31662306a36Sopenharmony_ci	if (err < 0)
31762306a36Sopenharmony_ci		return err;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	tegra = to_dc_state(crtc_state);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	tegra->planes |= WIN_A_ACT_REQ << plane->index;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciint tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	/* assume no swapping of fetched data */
32962306a36Sopenharmony_ci	if (swap)
33062306a36Sopenharmony_ci		*swap = BYTE_SWAP_NOSWAP;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	switch (fourcc) {
33362306a36Sopenharmony_ci	case DRM_FORMAT_ARGB4444:
33462306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_B4G4R4A4;
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	case DRM_FORMAT_ARGB1555:
33862306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_B5G5R5A1;
33962306a36Sopenharmony_ci		break;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	case DRM_FORMAT_RGB565:
34262306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_B5G6R5;
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	case DRM_FORMAT_RGBA5551:
34662306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_A1B5G5R5;
34762306a36Sopenharmony_ci		break;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
35062306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_B8G8R8A8;
35162306a36Sopenharmony_ci		break;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
35462306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_R8G8B8A8;
35562306a36Sopenharmony_ci		break;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	case DRM_FORMAT_ABGR4444:
35862306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_R4G4B4A4;
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	case DRM_FORMAT_ABGR1555:
36262306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_R5G5B5A;
36362306a36Sopenharmony_ci		break;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	case DRM_FORMAT_BGRA5551:
36662306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_AR5G5B5;
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	case DRM_FORMAT_XRGB1555:
37062306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_B5G5R5X1;
37162306a36Sopenharmony_ci		break;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	case DRM_FORMAT_RGBX5551:
37462306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_X1B5G5R5;
37562306a36Sopenharmony_ci		break;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	case DRM_FORMAT_XBGR1555:
37862306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_R5G5B5X1;
37962306a36Sopenharmony_ci		break;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	case DRM_FORMAT_BGRX5551:
38262306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_X1R5G5B5;
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	case DRM_FORMAT_BGR565:
38662306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_R5G6B5;
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	case DRM_FORMAT_BGRA8888:
39062306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_A8R8G8B8;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	case DRM_FORMAT_RGBA8888:
39462306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_A8B8G8R8;
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	case DRM_FORMAT_XRGB8888:
39862306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_B8G8R8X8;
39962306a36Sopenharmony_ci		break;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	case DRM_FORMAT_XBGR8888:
40262306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_R8G8B8X8;
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
40662306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr422;
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
41062306a36Sopenharmony_ci		if (!swap)
41162306a36Sopenharmony_ci			return -EINVAL;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr422;
41462306a36Sopenharmony_ci		*swap = BYTE_SWAP_SWAP2;
41562306a36Sopenharmony_ci		break;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
41862306a36Sopenharmony_ci		if (!swap)
41962306a36Sopenharmony_ci			return -EINVAL;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr422;
42262306a36Sopenharmony_ci		*swap = BYTE_SWAP_SWAP4;
42362306a36Sopenharmony_ci		break;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
42662306a36Sopenharmony_ci		if (!swap)
42762306a36Sopenharmony_ci			return -EINVAL;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr422;
43062306a36Sopenharmony_ci		*swap = BYTE_SWAP_SWAP4HW;
43162306a36Sopenharmony_ci		break;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	case DRM_FORMAT_YUV420:
43462306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr420P;
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	case DRM_FORMAT_YUV422:
43862306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr422P;
43962306a36Sopenharmony_ci		break;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	case DRM_FORMAT_YUV444:
44262306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr444P;
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
44662306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr420SP;
44762306a36Sopenharmony_ci		break;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
45062306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCrCb420SP;
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	case DRM_FORMAT_NV16:
45462306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr422SP;
45562306a36Sopenharmony_ci		break;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	case DRM_FORMAT_NV61:
45862306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCrCb422SP;
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	case DRM_FORMAT_NV24:
46262306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCbCr444SP;
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	case DRM_FORMAT_NV42:
46662306a36Sopenharmony_ci		*format = WIN_COLOR_DEPTH_YCrCb444SP;
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	default:
47062306a36Sopenharmony_ci		return -EINVAL;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return 0;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cibool tegra_plane_format_is_indexed(unsigned int format)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	switch (format) {
47962306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_P1:
48062306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_P2:
48162306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_P4:
48262306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_P8:
48362306a36Sopenharmony_ci		return true;
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return false;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cibool tegra_plane_format_is_yuv(unsigned int format, unsigned int *planes, unsigned int *bpc)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	switch (format) {
49262306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr422:
49362306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YUV422:
49462306a36Sopenharmony_ci		if (planes)
49562306a36Sopenharmony_ci			*planes = 1;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		if (bpc)
49862306a36Sopenharmony_ci			*bpc = 8;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		return true;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr420P:
50362306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YUV420P:
50462306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr422P:
50562306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YUV422P:
50662306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr422R:
50762306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YUV422R:
50862306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr422RA:
50962306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YUV422RA:
51062306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr444P:
51162306a36Sopenharmony_ci		if (planes)
51262306a36Sopenharmony_ci			*planes = 3;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		if (bpc)
51562306a36Sopenharmony_ci			*bpc = 8;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		return true;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCrCb420SP:
52062306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr420SP:
52162306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCrCb422SP:
52262306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr422SP:
52362306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCrCb444SP:
52462306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_YCbCr444SP:
52562306a36Sopenharmony_ci		if (planes)
52662306a36Sopenharmony_ci			*planes = 2;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		if (bpc)
52962306a36Sopenharmony_ci			*bpc = 8;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		return true;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (planes)
53562306a36Sopenharmony_ci		*planes = 1;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return false;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic bool __drm_format_has_alpha(u32 format)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	switch (format) {
54362306a36Sopenharmony_ci	case DRM_FORMAT_ARGB1555:
54462306a36Sopenharmony_ci	case DRM_FORMAT_RGBA5551:
54562306a36Sopenharmony_ci	case DRM_FORMAT_ABGR8888:
54662306a36Sopenharmony_ci	case DRM_FORMAT_ARGB8888:
54762306a36Sopenharmony_ci		return true;
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return false;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int tegra_plane_format_get_alpha(unsigned int opaque,
55462306a36Sopenharmony_ci					unsigned int *alpha)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	if (tegra_plane_format_is_yuv(opaque, NULL, NULL)) {
55762306a36Sopenharmony_ci		*alpha = opaque;
55862306a36Sopenharmony_ci		return 0;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	switch (opaque) {
56262306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_B5G5R5X1:
56362306a36Sopenharmony_ci		*alpha = WIN_COLOR_DEPTH_B5G5R5A1;
56462306a36Sopenharmony_ci		return 0;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_X1B5G5R5:
56762306a36Sopenharmony_ci		*alpha = WIN_COLOR_DEPTH_A1B5G5R5;
56862306a36Sopenharmony_ci		return 0;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_R8G8B8X8:
57162306a36Sopenharmony_ci		*alpha = WIN_COLOR_DEPTH_R8G8B8A8;
57262306a36Sopenharmony_ci		return 0;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_B8G8R8X8:
57562306a36Sopenharmony_ci		*alpha = WIN_COLOR_DEPTH_B8G8R8A8;
57662306a36Sopenharmony_ci		return 0;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_B5G6R5:
57962306a36Sopenharmony_ci		*alpha = opaque;
58062306a36Sopenharmony_ci		return 0;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return -EINVAL;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci/*
58762306a36Sopenharmony_ci * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
58862306a36Sopenharmony_ci * be emulated using the alpha formats and alpha blending disabled.
58962306a36Sopenharmony_ci */
59062306a36Sopenharmony_cistatic int tegra_plane_setup_opacity(struct tegra_plane *tegra,
59162306a36Sopenharmony_ci				     struct tegra_plane_state *state)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	unsigned int format;
59462306a36Sopenharmony_ci	int err;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	switch (state->format) {
59762306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_B5G5R5A1:
59862306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_A1B5G5R5:
59962306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_R8G8B8A8:
60062306a36Sopenharmony_ci	case WIN_COLOR_DEPTH_B8G8R8A8:
60162306a36Sopenharmony_ci		state->opaque = false;
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	default:
60562306a36Sopenharmony_ci		err = tegra_plane_format_get_alpha(state->format, &format);
60662306a36Sopenharmony_ci		if (err < 0)
60762306a36Sopenharmony_ci			return err;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		state->format = format;
61062306a36Sopenharmony_ci		state->opaque = true;
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return 0;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic int tegra_plane_check_transparency(struct tegra_plane *tegra,
61862306a36Sopenharmony_ci					  struct tegra_plane_state *state)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	struct drm_plane_state *old, *plane_state;
62162306a36Sopenharmony_ci	struct drm_plane *plane;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* check if zpos / transparency changed */
62662306a36Sopenharmony_ci	if (old->normalized_zpos == state->base.normalized_zpos &&
62762306a36Sopenharmony_ci	    to_tegra_plane_state(old)->opaque == state->opaque)
62862306a36Sopenharmony_ci		return 0;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* include all sibling planes into this commit */
63162306a36Sopenharmony_ci	drm_for_each_plane(plane, tegra->base.dev) {
63262306a36Sopenharmony_ci		struct tegra_plane *p = to_tegra_plane(plane);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		/* skip this plane and planes on different CRTCs */
63562306a36Sopenharmony_ci		if (p == tegra || p->dc != tegra->dc)
63662306a36Sopenharmony_ci			continue;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci		plane_state = drm_atomic_get_plane_state(state->base.state,
63962306a36Sopenharmony_ci							 plane);
64062306a36Sopenharmony_ci		if (IS_ERR(plane_state))
64162306a36Sopenharmony_ci			return PTR_ERR(plane_state);
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	return 1;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
64862306a36Sopenharmony_ci						  struct tegra_plane *other)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	unsigned int index = 0, i;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	WARN_ON(plane == other);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
65562306a36Sopenharmony_ci		if (i == plane->index)
65662306a36Sopenharmony_ci			continue;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		if (i == other->index)
65962306a36Sopenharmony_ci			break;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		index++;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return index;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void tegra_plane_update_transparency(struct tegra_plane *tegra,
66862306a36Sopenharmony_ci					    struct tegra_plane_state *state)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct drm_plane_state *new;
67162306a36Sopenharmony_ci	struct drm_plane *plane;
67262306a36Sopenharmony_ci	unsigned int i;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	for_each_new_plane_in_state(state->base.state, plane, new, i) {
67562306a36Sopenharmony_ci		struct tegra_plane *p = to_tegra_plane(plane);
67662306a36Sopenharmony_ci		unsigned index;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		/* skip this plane and planes on different CRTCs */
67962306a36Sopenharmony_ci		if (p == tegra || p->dc != tegra->dc)
68062306a36Sopenharmony_ci			continue;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		index = tegra_plane_get_overlap_index(tegra, p);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		if (new->fb && __drm_format_has_alpha(new->fb->format->format))
68562306a36Sopenharmony_ci			state->blending[index].alpha = true;
68662306a36Sopenharmony_ci		else
68762306a36Sopenharmony_ci			state->blending[index].alpha = false;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		if (new->normalized_zpos > state->base.normalized_zpos)
69062306a36Sopenharmony_ci			state->blending[index].top = true;
69162306a36Sopenharmony_ci		else
69262306a36Sopenharmony_ci			state->blending[index].top = false;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci		/*
69562306a36Sopenharmony_ci		 * Missing framebuffer means that plane is disabled, in this
69662306a36Sopenharmony_ci		 * case mark B / C window as top to be able to differentiate
69762306a36Sopenharmony_ci		 * windows indices order in regards to zPos for the middle
69862306a36Sopenharmony_ci		 * window X / Y registers programming.
69962306a36Sopenharmony_ci		 */
70062306a36Sopenharmony_ci		if (!new->fb)
70162306a36Sopenharmony_ci			state->blending[index].top = (index == 1);
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cistatic int tegra_plane_setup_transparency(struct tegra_plane *tegra,
70662306a36Sopenharmony_ci					  struct tegra_plane_state *state)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct tegra_plane_state *tegra_state;
70962306a36Sopenharmony_ci	struct drm_plane_state *new;
71062306a36Sopenharmony_ci	struct drm_plane *plane;
71162306a36Sopenharmony_ci	int err;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	/*
71462306a36Sopenharmony_ci	 * If planes zpos / transparency changed, sibling planes blending
71562306a36Sopenharmony_ci	 * state may require adjustment and in this case they will be included
71662306a36Sopenharmony_ci	 * into this atom commit, otherwise blending state is unchanged.
71762306a36Sopenharmony_ci	 */
71862306a36Sopenharmony_ci	err = tegra_plane_check_transparency(tegra, state);
71962306a36Sopenharmony_ci	if (err <= 0)
72062306a36Sopenharmony_ci		return err;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	/*
72362306a36Sopenharmony_ci	 * All planes are now in the atomic state, walk them up and update
72462306a36Sopenharmony_ci	 * transparency state for each plane.
72562306a36Sopenharmony_ci	 */
72662306a36Sopenharmony_ci	drm_for_each_plane(plane, tegra->base.dev) {
72762306a36Sopenharmony_ci		struct tegra_plane *p = to_tegra_plane(plane);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		/* skip planes on different CRTCs */
73062306a36Sopenharmony_ci		if (p->dc != tegra->dc)
73162306a36Sopenharmony_ci			continue;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		new = drm_atomic_get_new_plane_state(state->base.state, plane);
73462306a36Sopenharmony_ci		tegra_state = to_tegra_plane_state(new);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		/*
73762306a36Sopenharmony_ci		 * There is no need to update blending state for the disabled
73862306a36Sopenharmony_ci		 * plane.
73962306a36Sopenharmony_ci		 */
74062306a36Sopenharmony_ci		if (new->fb)
74162306a36Sopenharmony_ci			tegra_plane_update_transparency(p, tegra_state);
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	return 0;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ciint tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
74862306a36Sopenharmony_ci				   struct tegra_plane_state *state)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	int err;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	err = tegra_plane_setup_opacity(tegra, state);
75362306a36Sopenharmony_ci	if (err < 0)
75462306a36Sopenharmony_ci		return err;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	err = tegra_plane_setup_transparency(tegra, state);
75762306a36Sopenharmony_ci	if (err < 0)
75862306a36Sopenharmony_ci		return err;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	return 0;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic const char * const tegra_plane_icc_names[TEGRA_DC_LEGACY_PLANES_NUM] = {
76462306a36Sopenharmony_ci	"wina", "winb", "winc", NULL, NULL, NULL, "cursor",
76562306a36Sopenharmony_ci};
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ciint tegra_plane_interconnect_init(struct tegra_plane *plane)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	const char *icc_name = tegra_plane_icc_names[plane->index];
77062306a36Sopenharmony_ci	struct device *dev = plane->dc->dev;
77162306a36Sopenharmony_ci	struct tegra_dc *dc = plane->dc;
77262306a36Sopenharmony_ci	int err;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (WARN_ON(plane->index >= TEGRA_DC_LEGACY_PLANES_NUM) ||
77562306a36Sopenharmony_ci	    WARN_ON(!tegra_plane_icc_names[plane->index]))
77662306a36Sopenharmony_ci		return -EINVAL;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	plane->icc_mem = devm_of_icc_get(dev, icc_name);
77962306a36Sopenharmony_ci	err = PTR_ERR_OR_ZERO(plane->icc_mem);
78062306a36Sopenharmony_ci	if (err)
78162306a36Sopenharmony_ci		return dev_err_probe(dev, err, "failed to get %s interconnect\n",
78262306a36Sopenharmony_ci				     icc_name);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* plane B on T20/30 has a dedicated memory client for a 6-tap vertical filter */
78562306a36Sopenharmony_ci	if (plane->index == 1 && dc->soc->has_win_b_vfilter_mem_client) {
78662306a36Sopenharmony_ci		plane->icc_mem_vfilter = devm_of_icc_get(dev, "winb-vfilter");
78762306a36Sopenharmony_ci		err = PTR_ERR_OR_ZERO(plane->icc_mem_vfilter);
78862306a36Sopenharmony_ci		if (err)
78962306a36Sopenharmony_ci			return dev_err_probe(dev, err, "failed to get %s interconnect\n",
79062306a36Sopenharmony_ci					     "winb-vfilter");
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	return 0;
79462306a36Sopenharmony_ci}
795