1 /*
2  * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3  * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4  *
5  * This program is free software and is provided to you under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation, and any use by you of this program is subject to the terms
8  * of such GNU licence.
9  *
10  * ARM Mali DP plane manipulation routines.
11  */
12 
13 #include <drm/drmP.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_fb_cma_helper.h>
16 #include <drm/drm_gem_cma_helper.h>
17 #include <drm/drm_plane_helper.h>
18 
19 #include "malidp_hw.h"
20 #include "malidp_drv.h"
21 
22 /* Layer specific register offsets */
23 #define MALIDP_LAYER_FORMAT		0x000
24 #define MALIDP_LAYER_CONTROL		0x004
25 #define   LAYER_ENABLE			(1 << 0)
26 #define   LAYER_ROT_OFFSET		8
27 #define   LAYER_H_FLIP			(1 << 10)
28 #define   LAYER_V_FLIP			(1 << 11)
29 #define   LAYER_ROT_MASK		(0xf << 8)
30 #define   LAYER_COMP_MASK		(0x3 << 12)
31 #define   LAYER_COMP_PIXEL		(0x3 << 12)
32 #define   LAYER_COMP_PLANE		(0x2 << 12)
33 #define MALIDP_LAYER_COMPOSE		0x008
34 #define MALIDP_LAYER_SIZE		0x00c
35 #define   LAYER_H_VAL(x)		(((x) & 0x1fff) << 0)
36 #define   LAYER_V_VAL(x)		(((x) & 0x1fff) << 16)
37 #define MALIDP_LAYER_COMP_SIZE		0x010
38 #define MALIDP_LAYER_OFFSET		0x014
39 #define MALIDP_LAYER_STRIDE		0x018
40 
41 /*
42  * This 4-entry look-up-table is used to determine the full 8-bit alpha value
43  * for formats with 1- or 2-bit alpha channels.
44  * We set it to give 100%/0% opacity for 1-bit formats and 100%/66%/33%/0%
45  * opacity for 2-bit formats.
46  */
47 #define MALIDP_ALPHA_LUT 0xffaa5500
48 
49 static void malidp_de_plane_destroy(struct drm_plane *plane)
50 {
51 	struct malidp_plane *mp = to_malidp_plane(plane);
52 
53 	if (mp->base.fb)
54 		drm_framebuffer_unreference(mp->base.fb);
55 
56 	drm_plane_helper_disable(plane);
57 	drm_plane_cleanup(plane);
58 	devm_kfree(plane->dev->dev, mp);
59 }
60 
61 static struct
62 drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane)
63 {
64 	struct malidp_plane_state *state, *m_state;
65 
66 	if (!plane->state)
67 		return NULL;
68 
69 	state = kmalloc(sizeof(*state), GFP_KERNEL);
70 	if (state) {
71 		m_state = to_malidp_plane_state(plane->state);
72 		__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
73 		state->rotmem_size = m_state->rotmem_size;
74 		state->format = m_state->format;
75 		state->n_planes = m_state->n_planes;
76 	}
77 
78 	return &state->base;
79 }
80 
81 static void malidp_destroy_plane_state(struct drm_plane *plane,
82 				       struct drm_plane_state *state)
83 {
84 	struct malidp_plane_state *m_state = to_malidp_plane_state(state);
85 
86 	__drm_atomic_helper_plane_destroy_state(state);
87 	kfree(m_state);
88 }
89 
90 static const struct drm_plane_funcs malidp_de_plane_funcs = {
91 	.update_plane = drm_atomic_helper_update_plane,
92 	.disable_plane = drm_atomic_helper_disable_plane,
93 	.set_property = drm_atomic_helper_plane_set_property,
94 	.destroy = malidp_de_plane_destroy,
95 	.reset = drm_atomic_helper_plane_reset,
96 	.atomic_duplicate_state = malidp_duplicate_plane_state,
97 	.atomic_destroy_state = malidp_destroy_plane_state,
98 };
99 
100 static int malidp_de_plane_check(struct drm_plane *plane,
101 				 struct drm_plane_state *state)
102 {
103 	struct malidp_plane *mp = to_malidp_plane(plane);
104 	struct malidp_plane_state *ms = to_malidp_plane_state(state);
105 	struct drm_framebuffer *fb;
106 	int i;
107 	u32 src_w, src_h;
108 
109 	if (!state->crtc || !state->fb)
110 		return 0;
111 
112 	fb = state->fb;
113 
114 	ms->format = malidp_hw_get_format_id(&mp->hwdev->map, mp->layer->id,
115 					    fb->pixel_format);
116 	if (ms->format == MALIDP_INVALID_FORMAT_ID)
117 		return -EINVAL;
118 
119 	ms->n_planes = drm_format_num_planes(fb->pixel_format);
120 	for (i = 0; i < ms->n_planes; i++) {
121 		if (!malidp_hw_pitch_valid(mp->hwdev, fb->pitches[i])) {
122 			DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
123 				      fb->pitches[i], i);
124 			return -EINVAL;
125 		}
126 	}
127 
128 	src_w = state->src_w >> 16;
129 	src_h = state->src_h >> 16;
130 
131 	if ((state->crtc_w > mp->hwdev->max_line_size) ||
132 	    (state->crtc_h > mp->hwdev->max_line_size) ||
133 	    (state->crtc_w < mp->hwdev->min_line_size) ||
134 	    (state->crtc_h < mp->hwdev->min_line_size) ||
135 	    (state->crtc_w != src_w) || (state->crtc_h != src_h))
136 		return -EINVAL;
137 
138 	/* packed RGB888 / BGR888 can't be rotated or flipped */
139 	if (state->rotation != DRM_ROTATE_0 &&
140 	    (state->fb->pixel_format == DRM_FORMAT_RGB888 ||
141 	     state->fb->pixel_format == DRM_FORMAT_BGR888))
142 		return -EINVAL;
143 
144 	ms->rotmem_size = 0;
145 	if (state->rotation & MALIDP_ROTATED_MASK) {
146 		int val;
147 
148 		val = mp->hwdev->rotmem_required(mp->hwdev, state->crtc_h,
149 						 state->crtc_w,
150 						 state->fb->pixel_format);
151 		if (val < 0)
152 			return val;
153 
154 		ms->rotmem_size = val;
155 	}
156 
157 	return 0;
158 }
159 
160 static void malidp_de_plane_update(struct drm_plane *plane,
161 				   struct drm_plane_state *old_state)
162 {
163 	struct drm_gem_cma_object *obj;
164 	struct malidp_plane *mp;
165 	const struct malidp_hw_regmap *map;
166 	struct malidp_plane_state *ms = to_malidp_plane_state(plane->state);
167 	u16 ptr;
168 	u32 src_w, src_h, dest_w, dest_h, val;
169 	int i;
170 
171 	mp = to_malidp_plane(plane);
172 	map = &mp->hwdev->map;
173 
174 	/* convert src values from Q16 fixed point to integer */
175 	src_w = plane->state->src_w >> 16;
176 	src_h = plane->state->src_h >> 16;
177 	if (plane->state->rotation & MALIDP_ROTATED_MASK) {
178 		dest_w = plane->state->crtc_h;
179 		dest_h = plane->state->crtc_w;
180 	} else {
181 		dest_w = plane->state->crtc_w;
182 		dest_h = plane->state->crtc_h;
183 	}
184 
185 	malidp_hw_write(mp->hwdev, ms->format, mp->layer->base);
186 
187 	for (i = 0; i < ms->n_planes; i++) {
188 		/* calculate the offset for the layer's plane registers */
189 		ptr = mp->layer->ptr + (i << 4);
190 
191 		obj = drm_fb_cma_get_gem_obj(plane->state->fb, i);
192 		malidp_hw_write(mp->hwdev, lower_32_bits(obj->paddr), ptr);
193 		malidp_hw_write(mp->hwdev, upper_32_bits(obj->paddr), ptr + 4);
194 		malidp_hw_write(mp->hwdev, plane->state->fb->pitches[i],
195 				mp->layer->base + MALIDP_LAYER_STRIDE);
196 	}
197 
198 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(src_w) | LAYER_V_VAL(src_h),
199 			mp->layer->base + MALIDP_LAYER_SIZE);
200 
201 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(dest_w) | LAYER_V_VAL(dest_h),
202 			mp->layer->base + MALIDP_LAYER_COMP_SIZE);
203 
204 	malidp_hw_write(mp->hwdev, LAYER_H_VAL(plane->state->crtc_x) |
205 			LAYER_V_VAL(plane->state->crtc_y),
206 			mp->layer->base + MALIDP_LAYER_OFFSET);
207 
208 	/* first clear the rotation bits */
209 	val = malidp_hw_read(mp->hwdev, mp->layer->base + MALIDP_LAYER_CONTROL);
210 	val &= ~LAYER_ROT_MASK;
211 
212 	/* setup the rotation and axis flip bits */
213 	if (plane->state->rotation & DRM_ROTATE_MASK)
214 		val = ilog2(plane->state->rotation & DRM_ROTATE_MASK) << LAYER_ROT_OFFSET;
215 	if (plane->state->rotation & DRM_REFLECT_X)
216 		val |= LAYER_V_FLIP;
217 	if (plane->state->rotation & DRM_REFLECT_Y)
218 		val |= LAYER_H_FLIP;
219 
220 	/*
221 	 * always enable pixel alpha blending until we have a way to change
222 	 * blend modes
223 	 */
224 	val &= ~LAYER_COMP_MASK;
225 	val |= LAYER_COMP_PIXEL;
226 
227 	/* set the 'enable layer' bit */
228 	val |= LAYER_ENABLE;
229 
230 	malidp_hw_write(mp->hwdev, val,
231 			mp->layer->base + MALIDP_LAYER_CONTROL);
232 }
233 
234 static void malidp_de_plane_disable(struct drm_plane *plane,
235 				    struct drm_plane_state *state)
236 {
237 	struct malidp_plane *mp = to_malidp_plane(plane);
238 
239 	malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE,
240 			    mp->layer->base + MALIDP_LAYER_CONTROL);
241 }
242 
243 static const struct drm_plane_helper_funcs malidp_de_plane_helper_funcs = {
244 	.atomic_check = malidp_de_plane_check,
245 	.atomic_update = malidp_de_plane_update,
246 	.atomic_disable = malidp_de_plane_disable,
247 };
248 
249 int malidp_de_planes_init(struct drm_device *drm)
250 {
251 	struct malidp_drm *malidp = drm->dev_private;
252 	const struct malidp_hw_regmap *map = &malidp->dev->map;
253 	struct malidp_plane *plane = NULL;
254 	enum drm_plane_type plane_type;
255 	unsigned long crtcs = 1 << drm->mode_config.num_crtc;
256 	unsigned long flags = DRM_ROTATE_0 | DRM_ROTATE_90 | DRM_ROTATE_180 |
257 			      DRM_ROTATE_270 | DRM_REFLECT_X | DRM_REFLECT_Y;
258 	u32 *formats;
259 	int ret, i, j, n;
260 
261 	formats = kcalloc(map->n_input_formats, sizeof(*formats), GFP_KERNEL);
262 	if (!formats) {
263 		ret = -ENOMEM;
264 		goto cleanup;
265 	}
266 
267 	for (i = 0; i < map->n_layers; i++) {
268 		u8 id = map->layers[i].id;
269 
270 		plane = kzalloc(sizeof(*plane), GFP_KERNEL);
271 		if (!plane) {
272 			ret = -ENOMEM;
273 			goto cleanup;
274 		}
275 
276 		/* build the list of DRM supported formats based on the map */
277 		for (n = 0, j = 0;  j < map->n_input_formats; j++) {
278 			if ((map->input_formats[j].layer & id) == id)
279 				formats[n++] = map->input_formats[j].format;
280 		}
281 
282 		plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY :
283 					DRM_PLANE_TYPE_OVERLAY;
284 		ret = drm_universal_plane_init(drm, &plane->base, crtcs,
285 					       &malidp_de_plane_funcs, formats,
286 					       n, plane_type, NULL);
287 		if (ret < 0)
288 			goto cleanup;
289 
290 		drm_plane_helper_add(&plane->base,
291 				     &malidp_de_plane_helper_funcs);
292 		plane->hwdev = malidp->dev;
293 		plane->layer = &map->layers[i];
294 
295 		/* Skip the features which the SMART layer doesn't have */
296 		if (id == DE_SMART)
297 			continue;
298 
299 		drm_plane_create_rotation_property(&plane->base, DRM_ROTATE_0, flags);
300 		malidp_hw_write(malidp->dev, MALIDP_ALPHA_LUT,
301 				plane->layer->base + MALIDP_LAYER_COMPOSE);
302 	}
303 
304 	kfree(formats);
305 
306 	return 0;
307 
308 cleanup:
309 	malidp_de_planes_destroy(drm);
310 	kfree(formats);
311 
312 	return ret;
313 }
314 
315 void malidp_de_planes_destroy(struct drm_device *drm)
316 {
317 	struct drm_plane *p, *pt;
318 
319 	list_for_each_entry_safe(p, pt, &drm->mode_config.plane_list, head) {
320 		drm_plane_cleanup(p);
321 		kfree(p);
322 	}
323 }
324