aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-09-26 20:54:54 -0400
committerDave Airlie <airlied@redhat.com>2018-09-26 20:56:11 -0400
commit2e240beefe48f011f8aaaeaae27536c0d6baa177 (patch)
tree342364c18872fe0d8a781dcf58d049504ec05af1
parent36c9c3c91128e2b892c9be0dd9ee9bd82cbe82ad (diff)
parent122702077e4492e02de8a6257e6cb2227c617cf0 (diff)
Merge tag 'du-next-20180925' of git://linuxtv.org/pinchartl/media into drm-next
R-Car DU support for the D3 and E3 SoCs (v4.20) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Link: https://patchwork.freedesktop.org/patch/msgid/3289904.RCOHkcp7u8@avalon
-rw-r--r--Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt13
-rw-r--r--Documentation/devicetree/bindings/display/renesas,du.txt2
-rw-r--r--drivers/gpu/drm/bridge/thc63lvd1024.c18
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c136
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h5
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c63
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h3
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c88
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c12
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds.c359
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_lvds_regs.h43
11 files changed, 595 insertions, 147 deletions
diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
index 5a4e379bb414..3aeb0ec06fd0 100644
--- a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
+++ b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt
@@ -15,10 +15,21 @@ Required properties:
15 - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders 15 - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders
16 - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders 16 - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders
17 - "renesas,r8a77980-lvds" for R8A77980 (R-Car V3H) compatible LVDS encoders 17 - "renesas,r8a77980-lvds" for R8A77980 (R-Car V3H) compatible LVDS encoders
18 - "renesas,r8a77990-lvds" for R8A77990 (R-Car E3) compatible LVDS encoders
18 - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders 19 - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders
19 20
20- reg: Base address and length for the memory-mapped registers 21- reg: Base address and length for the memory-mapped registers
21- clocks: A phandle + clock-specifier pair for the functional clock 22- clocks: A list of phandles + clock-specifier pairs, one for each entry in
23 the clock-names property.
24- clock-names: Name of the clocks. This property is model-dependent.
25 - The functional clock, which mandatory for all models, shall be listed
26 first, and shall be named "fck".
27 - On R8A77990 and R8A77995, the LVDS encoder can use the EXTAL or
28 DU_DOTCLKINx clocks. Those clocks are optional. When supplied they must be
29 named "extal" and "dclkin.x" respectively, with "x" being the DU_DOTCLKIN
30 numerical index.
31 - When the clocks property only contains the functional clock, the
32 clock-names property may be omitted.
22- resets: A phandle + reset specifier for the module reset 33- resets: A phandle + reset specifier for the module reset
23 34
24Required nodes: 35Required nodes:
diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt
index caae2348a292..9de67be632d1 100644
--- a/Documentation/devicetree/bindings/display/renesas,du.txt
+++ b/Documentation/devicetree/bindings/display/renesas,du.txt
@@ -16,6 +16,7 @@ Required Properties:
16 - "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU 16 - "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU
17 - "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU 17 - "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU
18 - "renesas,du-r8a77980" for R8A77980 (R-Car V3H) compatible DU 18 - "renesas,du-r8a77980" for R8A77980 (R-Car V3H) compatible DU
19 - "renesas,du-r8a77990" for R8A77990 (R-Car E3) compatible DU
19 - "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU 20 - "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU
20 21
21 - reg: the memory-mapped I/O registers base address and length 22 - reg: the memory-mapped I/O registers base address and length
@@ -63,6 +64,7 @@ corresponding to each DU output.
63 R8A77965 (R-Car M3-N) DPAD 0 HDMI 0 LVDS 0 - 64 R8A77965 (R-Car M3-N) DPAD 0 HDMI 0 LVDS 0 -
64 R8A77970 (R-Car V3M) DPAD 0 LVDS 0 - - 65 R8A77970 (R-Car V3M) DPAD 0 LVDS 0 - -
65 R8A77980 (R-Car V3H) DPAD 0 LVDS 0 - - 66 R8A77980 (R-Car V3H) DPAD 0 LVDS 0 - -
67 R8A77990 (R-Car E3) DPAD 0 LVDS 0 LVDS 1 -
66 R8A77995 (R-Car D3) DPAD 0 LVDS 0 LVDS 1 - 68 R8A77995 (R-Car D3) DPAD 0 LVDS 0 LVDS 1 -
67 69
68 70
diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c
index c8b9edd5a7f4..b083a740565c 100644
--- a/drivers/gpu/drm/bridge/thc63lvd1024.c
+++ b/drivers/gpu/drm/bridge/thc63lvd1024.c
@@ -45,6 +45,23 @@ static int thc63_attach(struct drm_bridge *bridge)
45 return drm_bridge_attach(bridge->encoder, thc63->next, bridge); 45 return drm_bridge_attach(bridge->encoder, thc63->next, bridge);
46} 46}
47 47
48static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
49 const struct drm_display_mode *mode)
50{
51 /*
52 * The THC63LVD1024 clock frequency range is 8 to 135 MHz in single-in
53 * mode. Note that the limits are different in dual-in, single-out mode,
54 * and will need to be adjusted accordingly.
55 */
56 if (mode->clock < 8000)
57 return MODE_CLOCK_LOW;
58
59 if (mode->clock > 135000)
60 return MODE_CLOCK_HIGH;
61
62 return MODE_OK;
63}
64
48static void thc63_enable(struct drm_bridge *bridge) 65static void thc63_enable(struct drm_bridge *bridge)
49{ 66{
50 struct thc63_dev *thc63 = to_thc63(bridge); 67 struct thc63_dev *thc63 = to_thc63(bridge);
@@ -77,6 +94,7 @@ static void thc63_disable(struct drm_bridge *bridge)
77 94
78static const struct drm_bridge_funcs thc63_bridge_func = { 95static const struct drm_bridge_funcs thc63_bridge_func = {
79 .attach = thc63_attach, 96 .attach = thc63_attach,
97 .mode_valid = thc63_mode_valid,
80 .enable = thc63_enable, 98 .enable = thc63_enable,
81 .disable = thc63_disable, 99 .disable = thc63_disable,
82}; 100};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 6288b9ad9e24..17741843cf51 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -57,46 +57,12 @@ static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set)
57 rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set); 57 rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set);
58} 58}
59 59
60static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg, 60void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set)
61 u32 clr, u32 set)
62{ 61{
63 struct rcar_du_device *rcdu = rcrtc->group->dev; 62 struct rcar_du_device *rcdu = rcrtc->group->dev;
64 u32 value = rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
65 63
66 rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set); 64 rcrtc->dsysr = (rcrtc->dsysr & ~clr) | set;
67} 65 rcar_du_write(rcdu, rcrtc->mmio_offset + DSYSR, rcrtc->dsysr);
68
69static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
70{
71 int ret;
72
73 ret = clk_prepare_enable(rcrtc->clock);
74 if (ret < 0)
75 return ret;
76
77 ret = clk_prepare_enable(rcrtc->extclock);
78 if (ret < 0)
79 goto error_clock;
80
81 ret = rcar_du_group_get(rcrtc->group);
82 if (ret < 0)
83 goto error_group;
84
85 return 0;
86
87error_group:
88 clk_disable_unprepare(rcrtc->extclock);
89error_clock:
90 clk_disable_unprepare(rcrtc->clock);
91 return ret;
92}
93
94static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
95{
96 rcar_du_group_put(rcrtc->group);
97
98 clk_disable_unprepare(rcrtc->extclock);
99 clk_disable_unprepare(rcrtc->clock);
100} 66}
101 67
102/* ----------------------------------------------------------------------------- 68/* -----------------------------------------------------------------------------
@@ -294,6 +260,14 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
294 rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr); 260 rcar_du_group_write(rcrtc->group, DPLLCR, dpllcr);
295 261
296 escr = ESCR_DCLKSEL_DCLKIN | div; 262 escr = ESCR_DCLKSEL_DCLKIN | div;
263 } else if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) {
264 /*
265 * Use the LVDS PLL output as the dot clock when outputting to
266 * the LVDS encoder on an SoC that supports this clock routing
267 * option. We use the clock directly in that case, without any
268 * additional divider.
269 */
270 escr = ESCR_DCLKSEL_DCLKIN;
297 } else { 271 } else {
298 struct du_clk_params params = { .diff = (unsigned long)-1 }; 272 struct du_clk_params params = { .diff = (unsigned long)-1 };
299 273
@@ -546,6 +520,51 @@ static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
546 drm_crtc_vblank_on(&rcrtc->crtc); 520 drm_crtc_vblank_on(&rcrtc->crtc);
547} 521}
548 522
523static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
524{
525 int ret;
526
527 /*
528 * Guard against double-get, as the function is called from both the
529 * .atomic_enable() and .atomic_begin() handlers.
530 */
531 if (rcrtc->initialized)
532 return 0;
533
534 ret = clk_prepare_enable(rcrtc->clock);
535 if (ret < 0)
536 return ret;
537
538 ret = clk_prepare_enable(rcrtc->extclock);
539 if (ret < 0)
540 goto error_clock;
541
542 ret = rcar_du_group_get(rcrtc->group);
543 if (ret < 0)
544 goto error_group;
545
546 rcar_du_crtc_setup(rcrtc);
547 rcrtc->initialized = true;
548
549 return 0;
550
551error_group:
552 clk_disable_unprepare(rcrtc->extclock);
553error_clock:
554 clk_disable_unprepare(rcrtc->clock);
555 return ret;
556}
557
558static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
559{
560 rcar_du_group_put(rcrtc->group);
561
562 clk_disable_unprepare(rcrtc->extclock);
563 clk_disable_unprepare(rcrtc->clock);
564
565 rcrtc->initialized = false;
566}
567
549static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) 568static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
550{ 569{
551 bool interlaced; 570 bool interlaced;
@@ -556,9 +575,9 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
556 * actively driven). 575 * actively driven).
557 */ 576 */
558 interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE; 577 interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
559 rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK, 578 rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
560 (interlaced ? DSYSR_SCM_INT_VIDEO : 0) | 579 (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
561 DSYSR_TVM_MASTER); 580 DSYSR_TVM_MASTER);
562 581
563 rcar_du_group_start_stop(rcrtc->group, true); 582 rcar_du_group_start_stop(rcrtc->group, true);
564} 583}
@@ -624,8 +643,13 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
624 /* 643 /*
625 * Select switch sync mode. This stops display operation and configures 644 * Select switch sync mode. This stops display operation and configures
626 * the HSYNC and VSYNC signals as inputs. 645 * the HSYNC and VSYNC signals as inputs.
646 *
647 * TODO: Find another way to stop the display for DUs that don't support
648 * TVM sync.
627 */ 649 */
628 rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH); 650 if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_TVM_SYNC))
651 rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK,
652 DSYSR_TVM_SWITCH);
629 653
630 rcar_du_group_start_stop(rcrtc->group, false); 654 rcar_du_group_start_stop(rcrtc->group, false);
631} 655}
@@ -639,16 +663,7 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
639{ 663{
640 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); 664 struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
641 665
642 /* 666 rcar_du_crtc_get(rcrtc);
643 * If the CRTC has already been setup by the .atomic_begin() handler we
644 * can skip the setup stage.
645 */
646 if (!rcrtc->initialized) {
647 rcar_du_crtc_get(rcrtc);
648 rcar_du_crtc_setup(rcrtc);
649 rcrtc->initialized = true;
650 }
651
652 rcar_du_crtc_start(rcrtc); 667 rcar_du_crtc_start(rcrtc);
653} 668}
654 669
@@ -667,7 +682,6 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc,
667 } 682 }
668 spin_unlock_irq(&crtc->dev->event_lock); 683 spin_unlock_irq(&crtc->dev->event_lock);
669 684
670 rcrtc->initialized = false;
671 rcrtc->outputs = 0; 685 rcrtc->outputs = 0;
672} 686}
673 687
@@ -680,14 +694,17 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
680 694
681 /* 695 /*
682 * If a mode set is in progress we can be called with the CRTC disabled. 696 * If a mode set is in progress we can be called with the CRTC disabled.
683 * We then need to first setup the CRTC in order to configure planes. 697 * We thus need to first get and setup the CRTC in order to configure
684 * The .atomic_enable() handler will notice and skip the CRTC setup. 698 * planes. We must *not* put the CRTC in .atomic_flush(), as it must be
699 * kept awake until the .atomic_enable() call that will follow. The get
700 * operation in .atomic_enable() will in that case be a no-op, and the
701 * CRTC will be put later in .atomic_disable().
702 *
703 * If a mode set is not in progress the CRTC is enabled, and the
704 * following get call will be a no-op. There is thus no need to belance
705 * it in .atomic_flush() either.
685 */ 706 */
686 if (!rcrtc->initialized) { 707 rcar_du_crtc_get(rcrtc);
687 rcar_du_crtc_get(rcrtc);
688 rcar_du_crtc_setup(rcrtc);
689 rcrtc->initialized = true;
690 }
691 708
692 if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) 709 if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
693 rcar_du_vsp_atomic_begin(rcrtc); 710 rcar_du_vsp_atomic_begin(rcrtc);
@@ -1108,6 +1125,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex,
1108 rcrtc->group = rgrp; 1125 rcrtc->group = rgrp;
1109 rcrtc->mmio_offset = mmio_offsets[hwindex]; 1126 rcrtc->mmio_offset = mmio_offsets[hwindex];
1110 rcrtc->index = hwindex; 1127 rcrtc->index = hwindex;
1128 rcrtc->dsysr = (rcrtc->index % 2 ? 0 : DSYSR_DRES) | DSYSR_TVM_TVSYNC;
1111 1129
1112 if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) 1130 if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
1113 primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe].plane; 1131 primary = &rcrtc->vsp->planes[rcrtc->vsp_pipe].plane;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 4990bbe9ba26..59ac6e7d22c9 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -30,6 +30,7 @@ struct rcar_du_vsp;
30 * @mmio_offset: offset of the CRTC registers in the DU MMIO block 30 * @mmio_offset: offset of the CRTC registers in the DU MMIO block
31 * @index: CRTC software and hardware index 31 * @index: CRTC software and hardware index
32 * @initialized: whether the CRTC has been initialized and clocks enabled 32 * @initialized: whether the CRTC has been initialized and clocks enabled
33 * @dsysr: cached value of the DSYSR register
33 * @vblank_enable: whether vblank events are enabled on this CRTC 34 * @vblank_enable: whether vblank events are enabled on this CRTC
34 * @event: event to post when the pending page flip completes 35 * @event: event to post when the pending page flip completes
35 * @flip_wait: wait queue used to signal page flip completion 36 * @flip_wait: wait queue used to signal page flip completion
@@ -50,6 +51,8 @@ struct rcar_du_crtc {
50 unsigned int index; 51 unsigned int index;
51 bool initialized; 52 bool initialized;
52 53
54 u32 dsysr;
55
53 bool vblank_enable; 56 bool vblank_enable;
54 struct drm_pending_vblank_event *event; 57 struct drm_pending_vblank_event *event;
55 wait_queue_head_t flip_wait; 58 wait_queue_head_t flip_wait;
@@ -103,4 +106,6 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
103 enum rcar_du_output output); 106 enum rcar_du_output output);
104void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc); 107void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc);
105 108
109void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set);
110
106#endif /* __RCAR_DU_CRTC_H__ */ 111#endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 0954ecd2f943..084f58df4a8c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -36,7 +36,8 @@ static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
36 .gen = 2, 36 .gen = 2,
37 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 37 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
38 | RCAR_DU_FEATURE_EXT_CTRL_REGS 38 | RCAR_DU_FEATURE_EXT_CTRL_REGS
39 | RCAR_DU_FEATURE_INTERLACED, 39 | RCAR_DU_FEATURE_INTERLACED
40 | RCAR_DU_FEATURE_TVM_SYNC,
40 .channels_mask = BIT(1) | BIT(0), 41 .channels_mask = BIT(1) | BIT(0),
41 .routes = { 42 .routes = {
42 /* 43 /*
@@ -58,7 +59,8 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
58 .gen = 2, 59 .gen = 2,
59 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 60 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
60 | RCAR_DU_FEATURE_EXT_CTRL_REGS 61 | RCAR_DU_FEATURE_EXT_CTRL_REGS
61 | RCAR_DU_FEATURE_INTERLACED, 62 | RCAR_DU_FEATURE_INTERLACED
63 | RCAR_DU_FEATURE_TVM_SYNC,
62 .channels_mask = BIT(1) | BIT(0), 64 .channels_mask = BIT(1) | BIT(0),
63 .routes = { 65 .routes = {
64 /* 66 /*
@@ -77,7 +79,8 @@ static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
77 79
78static const struct rcar_du_device_info rcar_du_r8a7779_info = { 80static const struct rcar_du_device_info rcar_du_r8a7779_info = {
79 .gen = 2, 81 .gen = 2,
80 .features = RCAR_DU_FEATURE_INTERLACED, 82 .features = RCAR_DU_FEATURE_INTERLACED
83 | RCAR_DU_FEATURE_TVM_SYNC,
81 .channels_mask = BIT(1) | BIT(0), 84 .channels_mask = BIT(1) | BIT(0),
82 .routes = { 85 .routes = {
83 /* 86 /*
@@ -99,7 +102,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
99 .gen = 2, 102 .gen = 2,
100 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 103 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
101 | RCAR_DU_FEATURE_EXT_CTRL_REGS 104 | RCAR_DU_FEATURE_EXT_CTRL_REGS
102 | RCAR_DU_FEATURE_INTERLACED, 105 | RCAR_DU_FEATURE_INTERLACED
106 | RCAR_DU_FEATURE_TVM_SYNC,
103 .quirks = RCAR_DU_QUIRK_ALIGN_128B, 107 .quirks = RCAR_DU_QUIRK_ALIGN_128B,
104 .channels_mask = BIT(2) | BIT(1) | BIT(0), 108 .channels_mask = BIT(2) | BIT(1) | BIT(0),
105 .routes = { 109 .routes = {
@@ -128,7 +132,8 @@ static const struct rcar_du_device_info rcar_du_r8a7791_info = {
128 .gen = 2, 132 .gen = 2,
129 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 133 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
130 | RCAR_DU_FEATURE_EXT_CTRL_REGS 134 | RCAR_DU_FEATURE_EXT_CTRL_REGS
131 | RCAR_DU_FEATURE_INTERLACED, 135 | RCAR_DU_FEATURE_INTERLACED
136 | RCAR_DU_FEATURE_TVM_SYNC,
132 .channels_mask = BIT(1) | BIT(0), 137 .channels_mask = BIT(1) | BIT(0),
133 .routes = { 138 .routes = {
134 /* 139 /*
@@ -151,7 +156,8 @@ static const struct rcar_du_device_info rcar_du_r8a7792_info = {
151 .gen = 2, 156 .gen = 2,
152 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 157 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
153 | RCAR_DU_FEATURE_EXT_CTRL_REGS 158 | RCAR_DU_FEATURE_EXT_CTRL_REGS
154 | RCAR_DU_FEATURE_INTERLACED, 159 | RCAR_DU_FEATURE_INTERLACED
160 | RCAR_DU_FEATURE_TVM_SYNC,
155 .channels_mask = BIT(1) | BIT(0), 161 .channels_mask = BIT(1) | BIT(0),
156 .routes = { 162 .routes = {
157 /* R8A7792 has two RGB outputs. */ 163 /* R8A7792 has two RGB outputs. */
@@ -170,7 +176,8 @@ static const struct rcar_du_device_info rcar_du_r8a7794_info = {
170 .gen = 2, 176 .gen = 2,
171 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 177 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
172 | RCAR_DU_FEATURE_EXT_CTRL_REGS 178 | RCAR_DU_FEATURE_EXT_CTRL_REGS
173 | RCAR_DU_FEATURE_INTERLACED, 179 | RCAR_DU_FEATURE_INTERLACED
180 | RCAR_DU_FEATURE_TVM_SYNC,
174 .channels_mask = BIT(1) | BIT(0), 181 .channels_mask = BIT(1) | BIT(0),
175 .routes = { 182 .routes = {
176 /* 183 /*
@@ -193,7 +200,8 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
193 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 200 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
194 | RCAR_DU_FEATURE_EXT_CTRL_REGS 201 | RCAR_DU_FEATURE_EXT_CTRL_REGS
195 | RCAR_DU_FEATURE_VSP1_SOURCE 202 | RCAR_DU_FEATURE_VSP1_SOURCE
196 | RCAR_DU_FEATURE_INTERLACED, 203 | RCAR_DU_FEATURE_INTERLACED
204 | RCAR_DU_FEATURE_TVM_SYNC,
197 .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), 205 .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
198 .routes = { 206 .routes = {
199 /* 207 /*
@@ -226,7 +234,8 @@ static const struct rcar_du_device_info rcar_du_r8a7796_info = {
226 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 234 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
227 | RCAR_DU_FEATURE_EXT_CTRL_REGS 235 | RCAR_DU_FEATURE_EXT_CTRL_REGS
228 | RCAR_DU_FEATURE_VSP1_SOURCE 236 | RCAR_DU_FEATURE_VSP1_SOURCE
229 | RCAR_DU_FEATURE_INTERLACED, 237 | RCAR_DU_FEATURE_INTERLACED
238 | RCAR_DU_FEATURE_TVM_SYNC,
230 .channels_mask = BIT(2) | BIT(1) | BIT(0), 239 .channels_mask = BIT(2) | BIT(1) | BIT(0),
231 .routes = { 240 .routes = {
232 /* 241 /*
@@ -255,7 +264,8 @@ static const struct rcar_du_device_info rcar_du_r8a77965_info = {
255 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 264 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
256 | RCAR_DU_FEATURE_EXT_CTRL_REGS 265 | RCAR_DU_FEATURE_EXT_CTRL_REGS
257 | RCAR_DU_FEATURE_VSP1_SOURCE 266 | RCAR_DU_FEATURE_VSP1_SOURCE
258 | RCAR_DU_FEATURE_INTERLACED, 267 | RCAR_DU_FEATURE_INTERLACED
268 | RCAR_DU_FEATURE_TVM_SYNC,
259 .channels_mask = BIT(3) | BIT(1) | BIT(0), 269 .channels_mask = BIT(3) | BIT(1) | BIT(0),
260 .routes = { 270 .routes = {
261 /* 271 /*
@@ -284,7 +294,8 @@ static const struct rcar_du_device_info rcar_du_r8a77970_info = {
284 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK 294 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
285 | RCAR_DU_FEATURE_EXT_CTRL_REGS 295 | RCAR_DU_FEATURE_EXT_CTRL_REGS
286 | RCAR_DU_FEATURE_VSP1_SOURCE 296 | RCAR_DU_FEATURE_VSP1_SOURCE
287 | RCAR_DU_FEATURE_INTERLACED, 297 | RCAR_DU_FEATURE_INTERLACED
298 | RCAR_DU_FEATURE_TVM_SYNC,
288 .channels_mask = BIT(0), 299 .channels_mask = BIT(0),
289 .routes = { 300 .routes = {
290 /* R8A77970 has one RGB output and one LVDS output. */ 301 /* R8A77970 has one RGB output and one LVDS output. */
@@ -300,6 +311,34 @@ static const struct rcar_du_device_info rcar_du_r8a77970_info = {
300 .num_lvds = 1, 311 .num_lvds = 1,
301}; 312};
302 313
314static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
315 .gen = 3,
316 .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
317 | RCAR_DU_FEATURE_EXT_CTRL_REGS
318 | RCAR_DU_FEATURE_VSP1_SOURCE,
319 .channels_mask = BIT(1) | BIT(0),
320 .routes = {
321 /*
322 * R8A77990 and R8A77995 have one RGB output and two LVDS
323 * outputs.
324 */
325 [RCAR_DU_OUTPUT_DPAD0] = {
326 .possible_crtcs = BIT(0) | BIT(1),
327 .port = 0,
328 },
329 [RCAR_DU_OUTPUT_LVDS0] = {
330 .possible_crtcs = BIT(0),
331 .port = 1,
332 },
333 [RCAR_DU_OUTPUT_LVDS1] = {
334 .possible_crtcs = BIT(1),
335 .port = 2,
336 },
337 },
338 .num_lvds = 2,
339 .lvds_clk_mask = BIT(1) | BIT(0),
340};
341
303static const struct of_device_id rcar_du_of_table[] = { 342static const struct of_device_id rcar_du_of_table[] = {
304 { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info }, 343 { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
305 { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info }, 344 { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
@@ -313,6 +352,8 @@ static const struct of_device_id rcar_du_of_table[] = {
313 { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info }, 352 { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
314 { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info }, 353 { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
315 { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info }, 354 { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
355 { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
356 { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
316 { } 357 { }
317}; 358};
318 359
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index fef9ea5c22f3..143c037e2c0f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -27,6 +27,7 @@ struct rcar_du_device;
27#define RCAR_DU_FEATURE_EXT_CTRL_REGS BIT(1) /* Has extended control registers */ 27#define RCAR_DU_FEATURE_EXT_CTRL_REGS BIT(1) /* Has extended control registers */
28#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(2) /* Has inputs from VSP1 */ 28#define RCAR_DU_FEATURE_VSP1_SOURCE BIT(2) /* Has inputs from VSP1 */
29#define RCAR_DU_FEATURE_INTERLACED BIT(3) /* HW supports interlaced */ 29#define RCAR_DU_FEATURE_INTERLACED BIT(3) /* HW supports interlaced */
30#define RCAR_DU_FEATURE_TVM_SYNC BIT(4) /* Has TV switch/sync modes */
30 31
31#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */ 32#define RCAR_DU_QUIRK_ALIGN_128B BIT(0) /* Align pitches to 128 bytes */
32 33
@@ -53,6 +54,7 @@ struct rcar_du_output_routing {
53 * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) 54 * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*)
54 * @num_lvds: number of internal LVDS encoders 55 * @num_lvds: number of internal LVDS encoders
55 * @dpll_mask: bit mask of DU channels equipped with a DPLL 56 * @dpll_mask: bit mask of DU channels equipped with a DPLL
57 * @lvds_clk_mask: bitmask of channels that can use the LVDS clock as dot clock
56 */ 58 */
57struct rcar_du_device_info { 59struct rcar_du_device_info {
58 unsigned int gen; 60 unsigned int gen;
@@ -62,6 +64,7 @@ struct rcar_du_device_info {
62 struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; 64 struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
63 unsigned int num_lvds; 65 unsigned int num_lvds;
64 unsigned int dpll_mask; 66 unsigned int dpll_mask;
67 unsigned int lvds_clk_mask;
65}; 68};
66 69
67#define RCAR_DU_MAX_CRTCS 4 70#define RCAR_DU_MAX_CRTCS 4
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index ef2c177afb6d..d85f0a1c1581 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -56,8 +56,6 @@ static void rcar_du_group_setup_pins(struct rcar_du_group *rgrp)
56static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp) 56static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
57{ 57{
58 struct rcar_du_device *rcdu = rgrp->dev; 58 struct rcar_du_device *rcdu = rgrp->dev;
59 unsigned int possible_crtcs =
60 rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs;
61 u32 defr8 = DEFR8_CODE; 59 u32 defr8 = DEFR8_CODE;
62 60
63 if (rcdu->info->gen < 3) { 61 if (rcdu->info->gen < 3) {
@@ -69,26 +67,71 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
69 * DU instances that support it. 67 * DU instances that support it.
70 */ 68 */
71 if (rgrp->index == 0) { 69 if (rgrp->index == 0) {
72 if (possible_crtcs > 1) 70 defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
73 defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
74 if (rgrp->dev->vspd1_sink == 2) 71 if (rgrp->dev->vspd1_sink == 2)
75 defr8 |= DEFR8_VSCS; 72 defr8 |= DEFR8_VSCS;
76 } 73 }
77 } else { 74 } else {
78 /* 75 /*
79 * On Gen3 VSPD routing can't be configured, but DPAD routing 76 * On Gen3 VSPD routing can't be configured, and DPAD routing
80 * needs to be set despite having a single option available. 77 * is set in the group corresponding to the DPAD output (no Gen3
78 * SoC has multiple DPAD sources belonging to separate groups).
81 */ 79 */
82 unsigned int rgb_crtc = ffs(possible_crtcs) - 1; 80 if (rgrp->index == rcdu->dpad0_source / 2)
83 struct rcar_du_crtc *crtc = &rcdu->crtcs[rgb_crtc]; 81 defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
84
85 if (crtc->index / 2 == rgrp->index)
86 defr8 |= DEFR8_DRGBS_DU(crtc->index);
87 } 82 }
88 83
89 rcar_du_group_write(rgrp, DEFR8, defr8); 84 rcar_du_group_write(rgrp, DEFR8, defr8);
90} 85}
91 86
87static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp)
88{
89 struct rcar_du_device *rcdu = rgrp->dev;
90 struct rcar_du_crtc *rcrtc;
91 unsigned int num_crtcs = 0;
92 unsigned int i;
93 u32 didsr;
94
95 /*
96 * Configure input dot clock routing with a hardcoded configuration. If
97 * the DU channel can use the LVDS encoder output clock as the dot
98 * clock, do so. Otherwise route DU_DOTCLKINn signal to DUn.
99 *
100 * Each channel can then select between the dot clock configured here
101 * and the clock provided by the CPG through the ESCR register.
102 */
103 if (rcdu->info->gen < 3 && rgrp->index == 0) {
104 /*
105 * On Gen2 a single register in the first group controls dot
106 * clock selection for all channels.
107 */
108 rcrtc = rcdu->crtcs;
109 num_crtcs = rcdu->num_crtcs;
110 } else if (rcdu->info->gen == 3 && rgrp->num_crtcs > 1) {
111 /*
112 * On Gen3 dot clocks are setup through per-group registers,
113 * only available when the group has two channels.
114 */
115 rcrtc = &rcdu->crtcs[rgrp->index * 2];
116 num_crtcs = rgrp->num_crtcs;
117 }
118
119 if (!num_crtcs)
120 return;
121
122 didsr = DIDSR_CODE;
123 for (i = 0; i < num_crtcs; ++i, ++rcrtc) {
124 if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index))
125 didsr |= DIDSR_LCDS_LVDS0(i)
126 | DIDSR_PDCS_CLK(i, 0);
127 else
128 didsr |= DIDSR_LCDS_DCLKIN(i)
129 | DIDSR_PDCS_CLK(i, 0);
130 }
131
132 rcar_du_group_write(rgrp, DIDSR, didsr);
133}
134
92static void rcar_du_group_setup(struct rcar_du_group *rgrp) 135static void rcar_du_group_setup(struct rcar_du_group *rgrp)
93{ 136{
94 struct rcar_du_device *rcdu = rgrp->dev; 137 struct rcar_du_device *rcdu = rgrp->dev;
@@ -106,21 +149,7 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
106 149
107 if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { 150 if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
108 rcar_du_group_setup_defr8(rgrp); 151 rcar_du_group_setup_defr8(rgrp);
109 152 rcar_du_group_setup_didsr(rgrp);
110 /*
111 * Configure input dot clock routing. We currently hardcode the
112 * configuration to routing DOTCLKINn to DUn. Register fields
113 * depend on the DU generation, but the resulting value is 0 in
114 * all cases.
115 *
116 * On Gen2 a single register in the first group controls dot
117 * clock selection for all channels, while on Gen3 dot clocks
118 * are setup through per-group registers, only available when
119 * the group has two channels.
120 */
121 if ((rcdu->info->gen < 3 && rgrp->index == 0) ||
122 (rcdu->info->gen == 3 && rgrp->num_crtcs > 1))
123 rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE);
124 } 153 }
125 154
126 if (rcdu->info->gen >= 3) 155 if (rcdu->info->gen >= 3)
@@ -173,9 +202,10 @@ void rcar_du_group_put(struct rcar_du_group *rgrp)
173 202
174static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) 203static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
175{ 204{
176 rcar_du_group_write(rgrp, DSYSR, 205 struct rcar_du_crtc *rcrtc = &rgrp->dev->crtcs[rgrp->index * 2];
177 (rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) | 206
178 (start ? DSYSR_DEN : DSYSR_DRES)); 207 rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_DRES | DSYSR_DEN,
208 start ? DSYSR_DEN : DSYSR_DRES);
179} 209}
180 210
181void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) 211void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index b5d79ecd25ea..4ebd61ecbee1 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -544,6 +544,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
544 struct drm_device *dev = rcdu->ddev; 544 struct drm_device *dev = rcdu->ddev;
545 struct drm_encoder *encoder; 545 struct drm_encoder *encoder;
546 struct drm_fbdev_cma *fbdev; 546 struct drm_fbdev_cma *fbdev;
547 unsigned int dpad0_sources;
547 unsigned int num_encoders; 548 unsigned int num_encoders;
548 unsigned int num_groups; 549 unsigned int num_groups;
549 unsigned int swindex; 550 unsigned int swindex;
@@ -666,6 +667,17 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
666 encoder->possible_clones = (1 << num_encoders) - 1; 667 encoder->possible_clones = (1 << num_encoders) - 1;
667 } 668 }
668 669
670 /*
671 * Initialize the default DPAD0 source to the index of the first DU
672 * channel that can be connected to DPAD0. The exact value doesn't
673 * matter as it should be overwritten by mode setting for the RGB
674 * output, but it is nonetheless required to ensure a valid initial
675 * hardware configuration on Gen3 where DU0 can't always be connected to
676 * DPAD0.
677 */
678 dpad0_sources = rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs;
679 rcdu->dpad0_source = ffs(dpad0_sources) - 1;
680
669 drm_mode_config_reset(dev); 681 drm_mode_config_reset(dev);
670 682
671 drm_kms_helper_poll_init(dev); 683 drm_kms_helper_poll_init(dev);
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index ce0eb68c3416..173d7ad0b991 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -24,6 +24,8 @@
24 24
25#include "rcar_lvds_regs.h" 25#include "rcar_lvds_regs.h"
26 26
27struct rcar_lvds;
28
27/* Keep in sync with the LVDCR0.LVMD hardware register values. */ 29/* Keep in sync with the LVDCR0.LVMD hardware register values. */
28enum rcar_lvds_mode { 30enum rcar_lvds_mode {
29 RCAR_LVDS_MODE_JEIDA = 0, 31 RCAR_LVDS_MODE_JEIDA = 0,
@@ -31,14 +33,16 @@ enum rcar_lvds_mode {
31 RCAR_LVDS_MODE_VESA = 4, 33 RCAR_LVDS_MODE_VESA = 4,
32}; 34};
33 35
34#define RCAR_LVDS_QUIRK_LANES (1 << 0) /* LVDS lanes 1 and 3 inverted */ 36#define RCAR_LVDS_QUIRK_LANES BIT(0) /* LVDS lanes 1 and 3 inverted */
35#define RCAR_LVDS_QUIRK_GEN2_PLLCR (1 << 1) /* LVDPLLCR has gen2 layout */ 37#define RCAR_LVDS_QUIRK_GEN3_LVEN BIT(1) /* LVEN bit needs to be set on R8A77970/R8A7799x */
36#define RCAR_LVDS_QUIRK_GEN3_LVEN (1 << 2) /* LVEN bit needs to be set */ 38#define RCAR_LVDS_QUIRK_PWD BIT(2) /* PWD bit available (all of Gen3 but E3) */
37 /* on R8A77970/R8A7799x */ 39#define RCAR_LVDS_QUIRK_EXT_PLL BIT(3) /* Has extended PLL */
40#define RCAR_LVDS_QUIRK_DUAL_LINK BIT(4) /* Supports dual-link operation */
38 41
39struct rcar_lvds_device_info { 42struct rcar_lvds_device_info {
40 unsigned int gen; 43 unsigned int gen;
41 unsigned int quirks; 44 unsigned int quirks;
45 void (*pll_setup)(struct rcar_lvds *lvds, unsigned int freq);
42}; 46};
43 47
44struct rcar_lvds { 48struct rcar_lvds {
@@ -52,7 +56,11 @@ struct rcar_lvds {
52 struct drm_panel *panel; 56 struct drm_panel *panel;
53 57
54 void __iomem *mmio; 58 void __iomem *mmio;
55 struct clk *clock; 59 struct {
60 struct clk *mod; /* CPG module clock */
61 struct clk *extal; /* External clock */
62 struct clk *dotclkin[2]; /* External DU clocks */
63 } clocks;
56 bool enabled; 64 bool enabled;
57 65
58 struct drm_display_mode display_mode; 66 struct drm_display_mode display_mode;
@@ -128,33 +136,216 @@ static const struct drm_connector_funcs rcar_lvds_conn_funcs = {
128}; 136};
129 137
130/* ----------------------------------------------------------------------------- 138/* -----------------------------------------------------------------------------
131 * Bridge 139 * PLL Setup
132 */ 140 */
133 141
134static u32 rcar_lvds_lvdpllcr_gen2(unsigned int freq) 142static void rcar_lvds_pll_setup_gen2(struct rcar_lvds *lvds, unsigned int freq)
135{ 143{
136 if (freq < 39000) 144 u32 val;
137 return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M; 145
138 else if (freq < 61000) 146 if (freq < 39000000)
139 return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M; 147 val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_38M;
140 else if (freq < 121000) 148 else if (freq < 61000000)
141 return LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M; 149 val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_60M;
150 else if (freq < 121000000)
151 val = LVDPLLCR_CEEN | LVDPLLCR_COSEL | LVDPLLCR_PLLDLYCNT_121M;
142 else 152 else
143 return LVDPLLCR_PLLDLYCNT_150M; 153 val = LVDPLLCR_PLLDLYCNT_150M;
154
155 rcar_lvds_write(lvds, LVDPLLCR, val);
144} 156}
145 157
146static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq) 158static void rcar_lvds_pll_setup_gen3(struct rcar_lvds *lvds, unsigned int freq)
147{ 159{
148 if (freq < 42000) 160 u32 val;
149 return LVDPLLCR_PLLDIVCNT_42M; 161
150 else if (freq < 85000) 162 if (freq < 42000000)
151 return LVDPLLCR_PLLDIVCNT_85M; 163 val = LVDPLLCR_PLLDIVCNT_42M;
152 else if (freq < 128000) 164 else if (freq < 85000000)
153 return LVDPLLCR_PLLDIVCNT_128M; 165 val = LVDPLLCR_PLLDIVCNT_85M;
166 else if (freq < 128000000)
167 val = LVDPLLCR_PLLDIVCNT_128M;
154 else 168 else
155 return LVDPLLCR_PLLDIVCNT_148M; 169 val = LVDPLLCR_PLLDIVCNT_148M;
170
171 rcar_lvds_write(lvds, LVDPLLCR, val);
156} 172}
157 173
174struct pll_info {
175 unsigned long diff;
176 unsigned int pll_m;
177 unsigned int pll_n;
178 unsigned int pll_e;
179 unsigned int div;
180 u32 clksel;
181};
182
183static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk,
184 unsigned long target, struct pll_info *pll,
185 u32 clksel)
186{
187 unsigned long output;
188 unsigned long fin;
189 unsigned int m_min;
190 unsigned int m_max;
191 unsigned int m;
192 int error;
193
194 if (!clk)
195 return;
196
197 /*
198 * The LVDS PLL is made of a pre-divider and a multiplier (strangely
199 * enough called M and N respectively), followed by a post-divider E.
200 *
201 * ,-----. ,-----. ,-----. ,-----.
202 * Fin --> | 1/M | -Fpdf-> | PFD | --> | VCO | -Fvco-> | 1/E | --> Fout
203 * `-----' ,-> | | `-----' | `-----'
204 * | `-----' |
205 * | ,-----. |
206 * `-------- | 1/N | <-------'
207 * `-----'
208 *
209 * The clock output by the PLL is then further divided by a programmable
210 * divider DIV to achieve the desired target frequency. Finally, an
211 * optional fixed /7 divider is used to convert the bit clock to a pixel
212 * clock (as LVDS transmits 7 bits per lane per clock sample).
213 *
214 * ,-------. ,-----. |\
215 * Fout --> | 1/DIV | --> | 1/7 | --> | |
216 * `-------' | `-----' | | --> dot clock
217 * `------------> | |
218 * |/
219 *
220 * The /7 divider is optional when the LVDS PLL is used to generate a
221 * dot clock for the DU RGB output, without using the LVDS encoder. We
222 * don't support this configuration yet.
223 *
224 * The PLL allowed input frequency range is 12 MHz to 192 MHz.
225 */
226
227 fin = clk_get_rate(clk);
228 if (fin < 12000000 || fin > 192000000)
229 return;
230
231 /*
232 * The comparison frequency range is 12 MHz to 24 MHz, which limits the
233 * allowed values for the pre-divider M (normal range 1-8).
234 *
235 * Fpfd = Fin / M
236 */
237 m_min = max_t(unsigned int, 1, DIV_ROUND_UP(fin, 24000000));
238 m_max = min_t(unsigned int, 8, fin / 12000000);
239
240 for (m = m_min; m <= m_max; ++m) {
241 unsigned long fpfd;
242 unsigned int n_min;
243 unsigned int n_max;
244 unsigned int n;
245
246 /*
247 * The VCO operating range is 900 Mhz to 1800 MHz, which limits
248 * the allowed values for the multiplier N (normal range
249 * 60-120).
250 *
251 * Fvco = Fin * N / M
252 */
253 fpfd = fin / m;
254 n_min = max_t(unsigned int, 60, DIV_ROUND_UP(900000000, fpfd));
255 n_max = min_t(unsigned int, 120, 1800000000 / fpfd);
256
257 for (n = n_min; n < n_max; ++n) {
258 unsigned long fvco;
259 unsigned int e_min;
260 unsigned int e;
261
262 /*
263 * The output frequency is limited to 1039.5 MHz,
264 * limiting again the allowed values for the
265 * post-divider E (normal value 1, 2 or 4).
266 *
267 * Fout = Fvco / E
268 */
269 fvco = fpfd * n;
270 e_min = fvco > 1039500000 ? 1 : 0;
271
272 for (e = e_min; e < 3; ++e) {
273 unsigned long fout;
274 unsigned long diff;
275 unsigned int div;
276
277 /*
278 * Finally we have a programable divider after
279 * the PLL, followed by a an optional fixed /7
280 * divider.
281 */
282 fout = fvco / (1 << e) / 7;
283 div = DIV_ROUND_CLOSEST(fout, target);
284 diff = abs(fout / div - target);
285
286 if (diff < pll->diff) {
287 pll->diff = diff;
288 pll->pll_m = m;
289 pll->pll_n = n;
290 pll->pll_e = e;
291 pll->div = div;
292 pll->clksel = clksel;
293
294 if (diff == 0)
295 goto done;
296 }
297 }
298 }
299 }
300
301done:
302 output = fin * pll->pll_n / pll->pll_m / (1 << pll->pll_e)
303 / 7 / pll->div;
304 error = (long)(output - target) * 10000 / (long)target;
305
306 dev_dbg(lvds->dev,
307 "%pC %lu Hz -> Fout %lu Hz (target %lu Hz, error %d.%02u%%), PLL M/N/E/DIV %u/%u/%u/%u\n",
308 clk, fin, output, target, error / 100,
309 error < 0 ? -error % 100 : error % 100,
310 pll->pll_m, pll->pll_n, pll->pll_e, pll->div);
311}
312
313static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq)
314{
315 struct pll_info pll = { .diff = (unsigned long)-1 };
316 u32 lvdpllcr;
317
318 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[0], freq, &pll,
319 LVDPLLCR_CKSEL_DU_DOTCLKIN(0));
320 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.dotclkin[1], freq, &pll,
321 LVDPLLCR_CKSEL_DU_DOTCLKIN(1));
322 rcar_lvds_d3_e3_pll_calc(lvds, lvds->clocks.extal, freq, &pll,
323 LVDPLLCR_CKSEL_EXTAL);
324
325 lvdpllcr = LVDPLLCR_PLLON | pll.clksel | LVDPLLCR_CLKOUT
326 | LVDPLLCR_PLLN(pll.pll_n - 1) | LVDPLLCR_PLLM(pll.pll_m - 1);
327
328 if (pll.pll_e > 0)
329 lvdpllcr |= LVDPLLCR_STP_CLKOUTE | LVDPLLCR_OUTCLKSEL
330 | LVDPLLCR_PLLE(pll.pll_e - 1);
331
332 rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
333
334 if (pll.div > 1)
335 /*
336 * The DIVRESET bit is a misnomer, setting it to 1 deasserts the
337 * divisor reset.
338 */
339 rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL |
340 LVDDIV_DIVRESET | LVDDIV_DIV(pll.div - 1));
341 else
342 rcar_lvds_write(lvds, LVDDIV, 0);
343}
344
345/* -----------------------------------------------------------------------------
346 * Bridge
347 */
348
158static void rcar_lvds_enable(struct drm_bridge *bridge) 349static void rcar_lvds_enable(struct drm_bridge *bridge)
159{ 350{
160 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); 351 struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
@@ -164,14 +355,13 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
164 * do we get a state pointer? 355 * do we get a state pointer?
165 */ 356 */
166 struct drm_crtc *crtc = lvds->bridge.encoder->crtc; 357 struct drm_crtc *crtc = lvds->bridge.encoder->crtc;
167 u32 lvdpllcr;
168 u32 lvdhcr; 358 u32 lvdhcr;
169 u32 lvdcr0; 359 u32 lvdcr0;
170 int ret; 360 int ret;
171 361
172 WARN_ON(lvds->enabled); 362 WARN_ON(lvds->enabled);
173 363
174 ret = clk_prepare_enable(lvds->clock); 364 ret = clk_prepare_enable(lvds->clocks.mod);
175 if (ret < 0) 365 if (ret < 0)
176 return; 366 return;
177 367
@@ -196,12 +386,13 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
196 386
197 rcar_lvds_write(lvds, LVDCHCR, lvdhcr); 387 rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
198 388
389 if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK) {
390 /* Disable dual-link mode. */
391 rcar_lvds_write(lvds, LVDSTRIPE, 0);
392 }
393
199 /* PLL clock configuration. */ 394 /* PLL clock configuration. */
200 if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN2_PLLCR) 395 lvds->info->pll_setup(lvds, mode->clock * 1000);
201 lvdpllcr = rcar_lvds_lvdpllcr_gen2(mode->clock);
202 else
203 lvdpllcr = rcar_lvds_lvdpllcr_gen3(mode->clock);
204 rcar_lvds_write(lvds, LVDPLLCR, lvdpllcr);
205 396
206 /* Set the LVDS mode and select the input. */ 397 /* Set the LVDS mode and select the input. */
207 lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT; 398 lvdcr0 = lvds->mode << LVDCR0_LVMD_SHIFT;
@@ -220,11 +411,16 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
220 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 411 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
221 } 412 }
222 413
223 /* Turn the PLL on. */ 414 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
224 lvdcr0 |= LVDCR0_PLLON; 415 /*
225 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 416 * Turn the PLL on (simple PLL only, extended PLL is fully
417 * controlled through LVDPLLCR).
418 */
419 lvdcr0 |= LVDCR0_PLLON;
420 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
421 }
226 422
227 if (lvds->info->gen > 2) { 423 if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) {
228 /* Set LVDS normal mode. */ 424 /* Set LVDS normal mode. */
229 lvdcr0 |= LVDCR0_PWD; 425 lvdcr0 |= LVDCR0_PWD;
230 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 426 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
@@ -236,8 +432,10 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
236 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 432 rcar_lvds_write(lvds, LVDCR0, lvdcr0);
237 } 433 }
238 434
239 /* Wait for the startup delay. */ 435 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) {
240 usleep_range(100, 150); 436 /* Wait for the PLL startup delay (simple PLL only). */
437 usleep_range(100, 150);
438 }
241 439
242 /* Turn the output on. */ 440 /* Turn the output on. */
243 lvdcr0 |= LVDCR0_LVRES; 441 lvdcr0 |= LVDCR0_LVRES;
@@ -264,8 +462,9 @@ static void rcar_lvds_disable(struct drm_bridge *bridge)
264 462
265 rcar_lvds_write(lvds, LVDCR0, 0); 463 rcar_lvds_write(lvds, LVDCR0, 0);
266 rcar_lvds_write(lvds, LVDCR1, 0); 464 rcar_lvds_write(lvds, LVDCR1, 0);
465 rcar_lvds_write(lvds, LVDPLLCR, 0);
267 466
268 clk_disable_unprepare(lvds->clock); 467 clk_disable_unprepare(lvds->clocks.mod);
269 468
270 lvds->enabled = false; 469 lvds->enabled = false;
271} 470}
@@ -446,6 +645,60 @@ done:
446 return ret; 645 return ret;
447} 646}
448 647
648static struct clk *rcar_lvds_get_clock(struct rcar_lvds *lvds, const char *name,
649 bool optional)
650{
651 struct clk *clk;
652
653 clk = devm_clk_get(lvds->dev, name);
654 if (!IS_ERR(clk))
655 return clk;
656
657 if (PTR_ERR(clk) == -ENOENT && optional)
658 return NULL;
659
660 if (PTR_ERR(clk) != -EPROBE_DEFER)
661 dev_err(lvds->dev, "failed to get %s clock\n",
662 name ? name : "module");
663
664 return clk;
665}
666
667static int rcar_lvds_get_clocks(struct rcar_lvds *lvds)
668{
669 lvds->clocks.mod = rcar_lvds_get_clock(lvds, NULL, false);
670 if (IS_ERR(lvds->clocks.mod))
671 return PTR_ERR(lvds->clocks.mod);
672
673 /*
674 * LVDS encoders without an extended PLL have no external clock inputs.
675 */
676 if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))
677 return 0;
678
679 lvds->clocks.extal = rcar_lvds_get_clock(lvds, "extal", true);
680 if (IS_ERR(lvds->clocks.extal))
681 return PTR_ERR(lvds->clocks.extal);
682
683 lvds->clocks.dotclkin[0] = rcar_lvds_get_clock(lvds, "dclkin.0", true);
684 if (IS_ERR(lvds->clocks.dotclkin[0]))
685 return PTR_ERR(lvds->clocks.dotclkin[0]);
686
687 lvds->clocks.dotclkin[1] = rcar_lvds_get_clock(lvds, "dclkin.1", true);
688 if (IS_ERR(lvds->clocks.dotclkin[1]))
689 return PTR_ERR(lvds->clocks.dotclkin[1]);
690
691 /* At least one input to the PLL must be available. */
692 if (!lvds->clocks.extal && !lvds->clocks.dotclkin[0] &&
693 !lvds->clocks.dotclkin[1]) {
694 dev_err(lvds->dev,
695 "no input clock (extal, dclkin.0 or dclkin.1)\n");
696 return -EINVAL;
697 }
698
699 return 0;
700}
701
449static int rcar_lvds_probe(struct platform_device *pdev) 702static int rcar_lvds_probe(struct platform_device *pdev)
450{ 703{
451 struct rcar_lvds *lvds; 704 struct rcar_lvds *lvds;
@@ -475,11 +728,9 @@ static int rcar_lvds_probe(struct platform_device *pdev)
475 if (IS_ERR(lvds->mmio)) 728 if (IS_ERR(lvds->mmio))
476 return PTR_ERR(lvds->mmio); 729 return PTR_ERR(lvds->mmio);
477 730
478 lvds->clock = devm_clk_get(&pdev->dev, NULL); 731 ret = rcar_lvds_get_clocks(lvds);
479 if (IS_ERR(lvds->clock)) { 732 if (ret < 0)
480 dev_err(&pdev->dev, "failed to get clock\n"); 733 return ret;
481 return PTR_ERR(lvds->clock);
482 }
483 734
484 drm_bridge_add(&lvds->bridge); 735 drm_bridge_add(&lvds->bridge);
485 736
@@ -497,21 +748,39 @@ static int rcar_lvds_remove(struct platform_device *pdev)
497 748
498static const struct rcar_lvds_device_info rcar_lvds_gen2_info = { 749static const struct rcar_lvds_device_info rcar_lvds_gen2_info = {
499 .gen = 2, 750 .gen = 2,
500 .quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR, 751 .pll_setup = rcar_lvds_pll_setup_gen2,
501}; 752};
502 753
503static const struct rcar_lvds_device_info rcar_lvds_r8a7790_info = { 754static const struct rcar_lvds_device_info rcar_lvds_r8a7790_info = {
504 .gen = 2, 755 .gen = 2,
505 .quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR | RCAR_LVDS_QUIRK_LANES, 756 .quirks = RCAR_LVDS_QUIRK_LANES,
757 .pll_setup = rcar_lvds_pll_setup_gen2,
506}; 758};
507 759
508static const struct rcar_lvds_device_info rcar_lvds_gen3_info = { 760static const struct rcar_lvds_device_info rcar_lvds_gen3_info = {
509 .gen = 3, 761 .gen = 3,
762 .quirks = RCAR_LVDS_QUIRK_PWD,
763 .pll_setup = rcar_lvds_pll_setup_gen3,
510}; 764};
511 765
512static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = { 766static const struct rcar_lvds_device_info rcar_lvds_r8a77970_info = {
513 .gen = 3, 767 .gen = 3,
514 .quirks = RCAR_LVDS_QUIRK_GEN2_PLLCR | RCAR_LVDS_QUIRK_GEN3_LVEN, 768 .quirks = RCAR_LVDS_QUIRK_PWD | RCAR_LVDS_QUIRK_GEN3_LVEN,
769 .pll_setup = rcar_lvds_pll_setup_gen2,
770};
771
772static const struct rcar_lvds_device_info rcar_lvds_r8a77990_info = {
773 .gen = 3,
774 .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_EXT_PLL
775 | RCAR_LVDS_QUIRK_DUAL_LINK,
776 .pll_setup = rcar_lvds_pll_setup_d3_e3,
777};
778
779static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = {
780 .gen = 3,
781 .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_PWD
782 | RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK,
783 .pll_setup = rcar_lvds_pll_setup_d3_e3,
515}; 784};
516 785
517static const struct of_device_id rcar_lvds_of_table[] = { 786static const struct of_device_id rcar_lvds_of_table[] = {
@@ -523,6 +792,8 @@ static const struct of_device_id rcar_lvds_of_table[] = {
523 { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info }, 792 { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info },
524 { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info }, 793 { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
525 { .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info }, 794 { .compatible = "renesas,r8a77980-lvds", .data = &rcar_lvds_gen3_info },
795 { .compatible = "renesas,r8a77990-lvds", .data = &rcar_lvds_r8a77990_info },
796 { .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_r8a77995_info },
526 { } 797 { }
527}; 798};
528 799
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
index 4870f50d9bec..87149f2f8056 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -18,7 +18,7 @@
18#define LVDCR0_PLLON (1 << 4) 18#define LVDCR0_PLLON (1 << 4)
19#define LVDCR0_PWD (1 << 2) /* Gen3 only */ 19#define LVDCR0_PWD (1 << 2) /* Gen3 only */
20#define LVDCR0_BEN (1 << 2) /* Gen2 only */ 20#define LVDCR0_BEN (1 << 2) /* Gen2 only */
21#define LVDCR0_LVEN (1 << 1) /* Gen2 only */ 21#define LVDCR0_LVEN (1 << 1)
22#define LVDCR0_LVRES (1 << 0) 22#define LVDCR0_LVRES (1 << 0)
23 23
24#define LVDCR1 0x0004 24#define LVDCR1 0x0004
@@ -27,21 +27,36 @@
27#define LVDCR1_CLKSTBY (3 << 0) 27#define LVDCR1_CLKSTBY (3 << 0)
28 28
29#define LVDPLLCR 0x0008 29#define LVDPLLCR 0x0008
30/* Gen2 & V3M */
30#define LVDPLLCR_CEEN (1 << 14) 31#define LVDPLLCR_CEEN (1 << 14)
31#define LVDPLLCR_FBEN (1 << 13) 32#define LVDPLLCR_FBEN (1 << 13)
32#define LVDPLLCR_COSEL (1 << 12) 33#define LVDPLLCR_COSEL (1 << 12)
33/* Gen2 */
34#define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0) 34#define LVDPLLCR_PLLDLYCNT_150M (0x1bf << 0)
35#define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0) 35#define LVDPLLCR_PLLDLYCNT_121M (0x22c << 0)
36#define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0) 36#define LVDPLLCR_PLLDLYCNT_60M (0x77b << 0)
37#define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0) 37#define LVDPLLCR_PLLDLYCNT_38M (0x69a << 0)
38#define LVDPLLCR_PLLDLYCNT_MASK (0x7ff << 0) 38#define LVDPLLCR_PLLDLYCNT_MASK (0x7ff << 0)
39/* Gen3 */ 39/* Gen3 but V3M,D3 and E3 */
40#define LVDPLLCR_PLLDIVCNT_42M (0x014cb << 0) 40#define LVDPLLCR_PLLDIVCNT_42M (0x014cb << 0)
41#define LVDPLLCR_PLLDIVCNT_85M (0x00a45 << 0) 41#define LVDPLLCR_PLLDIVCNT_85M (0x00a45 << 0)
42#define LVDPLLCR_PLLDIVCNT_128M (0x006c3 << 0) 42#define LVDPLLCR_PLLDIVCNT_128M (0x006c3 << 0)
43#define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) 43#define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0)
44#define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0) 44#define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0)
45/* D3 and E3 */
46#define LVDPLLCR_PLLON (1 << 22)
47#define LVDPLLCR_PLLSEL_PLL0 (0 << 20)
48#define LVDPLLCR_PLLSEL_LVX (1 << 20)
49#define LVDPLLCR_PLLSEL_PLL1 (2 << 20)
50#define LVDPLLCR_CKSEL_LVX (1 << 17)
51#define LVDPLLCR_CKSEL_EXTAL (3 << 17)
52#define LVDPLLCR_CKSEL_DU_DOTCLKIN(n) ((5 + (n) * 2) << 17)
53#define LVDPLLCR_OCKSEL (1 << 16)
54#define LVDPLLCR_STP_CLKOUTE (1 << 14)
55#define LVDPLLCR_OUTCLKSEL (1 << 12)
56#define LVDPLLCR_CLKOUT (1 << 11)
57#define LVDPLLCR_PLLE(n) ((n) << 10)
58#define LVDPLLCR_PLLN(n) ((n) << 3)
59#define LVDPLLCR_PLLM(n) ((n) << 0)
45 60
46#define LVDCTRCR 0x000c 61#define LVDCTRCR 0x000c
47#define LVDCTRCR_CTR3SEL_ZERO (0 << 12) 62#define LVDCTRCR_CTR3SEL_ZERO (0 << 12)
@@ -71,4 +86,26 @@
71#define LVDCHCR_CHSEL_CH(n, c) ((((c) - (n)) & 3) << ((n) * 4)) 86#define LVDCHCR_CHSEL_CH(n, c) ((((c) - (n)) & 3) << ((n) * 4))
72#define LVDCHCR_CHSEL_MASK(n) (3 << ((n) * 4)) 87#define LVDCHCR_CHSEL_MASK(n) (3 << ((n) * 4))
73 88
89/* All registers below are specific to D3 and E3 */
90#define LVDSTRIPE 0x0014
91#define LVDSTRIPE_ST_TRGSEL_DISP (0 << 2)
92#define LVDSTRIPE_ST_TRGSEL_HSYNC_R (1 << 2)
93#define LVDSTRIPE_ST_TRGSEL_HSYNC_F (2 << 2)
94#define LVDSTRIPE_ST_SWAP (1 << 1)
95#define LVDSTRIPE_ST_ON (1 << 0)
96
97#define LVDSCR 0x0018
98#define LVDSCR_DEPTH(n) (((n) - 1) << 29)
99#define LVDSCR_BANDSET (1 << 28)
100#define LVDSCR_TWGCNT(n) ((((n) - 256) / 16) << 24)
101#define LVDSCR_SDIV(n) ((n) << 22)
102#define LVDSCR_MODE (1 << 21)
103#define LVDSCR_RSTN (1 << 20)
104
105#define LVDDIV 0x001c
106#define LVDDIV_DIVSEL (1 << 8)
107#define LVDDIV_DIVRESET (1 << 7)
108#define LVDDIV_DIVSTP (1 << 6)
109#define LVDDIV_DIV(n) ((n) << 0)
110
74#endif /* __RCAR_LVDS_REGS_H__ */ 111#endif /* __RCAR_LVDS_REGS_H__ */