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