forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
....@@ -1,33 +1,26 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2014 Traphandler
34 * Copyright (C) 2014 Free Electrons
45 *
56 * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
67 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
7
- *
8
- * This program is free software; you can redistribute it and/or modify it
9
- * under the terms of the GNU General Public License version 2 as published by
10
- * the Free Software Foundation.
11
- *
12
- * This program is distributed in the hope that it will be useful, but WITHOUT
13
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15
- * more details.
16
- *
17
- * You should have received a copy of the GNU General Public License along with
18
- * this program. If not, see <http://www.gnu.org/licenses/>.
198 */
209
2110 #include <linux/clk.h>
11
+#include <linux/mfd/atmel-hlcdc.h>
12
+#include <linux/pinctrl/consumer.h>
2213 #include <linux/pm.h>
2314 #include <linux/pm_runtime.h>
24
-#include <linux/pinctrl/consumer.h>
25
-
26
-#include <drm/drm_crtc.h>
27
-#include <drm/drm_crtc_helper.h>
28
-#include <drm/drmP.h>
2915
3016 #include <video/videomode.h>
17
+
18
+#include <drm/drm_atomic.h>
19
+#include <drm/drm_atomic_helper.h>
20
+#include <drm/drm_crtc.h>
21
+#include <drm/drm_modeset_helper_vtables.h>
22
+#include <drm/drm_probe_helper.h>
23
+#include <drm/drm_vblank.h>
3124
3225 #include "atmel_hlcdc_dc.h"
3326
....@@ -78,7 +71,8 @@
7871 unsigned long mode_rate;
7972 struct videomode vm;
8073 unsigned long prate;
81
- unsigned int cfg;
74
+ unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL;
75
+ unsigned int cfg = 0;
8276 int div, ret;
8377
8478 ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
....@@ -105,35 +99,50 @@
10599 (adj->crtc_hdisplay - 1) |
106100 ((adj->crtc_vdisplay - 1) << 16));
107101
108
- cfg = 0;
109
-
110102 prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
111103 mode_rate = adj->crtc_clock * 1000;
112
- if ((prate / 2) < mode_rate) {
104
+ if (!crtc->dc->desc->fixed_clksrc) {
113105 prate *= 2;
114106 cfg |= ATMEL_HLCDC_CLKSEL;
107
+ mask |= ATMEL_HLCDC_CLKSEL;
115108 }
116109
117110 div = DIV_ROUND_UP(prate, mode_rate);
118
- if (div < 2)
111
+ if (div < 2) {
119112 div = 2;
113
+ } else if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK) {
114
+ /* The divider ended up too big, try a lower base rate. */
115
+ cfg &= ~ATMEL_HLCDC_CLKSEL;
116
+ prate /= 2;
117
+ div = DIV_ROUND_UP(prate, mode_rate);
118
+ if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK)
119
+ div = ATMEL_HLCDC_CLKDIV_MASK;
120
+ } else {
121
+ int div_low = prate / mode_rate;
122
+
123
+ if (div_low >= 2 &&
124
+ (10 * (prate / div_low - mode_rate) <
125
+ (mode_rate - prate / div)))
126
+ /*
127
+ * At least 10 times better when using a higher
128
+ * frequency than requested, instead of a lower.
129
+ * So, go with that.
130
+ */
131
+ div = div_low;
132
+ }
120133
121134 cfg |= ATMEL_HLCDC_CLKDIV(div);
122135
123
- regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0),
124
- ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK |
125
- ATMEL_HLCDC_CLKPOL, cfg);
136
+ regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0), mask, cfg);
126137
127
- cfg = 0;
138
+ state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
139
+ cfg = state->output_mode << 8;
128140
129141 if (adj->flags & DRM_MODE_FLAG_NVSYNC)
130142 cfg |= ATMEL_HLCDC_VSPOL;
131143
132144 if (adj->flags & DRM_MODE_FLAG_NHSYNC)
133145 cfg |= ATMEL_HLCDC_HSPOL;
134
-
135
- state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
136
- cfg |= state->output_mode << 8;
137146
138147 regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
139148 ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
....@@ -232,6 +241,55 @@
232241 #define ATMEL_HLCDC_RGB888_OUTPUT BIT(3)
233242 #define ATMEL_HLCDC_OUTPUT_MODE_MASK GENMASK(3, 0)
234243
244
+static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
245
+{
246
+ struct drm_connector *connector = state->connector;
247
+ struct drm_display_info *info = &connector->display_info;
248
+ struct drm_encoder *encoder;
249
+ unsigned int supported_fmts = 0;
250
+ int j;
251
+
252
+ encoder = state->best_encoder;
253
+ if (!encoder)
254
+ encoder = connector->encoder;
255
+
256
+ switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
257
+ case 0:
258
+ break;
259
+ case MEDIA_BUS_FMT_RGB444_1X12:
260
+ return ATMEL_HLCDC_RGB444_OUTPUT;
261
+ case MEDIA_BUS_FMT_RGB565_1X16:
262
+ return ATMEL_HLCDC_RGB565_OUTPUT;
263
+ case MEDIA_BUS_FMT_RGB666_1X18:
264
+ return ATMEL_HLCDC_RGB666_OUTPUT;
265
+ case MEDIA_BUS_FMT_RGB888_1X24:
266
+ return ATMEL_HLCDC_RGB888_OUTPUT;
267
+ default:
268
+ return -EINVAL;
269
+ }
270
+
271
+ for (j = 0; j < info->num_bus_formats; j++) {
272
+ switch (info->bus_formats[j]) {
273
+ case MEDIA_BUS_FMT_RGB444_1X12:
274
+ supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
275
+ break;
276
+ case MEDIA_BUS_FMT_RGB565_1X16:
277
+ supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
278
+ break;
279
+ case MEDIA_BUS_FMT_RGB666_1X18:
280
+ supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
281
+ break;
282
+ case MEDIA_BUS_FMT_RGB888_1X24:
283
+ supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
284
+ break;
285
+ default:
286
+ break;
287
+ }
288
+ }
289
+
290
+ return supported_fmts;
291
+}
292
+
235293 static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
236294 {
237295 unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
....@@ -244,31 +302,12 @@
244302 crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
245303
246304 for_each_new_connector_in_state(state->state, connector, cstate, i) {
247
- struct drm_display_info *info = &connector->display_info;
248305 unsigned int supported_fmts = 0;
249
- int j;
250306
251307 if (!cstate->crtc)
252308 continue;
253309
254
- for (j = 0; j < info->num_bus_formats; j++) {
255
- switch (info->bus_formats[j]) {
256
- case MEDIA_BUS_FMT_RGB444_1X12:
257
- supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
258
- break;
259
- case MEDIA_BUS_FMT_RGB565_1X16:
260
- supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
261
- break;
262
- case MEDIA_BUS_FMT_RGB666_1X18:
263
- supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
264
- break;
265
- case MEDIA_BUS_FMT_RGB888_1X24:
266
- supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
267
- break;
268
- default:
269
- break;
270
- }
271
- }
310
+ supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
272311
273312 if (crtc->dc->desc->conflicting_output_formats)
274313 output_fmts &= supported_fmts;
....@@ -324,9 +363,7 @@
324363
325364 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
326365 .mode_valid = atmel_hlcdc_crtc_mode_valid,
327
- .mode_set = drm_helper_crtc_mode_set,
328366 .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
329
- .mode_set_base = drm_helper_crtc_mode_set_base,
330367 .atomic_check = atmel_hlcdc_crtc_atomic_check,
331368 .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
332369 .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
....@@ -374,10 +411,8 @@
374411 }
375412
376413 state = kzalloc(sizeof(*state), GFP_KERNEL);
377
- if (state) {
378
- crtc->state = &state->base;
379
- crtc->state->crtc = crtc;
380
- }
414
+ if (state)
415
+ __drm_atomic_helper_crtc_reset(crtc, &state->base);
381416 }
382417
383418 static struct drm_crtc_state *
....@@ -491,7 +526,6 @@
491526 }
492527
493528 drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
494
- drm_crtc_vblank_reset(&crtc->base);
495529
496530 drm_mode_crtc_set_gamma_size(&crtc->base, ATMEL_HLCDC_CLUT_SIZE);
497531 drm_crtc_enable_color_mgmt(&crtc->base, 0, false,