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