Commit | Line | Data |
---|---|---|
ca454bd4 LW |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Versatile Express PL111 handling | |
4 | * Copyright (C) 2018 Linus Walleij | |
5 | * | |
6 | * This module binds to the "arm,vexpress-muxfpga" device on the | |
7 | * Versatile Express configuration bus and sets up which CLCD instance | |
8 | * gets muxed out on the DVI bridge. | |
9 | */ | |
10 | #include <linux/device.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/regmap.h> | |
13 | #include <linux/vexpress.h> | |
14 | #include <linux/platform_device.h> | |
15 | #include <linux/of.h> | |
16 | #include <linux/of_address.h> | |
17 | #include <linux/of_platform.h> | |
18 | #include "pl111_drm.h" | |
19 | #include "pl111_vexpress.h" | |
20 | ||
21 | #define VEXPRESS_FPGAMUX_MOTHERBOARD 0x00 | |
22 | #define VEXPRESS_FPGAMUX_DAUGHTERBOARD_1 0x01 | |
23 | #define VEXPRESS_FPGAMUX_DAUGHTERBOARD_2 0x02 | |
24 | ||
25 | int pl111_vexpress_clcd_init(struct device *dev, | |
26 | struct pl111_drm_dev_private *priv, | |
27 | struct regmap *map) | |
28 | { | |
29 | struct device_node *root; | |
30 | struct device_node *child; | |
31 | struct device_node *ct_clcd = NULL; | |
32 | bool has_coretile_clcd = false; | |
33 | bool has_coretile_hdlcd = false; | |
34 | bool mux_motherboard = true; | |
35 | u32 val; | |
36 | int ret; | |
37 | ||
38 | /* | |
39 | * Check if we have a CLCD or HDLCD on the core tile by checking if a | |
40 | * CLCD or HDLCD is available in the root of the device tree. | |
41 | */ | |
42 | root = of_find_node_by_path("/"); | |
43 | if (!root) | |
44 | return -EINVAL; | |
45 | ||
46 | for_each_available_child_of_node(root, child) { | |
47 | if (of_device_is_compatible(child, "arm,pl111")) { | |
48 | has_coretile_clcd = true; | |
49 | ct_clcd = child; | |
50 | break; | |
51 | } | |
52 | if (of_device_is_compatible(child, "arm,hdlcd")) { | |
53 | has_coretile_hdlcd = true; | |
54 | break; | |
55 | } | |
56 | } | |
57 | ||
58 | /* | |
59 | * If there is a coretile HDLCD and it has a driver, | |
60 | * do not mux the CLCD on the motherboard to the DVI. | |
61 | */ | |
62 | if (has_coretile_hdlcd && IS_ENABLED(CONFIG_DRM_HDLCD)) | |
63 | mux_motherboard = false; | |
64 | ||
65 | /* | |
66 | * On the Vexpress CA9 we let the CLCD on the coretile | |
67 | * take precedence, so also in this case do not mux the | |
68 | * motherboard to the DVI. | |
69 | */ | |
70 | if (has_coretile_clcd) | |
71 | mux_motherboard = false; | |
72 | ||
73 | if (mux_motherboard) { | |
74 | dev_info(dev, "DVI muxed to motherboard CLCD\n"); | |
75 | val = VEXPRESS_FPGAMUX_MOTHERBOARD; | |
76 | } else if (ct_clcd == dev->of_node) { | |
77 | dev_info(dev, | |
78 | "DVI muxed to daughterboard 1 (core tile) CLCD\n"); | |
79 | val = VEXPRESS_FPGAMUX_DAUGHTERBOARD_1; | |
80 | } else { | |
81 | dev_info(dev, "core tile graphics present\n"); | |
82 | dev_info(dev, "this device will be deactivated\n"); | |
83 | return -ENODEV; | |
84 | } | |
85 | ||
86 | ret = regmap_write(map, 0, val); | |
87 | if (ret) { | |
88 | dev_err(dev, "error setting DVI muxmode\n"); | |
89 | return -ENODEV; | |
90 | } | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | /* | |
96 | * This sets up the regmap pointer that will then be retrieved by | |
97 | * the detection code in pl111_versatile.c and passed in to the | |
98 | * pl111_vexpress_clcd_init() function above. | |
99 | */ | |
100 | static int vexpress_muxfpga_probe(struct platform_device *pdev) | |
101 | { | |
102 | struct device *dev = &pdev->dev; | |
103 | struct regmap *map; | |
104 | ||
105 | map = devm_regmap_init_vexpress_config(&pdev->dev); | |
106 | if (IS_ERR(map)) | |
107 | return PTR_ERR(map); | |
108 | dev_set_drvdata(dev, map); | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static const struct of_device_id vexpress_muxfpga_match[] = { | |
7eb33224 | 114 | { .compatible = "arm,vexpress-muxfpga", }, |
115 | {} | |
ca454bd4 LW |
116 | }; |
117 | ||
118 | static struct platform_driver vexpress_muxfpga_driver = { | |
119 | .driver = { | |
120 | .name = "vexpress-muxfpga", | |
121 | .of_match_table = of_match_ptr(vexpress_muxfpga_match), | |
122 | }, | |
123 | .probe = vexpress_muxfpga_probe, | |
124 | }; | |
125 | ||
0a4587a0 LW |
126 | int vexpress_muxfpga_init(void) |
127 | { | |
128 | int ret; | |
129 | ||
130 | ret = platform_driver_register(&vexpress_muxfpga_driver); | |
131 | /* -EBUSY just means this driver is already registered */ | |
132 | if (ret == -EBUSY) | |
133 | ret = 0; | |
134 | return ret; | |
135 | } |