21398bba8fbde73c98193fa922cfbcade959c690
[platform/kernel/linux-starfive.git] / drivers / gpu / drm / verisilicon / vs_crtc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
4  */
5
6 #include <linux/clk.h>
7 #include <linux/debugfs.h>
8 #include <drm/drm_gem_atomic_helper.h>
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_atomic.h>
11
12 #include <drm/drm_crtc.h>
13 #include <drm/vs_drm.h>
14
15 #include "vs_crtc.h"
16
17 #if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE
18 #include <drm/drm_vblank.h>
19 #endif
20
21 void vs_crtc_destroy(struct drm_crtc *crtc)
22 {
23         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
24
25         drm_crtc_cleanup(crtc);
26         kfree(vs_crtc);
27 }
28
29 static void vs_crtc_reset(struct drm_crtc *crtc)
30 {
31         struct vs_crtc_state *state;
32
33         if (crtc->state) {
34                 __drm_atomic_helper_crtc_destroy_state(crtc->state);
35
36                 state = to_vs_crtc_state(crtc->state);
37                 kfree(state);
38                 crtc->state = NULL;
39         }
40
41         state = kzalloc(sizeof(*state), GFP_KERNEL);
42         if (state == NULL)
43                 return;
44
45         __drm_atomic_helper_crtc_reset(crtc, &state->base);
46
47         state->sync_mode = VS_SINGLE_DC;
48         state->output_fmt = MEDIA_BUS_FMT_RBG888_1X24;
49         state->encoder_type = DRM_MODE_ENCODER_NONE;
50 #ifdef CONFIG_VERISILICON_MMU
51         state->mmu_prefetch = VS_MMU_PREFETCH_DISABLE;
52 #endif
53 }
54
55 static struct drm_crtc_state *
56 vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
57 {
58         struct vs_crtc_state *ori_state;
59         struct vs_crtc_state *state;
60
61         if (WARN_ON(!crtc->state))
62                 return NULL;
63
64         ori_state = to_vs_crtc_state(crtc->state);
65         state = kzalloc(sizeof(*state), GFP_KERNEL);
66         if (!state)
67                 return NULL;
68
69         __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
70
71         state->sync_mode = ori_state->sync_mode;
72         state->output_fmt = ori_state->output_fmt;
73         state->encoder_type = ori_state->encoder_type;
74         state->bg_color = ori_state->bg_color;
75         state->bpp = ori_state->bpp;
76         state->sync_enable = ori_state->sync_enable;
77         state->dither_enable = ori_state->dither_enable;
78         state->underflow = ori_state->underflow;
79 #ifdef CONFIG_VERISILICON_MMU
80         state->mmu_prefetch = ori_state->mmu_prefetch;
81 #endif
82
83         return &state->base;
84 }
85
86 static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
87                                          struct drm_crtc_state *state)
88 {
89         __drm_atomic_helper_crtc_destroy_state(state);
90         kfree(to_vs_crtc_state(state));
91 }
92
93 static int vs_crtc_atomic_set_property(struct drm_crtc *crtc,
94                                            struct drm_crtc_state *state,
95                                            struct drm_property *property,
96                                            uint64_t val)
97 {
98         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
99         struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(state);
100
101         if (property == vs_crtc->sync_mode)
102                 vs_crtc_state->sync_mode = val;
103         else if (property == vs_crtc->mmu_prefetch)
104                 vs_crtc_state->mmu_prefetch = val;
105         else if (property == vs_crtc->bg_color)
106                 vs_crtc_state->bg_color = val;
107         else if (property == vs_crtc->panel_sync)
108                 vs_crtc_state->sync_enable = val;
109         else if (property == vs_crtc->dither)
110                 vs_crtc_state->dither_enable = val;
111         else
112                 return -EINVAL;
113
114         return 0;
115 }
116
117 static int vs_crtc_atomic_get_property(struct drm_crtc *crtc,
118                                            const struct drm_crtc_state *state,
119                                            struct drm_property *property,
120                                            uint64_t *val)
121 {
122         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
123         const struct vs_crtc_state *vs_crtc_state =
124                 container_of(state, const struct vs_crtc_state, base);
125
126         if (property == vs_crtc->sync_mode)
127                 *val = vs_crtc_state->sync_mode;
128         else if (property == vs_crtc->mmu_prefetch)
129                 *val = vs_crtc_state->mmu_prefetch;
130         else if (property == vs_crtc->bg_color)
131                 *val = vs_crtc_state->bg_color;
132         else if (property == vs_crtc->panel_sync)
133                 *val = vs_crtc_state->sync_enable;
134         else if (property == vs_crtc->dither)
135                 *val = vs_crtc_state->dither_enable;
136         else
137                 return -EINVAL;
138
139         return 0;
140 }
141
142 #ifdef CONFIG_DEBUG_FS
143 static int vs_crtc_debugfs_show(struct seq_file *s, void *data)
144 {
145         struct drm_crtc *crtc = s->private;
146         struct vs_crtc_state *crtc_state = to_vs_crtc_state(crtc->state);
147         struct drm_display_mode *mode = &crtc->state->adjusted_mode;
148
149         seq_printf(s, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
150         seq_printf(s, "\tactive = %d\n", crtc->state->active);
151         seq_printf(s, "\tsize = %dx%d\n", mode->hdisplay, mode->vdisplay);
152         seq_printf(s, "\tbpp = %u\n", crtc_state->bpp);
153         seq_printf(s, "\tunderflow = %d\n", crtc_state->underflow);
154
155         return 0;
156 }
157
158 static int vs_crtc_debugfs_open(struct inode *inode, struct file *file)
159 {
160         return single_open(file, vs_crtc_debugfs_show, inode->i_private);
161 }
162
163 static const struct file_operations vs_crtc_debugfs_fops = {
164         .open           = vs_crtc_debugfs_open,
165         .read           = seq_read,
166         .llseek         = seq_lseek,
167         .release        = single_release,
168 };
169
170 static int vs_crtc_debugfs_init(struct drm_crtc *crtc)
171 {
172         debugfs_create_file("status", 0444, crtc->debugfs_entry,
173                                 crtc, &vs_crtc_debugfs_fops);
174
175         return 0;
176 }
177 #else
178 static int vs_crtc_debugfs_init(struct drm_crtc *crtc)
179 {
180         return 0;
181 }
182 #endif /* CONFIG_DEBUG_FS */
183
184 static int vs_crtc_late_register(struct drm_crtc *crtc)
185 {
186         return vs_crtc_debugfs_init(crtc);
187 }
188
189 static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
190 {
191         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
192         struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
193
194         if (vs_crtc_state->encoder_type == DRM_MODE_ENCODER_DSI)
195                 vs_crtc->funcs->enable(vs_crtc->dev, crtc);
196
197         vs_crtc->funcs->enable_vblank(vs_crtc->dev, true);
198
199         return 0;
200 }
201
202 static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
203 {
204         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
205
206         vs_crtc->funcs->enable_vblank(vs_crtc->dev, false);
207 }
208
209 static const struct drm_crtc_funcs vs_crtc_funcs = {
210         .set_config             = drm_atomic_helper_set_config,
211         .destroy                = vs_crtc_destroy,
212         .page_flip              = drm_atomic_helper_page_flip,
213         .reset                  = vs_crtc_reset,
214         .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
215         .atomic_destroy_state   = vs_crtc_atomic_destroy_state,
216         .atomic_set_property    = vs_crtc_atomic_set_property,
217         .atomic_get_property    = vs_crtc_atomic_get_property,
218         //.gamma_set      = drm_atomic_helper_legacy_gamma_set,
219         .late_register          = vs_crtc_late_register,
220         .enable_vblank          = vs_crtc_enable_vblank,
221         .disable_vblank         = vs_crtc_disable_vblank,
222 };
223
224 static u8 cal_pixel_bits(u32 bus_format)
225 {
226         u8 bpp;
227
228         switch (bus_format) {
229         case MEDIA_BUS_FMT_RGB565_1X16:
230         case MEDIA_BUS_FMT_UYVY8_1X16:
231                 bpp = 16;
232                 break;
233         case MEDIA_BUS_FMT_RGB666_1X18:
234         case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
235                 bpp = 18;
236                 break;
237         case MEDIA_BUS_FMT_UYVY10_1X20:
238                 bpp = 20;
239                 break;
240         case MEDIA_BUS_FMT_BGR888_1X24:
241         case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
242         case MEDIA_BUS_FMT_YUV8_1X24:
243                 bpp = 24;
244                 break;
245         case MEDIA_BUS_FMT_RGB101010_1X30:
246         case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
247         case MEDIA_BUS_FMT_YUV10_1X30:
248                 bpp = 30;
249                 break;
250         default:
251                 bpp = 24;
252                 break;
253         }
254
255         return bpp;
256 }
257
258 static bool vs_crtc_mode_fixup(struct drm_crtc *crtc,
259                                    const struct drm_display_mode *mode,
260                                    struct drm_display_mode *adjusted_mode)
261 {
262         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
263
264         return vs_crtc->funcs->mode_fixup(vs_crtc->dev, mode, adjusted_mode);
265 }
266
267 static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
268                                         struct drm_atomic_state *state)
269 {
270         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
271         struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
272
273         vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
274
275         if (vs_crtc_state->encoder_type != DRM_MODE_ENCODER_DSI){
276                 vs_crtc->funcs->enable(vs_crtc->dev, crtc);
277                 drm_crtc_vblank_on(crtc);
278         } else {
279                 drm_crtc_vblank_on(crtc);
280         }
281
282 }
283
284 static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
285                                         struct drm_atomic_state *state)
286 {
287         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
288
289         drm_crtc_vblank_off(crtc);
290
291         vs_crtc->funcs->disable(vs_crtc->dev, crtc);
292
293         if (crtc->state->event && !crtc->state->active) {
294                 spin_lock_irq(&crtc->dev->event_lock);
295                 drm_crtc_send_vblank_event(crtc, crtc->state->event);
296                 spin_unlock_irq(&crtc->dev->event_lock);
297
298                 crtc->state->event = NULL;
299         }
300 }
301
302 static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
303                                   struct drm_atomic_state *state)
304 {
305         struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
306                                                                           crtc);
307         //struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,crtc);
308
309         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
310         struct device *dev = vs_crtc->dev;
311         struct drm_property_blob *blob = crtc->state->gamma_lut;
312         struct drm_color_lut *lut;
313         struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
314
315         if (crtc_state->color_mgmt_changed) {
316                 if ((blob) && (blob->length)) {
317                         lut = blob->data;
318                         vs_crtc->funcs->set_gamma(dev, crtc, lut,
319                                                   blob->length / sizeof(*lut));
320                         vs_crtc->funcs->enable_gamma(dev, crtc, true);
321                 } else {
322                         vs_crtc->funcs->enable_gamma(dev, crtc, false);
323                 }
324         }
325 }
326
327 static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
328                                   struct drm_atomic_state *state)
329 {
330         struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
331         struct drm_pending_vblank_event *event = crtc->state->event;
332
333         vs_crtc->funcs->commit(vs_crtc->dev);
334
335         if (event) {
336                 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
337
338                 spin_lock_irq(&crtc->dev->event_lock);
339                 drm_crtc_arm_vblank_event(crtc, event);
340                 spin_unlock_irq(&crtc->dev->event_lock);
341                 crtc->state->event = NULL;
342         }
343 }
344
345 static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
346         .mode_fixup = vs_crtc_mode_fixup,
347         .atomic_enable  = vs_crtc_atomic_enable,
348         .atomic_disable = vs_crtc_atomic_disable,
349         .atomic_begin   = vs_crtc_atomic_begin,
350         .atomic_flush   = vs_crtc_atomic_flush,
351 };
352
353 static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
354         { VS_SINGLE_DC,                         "single dc mode" },
355         { VS_MULTI_DC_PRIMARY,          "primary dc for multi dc mode" },
356         { VS_MULTI_DC_SECONDARY,        "secondary dc for multi dc mode" },
357 };
358
359 #ifdef CONFIG_VERISILICON_MMU
360 static const struct drm_prop_enum_list vs_mmu_prefetch_enum_list[] = {
361         { VS_MMU_PREFETCH_DISABLE,      "disable mmu prefetch" },
362         { VS_MMU_PREFETCH_ENABLE,       "enable mmu prefetch" },
363 };
364 #endif
365
366 struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
367                                    struct vs_dc_info *info)
368 {
369         struct vs_crtc *crtc;
370         int ret;
371
372         if (!info)
373                 return NULL;
374
375         crtc = kzalloc(sizeof(struct vs_crtc), GFP_KERNEL);
376         if (!crtc)
377                 return NULL;
378
379         ret = drm_crtc_init_with_planes(drm_dev, &crtc->base,
380                                         NULL, NULL, &vs_crtc_funcs,
381                                         info->name ? info->name : NULL);
382         if (ret)
383                 goto err_free_crtc;
384
385         drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
386
387         /* Set up the crtc properties */
388         if (info->pipe_sync) {
389                 crtc->sync_mode = drm_property_create_enum(drm_dev, 0,
390                                         "SYNC_MODE",
391                                         vs_sync_mode_enum_list,
392                                         ARRAY_SIZE(vs_sync_mode_enum_list));
393
394                 if (!crtc->sync_mode)
395                         goto err_cleanup_crts;
396
397                 drm_object_attach_property(&crtc->base.base,
398                                            crtc->sync_mode,
399                                            VS_SINGLE_DC);
400         }
401
402         if (info->gamma_size) {
403                 ret = drm_mode_crtc_set_gamma_size(&crtc->base,
404                                                    info->gamma_size);
405                 if (ret)
406                         goto err_cleanup_crts;
407
408                 drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
409                                            info->gamma_size);
410         }
411
412         if (info->background) {
413                 crtc->bg_color = drm_property_create_range(drm_dev, 0,
414                                                  "BG_COLOR", 0, 0xffffffff);
415
416                 if (!crtc->bg_color)
417                         goto err_cleanup_crts;
418
419                 drm_object_attach_property(&crtc->base.base, crtc->bg_color, 0);
420         }
421
422         if (info->panel_sync) {
423                 crtc->panel_sync = drm_property_create_bool(drm_dev, 0, "SYNC_ENABLED");
424
425                 if (!crtc->panel_sync)
426                         goto err_cleanup_crts;
427
428                 drm_object_attach_property(&crtc->base.base, crtc->panel_sync, 0);
429         }
430
431         crtc->dither = drm_property_create_bool(drm_dev, 0, "DITHER_ENABLED");
432         if (!crtc->dither)
433                 goto err_cleanup_crts;
434
435         drm_object_attach_property(&crtc->base.base, crtc->dither, 0);
436
437 #ifdef CONFIG_VERISILICON_MMU
438         if (info->mmu_prefetch) {
439                 crtc->mmu_prefetch = drm_property_create_enum(drm_dev, 0,
440                                                                 "MMU_PREFETCH",
441                                                                 vs_mmu_prefetch_enum_list,
442                                                                 ARRAY_SIZE(vs_mmu_prefetch_enum_list));
443                 if (!crtc->mmu_prefetch)
444                         goto err_cleanup_crts;
445
446                 drm_object_attach_property(&crtc->base.base,
447                                                                    crtc->mmu_prefetch,
448                                                                    VS_MMU_PREFETCH_DISABLE);
449         }
450 #endif
451
452         crtc->max_bpc = info->max_bpc;
453         crtc->color_formats = info->color_formats;
454         return crtc;
455
456 err_cleanup_crts:
457         drm_crtc_cleanup(&crtc->base);
458
459 err_free_crtc:
460         kfree(crtc);
461         return NULL;
462 }
463
464 void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
465 {
466         struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
467
468         drm_crtc_handle_vblank(crtc);
469
470         vs_crtc_state->underflow = underflow;
471 }