xref: /linux/drivers/gpu/drm/logicvc/logicvc_drm.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019-2022 Bootlin
4  * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
5  */
6 
7 #include <linux/bitfield.h>
8 #include <linux/clk.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/of_reserved_mem.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
16 #include <linux/types.h>
17 
18 #include <drm/drm_atomic_helper.h>
19 #include <drm/drm_client_setup.h>
20 #include <drm/drm_drv.h>
21 #include <drm/drm_fbdev_dma.h>
22 #include <drm/drm_fourcc.h>
23 #include <drm/drm_gem_dma_helper.h>
24 #include <drm/drm_print.h>
25 
26 #include "logicvc_crtc.h"
27 #include "logicvc_drm.h"
28 #include "logicvc_interface.h"
29 #include "logicvc_mode.h"
30 #include "logicvc_layer.h"
31 #include "logicvc_of.h"
32 #include "logicvc_regs.h"
33 
34 DEFINE_DRM_GEM_DMA_FOPS(logicvc_drm_fops);
35 
36 static int logicvc_drm_gem_dma_dumb_create(struct drm_file *file_priv,
37 					   struct drm_device *drm_dev,
38 					   struct drm_mode_create_dumb *args)
39 {
40 	struct logicvc_drm *logicvc = logicvc_drm(drm_dev);
41 
42 	/* Stride is always fixed to its configuration value. */
43 	args->pitch = logicvc->config.row_stride * DIV_ROUND_UP(args->bpp, 8);
44 
45 	return drm_gem_dma_dumb_create_internal(file_priv, drm_dev, args);
46 }
47 
48 static struct drm_driver logicvc_drm_driver = {
49 	.driver_features		= DRIVER_GEM | DRIVER_MODESET |
50 					  DRIVER_ATOMIC,
51 
52 	.fops				= &logicvc_drm_fops,
53 	.name				= "logicvc-drm",
54 	.desc				= "Xylon LogiCVC DRM driver",
55 	.date				= "20200403",
56 	.major				= 1,
57 	.minor				= 0,
58 
59 	DRM_GEM_DMA_DRIVER_OPS_VMAP_WITH_DUMB_CREATE(logicvc_drm_gem_dma_dumb_create),
60 	DRM_FBDEV_DMA_DRIVER_OPS,
61 };
62 
63 static struct regmap_config logicvc_drm_regmap_config = {
64 	.reg_bits	= 32,
65 	.val_bits	= 32,
66 	.reg_stride	= 4,
67 	.name		= "logicvc-drm",
68 };
69 
70 static irqreturn_t logicvc_drm_irq_handler(int irq, void *data)
71 {
72 	struct logicvc_drm *logicvc = data;
73 	irqreturn_t ret = IRQ_NONE;
74 	u32 stat = 0;
75 
76 	/* Get pending interrupt sources. */
77 	regmap_read(logicvc->regmap, LOGICVC_INT_STAT_REG, &stat);
78 
79 	/* Clear all pending interrupt sources. */
80 	regmap_write(logicvc->regmap, LOGICVC_INT_STAT_REG, stat);
81 
82 	if (stat & LOGICVC_INT_STAT_V_SYNC) {
83 		logicvc_crtc_vblank_handler(logicvc);
84 		ret = IRQ_HANDLED;
85 	}
86 
87 	return ret;
88 }
89 
90 static int logicvc_drm_config_parse(struct logicvc_drm *logicvc)
91 {
92 	struct drm_device *drm_dev = &logicvc->drm_dev;
93 	struct device *dev = drm_dev->dev;
94 	struct device_node *of_node = dev->of_node;
95 	struct logicvc_drm_config *config = &logicvc->config;
96 	struct device_node *layers_node;
97 	int ret;
98 
99 	logicvc_of_property_parse_bool(of_node, LOGICVC_OF_PROPERTY_DITHERING,
100 				       &config->dithering);
101 	logicvc_of_property_parse_bool(of_node,
102 				       LOGICVC_OF_PROPERTY_BACKGROUND_LAYER,
103 				       &config->background_layer);
104 	logicvc_of_property_parse_bool(of_node,
105 				       LOGICVC_OF_PROPERTY_LAYERS_CONFIGURABLE,
106 				       &config->layers_configurable);
107 
108 	ret = logicvc_of_property_parse_u32(of_node,
109 					    LOGICVC_OF_PROPERTY_DISPLAY_INTERFACE,
110 					    &config->display_interface);
111 	if (ret)
112 		return ret;
113 
114 	ret = logicvc_of_property_parse_u32(of_node,
115 					    LOGICVC_OF_PROPERTY_DISPLAY_COLORSPACE,
116 					    &config->display_colorspace);
117 	if (ret)
118 		return ret;
119 
120 	ret = logicvc_of_property_parse_u32(of_node,
121 					    LOGICVC_OF_PROPERTY_DISPLAY_DEPTH,
122 					    &config->display_depth);
123 	if (ret)
124 		return ret;
125 
126 	ret = logicvc_of_property_parse_u32(of_node,
127 					    LOGICVC_OF_PROPERTY_ROW_STRIDE,
128 					    &config->row_stride);
129 	if (ret)
130 		return ret;
131 
132 	layers_node = of_get_child_by_name(of_node, "layers");
133 	if (!layers_node) {
134 		drm_err(drm_dev, "Missing non-optional layers node\n");
135 		return -EINVAL;
136 	}
137 
138 	config->layers_count = of_get_child_count(layers_node);
139 	if (!config->layers_count) {
140 		drm_err(drm_dev,
141 			"Missing a non-optional layers children node\n");
142 		return -EINVAL;
143 	}
144 
145 	return 0;
146 }
147 
148 static int logicvc_clocks_prepare(struct logicvc_drm *logicvc)
149 {
150 	struct drm_device *drm_dev = &logicvc->drm_dev;
151 	struct device *dev = drm_dev->dev;
152 
153 	struct {
154 		struct clk **clk;
155 		char *name;
156 		bool optional;
157 	} clocks_map[] = {
158 		{
159 			.clk = &logicvc->vclk,
160 			.name = "vclk",
161 			.optional = false,
162 		},
163 		{
164 			.clk = &logicvc->vclk2,
165 			.name = "vclk2",
166 			.optional = true,
167 		},
168 		{
169 			.clk = &logicvc->lvdsclk,
170 			.name = "lvdsclk",
171 			.optional = true,
172 		},
173 		{
174 			.clk = &logicvc->lvdsclkn,
175 			.name = "lvdsclkn",
176 			.optional = true,
177 		},
178 	};
179 	unsigned int i;
180 	int ret;
181 
182 	for (i = 0; i < ARRAY_SIZE(clocks_map); i++) {
183 		struct clk *clk;
184 
185 		clk = devm_clk_get(dev, clocks_map[i].name);
186 		if (IS_ERR(clk)) {
187 			if (PTR_ERR(clk) == -ENOENT && clocks_map[i].optional)
188 				continue;
189 
190 			drm_err(drm_dev, "Missing non-optional clock %s\n",
191 				clocks_map[i].name);
192 
193 			ret = PTR_ERR(clk);
194 			goto error;
195 		}
196 
197 		ret = clk_prepare_enable(clk);
198 		if (ret) {
199 			drm_err(drm_dev,
200 				"Failed to prepare and enable clock %s\n",
201 				clocks_map[i].name);
202 			goto error;
203 		}
204 
205 		*clocks_map[i].clk = clk;
206 	}
207 
208 	return 0;
209 
210 error:
211 	for (i = 0; i < ARRAY_SIZE(clocks_map); i++) {
212 		if (!*clocks_map[i].clk)
213 			continue;
214 
215 		clk_disable_unprepare(*clocks_map[i].clk);
216 		*clocks_map[i].clk = NULL;
217 	}
218 
219 	return ret;
220 }
221 
222 static int logicvc_clocks_unprepare(struct logicvc_drm *logicvc)
223 {
224 	struct clk **clocks[] = {
225 		&logicvc->vclk,
226 		&logicvc->vclk2,
227 		&logicvc->lvdsclk,
228 		&logicvc->lvdsclkn,
229 	};
230 	unsigned int i;
231 
232 	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
233 		if (!*clocks[i])
234 			continue;
235 
236 		clk_disable_unprepare(*clocks[i]);
237 		*clocks[i] = NULL;
238 	}
239 
240 	return 0;
241 }
242 
243 static const struct logicvc_drm_caps logicvc_drm_caps[] = {
244 	{
245 		.major		= 3,
246 		.layer_address	= false,
247 	},
248 	{
249 		.major		= 4,
250 		.layer_address	= true,
251 	},
252 	{
253 		.major		= 5,
254 		.layer_address	= true,
255 	},
256 };
257 
258 static const struct logicvc_drm_caps *
259 logicvc_drm_caps_match(struct logicvc_drm *logicvc)
260 {
261 	struct drm_device *drm_dev = &logicvc->drm_dev;
262 	const struct logicvc_drm_caps *caps = NULL;
263 	unsigned int major, minor;
264 	char level;
265 	unsigned int i;
266 	u32 version;
267 
268 	regmap_read(logicvc->regmap, LOGICVC_IP_VERSION_REG, &version);
269 
270 	major = FIELD_GET(LOGICVC_IP_VERSION_MAJOR_MASK, version);
271 	minor = FIELD_GET(LOGICVC_IP_VERSION_MINOR_MASK, version);
272 	level = FIELD_GET(LOGICVC_IP_VERSION_LEVEL_MASK, version) + 'a';
273 
274 	for (i = 0; i < ARRAY_SIZE(logicvc_drm_caps); i++) {
275 		if (logicvc_drm_caps[i].major &&
276 		    logicvc_drm_caps[i].major != major)
277 			continue;
278 
279 		if (logicvc_drm_caps[i].minor &&
280 		    logicvc_drm_caps[i].minor != minor)
281 			continue;
282 
283 		if (logicvc_drm_caps[i].level &&
284 		    logicvc_drm_caps[i].level != level)
285 			continue;
286 
287 		caps = &logicvc_drm_caps[i];
288 	}
289 
290 	drm_info(drm_dev, "LogiCVC version %d.%02d.%c\n", major, minor, level);
291 
292 	return caps;
293 }
294 
295 static int logicvc_drm_probe(struct platform_device *pdev)
296 {
297 	struct device_node *of_node = pdev->dev.of_node;
298 	struct device_node *reserved_mem_node;
299 	struct reserved_mem *reserved_mem = NULL;
300 	const struct logicvc_drm_caps *caps;
301 	struct logicvc_drm *logicvc;
302 	struct device *dev = &pdev->dev;
303 	struct drm_device *drm_dev;
304 	struct regmap *regmap = NULL;
305 	struct resource res;
306 	void __iomem *base;
307 	int irq;
308 	int ret;
309 
310 	ret = of_reserved_mem_device_init(dev);
311 	if (ret && ret != -ENODEV) {
312 		dev_err(dev, "Failed to init memory region\n");
313 		goto error_early;
314 	}
315 
316 	reserved_mem_node = of_parse_phandle(of_node, "memory-region", 0);
317 	if (reserved_mem_node) {
318 		reserved_mem = of_reserved_mem_lookup(reserved_mem_node);
319 		of_node_put(reserved_mem_node);
320 	}
321 
322 	/* Get regmap from parent if available. */
323 	if (of_node->parent)
324 		regmap = syscon_node_to_regmap(of_node->parent);
325 
326 	/* Register our own regmap otherwise. */
327 	if (IS_ERR_OR_NULL(regmap)) {
328 		ret = of_address_to_resource(of_node, 0, &res);
329 		if (ret) {
330 			dev_err(dev, "Failed to get resource from address\n");
331 			goto error_reserved_mem;
332 		}
333 
334 		base = devm_ioremap_resource(dev, &res);
335 		if (IS_ERR(base)) {
336 			dev_err(dev, "Failed to map I/O base\n");
337 			ret = PTR_ERR(base);
338 			goto error_reserved_mem;
339 		}
340 
341 		logicvc_drm_regmap_config.max_register = resource_size(&res) -
342 							 4;
343 
344 		regmap = devm_regmap_init_mmio(dev, base,
345 					       &logicvc_drm_regmap_config);
346 		if (IS_ERR(regmap)) {
347 			dev_err(dev, "Failed to create regmap for I/O\n");
348 			ret = PTR_ERR(regmap);
349 			goto error_reserved_mem;
350 		}
351 	}
352 
353 	irq = platform_get_irq(pdev, 0);
354 	if (irq < 0) {
355 		ret = -ENODEV;
356 		goto error_reserved_mem;
357 	}
358 
359 	logicvc = devm_drm_dev_alloc(dev, &logicvc_drm_driver,
360 				     struct logicvc_drm, drm_dev);
361 	if (IS_ERR(logicvc)) {
362 		ret = PTR_ERR(logicvc);
363 		goto error_reserved_mem;
364 	}
365 
366 	platform_set_drvdata(pdev, logicvc);
367 	drm_dev = &logicvc->drm_dev;
368 
369 	logicvc->regmap = regmap;
370 	INIT_LIST_HEAD(&logicvc->layers_list);
371 
372 	caps = logicvc_drm_caps_match(logicvc);
373 	if (!caps) {
374 		ret = -EINVAL;
375 		goto error_reserved_mem;
376 	}
377 
378 	logicvc->caps = caps;
379 
380 	if (reserved_mem)
381 		logicvc->reserved_mem_base = reserved_mem->base;
382 
383 	ret = logicvc_clocks_prepare(logicvc);
384 	if (ret) {
385 		drm_err(drm_dev, "Failed to prepare clocks\n");
386 		goto error_reserved_mem;
387 	}
388 
389 	ret = devm_request_irq(dev, irq, logicvc_drm_irq_handler, 0,
390 			       dev_name(dev), logicvc);
391 	if (ret) {
392 		drm_err(drm_dev, "Failed to request IRQ\n");
393 		goto error_clocks;
394 	}
395 
396 	ret = logicvc_drm_config_parse(logicvc);
397 	if (ret && ret != -ENODEV) {
398 		drm_err(drm_dev, "Failed to parse config\n");
399 		goto error_clocks;
400 	}
401 
402 	ret = drmm_mode_config_init(drm_dev);
403 	if (ret) {
404 		drm_err(drm_dev, "Failed to init mode config\n");
405 		goto error_clocks;
406 	}
407 
408 	ret = logicvc_layers_init(logicvc);
409 	if (ret) {
410 		drm_err(drm_dev, "Failed to initialize layers\n");
411 		goto error_clocks;
412 	}
413 
414 	ret = logicvc_crtc_init(logicvc);
415 	if (ret) {
416 		drm_err(drm_dev, "Failed to initialize CRTC\n");
417 		goto error_clocks;
418 	}
419 
420 	logicvc_layers_attach_crtc(logicvc);
421 
422 	ret = logicvc_interface_init(logicvc);
423 	if (ret) {
424 		if (ret != -EPROBE_DEFER)
425 			drm_err(drm_dev, "Failed to initialize interface\n");
426 
427 		goto error_clocks;
428 	}
429 
430 	logicvc_interface_attach_crtc(logicvc);
431 
432 	ret = logicvc_mode_init(logicvc);
433 	if (ret) {
434 		drm_err(drm_dev, "Failed to initialize KMS\n");
435 		goto error_clocks;
436 	}
437 
438 	ret = drm_dev_register(drm_dev, 0);
439 	if (ret) {
440 		drm_err(drm_dev, "Failed to register DRM device\n");
441 		goto error_mode;
442 	}
443 
444 	drm_client_setup(drm_dev, NULL);
445 
446 	return 0;
447 
448 error_mode:
449 	logicvc_mode_fini(logicvc);
450 
451 error_clocks:
452 	logicvc_clocks_unprepare(logicvc);
453 
454 error_reserved_mem:
455 	of_reserved_mem_device_release(dev);
456 
457 error_early:
458 	return ret;
459 }
460 
461 static void logicvc_drm_remove(struct platform_device *pdev)
462 {
463 	struct logicvc_drm *logicvc = platform_get_drvdata(pdev);
464 	struct device *dev = &pdev->dev;
465 	struct drm_device *drm_dev = &logicvc->drm_dev;
466 
467 	drm_dev_unregister(drm_dev);
468 	drm_atomic_helper_shutdown(drm_dev);
469 
470 	logicvc_mode_fini(logicvc);
471 
472 	logicvc_clocks_unprepare(logicvc);
473 
474 	of_reserved_mem_device_release(dev);
475 }
476 
477 static void logicvc_drm_shutdown(struct platform_device *pdev)
478 {
479 	struct logicvc_drm *logicvc = platform_get_drvdata(pdev);
480 	struct drm_device *drm_dev = &logicvc->drm_dev;
481 
482 	drm_atomic_helper_shutdown(drm_dev);
483 }
484 
485 static const struct of_device_id logicvc_drm_of_table[] = {
486 	{ .compatible = "xylon,logicvc-3.02.a-display" },
487 	{ .compatible = "xylon,logicvc-4.01.a-display" },
488 	{},
489 };
490 MODULE_DEVICE_TABLE(of, logicvc_drm_of_table);
491 
492 static struct platform_driver logicvc_drm_platform_driver = {
493 	.probe		= logicvc_drm_probe,
494 	.remove_new	= logicvc_drm_remove,
495 	.shutdown	= logicvc_drm_shutdown,
496 	.driver		= {
497 		.name		= "logicvc-drm",
498 		.of_match_table	= logicvc_drm_of_table,
499 	},
500 };
501 
502 module_platform_driver(logicvc_drm_platform_driver);
503 
504 MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
505 MODULE_DESCRIPTION("Xylon LogiCVC DRM driver");
506 MODULE_LICENSE("GPL");
507