aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
blob: 8c89fc245b83f3315140418b57ec0d3c7887dc34 (plain) (blame)
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
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
 * Author: James.Qian.Wang <james.qian.wang@arm.com>
 *
 */
#ifndef _KOMEDA_KMS_H_
#define _KOMEDA_KMS_H_

#include <linux/list.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_writeback.h>
#include <drm/drm_print.h>
#include <video/videomode.h>
#include <video/display_timing.h>

/**
 * struct komeda_plane - komeda instance of drm_plane
 */
struct komeda_plane {
	/** @base: &drm_plane */
	struct drm_plane base;
	/**
	 * @layer:
	 *
	 * represents available layer input pipelines for this plane.
	 *
	 * NOTE:
	 * the layer is not for a specific Layer, but indicate a group of
	 * Layers with same capabilities.
	 */
	struct komeda_layer *layer;
};

/**
 * struct komeda_plane_state
 *
 * The plane_state can be split into two data flow (left/right) and handled
 * by two layers &komeda_plane.layer and &komeda_plane.layer.right
 */
struct komeda_plane_state {
	/** @base: &drm_plane_state */
	struct drm_plane_state base;
	/** @zlist_node: zorder list node */
	struct list_head zlist_node;

	/** @layer_split: on/off layer_split */
	u8 layer_split : 1;
};

/**
 * struct komeda_wb_connector
 */
struct komeda_wb_connector {
	/** @base: &drm_writeback_connector */
	struct drm_writeback_connector base;

	/** @wb_layer: represents associated writeback pipeline of komeda */
	struct komeda_layer *wb_layer;
};

/**
 * struct komeda_crtc
 */
struct komeda_crtc {
	/** @base: &drm_crtc */
	struct drm_crtc base;
	/** @master: only master has display output */
	struct komeda_pipeline *master;
	/**
	 * @slave: optional
	 *
	 * Doesn't have its own display output, the handled data flow will
	 * merge into the master.
	 */
	struct komeda_pipeline *slave;

	/** @slave_planes: komeda slave planes mask */
	u32 slave_planes;

	/** @wb_conn: komeda write back connector */
	struct komeda_wb_connector *wb_conn;

	/** @disable_done: this flip_done is for tracing the disable */
	struct completion *disable_done;
};

/**
 * struct komeda_crtc_state
 */
struct komeda_crtc_state {
	/** @base: &drm_crtc_state */
	struct drm_crtc_state base;

	/* private properties */

	/* computed state which are used by validate/check */
	/**
	 * @affected_pipes:
	 * the affected pipelines in once display instance
	 */
	u32 affected_pipes;
	/**
	 * @active_pipes:
	 * the active pipelines in once display instance
	 */
	u32 active_pipes;

	/** @clock_ratio: ratio of (aclk << 32)/pxlclk */
	u64 clock_ratio;

	/** @max_slave_zorder: the maximum of slave zorder */
	u32 max_slave_zorder;
};

/** struct komeda_kms_dev - for gather KMS related things */
struct komeda_kms_dev {
	/** @base: &drm_device */
	struct drm_device base;

	/** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
	int n_crtcs;
	/** @crtcs: crtcs list */
	struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
};

#define to_kplane(p)	container_of(p, struct komeda_plane, base)
#define to_kplane_st(p)	container_of(p, struct komeda_plane_state, base)
#define to_kconn(p)	container_of(p, struct komeda_wb_connector, base)
#define to_kcrtc(p)	container_of(p, struct komeda_crtc, base)
#define to_kcrtc_st(p)	container_of(p, struct komeda_crtc_state, base)
#define to_kdev(p)	container_of(p, struct komeda_kms_dev, base)
#define to_wb_conn(x)	container_of(x, struct drm_writeback_connector, base)

static inline bool is_writeback_only(struct drm_crtc_state *st)
{
	struct komeda_wb_connector *wb_conn = to_kcrtc(st->crtc)->wb_conn;
	struct drm_connector *conn = wb_conn ? &wb_conn->base.base : NULL;

	return conn && (st->connector_mask == BIT(drm_connector_index(conn)));
}

static inline bool
is_only_changed_connector(struct drm_crtc_state *st, struct drm_connector *conn)
{
	struct drm_crtc_state *old_st;
	u32 changed_connectors;

	old_st = drm_atomic_get_old_crtc_state(st->state, st->crtc);
	changed_connectors = st->connector_mask ^ old_st->connector_mask;

	return BIT(drm_connector_index(conn)) == changed_connectors;
}

static inline bool has_flip_h(u32 rot)
{
	u32 rotation = drm_rotation_simplify(rot,
					     DRM_MODE_ROTATE_0 |
					     DRM_MODE_ROTATE_90 |
					     DRM_MODE_REFLECT_MASK);

	if (rotation & DRM_MODE_ROTATE_90)
		return !!(rotation & DRM_MODE_REFLECT_Y);
	else
		return !!(rotation & DRM_MODE_REFLECT_X);
}

unsigned long komeda_calc_aclk(struct komeda_crtc_state *kcrtc_st);

int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);

int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
				struct komeda_dev *mdev);
int komeda_kms_add_wb_connectors(struct komeda_kms_dev *kms,
				 struct komeda_dev *mdev);
void komeda_kms_cleanup_private_objs(struct komeda_kms_dev *kms);

void komeda_crtc_handle_event(struct komeda_crtc   *kcrtc,
			      struct komeda_events *evts);

struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
void komeda_kms_detach(struct komeda_kms_dev *kms);

#endif /*_KOMEDA_KMS_H_*/