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