hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/gpu/drm/bridge/thc63lvd1024.c
....@@ -5,14 +5,16 @@
55 * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org>
66 */
77
8
-#include <drm/drmP.h>
9
-#include <drm/drm_bridge.h>
10
-#include <drm/drm_panel.h>
11
-
128 #include <linux/gpio/consumer.h>
9
+#include <linux/module.h>
10
+#include <linux/of.h>
1311 #include <linux/of_graph.h>
12
+#include <linux/platform_device.h>
1413 #include <linux/regulator/consumer.h>
1514 #include <linux/slab.h>
15
+
16
+#include <drm/drm_bridge.h>
17
+#include <drm/drm_panel.h>
1618
1719 enum thc63_ports {
1820 THC63_LVDS_IN0,
....@@ -31,6 +33,8 @@
3133
3234 struct drm_bridge bridge;
3335 struct drm_bridge *next;
36
+
37
+ struct drm_bridge_timings timings;
3438 };
3539
3640 static inline struct thc63_dev *to_thc63(struct drm_bridge *bridge)
....@@ -38,11 +42,43 @@
3842 return container_of(bridge, struct thc63_dev, bridge);
3943 }
4044
41
-static int thc63_attach(struct drm_bridge *bridge)
45
+static int thc63_attach(struct drm_bridge *bridge,
46
+ enum drm_bridge_attach_flags flags)
4247 {
4348 struct thc63_dev *thc63 = to_thc63(bridge);
4449
45
- return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
50
+ return drm_bridge_attach(bridge->encoder, thc63->next, bridge, flags);
51
+}
52
+
53
+static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
54
+ const struct drm_display_info *info,
55
+ const struct drm_display_mode *mode)
56
+{
57
+ struct thc63_dev *thc63 = to_thc63(bridge);
58
+ unsigned int min_freq;
59
+ unsigned int max_freq;
60
+
61
+ /*
62
+ * The THC63LVD1024 pixel rate range is 8 to 135 MHz in all modes but
63
+ * dual-in, single-out where it is 40 to 150 MHz. As dual-in, dual-out
64
+ * isn't supported by the driver yet, simply derive the limits from the
65
+ * input mode.
66
+ */
67
+ if (thc63->timings.dual_link) {
68
+ min_freq = 40000;
69
+ max_freq = 150000;
70
+ } else {
71
+ min_freq = 8000;
72
+ max_freq = 135000;
73
+ }
74
+
75
+ if (mode->clock < min_freq)
76
+ return MODE_CLOCK_LOW;
77
+
78
+ if (mode->clock > max_freq)
79
+ return MODE_CLOCK_HIGH;
80
+
81
+ return MODE_OK;
4682 }
4783
4884 static void thc63_enable(struct drm_bridge *bridge)
....@@ -77,25 +113,26 @@
77113
78114 static const struct drm_bridge_funcs thc63_bridge_func = {
79115 .attach = thc63_attach,
116
+ .mode_valid = thc63_mode_valid,
80117 .enable = thc63_enable,
81118 .disable = thc63_disable,
82119 };
83120
84121 static int thc63_parse_dt(struct thc63_dev *thc63)
85122 {
86
- struct device_node *thc63_out;
123
+ struct device_node *endpoint;
87124 struct device_node *remote;
88125
89
- thc63_out = of_graph_get_endpoint_by_regs(thc63->dev->of_node,
90
- THC63_RGB_OUT0, -1);
91
- if (!thc63_out) {
126
+ endpoint = of_graph_get_endpoint_by_regs(thc63->dev->of_node,
127
+ THC63_RGB_OUT0, -1);
128
+ if (!endpoint) {
92129 dev_err(thc63->dev, "Missing endpoint in port@%u\n",
93130 THC63_RGB_OUT0);
94131 return -ENODEV;
95132 }
96133
97
- remote = of_graph_get_remote_port_parent(thc63_out);
98
- of_node_put(thc63_out);
134
+ remote = of_graph_get_remote_port_parent(endpoint);
135
+ of_node_put(endpoint);
99136 if (!remote) {
100137 dev_err(thc63->dev, "Endpoint in port@%u unconnected\n",
101138 THC63_RGB_OUT0);
....@@ -113,6 +150,22 @@
113150 of_node_put(remote);
114151 if (!thc63->next)
115152 return -EPROBE_DEFER;
153
+
154
+ endpoint = of_graph_get_endpoint_by_regs(thc63->dev->of_node,
155
+ THC63_LVDS_IN1, -1);
156
+ if (endpoint) {
157
+ remote = of_graph_get_remote_port_parent(endpoint);
158
+ of_node_put(endpoint);
159
+
160
+ if (remote) {
161
+ if (of_device_is_available(remote))
162
+ thc63->timings.dual_link = true;
163
+ of_node_put(remote);
164
+ }
165
+ }
166
+
167
+ dev_dbg(thc63->dev, "operating in %s-link mode\n",
168
+ thc63->timings.dual_link ? "dual" : "single");
116169
117170 return 0;
118171 }
....@@ -170,6 +223,7 @@
170223 thc63->bridge.driver_private = thc63;
171224 thc63->bridge.of_node = pdev->dev.of_node;
172225 thc63->bridge.funcs = &thc63_bridge_func;
226
+ thc63->bridge.timings = &thc63->timings;
173227
174228 drm_bridge_add(&thc63->bridge);
175229