summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/imx/dpu/dpu-plane.h
blob: eeb52f5262b60cc4c0322c0f2bdbf9ca0213611e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*
 * Copyright 2017-2018 NXP
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

#ifndef __DPU_PLANE_H__
#define __DPU_PLANE_H__

#include <video/dpu.h>
#include "imx-drm.h"

#define MAX_DPU_PLANE_GRP	(MAX_CRTC / 2)

enum dpu_plane_src_type {
	DPU_PLANE_SRC_FL,
	DPU_PLANE_SRC_FW,
	DPU_PLANE_SRC_FD,
};

struct dpu_plane {
	struct drm_plane	base;
	struct dpu_plane_grp	*grp;
	struct list_head	head;
	unsigned int		stream_id;
};

struct dpu_plane_state {
	struct drm_plane_state	base;
	lb_prim_sel_t		stage;
	lb_sec_sel_t		source;
	dpu_block_id_t		blend;
	unsigned int		layer_x;
	unsigned int		layer_y;
	unsigned int		base_x;
	unsigned int		base_y;
	unsigned int		base_w;
	unsigned int		base_h;
	bool			is_top;
	bool			use_prefetch;
};

static const lb_prim_sel_t cf_stages[] = {LB_PRIM_SEL__CONSTFRAME0,
					  LB_PRIM_SEL__CONSTFRAME1};
static const lb_prim_sel_t stages[] = {LB_PRIM_SEL__LAYERBLEND0,
				       LB_PRIM_SEL__LAYERBLEND1,
				       LB_PRIM_SEL__LAYERBLEND2,
				       LB_PRIM_SEL__LAYERBLEND3,
				       LB_PRIM_SEL__LAYERBLEND4,
				       LB_PRIM_SEL__LAYERBLEND5};
/* FIXME: Correct the source entries for subsidiary layers. */
static const lb_sec_sel_t sources[] = {LB_SEC_SEL__FETCHLAYER0,
				       LB_SEC_SEL__FETCHLAYER1,
				       LB_SEC_SEL__FETCHWARP2,
				       LB_SEC_SEL__FETCHDECODE0,
				       LB_SEC_SEL__FETCHDECODE1,
				       LB_SEC_SEL__FETCHDECODE2,
				       LB_SEC_SEL__FETCHDECODE3};
static const dpu_block_id_t blends[] = {ID_LAYERBLEND0, ID_LAYERBLEND1,
					ID_LAYERBLEND2, ID_LAYERBLEND3,
					ID_LAYERBLEND4, ID_LAYERBLEND5};

static inline struct dpu_plane *to_dpu_plane(struct drm_plane *plane)
{
	return container_of(plane, struct dpu_plane, base);
}

static inline struct dpu_plane_state *
to_dpu_plane_state(struct drm_plane_state *plane_state)
{
	return container_of(plane_state, struct dpu_plane_state, base);
}

static inline int source_to_type(lb_sec_sel_t source)
{
	switch (source) {
	case LB_SEC_SEL__FETCHLAYER0:
	case LB_SEC_SEL__FETCHLAYER1:
		return DPU_PLANE_SRC_FL;
	case LB_SEC_SEL__FETCHWARP2:
		return DPU_PLANE_SRC_FW;
	case LB_SEC_SEL__FETCHDECODE0:
	case LB_SEC_SEL__FETCHDECODE1:
	case LB_SEC_SEL__FETCHDECODE2:
	case LB_SEC_SEL__FETCHDECODE3:
		return DPU_PLANE_SRC_FD;
	default:
		break;
	}

	WARN_ON(1);
	return -EINVAL;
}

static inline int source_to_id(lb_sec_sel_t source)
{
	int i, offset = 0;
	int type = source_to_type(source);

	for (i = 0; i < ARRAY_SIZE(sources); i++) {
		if (source == sources[i]) {
			if (type == DPU_PLANE_SRC_FD ||
			    type == DPU_PLANE_SRC_FW) {
				while (offset < ARRAY_SIZE(sources)) {
					if (source_to_type(sources[offset]) ==
					    type)
						break;
					offset++;
				}

				i -= offset;
			}

			return i;
		}
	}

	WARN_ON(1);
	return -EINVAL;
}

static inline struct dpu_fetchunit *
source_to_fu(struct dpu_plane_res *res, lb_sec_sel_t source)
{
	int fu_type = source_to_type(source);
	int fu_id = source_to_id(source);

	if (fu_type < 0 || fu_id < 0)
		return NULL;

	switch (fu_type) {
	case DPU_PLANE_SRC_FD:
		return res->fd[fu_id];
	case DPU_PLANE_SRC_FL:
		return res->fl[fu_id];
	case DPU_PLANE_SRC_FW:
		return res->fw[fu_id];
	}

	return NULL;
}

static inline struct dpu_fetchunit *
dpstate_to_fu(struct dpu_plane_state *dpstate)
{
	struct drm_plane *plane = dpstate->base.plane;
	struct dpu_plane *dplane = to_dpu_plane(plane);
	struct dpu_plane_res *res = &dplane->grp->res;

	return source_to_fu(res, dpstate->source);
}

static inline int blend_to_id(dpu_block_id_t blend)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(blends); i++) {
		if (blend == blends[i])
			return i;
	}

	WARN_ON(1);
	return -EINVAL;
}

static inline bool drm_format_is_yuv(uint32_t format)
{
	switch (format) {
	case DRM_FORMAT_YUYV:
	case DRM_FORMAT_UYVY:
	case DRM_FORMAT_NV12:
	case DRM_FORMAT_NV21:
		return true;
	default:
		break;
	}

	return false;
}

struct dpu_plane *dpu_plane_init(struct drm_device *drm,
				 unsigned int possible_crtcs,
				 unsigned int stream_id,
				 struct dpu_plane_grp *grp,
				 enum drm_plane_type type);
#endif