1
2
3
4
5
6
7
8
9
10#include <linux/clk.h>
11#include <linux/delay.h>
12#include <linux/io.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_device.h>
16#include <linux/of_graph.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/sys_soc.h>
20
21#include <drm/drm_atomic.h>
22#include <drm/drm_atomic_helper.h>
23#include <drm/drm_bridge.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
29#include "rcar_lvds.h"
30#include "rcar_lvds_regs.h"
31
32struct rcar_lvds;
33
34
35enum rcar_lvds_mode {
36 RCAR_LVDS_MODE_JEIDA = 0,
37 RCAR_LVDS_MODE_MIRROR = 1,
38 RCAR_LVDS_MODE_VESA = 4,
39};
40
41enum rcar_lvds_link_type {
42 RCAR_LVDS_SINGLE_LINK = 0,
43 RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 1,
44 RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 2,
45};
46
47#define RCAR_LVDS_QUIRK_LANES BIT(0)
48#define RCAR_LVDS_QUIRK_GEN3_LVEN BIT(1)
49#define RCAR_LVDS_QUIRK_PWD BIT(2)
50#define RCAR_LVDS_QUIRK_EXT_PLL BIT(3)
51#define RCAR_LVDS_QUIRK_DUAL_LINK BIT(4)
52
53struct rcar_lvds_device_info {
54 unsigned int gen;
55 unsigned int quirks;
56 void (*pll_setup)(struct rcar_lvds *lvds, unsigned int freq);
57};
58
59struct rcar_lvds {
60 struct device *dev;
61 const struct rcar_lvds_device_info *info;
62
63 struct drm_bridge bridge;
64
65 struct drm_bridge *next_bridge;
66 struct drm_panel *panel;
67
68 void __iomem *mmio;
69 struct {
70 struct clk *mod;
71 struct clk *extal;
72 struct clk *dotclkin[2];
73 } clocks;
74
75 struct drm_bridge *companion;
76 enum rcar_lvds_link_type link_type;
77};
78
79#define bridge_to_rcar_lvds(b) \
80 container_of(b, struct rcar_lvds, bridge)
81
82static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
83{
84 iowrite32(data, lvds->mmio + reg);
85}
86
87
88
89
90
91static void rcar_lvds_pll_setup_gen2(struct rcar_lvds *lvds, unsigned int freq)
92{
93 u32 val;
94
95 if (freq < 39000000)
96 val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
97 else if (freq < 61000000)
98 val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
99 else if (freq < 121000000)
100 val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
101 else
102 val = LVDPLLCR_PLLDLYCNT_150M;
103
104 rcar_lvds_write(lvds, LVDPLLCR, val);
105}
106
107static void rcar_lvds_pll_setup_gen3(struct rcar_lvds *lvds, unsigned int freq)
108{
109 u32 val;
110
111 if (freq < 42000000)
112 val = LVDPLLCR_PLLDIVCNT_42M;
113 else if (freq < 85000000)
114 val = LVDPLLCR_PLLDIVCNT_85M;
115 else if (freq < 128000000)
116 val = LVDPLLCR_PLLDIVCNT_128M;
117 else
118 val = LVDPLLCR_PLLDIVCNT_148M;
119
120 rcar_lvds_write(lvds, LVDPLLCR, val);
121}
122
123struct pll_info {
124 unsigned long diff;
125 unsigned int pll_m;
126 unsigned int pll_n;
127 unsigned int pll_e;
128 unsigned int div;
129 u32 clksel;
130};
131
132static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
133 unsigned long target, struct pll_info *pll,
134 u32 clksel, bool dot_clock_only)
135{
136 unsigned int div7 = dot_clock_only ? 1 : 7;
137 unsigned long output;
138 unsigned long fin;
139 unsigned int m_min;
140 unsigned int m_max;
141 unsigned int m;
142 int error;
143
144 if (!clk)
145 return;
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 fin = clk_get_rate(clk);
178 if (fin < 12000000 || fin > 192000000)
179 return;
180
181
182
183
184
185
186
187 m_min = max_t(unsigned int, 1, DIV_ROUND_UP(fin, 24000000));
188 m_max = min_t(unsigned int, 8, fin / 12000000);
189
190 for (m = m_min; m <= m_max; ++m) {
191 unsigned long fpfd;
192 unsigned int n_min;
193 unsigned int n_max;
194 unsigned int n;
195
196
197
198
199
200
201
202
203 fpfd = fin / m;
204 n_min = max_t(unsigned int, 60, DIV_ROUND_UP(900000000, fpfd));
205 n_max = min_t(unsigned int, 120, 1800000000 / fpfd);
206
207 for (n = n_min; n < n_max; ++n) {
208 unsigned long fvco;
209 unsigned int e_min;
210 unsigned int e;
211
212
213
214
215
216
217
218
219 fvco = fpfd * n;
220 e_min = fvco > 1039500000 ? 1 : 0;
221
222 for (e = e_min; e < 3; ++e) {
223 unsigned long fout;
224 unsigned long diff;
225 unsigned int div;
226
227
228
229
230
231
232 fout = fvco / (1 << e) / div7;
233 div = max(1UL, DIV_ROUND_CLOSEST(fout, target));
234 diff = abs(fout / div - target);
235
236 if (diff < pll->diff) {
237 pll->diff = diff;
238 pll->pll_m = m;
239 pll->pll_n = n;
240 pll->pll_e = e;
241 pll->div = div;
242 pll->clksel = clksel;
243
244 if (diff == 0)
245 goto done;
246 }
247 }
248 }
249 }
250
251done:
252 output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e)
253 / div7 / pll->div;
254 error = (long)(output - target) * 10000 / (long)target;
255
256 dev_dbg(lvds->dev,
257 "%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/E/DIV %u/%u/%u/%u\n",
258 clk, fin, output, target, error / 100,
259 error < 0 ? -error % 100 : error % 100,
260 pll->pll_m, pll->pll_n, pll->pll_e, pll->div);
261}
262
263static void __rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds,
264 unsigned int freq, bool dot_clock_only)
265{
266 struct pll_info pll = { .diff = (unsigned long)-1 };
267 u32 lvdpllcr;
268
269 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll,
270 LVDPLLCR_CKSEL_DU_DOTCLKIN(0), dot_clock_only);
271 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll,
272 LVDPLLCR_CKSEL_DU_DOTCLKIN(1), dot_clock_only);
273 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll,
274 LVDPLLCR_CKSEL_EXTAL, dot_clock_only);
275
276 lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT
277 | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1);
278
279 if (pll.pll_e > 0)
280 lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL
281 | LVDPLLCR_PLLE(pll.pll_e - 1);
282
283 if (dot_clock_only)
284 lvdpllcr |= LVDPLLCR_OCKSEL;
285
286 rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
287
288 if (pll.div > 1)
289
290
291
292
293 rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL |
294 LVDDIV_DIVRESET | LVDDIV_DIV(pll.div - 1));
295 else
296 rcar_lvds_write(lvds, LVDDIV, 0);
297}
298
299static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
300{
301 __rcar_lvds_pll_setup_d3_e3(lvds, freq, false);
302}
303
304
305
306
307
308int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq)
309{
310 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
311 int ret;
312
313 if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
314 return -ENODEV;
315
316 dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq);
317
318 ret = clk_prepare_enable(lvds->clocks.mod);
319 if (ret < 0)
320 return ret;
321
322 __rcar_lvds_pll_setup_d3_e3(lvds, freq, true);
323
324 return 0;
325}
326EXPORT_SYMBOL_GPL(rcar_lvds_clk_enable);
327
328void rcar_lvds_clk_disable(struct drm_bridge *bridge)
329{
330 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
331
332 if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)))
333 return;
334
335 dev_dbg(lvds->dev, "disabling LVDS PLL\n");
336
337 rcar_lvds_write(lvds, LVDPLLCR, 0);
338
339 clk_disable_unprepare(lvds->clocks.mod);
340}
341EXPORT_SYMBOL_GPL(rcar_lvds_clk_disable);
342
343
344
345
346
347static enum rcar_lvds_mode rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds,
348 const struct drm_connector *connector)
349{
350 const struct drm_display_info *info;
351 enum rcar_lvds_mode mode;
352
353
354
355
356
357 if (!lvds->panel)
358 return RCAR_LVDS_MODE_JEIDA;
359
360 info = &connector->display_info;
361 if (!info->num_bus_formats || !info->bus_formats) {
362 dev_warn(lvds->dev,
363 "no LVDS bus format reported, using JEIDA\n");
364 return RCAR_LVDS_MODE_JEIDA;
365 }
366
367 switch (info->bus_formats[0]) {
368 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
369 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
370 mode = RCAR_LVDS_MODE_JEIDA;
371 break;
372 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
373 mode = RCAR_LVDS_MODE_VESA;
374 break;
375 default:
376 dev_warn(lvds->dev,
377 "unsupported LVDS bus format 0x%04x, using JEIDA\n",
378 info->bus_formats[0]);
379 return RCAR_LVDS_MODE_JEIDA;
380 }
381
382 if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
383 mode |= RCAR_LVDS_MODE_MIRROR;
384
385 return mode;
386}
387
388static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
389 struct drm_atomic_state *state,
390 struct drm_crtc *crtc,
391 struct drm_connector *connector)
392{
393 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
394 u32 lvdhcr;
395 u32 lvdcr0;
396 int ret;
397
398 ret = clk_prepare_enable(lvds->clocks.mod);
399 if (ret < 0)
400 return;
401
402
403 if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
404 __rcar_lvds_atomic_enable(lvds->companion, state, crtc,
405 connector);
406
407
408
409
410
411
412
413
414
415 rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
416 LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
417 LVDCTRCR_CTR0SEL_HSYNC);
418
419 if (lvds->info->quirks & RCAR_LVDS_QUIRK_LANES)
420 lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
421 | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
422 else
423 lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
424 | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
425
426 rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
427
428 if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK) {
429 u32 lvdstripe = 0;
430
431 if (lvds->link_type != RCAR_LVDS_SINGLE_LINK) {
432
433
434
435
436
437
438
439 bool swap_pixels = lvds->link_type ==
440 RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
441
442
443
444
445
446
447
448
449 lvdstripe = LVDSTRIPE_ST_ON
450 | (lvds->companion && swap_pixels ?
451 LVDSTRIPE_ST_SWAP : 0);
452 }
453 rcar_lvds_write(lvds, LVDSTRIPE, lvdstripe);
454 }
455
456
457
458
459
460 if (lvds->link_type == RCAR_LVDS_SINGLE_LINK || lvds->companion) {
461 const struct drm_crtc_state *crtc_state =
462 drm_atomic_get_new_crtc_state(state, crtc);
463 const struct drm_display_mode *mode =
464 &crtc_state->adjusted_mode;
465
466 lvds->info->pll_setup(lvds, mode->clock * 1000);
467 }
468
469
470 lvdcr0 = rcar_lvds_get_lvds_mode(lvds, connector) << LVDCR0_LVMD_SHIFT;
471
472 if (lvds->bridge.encoder) {
473 if (drm_crtc_index(crtc) == 2)
474 lvdcr0 |= LVDCR0_DUSEL;
475 }
476
477 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
478
479
480 rcar_lvds_write(lvds, LVDCR1,
481 LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
482 LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
483
484 if (lvds->info->gen < 3) {
485
486 lvdcr0 |= LVDCR0_BEN | LVDCR0_LVEN;
487 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
488 }
489
490 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
491
492
493
494
495 lvdcr0 |= LVDCR0_PLLON;
496 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
497 }
498
499 if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
500
501 lvdcr0 |= LVDCR0_PWD;
502 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
503 }
504
505 if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) {
506
507
508
509
510 lvdcr0 |= LVDCR0_LVEN;
511 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_PWD))
512 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
513 }
514
515 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
516
517 usleep_range(100, 150);
518 }
519
520
521 lvdcr0 |= LVDCR0_LVRES;
522 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
523}
524
525static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
526 struct drm_bridge_state *old_bridge_state)
527{
528 struct drm_atomic_state *state = old_bridge_state->base.state;
529 struct drm_connector *connector;
530 struct drm_crtc *crtc;
531
532 connector = drm_atomic_get_new_connector_for_encoder(state,
533 bridge->encoder);
534 crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
535
536 __rcar_lvds_atomic_enable(bridge, state, crtc, connector);
537}
538
539static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
540 struct drm_bridge_state *old_bridge_state)
541{
542 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
543
544 rcar_lvds_write(lvds, LVDCR0, 0);
545 rcar_lvds_write(lvds, LVDCR1, 0);
546 rcar_lvds_write(lvds, LVDPLLCR, 0);
547
548
549 if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
550 lvds->companion->funcs->atomic_disable(lvds->companion,
551 old_bridge_state);
552
553 clk_disable_unprepare(lvds->clocks.mod);
554}
555
556static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
557 const struct drm_display_mode *mode,
558 struct drm_display_mode *adjusted_mode)
559{
560 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
561 int min_freq;
562
563
564
565
566
567
568 min_freq = lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL ? 5000 : 31000;
569 adjusted_mode->clock = clamp(adjusted_mode->clock, min_freq, 148500);
570
571 return true;
572}
573
574static int rcar_lvds_attach(struct drm_bridge *bridge,
575 enum drm_bridge_attach_flags flags)
576{
577 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
578
579 if (!lvds->next_bridge)
580 return 0;
581
582 return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge,
583 flags);
584}
585
586static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
587 .attach = rcar_lvds_attach,
588 .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
589 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
590 .atomic_reset = drm_atomic_helper_bridge_reset,
591 .atomic_enable = rcar_lvds_atomic_enable,
592 .atomic_disable = rcar_lvds_atomic_disable,
593 .mode_fixup = rcar_lvds_mode_fixup,
594};
595
596bool rcar_lvds_dual_link(struct drm_bridge *bridge)
597{
598 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
599
600 return lvds->link_type != RCAR_LVDS_SINGLE_LINK;
601}
602EXPORT_SYMBOL_GPL(rcar_lvds_dual_link);
603
604bool rcar_lvds_is_connected(struct drm_bridge *bridge)
605{
606 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
607
608 return lvds->next_bridge != NULL;
609}
610EXPORT_SYMBOL_GPL(rcar_lvds_is_connected);
611
612
613
614
615
616static int rcar_lvds_parse_dt_companion(struct rcar_lvds *lvds)
617{
618 const struct of_device_id *match;
619 struct device_node *companion;
620 struct device_node *port0, *port1;
621 struct rcar_lvds *companion_lvds;
622 struct device *dev = lvds->dev;
623 int dual_link;
624 int ret = 0;
625
626
627 companion = of_parse_phandle(dev->of_node, "renesas,companion", 0);
628 if (!companion)
629 return 0;
630
631
632
633
634
635 match = of_match_device(dev->driver->of_match_table, dev);
636 if (!of_device_is_compatible(companion, match->compatible)) {
637 dev_err(dev, "Companion LVDS encoder is invalid\n");
638 ret = -ENXIO;
639 goto done;
640 }
641
642
643
644
645
646
647
648 port0 = of_graph_get_port_by_id(dev->of_node, 1);
649 port1 = of_graph_get_port_by_id(companion, 1);
650 dual_link = drm_of_lvds_get_dual_link_pixel_order(port0, port1);
651 of_node_put(port0);
652 of_node_put(port1);
653
654 switch (dual_link) {
655 case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS:
656 lvds->link_type = RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS;
657 break;
658 case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS:
659 lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
660 break;
661 default:
662
663
664
665
666
667
668 if (lvds->next_bridge->timings &&
669 lvds->next_bridge->timings->dual_link)
670 lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
671 else
672 lvds->link_type = RCAR_LVDS_SINGLE_LINK;
673 }
674
675 if (lvds->link_type == RCAR_LVDS_SINGLE_LINK) {
676 dev_dbg(dev, "Single-link configuration detected\n");
677 goto done;
678 }
679
680 lvds->companion = of_drm_find_bridge(companion);
681 if (!lvds->companion) {
682 ret = -EPROBE_DEFER;
683 goto done;
684 }
685
686 dev_dbg(dev,
687 "Dual-link configuration detected (companion encoder %pOF)\n",
688 companion);
689
690 if (lvds->link_type == RCAR_LVDS_DUAL_LINK_ODD_EVEN_PIXELS)
691 dev_dbg(dev, "Data swapping required\n");
692
693
694
695
696
697
698
699
700
701
702 companion_lvds = bridge_to_rcar_lvds(lvds->companion);
703 companion_lvds->link_type = lvds->link_type;
704
705done:
706 of_node_put(companion);
707
708 return ret;
709}
710
711static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
712{
713 int ret;
714
715 ret = drm_of_find_panel_or_bridge(lvds->dev->of_node, 1, 0,
716 &lvds->panel, &lvds->next_bridge);
717 if (ret)
718 goto done;
719
720 if (lvds->panel) {
721 lvds->next_bridge = devm_drm_panel_bridge_add(lvds->dev,
722 lvds->panel);
723 if (IS_ERR_OR_NULL(lvds->next_bridge)) {
724 ret = -EINVAL;
725 goto done;
726 }
727 }
728
729 if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK)
730 ret = rcar_lvds_parse_dt_companion(lvds);
731
732done:
733
734
735
736
737
738
739 if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)
740 return ret == -ENODEV ? 0 : ret;
741
742 return ret;
743}
744
745static struct clk *rcar_lvds_get_clock(struct rcar_lvds *lvds, const char *name,
746 bool optional)
747{
748 struct clk *clk;
749
750 clk = devm_clk_get(lvds->dev, name);
751 if (!IS_ERR(clk))
752 return clk;
753
754 if (PTR_ERR(clk) == -ENOENT && optional)
755 return NULL;
756
757 dev_err_probe(lvds->dev, PTR_ERR(clk), "failed to get %s clock\n",
758 name ? name : "module");
759
760 return clk;
761}
762
763static int rcar_lvds_get_clocks(struct rcar_lvds *lvds)
764{
765 lvds->clocks.mod = rcar_lvds_get_clock(lvds, NULL, false);
766 if (IS_ERR(lvds->clocks.mod))
767 return PTR_ERR(lvds->clocks.mod);
768
769
770
771
772 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))
773 return 0;
774
775 lvds->clocks.extal = rcar_lvds_get_clock(lvds, "extal", true);
776 if (IS_ERR(lvds->clocks.extal))
777 return PTR_ERR(lvds->clocks.extal);
778
779 lvds->clocks.dotclkin[0] = rcar_lvds_get_clock(lvds, "dclkin.0", true);
780 if (IS_ERR(lvds->clocks.dotclkin[0]))
781 return PTR_ERR(lvds->clocks.dotclkin[0]);
782
783 lvds->clocks.dotclkin[1] = rcar_lvds_get_clock(lvds, "dclkin.1", true);
784 if (IS_ERR(lvds->clocks.dotclkin[1]))
785 return PTR_ERR(lvds->clocks.dotclkin[1]);
786
787
788 if (!lvds->clocks.extal && !lvds->clocks.dotclkin[0] &&
789 !lvds->clocks.dotclkin[1]) {
790 dev_err(lvds->dev,
791 "no input clock (extal, dclkin.0 or dclkin.1)\n");
792 return -EINVAL;
793 }
794
795 return 0;
796}
797
798static const struct rcar_lvds_device_info rcar_lvds_r8a7790es1_info = {
799 .gen = 2,
800 .quirks = RCAR_LVDS_QUIRK_LANES,
801 .pll_setup = rcar_lvds_pll_setup_gen2,
802};
803
804static const struct soc_device_attribute lvds_quirk_matches[] = {
805 {
806 .soc_id = "r8a7790", .revision = "ES1.*",
807 .data = &rcar_lvds_r8a7790es1_info,
808 },
809 { }
810};
811
812static int rcar_lvds_probe(struct platform_device *pdev)
813{
814 const struct soc_device_attribute *attr;
815 struct rcar_lvds *lvds;
816 int ret;
817
818 lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
819 if (lvds == NULL)
820 return -ENOMEM;
821
822 platform_set_drvdata(pdev, lvds);
823
824 lvds->dev = &pdev->dev;
825 lvds->info = of_device_get_match_data(&pdev->dev);
826
827 attr = soc_device_match(lvds_quirk_matches);
828 if (attr)
829 lvds->info = attr->data;
830
831 ret = rcar_lvds_parse_dt(lvds);
832 if (ret < 0)
833 return ret;
834
835 lvds->bridge.funcs = &rcar_lvds_bridge_ops;
836 lvds->bridge.of_node = pdev->dev.of_node;
837
838 lvds->mmio = devm_platform_ioremap_resource(pdev, 0);
839 if (IS_ERR(lvds->mmio))
840 return PTR_ERR(lvds->mmio);
841
842 ret = rcar_lvds_get_clocks(lvds);
843 if (ret < 0)
844 return ret;
845
846 drm_bridge_add(&lvds->bridge);
847
848 return 0;
849}
850
851static int rcar_lvds_remove(struct platform_device *pdev)
852{
853 struct rcar_lvds *lvds = platform_get_drvdata(pdev);
854
855 drm_bridge_remove(&lvds->bridge);
856
857 return 0;
858}
859
860static const struct rcar_lvds_device_info rcar_lvds_gen2_info = {
861 .gen = 2,
862 .pll_setup = rcar_lvds_pll_setup_gen2,
863};
864
865static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
866 .gen = 3,
867 .quirks = RCAR_LVDS_QUIRK_PWD,
868 .pll_setup = rcar_lvds_pll_setup_gen3,
869};
870
871static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = {
872 .gen = 3,
873 .quirks = RCAR_LVDS_QUIRK_PWD | RCAR_LVDS_QUIRK_GEN3_LVEN,
874 .pll_setup = rcar_lvds_pll_setup_gen2,
875};
876
877static const struct rcar_lvds_device_info rcar_lvds_r8a77990_info = {
878 .gen = 3,
879 .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_EXT_PLL
880 | RCAR_LVDS_QUIRK_DUAL_LINK,
881 .pll_setup = rcar_lvds_pll_setup_d3_e3,
882};
883
884static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = {
885 .gen = 3,
886 .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_PWD
887 | RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK,
888 .pll_setup = rcar_lvds_pll_setup_d3_e3,
889};
890
891static const struct of_device_id rcar_lvds_of_table[] = {
892 { .compatible = "renesas,r8a7742-lvds", .data = &rcar_lvds_gen2_info },
893 { .compatible = "renesas,r8a7743-lvds", .data = &rcar_lvds_gen2_info },
894 { .compatible = "renesas,r8a7744-lvds", .data = &rcar_lvds_gen2_info },
895 { .compatible = "renesas,r8a774a1-lvds", .data = &rcar_lvds_gen3_info },
896 { .compatible = "renesas,r8a774b1-lvds", .data = &rcar_lvds_gen3_info },
897 { .compatible = "renesas,r8a774c0-lvds", .data = &rcar_lvds_r8a77990_info },
898 { .compatible = "renesas,r8a774e1-lvds", .data = &rcar_lvds_gen3_info },
899 { .compatible = "renesas,r8a7790-lvds", .data = &rcar_lvds_gen2_info },
900 { .compatible = "renesas,r8a7791-lvds", .data = &rcar_lvds_gen2_info },
901 { .compatible = "renesas,r8a7793-lvds", .data = &rcar_lvds_gen2_info },
902 { .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info },
903 { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
904 { .compatible = "renesas,r8a77961-lvds", .data = &rcar_lvds_gen3_info },
905 { .compatible = "renesas,r8a77965-lvds", .data = &rcar_lvds_gen3_info },
906 { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
907 { .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info },
908 { .compatible = "renesas,r8a77990-lvds", .data = &rcar_lvds_r8a77990_info },
909 { .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_r8a77995_info },
910 { }
911};
912
913MODULE_DEVICE_TABLE(of, rcar_lvds_of_table);
914
915static struct platform_driver rcar_lvds_platform_driver = {
916 .probe = rcar_lvds_probe,
917 .remove = rcar_lvds_remove,
918 .driver = {
919 .name = "rcar-lvds",
920 .of_match_table = rcar_lvds_of_table,
921 },
922};
923
924module_platform_driver(rcar_lvds_platform_driver);
925
926MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
927MODULE_DESCRIPTION("Renesas R-Car LVDS Encoder Driver");
928MODULE_LICENSE("GPL");
929