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/aperture.h>
12 #include <linux/component.h>
13 #include <linux/dma-mapping.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
19 #include <drm/drm_atomic.h>
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_client_setup.h>
22 #include <drm/drm_drv.h>
23 #include <drm/drm_fbdev_dma.h>
24 #include <drm/drm_fourcc.h>
25 #include <drm/drm_gem_dma_helper.h>
26 #include <drm/drm_gem_framebuffer_helper.h>
27 #include <drm/drm_module.h>
28 #include <drm/drm_probe_helper.h>
29 #include <drm/drm_vblank.h>
30 #include <drm/drm_managed.h>
34 #define STM_MAX_FB_WIDTH 2048
35 #define STM_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */
37 static const struct drm_mode_config_funcs drv_mode_config_funcs
= {
38 .fb_create
= drm_gem_fb_create
,
39 .atomic_check
= drm_atomic_helper_check
,
40 .atomic_commit
= drm_atomic_helper_commit
,
43 static int stm_gem_dma_dumb_create(struct drm_file
*file
,
44 struct drm_device
*dev
,
45 struct drm_mode_create_dumb
*args
)
47 unsigned int min_pitch
= DIV_ROUND_UP(args
->width
* args
->bpp
, 8);
50 * in order to optimize data transfer, pitch is aligned on
51 * 128 bytes, height is aligned on 4 bytes
53 args
->pitch
= roundup(min_pitch
, 128);
54 args
->height
= roundup(args
->height
, 4);
56 return drm_gem_dma_dumb_create_internal(file
, dev
, args
);
59 DEFINE_DRM_GEM_DMA_FOPS(drv_driver_fops
);
61 static const struct drm_driver drv_driver
= {
62 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
| DRIVER_ATOMIC
,
64 .desc
= "STMicroelectronics SoC DRM",
69 .fops
= &drv_driver_fops
,
70 DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(stm_gem_dma_dumb_create
),
71 DRM_FBDEV_DMA_DRIVER_OPS
,
74 static int drv_load(struct drm_device
*ddev
)
76 struct platform_device
*pdev
= to_platform_device(ddev
->dev
);
77 struct ltdc_device
*ldev
;
80 DRM_DEBUG("%s\n", __func__
);
82 ldev
= drmm_kzalloc(ddev
, sizeof(*ldev
), GFP_KERNEL
);
86 ddev
->dev_private
= (void *)ldev
;
88 ret
= drmm_mode_config_init(ddev
);
93 * set max width and height as default value.
94 * this value would be used to check framebuffer size limitation
95 * at drm_mode_addfb().
97 ddev
->mode_config
.min_width
= 0;
98 ddev
->mode_config
.min_height
= 0;
99 ddev
->mode_config
.max_width
= STM_MAX_FB_WIDTH
;
100 ddev
->mode_config
.max_height
= STM_MAX_FB_HEIGHT
;
101 ddev
->mode_config
.funcs
= &drv_mode_config_funcs
;
102 ddev
->mode_config
.normalize_zpos
= true;
104 ret
= ltdc_load(ddev
);
108 drm_mode_config_reset(ddev
);
109 drm_kms_helper_poll_init(ddev
);
111 platform_set_drvdata(pdev
, ddev
);
116 static void drv_unload(struct drm_device
*ddev
)
118 DRM_DEBUG("%s\n", __func__
);
120 drm_kms_helper_poll_fini(ddev
);
121 drm_atomic_helper_shutdown(ddev
);
125 static __maybe_unused
int drv_suspend(struct device
*dev
)
127 struct drm_device
*ddev
= dev_get_drvdata(dev
);
128 struct ltdc_device
*ldev
= ddev
->dev_private
;
129 struct drm_atomic_state
*state
;
131 WARN_ON(ldev
->suspend_state
);
133 state
= drm_atomic_helper_suspend(ddev
);
135 return PTR_ERR(state
);
137 ldev
->suspend_state
= state
;
138 pm_runtime_force_suspend(dev
);
143 static __maybe_unused
int drv_resume(struct device
*dev
)
145 struct drm_device
*ddev
= dev_get_drvdata(dev
);
146 struct ltdc_device
*ldev
= ddev
->dev_private
;
149 if (WARN_ON(!ldev
->suspend_state
))
152 pm_runtime_force_resume(dev
);
153 ret
= drm_atomic_helper_resume(ddev
, ldev
->suspend_state
);
155 pm_runtime_force_suspend(dev
);
157 ldev
->suspend_state
= NULL
;
162 static __maybe_unused
int drv_runtime_suspend(struct device
*dev
)
164 struct drm_device
*ddev
= dev_get_drvdata(dev
);
166 DRM_DEBUG_DRIVER("\n");
172 static __maybe_unused
int drv_runtime_resume(struct device
*dev
)
174 struct drm_device
*ddev
= dev_get_drvdata(dev
);
176 DRM_DEBUG_DRIVER("\n");
177 return ltdc_resume(ddev
);
180 static const struct dev_pm_ops drv_pm_ops
= {
181 SET_SYSTEM_SLEEP_PM_OPS(drv_suspend
, drv_resume
)
182 SET_RUNTIME_PM_OPS(drv_runtime_suspend
,
183 drv_runtime_resume
, NULL
)
186 static int stm_drm_platform_probe(struct platform_device
*pdev
)
188 struct device
*dev
= &pdev
->dev
;
189 struct drm_device
*ddev
;
192 DRM_DEBUG("%s\n", __func__
);
194 ret
= aperture_remove_all_conflicting_devices(drv_driver
.name
);
198 dma_set_coherent_mask(dev
, DMA_BIT_MASK(32));
200 ddev
= drm_dev_alloc(&drv_driver
, dev
);
202 return PTR_ERR(ddev
);
204 ret
= drv_load(ddev
);
208 ret
= drm_dev_register(ddev
, 0);
212 drm_client_setup_with_fourcc(ddev
, DRM_FORMAT_RGB565
);
224 static void stm_drm_platform_remove(struct platform_device
*pdev
)
226 struct drm_device
*ddev
= platform_get_drvdata(pdev
);
228 DRM_DEBUG("%s\n", __func__
);
230 drm_dev_unregister(ddev
);
235 static void stm_drm_platform_shutdown(struct platform_device
*pdev
)
237 drm_atomic_helper_shutdown(platform_get_drvdata(pdev
));
240 static const struct of_device_id drv_dt_ids
[] = {
241 { .compatible
= "st,stm32-ltdc"},
244 MODULE_DEVICE_TABLE(of
, drv_dt_ids
);
246 static struct platform_driver stm_drm_platform_driver
= {
247 .probe
= stm_drm_platform_probe
,
248 .remove
= stm_drm_platform_remove
,
249 .shutdown
= stm_drm_platform_shutdown
,
251 .name
= "stm32-display",
252 .of_match_table
= drv_dt_ids
,
257 drm_module_platform_driver(stm_drm_platform_driver
);
259 MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
260 MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
261 MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
262 MODULE_AUTHOR("Mickael Reulier <mickael.reulier@st.com>");
263 MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver");
264 MODULE_LICENSE("GPL v2");