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); | |
f78e772a BG |
70 | if (ret) { |
71 | drm_kms_helper_poll_fini(dev); | |
72 | drm_mode_config_cleanup(dev); | |
73 | kfree(private); | |
9bbf86fe | 74 | return ret; |
f78e772a | 75 | } |
9bbf86fe BG |
76 | |
77 | drm_helper_disable_unused_functions(dev); | |
78 | ||
79 | #ifdef CONFIG_DRM_STI_FBDEV | |
80 | drm_fbdev_cma_init(dev, 32, | |
81 | dev->mode_config.num_crtc, | |
82 | dev->mode_config.num_connector); | |
83 | #endif | |
84 | return 0; | |
85 | } | |
86 | ||
87 | static const struct file_operations sti_drm_driver_fops = { | |
88 | .owner = THIS_MODULE, | |
89 | .open = drm_open, | |
90 | .mmap = drm_gem_cma_mmap, | |
91 | .poll = drm_poll, | |
92 | .read = drm_read, | |
93 | .unlocked_ioctl = drm_ioctl, | |
94 | #ifdef CONFIG_COMPAT | |
95 | .compat_ioctl = drm_compat_ioctl, | |
96 | #endif | |
97 | .release = drm_release, | |
98 | }; | |
99 | ||
100 | static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev, | |
101 | struct drm_gem_object *obj, | |
102 | int flags) | |
103 | { | |
104 | /* we want to be able to write in mmapped buffer */ | |
105 | flags |= O_RDWR; | |
106 | return drm_gem_prime_export(dev, obj, flags); | |
107 | } | |
108 | ||
109 | static struct drm_driver sti_drm_driver = { | |
110 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | | |
111 | DRIVER_GEM | DRIVER_PRIME, | |
112 | .load = sti_drm_load, | |
113 | .gem_free_object = drm_gem_cma_free_object, | |
114 | .gem_vm_ops = &drm_gem_cma_vm_ops, | |
115 | .dumb_create = drm_gem_cma_dumb_create, | |
116 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | |
117 | .dumb_destroy = drm_gem_dumb_destroy, | |
118 | .fops = &sti_drm_driver_fops, | |
119 | ||
120 | .get_vblank_counter = drm_vblank_count, | |
121 | .enable_vblank = sti_drm_crtc_enable_vblank, | |
122 | .disable_vblank = sti_drm_crtc_disable_vblank, | |
123 | ||
124 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | |
125 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | |
126 | .gem_prime_export = sti_drm_gem_prime_export, | |
127 | .gem_prime_import = drm_gem_prime_import, | |
128 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | |
129 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | |
130 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | |
131 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | |
132 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | |
133 | ||
134 | .name = DRIVER_NAME, | |
135 | .desc = DRIVER_DESC, | |
136 | .date = DRIVER_DATE, | |
137 | .major = DRIVER_MAJOR, | |
138 | .minor = DRIVER_MINOR, | |
139 | }; | |
140 | ||
141 | static int compare_of(struct device *dev, void *data) | |
142 | { | |
143 | return dev->of_node == data; | |
144 | } | |
145 | ||
146 | static int sti_drm_bind(struct device *dev) | |
147 | { | |
148 | return drm_platform_init(&sti_drm_driver, to_platform_device(dev)); | |
149 | } | |
150 | ||
151 | static void sti_drm_unbind(struct device *dev) | |
152 | { | |
153 | drm_put_dev(dev_get_drvdata(dev)); | |
154 | } | |
155 | ||
156 | static const struct component_master_ops sti_drm_ops = { | |
157 | .bind = sti_drm_bind, | |
158 | .unbind = sti_drm_unbind, | |
159 | }; | |
160 | ||
161 | static int sti_drm_master_probe(struct platform_device *pdev) | |
162 | { | |
163 | struct device *dev = &pdev->dev; | |
164 | struct device_node *node = dev->parent->of_node; | |
165 | struct device_node *child_np; | |
166 | struct component_match *match = NULL; | |
167 | ||
168 | dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | |
169 | ||
170 | child_np = of_get_next_available_child(node, NULL); | |
171 | ||
172 | while (child_np) { | |
173 | component_match_add(dev, &match, compare_of, child_np); | |
174 | of_node_put(child_np); | |
175 | child_np = of_get_next_available_child(node, child_np); | |
176 | } | |
177 | ||
178 | return component_master_add_with_match(dev, &sti_drm_ops, match); | |
179 | } | |
180 | ||
181 | static int sti_drm_master_remove(struct platform_device *pdev) | |
182 | { | |
183 | component_master_del(&pdev->dev, &sti_drm_ops); | |
184 | return 0; | |
185 | } | |
186 | ||
187 | static struct platform_driver sti_drm_master_driver = { | |
188 | .probe = sti_drm_master_probe, | |
189 | .remove = sti_drm_master_remove, | |
190 | .driver = { | |
9bbf86fe BG |
191 | .name = DRIVER_NAME "__master", |
192 | }, | |
193 | }; | |
194 | ||
195 | static int sti_drm_platform_probe(struct platform_device *pdev) | |
196 | { | |
197 | struct device *dev = &pdev->dev; | |
198 | struct device_node *node = dev->of_node; | |
199 | struct platform_device *master; | |
200 | ||
201 | of_platform_populate(node, NULL, NULL, dev); | |
202 | ||
203 | platform_driver_register(&sti_drm_master_driver); | |
204 | master = platform_device_register_resndata(dev, | |
205 | DRIVER_NAME "__master", -1, | |
206 | NULL, 0, NULL, 0); | |
eacd9aa9 WY |
207 | if (IS_ERR(master)) |
208 | return PTR_ERR(master); | |
9bbf86fe BG |
209 | |
210 | platform_set_drvdata(pdev, master); | |
211 | return 0; | |
212 | } | |
213 | ||
214 | static int sti_drm_platform_remove(struct platform_device *pdev) | |
215 | { | |
216 | struct platform_device *master = platform_get_drvdata(pdev); | |
217 | ||
218 | of_platform_depopulate(&pdev->dev); | |
219 | platform_device_unregister(master); | |
220 | platform_driver_unregister(&sti_drm_master_driver); | |
221 | return 0; | |
222 | } | |
223 | ||
224 | static const struct of_device_id sti_drm_dt_ids[] = { | |
225 | { .compatible = "st,sti-display-subsystem", }, | |
226 | { /* end node */ }, | |
227 | }; | |
228 | MODULE_DEVICE_TABLE(of, sti_drm_dt_ids); | |
229 | ||
230 | static struct platform_driver sti_drm_platform_driver = { | |
231 | .probe = sti_drm_platform_probe, | |
232 | .remove = sti_drm_platform_remove, | |
233 | .driver = { | |
9bbf86fe BG |
234 | .name = DRIVER_NAME, |
235 | .of_match_table = sti_drm_dt_ids, | |
236 | }, | |
237 | }; | |
238 | ||
239 | module_platform_driver(sti_drm_platform_driver); | |
240 | ||
241 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); | |
242 | MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); | |
243 | MODULE_LICENSE("GPL"); |