xref: /linux/drivers/gpu/drm/loongson/lsdc_crtc.c (revision 1553a1c48281243359a9529a10ddb551f3b967ab)
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_debugfs.h>
11 #include <drm/drm_vblank.h>
12 
13 #include "lsdc_drv.h"
14 
15 /*
16  * After the CRTC soft reset, the vblank counter would be reset to zero.
17  * But the address and other settings in the CRTC register remain the same
18  * as before.
19  */
20 
21 static void lsdc_crtc0_soft_reset(struct lsdc_crtc *lcrtc)
22 {
23 	struct lsdc_device *ldev = lcrtc->ldev;
24 	u32 val;
25 
26 	val = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
27 
28 	val &= CFG_VALID_BITS_MASK;
29 
30 	/* Soft reset bit, active low */
31 	val &= ~CFG_RESET_N;
32 
33 	val &= ~CFG_PIX_FMT_MASK;
34 
35 	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val);
36 
37 	udelay(1);
38 
39 	val |= CFG_RESET_N | LSDC_PF_XRGB8888 | CFG_OUTPUT_ENABLE;
40 
41 	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val);
42 
43 	/* Wait about a vblank time */
44 	mdelay(20);
45 }
46 
47 static void lsdc_crtc1_soft_reset(struct lsdc_crtc *lcrtc)
48 {
49 	struct lsdc_device *ldev = lcrtc->ldev;
50 	u32 val;
51 
52 	val = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
53 
54 	val &= CFG_VALID_BITS_MASK;
55 
56 	/* Soft reset bit, active low */
57 	val &= ~CFG_RESET_N;
58 
59 	val &= ~CFG_PIX_FMT_MASK;
60 
61 	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val);
62 
63 	udelay(1);
64 
65 	val |= CFG_RESET_N | LSDC_PF_XRGB8888 | CFG_OUTPUT_ENABLE;
66 
67 	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val);
68 
69 	/* Wait about a vblank time */
70 	msleep(20);
71 }
72 
73 static void lsdc_crtc0_enable(struct lsdc_crtc *lcrtc)
74 {
75 	struct lsdc_device *ldev = lcrtc->ldev;
76 	u32 val;
77 
78 	val = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
79 
80 	/*
81 	 * This may happen in extremely rare cases, but a soft reset can
82 	 * bring it back to normal. We add a warning here, hoping to catch
83 	 * something if it happens.
84 	 */
85 	if (val & CRTC_ANCHORED) {
86 		drm_warn(&ldev->base, "%s stall\n", lcrtc->base.name);
87 		return lsdc_crtc0_soft_reset(lcrtc);
88 	}
89 
90 	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val | CFG_OUTPUT_ENABLE);
91 }
92 
93 static void lsdc_crtc0_disable(struct lsdc_crtc *lcrtc)
94 {
95 	struct lsdc_device *ldev = lcrtc->ldev;
96 
97 	lsdc_ureg32_clr(ldev, LSDC_CRTC0_CFG_REG, CFG_OUTPUT_ENABLE);
98 
99 	udelay(9);
100 }
101 
102 static void lsdc_crtc1_enable(struct lsdc_crtc *lcrtc)
103 {
104 	struct lsdc_device *ldev = lcrtc->ldev;
105 	u32 val;
106 
107 	/*
108 	 * This may happen in extremely rare cases, but a soft reset can
109 	 * bring it back to normal. We add a warning here, hoping to catch
110 	 * something if it happens.
111 	 */
112 	val = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
113 	if (val & CRTC_ANCHORED) {
114 		drm_warn(&ldev->base, "%s stall\n", lcrtc->base.name);
115 		return lsdc_crtc1_soft_reset(lcrtc);
116 	}
117 
118 	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val | CFG_OUTPUT_ENABLE);
119 }
120 
121 static void lsdc_crtc1_disable(struct lsdc_crtc *lcrtc)
122 {
123 	struct lsdc_device *ldev = lcrtc->ldev;
124 
125 	lsdc_ureg32_clr(ldev, LSDC_CRTC1_CFG_REG, CFG_OUTPUT_ENABLE);
126 
127 	udelay(9);
128 }
129 
130 /* All Loongson display controllers have hardware scanout position recoders */
131 
132 static void lsdc_crtc0_scan_pos(struct lsdc_crtc *lcrtc, int *hpos, int *vpos)
133 {
134 	struct lsdc_device *ldev = lcrtc->ldev;
135 	u32 val;
136 
137 	val = lsdc_rreg32(ldev, LSDC_CRTC0_SCAN_POS_REG);
138 
139 	*hpos = val >> 16;
140 	*vpos = val & 0xffff;
141 }
142 
143 static void lsdc_crtc1_scan_pos(struct lsdc_crtc *lcrtc, int *hpos, int *vpos)
144 {
145 	struct lsdc_device *ldev = lcrtc->ldev;
146 	u32 val;
147 
148 	val = lsdc_rreg32(ldev, LSDC_CRTC1_SCAN_POS_REG);
149 
150 	*hpos = val >> 16;
151 	*vpos = val & 0xffff;
152 }
153 
154 static void lsdc_crtc0_enable_vblank(struct lsdc_crtc *lcrtc)
155 {
156 	struct lsdc_device *ldev = lcrtc->ldev;
157 
158 	lsdc_ureg32_set(ldev, LSDC_INT_REG, INT_CRTC0_VSYNC_EN);
159 }
160 
161 static void lsdc_crtc0_disable_vblank(struct lsdc_crtc *lcrtc)
162 {
163 	struct lsdc_device *ldev = lcrtc->ldev;
164 
165 	lsdc_ureg32_clr(ldev, LSDC_INT_REG, INT_CRTC0_VSYNC_EN);
166 }
167 
168 static void lsdc_crtc1_enable_vblank(struct lsdc_crtc *lcrtc)
169 {
170 	struct lsdc_device *ldev = lcrtc->ldev;
171 
172 	lsdc_ureg32_set(ldev, LSDC_INT_REG, INT_CRTC1_VSYNC_EN);
173 }
174 
175 static void lsdc_crtc1_disable_vblank(struct lsdc_crtc *lcrtc)
176 {
177 	struct lsdc_device *ldev = lcrtc->ldev;
178 
179 	lsdc_ureg32_clr(ldev, LSDC_INT_REG, INT_CRTC1_VSYNC_EN);
180 }
181 
182 static void lsdc_crtc0_flip(struct lsdc_crtc *lcrtc)
183 {
184 	struct lsdc_device *ldev = lcrtc->ldev;
185 
186 	lsdc_ureg32_set(ldev, LSDC_CRTC0_CFG_REG, CFG_PAGE_FLIP);
187 }
188 
189 static void lsdc_crtc1_flip(struct lsdc_crtc *lcrtc)
190 {
191 	struct lsdc_device *ldev = lcrtc->ldev;
192 
193 	lsdc_ureg32_set(ldev, LSDC_CRTC1_CFG_REG, CFG_PAGE_FLIP);
194 }
195 
196 /*
197  * CRTC0 clone from CRTC1 or CRTC1 clone from CRTC0 using hardware logic
198  * This may be useful for custom cloning (TWIN) applications. Saving the
199  * bandwidth compared with the clone (mirroring) display mode provided by
200  * drm core.
201  */
202 
203 static void lsdc_crtc0_clone(struct lsdc_crtc *lcrtc)
204 {
205 	struct lsdc_device *ldev = lcrtc->ldev;
206 
207 	lsdc_ureg32_set(ldev, LSDC_CRTC0_CFG_REG, CFG_HW_CLONE);
208 }
209 
210 static void lsdc_crtc1_clone(struct lsdc_crtc *lcrtc)
211 {
212 	struct lsdc_device *ldev = lcrtc->ldev;
213 
214 	lsdc_ureg32_set(ldev, LSDC_CRTC1_CFG_REG, CFG_HW_CLONE);
215 }
216 
217 static void lsdc_crtc0_set_mode(struct lsdc_crtc *lcrtc,
218 				const struct drm_display_mode *mode)
219 {
220 	struct lsdc_device *ldev = lcrtc->ldev;
221 
222 	lsdc_wreg32(ldev, LSDC_CRTC0_HDISPLAY_REG,
223 		    (mode->crtc_htotal << 16) | mode->crtc_hdisplay);
224 
225 	lsdc_wreg32(ldev, LSDC_CRTC0_VDISPLAY_REG,
226 		    (mode->crtc_vtotal << 16) | mode->crtc_vdisplay);
227 
228 	lsdc_wreg32(ldev, LSDC_CRTC0_HSYNC_REG,
229 		    (mode->crtc_hsync_end << 16) | mode->crtc_hsync_start | HSYNC_EN);
230 
231 	lsdc_wreg32(ldev, LSDC_CRTC0_VSYNC_REG,
232 		    (mode->crtc_vsync_end << 16) | mode->crtc_vsync_start | VSYNC_EN);
233 }
234 
235 static void lsdc_crtc1_set_mode(struct lsdc_crtc *lcrtc,
236 				const struct drm_display_mode *mode)
237 {
238 	struct lsdc_device *ldev = lcrtc->ldev;
239 
240 	lsdc_wreg32(ldev, LSDC_CRTC1_HDISPLAY_REG,
241 		    (mode->crtc_htotal << 16) | mode->crtc_hdisplay);
242 
243 	lsdc_wreg32(ldev, LSDC_CRTC1_VDISPLAY_REG,
244 		    (mode->crtc_vtotal << 16) | mode->crtc_vdisplay);
245 
246 	lsdc_wreg32(ldev, LSDC_CRTC1_HSYNC_REG,
247 		    (mode->crtc_hsync_end << 16) | mode->crtc_hsync_start | HSYNC_EN);
248 
249 	lsdc_wreg32(ldev, LSDC_CRTC1_VSYNC_REG,
250 		    (mode->crtc_vsync_end << 16) | mode->crtc_vsync_start | VSYNC_EN);
251 }
252 
253 /*
254  * This is required for S3 support.
255  * After resuming from suspend, LSDC_CRTCx_CFG_REG (x = 0 or 1) is filled
256  * with garbage value, which causes the CRTC hang there.
257  *
258  * This function provides minimal settings for the affected registers.
259  * This overrides the firmware's settings on startup, making the CRTC work
260  * on our own, similar to the functional of GPU POST (Power On Self Test).
261  * Only touch CRTC hardware-related parts.
262  */
263 
264 static void lsdc_crtc0_reset(struct lsdc_crtc *lcrtc)
265 {
266 	struct lsdc_device *ldev = lcrtc->ldev;
267 
268 	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, CFG_RESET_N | LSDC_PF_XRGB8888);
269 }
270 
271 static void lsdc_crtc1_reset(struct lsdc_crtc *lcrtc)
272 {
273 	struct lsdc_device *ldev = lcrtc->ldev;
274 
275 	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, CFG_RESET_N | LSDC_PF_XRGB8888);
276 }
277 
278 static const struct lsdc_crtc_hw_ops ls7a1000_crtc_hw_ops[2] = {
279 	{
280 		.enable = lsdc_crtc0_enable,
281 		.disable = lsdc_crtc0_disable,
282 		.enable_vblank = lsdc_crtc0_enable_vblank,
283 		.disable_vblank = lsdc_crtc0_disable_vblank,
284 		.flip = lsdc_crtc0_flip,
285 		.clone = lsdc_crtc0_clone,
286 		.set_mode = lsdc_crtc0_set_mode,
287 		.get_scan_pos = lsdc_crtc0_scan_pos,
288 		.soft_reset = lsdc_crtc0_soft_reset,
289 		.reset = lsdc_crtc0_reset,
290 	},
291 	{
292 		.enable = lsdc_crtc1_enable,
293 		.disable = lsdc_crtc1_disable,
294 		.enable_vblank = lsdc_crtc1_enable_vblank,
295 		.disable_vblank = lsdc_crtc1_disable_vblank,
296 		.flip = lsdc_crtc1_flip,
297 		.clone = lsdc_crtc1_clone,
298 		.set_mode = lsdc_crtc1_set_mode,
299 		.get_scan_pos = lsdc_crtc1_scan_pos,
300 		.soft_reset = lsdc_crtc1_soft_reset,
301 		.reset = lsdc_crtc1_reset,
302 	},
303 };
304 
305 /*
306  * The 32-bit hardware vblank counter has been available since LS7A2000
307  * and LS2K2000. The counter increases even though the CRTC is disabled,
308  * it will be reset only if the CRTC is being soft reset.
309  * Those registers are also readable for ls7a1000, but its value does not
310  * change.
311  */
312 
313 static u32 lsdc_crtc0_get_vblank_count(struct lsdc_crtc *lcrtc)
314 {
315 	struct lsdc_device *ldev = lcrtc->ldev;
316 
317 	return lsdc_rreg32(ldev, LSDC_CRTC0_VSYNC_COUNTER_REG);
318 }
319 
320 static u32 lsdc_crtc1_get_vblank_count(struct lsdc_crtc *lcrtc)
321 {
322 	struct lsdc_device *ldev = lcrtc->ldev;
323 
324 	return lsdc_rreg32(ldev, LSDC_CRTC1_VSYNC_COUNTER_REG);
325 }
326 
327 /*
328  * The DMA step bit fields are available since LS7A2000/LS2K2000, for
329  * supporting odd resolutions. But a large DMA step save the bandwidth.
330  * The larger, the better. Behavior of writing those bits on LS7A1000
331  * or LS2K1000 is underfined.
332  */
333 
334 static void lsdc_crtc0_set_dma_step(struct lsdc_crtc *lcrtc,
335 				    enum lsdc_dma_steps dma_step)
336 {
337 	struct lsdc_device *ldev = lcrtc->ldev;
338 	u32 val = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
339 
340 	val &= ~CFG_DMA_STEP_MASK;
341 	val |= dma_step << CFG_DMA_STEP_SHIFT;
342 
343 	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val);
344 }
345 
346 static void lsdc_crtc1_set_dma_step(struct lsdc_crtc *lcrtc,
347 				    enum lsdc_dma_steps dma_step)
348 {
349 	struct lsdc_device *ldev = lcrtc->ldev;
350 	u32 val = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
351 
352 	val &= ~CFG_DMA_STEP_MASK;
353 	val |= dma_step << CFG_DMA_STEP_SHIFT;
354 
355 	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val);
356 }
357 
358 static const struct lsdc_crtc_hw_ops ls7a2000_crtc_hw_ops[2] = {
359 	{
360 		.enable = lsdc_crtc0_enable,
361 		.disable = lsdc_crtc0_disable,
362 		.enable_vblank = lsdc_crtc0_enable_vblank,
363 		.disable_vblank = lsdc_crtc0_disable_vblank,
364 		.flip = lsdc_crtc0_flip,
365 		.clone = lsdc_crtc0_clone,
366 		.set_mode = lsdc_crtc0_set_mode,
367 		.soft_reset = lsdc_crtc0_soft_reset,
368 		.get_scan_pos = lsdc_crtc0_scan_pos,
369 		.set_dma_step = lsdc_crtc0_set_dma_step,
370 		.get_vblank_counter = lsdc_crtc0_get_vblank_count,
371 		.reset = lsdc_crtc0_reset,
372 	},
373 	{
374 		.enable = lsdc_crtc1_enable,
375 		.disable = lsdc_crtc1_disable,
376 		.enable_vblank = lsdc_crtc1_enable_vblank,
377 		.disable_vblank = lsdc_crtc1_disable_vblank,
378 		.flip = lsdc_crtc1_flip,
379 		.clone = lsdc_crtc1_clone,
380 		.set_mode = lsdc_crtc1_set_mode,
381 		.get_scan_pos = lsdc_crtc1_scan_pos,
382 		.soft_reset = lsdc_crtc1_soft_reset,
383 		.set_dma_step = lsdc_crtc1_set_dma_step,
384 		.get_vblank_counter = lsdc_crtc1_get_vblank_count,
385 		.reset = lsdc_crtc1_reset,
386 	},
387 };
388 
389 static void lsdc_crtc_reset(struct drm_crtc *crtc)
390 {
391 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
392 	const struct lsdc_crtc_hw_ops *ops = lcrtc->hw_ops;
393 	struct lsdc_crtc_state *priv_crtc_state;
394 
395 	if (crtc->state)
396 		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
397 
398 	priv_crtc_state = kzalloc(sizeof(*priv_crtc_state), GFP_KERNEL);
399 
400 	if (!priv_crtc_state)
401 		__drm_atomic_helper_crtc_reset(crtc, NULL);
402 	else
403 		__drm_atomic_helper_crtc_reset(crtc, &priv_crtc_state->base);
404 
405 	/* Reset the CRTC hardware, this is required for S3 support */
406 	ops->reset(lcrtc);
407 }
408 
409 static void lsdc_crtc_atomic_destroy_state(struct drm_crtc *crtc,
410 					   struct drm_crtc_state *state)
411 {
412 	struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state);
413 
414 	__drm_atomic_helper_crtc_destroy_state(&priv_state->base);
415 
416 	kfree(priv_state);
417 }
418 
419 static struct drm_crtc_state *
420 lsdc_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
421 {
422 	struct lsdc_crtc_state *new_priv_state;
423 	struct lsdc_crtc_state *old_priv_state;
424 
425 	new_priv_state = kzalloc(sizeof(*new_priv_state), GFP_KERNEL);
426 	if (!new_priv_state)
427 		return NULL;
428 
429 	__drm_atomic_helper_crtc_duplicate_state(crtc, &new_priv_state->base);
430 
431 	old_priv_state = to_lsdc_crtc_state(crtc->state);
432 
433 	memcpy(&new_priv_state->pparms, &old_priv_state->pparms,
434 	       sizeof(new_priv_state->pparms));
435 
436 	return &new_priv_state->base;
437 }
438 
439 static u32 lsdc_crtc_get_vblank_counter(struct drm_crtc *crtc)
440 {
441 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
442 
443 	/* 32-bit hardware vblank counter */
444 	return lcrtc->hw_ops->get_vblank_counter(lcrtc);
445 }
446 
447 static int lsdc_crtc_enable_vblank(struct drm_crtc *crtc)
448 {
449 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
450 
451 	if (!lcrtc->has_vblank)
452 		return -EINVAL;
453 
454 	lcrtc->hw_ops->enable_vblank(lcrtc);
455 
456 	return 0;
457 }
458 
459 static void lsdc_crtc_disable_vblank(struct drm_crtc *crtc)
460 {
461 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
462 
463 	if (!lcrtc->has_vblank)
464 		return;
465 
466 	lcrtc->hw_ops->disable_vblank(lcrtc);
467 }
468 
469 /*
470  * CRTC related debugfs
471  * Primary planes and cursor planes belong to the CRTC as well.
472  * For the sake of convenience, plane-related registers are also add here.
473  */
474 
475 #define REG_DEF(reg) { \
476 	.name = __stringify_1(LSDC_##reg##_REG), \
477 	.offset = LSDC_##reg##_REG, \
478 }
479 
480 static const struct lsdc_reg32 lsdc_crtc_regs_array[2][21] = {
481 	[0] = {
482 		REG_DEF(CRTC0_CFG),
483 		REG_DEF(CRTC0_FB_ORIGIN),
484 		REG_DEF(CRTC0_DVO_CONF),
485 		REG_DEF(CRTC0_HDISPLAY),
486 		REG_DEF(CRTC0_HSYNC),
487 		REG_DEF(CRTC0_VDISPLAY),
488 		REG_DEF(CRTC0_VSYNC),
489 		REG_DEF(CRTC0_GAMMA_INDEX),
490 		REG_DEF(CRTC0_GAMMA_DATA),
491 		REG_DEF(CRTC0_SYNC_DEVIATION),
492 		REG_DEF(CRTC0_VSYNC_COUNTER),
493 		REG_DEF(CRTC0_SCAN_POS),
494 		REG_DEF(CRTC0_STRIDE),
495 		REG_DEF(CRTC0_FB1_ADDR_HI),
496 		REG_DEF(CRTC0_FB1_ADDR_LO),
497 		REG_DEF(CRTC0_FB0_ADDR_HI),
498 		REG_DEF(CRTC0_FB0_ADDR_LO),
499 		REG_DEF(CURSOR0_CFG),
500 		REG_DEF(CURSOR0_POSITION),
501 		REG_DEF(CURSOR0_BG_COLOR),
502 		REG_DEF(CURSOR0_FG_COLOR),
503 	},
504 	[1] = {
505 		REG_DEF(CRTC1_CFG),
506 		REG_DEF(CRTC1_FB_ORIGIN),
507 		REG_DEF(CRTC1_DVO_CONF),
508 		REG_DEF(CRTC1_HDISPLAY),
509 		REG_DEF(CRTC1_HSYNC),
510 		REG_DEF(CRTC1_VDISPLAY),
511 		REG_DEF(CRTC1_VSYNC),
512 		REG_DEF(CRTC1_GAMMA_INDEX),
513 		REG_DEF(CRTC1_GAMMA_DATA),
514 		REG_DEF(CRTC1_SYNC_DEVIATION),
515 		REG_DEF(CRTC1_VSYNC_COUNTER),
516 		REG_DEF(CRTC1_SCAN_POS),
517 		REG_DEF(CRTC1_STRIDE),
518 		REG_DEF(CRTC1_FB1_ADDR_HI),
519 		REG_DEF(CRTC1_FB1_ADDR_LO),
520 		REG_DEF(CRTC1_FB0_ADDR_HI),
521 		REG_DEF(CRTC1_FB0_ADDR_LO),
522 		REG_DEF(CURSOR1_CFG),
523 		REG_DEF(CURSOR1_POSITION),
524 		REG_DEF(CURSOR1_BG_COLOR),
525 		REG_DEF(CURSOR1_FG_COLOR),
526 	},
527 };
528 
529 static int lsdc_crtc_show_regs(struct seq_file *m, void *arg)
530 {
531 	struct drm_info_node *node = (struct drm_info_node *)m->private;
532 	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
533 	struct lsdc_device *ldev = lcrtc->ldev;
534 	unsigned int i;
535 
536 	for (i = 0; i < lcrtc->nreg; i++) {
537 		const struct lsdc_reg32 *preg = &lcrtc->preg[i];
538 		u32 offset = preg->offset;
539 
540 		seq_printf(m, "%s (0x%04x): 0x%08x\n",
541 			   preg->name, offset, lsdc_rreg32(ldev, offset));
542 	}
543 
544 	return 0;
545 }
546 
547 static int lsdc_crtc_show_scan_position(struct seq_file *m, void *arg)
548 {
549 	struct drm_info_node *node = (struct drm_info_node *)m->private;
550 	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
551 	int x, y;
552 
553 	lcrtc->hw_ops->get_scan_pos(lcrtc, &x, &y);
554 	seq_printf(m, "Scanout position: x: %08u, y: %08u\n", x, y);
555 
556 	return 0;
557 }
558 
559 static int lsdc_crtc_show_vblank_counter(struct seq_file *m, void *arg)
560 {
561 	struct drm_info_node *node = (struct drm_info_node *)m->private;
562 	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
563 
564 	if (lcrtc->hw_ops->get_vblank_counter)
565 		seq_printf(m, "%s vblank counter: %08u\n\n", lcrtc->base.name,
566 			   lcrtc->hw_ops->get_vblank_counter(lcrtc));
567 
568 	return 0;
569 }
570 
571 static int lsdc_pixpll_show_clock(struct seq_file *m, void *arg)
572 {
573 	struct drm_info_node *node = (struct drm_info_node *)m->private;
574 	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
575 	struct lsdc_pixpll *pixpll = &lcrtc->pixpll;
576 	const struct lsdc_pixpll_funcs *funcs = pixpll->funcs;
577 	struct drm_crtc *crtc = &lcrtc->base;
578 	struct drm_display_mode *mode = &crtc->state->mode;
579 	struct drm_printer printer = drm_seq_file_printer(m);
580 	unsigned int out_khz;
581 
582 	out_khz = funcs->get_rate(pixpll);
583 
584 	seq_printf(m, "%s: %dx%d@%d\n", crtc->name,
585 		   mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode));
586 
587 	seq_printf(m, "Pixel clock required: %d kHz\n", mode->clock);
588 	seq_printf(m, "Actual frequency output: %u kHz\n", out_khz);
589 	seq_printf(m, "Diff: %d kHz\n", out_khz - mode->clock);
590 
591 	funcs->print(pixpll, &printer);
592 
593 	return 0;
594 }
595 
596 static struct drm_info_list lsdc_crtc_debugfs_list[2][4] = {
597 	[0] = {
598 		{ "regs", lsdc_crtc_show_regs, 0, NULL },
599 		{ "pixclk", lsdc_pixpll_show_clock, 0, NULL },
600 		{ "scanpos", lsdc_crtc_show_scan_position, 0, NULL },
601 		{ "vblanks", lsdc_crtc_show_vblank_counter, 0, NULL },
602 	},
603 	[1] = {
604 		{ "regs", lsdc_crtc_show_regs, 0, NULL },
605 		{ "pixclk", lsdc_pixpll_show_clock, 0, NULL },
606 		{ "scanpos", lsdc_crtc_show_scan_position, 0, NULL },
607 		{ "vblanks", lsdc_crtc_show_vblank_counter, 0, NULL },
608 	},
609 };
610 
611 /* operate manually */
612 
613 static int lsdc_crtc_man_op_show(struct seq_file *m, void *data)
614 {
615 	seq_puts(m, "soft_reset: soft reset this CRTC\n");
616 	seq_puts(m, "enable: enable this CRTC\n");
617 	seq_puts(m, "disable: disable this CRTC\n");
618 	seq_puts(m, "flip: trigger the page flip\n");
619 	seq_puts(m, "clone: clone the another crtc with hardware logic\n");
620 
621 	return 0;
622 }
623 
624 static int lsdc_crtc_man_op_open(struct inode *inode, struct file *file)
625 {
626 	struct drm_crtc *crtc = inode->i_private;
627 
628 	return single_open(file, lsdc_crtc_man_op_show, crtc);
629 }
630 
631 static ssize_t lsdc_crtc_man_op_write(struct file *file,
632 				      const char __user *ubuf,
633 				      size_t len,
634 				      loff_t *offp)
635 {
636 	struct seq_file *m = file->private_data;
637 	struct lsdc_crtc *lcrtc = m->private;
638 	const struct lsdc_crtc_hw_ops *ops = lcrtc->hw_ops;
639 	char buf[16];
640 
641 	if (len > sizeof(buf) - 1)
642 		return -EINVAL;
643 
644 	if (copy_from_user(buf, ubuf, len))
645 		return -EFAULT;
646 
647 	buf[len] = '\0';
648 
649 	if (sysfs_streq(buf, "soft_reset"))
650 		ops->soft_reset(lcrtc);
651 	else if (sysfs_streq(buf, "enable"))
652 		ops->enable(lcrtc);
653 	else if (sysfs_streq(buf, "disable"))
654 		ops->disable(lcrtc);
655 	else if (sysfs_streq(buf, "flip"))
656 		ops->flip(lcrtc);
657 	else if (sysfs_streq(buf, "clone"))
658 		ops->clone(lcrtc);
659 
660 	return len;
661 }
662 
663 static const struct file_operations lsdc_crtc_man_op_fops = {
664 	.owner = THIS_MODULE,
665 	.open = lsdc_crtc_man_op_open,
666 	.read = seq_read,
667 	.llseek = seq_lseek,
668 	.release = single_release,
669 	.write = lsdc_crtc_man_op_write,
670 };
671 
672 static int lsdc_crtc_late_register(struct drm_crtc *crtc)
673 {
674 	struct lsdc_display_pipe *dispipe = crtc_to_display_pipe(crtc);
675 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
676 	struct drm_minor *minor = crtc->dev->primary;
677 	unsigned int index = dispipe->index;
678 	unsigned int i;
679 
680 	lcrtc->preg = lsdc_crtc_regs_array[index];
681 	lcrtc->nreg = ARRAY_SIZE(lsdc_crtc_regs_array[index]);
682 	lcrtc->p_info_list = lsdc_crtc_debugfs_list[index];
683 	lcrtc->n_info_list = ARRAY_SIZE(lsdc_crtc_debugfs_list[index]);
684 
685 	for (i = 0; i < lcrtc->n_info_list; ++i)
686 		lcrtc->p_info_list[i].data = lcrtc;
687 
688 	drm_debugfs_create_files(lcrtc->p_info_list, lcrtc->n_info_list,
689 				 crtc->debugfs_entry, minor);
690 
691 	/* Manual operations supported */
692 	debugfs_create_file("ops", 0644, crtc->debugfs_entry, lcrtc,
693 			    &lsdc_crtc_man_op_fops);
694 
695 	return 0;
696 }
697 
698 static void lsdc_crtc_atomic_print_state(struct drm_printer *p,
699 					 const struct drm_crtc_state *state)
700 {
701 	const struct lsdc_crtc_state *priv_state;
702 	const struct lsdc_pixpll_parms *pparms;
703 
704 	priv_state = container_of_const(state, struct lsdc_crtc_state, base);
705 	pparms = &priv_state->pparms;
706 
707 	drm_printf(p, "\tInput clock divider = %u\n", pparms->div_ref);
708 	drm_printf(p, "\tMedium clock multiplier = %u\n", pparms->loopc);
709 	drm_printf(p, "\tOutput clock divider = %u\n", pparms->div_out);
710 }
711 
712 static const struct drm_crtc_funcs ls7a1000_crtc_funcs = {
713 	.reset = lsdc_crtc_reset,
714 	.destroy = drm_crtc_cleanup,
715 	.set_config = drm_atomic_helper_set_config,
716 	.page_flip = drm_atomic_helper_page_flip,
717 	.atomic_duplicate_state = lsdc_crtc_atomic_duplicate_state,
718 	.atomic_destroy_state = lsdc_crtc_atomic_destroy_state,
719 	.late_register = lsdc_crtc_late_register,
720 	.enable_vblank = lsdc_crtc_enable_vblank,
721 	.disable_vblank = lsdc_crtc_disable_vblank,
722 	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
723 	.atomic_print_state = lsdc_crtc_atomic_print_state,
724 };
725 
726 static const struct drm_crtc_funcs ls7a2000_crtc_funcs = {
727 	.reset = lsdc_crtc_reset,
728 	.destroy = drm_crtc_cleanup,
729 	.set_config = drm_atomic_helper_set_config,
730 	.page_flip = drm_atomic_helper_page_flip,
731 	.atomic_duplicate_state = lsdc_crtc_atomic_duplicate_state,
732 	.atomic_destroy_state = lsdc_crtc_atomic_destroy_state,
733 	.late_register = lsdc_crtc_late_register,
734 	.get_vblank_counter = lsdc_crtc_get_vblank_counter,
735 	.enable_vblank = lsdc_crtc_enable_vblank,
736 	.disable_vblank = lsdc_crtc_disable_vblank,
737 	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
738 	.atomic_print_state = lsdc_crtc_atomic_print_state,
739 };
740 
741 static enum drm_mode_status
742 lsdc_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
743 {
744 	struct drm_device *ddev = crtc->dev;
745 	struct lsdc_device *ldev = to_lsdc(ddev);
746 	const struct lsdc_desc *descp = ldev->descp;
747 	unsigned int pitch;
748 
749 	if (mode->hdisplay > descp->max_width)
750 		return MODE_BAD_HVALUE;
751 
752 	if (mode->vdisplay > descp->max_height)
753 		return MODE_BAD_VVALUE;
754 
755 	if (mode->clock > descp->max_pixel_clk) {
756 		drm_dbg_kms(ddev, "mode %dx%d, pixel clock=%d is too high\n",
757 			    mode->hdisplay, mode->vdisplay, mode->clock);
758 		return MODE_CLOCK_HIGH;
759 	}
760 
761 	/* 4 for DRM_FORMAT_XRGB8888 */
762 	pitch = mode->hdisplay * 4;
763 
764 	if (pitch % descp->pitch_align) {
765 		drm_dbg_kms(ddev, "align to %u bytes is required: %u\n",
766 			    descp->pitch_align, pitch);
767 		return MODE_BAD_WIDTH;
768 	}
769 
770 	return MODE_OK;
771 }
772 
773 static int lsdc_pixpll_atomic_check(struct drm_crtc *crtc,
774 				    struct drm_crtc_state *state)
775 {
776 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
777 	struct lsdc_pixpll *pixpll = &lcrtc->pixpll;
778 	const struct lsdc_pixpll_funcs *pfuncs = pixpll->funcs;
779 	struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state);
780 	unsigned int clock = state->mode.clock;
781 	int ret;
782 
783 	ret = pfuncs->compute(pixpll, clock, &priv_state->pparms);
784 	if (ret) {
785 		drm_warn(crtc->dev, "Failed to find PLL params for %ukHz\n",
786 			 clock);
787 		return -EINVAL;
788 	}
789 
790 	return 0;
791 }
792 
793 static int lsdc_crtc_helper_atomic_check(struct drm_crtc *crtc,
794 					 struct drm_atomic_state *state)
795 {
796 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
797 
798 	if (!crtc_state->enable)
799 		return 0;
800 
801 	return lsdc_pixpll_atomic_check(crtc, crtc_state);
802 }
803 
804 static void lsdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
805 {
806 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
807 	const struct lsdc_crtc_hw_ops *crtc_hw_ops = lcrtc->hw_ops;
808 	struct lsdc_pixpll *pixpll = &lcrtc->pixpll;
809 	const struct lsdc_pixpll_funcs *pixpll_funcs = pixpll->funcs;
810 	struct drm_crtc_state *state = crtc->state;
811 	struct drm_display_mode *mode = &state->mode;
812 	struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state);
813 
814 	pixpll_funcs->update(pixpll, &priv_state->pparms);
815 
816 	if (crtc_hw_ops->set_dma_step) {
817 		unsigned int width_in_bytes = mode->hdisplay * 4;
818 		enum lsdc_dma_steps dma_step;
819 
820 		/*
821 		 * Using DMA step as large as possible, for improving
822 		 * hardware DMA efficiency.
823 		 */
824 		if (width_in_bytes % 256 == 0)
825 			dma_step = LSDC_DMA_STEP_256_BYTES;
826 		else if (width_in_bytes % 128 == 0)
827 			dma_step = LSDC_DMA_STEP_128_BYTES;
828 		else if (width_in_bytes % 64 == 0)
829 			dma_step = LSDC_DMA_STEP_64_BYTES;
830 		else  /* width_in_bytes % 32 == 0 */
831 			dma_step = LSDC_DMA_STEP_32_BYTES;
832 
833 		crtc_hw_ops->set_dma_step(lcrtc, dma_step);
834 	}
835 
836 	crtc_hw_ops->set_mode(lcrtc, mode);
837 }
838 
839 static void lsdc_crtc_send_vblank(struct drm_crtc *crtc)
840 {
841 	struct drm_device *ddev = crtc->dev;
842 	unsigned long flags;
843 
844 	if (!crtc->state || !crtc->state->event)
845 		return;
846 
847 	drm_dbg(ddev, "Send vblank manually\n");
848 
849 	spin_lock_irqsave(&ddev->event_lock, flags);
850 	drm_crtc_send_vblank_event(crtc, crtc->state->event);
851 	crtc->state->event = NULL;
852 	spin_unlock_irqrestore(&ddev->event_lock, flags);
853 }
854 
855 static void lsdc_crtc_atomic_enable(struct drm_crtc *crtc,
856 				    struct drm_atomic_state *state)
857 {
858 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
859 
860 	if (lcrtc->has_vblank)
861 		drm_crtc_vblank_on(crtc);
862 
863 	lcrtc->hw_ops->enable(lcrtc);
864 }
865 
866 static void lsdc_crtc_atomic_disable(struct drm_crtc *crtc,
867 				     struct drm_atomic_state *state)
868 {
869 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
870 
871 	if (lcrtc->has_vblank)
872 		drm_crtc_vblank_off(crtc);
873 
874 	lcrtc->hw_ops->disable(lcrtc);
875 
876 	/*
877 	 * Make sure we issue a vblank event after disabling the CRTC if
878 	 * someone was waiting it.
879 	 */
880 	lsdc_crtc_send_vblank(crtc);
881 }
882 
883 static void lsdc_crtc_atomic_flush(struct drm_crtc *crtc,
884 				   struct drm_atomic_state *state)
885 {
886 	spin_lock_irq(&crtc->dev->event_lock);
887 	if (crtc->state->event) {
888 		if (drm_crtc_vblank_get(crtc) == 0)
889 			drm_crtc_arm_vblank_event(crtc, crtc->state->event);
890 		else
891 			drm_crtc_send_vblank_event(crtc, crtc->state->event);
892 		crtc->state->event = NULL;
893 	}
894 	spin_unlock_irq(&crtc->dev->event_lock);
895 }
896 
897 static bool lsdc_crtc_get_scanout_position(struct drm_crtc *crtc,
898 					   bool in_vblank_irq,
899 					   int *vpos,
900 					   int *hpos,
901 					   ktime_t *stime,
902 					   ktime_t *etime,
903 					   const struct drm_display_mode *mode)
904 {
905 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
906 	const struct lsdc_crtc_hw_ops *ops = lcrtc->hw_ops;
907 	int vsw, vbp, vactive_start, vactive_end, vfp_end;
908 	int x, y;
909 
910 	vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
911 	vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
912 
913 	vactive_start = vsw + vbp + 1;
914 	vactive_end = vactive_start + mode->crtc_vdisplay;
915 
916 	/* last scan line before VSYNC */
917 	vfp_end = mode->crtc_vtotal;
918 
919 	if (stime)
920 		*stime = ktime_get();
921 
922 	ops->get_scan_pos(lcrtc, &x, &y);
923 
924 	if (y > vactive_end)
925 		y = y - vfp_end - vactive_start;
926 	else
927 		y -= vactive_start;
928 
929 	*vpos = y;
930 	*hpos = 0;
931 
932 	if (etime)
933 		*etime = ktime_get();
934 
935 	return true;
936 }
937 
938 static const struct drm_crtc_helper_funcs lsdc_crtc_helper_funcs = {
939 	.mode_valid = lsdc_crtc_mode_valid,
940 	.mode_set_nofb = lsdc_crtc_mode_set_nofb,
941 	.atomic_enable = lsdc_crtc_atomic_enable,
942 	.atomic_disable = lsdc_crtc_atomic_disable,
943 	.atomic_check = lsdc_crtc_helper_atomic_check,
944 	.atomic_flush = lsdc_crtc_atomic_flush,
945 	.get_scanout_position = lsdc_crtc_get_scanout_position,
946 };
947 
948 int ls7a1000_crtc_init(struct drm_device *ddev,
949 		       struct drm_crtc *crtc,
950 		       struct drm_plane *primary,
951 		       struct drm_plane *cursor,
952 		       unsigned int index,
953 		       bool has_vblank)
954 {
955 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
956 	int ret;
957 
958 	ret = lsdc_pixpll_init(&lcrtc->pixpll, ddev, index);
959 	if (ret) {
960 		drm_err(ddev, "pixel pll init failed: %d\n", ret);
961 		return ret;
962 	}
963 
964 	lcrtc->ldev = to_lsdc(ddev);
965 	lcrtc->has_vblank = has_vblank;
966 	lcrtc->hw_ops = &ls7a1000_crtc_hw_ops[index];
967 
968 	ret = drm_crtc_init_with_planes(ddev, crtc, primary, cursor,
969 					&ls7a1000_crtc_funcs,
970 					"LS-CRTC-%d", index);
971 	if (ret) {
972 		drm_err(ddev, "crtc init with planes failed: %d\n", ret);
973 		return ret;
974 	}
975 
976 	drm_crtc_helper_add(crtc, &lsdc_crtc_helper_funcs);
977 
978 	ret = drm_mode_crtc_set_gamma_size(crtc, 256);
979 	if (ret)
980 		return ret;
981 
982 	drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
983 
984 	return 0;
985 }
986 
987 int ls7a2000_crtc_init(struct drm_device *ddev,
988 		       struct drm_crtc *crtc,
989 		       struct drm_plane *primary,
990 		       struct drm_plane *cursor,
991 		       unsigned int index,
992 		       bool has_vblank)
993 {
994 	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
995 	int ret;
996 
997 	ret = lsdc_pixpll_init(&lcrtc->pixpll, ddev, index);
998 	if (ret) {
999 		drm_err(ddev, "crtc init with pll failed: %d\n", ret);
1000 		return ret;
1001 	}
1002 
1003 	lcrtc->ldev = to_lsdc(ddev);
1004 	lcrtc->has_vblank = has_vblank;
1005 	lcrtc->hw_ops = &ls7a2000_crtc_hw_ops[index];
1006 
1007 	ret = drm_crtc_init_with_planes(ddev, crtc, primary, cursor,
1008 					&ls7a2000_crtc_funcs,
1009 					"LS-CRTC-%u", index);
1010 	if (ret) {
1011 		drm_err(ddev, "crtc init with planes failed: %d\n", ret);
1012 		return ret;
1013 	}
1014 
1015 	drm_crtc_helper_add(crtc, &lsdc_crtc_helper_funcs);
1016 
1017 	ret = drm_mode_crtc_set_gamma_size(crtc, 256);
1018 	if (ret)
1019 		return ret;
1020 
1021 	drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
1022 
1023 	return 0;
1024 }
1025