• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) STMicroelectronics SA 2014
3  * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4  * License terms:  GNU General Public License (GPL), version 2
5  */
6 
7 #include <drm/drmP.h>
8 
9 #include <linux/component.h>
10 #include <linux/debugfs.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 
15 #include <drm/drm_crtc_helper.h>
16 #include <drm/drm_gem_cma_helper.h>
17 #include <drm/drm_fb_cma_helper.h>
18 
19 #include "sti_drm_drv.h"
20 #include "sti_drm_crtc.h"
21 
22 #define DRIVER_NAME	"sti"
23 #define DRIVER_DESC	"STMicroelectronics SoC DRM"
24 #define DRIVER_DATE	"20140601"
25 #define DRIVER_MAJOR	1
26 #define DRIVER_MINOR	0
27 
28 #define STI_MAX_FB_HEIGHT	4096
29 #define STI_MAX_FB_WIDTH	4096
30 
31 static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
32 	.fb_create = drm_fb_cma_create,
33 };
34 
sti_drm_mode_config_init(struct drm_device * dev)35 static void sti_drm_mode_config_init(struct drm_device *dev)
36 {
37 	dev->mode_config.min_width = 0;
38 	dev->mode_config.min_height = 0;
39 
40 	/*
41 	 * set max width and height as default value.
42 	 * this value would be used to check framebuffer size limitation
43 	 * at drm_mode_addfb().
44 	 */
45 	dev->mode_config.max_width = STI_MAX_FB_HEIGHT;
46 	dev->mode_config.max_height = STI_MAX_FB_WIDTH;
47 
48 	dev->mode_config.funcs = &sti_drm_mode_config_funcs;
49 }
50 
sti_drm_load(struct drm_device * dev,unsigned long flags)51 static int sti_drm_load(struct drm_device *dev, unsigned long flags)
52 {
53 	struct sti_drm_private *private;
54 	int ret;
55 
56 	private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL);
57 	if (!private) {
58 		DRM_ERROR("Failed to allocate private\n");
59 		return -ENOMEM;
60 	}
61 	dev->dev_private = (void *)private;
62 	private->drm_dev = dev;
63 
64 	drm_mode_config_init(dev);
65 	drm_kms_helper_poll_init(dev);
66 
67 	sti_drm_mode_config_init(dev);
68 
69 	ret = component_bind_all(dev->dev, dev);
70 	if (ret)
71 		return ret;
72 
73 	drm_helper_disable_unused_functions(dev);
74 
75 #ifdef CONFIG_DRM_STI_FBDEV
76 	drm_fbdev_cma_init(dev, 32,
77 		   dev->mode_config.num_crtc,
78 		   dev->mode_config.num_connector);
79 #endif
80 	return 0;
81 }
82 
83 static const struct file_operations sti_drm_driver_fops = {
84 	.owner = THIS_MODULE,
85 	.open = drm_open,
86 	.mmap = drm_gem_cma_mmap,
87 	.poll = drm_poll,
88 	.read = drm_read,
89 	.unlocked_ioctl = drm_ioctl,
90 #ifdef CONFIG_COMPAT
91 	.compat_ioctl = drm_compat_ioctl,
92 #endif
93 	.release = drm_release,
94 };
95 
sti_drm_gem_prime_export(struct drm_device * dev,struct drm_gem_object * obj,int flags)96 static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev,
97 						struct drm_gem_object *obj,
98 						int flags)
99 {
100 	/* we want to be able to write in mmapped buffer */
101 	flags |= O_RDWR;
102 	return drm_gem_prime_export(dev, obj, flags);
103 }
104 
105 static struct drm_driver sti_drm_driver = {
106 	.driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
107 	    DRIVER_GEM | DRIVER_PRIME,
108 	.load = sti_drm_load,
109 	.gem_free_object = drm_gem_cma_free_object,
110 	.gem_vm_ops = &drm_gem_cma_vm_ops,
111 	.dumb_create = drm_gem_cma_dumb_create,
112 	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
113 	.dumb_destroy = drm_gem_dumb_destroy,
114 	.fops = &sti_drm_driver_fops,
115 
116 	.get_vblank_counter = drm_vblank_count,
117 	.enable_vblank = sti_drm_crtc_enable_vblank,
118 	.disable_vblank = sti_drm_crtc_disable_vblank,
119 
120 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
121 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
122 	.gem_prime_export = sti_drm_gem_prime_export,
123 	.gem_prime_import = drm_gem_prime_import,
124 	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
125 	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
126 	.gem_prime_vmap = drm_gem_cma_prime_vmap,
127 	.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
128 	.gem_prime_mmap = drm_gem_cma_prime_mmap,
129 
130 	.name = DRIVER_NAME,
131 	.desc = DRIVER_DESC,
132 	.date = DRIVER_DATE,
133 	.major = DRIVER_MAJOR,
134 	.minor = DRIVER_MINOR,
135 };
136 
compare_of(struct device * dev,void * data)137 static int compare_of(struct device *dev, void *data)
138 {
139 	return dev->of_node == data;
140 }
141 
sti_drm_bind(struct device * dev)142 static int sti_drm_bind(struct device *dev)
143 {
144 	return drm_platform_init(&sti_drm_driver, to_platform_device(dev));
145 }
146 
sti_drm_unbind(struct device * dev)147 static void sti_drm_unbind(struct device *dev)
148 {
149 	drm_put_dev(dev_get_drvdata(dev));
150 }
151 
152 static const struct component_master_ops sti_drm_ops = {
153 	.bind = sti_drm_bind,
154 	.unbind = sti_drm_unbind,
155 };
156 
sti_drm_master_probe(struct platform_device * pdev)157 static int sti_drm_master_probe(struct platform_device *pdev)
158 {
159 	struct device *dev = &pdev->dev;
160 	struct device_node *node = dev->parent->of_node;
161 	struct device_node *child_np;
162 	struct component_match *match = NULL;
163 
164 	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
165 
166 	child_np = of_get_next_available_child(node, NULL);
167 
168 	while (child_np) {
169 		component_match_add(dev, &match, compare_of, child_np);
170 		of_node_put(child_np);
171 		child_np = of_get_next_available_child(node, child_np);
172 	}
173 
174 	return component_master_add_with_match(dev, &sti_drm_ops, match);
175 }
176 
sti_drm_master_remove(struct platform_device * pdev)177 static int sti_drm_master_remove(struct platform_device *pdev)
178 {
179 	component_master_del(&pdev->dev, &sti_drm_ops);
180 	return 0;
181 }
182 
183 static struct platform_driver sti_drm_master_driver = {
184 	.probe = sti_drm_master_probe,
185 	.remove = sti_drm_master_remove,
186 	.driver = {
187 		.owner = THIS_MODULE,
188 		.name = DRIVER_NAME "__master",
189 	},
190 };
191 
sti_drm_platform_probe(struct platform_device * pdev)192 static int sti_drm_platform_probe(struct platform_device *pdev)
193 {
194 	struct device *dev = &pdev->dev;
195 	struct device_node *node = dev->of_node;
196 	struct platform_device *master;
197 
198 	of_platform_populate(node, NULL, NULL, dev);
199 
200 	platform_driver_register(&sti_drm_master_driver);
201 	master = platform_device_register_resndata(dev,
202 			DRIVER_NAME "__master", -1,
203 			NULL, 0, NULL, 0);
204 	if (IS_ERR(master))
205                return PTR_ERR(master);
206 
207 	platform_set_drvdata(pdev, master);
208 	return 0;
209 }
210 
sti_drm_platform_remove(struct platform_device * pdev)211 static int sti_drm_platform_remove(struct platform_device *pdev)
212 {
213 	struct platform_device *master = platform_get_drvdata(pdev);
214 
215 	of_platform_depopulate(&pdev->dev);
216 	platform_device_unregister(master);
217 	platform_driver_unregister(&sti_drm_master_driver);
218 	return 0;
219 }
220 
221 static const struct of_device_id sti_drm_dt_ids[] = {
222 	{ .compatible = "st,sti-display-subsystem", },
223 	{ /* end node */ },
224 };
225 MODULE_DEVICE_TABLE(of, sti_drm_dt_ids);
226 
227 static struct platform_driver sti_drm_platform_driver = {
228 	.probe = sti_drm_platform_probe,
229 	.remove = sti_drm_platform_remove,
230 	.driver = {
231 		.owner = THIS_MODULE,
232 		.name = DRIVER_NAME,
233 		.of_match_table = sti_drm_dt_ids,
234 	},
235 };
236 
237 module_platform_driver(sti_drm_platform_driver);
238 
239 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
240 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
241 MODULE_LICENSE("GPL");
242