]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/msm/msm_drv.c
drm/msm: add register definitions for gpu
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / msm / msm_drv.c
CommitLineData
c8afe684
RC
1/*
2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "msm_drv.h"
19
20#include <mach/iommu.h>
21
22static void msm_fb_output_poll_changed(struct drm_device *dev)
23{
24 struct msm_drm_private *priv = dev->dev_private;
25 if (priv->fbdev)
26 drm_fb_helper_hotplug_event(priv->fbdev);
27}
28
29static const struct drm_mode_config_funcs mode_config_funcs = {
30 .fb_create = msm_framebuffer_create,
31 .output_poll_changed = msm_fb_output_poll_changed,
32};
33
34static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
35 unsigned long iova, int flags, void *arg)
36{
37 DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
38 return 0;
39}
40
41int msm_register_iommu(struct drm_device *dev, struct iommu_domain *iommu)
42{
43 struct msm_drm_private *priv = dev->dev_private;
44 int idx = priv->num_iommus++;
45
46 if (WARN_ON(idx >= ARRAY_SIZE(priv->iommus)))
47 return -EINVAL;
48
49 priv->iommus[idx] = iommu;
50
51 iommu_set_fault_handler(iommu, msm_fault_handler, dev);
52
53 /* need to iommu_attach_device() somewhere?? on resume?? */
54
55 return idx;
56}
57
58int msm_iommu_attach(struct drm_device *dev, struct iommu_domain *iommu,
59 const char **names, int cnt)
60{
61 int i, ret;
62
63 for (i = 0; i < cnt; i++) {
64 struct device *ctx = msm_iommu_get_ctx(names[i]);
65 if (!ctx)
66 continue;
67 ret = iommu_attach_device(iommu, ctx);
68 if (ret) {
69 dev_warn(dev->dev, "could not attach iommu to %s", names[i]);
70 return ret;
71 }
72 }
73 return 0;
74}
75
76#ifdef CONFIG_DRM_MSM_REGISTER_LOGGING
77static bool reglog = false;
78MODULE_PARM_DESC(reglog, "Enable register read/write logging");
79module_param(reglog, bool, 0600);
80#else
81#define reglog 0
82#endif
83
84void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
85 const char *dbgname)
86{
87 struct resource *res;
88 unsigned long size;
89 void __iomem *ptr;
90
91 if (name)
92 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
93 else
94 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
95
96 if (!res) {
97 dev_err(&pdev->dev, "failed to get memory resource: %s\n", name);
98 return ERR_PTR(-EINVAL);
99 }
100
101 size = resource_size(res);
102
103 ptr = devm_ioremap_nocache(&pdev->dev, res->start, size);
104 if (!ptr) {
105 dev_err(&pdev->dev, "failed to ioremap: %s\n", name);
106 return ERR_PTR(-ENOMEM);
107 }
108
109 if (reglog)
110 printk(KERN_DEBUG "IO:region %s %08x %08lx\n", dbgname, (u32)ptr, size);
111
112 return ptr;
113}
114
115void msm_writel(u32 data, void __iomem *addr)
116{
117 if (reglog)
118 printk(KERN_DEBUG "IO:W %08x %08x\n", (u32)addr, data);
119 writel(data, addr);
120}
121
122u32 msm_readl(const void __iomem *addr)
123{
124 u32 val = readl(addr);
125 if (reglog)
126 printk(KERN_ERR "IO:R %08x %08x\n", (u32)addr, val);
127 return val;
128}
129
130/*
131 * DRM operations:
132 */
133
134static int msm_unload(struct drm_device *dev)
135{
136 struct msm_drm_private *priv = dev->dev_private;
137 struct msm_kms *kms = priv->kms;
138
139 drm_kms_helper_poll_fini(dev);
140 drm_mode_config_cleanup(dev);
141 drm_vblank_cleanup(dev);
142
143 pm_runtime_get_sync(dev->dev);
144 drm_irq_uninstall(dev);
145 pm_runtime_put_sync(dev->dev);
146
147 flush_workqueue(priv->wq);
148 destroy_workqueue(priv->wq);
149
150 if (kms) {
151 pm_runtime_disable(dev->dev);
152 kms->funcs->destroy(kms);
153 }
154
155
156 dev->dev_private = NULL;
157
158 kfree(priv);
159
160 return 0;
161}
162
163static int msm_load(struct drm_device *dev, unsigned long flags)
164{
165 struct platform_device *pdev = dev->platformdev;
166 struct msm_drm_private *priv;
167 struct msm_kms *kms;
168 int ret;
169
170 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
171 if (!priv) {
172 dev_err(dev->dev, "failed to allocate private data\n");
173 return -ENOMEM;
174 }
175
176 dev->dev_private = priv;
177
178 priv->wq = alloc_ordered_workqueue("msm", 0);
179
180 INIT_LIST_HEAD(&priv->inactive_list);
181
182 drm_mode_config_init(dev);
183
184 kms = mdp4_kms_init(dev);
185 if (IS_ERR(kms)) {
186 /*
187 * NOTE: once we have GPU support, having no kms should not
188 * be considered fatal.. ideally we would still support gpu
189 * and (for example) use dmabuf/prime to share buffers with
190 * imx drm driver on iMX5
191 */
192 dev_err(dev->dev, "failed to load kms\n");
193 ret = PTR_ERR(priv->kms);
194 goto fail;
195 }
196
197 priv->kms = kms;
198
199 if (kms) {
200 pm_runtime_enable(dev->dev);
201 ret = kms->funcs->hw_init(kms);
202 if (ret) {
203 dev_err(dev->dev, "kms hw init failed: %d\n", ret);
204 goto fail;
205 }
206 }
207
208 dev->mode_config.min_width = 0;
209 dev->mode_config.min_height = 0;
210 dev->mode_config.max_width = 2048;
211 dev->mode_config.max_height = 2048;
212 dev->mode_config.funcs = &mode_config_funcs;
213
214 ret = drm_vblank_init(dev, 1);
215 if (ret < 0) {
216 dev_err(dev->dev, "failed to initialize vblank\n");
217 goto fail;
218 }
219
220 pm_runtime_get_sync(dev->dev);
221 ret = drm_irq_install(dev);
222 pm_runtime_put_sync(dev->dev);
223 if (ret < 0) {
224 dev_err(dev->dev, "failed to install IRQ handler\n");
225 goto fail;
226 }
227
228 platform_set_drvdata(pdev, dev);
229
230#ifdef CONFIG_DRM_MSM_FBDEV
231 priv->fbdev = msm_fbdev_init(dev);
232#endif
233
234 drm_kms_helper_poll_init(dev);
235
236 return 0;
237
238fail:
239 msm_unload(dev);
240 return ret;
241}
242
243static void msm_preclose(struct drm_device *dev, struct drm_file *file)
244{
245 struct msm_drm_private *priv = dev->dev_private;
246 struct msm_kms *kms = priv->kms;
247 if (kms)
248 kms->funcs->preclose(kms, file);
249}
250
251static void msm_lastclose(struct drm_device *dev)
252{
253 struct msm_drm_private *priv = dev->dev_private;
254 if (priv->fbdev) {
255 drm_modeset_lock_all(dev);
256 drm_fb_helper_restore_fbdev_mode(priv->fbdev);
257 drm_modeset_unlock_all(dev);
258 }
259}
260
261static irqreturn_t msm_irq(DRM_IRQ_ARGS)
262{
263 struct drm_device *dev = arg;
264 struct msm_drm_private *priv = dev->dev_private;
265 struct msm_kms *kms = priv->kms;
266 BUG_ON(!kms);
267 return kms->funcs->irq(kms);
268}
269
270static void msm_irq_preinstall(struct drm_device *dev)
271{
272 struct msm_drm_private *priv = dev->dev_private;
273 struct msm_kms *kms = priv->kms;
274 BUG_ON(!kms);
275 kms->funcs->irq_preinstall(kms);
276}
277
278static int msm_irq_postinstall(struct drm_device *dev)
279{
280 struct msm_drm_private *priv = dev->dev_private;
281 struct msm_kms *kms = priv->kms;
282 BUG_ON(!kms);
283 return kms->funcs->irq_postinstall(kms);
284}
285
286static void msm_irq_uninstall(struct drm_device *dev)
287{
288 struct msm_drm_private *priv = dev->dev_private;
289 struct msm_kms *kms = priv->kms;
290 BUG_ON(!kms);
291 kms->funcs->irq_uninstall(kms);
292}
293
294static int msm_enable_vblank(struct drm_device *dev, int crtc_id)
295{
296 struct msm_drm_private *priv = dev->dev_private;
297 struct msm_kms *kms = priv->kms;
298 if (!kms)
299 return -ENXIO;
300 DBG("dev=%p, crtc=%d", dev, crtc_id);
301 return kms->funcs->enable_vblank(kms, priv->crtcs[crtc_id]);
302}
303
304static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
305{
306 struct msm_drm_private *priv = dev->dev_private;
307 struct msm_kms *kms = priv->kms;
308 if (!kms)
309 return;
310 DBG("dev=%p, crtc=%d", dev, crtc_id);
311 kms->funcs->disable_vblank(kms, priv->crtcs[crtc_id]);
312}
313
314/*
315 * DRM debugfs:
316 */
317
318#ifdef CONFIG_DEBUG_FS
319static int msm_gem_show(struct drm_device *dev, struct seq_file *m)
320{
321 struct msm_drm_private *priv = dev->dev_private;
322
323 seq_printf(m, "All Objects:\n");
324 msm_gem_describe_objects(&priv->inactive_list, m);
325
326 return 0;
327}
328
329static int msm_mm_show(struct drm_device *dev, struct seq_file *m)
330{
331 return drm_mm_dump_table(m, dev->mm_private);
332}
333
334static int msm_fb_show(struct drm_device *dev, struct seq_file *m)
335{
336 struct msm_drm_private *priv = dev->dev_private;
337 struct drm_framebuffer *fb, *fbdev_fb = NULL;
338
339 if (priv->fbdev) {
340 seq_printf(m, "fbcon ");
341 fbdev_fb = priv->fbdev->fb;
342 msm_framebuffer_describe(fbdev_fb, m);
343 }
344
345 mutex_lock(&dev->mode_config.fb_lock);
346 list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
347 if (fb == fbdev_fb)
348 continue;
349
350 seq_printf(m, "user ");
351 msm_framebuffer_describe(fb, m);
352 }
353 mutex_unlock(&dev->mode_config.fb_lock);
354
355 return 0;
356}
357
358static int show_locked(struct seq_file *m, void *arg)
359{
360 struct drm_info_node *node = (struct drm_info_node *) m->private;
361 struct drm_device *dev = node->minor->dev;
362 int (*show)(struct drm_device *dev, struct seq_file *m) =
363 node->info_ent->data;
364 int ret;
365
366 ret = mutex_lock_interruptible(&dev->struct_mutex);
367 if (ret)
368 return ret;
369
370 ret = show(dev, m);
371
372 mutex_unlock(&dev->struct_mutex);
373
374 return ret;
375}
376
377static struct drm_info_list msm_debugfs_list[] = {
378 {"gem", show_locked, 0, msm_gem_show},
379 { "mm", show_locked, 0, msm_mm_show },
380 { "fb", show_locked, 0, msm_fb_show },
381};
382
383static int msm_debugfs_init(struct drm_minor *minor)
384{
385 struct drm_device *dev = minor->dev;
386 int ret;
387
388 ret = drm_debugfs_create_files(msm_debugfs_list,
389 ARRAY_SIZE(msm_debugfs_list),
390 minor->debugfs_root, minor);
391
392 if (ret) {
393 dev_err(dev->dev, "could not install msm_debugfs_list\n");
394 return ret;
395 }
396
397 return ret;
398}
399
400static void msm_debugfs_cleanup(struct drm_minor *minor)
401{
402 drm_debugfs_remove_files(msm_debugfs_list,
403 ARRAY_SIZE(msm_debugfs_list), minor);
404}
405#endif
406
407static const struct vm_operations_struct vm_ops = {
408 .fault = msm_gem_fault,
409 .open = drm_gem_vm_open,
410 .close = drm_gem_vm_close,
411};
412
413static const struct file_operations fops = {
414 .owner = THIS_MODULE,
415 .open = drm_open,
416 .release = drm_release,
417 .unlocked_ioctl = drm_ioctl,
418#ifdef CONFIG_COMPAT
419 .compat_ioctl = drm_compat_ioctl,
420#endif
421 .poll = drm_poll,
422 .read = drm_read,
423 .llseek = no_llseek,
424 .mmap = msm_gem_mmap,
425};
426
427static struct drm_driver msm_driver = {
428 .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
429 .load = msm_load,
430 .unload = msm_unload,
431 .preclose = msm_preclose,
432 .lastclose = msm_lastclose,
433 .irq_handler = msm_irq,
434 .irq_preinstall = msm_irq_preinstall,
435 .irq_postinstall = msm_irq_postinstall,
436 .irq_uninstall = msm_irq_uninstall,
437 .get_vblank_counter = drm_vblank_count,
438 .enable_vblank = msm_enable_vblank,
439 .disable_vblank = msm_disable_vblank,
440 .gem_free_object = msm_gem_free_object,
441 .gem_vm_ops = &vm_ops,
442 .dumb_create = msm_gem_dumb_create,
443 .dumb_map_offset = msm_gem_dumb_map_offset,
444 .dumb_destroy = msm_gem_dumb_destroy,
445#ifdef CONFIG_DEBUG_FS
446 .debugfs_init = msm_debugfs_init,
447 .debugfs_cleanup = msm_debugfs_cleanup,
448#endif
449 .fops = &fops,
450 .name = "msm",
451 .desc = "MSM Snapdragon DRM",
452 .date = "20130625",
453 .major = 1,
454 .minor = 0,
455};
456
457#ifdef CONFIG_PM_SLEEP
458static int msm_pm_suspend(struct device *dev)
459{
460 struct drm_device *ddev = dev_get_drvdata(dev);
461
462 drm_kms_helper_poll_disable(ddev);
463
464 return 0;
465}
466
467static int msm_pm_resume(struct device *dev)
468{
469 struct drm_device *ddev = dev_get_drvdata(dev);
470
471 drm_kms_helper_poll_enable(ddev);
472
473 return 0;
474}
475#endif
476
477static const struct dev_pm_ops msm_pm_ops = {
478 SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume)
479};
480
481/*
482 * Platform driver:
483 */
484
485static int msm_pdev_probe(struct platform_device *pdev)
486{
487 return drm_platform_init(&msm_driver, pdev);
488}
489
490static int msm_pdev_remove(struct platform_device *pdev)
491{
492 drm_platform_exit(&msm_driver, pdev);
493
494 return 0;
495}
496
497static const struct platform_device_id msm_id[] = {
498 { "mdp", 0 },
499 { }
500};
501
502static struct platform_driver msm_platform_driver = {
503 .probe = msm_pdev_probe,
504 .remove = msm_pdev_remove,
505 .driver = {
506 .owner = THIS_MODULE,
507 .name = "msm",
508 .pm = &msm_pm_ops,
509 },
510 .id_table = msm_id,
511};
512
513static int __init msm_drm_register(void)
514{
515 DBG("init");
516 hdmi_register();
517 return platform_driver_register(&msm_platform_driver);
518}
519
520static void __exit msm_drm_unregister(void)
521{
522 DBG("fini");
523 platform_driver_unregister(&msm_platform_driver);
524 hdmi_unregister();
525}
526
527module_init(msm_drm_register);
528module_exit(msm_drm_unregister);
529
530MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
531MODULE_DESCRIPTION("MSM DRM Driver");
532MODULE_LICENSE("GPL");