b4e33e3e0250e0fa2b070890628d368987504ce4
[cascardo/linux.git] / drivers / gpu / drm / fsl-dcu / fsl_dcu_drm_drv.c
1 /*
2  * Copyright 2015 Freescale Semiconductor, Inc.
3  *
4  * Freescale DCU drm device driver
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <linux/clk.h>
13 #include <linux/clk-provider.h>
14 #include <linux/io.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/mm.h>
17 #include <linux/module.h>
18 #include <linux/of_platform.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/regmap.h>
23
24 #include <drm/drmP.h>
25 #include <drm/drm_crtc_helper.h>
26 #include <drm/drm_gem_cma_helper.h>
27
28 #include "fsl_dcu_drm_crtc.h"
29 #include "fsl_dcu_drm_drv.h"
30
31 static bool fsl_dcu_drm_is_volatile_reg(struct device *dev, unsigned int reg)
32 {
33         if (reg == DCU_INT_STATUS || reg == DCU_UPDATE_MODE)
34                 return true;
35
36         return false;
37 }
38
39 static const struct regmap_config fsl_dcu_regmap_config = {
40         .reg_bits = 32,
41         .reg_stride = 4,
42         .val_bits = 32,
43         .cache_type = REGCACHE_RBTREE,
44
45         .volatile_reg = fsl_dcu_drm_is_volatile_reg,
46 };
47
48 static int fsl_dcu_drm_irq_init(struct drm_device *dev)
49 {
50         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
51         unsigned int value;
52         int ret;
53
54         ret = drm_irq_install(dev, fsl_dev->irq);
55         if (ret < 0)
56                 dev_err(dev->dev, "failed to install IRQ handler\n");
57
58         ret = regmap_write(fsl_dev->regmap, DCU_INT_STATUS, 0);
59         if (ret)
60                 dev_err(dev->dev, "set DCU_INT_STATUS failed\n");
61         ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value);
62         if (ret)
63                 dev_err(dev->dev, "read DCU_INT_MASK failed\n");
64         value &= DCU_INT_MASK_VBLANK;
65         ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value);
66         if (ret)
67                 dev_err(dev->dev, "set DCU_INT_MASK failed\n");
68         ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
69                            DCU_UPDATE_MODE_READREG);
70         if (ret)
71                 dev_err(dev->dev, "set DCU_UPDATE_MODE failed\n");
72
73         return ret;
74 }
75
76 static int fsl_dcu_load(struct drm_device *drm, unsigned long flags)
77 {
78         struct device *dev = drm->dev;
79         struct fsl_dcu_drm_device *fsl_dev = drm->dev_private;
80         int ret;
81
82         ret = fsl_dcu_drm_modeset_init(fsl_dev);
83         if (ret < 0) {
84                 dev_err(dev, "failed to initialize mode setting\n");
85                 return ret;
86         }
87
88         ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
89         if (ret < 0) {
90                 dev_err(dev, "failed to initialize vblank\n");
91                 goto done;
92         }
93         drm->vblank_disable_allowed = true;
94
95         ret = fsl_dcu_drm_irq_init(drm);
96         if (ret < 0)
97                 goto done;
98         drm->irq_enabled = true;
99
100         fsl_dcu_fbdev_init(drm);
101
102         return 0;
103 done:
104         if (ret) {
105                 drm_mode_config_cleanup(drm);
106                 drm_vblank_cleanup(drm);
107                 drm_irq_uninstall(drm);
108                 drm->dev_private = NULL;
109         }
110
111         return ret;
112 }
113
114 static int fsl_dcu_unload(struct drm_device *dev)
115 {
116         drm_mode_config_cleanup(dev);
117         drm_vblank_cleanup(dev);
118         drm_irq_uninstall(dev);
119
120         dev->dev_private = NULL;
121
122         return 0;
123 }
124
125 static irqreturn_t fsl_dcu_drm_irq(int irq, void *arg)
126 {
127         struct drm_device *dev = arg;
128         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
129         unsigned int int_status;
130         int ret;
131
132         ret = regmap_read(fsl_dev->regmap, DCU_INT_STATUS, &int_status);
133         if (ret)
134                 dev_err(dev->dev, "set DCU_INT_STATUS failed\n");
135         if (int_status & DCU_INT_STATUS_VBLANK)
136                 drm_handle_vblank(dev, 0);
137
138         ret = regmap_write(fsl_dev->regmap, DCU_INT_STATUS, int_status);
139         if (ret)
140                 dev_err(dev->dev, "set DCU_INT_STATUS failed\n");
141         ret = regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE,
142                            DCU_UPDATE_MODE_READREG);
143         if (ret)
144                 dev_err(dev->dev, "set DCU_UPDATE_MODE failed\n");
145
146         return IRQ_HANDLED;
147 }
148
149 static int fsl_dcu_drm_enable_vblank(struct drm_device *dev, unsigned int pipe)
150 {
151         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
152         unsigned int value;
153         int ret;
154
155         ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value);
156         if (ret)
157                 dev_err(dev->dev, "read DCU_INT_MASK failed\n");
158         value &= ~DCU_INT_MASK_VBLANK;
159         ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value);
160         if (ret)
161                 dev_err(dev->dev, "set DCU_INT_MASK failed\n");
162         return 0;
163 }
164
165 static void fsl_dcu_drm_disable_vblank(struct drm_device *dev,
166                                        unsigned int pipe)
167 {
168         struct fsl_dcu_drm_device *fsl_dev = dev->dev_private;
169         unsigned int value;
170         int ret;
171
172         ret = regmap_read(fsl_dev->regmap, DCU_INT_MASK, &value);
173         if (ret)
174                 dev_err(dev->dev, "read DCU_INT_MASK failed\n");
175         value |= DCU_INT_MASK_VBLANK;
176         ret = regmap_write(fsl_dev->regmap, DCU_INT_MASK, value);
177         if (ret)
178                 dev_err(dev->dev, "set DCU_INT_MASK failed\n");
179 }
180
181 static const struct file_operations fsl_dcu_drm_fops = {
182         .owner          = THIS_MODULE,
183         .open           = drm_open,
184         .release        = drm_release,
185         .unlocked_ioctl = drm_ioctl,
186 #ifdef CONFIG_COMPAT
187         .compat_ioctl   = drm_compat_ioctl,
188 #endif
189         .poll           = drm_poll,
190         .read           = drm_read,
191         .llseek         = no_llseek,
192         .mmap           = drm_gem_cma_mmap,
193 };
194
195 static struct drm_driver fsl_dcu_drm_driver = {
196         .driver_features        = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
197                                 | DRIVER_PRIME | DRIVER_ATOMIC,
198         .load                   = fsl_dcu_load,
199         .unload                 = fsl_dcu_unload,
200         .irq_handler            = fsl_dcu_drm_irq,
201         .get_vblank_counter     = drm_vblank_no_hw_counter,
202         .enable_vblank          = fsl_dcu_drm_enable_vblank,
203         .disable_vblank         = fsl_dcu_drm_disable_vblank,
204         .gem_free_object        = drm_gem_cma_free_object,
205         .gem_vm_ops             = &drm_gem_cma_vm_ops,
206         .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
207         .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
208         .gem_prime_import       = drm_gem_prime_import,
209         .gem_prime_export       = drm_gem_prime_export,
210         .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
211         .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
212         .gem_prime_vmap         = drm_gem_cma_prime_vmap,
213         .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
214         .gem_prime_mmap         = drm_gem_cma_prime_mmap,
215         .dumb_create            = drm_gem_cma_dumb_create,
216         .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
217         .dumb_destroy           = drm_gem_dumb_destroy,
218         .fops                   = &fsl_dcu_drm_fops,
219         .name                   = "fsl-dcu-drm",
220         .desc                   = "Freescale DCU DRM",
221         .date                   = "20150213",
222         .major                  = 1,
223         .minor                  = 0,
224 };
225
226 #ifdef CONFIG_PM_SLEEP
227 static int fsl_dcu_drm_pm_suspend(struct device *dev)
228 {
229         struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
230
231         if (!fsl_dev)
232                 return 0;
233
234         drm_kms_helper_poll_disable(fsl_dev->drm);
235         regcache_cache_only(fsl_dev->regmap, true);
236         regcache_mark_dirty(fsl_dev->regmap);
237         clk_disable(fsl_dev->clk);
238         clk_unprepare(fsl_dev->clk);
239
240         return 0;
241 }
242
243 static int fsl_dcu_drm_pm_resume(struct device *dev)
244 {
245         struct fsl_dcu_drm_device *fsl_dev = dev_get_drvdata(dev);
246         int ret;
247
248         if (!fsl_dev)
249                 return 0;
250
251         ret = clk_enable(fsl_dev->clk);
252         if (ret < 0) {
253                 dev_err(dev, "failed to enable dcu clk\n");
254                 clk_unprepare(fsl_dev->clk);
255                 return ret;
256         }
257         ret = clk_prepare(fsl_dev->clk);
258         if (ret < 0) {
259                 dev_err(dev, "failed to prepare dcu clk\n");
260                 return ret;
261         }
262
263         drm_kms_helper_poll_enable(fsl_dev->drm);
264         regcache_cache_only(fsl_dev->regmap, false);
265         regcache_sync(fsl_dev->regmap);
266
267         return 0;
268 }
269 #endif
270
271 static const struct dev_pm_ops fsl_dcu_drm_pm_ops = {
272         SET_SYSTEM_SLEEP_PM_OPS(fsl_dcu_drm_pm_suspend, fsl_dcu_drm_pm_resume)
273 };
274
275 static const struct fsl_dcu_soc_data fsl_dcu_ls1021a_data = {
276         .name = "ls1021a",
277         .total_layer = 16,
278         .max_layer = 4,
279 };
280
281 static const struct fsl_dcu_soc_data fsl_dcu_vf610_data = {
282         .name = "vf610",
283         .total_layer = 64,
284         .max_layer = 6,
285 };
286
287 static const struct of_device_id fsl_dcu_of_match[] = {
288         {
289                 .compatible = "fsl,ls1021a-dcu",
290                 .data = &fsl_dcu_ls1021a_data,
291         }, {
292                 .compatible = "fsl,vf610-dcu",
293                 .data = &fsl_dcu_vf610_data,
294         }, {
295         },
296 };
297 MODULE_DEVICE_TABLE(of, fsl_dcu_of_match);
298
299 static int fsl_dcu_drm_probe(struct platform_device *pdev)
300 {
301         struct fsl_dcu_drm_device *fsl_dev;
302         struct drm_device *drm;
303         struct device *dev = &pdev->dev;
304         struct resource *res;
305         void __iomem *base;
306         struct drm_driver *driver = &fsl_dcu_drm_driver;
307         const struct of_device_id *id;
308         int ret;
309
310         fsl_dev = devm_kzalloc(dev, sizeof(*fsl_dev), GFP_KERNEL);
311         if (!fsl_dev)
312                 return -ENOMEM;
313
314         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
315         if (!res) {
316                 dev_err(dev, "could not get memory IO resource\n");
317                 return -ENODEV;
318         }
319
320         base = devm_ioremap_resource(dev, res);
321         if (IS_ERR(base)) {
322                 ret = PTR_ERR(base);
323                 return ret;
324         }
325
326         fsl_dev->irq = platform_get_irq(pdev, 0);
327         if (fsl_dev->irq < 0) {
328                 dev_err(dev, "failed to get irq\n");
329                 return -ENXIO;
330         }
331
332         fsl_dev->clk = devm_clk_get(dev, "dcu");
333         if (IS_ERR(fsl_dev->clk)) {
334                 ret = PTR_ERR(fsl_dev->clk);
335                 dev_err(dev, "failed to get dcu clock\n");
336                 return ret;
337         }
338         ret = clk_prepare(fsl_dev->clk);
339         if (ret < 0) {
340                 dev_err(dev, "failed to prepare dcu clk\n");
341                 return ret;
342         }
343         ret = clk_enable(fsl_dev->clk);
344         if (ret < 0) {
345                 dev_err(dev, "failed to enable dcu clk\n");
346                 clk_unprepare(fsl_dev->clk);
347                 return ret;
348         }
349
350         fsl_dev->regmap = devm_regmap_init_mmio(dev, base,
351                         &fsl_dcu_regmap_config);
352         if (IS_ERR(fsl_dev->regmap)) {
353                 dev_err(dev, "regmap init failed\n");
354                 return PTR_ERR(fsl_dev->regmap);
355         }
356
357         id = of_match_node(fsl_dcu_of_match, pdev->dev.of_node);
358         if (!id)
359                 return -ENODEV;
360         fsl_dev->soc = id->data;
361
362         drm = drm_dev_alloc(driver, dev);
363         if (!drm)
364                 return -ENOMEM;
365
366         fsl_dev->dev = dev;
367         fsl_dev->drm = drm;
368         fsl_dev->np = dev->of_node;
369         drm->dev_private = fsl_dev;
370         dev_set_drvdata(dev, fsl_dev);
371
372         ret = drm_dev_register(drm, 0);
373         if (ret < 0)
374                 goto unref;
375
376         DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name,
377                  driver->major, driver->minor, driver->patchlevel,
378                  driver->date, drm->primary->index);
379
380         return 0;
381
382 unref:
383         drm_dev_unref(drm);
384         return ret;
385 }
386
387 static int fsl_dcu_drm_remove(struct platform_device *pdev)
388 {
389         struct fsl_dcu_drm_device *fsl_dev = platform_get_drvdata(pdev);
390
391         drm_put_dev(fsl_dev->drm);
392
393         return 0;
394 }
395
396 static struct platform_driver fsl_dcu_drm_platform_driver = {
397         .probe          = fsl_dcu_drm_probe,
398         .remove         = fsl_dcu_drm_remove,
399         .driver         = {
400                 .name   = "fsl-dcu",
401                 .pm     = &fsl_dcu_drm_pm_ops,
402                 .of_match_table = fsl_dcu_of_match,
403         },
404 };
405
406 module_platform_driver(fsl_dcu_drm_platform_driver);
407
408 MODULE_DESCRIPTION("Freescale DCU DRM Driver");
409 MODULE_LICENSE("GPL");