xref: /linux/drivers/gpu/drm/loongson/lsdc_plane.c (revision 40288c9206c17eb66a603262e06a58d300d0f279)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2023 Loongson Technology Corporation Limited
4  */
5 
6 #include <linux/delay.h>
7 
8 #include <drm/drm_atomic.h>
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_blend.h>
11 #include <drm/drm_framebuffer.h>
12 #include <drm/drm_gem_atomic_helper.h>
13 #include <drm/drm_print.h>
14 
15 #include "lsdc_drv.h"
16 #include "lsdc_regs.h"
17 #include "lsdc_ttm.h"
18 
19 static const u32 lsdc_primary_formats[] = {
20 	DRM_FORMAT_XRGB8888,
21 };
22 
23 static const u32 lsdc_cursor_formats[] = {
24 	DRM_FORMAT_ARGB8888,
25 };
26 
27 static const u64 lsdc_fb_format_modifiers[] = {
28 	DRM_FORMAT_MOD_LINEAR,
29 	DRM_FORMAT_MOD_INVALID
30 };
31 
lsdc_get_fb_offset(struct drm_framebuffer * fb,struct drm_plane_state * state)32 static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb,
33 				       struct drm_plane_state *state)
34 {
35 	unsigned int offset = fb->offsets[0];
36 
37 	offset += fb->format->cpp[0] * (state->src_x >> 16);
38 	offset += fb->pitches[0] * (state->src_y >> 16);
39 
40 	return offset;
41 }
42 
lsdc_fb_base_addr(struct drm_framebuffer * fb)43 static u64 lsdc_fb_base_addr(struct drm_framebuffer *fb)
44 {
45 	struct lsdc_device *ldev = to_lsdc(fb->dev);
46 	struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]);
47 
48 	return lsdc_bo_gpu_offset(lbo) + ldev->vram_base;
49 }
50 
lsdc_primary_atomic_check(struct drm_plane * plane,struct drm_atomic_commit * state)51 static int lsdc_primary_atomic_check(struct drm_plane *plane,
52 				     struct drm_atomic_commit *state)
53 {
54 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
55 	struct drm_crtc *crtc = new_plane_state->crtc;
56 	struct drm_crtc_state *new_crtc_state;
57 
58 	if (!crtc)
59 		return 0;
60 
61 	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
62 
63 	return drm_atomic_helper_check_plane_state(new_plane_state,
64 						   new_crtc_state,
65 						   DRM_PLANE_NO_SCALING,
66 						   DRM_PLANE_NO_SCALING,
67 						   false, true);
68 }
69 
lsdc_primary_atomic_update(struct drm_plane * plane,struct drm_atomic_commit * state)70 static void lsdc_primary_atomic_update(struct drm_plane *plane,
71 				       struct drm_atomic_commit *state)
72 {
73 	struct lsdc_primary *primary = to_lsdc_primary(plane);
74 	const struct lsdc_primary_plane_ops *ops = primary->ops;
75 	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
76 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
77 	struct drm_framebuffer *new_fb = new_plane_state->fb;
78 	struct drm_framebuffer *old_fb = old_plane_state->fb;
79 	u64 fb_addr = lsdc_fb_base_addr(new_fb);
80 
81 	fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state);
82 
83 	ops->update_fb_addr(primary, fb_addr);
84 	ops->update_fb_stride(primary, new_fb->pitches[0]);
85 
86 	if (!old_fb || old_fb->format != new_fb->format)
87 		ops->update_fb_format(primary, new_fb->format);
88 }
89 
lsdc_primary_atomic_disable(struct drm_plane * plane,struct drm_atomic_commit * state)90 static void lsdc_primary_atomic_disable(struct drm_plane *plane,
91 					struct drm_atomic_commit *state)
92 {
93 	/*
94 	 * Do nothing, just prevent call into atomic_update().
95 	 * Writing the format as LSDC_PF_NONE can disable the primary,
96 	 * But it seems not necessary...
97 	 */
98 	drm_dbg(plane->dev, "%s disabled\n", plane->name);
99 }
100 
lsdc_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * new_state)101 static int lsdc_plane_prepare_fb(struct drm_plane *plane,
102 				 struct drm_plane_state *new_state)
103 {
104 	struct drm_framebuffer *fb = new_state->fb;
105 	struct lsdc_bo *lbo;
106 	u64 gpu_vaddr;
107 	int ret;
108 
109 	if (!fb)
110 		return 0;
111 
112 	lbo = gem_to_lsdc_bo(fb->obj[0]);
113 
114 	ret = lsdc_bo_reserve(lbo);
115 	if (unlikely(ret)) {
116 		drm_err(plane->dev, "bo %p reserve failed\n", lbo);
117 		return ret;
118 	}
119 
120 	ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr);
121 
122 	lsdc_bo_unreserve(lbo);
123 
124 	if (unlikely(ret)) {
125 		drm_err(plane->dev, "bo %p pin failed\n", lbo);
126 		return ret;
127 	}
128 
129 	lsdc_bo_ref(lbo);
130 
131 	if (plane->type != DRM_PLANE_TYPE_CURSOR)
132 		drm_dbg(plane->dev,
133 			"%s[%p] pin at 0x%llx, bo size: %zu\n",
134 			plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo));
135 
136 	return drm_gem_plane_helper_prepare_fb(plane, new_state);
137 }
138 
lsdc_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * old_state)139 static void lsdc_plane_cleanup_fb(struct drm_plane *plane,
140 				  struct drm_plane_state *old_state)
141 {
142 	struct drm_framebuffer *fb = old_state->fb;
143 	struct lsdc_bo *lbo;
144 	int ret;
145 
146 	if (!fb)
147 		return;
148 
149 	lbo = gem_to_lsdc_bo(fb->obj[0]);
150 
151 	ret = lsdc_bo_reserve(lbo);
152 	if (unlikely(ret)) {
153 		drm_err(plane->dev, "%p reserve failed\n", lbo);
154 		return;
155 	}
156 
157 	lsdc_bo_unpin(lbo);
158 
159 	lsdc_bo_unreserve(lbo);
160 
161 	lsdc_bo_unref(lbo);
162 
163 	if (plane->type != DRM_PLANE_TYPE_CURSOR)
164 		drm_dbg(plane->dev, "%s unpin\n", plane->name);
165 }
166 
167 static const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = {
168 	.prepare_fb = lsdc_plane_prepare_fb,
169 	.cleanup_fb = lsdc_plane_cleanup_fb,
170 	.atomic_check = lsdc_primary_atomic_check,
171 	.atomic_update = lsdc_primary_atomic_update,
172 	.atomic_disable = lsdc_primary_atomic_disable,
173 };
174 
lsdc_cursor_plane_atomic_async_check(struct drm_plane * plane,struct drm_atomic_commit * state,bool flip)175 static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane,
176 						struct drm_atomic_commit *state,
177 						bool flip)
178 {
179 	struct drm_plane_state *new_state;
180 	struct drm_crtc_state *crtc_state;
181 
182 	new_state = drm_atomic_get_new_plane_state(state, plane);
183 
184 	if (!plane->state || !plane->state->fb) {
185 		drm_dbg(plane->dev, "%s: state is NULL\n", plane->name);
186 		return -EINVAL;
187 	}
188 
189 	if (new_state->crtc_w != new_state->crtc_h) {
190 		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
191 			new_state->crtc_w, new_state->crtc_h);
192 		return -EINVAL;
193 	}
194 
195 	if (new_state->crtc_w != 64 && new_state->crtc_w != 32) {
196 		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
197 			new_state->crtc_w, new_state->crtc_h);
198 		return -EINVAL;
199 	}
200 
201 	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
202 	if (!crtc_state->active)
203 		return -EINVAL;
204 
205 	if (plane->state->crtc != new_state->crtc ||
206 	    plane->state->src_w != new_state->src_w ||
207 	    plane->state->src_h != new_state->src_h ||
208 	    plane->state->crtc_w != new_state->crtc_w ||
209 	    plane->state->crtc_h != new_state->crtc_h)
210 		return -EINVAL;
211 
212 	if (new_state->visible != plane->state->visible)
213 		return -EINVAL;
214 
215 	return drm_atomic_helper_check_plane_state(plane->state,
216 						   crtc_state,
217 						   DRM_PLANE_NO_SCALING,
218 						   DRM_PLANE_NO_SCALING,
219 						   true, true);
220 }
221 
lsdc_cursor_plane_atomic_async_update(struct drm_plane * plane,struct drm_atomic_commit * state)222 static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane,
223 						  struct drm_atomic_commit *state)
224 {
225 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
226 	const struct lsdc_cursor_plane_ops *ops = cursor->ops;
227 	struct drm_framebuffer *old_fb = plane->state->fb;
228 	struct drm_framebuffer *new_fb;
229 	struct drm_plane_state *new_state;
230 
231 	new_state = drm_atomic_get_new_plane_state(state, plane);
232 
233 	new_fb = plane->state->fb;
234 
235 	plane->state->crtc_x = new_state->crtc_x;
236 	plane->state->crtc_y = new_state->crtc_y;
237 	plane->state->crtc_h = new_state->crtc_h;
238 	plane->state->crtc_w = new_state->crtc_w;
239 	plane->state->src_x = new_state->src_x;
240 	plane->state->src_y = new_state->src_y;
241 	plane->state->src_h = new_state->src_h;
242 	plane->state->src_w = new_state->src_w;
243 	swap(plane->state->fb, new_state->fb);
244 
245 	if (new_state->visible) {
246 		enum lsdc_cursor_size cursor_size;
247 
248 		switch (new_state->crtc_w) {
249 		case 64:
250 			cursor_size = CURSOR_SIZE_64X64;
251 			break;
252 		case 32:
253 			cursor_size = CURSOR_SIZE_32X32;
254 			break;
255 		default:
256 			cursor_size = CURSOR_SIZE_32X32;
257 			break;
258 		}
259 
260 		ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y);
261 
262 		ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
263 
264 		if (!old_fb || old_fb != new_fb)
265 			ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb));
266 	}
267 }
268 
269 /* ls7a1000 cursor plane helpers */
270 
ls7a1000_cursor_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_commit * state)271 static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane,
272 					      struct drm_atomic_commit *state)
273 {
274 	struct drm_plane_state *new_plane_state;
275 	struct drm_crtc_state *new_crtc_state;
276 	struct drm_crtc *crtc;
277 
278 	new_plane_state = drm_atomic_get_new_plane_state(state, plane);
279 
280 	crtc = new_plane_state->crtc;
281 	if (!crtc) {
282 		drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
283 		return 0;
284 	}
285 
286 	if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) {
287 		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
288 			new_plane_state->crtc_w, new_plane_state->crtc_h);
289 		return -EINVAL;
290 	}
291 
292 	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
293 
294 	return drm_atomic_helper_check_plane_state(new_plane_state,
295 						   new_crtc_state,
296 						   DRM_PLANE_NO_SCALING,
297 						   DRM_PLANE_NO_SCALING,
298 						   true, true);
299 }
300 
ls7a1000_cursor_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_commit * state)301 static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane,
302 						struct drm_atomic_commit *state)
303 {
304 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
305 	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
306 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
307 	struct drm_framebuffer *new_fb = new_plane_state->fb;
308 	struct drm_framebuffer *old_fb = old_plane_state->fb;
309 	const struct lsdc_cursor_plane_ops *ops = cursor->ops;
310 	u64 addr = lsdc_fb_base_addr(new_fb);
311 
312 	if (!new_plane_state->visible)
313 		return;
314 
315 	ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
316 
317 	if (!old_fb || old_fb != new_fb)
318 		ops->update_bo_addr(cursor, addr);
319 
320 	ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888);
321 }
322 
ls7a1000_cursor_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_commit * state)323 static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane,
324 						 struct drm_atomic_commit *state)
325 {
326 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
327 	const struct lsdc_cursor_plane_ops *ops = cursor->ops;
328 
329 	ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE);
330 }
331 
332 static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = {
333 	.prepare_fb = lsdc_plane_prepare_fb,
334 	.cleanup_fb = lsdc_plane_cleanup_fb,
335 	.atomic_check = ls7a1000_cursor_plane_atomic_check,
336 	.atomic_update = ls7a1000_cursor_plane_atomic_update,
337 	.atomic_disable = ls7a1000_cursor_plane_atomic_disable,
338 	.atomic_async_check = lsdc_cursor_plane_atomic_async_check,
339 	.atomic_async_update = lsdc_cursor_plane_atomic_async_update,
340 };
341 
342 /* ls7a2000 cursor plane helpers */
343 
ls7a2000_cursor_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_commit * state)344 static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane,
345 					      struct drm_atomic_commit *state)
346 {
347 	struct drm_plane_state *new_plane_state;
348 	struct drm_crtc_state *new_crtc_state;
349 	struct drm_crtc *crtc;
350 
351 	new_plane_state = drm_atomic_get_new_plane_state(state, plane);
352 
353 	crtc = new_plane_state->crtc;
354 	if (!crtc) {
355 		drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
356 		return 0;
357 	}
358 
359 	if (new_plane_state->crtc_w != new_plane_state->crtc_h) {
360 		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
361 			new_plane_state->crtc_w, new_plane_state->crtc_h);
362 		return -EINVAL;
363 	}
364 
365 	if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) {
366 		drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
367 			new_plane_state->crtc_w, new_plane_state->crtc_h);
368 		return -EINVAL;
369 	}
370 
371 	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
372 
373 	return drm_atomic_helper_check_plane_state(new_plane_state,
374 						   new_crtc_state,
375 						   DRM_PLANE_NO_SCALING,
376 						   DRM_PLANE_NO_SCALING,
377 						   true, true);
378 }
379 
380 /* Update the format, size and location of the cursor */
381 
ls7a2000_cursor_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_commit * state)382 static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane,
383 						struct drm_atomic_commit *state)
384 {
385 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
386 	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
387 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
388 	struct drm_framebuffer *new_fb = new_plane_state->fb;
389 	struct drm_framebuffer *old_fb = old_plane_state->fb;
390 	const struct lsdc_cursor_plane_ops *ops = cursor->ops;
391 	enum lsdc_cursor_size cursor_size;
392 
393 	if (!new_plane_state->visible)
394 		return;
395 
396 	ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
397 
398 	if (!old_fb || new_fb != old_fb) {
399 		u64 addr = lsdc_fb_base_addr(new_fb);
400 
401 		ops->update_bo_addr(cursor, addr);
402 	}
403 
404 	switch (new_plane_state->crtc_w) {
405 	case 64:
406 		cursor_size = CURSOR_SIZE_64X64;
407 		break;
408 	case 32:
409 		cursor_size = CURSOR_SIZE_32X32;
410 		break;
411 	default:
412 		cursor_size = CURSOR_SIZE_64X64;
413 		break;
414 	}
415 
416 	ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
417 }
418 
ls7a2000_cursor_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_commit * state)419 static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane,
420 						 struct drm_atomic_commit *state)
421 {
422 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
423 	const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops;
424 
425 	hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE);
426 }
427 
428 static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = {
429 	.prepare_fb = lsdc_plane_prepare_fb,
430 	.cleanup_fb = lsdc_plane_cleanup_fb,
431 	.atomic_check = ls7a2000_cursor_plane_atomic_check,
432 	.atomic_update = ls7a2000_cursor_plane_atomic_update,
433 	.atomic_disable = ls7a2000_cursor_plane_atomic_disable,
434 	.atomic_async_check = lsdc_cursor_plane_atomic_async_check,
435 	.atomic_async_update = lsdc_cursor_plane_atomic_async_update,
436 };
437 
lsdc_plane_atomic_print_state(struct drm_printer * p,const struct drm_plane_state * state)438 static void lsdc_plane_atomic_print_state(struct drm_printer *p,
439 					  const struct drm_plane_state *state)
440 {
441 	struct drm_framebuffer *fb = state->fb;
442 	u64 addr;
443 
444 	if (!fb)
445 		return;
446 
447 	addr = lsdc_fb_base_addr(fb);
448 
449 	drm_printf(p, "\tdma addr=%llx\n", addr);
450 }
451 
452 static const struct drm_plane_funcs lsdc_plane_funcs = {
453 	.update_plane = drm_atomic_helper_update_plane,
454 	.disable_plane = drm_atomic_helper_disable_plane,
455 	.destroy = drm_plane_cleanup,
456 	.reset = drm_atomic_helper_plane_reset,
457 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
458 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
459 	.atomic_print_state = lsdc_plane_atomic_print_state,
460 };
461 
462 /* Primary plane 0 hardware related ops  */
463 
lsdc_primary0_update_fb_addr(struct lsdc_primary * primary,u64 addr)464 static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr)
465 {
466 	struct lsdc_device *ldev = primary->ldev;
467 	u32 status;
468 	u32 lo, hi;
469 
470 	/* 40-bit width physical address bus */
471 	lo = addr & 0xFFFFFFFF;
472 	hi = (addr >> 32) & 0xFF;
473 
474 	status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
475 	if (status & FB_REG_IN_USING) {
476 		lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo);
477 		lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi);
478 	} else {
479 		lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo);
480 		lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi);
481 	}
482 }
483 
lsdc_primary0_update_fb_stride(struct lsdc_primary * primary,u32 stride)484 static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride)
485 {
486 	struct lsdc_device *ldev = primary->ldev;
487 
488 	lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride);
489 }
490 
lsdc_primary0_update_fb_format(struct lsdc_primary * primary,const struct drm_format_info * format)491 static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary,
492 					   const struct drm_format_info *format)
493 {
494 	struct lsdc_device *ldev = primary->ldev;
495 	u32 status;
496 
497 	status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
498 
499 	/*
500 	 * TODO: add RGB565 support, only support XRBG8888 at present
501 	 */
502 	status &= ~CFG_PIX_FMT_MASK;
503 	status |= LSDC_PF_XRGB8888;
504 
505 	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status);
506 }
507 
508 /* Primary plane 1 hardware related ops */
509 
lsdc_primary1_update_fb_addr(struct lsdc_primary * primary,u64 addr)510 static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr)
511 {
512 	struct lsdc_device *ldev = primary->ldev;
513 	u32 status;
514 	u32 lo, hi;
515 
516 	/* 40-bit width physical address bus */
517 	lo = addr & 0xFFFFFFFF;
518 	hi = (addr >> 32) & 0xFF;
519 
520 	status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
521 	if (status & FB_REG_IN_USING) {
522 		lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo);
523 		lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi);
524 	} else {
525 		lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo);
526 		lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi);
527 	}
528 }
529 
lsdc_primary1_update_fb_stride(struct lsdc_primary * primary,u32 stride)530 static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride)
531 {
532 	struct lsdc_device *ldev = primary->ldev;
533 
534 	lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride);
535 }
536 
lsdc_primary1_update_fb_format(struct lsdc_primary * primary,const struct drm_format_info * format)537 static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary,
538 					   const struct drm_format_info *format)
539 {
540 	struct lsdc_device *ldev = primary->ldev;
541 	u32 status;
542 
543 	status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
544 
545 	/*
546 	 * TODO: add RGB565 support, only support XRBG8888 at present
547 	 */
548 	status &= ~CFG_PIX_FMT_MASK;
549 	status |= LSDC_PF_XRGB8888;
550 
551 	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status);
552 }
553 
554 static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = {
555 	{
556 		.update_fb_addr = lsdc_primary0_update_fb_addr,
557 		.update_fb_stride = lsdc_primary0_update_fb_stride,
558 		.update_fb_format = lsdc_primary0_update_fb_format,
559 	},
560 	{
561 		.update_fb_addr = lsdc_primary1_update_fb_addr,
562 		.update_fb_stride = lsdc_primary1_update_fb_stride,
563 		.update_fb_format = lsdc_primary1_update_fb_format,
564 	},
565 };
566 
567 /*
568  * Update location, format, enable and disable state of the cursor,
569  * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0,
570  * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor
571  * plane is automatically done by hardware, the cursor is alway on the top of
572  * the primary plane. In other word, z-order is fixed in hardware and cannot
573  * be changed. For those old DC who has only one hardware cursor, we made it
574  * shared by the two screen, this works on extend screen mode.
575  */
576 
577 /* cursor plane 0 (for pipe 0) related hardware ops */
578 
lsdc_cursor0_update_bo_addr(struct lsdc_cursor * cursor,u64 addr)579 static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
580 {
581 	struct lsdc_device *ldev = cursor->ldev;
582 
583 	/* 40-bit width physical address bus */
584 	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
585 	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
586 }
587 
lsdc_cursor0_update_position(struct lsdc_cursor * cursor,int x,int y)588 static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y)
589 {
590 	struct lsdc_device *ldev = cursor->ldev;
591 
592 	if (x < 0)
593 		x = 0;
594 
595 	if (y < 0)
596 		y = 0;
597 
598 	lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
599 }
600 
lsdc_cursor0_update_cfg(struct lsdc_cursor * cursor,enum lsdc_cursor_size cursor_size,enum lsdc_cursor_format fmt)601 static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor,
602 				    enum lsdc_cursor_size cursor_size,
603 				    enum lsdc_cursor_format fmt)
604 {
605 	struct lsdc_device *ldev = cursor->ldev;
606 	u32 cfg;
607 
608 	cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT |
609 	      cursor_size << CURSOR_SIZE_SHIFT |
610 	      fmt << CURSOR_FORMAT_SHIFT;
611 
612 	lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
613 }
614 
615 /* cursor plane 1 (for pipe 1) related hardware ops */
616 
lsdc_cursor1_update_bo_addr(struct lsdc_cursor * cursor,u64 addr)617 static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
618 {
619 	struct lsdc_device *ldev = cursor->ldev;
620 
621 	/* 40-bit width physical address bus */
622 	lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF);
623 	lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr);
624 }
625 
lsdc_cursor1_update_position(struct lsdc_cursor * cursor,int x,int y)626 static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y)
627 {
628 	struct lsdc_device *ldev = cursor->ldev;
629 
630 	if (x < 0)
631 		x = 0;
632 
633 	if (y < 0)
634 		y = 0;
635 
636 	lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x);
637 }
638 
lsdc_cursor1_update_cfg(struct lsdc_cursor * cursor,enum lsdc_cursor_size cursor_size,enum lsdc_cursor_format fmt)639 static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor,
640 				    enum lsdc_cursor_size cursor_size,
641 				    enum lsdc_cursor_format fmt)
642 {
643 	struct lsdc_device *ldev = cursor->ldev;
644 	u32 cfg;
645 
646 	cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
647 	      cursor_size << CURSOR_SIZE_SHIFT |
648 	      fmt << CURSOR_FORMAT_SHIFT;
649 
650 	lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg);
651 }
652 
653 /* The hardware cursors become normal since ls7a2000/ls2k2000 */
654 
655 static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = {
656 	{
657 		.update_bo_addr = lsdc_cursor0_update_bo_addr,
658 		.update_cfg = lsdc_cursor0_update_cfg,
659 		.update_position = lsdc_cursor0_update_position,
660 	},
661 	{
662 		.update_bo_addr = lsdc_cursor1_update_bo_addr,
663 		.update_cfg = lsdc_cursor1_update_cfg,
664 		.update_position = lsdc_cursor1_update_position,
665 	},
666 };
667 
668 /* Quirks for cursor 1, only for old loongson display controller */
669 
lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor * cursor,u64 addr)670 static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr)
671 {
672 	struct lsdc_device *ldev = cursor->ldev;
673 
674 	/* 40-bit width physical address bus */
675 	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
676 	lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
677 }
678 
lsdc_cursor1_update_position_quirk(struct lsdc_cursor * cursor,int x,int y)679 static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y)
680 {
681 	struct lsdc_device *ldev = cursor->ldev;
682 
683 	if (x < 0)
684 		x = 0;
685 
686 	if (y < 0)
687 		y = 0;
688 
689 	lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
690 }
691 
lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor * cursor,enum lsdc_cursor_size cursor_size,enum lsdc_cursor_format fmt)692 static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor,
693 					  enum lsdc_cursor_size cursor_size,
694 					  enum lsdc_cursor_format fmt)
695 {
696 	struct lsdc_device *ldev = cursor->ldev;
697 	u32 cfg;
698 
699 	cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
700 	      cursor_size << CURSOR_SIZE_SHIFT |
701 	      fmt << CURSOR_FORMAT_SHIFT;
702 
703 	lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
704 }
705 
706 /*
707  * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane
708  */
709 static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = {
710 	{
711 		.update_bo_addr = lsdc_cursor0_update_bo_addr,
712 		.update_cfg = lsdc_cursor0_update_cfg,
713 		.update_position = lsdc_cursor0_update_position,
714 	},
715 	{
716 		.update_bo_addr = lsdc_cursor1_update_bo_addr_quirk,
717 		.update_cfg = lsdc_cursor1_update_cfg_quirk,
718 		.update_position = lsdc_cursor1_update_position_quirk,
719 	},
720 };
721 
lsdc_primary_plane_init(struct drm_device * ddev,struct drm_plane * plane,unsigned int index)722 int lsdc_primary_plane_init(struct drm_device *ddev,
723 			    struct drm_plane *plane,
724 			    unsigned int index)
725 {
726 	struct lsdc_primary *primary = to_lsdc_primary(plane);
727 	int ret;
728 
729 	ret = drm_universal_plane_init(ddev, plane, 1 << index,
730 				       &lsdc_plane_funcs,
731 				       lsdc_primary_formats,
732 				       ARRAY_SIZE(lsdc_primary_formats),
733 				       lsdc_fb_format_modifiers,
734 				       DRM_PLANE_TYPE_PRIMARY,
735 				       "ls-primary-plane-%u", index);
736 	if (ret)
737 		return ret;
738 
739 	drm_plane_helper_add(plane, &lsdc_primary_helper_funcs);
740 
741 	primary->ldev = to_lsdc(ddev);
742 	primary->ops = &lsdc_primary_plane_hw_ops[index];
743 
744 	return 0;
745 }
746 
ls7a1000_cursor_plane_init(struct drm_device * ddev,struct drm_plane * plane,unsigned int index)747 int ls7a1000_cursor_plane_init(struct drm_device *ddev,
748 			       struct drm_plane *plane,
749 			       unsigned int index)
750 {
751 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
752 	int ret;
753 
754 	ret = drm_universal_plane_init(ddev, plane, 1 << index,
755 				       &lsdc_plane_funcs,
756 				       lsdc_cursor_formats,
757 				       ARRAY_SIZE(lsdc_cursor_formats),
758 				       lsdc_fb_format_modifiers,
759 				       DRM_PLANE_TYPE_CURSOR,
760 				       "ls-cursor-plane-%u", index);
761 	if (ret)
762 		return ret;
763 
764 	cursor->ldev = to_lsdc(ddev);
765 	cursor->ops = &ls7a1000_cursor_hw_ops[index];
766 
767 	drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs);
768 
769 	return drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE));
770 }
771 
ls7a2000_cursor_plane_init(struct drm_device * ddev,struct drm_plane * plane,unsigned int index)772 int ls7a2000_cursor_plane_init(struct drm_device *ddev,
773 			       struct drm_plane *plane,
774 			       unsigned int index)
775 {
776 	struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
777 	int ret;
778 
779 	ret = drm_universal_plane_init(ddev, plane, 1 << index,
780 				       &lsdc_plane_funcs,
781 				       lsdc_cursor_formats,
782 				       ARRAY_SIZE(lsdc_cursor_formats),
783 				       lsdc_fb_format_modifiers,
784 				       DRM_PLANE_TYPE_CURSOR,
785 				       "ls-cursor-plane-%u", index);
786 	if (ret)
787 		return ret;
788 
789 	cursor->ldev = to_lsdc(ddev);
790 	cursor->ops = &ls7a2000_cursor_hw_ops[index];
791 
792 	drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs);
793 
794 	return drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE));
795 }
796