forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/pl111/pl111_versatile.c
....@@ -1,14 +1,24 @@
1
-#include <linux/amba/clcd-regs.h>
1
+// SPDX-License-Identifier: GPL-2.0-only
2
+
3
+/*
4
+ * Versatile family (ARM reference designs) handling for the PL11x.
5
+ * This is based on code and know-how in the previous frame buffer
6
+ * driver in drivers/video/fbdev/amba-clcd.c:
7
+ * Copyright (C) 2001 ARM Limited, by David A Rusling
8
+ * Updated to 2.5 by Deep Blue Solutions Ltd.
9
+ * Major contributions and discoveries by Russell King.
10
+ */
11
+
12
+#include <linux/bitops.h>
213 #include <linux/device.h>
14
+#include <linux/mfd/syscon.h>
15
+#include <linux/module.h>
316 #include <linux/of.h>
417 #include <linux/of_platform.h>
518 #include <linux/regmap.h>
6
-#include <linux/mfd/syscon.h>
7
-#include <linux/bitops.h>
8
-#include <linux/module.h>
9
-#include <drm/drmP.h>
19
+#include <linux/vexpress.h>
20
+
1021 #include "pl111_versatile.h"
11
-#include "pl111_vexpress.h"
1222 #include "pl111_drm.h"
1323
1424 static struct regmap *versatile_syscon_map;
....@@ -17,6 +27,7 @@
1727 * We detect the different syscon types from the compatible strings.
1828 */
1929 enum versatile_clcd {
30
+ INTEGRATOR_IMPD1,
2031 INTEGRATOR_CLCD_CM,
2132 VERSATILE_CLCD,
2233 REALVIEW_CLCD_EB,
....@@ -59,6 +70,14 @@
5970 {
6071 .compatible = "arm,vexpress-muxfpga",
6172 .data = (void *)VEXPRESS_CLCD_V2M,
73
+ },
74
+ {},
75
+};
76
+
77
+static const struct of_device_id impd1_clcd_of_match[] = {
78
+ {
79
+ .compatible = "arm,im-pd1-syscon",
80
+ .data = (void *)INTEGRATOR_IMPD1,
6281 },
6382 {},
6483 };
....@@ -121,6 +140,36 @@
121140 INTEGRATOR_HDR_CTRL_OFFSET,
122141 INTEGRATOR_CLCD_MASK,
123142 val);
143
+}
144
+
145
+#define IMPD1_CTRL_OFFSET 0x18
146
+#define IMPD1_CTRL_DISP_LCD (0 << 0)
147
+#define IMPD1_CTRL_DISP_VGA (1 << 0)
148
+#define IMPD1_CTRL_DISP_LCD1 (2 << 0)
149
+#define IMPD1_CTRL_DISP_ENABLE (1 << 2)
150
+#define IMPD1_CTRL_DISP_MASK (7 << 0)
151
+
152
+static void pl111_impd1_enable(struct drm_device *drm, u32 format)
153
+{
154
+ u32 val;
155
+
156
+ dev_info(drm->dev, "enable IM-PD1 CLCD connectors\n");
157
+ val = IMPD1_CTRL_DISP_VGA | IMPD1_CTRL_DISP_ENABLE;
158
+
159
+ regmap_update_bits(versatile_syscon_map,
160
+ IMPD1_CTRL_OFFSET,
161
+ IMPD1_CTRL_DISP_MASK,
162
+ val);
163
+}
164
+
165
+static void pl111_impd1_disable(struct drm_device *drm)
166
+{
167
+ dev_info(drm->dev, "disable IM-PD1 CLCD connectors\n");
168
+
169
+ regmap_update_bits(versatile_syscon_map,
170
+ IMPD1_CTRL_OFFSET,
171
+ IMPD1_CTRL_DISP_MASK,
172
+ 0);
124173 }
125174
126175 /*
....@@ -269,6 +318,20 @@
269318 };
270319
271320 /*
321
+ * The IM-PD1 variant is a PL110 with a bunch of broken, or not
322
+ * yet implemented features
323
+ */
324
+static const struct pl111_variant_data pl110_impd1 = {
325
+ .name = "PL110 IM-PD1",
326
+ .is_pl110 = true,
327
+ .broken_clockdivider = true,
328
+ .broken_vblank = true,
329
+ .formats = pl110_integrator_pixel_formats,
330
+ .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
331
+ .fb_bpp = 16,
332
+};
333
+
334
+/*
272335 * This is the in-between PL110 variant found in the ARM Versatile,
273336 * supporting RGB565/BGR565
274337 */
....@@ -306,13 +369,111 @@
306369 .broken_clockdivider = true,
307370 };
308371
372
+#define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00
373
+#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01
374
+#define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02
375
+
376
+static int pl111_vexpress_clcd_init(struct device *dev, struct device_node *np,
377
+ struct pl111_drm_dev_private *priv)
378
+{
379
+ struct platform_device *pdev;
380
+ struct device_node *root;
381
+ struct device_node *child;
382
+ struct device_node *ct_clcd = NULL;
383
+ struct regmap *map;
384
+ bool has_coretile_clcd = false;
385
+ bool has_coretile_hdlcd = false;
386
+ bool mux_motherboard = true;
387
+ u32 val;
388
+ int ret;
389
+
390
+ if (!IS_ENABLED(CONFIG_VEXPRESS_CONFIG))
391
+ return -ENODEV;
392
+
393
+ /*
394
+ * Check if we have a CLCD or HDLCD on the core tile by checking if a
395
+ * CLCD or HDLCD is available in the root of the device tree.
396
+ */
397
+ root = of_find_node_by_path("/");
398
+ if (!root)
399
+ return -EINVAL;
400
+
401
+ for_each_available_child_of_node(root, child) {
402
+ if (of_device_is_compatible(child, "arm,pl111")) {
403
+ has_coretile_clcd = true;
404
+ ct_clcd = child;
405
+ of_node_put(child);
406
+ break;
407
+ }
408
+ if (of_device_is_compatible(child, "arm,hdlcd")) {
409
+ has_coretile_hdlcd = true;
410
+ of_node_put(child);
411
+ break;
412
+ }
413
+ }
414
+
415
+ of_node_put(root);
416
+
417
+ /*
418
+ * If there is a coretile HDLCD and it has a driver,
419
+ * do not mux the CLCD on the motherboard to the DVI.
420
+ */
421
+ if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD))
422
+ mux_motherboard = false;
423
+
424
+ /*
425
+ * On the Vexpress CA9 we let the CLCD on the coretile
426
+ * take precedence, so also in this case do not mux the
427
+ * motherboard to the DVI.
428
+ */
429
+ if (has_coretile_clcd)
430
+ mux_motherboard = false;
431
+
432
+ if (mux_motherboard) {
433
+ dev_info(dev, "DVI muxed to motherboard CLCD\n");
434
+ val = VEXPRESS_FPGAMUX_MOTHERBOARD;
435
+ } else if (ct_clcd == dev->of_node) {
436
+ dev_info(dev,
437
+ "DVI muxed to daughterboard 1 (core tile) CLCD\n");
438
+ val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1;
439
+ } else {
440
+ dev_info(dev, "core tile graphics present\n");
441
+ dev_info(dev, "this device will be deactivated\n");
442
+ return -ENODEV;
443
+ }
444
+
445
+ /* Call into deep Vexpress configuration API */
446
+ pdev = of_find_device_by_node(np);
447
+ if (!pdev) {
448
+ dev_err(dev, "can't find the sysreg device, deferring\n");
449
+ return -EPROBE_DEFER;
450
+ }
451
+
452
+ map = devm_regmap_init_vexpress_config(&pdev->dev);
453
+ if (IS_ERR(map)) {
454
+ platform_device_put(pdev);
455
+ return PTR_ERR(map);
456
+ }
457
+
458
+ ret = regmap_write(map, 0, val);
459
+ platform_device_put(pdev);
460
+ if (ret) {
461
+ dev_err(dev, "error setting DVI muxmode\n");
462
+ return -ENODEV;
463
+ }
464
+
465
+ priv->variant = &pl111_vexpress;
466
+ dev_info(dev, "initializing Versatile Express PL111\n");
467
+
468
+ return 0;
469
+}
470
+
309471 int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
310472 {
311473 const struct of_device_id *clcd_id;
312474 enum versatile_clcd versatile_clcd_type;
313475 struct device_node *np;
314476 struct regmap *map;
315
- int ret;
316477
317478 np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
318479 &clcd_id);
....@@ -320,39 +481,32 @@
320481 /* Non-ARM reference designs, just bail out */
321482 return 0;
322483 }
484
+
323485 versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
324486
325487 /* Versatile Express special handling */
326488 if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
327
- struct platform_device *pdev;
328
-
329
- /* Registers a driver for the muxfpga */
330
- ret = vexpress_muxfpga_init();
331
- if (ret) {
332
- dev_err(dev, "unable to initialize muxfpga driver\n");
333
- of_node_put(np);
334
- return ret;
335
- }
336
-
337
- /* Call into deep Vexpress configuration API */
338
- pdev = of_find_device_by_node(np);
339
- if (!pdev) {
340
- dev_err(dev, "can't find the sysreg device, deferring\n");
341
- of_node_put(np);
342
- return -EPROBE_DEFER;
343
- }
344
- map = dev_get_drvdata(&pdev->dev);
345
- if (!map) {
346
- dev_err(dev, "sysreg has not yet probed\n");
347
- platform_device_put(pdev);
348
- of_node_put(np);
349
- return -EPROBE_DEFER;
350
- }
351
- } else {
352
- map = syscon_node_to_regmap(np);
489
+ int ret = pl111_vexpress_clcd_init(dev, np, priv);
490
+ of_node_put(np);
491
+ if (ret)
492
+ dev_err(dev, "Versatile Express init failed - %d", ret);
493
+ return ret;
353494 }
354
- of_node_put(np);
355495
496
+ /*
497
+ * On the Integrator, check if we should use the IM-PD1 instead,
498
+ * if we find it, it will take precedence. This is on the Integrator/AP
499
+ * which only has this option for PL110 graphics.
500
+ */
501
+ if (versatile_clcd_type == INTEGRATOR_CLCD_CM) {
502
+ np = of_find_matching_node_and_match(NULL, impd1_clcd_of_match,
503
+ &clcd_id);
504
+ if (np)
505
+ versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
506
+ }
507
+
508
+ map = syscon_node_to_regmap(np);
509
+ of_node_put(np);
356510 if (IS_ERR(map)) {
357511 dev_err(dev, "no Versatile syscon regmap\n");
358512 return PTR_ERR(map);
....@@ -364,6 +518,13 @@
364518 priv->variant = &pl110_integrator;
365519 priv->variant_display_enable = pl111_integrator_enable;
366520 dev_info(dev, "set up callbacks for Integrator PL110\n");
521
+ break;
522
+ case INTEGRATOR_IMPD1:
523
+ versatile_syscon_map = map;
524
+ priv->variant = &pl110_impd1;
525
+ priv->variant_display_enable = pl111_impd1_enable;
526
+ priv->variant_display_disable = pl111_impd1_disable;
527
+ dev_info(dev, "set up callbacks for IM-PD1 PL110\n");
367528 break;
368529 case VERSATILE_CLCD:
369530 versatile_syscon_map = map;
....@@ -390,13 +551,6 @@
390551 priv->variant_display_enable = pl111_realview_clcd_enable;
391552 priv->variant_display_disable = pl111_realview_clcd_disable;
392553 dev_info(dev, "set up callbacks for RealView PL111\n");
393
- break;
394
- case VEXPRESS_CLCD_V2M:
395
- priv->variant = &pl111_vexpress;
396
- dev_info(dev, "initializing Versatile Express PL111\n");
397
- ret = pl111_vexpress_clcd_init(dev, priv, map);
398
- if (ret)
399
- return ret;
400554 break;
401555 default:
402556 dev_info(dev, "unknown Versatile system controller\n");