1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 VeriSilicon Holdings Co., Ltd.
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>
12 #include <drm/drm_crtc.h>
13 #include <drm/vs_drm.h>
17 #if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE
18 #include <drm/drm_vblank.h>
21 void vs_crtc_destroy(struct drm_crtc *crtc)
23 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
25 drm_crtc_cleanup(crtc);
29 static void vs_crtc_reset(struct drm_crtc *crtc)
31 struct vs_crtc_state *state;
34 __drm_atomic_helper_crtc_destroy_state(crtc->state);
36 state = to_vs_crtc_state(crtc->state);
41 state = kzalloc(sizeof(*state), GFP_KERNEL);
45 __drm_atomic_helper_crtc_reset(crtc, &state->base);
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;
55 static struct drm_crtc_state *
56 vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
58 struct vs_crtc_state *ori_state;
59 struct vs_crtc_state *state;
61 if (WARN_ON(!crtc->state))
64 ori_state = to_vs_crtc_state(crtc->state);
65 state = kzalloc(sizeof(*state), GFP_KERNEL);
69 __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
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;
86 static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc,
87 struct drm_crtc_state *state)
89 __drm_atomic_helper_crtc_destroy_state(state);
90 kfree(to_vs_crtc_state(state));
93 static int vs_crtc_atomic_set_property(struct drm_crtc *crtc,
94 struct drm_crtc_state *state,
95 struct drm_property *property,
98 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
99 struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(state);
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;
117 static int vs_crtc_atomic_get_property(struct drm_crtc *crtc,
118 const struct drm_crtc_state *state,
119 struct drm_property *property,
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);
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;
142 #ifdef CONFIG_DEBUG_FS
143 static int vs_crtc_debugfs_show(struct seq_file *s, void *data)
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;
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);
158 static int vs_crtc_debugfs_open(struct inode *inode, struct file *file)
160 return single_open(file, vs_crtc_debugfs_show, inode->i_private);
163 static const struct file_operations vs_crtc_debugfs_fops = {
164 .open = vs_crtc_debugfs_open,
167 .release = single_release,
170 static int vs_crtc_debugfs_init(struct drm_crtc *crtc)
172 debugfs_create_file("status", 0444, crtc->debugfs_entry,
173 crtc, &vs_crtc_debugfs_fops);
178 static int vs_crtc_debugfs_init(struct drm_crtc *crtc)
182 #endif /* CONFIG_DEBUG_FS */
184 static int vs_crtc_late_register(struct drm_crtc *crtc)
186 return vs_crtc_debugfs_init(crtc);
189 static int vs_crtc_enable_vblank(struct drm_crtc *crtc)
191 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
192 struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
194 vs_crtc->funcs->enable_vblank(vs_crtc->dev, true);
199 static void vs_crtc_disable_vblank(struct drm_crtc *crtc)
201 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
203 vs_crtc->funcs->enable_vblank(vs_crtc->dev, false);
206 static const struct drm_crtc_funcs vs_crtc_funcs = {
207 .set_config = drm_atomic_helper_set_config,
208 .destroy = vs_crtc_destroy,
209 .page_flip = drm_atomic_helper_page_flip,
210 .reset = vs_crtc_reset,
211 .atomic_duplicate_state = vs_crtc_atomic_duplicate_state,
212 .atomic_destroy_state = vs_crtc_atomic_destroy_state,
213 .atomic_set_property = vs_crtc_atomic_set_property,
214 .atomic_get_property = vs_crtc_atomic_get_property,
215 //.gamma_set = drm_atomic_helper_legacy_gamma_set,
216 .late_register = vs_crtc_late_register,
217 .enable_vblank = vs_crtc_enable_vblank,
218 .disable_vblank = vs_crtc_disable_vblank,
221 static u8 cal_pixel_bits(u32 bus_format)
225 switch (bus_format) {
226 case MEDIA_BUS_FMT_RGB565_1X16:
227 case MEDIA_BUS_FMT_UYVY8_1X16:
230 case MEDIA_BUS_FMT_RGB666_1X18:
231 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
234 case MEDIA_BUS_FMT_UYVY10_1X20:
237 case MEDIA_BUS_FMT_BGR888_1X24:
238 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
239 case MEDIA_BUS_FMT_YUV8_1X24:
242 case MEDIA_BUS_FMT_RGB101010_1X30:
243 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
244 case MEDIA_BUS_FMT_YUV10_1X30:
255 static bool vs_crtc_mode_fixup(struct drm_crtc *crtc,
256 const struct drm_display_mode *mode,
257 struct drm_display_mode *adjusted_mode)
259 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
261 return vs_crtc->funcs->mode_fixup(vs_crtc->dev, mode, adjusted_mode);
264 static void vs_crtc_atomic_enable(struct drm_crtc *crtc,
265 struct drm_atomic_state *state)
267 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
268 struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
270 vs_crtc_state->bpp = cal_pixel_bits(vs_crtc_state->output_fmt);
272 vs_crtc->funcs->enable(vs_crtc->dev, crtc);
273 drm_crtc_vblank_on(crtc);
277 static void vs_crtc_atomic_disable(struct drm_crtc *crtc,
278 struct drm_atomic_state *state)
280 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
282 drm_crtc_vblank_off(crtc);
284 vs_crtc->funcs->disable(vs_crtc->dev, crtc);
286 if (crtc->state->event && !crtc->state->active) {
287 spin_lock_irq(&crtc->dev->event_lock);
288 drm_crtc_send_vblank_event(crtc, crtc->state->event);
289 spin_unlock_irq(&crtc->dev->event_lock);
291 crtc->state->event = NULL;
295 static void vs_crtc_atomic_begin(struct drm_crtc *crtc,
296 struct drm_atomic_state *state)
298 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
300 //struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,crtc);
302 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
303 struct device *dev = vs_crtc->dev;
304 struct drm_property_blob *blob = crtc->state->gamma_lut;
305 struct drm_color_lut *lut;
306 struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
308 if (crtc_state->color_mgmt_changed) {
309 if ((blob) && (blob->length)) {
311 vs_crtc->funcs->set_gamma(dev, crtc, lut,
312 blob->length / sizeof(*lut));
313 vs_crtc->funcs->enable_gamma(dev, crtc, true);
315 vs_crtc->funcs->enable_gamma(dev, crtc, false);
320 static void vs_crtc_atomic_flush(struct drm_crtc *crtc,
321 struct drm_atomic_state *state)
323 struct vs_crtc *vs_crtc = to_vs_crtc(crtc);
324 struct drm_pending_vblank_event *event = crtc->state->event;
326 vs_crtc->funcs->commit(vs_crtc->dev);
329 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
331 spin_lock_irq(&crtc->dev->event_lock);
332 drm_crtc_arm_vblank_event(crtc, event);
333 spin_unlock_irq(&crtc->dev->event_lock);
334 crtc->state->event = NULL;
338 static const struct drm_crtc_helper_funcs vs_crtc_helper_funcs = {
339 .mode_fixup = vs_crtc_mode_fixup,
340 .atomic_enable = vs_crtc_atomic_enable,
341 .atomic_disable = vs_crtc_atomic_disable,
342 .atomic_begin = vs_crtc_atomic_begin,
343 .atomic_flush = vs_crtc_atomic_flush,
346 static const struct drm_prop_enum_list vs_sync_mode_enum_list[] = {
347 { VS_SINGLE_DC, "single dc mode" },
348 { VS_MULTI_DC_PRIMARY, "primary dc for multi dc mode" },
349 { VS_MULTI_DC_SECONDARY, "secondary dc for multi dc mode" },
352 #ifdef CONFIG_VERISILICON_MMU
353 static const struct drm_prop_enum_list vs_mmu_prefetch_enum_list[] = {
354 { VS_MMU_PREFETCH_DISABLE, "disable mmu prefetch" },
355 { VS_MMU_PREFETCH_ENABLE, "enable mmu prefetch" },
359 struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev,
360 struct vs_dc_info *info)
362 struct vs_crtc *crtc;
368 crtc = kzalloc(sizeof(struct vs_crtc), GFP_KERNEL);
372 ret = drm_crtc_init_with_planes(drm_dev, &crtc->base,
373 NULL, NULL, &vs_crtc_funcs,
374 info->name ? info->name : NULL);
378 drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs);
380 /* Set up the crtc properties */
381 if (info->pipe_sync) {
382 crtc->sync_mode = drm_property_create_enum(drm_dev, 0,
384 vs_sync_mode_enum_list,
385 ARRAY_SIZE(vs_sync_mode_enum_list));
387 if (!crtc->sync_mode)
388 goto err_cleanup_crts;
390 drm_object_attach_property(&crtc->base.base,
395 if (info->gamma_size) {
396 ret = drm_mode_crtc_set_gamma_size(&crtc->base,
399 goto err_cleanup_crts;
401 drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
405 if (info->background) {
406 crtc->bg_color = drm_property_create_range(drm_dev, 0,
407 "BG_COLOR", 0, 0xffffffff);
410 goto err_cleanup_crts;
412 drm_object_attach_property(&crtc->base.base, crtc->bg_color, 0);
415 if (info->panel_sync) {
416 crtc->panel_sync = drm_property_create_bool(drm_dev, 0, "SYNC_ENABLED");
418 if (!crtc->panel_sync)
419 goto err_cleanup_crts;
421 drm_object_attach_property(&crtc->base.base, crtc->panel_sync, 0);
424 crtc->dither = drm_property_create_bool(drm_dev, 0, "DITHER_ENABLED");
426 goto err_cleanup_crts;
428 drm_object_attach_property(&crtc->base.base, crtc->dither, 0);
430 #ifdef CONFIG_VERISILICON_MMU
431 if (info->mmu_prefetch) {
432 crtc->mmu_prefetch = drm_property_create_enum(drm_dev, 0,
434 vs_mmu_prefetch_enum_list,
435 ARRAY_SIZE(vs_mmu_prefetch_enum_list));
436 if (!crtc->mmu_prefetch)
437 goto err_cleanup_crts;
439 drm_object_attach_property(&crtc->base.base,
441 VS_MMU_PREFETCH_DISABLE);
445 crtc->max_bpc = info->max_bpc;
446 crtc->color_formats = info->color_formats;
450 drm_crtc_cleanup(&crtc->base);
457 void vs_crtc_handle_vblank(struct drm_crtc *crtc, bool underflow)
459 struct vs_crtc_state *vs_crtc_state = to_vs_crtc_state(crtc->state);
461 drm_crtc_handle_vblank(crtc);
463 vs_crtc_state->underflow = underflow;