Commit | Line | Data |
---|---|---|
9bbf86fe BG |
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 | ||
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 | ||
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 | ||
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 | ||
137 | static int compare_of(struct device *dev, void *data) | |
138 | { | |
139 | return dev->of_node == data; | |
140 | } | |
141 | ||
142 | static int sti_drm_bind(struct device *dev) | |
143 | { | |
144 | return drm_platform_init(&sti_drm_driver, to_platform_device(dev)); | |
145 | } | |
146 | ||
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 | ||
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 | ||
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 | ||
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 (!master) | |
205 | return -EINVAL; | |
206 | ||
207 | platform_set_drvdata(pdev, master); | |
208 | return 0; | |
209 | } | |
210 | ||
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"); |