1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2014
4 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
7 #include <linux/component.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/of_platform.h>
13 #include <drm/drm_atomic.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_debugfs.h>
16 #include <drm/drm_drv.h>
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_fb_helper.h>
19 #include <drm/drm_gem_cma_helper.h>
20 #include <drm/drm_gem_framebuffer_helper.h>
21 #include <drm/drm_of.h>
22 #include <drm/drm_probe_helper.h>
25 #include "sti_plane.h"
27 #define DRIVER_NAME "sti"
28 #define DRIVER_DESC "STMicroelectronics SoC DRM"
29 #define DRIVER_DATE "20140601"
30 #define DRIVER_MAJOR 1
31 #define DRIVER_MINOR 0
33 #define STI_MAX_FB_HEIGHT 4096
34 #define STI_MAX_FB_WIDTH 4096
36 static int sti_drm_fps_get(void *data
, u64
*val
)
38 struct drm_device
*drm_dev
= data
;
43 list_for_each_entry(p
, &drm_dev
->mode_config
.plane_list
, head
) {
44 struct sti_plane
*plane
= to_sti_plane(p
);
46 *val
|= plane
->fps_info
.output
<< i
;
53 static int sti_drm_fps_set(void *data
, u64 val
)
55 struct drm_device
*drm_dev
= data
;
59 list_for_each_entry(p
, &drm_dev
->mode_config
.plane_list
, head
) {
60 struct sti_plane
*plane
= to_sti_plane(p
);
62 memset(&plane
->fps_info
, 0, sizeof(plane
->fps_info
));
63 plane
->fps_info
.output
= (val
>> i
) & 1;
71 DEFINE_SIMPLE_ATTRIBUTE(sti_drm_fps_fops
,
72 sti_drm_fps_get
, sti_drm_fps_set
, "%llu\n");
74 static int sti_drm_fps_dbg_show(struct seq_file
*s
, void *data
)
76 struct drm_info_node
*node
= s
->private;
77 struct drm_device
*dev
= node
->minor
->dev
;
80 list_for_each_entry(p
, &dev
->mode_config
.plane_list
, head
) {
81 struct sti_plane
*plane
= to_sti_plane(p
);
83 seq_printf(s
, "%s%s\n",
84 plane
->fps_info
.fps_str
,
85 plane
->fps_info
.fips_str
);
91 static struct drm_info_list sti_drm_dbg_list
[] = {
92 {"fps_get", sti_drm_fps_dbg_show
, 0},
95 static void sti_drm_dbg_init(struct drm_minor
*minor
)
97 drm_debugfs_create_files(sti_drm_dbg_list
,
98 ARRAY_SIZE(sti_drm_dbg_list
),
99 minor
->debugfs_root
, minor
);
101 debugfs_create_file("fps_show", S_IRUGO
| S_IWUSR
, minor
->debugfs_root
,
102 minor
->dev
, &sti_drm_fps_fops
);
104 DRM_INFO("%s: debugfs installed\n", DRIVER_NAME
);
107 static const struct drm_mode_config_funcs sti_mode_config_funcs
= {
108 .fb_create
= drm_gem_fb_create
,
109 .atomic_check
= drm_atomic_helper_check
,
110 .atomic_commit
= drm_atomic_helper_commit
,
113 static void sti_mode_config_init(struct drm_device
*dev
)
115 dev
->mode_config
.min_width
= 0;
116 dev
->mode_config
.min_height
= 0;
119 * set max width and height as default value.
120 * this value would be used to check framebuffer size limitation
121 * at drm_mode_addfb().
123 dev
->mode_config
.max_width
= STI_MAX_FB_WIDTH
;
124 dev
->mode_config
.max_height
= STI_MAX_FB_HEIGHT
;
126 dev
->mode_config
.funcs
= &sti_mode_config_funcs
;
128 dev
->mode_config
.normalize_zpos
= true;
131 DEFINE_DRM_GEM_CMA_FOPS(sti_driver_fops
);
133 static const struct drm_driver sti_driver
= {
134 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
| DRIVER_ATOMIC
,
135 .fops
= &sti_driver_fops
,
136 DRM_GEM_CMA_DRIVER_OPS
,
138 .debugfs_init
= sti_drm_dbg_init
,
143 .major
= DRIVER_MAJOR
,
144 .minor
= DRIVER_MINOR
,
147 static int compare_of(struct device
*dev
, void *data
)
149 return dev
->of_node
== data
;
152 static int sti_init(struct drm_device
*ddev
)
154 struct sti_private
*private;
156 private = kzalloc(sizeof(*private), GFP_KERNEL
);
160 ddev
->dev_private
= (void *)private;
161 dev_set_drvdata(ddev
->dev
, ddev
);
162 private->drm_dev
= ddev
;
164 drm_mode_config_init(ddev
);
166 sti_mode_config_init(ddev
);
168 drm_kms_helper_poll_init(ddev
);
173 static void sti_cleanup(struct drm_device
*ddev
)
175 struct sti_private
*private = ddev
->dev_private
;
177 drm_kms_helper_poll_fini(ddev
);
178 drm_atomic_helper_shutdown(ddev
);
179 drm_mode_config_cleanup(ddev
);
180 component_unbind_all(ddev
->dev
, ddev
);
182 ddev
->dev_private
= NULL
;
185 static int sti_bind(struct device
*dev
)
187 struct drm_device
*ddev
;
190 ddev
= drm_dev_alloc(&sti_driver
, dev
);
192 return PTR_ERR(ddev
);
194 ret
= sti_init(ddev
);
196 goto err_drm_dev_put
;
198 ret
= component_bind_all(ddev
->dev
, ddev
);
202 ret
= drm_dev_register(ddev
, 0);
206 drm_mode_config_reset(ddev
);
208 drm_fbdev_generic_setup(ddev
, 32);
219 static void sti_unbind(struct device
*dev
)
221 struct drm_device
*ddev
= dev_get_drvdata(dev
);
223 drm_dev_unregister(ddev
);
228 static const struct component_master_ops sti_ops
= {
230 .unbind
= sti_unbind
,
233 static int sti_platform_probe(struct platform_device
*pdev
)
235 struct device
*dev
= &pdev
->dev
;
236 struct device_node
*node
= dev
->of_node
;
237 struct device_node
*child_np
;
238 struct component_match
*match
= NULL
;
240 dma_set_coherent_mask(dev
, DMA_BIT_MASK(32));
242 devm_of_platform_populate(dev
);
244 child_np
= of_get_next_available_child(node
, NULL
);
247 drm_of_component_match_add(dev
, &match
, compare_of
,
249 child_np
= of_get_next_available_child(node
, child_np
);
252 return component_master_add_with_match(dev
, &sti_ops
, match
);
255 static int sti_platform_remove(struct platform_device
*pdev
)
257 component_master_del(&pdev
->dev
, &sti_ops
);
262 static const struct of_device_id sti_dt_ids
[] = {
263 { .compatible
= "st,sti-display-subsystem", },
266 MODULE_DEVICE_TABLE(of
, sti_dt_ids
);
268 static struct platform_driver sti_platform_driver
= {
269 .probe
= sti_platform_probe
,
270 .remove
= sti_platform_remove
,
273 .of_match_table
= sti_dt_ids
,
277 static struct platform_driver
* const drivers
[] = {
284 &sti_compositor_driver
,
285 &sti_platform_driver
,
288 static int sti_drm_init(void)
290 return platform_register_drivers(drivers
, ARRAY_SIZE(drivers
));
292 module_init(sti_drm_init
);
294 static void sti_drm_exit(void)
296 platform_unregister_drivers(drivers
, ARRAY_SIZE(drivers
));
298 module_exit(sti_drm_exit
);
300 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
301 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
302 MODULE_LICENSE("GPL");