1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2017
5 * Authors: Philippe Cornu <philippe.cornu@st.com>
6 * Yannick Fertre <yannick.fertre@st.com>
7 * Fabien Dessenne <fabien.dessenne@st.com>
8 * Mickael Reulier <mickael.reulier@st.com>
11 #include <linux/component.h>
12 #include <linux/of_platform.h>
14 #include <drm/drm_atomic.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_fb_helper.h>
18 #include <drm/drm_fb_cma_helper.h>
19 #include <drm/drm_gem_cma_helper.h>
20 #include <drm/drm_gem_framebuffer_helper.h>
24 #define STM_MAX_FB_WIDTH 2048
25 #define STM_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */
27 static const struct drm_mode_config_funcs drv_mode_config_funcs
= {
28 .fb_create
= drm_gem_fb_create
,
29 .output_poll_changed
= drm_fb_helper_output_poll_changed
,
30 .atomic_check
= drm_atomic_helper_check
,
31 .atomic_commit
= drm_atomic_helper_commit
,
34 static int stm_gem_cma_dumb_create(struct drm_file
*file
,
35 struct drm_device
*dev
,
36 struct drm_mode_create_dumb
*args
)
38 unsigned int min_pitch
= DIV_ROUND_UP(args
->width
* args
->bpp
, 8);
41 * in order to optimize data transfer, pitch is aligned on
42 * 128 bytes, height is aligned on 4 bytes
44 args
->pitch
= roundup(min_pitch
, 128);
45 args
->height
= roundup(args
->height
, 4);
47 return drm_gem_cma_dumb_create_internal(file
, dev
, args
);
50 DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops
);
52 static struct drm_driver drv_driver
= {
53 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
| DRIVER_PRIME
|
55 .lastclose
= drm_fb_helper_lastclose
,
57 .desc
= "STMicroelectronics SoC DRM",
62 .fops
= &drv_driver_fops
,
63 .dumb_create
= stm_gem_cma_dumb_create
,
64 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
65 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
66 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
67 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
68 .gem_prime_export
= drm_gem_prime_export
,
69 .gem_prime_import
= drm_gem_prime_import
,
70 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
71 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
72 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
73 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
74 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
77 static int drv_load(struct drm_device
*ddev
)
79 struct platform_device
*pdev
= to_platform_device(ddev
->dev
);
80 struct ltdc_device
*ldev
;
83 DRM_DEBUG("%s\n", __func__
);
85 ldev
= devm_kzalloc(ddev
->dev
, sizeof(*ldev
), GFP_KERNEL
);
89 ddev
->dev_private
= (void *)ldev
;
91 drm_mode_config_init(ddev
);
94 * set max width and height as default value.
95 * this value would be used to check framebuffer size limitation
96 * at drm_mode_addfb().
98 ddev
->mode_config
.min_width
= 0;
99 ddev
->mode_config
.min_height
= 0;
100 ddev
->mode_config
.max_width
= STM_MAX_FB_WIDTH
;
101 ddev
->mode_config
.max_height
= STM_MAX_FB_HEIGHT
;
102 ddev
->mode_config
.funcs
= &drv_mode_config_funcs
;
104 ret
= ltdc_load(ddev
);
108 drm_mode_config_reset(ddev
);
109 drm_kms_helper_poll_init(ddev
);
111 if (ddev
->mode_config
.num_connector
) {
112 ret
= drm_fb_cma_fbdev_init(ddev
, 16, 0);
114 DRM_DEBUG("Warning: fails to create fbdev\n");
117 platform_set_drvdata(pdev
, ddev
);
121 drm_mode_config_cleanup(ddev
);
125 static void drv_unload(struct drm_device
*ddev
)
127 DRM_DEBUG("%s\n", __func__
);
129 drm_fb_cma_fbdev_fini(ddev
);
130 drm_kms_helper_poll_fini(ddev
);
132 drm_mode_config_cleanup(ddev
);
135 static int stm_drm_platform_probe(struct platform_device
*pdev
)
137 struct device
*dev
= &pdev
->dev
;
138 struct drm_device
*ddev
;
141 DRM_DEBUG("%s\n", __func__
);
143 dma_set_coherent_mask(dev
, DMA_BIT_MASK(32));
145 ddev
= drm_dev_alloc(&drv_driver
, dev
);
147 return PTR_ERR(ddev
);
149 ret
= drv_load(ddev
);
153 ret
= drm_dev_register(ddev
, 0);
165 static int stm_drm_platform_remove(struct platform_device
*pdev
)
167 struct drm_device
*ddev
= platform_get_drvdata(pdev
);
169 DRM_DEBUG("%s\n", __func__
);
171 drm_dev_unregister(ddev
);
178 static const struct of_device_id drv_dt_ids
[] = {
179 { .compatible
= "st,stm32-ltdc"},
182 MODULE_DEVICE_TABLE(of
, drv_dt_ids
);
184 static struct platform_driver stm_drm_platform_driver
= {
185 .probe
= stm_drm_platform_probe
,
186 .remove
= stm_drm_platform_remove
,
188 .name
= "stm32-display",
189 .of_match_table
= drv_dt_ids
,
193 module_platform_driver(stm_drm_platform_driver
);
195 MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
196 MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
197 MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
198 MODULE_AUTHOR("Mickael Reulier <mickael.reulier@st.com>");
199 MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver");
200 MODULE_LICENSE("GPL v2");