1
2
3
4
5
6
7
8
9#include <linux/component.h>
10#include <linux/ioport.h>
11#include <linux/module.h>
12#include <linux/of_address.h>
13#include <linux/of_device.h>
14#include <linux/of_irq.h>
15#include <linux/regmap.h>
16#include <linux/reset.h>
17
18#include <drm/drm_atomic_helper.h>
19#include <drm/drm_bridge.h>
20#include <drm/drm_connector.h>
21#include <drm/drm_crtc.h>
22#include <drm/drm_encoder.h>
23#include <drm/drm_modes.h>
24#include <drm/drm_of.h>
25#include <drm/drm_panel.h>
26#include <drm/drm_print.h>
27#include <drm/drm_probe_helper.h>
28#include <drm/drm_vblank.h>
29
30#include <uapi/drm/drm_mode.h>
31
32#include "sun4i_crtc.h"
33#include "sun4i_dotclock.h"
34#include "sun4i_drv.h"
35#include "sun4i_lvds.h"
36#include "sun4i_rgb.h"
37#include "sun4i_tcon.h"
38#include "sun6i_mipi_dsi.h"
39#include "sun8i_tcon_top.h"
40#include "sunxi_engine.h"
41
42static struct drm_connector *sun4i_tcon_get_connector(const struct drm_encoder *encoder)
43{
44 struct drm_connector *connector;
45 struct drm_connector_list_iter iter;
46
47 drm_connector_list_iter_begin(encoder->dev, &iter);
48 drm_for_each_connector_iter(connector, &iter)
49 if (connector->encoder == encoder) {
50 drm_connector_list_iter_end(&iter);
51 return connector;
52 }
53 drm_connector_list_iter_end(&iter);
54
55 return NULL;
56}
57
58static int sun4i_tcon_get_pixel_depth(const struct drm_encoder *encoder)
59{
60 struct drm_connector *connector;
61 struct drm_display_info *info;
62
63 connector = sun4i_tcon_get_connector(encoder);
64 if (!connector)
65 return -EINVAL;
66
67 info = &connector->display_info;
68 if (info->num_bus_formats != 1)
69 return -EINVAL;
70
71 switch (info->bus_formats[0]) {
72 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
73 return 18;
74
75 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
76 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
77 return 24;
78 }
79
80 return -EINVAL;
81}
82
83static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
84 bool enabled)
85{
86 struct clk *clk;
87
88 switch (channel) {
89 case 0:
90 WARN_ON(!tcon->quirks->has_channel_0);
91 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
92 SUN4I_TCON0_CTL_TCON_ENABLE,
93 enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
94 clk = tcon->dclk;
95 break;
96 case 1:
97 WARN_ON(!tcon->quirks->has_channel_1);
98 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
99 SUN4I_TCON1_CTL_TCON_ENABLE,
100 enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
101 clk = tcon->sclk1;
102 break;
103 default:
104 DRM_WARN("Unknown channel... doing nothing\n");
105 return;
106 }
107
108 if (enabled) {
109 clk_prepare_enable(clk);
110 clk_rate_exclusive_get(clk);
111 } else {
112 clk_rate_exclusive_put(clk);
113 clk_disable_unprepare(clk);
114 }
115}
116
117static void sun4i_tcon_setup_lvds_phy(struct sun4i_tcon *tcon,
118 const struct drm_encoder *encoder)
119{
120 regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
121 SUN4I_TCON0_LVDS_ANA0_CK_EN |
122 SUN4I_TCON0_LVDS_ANA0_REG_V |
123 SUN4I_TCON0_LVDS_ANA0_REG_C |
124 SUN4I_TCON0_LVDS_ANA0_EN_MB |
125 SUN4I_TCON0_LVDS_ANA0_PD |
126 SUN4I_TCON0_LVDS_ANA0_DCHS);
127
128 udelay(2);
129 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA1_REG,
130 SUN4I_TCON0_LVDS_ANA1_INIT,
131 SUN4I_TCON0_LVDS_ANA1_INIT);
132 udelay(1);
133 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA1_REG,
134 SUN4I_TCON0_LVDS_ANA1_UPDATE,
135 SUN4I_TCON0_LVDS_ANA1_UPDATE);
136 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
137 SUN4I_TCON0_LVDS_ANA0_EN_MB,
138 SUN4I_TCON0_LVDS_ANA0_EN_MB);
139}
140
141static void sun6i_tcon_setup_lvds_phy(struct sun4i_tcon *tcon,
142 const struct drm_encoder *encoder)
143{
144 u8 val;
145
146 regmap_write(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
147 SUN6I_TCON0_LVDS_ANA0_C(2) |
148 SUN6I_TCON0_LVDS_ANA0_V(3) |
149 SUN6I_TCON0_LVDS_ANA0_PD(2) |
150 SUN6I_TCON0_LVDS_ANA0_EN_LDO);
151 udelay(2);
152
153 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
154 SUN6I_TCON0_LVDS_ANA0_EN_MB,
155 SUN6I_TCON0_LVDS_ANA0_EN_MB);
156 udelay(2);
157
158 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
159 SUN6I_TCON0_LVDS_ANA0_EN_DRVC,
160 SUN6I_TCON0_LVDS_ANA0_EN_DRVC);
161
162 if (sun4i_tcon_get_pixel_depth(encoder) == 18)
163 val = 7;
164 else
165 val = 0xf;
166
167 regmap_write_bits(tcon->regs, SUN4I_TCON0_LVDS_ANA0_REG,
168 SUN6I_TCON0_LVDS_ANA0_EN_DRVD(0xf),
169 SUN6I_TCON0_LVDS_ANA0_EN_DRVD(val));
170}
171
172static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
173 const struct drm_encoder *encoder,
174 bool enabled)
175{
176 if (enabled) {
177 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
178 SUN4I_TCON0_LVDS_IF_EN,
179 SUN4I_TCON0_LVDS_IF_EN);
180 if (tcon->quirks->setup_lvds_phy)
181 tcon->quirks->setup_lvds_phy(tcon, encoder);
182 } else {
183 regmap_update_bits(tcon->regs, SUN4I_TCON0_LVDS_IF_REG,
184 SUN4I_TCON0_LVDS_IF_EN, 0);
185 }
186}
187
188void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
189 const struct drm_encoder *encoder,
190 bool enabled)
191{
192 bool is_lvds = false;
193 int channel;
194
195 switch (encoder->encoder_type) {
196 case DRM_MODE_ENCODER_LVDS:
197 is_lvds = true;
198 fallthrough;
199 case DRM_MODE_ENCODER_DSI:
200 case DRM_MODE_ENCODER_NONE:
201 channel = 0;
202 break;
203 case DRM_MODE_ENCODER_TMDS:
204 case DRM_MODE_ENCODER_TVDAC:
205 channel = 1;
206 break;
207 default:
208 DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
209 return;
210 }
211
212 if (is_lvds && !enabled)
213 sun4i_tcon_lvds_set_status(tcon, encoder, false);
214
215 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
216 SUN4I_TCON_GCTL_TCON_ENABLE,
217 enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
218
219 if (is_lvds && enabled)
220 sun4i_tcon_lvds_set_status(tcon, encoder, true);
221
222 sun4i_tcon_channel_set_status(tcon, channel, enabled);
223}
224
225void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
226{
227 u32 mask, val = 0;
228
229 DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
230
231 mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
232 SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |
233 SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;
234
235 if (enable)
236 val = mask;
237
238 regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);
239}
240EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
241
242
243
244
245
246
247
248static struct sun4i_tcon *sun4i_get_tcon0(struct drm_device *drm)
249{
250 struct sun4i_drv *drv = drm->dev_private;
251 struct sun4i_tcon *tcon;
252
253 list_for_each_entry(tcon, &drv->tcon_list, list)
254 if (tcon->id == 0)
255 return tcon;
256
257 dev_warn(drm->dev,
258 "TCON0 not found, display output muxing may not work\n");
259
260 return NULL;
261}
262
263static void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
264 const struct drm_encoder *encoder)
265{
266 int ret = -ENOTSUPP;
267
268 if (tcon->quirks->set_mux)
269 ret = tcon->quirks->set_mux(tcon, encoder);
270
271 DRM_DEBUG_DRIVER("Muxing encoder %s to CRTC %s: %d\n",
272 encoder->name, encoder->crtc->name, ret);
273}
274
275static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,
276 int channel)
277{
278 int delay = mode->vtotal - mode->vdisplay;
279
280 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
281 delay /= 2;
282
283 if (channel == 1)
284 delay -= 2;
285
286 delay = min(delay, 30);
287
288 DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);
289
290 return delay;
291}
292
293static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
294 const struct drm_display_mode *mode)
295{
296
297 clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
298
299
300 regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
301 SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
302 SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
303}
304
305static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
306 const struct drm_connector *connector)
307{
308 u32 bus_format = 0;
309 u32 val = 0;
310
311
312 if (!connector)
313 return;
314
315
316
317
318
319
320
321 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PR_REG, 0x11111111);
322 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PG_REG, 0x11111111);
323 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PB_REG, 0x11111111);
324 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LR_REG, 0x11111111);
325 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LG_REG, 0x11111111);
326 regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LB_REG, 0x11111111);
327 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL0_REG, 0x01010000);
328 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL1_REG, 0x15151111);
329 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL2_REG, 0x57575555);
330 regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL3_REG, 0x7f7f7777);
331
332
333 if (connector->display_info.bpc == 6)
334 val |= SUN4I_TCON0_FRM_CTL_EN;
335
336 if (connector->display_info.num_bus_formats == 1)
337 bus_format = connector->display_info.bus_formats[0];
338
339
340 switch (bus_format) {
341 case MEDIA_BUS_FMT_RGB565_1X16:
342
343 val |= SUN4I_TCON0_FRM_CTL_MODE_R;
344 val |= SUN4I_TCON0_FRM_CTL_MODE_B;
345 fallthrough;
346 case MEDIA_BUS_FMT_RGB666_1X18:
347 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
348
349 val |= SUN4I_TCON0_FRM_CTL_EN;
350 break;
351 }
352
353
354 regmap_write(tcon->regs, SUN4I_TCON_FRM_CTL_REG, val);
355}
356
357static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
358 const struct drm_encoder *encoder,
359 const struct drm_display_mode *mode)
360{
361
362 struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
363 struct mipi_dsi_device *device = dsi->device;
364 u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
365 u8 lanes = device->lanes;
366 u32 block_space, start_delay;
367 u32 tcon_div;
368
369 tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;
370 tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;
371
372 sun4i_tcon0_mode_set_common(tcon, mode);
373
374
375 sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
376
377 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
378 SUN4I_TCON0_CTL_IF_MASK,
379 SUN4I_TCON0_CTL_IF_8080);
380
381 regmap_write(tcon->regs, SUN4I_TCON_ECC_FIFO_REG,
382 SUN4I_TCON_ECC_FIFO_EN);
383
384 regmap_write(tcon->regs, SUN4I_TCON0_CPU_IF_REG,
385 SUN4I_TCON0_CPU_IF_MODE_DSI |
386 SUN4I_TCON0_CPU_IF_TRI_FIFO_FLUSH |
387 SUN4I_TCON0_CPU_IF_TRI_FIFO_EN |
388 SUN4I_TCON0_CPU_IF_TRI_EN);
389
390
391
392
393
394
395
396 regmap_read(tcon->regs, SUN4I_TCON0_DCLK_REG, &tcon_div);
397 tcon_div &= GENMASK(6, 0);
398 block_space = mode->htotal * bpp / (tcon_div * lanes);
399 block_space -= mode->hdisplay + 40;
400
401 regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI0_REG,
402 SUN4I_TCON0_CPU_TRI0_BLOCK_SPACE(block_space) |
403 SUN4I_TCON0_CPU_TRI0_BLOCK_SIZE(mode->hdisplay));
404
405 regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI1_REG,
406 SUN4I_TCON0_CPU_TRI1_BLOCK_NUM(mode->vdisplay));
407
408 start_delay = (mode->crtc_vtotal - mode->crtc_vdisplay - 10 - 1);
409 start_delay = start_delay * mode->crtc_htotal * 149;
410 start_delay = start_delay / (mode->crtc_clock / 1000) / 8;
411 regmap_write(tcon->regs, SUN4I_TCON0_CPU_TRI2_REG,
412 SUN4I_TCON0_CPU_TRI2_TRANS_START_SET(10) |
413 SUN4I_TCON0_CPU_TRI2_START_DELAY(start_delay));
414
415
416
417
418
419 regmap_write(tcon->regs, SUN4I_TCON_SAFE_PERIOD_REG,
420 SUN4I_TCON_SAFE_PERIOD_NUM(3000) |
421 SUN4I_TCON_SAFE_PERIOD_MODE(3));
422
423
424 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG,
425 0xe0000000);
426}
427
428static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
429 const struct drm_encoder *encoder,
430 const struct drm_display_mode *mode)
431{
432 unsigned int bp;
433 u8 clk_delay;
434 u32 reg, val = 0;
435
436 WARN_ON(!tcon->quirks->has_channel_0);
437
438 tcon->dclk_min_div = 7;
439 tcon->dclk_max_div = 7;
440 sun4i_tcon0_mode_set_common(tcon, mode);
441
442
443 sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
444
445
446 clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
447 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
448 SUN4I_TCON0_CTL_CLK_DELAY_MASK,
449 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
450
451
452
453
454
455 bp = mode->crtc_htotal - mode->crtc_hsync_start;
456 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
457 mode->crtc_htotal, bp);
458
459
460 regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
461 SUN4I_TCON0_BASIC1_H_TOTAL(mode->htotal) |
462 SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
463
464
465
466
467
468 bp = mode->crtc_vtotal - mode->crtc_vsync_start;
469 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
470 mode->crtc_vtotal, bp);
471
472
473 regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
474 SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
475 SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
476
477 reg = SUN4I_TCON0_LVDS_IF_CLK_SEL_TCON0;
478 if (sun4i_tcon_get_pixel_depth(encoder) == 24)
479 reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_24BITS;
480 else
481 reg |= SUN4I_TCON0_LVDS_IF_BITWIDTH_18BITS;
482
483 regmap_write(tcon->regs, SUN4I_TCON0_LVDS_IF_REG, reg);
484
485
486 if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
487 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
488
489 if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
490 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
491
492 regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
493
494
495 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
496 SUN4I_TCON_GCTL_IOMAP_MASK,
497 SUN4I_TCON_GCTL_IOMAP_TCON0);
498
499
500 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000);
501}
502
503static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
504 const struct drm_encoder *encoder,
505 const struct drm_display_mode *mode)
506{
507 struct drm_connector *connector = sun4i_tcon_get_connector(encoder);
508 const struct drm_display_info *info = &connector->display_info;
509 unsigned int bp, hsync, vsync;
510 u8 clk_delay;
511 u32 val = 0;
512
513 WARN_ON(!tcon->quirks->has_channel_0);
514
515 tcon->dclk_min_div = tcon->quirks->dclk_min_div;
516 tcon->dclk_max_div = 127;
517 sun4i_tcon0_mode_set_common(tcon, mode);
518
519
520 sun4i_tcon0_mode_set_dithering(tcon, connector);
521
522
523 clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
524 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
525 SUN4I_TCON0_CTL_CLK_DELAY_MASK,
526 SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
527
528
529
530
531
532 bp = mode->crtc_htotal - mode->crtc_hsync_start;
533 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
534 mode->crtc_htotal, bp);
535
536
537 regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
538 SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |
539 SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
540
541
542
543
544
545 bp = mode->crtc_vtotal - mode->crtc_vsync_start;
546 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
547 mode->crtc_vtotal, bp);
548
549
550 regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
551 SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal * 2) |
552 SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
553
554
555 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
556 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
557 DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
558 regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,
559 SUN4I_TCON0_BASIC3_V_SYNC(vsync) |
560 SUN4I_TCON0_BASIC3_H_SYNC(hsync));
561
562
563 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
564 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
565
566 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
567 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
568
569 if (info->bus_flags & DRM_BUS_FLAG_DE_LOW)
570 val |= SUN4I_TCON0_IO_POL_DE_NEGATIVE;
571
572 if (info->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
573 val |= SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE;
574
575 regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
576 SUN4I_TCON0_IO_POL_HSYNC_POSITIVE |
577 SUN4I_TCON0_IO_POL_VSYNC_POSITIVE |
578 SUN4I_TCON0_IO_POL_DCLK_DRIVE_NEGEDGE |
579 SUN4I_TCON0_IO_POL_DE_NEGATIVE,
580 val);
581
582
583 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
584 SUN4I_TCON_GCTL_IOMAP_MASK,
585 SUN4I_TCON_GCTL_IOMAP_TCON0);
586
587
588 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
589}
590
591static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
592 const struct drm_display_mode *mode)
593{
594 unsigned int bp, hsync, vsync, vtotal;
595 u8 clk_delay;
596 u32 val;
597
598 WARN_ON(!tcon->quirks->has_channel_1);
599
600
601 clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
602
603
604 clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
605 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
606 SUN4I_TCON1_CTL_CLK_DELAY_MASK,
607 SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));
608
609
610 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
611 val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;
612 else
613 val = 0;
614 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
615 SUN4I_TCON1_CTL_INTERLACE_ENABLE,
616 val);
617
618
619 regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
620 SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
621 SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
622
623
624 regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
625 SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
626 SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
627
628
629 regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
630 SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
631 SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
632
633
634 bp = mode->crtc_htotal - mode->crtc_hsync_start;
635 DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
636 mode->htotal, bp);
637 regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
638 SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
639 SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
640
641 bp = mode->crtc_vtotal - mode->crtc_vsync_start;
642 DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
643 mode->crtc_vtotal, bp);
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658 vtotal = mode->vtotal;
659 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
660 vtotal = vtotal * 2;
661
662
663 regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,
664 SUN4I_TCON1_BASIC4_V_TOTAL(vtotal) |
665 SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));
666
667
668 hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
669 vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
670 DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
671 regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,
672 SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
673 SUN4I_TCON1_BASIC5_H_SYNC(hsync));
674
675
676 if (tcon->quirks->polarity_in_ch0) {
677 val = 0;
678
679 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
680 val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
681
682 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
683 val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
684
685 regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
686 } else {
687
688 val = SUN4I_TCON1_IO_POL_UNKNOWN;
689
690 if (mode->flags & DRM_MODE_FLAG_PHSYNC)
691 val |= SUN4I_TCON1_IO_POL_HSYNC_POSITIVE;
692
693 if (mode->flags & DRM_MODE_FLAG_PVSYNC)
694 val |= SUN4I_TCON1_IO_POL_VSYNC_POSITIVE;
695
696 regmap_write(tcon->regs, SUN4I_TCON1_IO_POL_REG, val);
697 }
698
699
700 regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
701 SUN4I_TCON_GCTL_IOMAP_MASK,
702 SUN4I_TCON_GCTL_IOMAP_TCON1);
703}
704
705void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
706 const struct drm_encoder *encoder,
707 const struct drm_display_mode *mode)
708{
709 switch (encoder->encoder_type) {
710 case DRM_MODE_ENCODER_DSI:
711
712 sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);
713 break;
714 case DRM_MODE_ENCODER_LVDS:
715 sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
716 break;
717 case DRM_MODE_ENCODER_NONE:
718 sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);
719 sun4i_tcon_set_mux(tcon, 0, encoder);
720 break;
721 case DRM_MODE_ENCODER_TVDAC:
722 case DRM_MODE_ENCODER_TMDS:
723 sun4i_tcon1_mode_set(tcon, mode);
724 sun4i_tcon_set_mux(tcon, 1, encoder);
725 break;
726 default:
727 DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
728 }
729}
730EXPORT_SYMBOL(sun4i_tcon_mode_set);
731
732static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
733 struct sun4i_crtc *scrtc)
734{
735 unsigned long flags;
736
737 spin_lock_irqsave(&dev->event_lock, flags);
738 if (scrtc->event) {
739 drm_crtc_send_vblank_event(&scrtc->crtc, scrtc->event);
740 drm_crtc_vblank_put(&scrtc->crtc);
741 scrtc->event = NULL;
742 }
743 spin_unlock_irqrestore(&dev->event_lock, flags);
744}
745
746static irqreturn_t sun4i_tcon_handler(int irq, void *private)
747{
748 struct sun4i_tcon *tcon = private;
749 struct drm_device *drm = tcon->drm;
750 struct sun4i_crtc *scrtc = tcon->crtc;
751 struct sunxi_engine *engine = scrtc->engine;
752 unsigned int status;
753
754 regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
755
756 if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
757 SUN4I_TCON_GINT0_VBLANK_INT(1) |
758 SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))
759 return IRQ_NONE;
760
761 drm_crtc_handle_vblank(&scrtc->crtc);
762 sun4i_tcon_finish_page_flip(drm, scrtc);
763
764
765 regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
766 SUN4I_TCON_GINT0_VBLANK_INT(0) |
767 SUN4I_TCON_GINT0_VBLANK_INT(1) |
768 SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,
769 0);
770
771 if (engine->ops->vblank_quirk)
772 engine->ops->vblank_quirk(engine);
773
774 return IRQ_HANDLED;
775}
776
777static int sun4i_tcon_init_clocks(struct device *dev,
778 struct sun4i_tcon *tcon)
779{
780 tcon->clk = devm_clk_get(dev, "ahb");
781 if (IS_ERR(tcon->clk)) {
782 dev_err(dev, "Couldn't get the TCON bus clock\n");
783 return PTR_ERR(tcon->clk);
784 }
785 clk_prepare_enable(tcon->clk);
786
787 if (tcon->quirks->has_channel_0) {
788 tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
789 if (IS_ERR(tcon->sclk0)) {
790 dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
791 return PTR_ERR(tcon->sclk0);
792 }
793 }
794 clk_prepare_enable(tcon->sclk0);
795
796 if (tcon->quirks->has_channel_1) {
797 tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
798 if (IS_ERR(tcon->sclk1)) {
799 dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
800 return PTR_ERR(tcon->sclk1);
801 }
802 }
803
804 return 0;
805}
806
807static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
808{
809 clk_disable_unprepare(tcon->sclk0);
810 clk_disable_unprepare(tcon->clk);
811}
812
813static int sun4i_tcon_init_irq(struct device *dev,
814 struct sun4i_tcon *tcon)
815{
816 struct platform_device *pdev = to_platform_device(dev);
817 int irq, ret;
818
819 irq = platform_get_irq(pdev, 0);
820 if (irq < 0)
821 return irq;
822
823 ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0,
824 dev_name(dev), tcon);
825 if (ret) {
826 dev_err(dev, "Couldn't request the IRQ\n");
827 return ret;
828 }
829
830 return 0;
831}
832
833static const struct regmap_config sun4i_tcon_regmap_config = {
834 .reg_bits = 32,
835 .val_bits = 32,
836 .reg_stride = 4,
837 .max_register = 0x800,
838};
839
840static int sun4i_tcon_init_regmap(struct device *dev,
841 struct sun4i_tcon *tcon)
842{
843 struct platform_device *pdev = to_platform_device(dev);
844 struct resource *res;
845 void __iomem *regs;
846
847 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
848 regs = devm_ioremap_resource(dev, res);
849 if (IS_ERR(regs))
850 return PTR_ERR(regs);
851
852 tcon->regs = devm_regmap_init_mmio(dev, regs,
853 &sun4i_tcon_regmap_config);
854 if (IS_ERR(tcon->regs)) {
855 dev_err(dev, "Couldn't create the TCON regmap\n");
856 return PTR_ERR(tcon->regs);
857 }
858
859
860 regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);
861 regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);
862 regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);
863
864
865 regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);
866 regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);
867
868 return 0;
869}
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886static struct sunxi_engine *
887sun4i_tcon_find_engine_traverse(struct sun4i_drv *drv,
888 struct device_node *node,
889 u32 port_id)
890{
891 struct device_node *port, *ep, *remote;
892 struct sunxi_engine *engine = ERR_PTR(-EINVAL);
893 u32 reg = 0;
894
895 port = of_graph_get_port_by_id(node, port_id);
896 if (!port)
897 return ERR_PTR(-EINVAL);
898
899
900
901
902
903
904
905
906
907
908 if (of_get_available_child_count(port) != 1)
909 goto out_put_port;
910
911
912 ep = of_get_next_available_child(port, NULL);
913 if (!ep)
914 goto out_put_port;
915
916 remote = of_graph_get_remote_port_parent(ep);
917 if (!remote)
918 goto out_put_ep;
919
920
921 list_for_each_entry(engine, &drv->engine_list, list)
922 if (remote == engine->node)
923 goto out_put_remote;
924
925
926
927
928
929
930
931
932
933 of_node_put(port);
934 port = of_graph_get_remote_port(ep);
935 if (!of_property_read_u32(port, "reg", ®) && reg > 0)
936 reg -= 1;
937
938
939 engine = sun4i_tcon_find_engine_traverse(drv, remote, reg);
940
941out_put_remote:
942 of_node_put(remote);
943out_put_ep:
944 of_node_put(ep);
945out_put_port:
946 of_node_put(port);
947
948 return engine;
949}
950
951
952
953
954
955
956
957
958
959
960
961static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
962{
963 struct device_node *ep;
964 int ret = -EINVAL;
965
966
967 for_each_available_child_of_node(port, ep) {
968 struct device_node *remote;
969 u32 reg;
970
971 remote = of_graph_get_remote_endpoint(ep);
972 if (!remote)
973 continue;
974
975 ret = of_property_read_u32(remote, "reg", ®);
976 if (ret)
977 continue;
978
979 ret = reg;
980 }
981
982 return ret;
983}
984
985
986
987
988
989
990static struct sunxi_engine *sun4i_tcon_get_engine_by_id(struct sun4i_drv *drv,
991 int id)
992{
993 struct sunxi_engine *engine;
994
995 list_for_each_entry(engine, &drv->engine_list, list)
996 if (engine->id == id)
997 return engine;
998
999 return ERR_PTR(-EINVAL);
1000}
1001
1002static bool sun4i_tcon_connected_to_tcon_top(struct device_node *node)
1003{
1004 struct device_node *remote;
1005 bool ret = false;
1006
1007 remote = of_graph_get_remote_node(node, 0, -1);
1008 if (remote) {
1009 ret = !!(IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
1010 of_match_node(sun8i_tcon_top_of_table, remote));
1011 of_node_put(remote);
1012 }
1013
1014 return ret;
1015}
1016
1017static int sun4i_tcon_get_index(struct sun4i_drv *drv)
1018{
1019 struct list_head *pos;
1020 int size = 0;
1021
1022
1023
1024
1025
1026
1027 list_for_each(pos, &drv->tcon_list)
1028 ++size;
1029
1030 return size;
1031}
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
1067 struct device_node *node)
1068{
1069 struct device_node *port;
1070 struct sunxi_engine *engine;
1071
1072 port = of_graph_get_port_by_id(node, 0);
1073 if (!port)
1074 return ERR_PTR(-EINVAL);
1075
1076
1077
1078
1079
1080 if (of_get_child_count(port) > 1) {
1081 int id;
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095 if (sun4i_tcon_connected_to_tcon_top(node))
1096 id = sun4i_tcon_get_index(drv);
1097 else
1098 id = sun4i_tcon_of_get_id_from_port(port);
1099
1100
1101 engine = sun4i_tcon_get_engine_by_id(drv, id);
1102
1103 of_node_put(port);
1104 return engine;
1105 }
1106
1107
1108 of_node_put(port);
1109 return sun4i_tcon_find_engine_traverse(drv, node, 0);
1110}
1111
1112static int sun4i_tcon_bind(struct device *dev, struct device *master,
1113 void *data)
1114{
1115 struct drm_device *drm = data;
1116 struct sun4i_drv *drv = drm->dev_private;
1117 struct sunxi_engine *engine;
1118 struct device_node *remote;
1119 struct sun4i_tcon *tcon;
1120 struct reset_control *edp_rstc;
1121 bool has_lvds_rst, has_lvds_alt, can_lvds;
1122 int ret;
1123
1124 engine = sun4i_tcon_find_engine(drv, dev->of_node);
1125 if (IS_ERR(engine)) {
1126 dev_err(dev, "Couldn't find matching engine\n");
1127 return -EPROBE_DEFER;
1128 }
1129
1130 tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
1131 if (!tcon)
1132 return -ENOMEM;
1133 dev_set_drvdata(dev, tcon);
1134 tcon->drm = drm;
1135 tcon->dev = dev;
1136 tcon->id = engine->id;
1137 tcon->quirks = of_device_get_match_data(dev);
1138
1139 tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
1140 if (IS_ERR(tcon->lcd_rst)) {
1141 dev_err(dev, "Couldn't get our reset line\n");
1142 return PTR_ERR(tcon->lcd_rst);
1143 }
1144
1145 if (tcon->quirks->needs_edp_reset) {
1146 edp_rstc = devm_reset_control_get_shared(dev, "edp");
1147 if (IS_ERR(edp_rstc)) {
1148 dev_err(dev, "Couldn't get edp reset line\n");
1149 return PTR_ERR(edp_rstc);
1150 }
1151
1152 ret = reset_control_deassert(edp_rstc);
1153 if (ret) {
1154 dev_err(dev, "Couldn't deassert edp reset line\n");
1155 return ret;
1156 }
1157 }
1158
1159
1160 ret = reset_control_reset(tcon->lcd_rst);
1161 if (ret) {
1162 dev_err(dev, "Couldn't deassert our reset line\n");
1163 return ret;
1164 }
1165
1166 if (tcon->quirks->supports_lvds) {
1167
1168
1169
1170
1171
1172
1173
1174 tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
1175 if (IS_ERR(tcon->lvds_rst)) {
1176 dev_err(dev, "Couldn't get our reset line\n");
1177 return PTR_ERR(tcon->lvds_rst);
1178 } else if (tcon->lvds_rst) {
1179 has_lvds_rst = true;
1180 reset_control_reset(tcon->lvds_rst);
1181 } else {
1182 has_lvds_rst = false;
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192 if (tcon->quirks->has_lvds_alt) {
1193 tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
1194 if (IS_ERR(tcon->lvds_pll)) {
1195 if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
1196 has_lvds_alt = false;
1197 } else {
1198 dev_err(dev, "Couldn't get the LVDS PLL\n");
1199 return PTR_ERR(tcon->lvds_pll);
1200 }
1201 } else {
1202 has_lvds_alt = true;
1203 }
1204 }
1205
1206 if (!has_lvds_rst ||
1207 (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
1208 dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n");
1209 dev_warn(dev, "LVDS output disabled\n");
1210 can_lvds = false;
1211 } else {
1212 can_lvds = true;
1213 }
1214 } else {
1215 can_lvds = false;
1216 }
1217
1218 ret = sun4i_tcon_init_clocks(dev, tcon);
1219 if (ret) {
1220 dev_err(dev, "Couldn't init our TCON clocks\n");
1221 goto err_assert_reset;
1222 }
1223
1224 ret = sun4i_tcon_init_regmap(dev, tcon);
1225 if (ret) {
1226 dev_err(dev, "Couldn't init our TCON regmap\n");
1227 goto err_free_clocks;
1228 }
1229
1230 if (tcon->quirks->has_channel_0) {
1231 ret = sun4i_dclk_create(dev, tcon);
1232 if (ret) {
1233 dev_err(dev, "Couldn't create our TCON dot clock\n");
1234 goto err_free_clocks;
1235 }
1236 }
1237
1238 ret = sun4i_tcon_init_irq(dev, tcon);
1239 if (ret) {
1240 dev_err(dev, "Couldn't init our TCON interrupts\n");
1241 goto err_free_dotclock;
1242 }
1243
1244 tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
1245 if (IS_ERR(tcon->crtc)) {
1246 dev_err(dev, "Couldn't create our CRTC\n");
1247 ret = PTR_ERR(tcon->crtc);
1248 goto err_free_dotclock;
1249 }
1250
1251 if (tcon->quirks->has_channel_0) {
1252
1253
1254
1255
1256
1257 remote = of_graph_get_remote_node(dev->of_node, 1, 0);
1258 if (of_device_is_compatible(remote, "panel-lvds"))
1259 if (can_lvds)
1260 ret = sun4i_lvds_init(drm, tcon);
1261 else
1262 ret = -EINVAL;
1263 else
1264 ret = sun4i_rgb_init(drm, tcon);
1265 of_node_put(remote);
1266
1267 if (ret < 0)
1268 goto err_free_dotclock;
1269 }
1270
1271 if (tcon->quirks->needs_de_be_mux) {
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
1283 SUN4I_TCON0_CTL_SRC_SEL_MASK,
1284 tcon->id);
1285 regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
1286 SUN4I_TCON1_CTL_SRC_SEL_MASK,
1287 tcon->id);
1288 }
1289
1290 list_add_tail(&tcon->list, &drv->tcon_list);
1291
1292 return 0;
1293
1294err_free_dotclock:
1295 if (tcon->quirks->has_channel_0)
1296 sun4i_dclk_free(tcon);
1297err_free_clocks:
1298 sun4i_tcon_free_clocks(tcon);
1299err_assert_reset:
1300 reset_control_assert(tcon->lcd_rst);
1301 return ret;
1302}
1303
1304static void sun4i_tcon_unbind(struct device *dev, struct device *master,
1305 void *data)
1306{
1307 struct sun4i_tcon *tcon = dev_get_drvdata(dev);
1308
1309 list_del(&tcon->list);
1310 if (tcon->quirks->has_channel_0)
1311 sun4i_dclk_free(tcon);
1312 sun4i_tcon_free_clocks(tcon);
1313}
1314
1315static const struct component_ops sun4i_tcon_ops = {
1316 .bind = sun4i_tcon_bind,
1317 .unbind = sun4i_tcon_unbind,
1318};
1319
1320static int sun4i_tcon_probe(struct platform_device *pdev)
1321{
1322 struct device_node *node = pdev->dev.of_node;
1323 const struct sun4i_tcon_quirks *quirks;
1324 struct drm_bridge *bridge;
1325 struct drm_panel *panel;
1326 int ret;
1327
1328 quirks = of_device_get_match_data(&pdev->dev);
1329
1330
1331 if (quirks->has_channel_0) {
1332 ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
1333 if (ret == -EPROBE_DEFER)
1334 return ret;
1335 }
1336
1337 return component_add(&pdev->dev, &sun4i_tcon_ops);
1338}
1339
1340static int sun4i_tcon_remove(struct platform_device *pdev)
1341{
1342 component_del(&pdev->dev, &sun4i_tcon_ops);
1343
1344 return 0;
1345}
1346
1347
1348static int sun4i_a10_tcon_set_mux(struct sun4i_tcon *tcon,
1349 const struct drm_encoder *encoder)
1350{
1351 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
1352 u32 shift;
1353
1354 if (!tcon0)
1355 return -EINVAL;
1356
1357 switch (encoder->encoder_type) {
1358 case DRM_MODE_ENCODER_TMDS:
1359
1360 shift = 8;
1361 break;
1362 default:
1363 return -EINVAL;
1364 }
1365
1366 regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
1367 0x3 << shift, tcon->id << shift);
1368
1369 return 0;
1370}
1371
1372static int sun5i_a13_tcon_set_mux(struct sun4i_tcon *tcon,
1373 const struct drm_encoder *encoder)
1374{
1375 u32 val;
1376
1377 if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
1378 val = 1;
1379 else
1380 val = 0;
1381
1382
1383
1384
1385 return regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
1386}
1387
1388static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
1389 const struct drm_encoder *encoder)
1390{
1391 struct sun4i_tcon *tcon0 = sun4i_get_tcon0(encoder->dev);
1392 u32 shift;
1393
1394 if (!tcon0)
1395 return -EINVAL;
1396
1397 switch (encoder->encoder_type) {
1398 case DRM_MODE_ENCODER_TMDS:
1399
1400 shift = 8;
1401 break;
1402 default:
1403
1404 return -EINVAL;
1405 }
1406
1407 regmap_update_bits(tcon0->regs, SUN4I_TCON_MUX_CTRL_REG,
1408 0x3 << shift, tcon->id << shift);
1409
1410 return 0;
1411}
1412
1413static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
1414 const struct drm_encoder *encoder)
1415{
1416 struct device_node *port, *remote;
1417 struct platform_device *pdev;
1418 int id, ret;
1419
1420
1421
1422 port = of_graph_get_port_by_id(tcon->dev->of_node, 0);
1423 if (!port)
1424 return -EINVAL;
1425
1426 id = sun4i_tcon_of_get_id_from_port(port);
1427 of_node_put(port);
1428
1429 remote = of_graph_get_remote_node(tcon->dev->of_node, 0, -1);
1430 if (!remote)
1431 return -EINVAL;
1432
1433 pdev = of_find_device_by_node(remote);
1434 of_node_put(remote);
1435 if (!pdev)
1436 return -EINVAL;
1437
1438 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
1439 encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
1440 ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
1441 if (ret) {
1442 put_device(&pdev->dev);
1443 return ret;
1444 }
1445 }
1446
1447 if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
1448 ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
1449 if (ret) {
1450 put_device(&pdev->dev);
1451 return ret;
1452 }
1453 }
1454
1455 return 0;
1456}
1457
1458static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
1459 .has_channel_0 = true,
1460 .has_channel_1 = true,
1461 .dclk_min_div = 4,
1462 .set_mux = sun4i_a10_tcon_set_mux,
1463};
1464
1465static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
1466 .has_channel_0 = true,
1467 .has_channel_1 = true,
1468 .dclk_min_div = 4,
1469 .set_mux = sun5i_a13_tcon_set_mux,
1470};
1471
1472static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
1473 .has_channel_0 = true,
1474 .has_channel_1 = true,
1475 .has_lvds_alt = true,
1476 .needs_de_be_mux = true,
1477 .dclk_min_div = 1,
1478 .set_mux = sun6i_tcon_set_mux,
1479};
1480
1481static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
1482 .has_channel_0 = true,
1483 .has_channel_1 = true,
1484 .needs_de_be_mux = true,
1485 .dclk_min_div = 1,
1486};
1487
1488static const struct sun4i_tcon_quirks sun7i_a20_tcon0_quirks = {
1489 .supports_lvds = true,
1490 .has_channel_0 = true,
1491 .has_channel_1 = true,
1492 .dclk_min_div = 4,
1493
1494 .set_mux = sun4i_a10_tcon_set_mux,
1495 .setup_lvds_phy = sun4i_tcon_setup_lvds_phy,
1496};
1497
1498static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
1499 .has_channel_0 = true,
1500 .has_channel_1 = true,
1501 .dclk_min_div = 4,
1502
1503 .set_mux = sun4i_a10_tcon_set_mux,
1504};
1505
1506static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
1507 .has_channel_0 = true,
1508 .has_lvds_alt = true,
1509 .dclk_min_div = 1,
1510 .setup_lvds_phy = sun6i_tcon_setup_lvds_phy,
1511 .supports_lvds = true,
1512};
1513
1514static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
1515 .supports_lvds = true,
1516 .has_channel_0 = true,
1517 .dclk_min_div = 1,
1518 .setup_lvds_phy = sun6i_tcon_setup_lvds_phy,
1519};
1520
1521static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
1522 .has_channel_1 = true,
1523};
1524
1525static const struct sun4i_tcon_quirks sun8i_r40_tv_quirks = {
1526 .has_channel_1 = true,
1527 .polarity_in_ch0 = true,
1528 .set_mux = sun8i_r40_tcon_tv_set_mux,
1529};
1530
1531static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
1532 .has_channel_0 = true,
1533 .dclk_min_div = 1,
1534};
1535
1536static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {
1537 .has_channel_0 = true,
1538 .needs_edp_reset = true,
1539 .dclk_min_div = 1,
1540};
1541
1542static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {
1543 .has_channel_1 = true,
1544 .needs_edp_reset = true,
1545};
1546
1547
1548const struct of_device_id sun4i_tcon_of_table[] = {
1549 { .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
1550 { .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
1551 { .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
1552 { .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
1553 { .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
1554 { .compatible = "allwinner,sun7i-a20-tcon0", .data = &sun7i_a20_tcon0_quirks },
1555 { .compatible = "allwinner,sun7i-a20-tcon1", .data = &sun7i_a20_quirks },
1556 { .compatible = "allwinner,sun8i-a23-tcon", .data = &sun8i_a33_quirks },
1557 { .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
1558 { .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
1559 { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
1560 { .compatible = "allwinner,sun8i-r40-tcon-tv", .data = &sun8i_r40_tv_quirks },
1561 { .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
1562 { .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
1563 { .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
1564 { }
1565};
1566MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
1567EXPORT_SYMBOL(sun4i_tcon_of_table);
1568
1569static struct platform_driver sun4i_tcon_platform_driver = {
1570 .probe = sun4i_tcon_probe,
1571 .remove = sun4i_tcon_remove,
1572 .driver = {
1573 .name = "sun4i-tcon",
1574 .of_match_table = sun4i_tcon_of_table,
1575 },
1576};
1577module_platform_driver(sun4i_tcon_platform_driver);
1578
1579MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1580MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver");
1581MODULE_LICENSE("GPL");
1582