forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/gpu/drm/sun4i/sun4i_rgb.c
....@@ -1,22 +1,20 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2015 Free Electrons
34 * Copyright (C) 2015 NextThing Co
45 *
56 * Maxime Ripard <maxime.ripard@free-electrons.com>
6
- *
7
- * This program is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU General Public License as
9
- * published by the Free Software Foundation; either version 2 of
10
- * the License, or (at your option) any later version.
117 */
128
139 #include <linux/clk.h>
1410
15
-#include <drm/drmP.h>
1611 #include <drm/drm_atomic_helper.h>
17
-#include <drm/drm_crtc_helper.h>
12
+#include <drm/drm_bridge.h>
1813 #include <drm/drm_of.h>
1914 #include <drm/drm_panel.h>
15
+#include <drm/drm_print.h>
16
+#include <drm/drm_probe_helper.h>
17
+#include <drm/drm_simple_kms_helper.h>
2018
2119 #include "sun4i_crtc.h"
2220 #include "sun4i_tcon.h"
....@@ -27,6 +25,8 @@
2725 struct drm_encoder encoder;
2826
2927 struct sun4i_tcon *tcon;
28
+ struct drm_panel *panel;
29
+ struct drm_bridge *bridge;
3030 };
3131
3232 static inline struct sun4i_rgb *
....@@ -47,10 +47,17 @@
4747 {
4848 struct sun4i_rgb *rgb =
4949 drm_connector_to_sun4i_rgb(connector);
50
- struct sun4i_tcon *tcon = rgb->tcon;
5150
52
- return drm_panel_get_modes(tcon->panel);
51
+ return drm_panel_get_modes(rgb->panel, connector);
5352 }
53
+
54
+/*
55
+ * VESA DMT defines a tolerance of 0.5% on the pixel clock, while the
56
+ * CVT spec reuses that tolerance in its examples, so it looks to be a
57
+ * good default tolerance for the EDID-based modes. Define it to 5 per
58
+ * mille to avoid floating point operations.
59
+ */
60
+#define SUN4I_RGB_DOTCLOCK_TOLERANCE_PER_MILLE 5
5461
5562 static enum drm_mode_status sun4i_rgb_mode_valid(struct drm_encoder *crtc,
5663 const struct drm_display_mode *mode)
....@@ -59,8 +66,9 @@
5966 struct sun4i_tcon *tcon = rgb->tcon;
6067 u32 hsync = mode->hsync_end - mode->hsync_start;
6168 u32 vsync = mode->vsync_end - mode->vsync_start;
62
- unsigned long rate = mode->clock * 1000;
63
- long rounded_rate;
69
+ unsigned long long rate = mode->clock * 1000;
70
+ unsigned long long lowest, highest;
71
+ unsigned long long rounded_rate;
6472
6573 DRM_DEBUG_DRIVER("Validating modes...\n");
6674
....@@ -92,31 +100,51 @@
92100
93101 DRM_DEBUG_DRIVER("Vertical parameters OK\n");
94102
103
+ /*
104
+ * TODO: We should use the struct display_timing if available
105
+ * and / or trying to stretch the timings within that
106
+ * tolerancy to take care of panels that we wouldn't be able
107
+ * to have a exact match for.
108
+ */
109
+ if (rgb->panel) {
110
+ DRM_DEBUG_DRIVER("RGB panel used, skipping clock rate checks");
111
+ goto out;
112
+ }
113
+
114
+ /*
115
+ * That shouldn't ever happen unless something is really wrong, but it
116
+ * doesn't harm to check.
117
+ */
118
+ if (!rgb->bridge)
119
+ goto out;
120
+
95121 tcon->dclk_min_div = 6;
96122 tcon->dclk_max_div = 127;
97123 rounded_rate = clk_round_rate(tcon->dclk, rate);
98
- if (rounded_rate < rate)
124
+
125
+ lowest = rate * (1000 - SUN4I_RGB_DOTCLOCK_TOLERANCE_PER_MILLE);
126
+ do_div(lowest, 1000);
127
+ if (rounded_rate < lowest)
99128 return MODE_CLOCK_LOW;
100129
101
- if (rounded_rate > rate)
130
+ highest = rate * (1000 + SUN4I_RGB_DOTCLOCK_TOLERANCE_PER_MILLE);
131
+ do_div(highest, 1000);
132
+ if (rounded_rate > highest)
102133 return MODE_CLOCK_HIGH;
103134
135
+out:
104136 DRM_DEBUG_DRIVER("Clock rate OK\n");
105137
106138 return MODE_OK;
107139 }
108140
109
-static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
141
+static const struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
110142 .get_modes = sun4i_rgb_get_modes,
111143 };
112144
113145 static void
114146 sun4i_rgb_connector_destroy(struct drm_connector *connector)
115147 {
116
- struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
117
- struct sun4i_tcon *tcon = rgb->tcon;
118
-
119
- drm_panel_detach(tcon->panel);
120148 drm_connector_cleanup(connector);
121149 }
122150
....@@ -131,48 +159,36 @@
131159 static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
132160 {
133161 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
134
- struct sun4i_tcon *tcon = rgb->tcon;
135162
136163 DRM_DEBUG_DRIVER("Enabling RGB output\n");
137164
138
- if (!IS_ERR(tcon->panel)) {
139
- drm_panel_prepare(tcon->panel);
140
- drm_panel_enable(tcon->panel);
165
+ if (rgb->panel) {
166
+ drm_panel_prepare(rgb->panel);
167
+ drm_panel_enable(rgb->panel);
141168 }
142169 }
143170
144171 static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
145172 {
146173 struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
147
- struct sun4i_tcon *tcon = rgb->tcon;
148174
149175 DRM_DEBUG_DRIVER("Disabling RGB output\n");
150176
151
- if (!IS_ERR(tcon->panel)) {
152
- drm_panel_disable(tcon->panel);
153
- drm_panel_unprepare(tcon->panel);
177
+ if (rgb->panel) {
178
+ drm_panel_disable(rgb->panel);
179
+ drm_panel_unprepare(rgb->panel);
154180 }
155181 }
156182
157
-static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
183
+static const struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
158184 .disable = sun4i_rgb_encoder_disable,
159185 .enable = sun4i_rgb_encoder_enable,
160186 .mode_valid = sun4i_rgb_mode_valid,
161187 };
162188
163
-static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder)
164
-{
165
- drm_encoder_cleanup(encoder);
166
-}
167
-
168
-static struct drm_encoder_funcs sun4i_rgb_enc_funcs = {
169
- .destroy = sun4i_rgb_enc_destroy,
170
-};
171
-
172189 int sun4i_rgb_init(struct drm_device *drm, struct sun4i_tcon *tcon)
173190 {
174191 struct drm_encoder *encoder;
175
- struct drm_bridge *bridge;
176192 struct sun4i_rgb *rgb;
177193 int ret;
178194
....@@ -183,7 +199,7 @@
183199 encoder = &rgb->encoder;
184200
185201 ret = drm_of_find_panel_or_bridge(tcon->dev->of_node, 1, 0,
186
- &tcon->panel, &bridge);
202
+ &rgb->panel, &rgb->bridge);
187203 if (ret) {
188204 dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
189205 return 0;
....@@ -191,11 +207,8 @@
191207
192208 drm_encoder_helper_add(&rgb->encoder,
193209 &sun4i_rgb_enc_helper_funcs);
194
- ret = drm_encoder_init(drm,
195
- &rgb->encoder,
196
- &sun4i_rgb_enc_funcs,
197
- DRM_MODE_ENCODER_NONE,
198
- NULL);
210
+ ret = drm_simple_encoder_init(drm, &rgb->encoder,
211
+ DRM_MODE_ENCODER_NONE);
199212 if (ret) {
200213 dev_err(drm->dev, "Couldn't initialise the rgb encoder\n");
201214 goto err_out;
....@@ -204,7 +217,7 @@
204217 /* The RGB encoder can only work with the TCON channel 0 */
205218 rgb->encoder.possible_crtcs = drm_crtc_mask(&tcon->crtc->crtc);
206219
207
- if (tcon->panel) {
220
+ if (rgb->panel) {
208221 drm_connector_helper_add(&rgb->connector,
209222 &sun4i_rgb_con_helper_funcs);
210223 ret = drm_connector_init(drm, &rgb->connector,
....@@ -217,16 +230,10 @@
217230
218231 drm_connector_attach_encoder(&rgb->connector,
219232 &rgb->encoder);
220
-
221
- ret = drm_panel_attach(tcon->panel, &rgb->connector);
222
- if (ret) {
223
- dev_err(drm->dev, "Couldn't attach our panel\n");
224
- goto err_cleanup_connector;
225
- }
226233 }
227234
228
- if (bridge) {
229
- ret = drm_bridge_attach(encoder, bridge, NULL);
235
+ if (rgb->bridge) {
236
+ ret = drm_bridge_attach(encoder, rgb->bridge, NULL, 0);
230237 if (ret) {
231238 dev_err(drm->dev, "Couldn't attach our bridge\n");
232239 goto err_cleanup_connector;