Hi!
This is a prototype extension of the series "R-Car D3 LVDS/HDMI support" that includes an up-port of the LVDS PLL support in the BSP.
While this is prototype-quality code, there are in my judgment no serious hacks in it. The most significant deviation in behavior between this and the BSP code is that the LVDS PLL setup is not done in two steps, but in one go as the LVDS device is enabled. This was easier to implement, and works just as fine.
Instructions for testing this are found at https://elinux.org/User:Uli/D3_HDMI_Test, including links to git trees based on renesas-drivers and drm-next, as well as config files for each.
CU Uli
Jacopo Mondi (1): drm: rcar-du: lvds: Handle LVDS interface reset
Kieran Bingham (1): arm64: dts: renesas: r8a77995: Add LVDS support
Koji Matsuoka (5): drm: rcar-du: Add clk_set_rate for external clock device drm: rcar-du: Fix digital RGB routing for R8A77995 drm/bridge: adv7511: Add max-clock, min-vrefresh options drm: rcar-du: Fix procedure for extal and dotclkin selection arm64: dts: r8a77995-draak: set external clock for DU
Ulrich Hecht (3): drm: rcar-du: Add r8a77995 device support drm: rcar-du: lvds: LVDS PLL support arm64: dts: renesas: r8a77995-draak: add HDMI output
arch/arm64/boot/dts/renesas/r8a77995-draak.dts | 92 +++++++++- arch/arm64/boot/dts/renesas/r8a77995.dtsi | 56 ++++++ drivers/gpu/drm/bridge/adv7511/adv7511.h | 7 + drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 +++ drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 33 ++-- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 4 + drivers/gpu/drm/rcar-du/rcar_du_drv.c | 28 +++ drivers/gpu/drm/rcar-du/rcar_du_drv.h | 4 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 18 +- drivers/gpu/drm/rcar-du/rcar_lvds.c | 227 +++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 44 ++++- 11 files changed, 517 insertions(+), 18 deletions(-)
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index b52b3e8..cd6803a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -229,6 +229,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) unsigned long rate; u32 extdiv;
+ clk_set_rate(rcrtc->extclock, mode_clock); extclk = clk_get_rate(rcrtc->extclock); if (rcdu->info->dpll_ch & (1 << rcrtc->index)) { unsigned long target = mode_clock;
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:49:55 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index b52b3e8..cd6803a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -229,6 +229,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) unsigned long rate; u32 extdiv;
clk_set_rate(rcrtc->extclock, mode_clock);
This is a hack, Jacopo has posted "[PATCH 3/3] drm: rcar-du: Improve non-DPLL clock selection" which I think is a better solution (or will be in v2 :-)).
extclk = clk_get_rate(rcrtc->extclock); if (rcdu->info->dpll_ch & (1 << rcrtc->index)) { unsigned long target = mode_clock;
Add support for the R-Car D3 (R8A77995) SoC to the R-Car DU driver.
Based on patch by Koji Matsuoka koji.matsuoka.xm@renesas.com.
Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 17 ++++++----------- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 3 ++- 4 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index cd6803a..9153e7a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -53,14 +53,6 @@ static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr) rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr); }
-static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set) -{ - struct rcar_du_device *rcdu = rcrtc->group->dev; - - rcar_du_write(rcdu, rcrtc->mmio_offset + reg, - rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set); -} - static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr, u32 set) { @@ -527,7 +519,8 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) * actively driven). */ interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE; - rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK, + rcar_du_crtc_clr_set(rcrtc, DSYSR, + DSYSR_TVM_MASK | DSYSR_SCM_MASK | DSYSR_ILTS, (interlaced ? DSYSR_SCM_INT_VIDEO : 0) | DSYSR_TVM_MASTER);
@@ -596,7 +589,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) * Select switch sync mode. This stops display operation and configures * the HSYNC and VSYNC signals as inputs. */ - rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH); + rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_ILTS, + rcar_du_needs(rcrtc->group->dev, RCAR_DU_QUIRK_TVM_MASTER_ONLY) ? + DSYSR_TVM_MASTER : DSYSR_TVM_SWITCH);
rcar_du_group_start_stop(rcrtc->group, false); } @@ -744,7 +739,7 @@ static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc) struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL); - rcar_du_crtc_set(rcrtc, DIER, DIER_VBE); + rcar_du_crtc_clr_set(rcrtc, DIER, DIER_TVE | DIER_FRE, DIER_VBE); rcrtc->vblank_enable = true;
return 0; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 56f9472..5c2f764 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -294,6 +294,31 @@ static const struct rcar_du_device_info rcar_du_r8a77970_info = { .num_lvds = 1, };
+static const struct rcar_du_device_info rcar_du_r8a77995_info = { + .gen = 3, + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK + | RCAR_DU_FEATURE_EXT_CTRL_REGS + | RCAR_DU_FEATURE_VSP1_SOURCE, + .quirks = RCAR_DU_QUIRK_TVM_MASTER_ONLY, + .channels_mask = BIT(1) | BIT(0), + .routes = { + /* R8A77995 has two LVDS output and one RGB output. */ + [RCAR_DU_OUTPUT_DPAD0] = { + .possible_crtcs = BIT(0) | BIT(1), + .port = 0, + }, + [RCAR_DU_OUTPUT_LVDS0] = { + .possible_crtcs = BIT(0), + .port = 1, + }, + [RCAR_DU_OUTPUT_LVDS1] = { + .possible_crtcs = BIT(1), + .port = 2, + }, + }, + .num_lvds = 2, +}; + static const struct of_device_id rcar_du_of_table[] = { { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info }, { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info }, @@ -307,6 +332,7 @@ static const struct of_device_id rcar_du_of_table[] = { { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info }, { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info }, { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info }, + { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a77995_info }, { } };
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index b3a25e8..6257405 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -32,6 +32,7 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ +#define RCAR_DU_QUIRK_TVM_MASTER_ONLY (1 << 1) /* Does not have TV switch/sync modes */
/* * struct rcar_du_output_routing - Output routing specification diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index d539cb2..9a0a694 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -178,7 +178,8 @@ void rcar_du_group_put(struct rcar_du_group *rgrp) static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) { rcar_du_group_write(rgrp, DSYSR, - (rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) | + (rcar_du_group_read(rgrp, DSYSR) & + ~(DSYSR_DRES | DSYSR_DEN | DSYSR_ILTS)) | (start ? DSYSR_DEN : DSYSR_DRES)); }
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:49:56 EEST Ulrich Hecht wrote:
Add support for the R-Car D3 (R8A77995) SoC to the R-Car DU driver.
Based on patch by Koji Matsuoka koji.matsuoka.xm@renesas.com.
Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 17 ++++++----------- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 3 ++- 4 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index cd6803a..9153e7a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -53,14 +53,6 @@ static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr) rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr); }
-static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set) -{
- struct rcar_du_device *rcdu = rcrtc->group->dev;
- rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set);
-}
static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr, u32 set) { @@ -527,7 +519,8 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) * actively driven). */ interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
- rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
- rcar_du_crtc_clr_set(rcrtc, DSYSR,
DSYSR_TVM_MASK | DSYSR_SCM_MASK | DSYSR_ILTS,
The ILTS bit defaults to 0 so this shouldn't be needed. However, we never initialize the DSYSR register completely but only modify bits. It would be safer to write all bits at init time. I'll write a separate patch.
(interlaced ? DSYSR_SCM_INT_VIDEO : 0) | DSYSR_TVM_MASTER);
@@ -596,7 +589,9 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) * Select switch sync mode. This stops display operation and configures * the HSYNC and VSYNC signals as inputs. */
- rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
- rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_ILTS,
rcar_du_needs(rcrtc->group->dev, RCAR_DU_QUIRK_TVM_MASTER_ONLY) ?
DSYSR_TVM_MASTER : DSYSR_TVM_SWITCH);
Now this is a problem. The driver uses switch mode as a way to disable the display output, as the display enable bits in the DSYSR register cover a group of two DU channels. TVM switch mode was the only workaround I found to be able to disable the display output. If the D3 and E3 SoCs don't implement TVM switch mode we need a different mechanism.
rcar_du_group_start_stop(rcrtc->group, false); } @@ -744,7 +739,7 @@ static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc) struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL);
- rcar_du_crtc_set(rcrtc, DIER, DIER_VBE);
rcar_du_crtc_clr_set(rcrtc, DIER, DIER_TVE | DIER_FRE, DIER_VBE); rcrtc->vblank_enable = true;
return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 56f9472..5c2f764 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -294,6 +294,31 @@ static const struct rcar_du_device_info rcar_du_r8a77970_info = { .num_lvds = 1, };
+static const struct rcar_du_device_info rcar_du_r8a77995_info = {
- .gen = 3,
- .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
| RCAR_DU_FEATURE_EXT_CTRL_REGS
| RCAR_DU_FEATURE_VSP1_SOURCE,
- .quirks = RCAR_DU_QUIRK_TVM_MASTER_ONLY,
- .channels_mask = BIT(1) | BIT(0),
- .routes = {
/* R8A77995 has two LVDS output and one RGB output. */
[RCAR_DU_OUTPUT_DPAD0] = {
.possible_crtcs = BIT(0) | BIT(1),
.port = 0,
},
[RCAR_DU_OUTPUT_LVDS0] = {
.possible_crtcs = BIT(0),
.port = 1,
},
[RCAR_DU_OUTPUT_LVDS1] = {
.possible_crtcs = BIT(1),
.port = 2,
},
- },
- .num_lvds = 2,
+};
static const struct of_device_id rcar_du_of_table[] = { { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info }, { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info }, @@ -307,6 +332,7 @@ static const struct of_device_id rcar_du_of_table[] = { { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info }, { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info }, { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
- { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a77995_info }, { }
};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index b3a25e8..6257405 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -32,6 +32,7 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes
*/
+#define RCAR_DU_QUIRK_TVM_MASTER_ONLY (1 << 1) /* Does not have TV switch/sync modes */
/*
- struct rcar_du_output_routing - Output routing specification
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index d539cb2..9a0a694 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -178,7 +178,8 @@ void rcar_du_group_put(struct rcar_du_group *rgrp) static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start) { rcar_du_group_write(rgrp, DSYSR,
(rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
(rcar_du_group_read(rgrp, DSYSR) &
(start ? DSYSR_DEN : DSYSR_DRES));~(DSYSR_DRES | DSYSR_DEN | DSYSR_ILTS)) |
}
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds D3 definition for DU and fixes digital RGB routing.
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com --- drivers/gpu/drm/rcar-du/rcar_du_drv.c | 3 ++- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_group.c | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 5c2f764..d930996 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -298,7 +298,8 @@ static const struct rcar_du_device_info rcar_du_r8a77995_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_EXT_CTRL_REGS - | RCAR_DU_FEATURE_VSP1_SOURCE, + | RCAR_DU_FEATURE_VSP1_SOURCE + | RCAR_DU_FEATURE_R8A77995_REGS, .quirks = RCAR_DU_QUIRK_TVM_MASTER_ONLY, .channels_mask = BIT(1) | BIT(0), .routes = { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 6257405..9355b58 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -30,6 +30,8 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ #define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */ #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */ +#define RCAR_DU_FEATURE_R8A77965_REGS (1 << 3) /* Use R8A77965 registers */ +#define RCAR_DU_FEATURE_R8A77995_REGS (1 << 4) /* Use R8A77995 registers */
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ #define RCAR_DU_QUIRK_TVM_MASTER_ONLY (1 << 1) /* Does not have TV switch/sync modes */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 9a0a694..371d780 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -88,6 +88,10 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
if (crtc->index / 2 == rgrp->index) defr8 |= DEFR8_DRGBS_DU(crtc->index); + + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_R8A77995_REGS)) + defr8 |= (DEFR8_DRGBS_DU(rcdu->dpad0_source) | + DEFR8_DRGBS_DU(crtc->index)); }
rcar_du_group_write(rgrp, DEFR8, defr8);
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:49:57 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds D3 definition for DU and fixes digital RGB routing.
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com
drivers/gpu/drm/rcar-du/rcar_du_drv.c | 3 ++- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_group.c | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 5c2f764..d930996 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -298,7 +298,8 @@ static const struct rcar_du_device_info rcar_du_r8a77995_info = { .gen = 3, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
| RCAR_DU_FEATURE_EXT_CTRL_REGS
| RCAR_DU_FEATURE_VSP1_SOURCE,
| RCAR_DU_FEATURE_VSP1_SOURCE
.quirks = RCAR_DU_QUIRK_TVM_MASTER_ONLY, .channels_mask = BIT(1) | BIT(0), .routes = {| RCAR_DU_FEATURE_R8A77995_REGS,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 6257405..9355b58 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -30,6 +30,8 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ #define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */ #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */ +#define RCAR_DU_FEATURE_R8A77965_REGS (1 << 3) /* Use R8A77965 registers */ +#define RCAR_DU_FEATURE_R8A77995_REGS (1 << 4) /* Use R8A77995 registers */
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes
*/
#define RCAR_DU_QUIRK_TVM_MASTER_ONLY (1 << 1) /* Does not have TV switch/sync modes */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 9a0a694..371d780 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -88,6 +88,10 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
if (crtc->index / 2 == rgrp->index) defr8 |= DEFR8_DRGBS_DU(crtc->index);
if (rcar_du_has(rcdu, RCAR_DU_FEATURE_R8A77995_REGS))
defr8 |= (DEFR8_DRGBS_DU(rcdu->dpad0_source) |
DEFR8_DRGBS_DU(crtc->index));
Does this need a special case ? Can't we replace the existing logic with code based on dpad0_source, and make sure that dpad0_source always contains the correct value on SoCs that have a hardcoded connection between DU and DPAD ?
}
rcar_du_group_write(rgrp, DEFR8, defr8);
In R-Car D3 and E3, the DU dot clock can be sourced from the LVDS PLL. This patch enables that PLL if present.
Based on patch by Koji Matsuoka koji.matsuoka.xm@renesas.com.
Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 3 + drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_drv.c | 3 +- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 11 +- drivers/gpu/drm/rcar-du/rcar_lvds.c | 212 +++++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 46 ++++++- 7 files changed, 274 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 9153e7a..a903456 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -275,6 +275,9 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) mode_clock, extrate, rate, escr); }
+ if (rcar_du_has(rcdu, RCAR_DU_FEATURE_LVDS_PLL)) + escr = 0; + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, escr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 7680cb2..65de551 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -44,6 +44,7 @@ struct rcar_du_vsp; * @group: CRTC group this CRTC belongs to * @vsp: VSP feeding video to this CRTC * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC + * @lvds_ch: index of LVDS */ struct rcar_du_crtc { struct drm_crtc crtc; @@ -67,6 +68,7 @@ struct rcar_du_crtc { struct rcar_du_group *group; struct rcar_du_vsp *vsp; unsigned int vsp_pipe; + int lvds_ch; };
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index d930996..3338ef5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -299,7 +299,8 @@ static const struct rcar_du_device_info rcar_du_r8a77995_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE - | RCAR_DU_FEATURE_R8A77995_REGS, + | RCAR_DU_FEATURE_R8A77995_REGS + | RCAR_DU_FEATURE_LVDS_PLL, .quirks = RCAR_DU_QUIRK_TVM_MASTER_ONLY, .channels_mask = BIT(1) | BIT(0), .routes = { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 9355b58..6009b7d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -32,6 +32,7 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */ #define RCAR_DU_FEATURE_R8A77965_REGS (1 << 3) /* Use R8A77965 registers */ #define RCAR_DU_FEATURE_R8A77995_REGS (1 << 4) /* Use R8A77995 registers */ +#define RCAR_DU_FEATURE_LVDS_PLL (1 << 5) /* Use PLL in LVDS */
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ #define RCAR_DU_QUIRK_TVM_MASTER_ONLY (1 << 1) /* Does not have TV switch/sync modes */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 371d780..44681e3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -126,8 +126,15 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) * are setup through per-group registers, only available when * the group has two channels. */ - if ((rcdu->info->gen < 3 && rgrp->index == 0) || - (rcdu->info->gen == 3 && rgrp->num_crtcs > 1)) + if (rcar_du_has(rcdu, RCAR_DU_FEATURE_LVDS_PLL)) + rcar_du_group_write(rgrp, + DIDSR, DIDSR_CODE | + DIDSR_LCDS_LVDS0(1) | + DIDSR_LCDS_LVDS0(0) | + DIDSR_PDCS_CLK(1, 0) | + DIDSR_PDCS_CLK(0, 0)); + else if ((rcdu->info->gen < 3 && rgrp->index == 0) || + (rcdu->info->gen == 3 && rgrp->num_crtcs > 1)) rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE); }
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 4c39de3..cd55576 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -23,6 +23,8 @@ #include <drm/drm_panel.h>
#include "rcar_lvds_regs.h" +#include "rcar_du_crtc.h" +#include "rcar_du_drv.h"
/* Keep in sync with the LVDCR0.LVMD hardware register values. */ enum rcar_lvds_mode { @@ -65,6 +67,15 @@ struct rcar_lvds { #define connector_to_rcar_lvds(connector) \ container_of(connector, struct rcar_lvds, connector)
+struct pll_info { + unsigned int pllclk; + unsigned int diff; + unsigned int clk_n; + unsigned int clk_m; + unsigned int clk_e; + unsigned int div; +}; + static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data) { iowrite32(data, lvds->mmio + reg); @@ -155,6 +166,198 @@ static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq) return LVDPLLCR_PLLDIVCNT_148M; }
+static void rcar_lvds_pll_calc(struct rcar_du_crtc *rcrtc, + struct pll_info *pll, unsigned int in_fre, + unsigned int mode_freq, bool edivider) +{ + unsigned long diff = (unsigned long)-1; + unsigned long fout, fpfd, fvco, n, m, e, div; + bool clk_diff_set = true; + + if (in_fre < 12000000 || in_fre > 192000000) + return; + + for (n = 0; n < 127; n++) { + if (n + 1 < 60 || n + 1 > 120) + continue; + + for (m = 0; m < 7; m++) { + for (e = 0; e < 1; e++) { + if (edivider) + fout = (((in_fre / 1000) * (n + 1)) / + ((m + 1) * (e + 1) * 2)) * + 1000; + else + fout = (((in_fre / 1000) * (n + 1)) / + (m + 1)) * 1000; + + if (fout > 1039500000) + continue; + + fpfd = (in_fre / (m + 1)); + if (fpfd < 12000000 || fpfd > 24000000) + continue; + + fvco = (((in_fre / 1000) * (n + 1)) / (m + 1)) + * 1000; + if (fvco < 900000000 || fvco > 1800000000) + continue; + + fout = fout / 7; /* 7 divider */ + + for (div = 0; div < 64; div++) { + diff = abs((long)(fout / (div + 1)) - + (long)mode_freq); + + if (clk_diff_set || + (diff == 0 || + pll->diff > diff)) { + pll->diff = diff; + pll->clk_n = n; + pll->clk_m = m; + pll->clk_e = e; + pll->pllclk = fout; + pll->div = div; + + clk_diff_set = false; + + if (diff == 0) + return; + } + } + } + } + } +} + +static void rcar_lvds_pll_pre_start(struct rcar_lvds *lvds, + struct rcar_du_crtc *rcrtc) +{ + const struct drm_display_mode *mode = + &rcrtc->crtc.state->adjusted_mode; + unsigned int mode_freq = mode->clock * 1000; + unsigned int ext_clk = 0; + struct pll_info *lvds_pll[2]; + u32 clksel, cksel; + int i, ret; + + if (rcrtc->extclock) + ext_clk = clk_get_rate(rcrtc->extclock); + else + dev_warn(lvds->dev, "external clock is not set\n"); + + dev_dbg(lvds->dev, "external clock %d Hz\n", ext_clk); + + if (lvds->enabled) + return; + + for (i = 0; i < 2; i++) { + lvds_pll[i] = kzalloc(sizeof(*lvds_pll), GFP_KERNEL); + if (!lvds_pll[i]) + return; + } + + /* software reset release */ + reset_control_deassert(lvds->rst); + + ret = clk_prepare_enable(lvds->clock); + if (ret < 0) + goto end; + + for (i = 0; i < 2; i++) { + bool edivider; + + if (i == 0) + edivider = true; + else + edivider = false; + + rcar_lvds_pll_calc(rcrtc, lvds_pll[i], ext_clk, + mode_freq, edivider); + } + + dev_dbg(lvds->dev, "mode_frequency %d Hz\n", mode_freq); + + if (lvds_pll[1]->diff >= lvds_pll[0]->diff) { + /* use E-edivider */ + i = 0; + clksel = LVDPLLCR_OUTCLKSEL_AFTER | + LVDPLLCR_STP_CLKOUTE1_EN; + } else { + /* do not use E-divider */ + i = 1; + clksel = LVDPLLCR_OUTCLKSEL_BEFORE | + LVDPLLCR_STP_CLKOUTE1_DIS; + } + dev_dbg(lvds->dev, + "E-divider %s\n", (i == 0 ? "is used" : "is not used")); + + dev_dbg(lvds->dev, + "pllclk:%u, n:%u, m:%u, e:%u, diff:%u, div:%u\n", + lvds_pll[i]->pllclk, lvds_pll[i]->clk_n, lvds_pll[i]->clk_m, + lvds_pll[i]->clk_e, lvds_pll[i]->diff, lvds_pll[i]->div); + + if (rcrtc->extal_use) + cksel = LVDPLLCR_CKSEL_EXTAL; + else + cksel = LVDPLLCR_CKSEL_DU_DOTCLKIN(rcrtc->index); + + rcar_lvds_write(lvds, LVDPLLCR, LVDPLLCR_PLLON | + LVDPLLCR_OCKSEL_7 | clksel | LVDPLLCR_CLKOUT_ENABLE | + cksel | (lvds_pll[i]->clk_e << 10) | + (lvds_pll[i]->clk_n << 3) | lvds_pll[i]->clk_m); + + if (lvds_pll[i]->div > 0) + rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL | + LVDDIV_DIVRESET | lvds_pll[i]->div); + else + rcar_lvds_write(lvds, LVDDIV, 0); + + dev_dbg(lvds->dev, "LVDPLLCR: 0x%x\n", + ioread32(lvds->mmio + LVDPLLCR)); + dev_dbg(lvds->dev, "LVDDIV: 0x%x\n", + ioread32(lvds->mmio + LVDDIV)); + +end: + for (i = 0; i < 2; i++) + kfree(lvds_pll[i]); +} + +static void rcar_lvds_pll_start(struct rcar_lvds *lvds, + struct rcar_du_crtc *rcrtc) +{ + u32 lvdhcr, lvdcr0; + + rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO | + LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC | + LVDCTRCR_CTR0SEL_HSYNC); + + lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1) | + LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3); + rcar_lvds_write(lvds, LVDCHCR, lvdhcr); + + rcar_lvds_write(lvds, LVDSTRIPE, 0); + /* Turn all the channels on. */ + rcar_lvds_write(lvds, LVDCR1, + LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) | + LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | + LVDCR1_CLKSTBY); + /* + * Turn the PLL on, set it to LVDS normal mode, wait for the startup + * delay and turn the output on. + */ + lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PWD; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + + lvdcr0 |= LVDCR0_LVEN; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + + lvdcr0 |= LVDCR0_LVRES; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + + lvds->enabled = true; +} + static void rcar_lvds_enable(struct drm_bridge *bridge) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -164,6 +367,7 @@ static void rcar_lvds_enable(struct drm_bridge *bridge) * do we get a state pointer? */ struct drm_crtc *crtc = lvds->bridge.encoder->crtc; + struct rcar_du_device *rcdu = to_rcar_crtc(crtc)->group->dev; u32 lvdpllcr; u32 lvdhcr; u32 lvdcr0; @@ -171,6 +375,12 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
WARN_ON(lvds->enabled);
+ if (rcar_du_has(rcdu, RCAR_DU_FEATURE_LVDS_PLL)) { + rcar_lvds_pll_pre_start(lvds, to_rcar_crtc(crtc)); + rcar_lvds_pll_start(lvds, to_rcar_crtc(crtc)); + return; + } + ret = clk_prepare_enable(lvds->clock); if (ret < 0) return; @@ -264,6 +474,7 @@ static void rcar_lvds_disable(struct drm_bridge *bridge)
rcar_lvds_write(lvds, LVDCR0, 0); rcar_lvds_write(lvds, LVDCR1, 0); + rcar_lvds_write(lvds, LVDPLLCR, 0);
clk_disable_unprepare(lvds->clock);
@@ -522,6 +733,7 @@ static const struct of_device_id rcar_lvds_of_table[] = { { .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info }, { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info }, { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info }, + { .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_gen3_info }, { } };
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h index 2896835..e37db95 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h @@ -21,7 +21,7 @@ #define LVDCR0_PLLON (1 << 4) #define LVDCR0_PWD (1 << 2) /* Gen3 only */ #define LVDCR0_BEN (1 << 2) /* Gen2 only */ -#define LVDCR0_LVEN (1 << 1) /* Gen2 only */ +#define LVDCR0_LVEN (1 << 1) #define LVDCR0_LVRES (1 << 0)
#define LVDCR1 0x0004 @@ -46,6 +46,24 @@ #define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) #define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0)
+/* R-Car D3 */ +#define LVDPLLCR_PLLON (1 << 22) +#define LVDPLLCR_PLLSEL_PLL0 (0 << 20) +#define LVDPLLCR_PLLSEL_LVX (1 << 20) +#define LVDPLLCR_PLLSEL_PLL1 (2 << 20) +#define LVDPLLCR_CKSEL_LVX (1 << 17) +#define LVDPLLCR_CKSEL_EXTAL (3 << 17) +#define LVDPLLCR_CKSEL_DU_DOTCLKIN0 (5 << 17) +#define LVDPLLCR_CKSEL_DU_DOTCLKIN1 (7 << 17) +#define LVDPLLCR_OCKSEL_7 (0 << 16) +#define LVDPLLCR_OCKSEL_NOT_DIVIDED (1 << 16) +#define LVDPLLCR_STP_CLKOUTE1_DIS (0 << 14) +#define LVDPLLCR_STP_CLKOUTE1_EN (1 << 14) +#define LVDPLLCR_OUTCLKSEL_BEFORE (0 << 12) +#define LVDPLLCR_OUTCLKSEL_AFTER (1 << 12) +#define LVDPLLCR_CLKOUT_DISABLE (0 << 11) +#define LVDPLLCR_CLKOUT_ENABLE (1 << 11) + #define LVDCTRCR 0x000c #define LVDCTRCR_CTR3SEL_ZERO (0 << 12) #define LVDCTRCR_CTR3SEL_ODD (1 << 12) @@ -74,4 +92,30 @@ #define LVDCHCR_CHSEL_CH(n, c) ((((c) - (n)) & 3) << ((n) * 4)) #define LVDCHCR_CHSEL_MASK(n) (3 << ((n) * 4))
+#define LVDSTRIPE 0x0014 +#define LVDSTRIPE_ST_TRGSEL_DISP (0 << 2) +#define LVDSTRIPE_ST_TRGSEL_HSYNC_R (1 << 2) +#define LVDSTRIPE_ST_TRGSEL_HSYNC_F (2 << 2) + +#define LVDSTRIPE_ST_SWAP_NORMAL (0 << 1) +#define LVDSTRIPE_ST_SWAP_SWAP (1 << 1) +#define LVDSTRIPE_ST_ON (1 << 0) + +#define LVDSCR 0x0018 +#define LVDSCR_DEPTH_DP1 (0 << 29) +#define LVDSCR_DEPTH_DP2 (1 << 29) +#define LVDSCR_DEPTH_DP3 (2 << 29) +#define LVDSCR_BANDSET_10KHZ_LESS_THAN (1 << 28) +#define LVDSCR_SDIV_SR1 (0 << 22) +#define LVDSCR_SDIV_SR2 (1 << 22) +#define LVDSCR_SDIV_SR4 (2 << 22) +#define LVDSCR_SDIV_SR8 (3 << 22) +#define LVDSCR_MODE_DOWN (1 << 21) +#define LVDSCR_RSTN_ENABLE (1 << 20) + +#define LVDDIV 0x001c +#define LVDDIV_DIVSEL (1 << 8) +#define LVDDIV_DIVRESET (1 << 7) +#define LVDDIV_DIVSTP (1 << 6) + #endif /* __RCAR_LVDS_REGS_H__ */
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:49:58 EEST Ulrich Hecht wrote:
In R-Car D3 and E3, the DU dot clock can be sourced from the LVDS PLL. This patch enables that PLL if present.
Based on patch by Koji Matsuoka koji.matsuoka.xm@renesas.com.
Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 3 + drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 + drivers/gpu/drm/rcar-du/rcar_du_drv.c | 3 +- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 11 +- drivers/gpu/drm/rcar-du/rcar_lvds.c | 212 ++++++++++++++++++++++++++++ drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 46 ++++++-
The DU and LVDS encoder changes should be split in two patches.
7 files changed, 274 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 9153e7a..a903456 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -275,6 +275,9 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) mode_clock, extrate, rate, escr); }
- if (rcar_du_has(rcdu, RCAR_DU_FEATURE_LVDS_PLL))
escr = 0;
- rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, escr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 7680cb2..65de551 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -44,6 +44,7 @@ struct rcar_du_vsp;
- @group: CRTC group this CRTC belongs to
- @vsp: VSP feeding video to this CRTC
- @vsp_pipe: index of the VSP pipeline feeding video to this CRTC
*/
- @lvds_ch: index of LVDS
struct rcar_du_crtc { struct drm_crtc crtc; @@ -67,6 +68,7 @@ struct rcar_du_crtc { struct rcar_du_group *group; struct rcar_du_vsp *vsp; unsigned int vsp_pipe;
- int lvds_ch;
This field is never set or used.
};
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index d930996..3338ef5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -299,7 +299,8 @@ static const struct rcar_du_device_info rcar_du_r8a77995_info = { .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_EXT_CTRL_REGS | RCAR_DU_FEATURE_VSP1_SOURCE
| RCAR_DU_FEATURE_R8A77995_REGS,
| RCAR_DU_FEATURE_R8A77995_REGS
.quirks = RCAR_DU_QUIRK_TVM_MASTER_ONLY, .channels_mask = BIT(1) | BIT(0), .routes = {| RCAR_DU_FEATURE_LVDS_PLL,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 9355b58..6009b7d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -32,6 +32,7 @@ struct rcar_du_device; #define RCAR_DU_FEATURE_VSP1_SOURCE (1 << 2) /* Has inputs from VSP1 */ #define RCAR_DU_FEATURE_R8A77965_REGS (1 << 3) /* Use R8A77965 registers
*/
#define RCAR_DU_FEATURE_R8A77995_REGS (1 << 4) /* Use R8A77995 registers
*/
+#define RCAR_DU_FEATURE_LVDS_PLL (1 << 5) /* Use PLL in LVDS */
The feature bit should tell if the LVDS encore has a PLL. Whether to use it or not should be a runtime decision.
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes
*/
#define RCAR_DU_QUIRK_TVM_MASTER_ONLY (1 << 1) /* Does not have TV switch/sync modes */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 371d780..44681e3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -126,8 +126,15 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp) * are setup through per-group registers, only available when * the group has two channels. */
if ((rcdu->info->gen < 3 && rgrp->index == 0) ||
(rcdu->info->gen == 3 && rgrp->num_crtcs > 1))
if (rcar_du_has(rcdu, RCAR_DU_FEATURE_LVDS_PLL))
rcar_du_group_write(rgrp,
DIDSR, DIDSR_CODE |
DIDSR_LCDS_LVDS0(1) |
DIDSR_LCDS_LVDS0(0) |
DIDSR_PDCS_CLK(1, 0) |
DIDSR_PDCS_CLK(0, 0));
else if ((rcdu->info->gen < 3 && rgrp->index == 0) ||
}(rcdu->info->gen == 3 && rgrp->num_crtcs > 1)) rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE);
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 4c39de3..cd55576 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -23,6 +23,8 @@ #include <drm/drm_panel.h>
#include "rcar_lvds_regs.h" +#include "rcar_du_crtc.h" +#include "rcar_du_drv.h"
That's a layering violation that I'd like to avoid.
/* Keep in sync with the LVDCR0.LVMD hardware register values. */ enum rcar_lvds_mode { @@ -65,6 +67,15 @@ struct rcar_lvds { #define connector_to_rcar_lvds(connector) \ container_of(connector, struct rcar_lvds, connector)
+struct pll_info {
- unsigned int pllclk;
- unsigned int diff;
- unsigned int clk_n;
- unsigned int clk_m;
- unsigned int clk_e;
- unsigned int div;
+};
static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data) { iowrite32(data, lvds->mmio + reg); @@ -155,6 +166,198 @@ static u32 rcar_lvds_lvdpllcr_gen3(unsigned int freq) return LVDPLLCR_PLLDIVCNT_148M; }
+static void rcar_lvds_pll_calc(struct rcar_du_crtc *rcrtc,
struct pll_info *pll, unsigned int in_fre,
unsigned int mode_freq, bool edivider)
+{
- unsigned long diff = (unsigned long)-1;
- unsigned long fout, fpfd, fvco, n, m, e, div;
- bool clk_diff_set = true;
- if (in_fre < 12000000 || in_fre > 192000000)
return;
- for (n = 0; n < 127; n++) {
if (n + 1 < 60 || n + 1 > 120)
continue;
Seriously ? :-)
for (m = 0; m < 7; m++) {
for (e = 0; e < 1; e++) {
if (edivider)
fout = (((in_fre / 1000) * (n + 1)) /
((m + 1) * (e + 1) * 2)) *
1000;
else
fout = (((in_fre / 1000) * (n + 1)) /
(m + 1)) * 1000;
if (fout > 1039500000)
continue;
fpfd = (in_fre / (m + 1));
if (fpfd < 12000000 || fpfd > 24000000)
continue;
fvco = (((in_fre / 1000) * (n + 1)) / (m + 1))
* 1000;
if (fvco < 900000000 || fvco > 1800000000)
continue;
fout = fout / 7; /* 7 divider */
for (div = 0; div < 64; div++) {
That's a lot of iterations for the four nested loops, surely it can be simplified.
diff = abs((long)(fout / (div + 1)) -
(long)mode_freq);
if (clk_diff_set ||
(diff == 0 ||
pll->diff > diff)) {
pll->diff = diff;
pll->clk_n = n;
pll->clk_m = m;
pll->clk_e = e;
pll->pllclk = fout;
pll->div = div;
clk_diff_set = false;
if (diff == 0)
return;
}
}
}
}
- }
+}
+static void rcar_lvds_pll_pre_start(struct rcar_lvds *lvds,
struct rcar_du_crtc *rcrtc)
+{
- const struct drm_display_mode *mode =
&rcrtc->crtc.state->adjusted_mode;
- unsigned int mode_freq = mode->clock * 1000;
- unsigned int ext_clk = 0;
- struct pll_info *lvds_pll[2];
- u32 clksel, cksel;
- int i, ret;
- if (rcrtc->extclock)
ext_clk = clk_get_rate(rcrtc->extclock);
- else
dev_warn(lvds->dev, "external clock is not set\n");
- dev_dbg(lvds->dev, "external clock %d Hz\n", ext_clk);
- if (lvds->enabled)
return;
- for (i = 0; i < 2; i++) {
lvds_pll[i] = kzalloc(sizeof(*lvds_pll), GFP_KERNEL);
if (!lvds_pll[i])
return;
Memory leak if kzalloc() fails in any but the first iteration.
Why do you need dynamic allocation at all ?
- }
- /* software reset release */
- reset_control_deassert(lvds->rst);
- ret = clk_prepare_enable(lvds->clock);
- if (ret < 0)
goto end;
- for (i = 0; i < 2; i++) {
bool edivider;
if (i == 0)
edivider = true;
else
edivider = false;
rcar_lvds_pll_calc(rcrtc, lvds_pll[i], ext_clk,
mode_freq, edivider);
- }
- dev_dbg(lvds->dev, "mode_frequency %d Hz\n", mode_freq);
- if (lvds_pll[1]->diff >= lvds_pll[0]->diff) {
/* use E-edivider */
i = 0;
clksel = LVDPLLCR_OUTCLKSEL_AFTER |
LVDPLLCR_STP_CLKOUTE1_EN;
- } else {
/* do not use E-divider */
i = 1;
clksel = LVDPLLCR_OUTCLKSEL_BEFORE |
LVDPLLCR_STP_CLKOUTE1_DIS;
- }
- dev_dbg(lvds->dev,
"E-divider %s\n", (i == 0 ? "is used" : "is not used"));
- dev_dbg(lvds->dev,
"pllclk:%u, n:%u, m:%u, e:%u, diff:%u, div:%u\n",
lvds_pll[i]->pllclk, lvds_pll[i]->clk_n, lvds_pll[i]->clk_m,
lvds_pll[i]->clk_e, lvds_pll[i]->diff, lvds_pll[i]->div);
- if (rcrtc->extal_use)
cksel = LVDPLLCR_CKSEL_EXTAL;
- else
cksel = LVDPLLCR_CKSEL_DU_DOTCLKIN(rcrtc->index);
- rcar_lvds_write(lvds, LVDPLLCR, LVDPLLCR_PLLON |
LVDPLLCR_OCKSEL_7 | clksel | LVDPLLCR_CLKOUT_ENABLE |
cksel | (lvds_pll[i]->clk_e << 10) |
(lvds_pll[i]->clk_n << 3) | lvds_pll[i]->clk_m);
- if (lvds_pll[i]->div > 0)
rcar_lvds_write(lvds, LVDDIV, LVDDIV_DIVSEL |
LVDDIV_DIVRESET | lvds_pll[i]->div);
- else
rcar_lvds_write(lvds, LVDDIV, 0);
- dev_dbg(lvds->dev, "LVDPLLCR: 0x%x\n",
ioread32(lvds->mmio + LVDPLLCR));
- dev_dbg(lvds->dev, "LVDDIV: 0x%x\n",
ioread32(lvds->mmio + LVDDIV));
+end:
- for (i = 0; i < 2; i++)
kfree(lvds_pll[i]);
+}
+static void rcar_lvds_pll_start(struct rcar_lvds *lvds,
struct rcar_du_crtc *rcrtc)
+{
- u32 lvdhcr, lvdcr0;
- rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
LVDCTRCR_CTR0SEL_HSYNC);
- lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1) |
LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
- rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
- rcar_lvds_write(lvds, LVDSTRIPE, 0);
- /* Turn all the channels on. */
- rcar_lvds_write(lvds, LVDCR1,
LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) |
LVDCR1_CLKSTBY);
- /*
* Turn the PLL on, set it to LVDS normal mode, wait for the startup
* delay and turn the output on.
*/
- lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PWD;
- rcar_lvds_write(lvds, LVDCR0, lvdcr0);
- lvdcr0 |= LVDCR0_LVEN;
- rcar_lvds_write(lvds, LVDCR0, lvdcr0);
- lvdcr0 |= LVDCR0_LVRES;
- rcar_lvds_write(lvds, LVDCR0, lvdcr0);
- lvds->enabled = true;
+}
static void rcar_lvds_enable(struct drm_bridge *bridge) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -164,6 +367,7 @@ static void rcar_lvds_enable(struct drm_bridge *bridge) * do we get a state pointer? */ struct drm_crtc *crtc = lvds->bridge.encoder->crtc;
- struct rcar_du_device *rcdu = to_rcar_crtc(crtc)->group->dev; u32 lvdpllcr; u32 lvdhcr; u32 lvdcr0;
@@ -171,6 +375,12 @@ static void rcar_lvds_enable(struct drm_bridge *bridge)
WARN_ON(lvds->enabled);
- if (rcar_du_has(rcdu, RCAR_DU_FEATURE_LVDS_PLL)) {
This should be turned into an LVDS encoder feature bit.
rcar_lvds_pll_pre_start(lvds, to_rcar_crtc(crtc));
rcar_lvds_pll_start(lvds, to_rcar_crtc(crtc));
return;
- }
- ret = clk_prepare_enable(lvds->clock); if (ret < 0) return;
@@ -264,6 +474,7 @@ static void rcar_lvds_disable(struct drm_bridge *bridge)
rcar_lvds_write(lvds, LVDCR0, 0); rcar_lvds_write(lvds, LVDCR1, 0);
rcar_lvds_write(lvds, LVDPLLCR, 0);
clk_disable_unprepare(lvds->clock);
@@ -522,6 +733,7 @@ static const struct of_device_id rcar_lvds_of_table[] = { { .compatible = "renesas,r8a7795-lvds", .data = &rcar_lvds_gen3_info }, { .compatible = "renesas,r8a7796-lvds", .data = &rcar_lvds_gen3_info }, { .compatible = "renesas,r8a77970-lvds", .data = &rcar_lvds_r8a77970_info },
- { .compatible = "renesas,r8a77995-lvds", .data = &rcar_lvds_gen3_info },
{ } };
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h index 2896835..e37db95 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h @@ -21,7 +21,7 @@ #define LVDCR0_PLLON (1 << 4) #define LVDCR0_PWD (1 << 2) /* Gen3 only */ #define LVDCR0_BEN (1 << 2) /* Gen2 only */ -#define LVDCR0_LVEN (1 << 1) /* Gen2 only */ +#define LVDCR0_LVEN (1 << 1) #define LVDCR0_LVRES (1 << 0)
#define LVDCR1 0x0004 @@ -46,6 +46,24 @@ #define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) #define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0)
+/* R-Car D3 */ +#define LVDPLLCR_PLLON (1 << 22) +#define LVDPLLCR_PLLSEL_PLL0 (0 << 20) +#define LVDPLLCR_PLLSEL_LVX (1 << 20) +#define LVDPLLCR_PLLSEL_PLL1 (2 << 20) +#define LVDPLLCR_CKSEL_LVX (1 << 17) +#define LVDPLLCR_CKSEL_EXTAL (3 << 17) +#define LVDPLLCR_CKSEL_DU_DOTCLKIN0 (5 << 17) +#define LVDPLLCR_CKSEL_DU_DOTCLKIN1 (7 << 17) +#define LVDPLLCR_OCKSEL_7 (0 << 16) +#define LVDPLLCR_OCKSEL_NOT_DIVIDED (1 << 16) +#define LVDPLLCR_STP_CLKOUTE1_DIS (0 << 14) +#define LVDPLLCR_STP_CLKOUTE1_EN (1 << 14) +#define LVDPLLCR_OUTCLKSEL_BEFORE (0 << 12) +#define LVDPLLCR_OUTCLKSEL_AFTER (1 << 12) +#define LVDPLLCR_CLKOUT_DISABLE (0 << 11) +#define LVDPLLCR_CLKOUT_ENABLE (1 << 11)
#define LVDCTRCR 0x000c #define LVDCTRCR_CTR3SEL_ZERO (0 << 12) #define LVDCTRCR_CTR3SEL_ODD (1 << 12) @@ -74,4 +92,30 @@ #define LVDCHCR_CHSEL_CH(n, c) ((((c) - (n)) & 3) << ((n) * 4)) #define LVDCHCR_CHSEL_MASK(n) (3 << ((n) * 4))
+#define LVDSTRIPE 0x0014 +#define LVDSTRIPE_ST_TRGSEL_DISP (0 << 2) +#define LVDSTRIPE_ST_TRGSEL_HSYNC_R (1 << 2) +#define LVDSTRIPE_ST_TRGSEL_HSYNC_F (2 << 2)
+#define LVDSTRIPE_ST_SWAP_NORMAL (0 << 1) +#define LVDSTRIPE_ST_SWAP_SWAP (1 << 1) +#define LVDSTRIPE_ST_ON (1 << 0)
+#define LVDSCR 0x0018 +#define LVDSCR_DEPTH_DP1 (0 << 29) +#define LVDSCR_DEPTH_DP2 (1 << 29) +#define LVDSCR_DEPTH_DP3 (2 << 29) +#define LVDSCR_BANDSET_10KHZ_LESS_THAN (1 << 28) +#define LVDSCR_SDIV_SR1 (0 << 22) +#define LVDSCR_SDIV_SR2 (1 << 22) +#define LVDSCR_SDIV_SR4 (2 << 22) +#define LVDSCR_SDIV_SR8 (3 << 22) +#define LVDSCR_MODE_DOWN (1 << 21) +#define LVDSCR_RSTN_ENABLE (1 << 20)
+#define LVDDIV 0x001c +#define LVDDIV_DIVSEL (1 << 8) +#define LVDDIV_DIVRESET (1 << 7) +#define LVDDIV_DIVSTP (1 << 6)
#endif /* __RCAR_LVDS_REGS_H__ */
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds the option to specify a maximal clock and a minimal vertical refresh rate.
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com [uli: renamed properties, fixed transposed parsing] Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu --- drivers/gpu/drm/bridge/adv7511/adv7511.h | 7 +++++++ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 73d8ccb..7f29d4f 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -271,6 +271,8 @@ enum adv7511_sync_polarity { * @sync_pulse: Select the sync pulse * @vsync_polarity: vsync input signal configuration * @hsync_polarity: hsync input signal configuration + * @min_vrefresh_option: min vrefresh option + * @max_freq_option: max frequency option */ struct adv7511_link_config { unsigned int input_color_depth; @@ -285,6 +287,9 @@ struct adv7511_link_config { enum adv7511_input_sync_pulse sync_pulse; enum adv7511_sync_polarity vsync_polarity; enum adv7511_sync_polarity hsync_polarity; + + unsigned int min_vrefresh_option; + unsigned int max_freq_option; };
/** @@ -354,6 +359,8 @@ struct adv7511 { enum adv7511_sync_polarity vsync_polarity; enum adv7511_sync_polarity hsync_polarity; bool rgb; + unsigned int min_vref; + unsigned int max_freq;
struct gpio_desc *gpio_pd;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 6437b87..2938b02 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -323,6 +323,8 @@ static void adv7511_set_link_config(struct adv7511 *adv7511, adv7511->hsync_polarity = config->hsync_polarity; adv7511->vsync_polarity = config->vsync_polarity; adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; + adv7511->min_vref = config->min_vrefresh_option; + adv7511->max_freq = config->max_freq_option; }
static void __adv7511_power_on(struct adv7511 *adv7511) @@ -660,6 +662,16 @@ static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, if (mode->clock > 165000) return MODE_CLOCK_HIGH;
+ if (adv7511->max_freq) { + if (mode->clock > (adv7511->max_freq / 1000)) + return MODE_CLOCK_HIGH; + } + + if (adv7511->min_vref) { + if (drm_mode_vrefresh(mode) < adv7511->min_vref) + return MODE_BAD; + } + return MODE_OK; }
@@ -1074,6 +1086,16 @@ static int adv7511_parse_dt(struct device_node *np, config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
+ ret = of_property_read_u32(np, "max-clock", + &config->max_freq_option); + if (ret < 0) + config->max_freq_option = 0; + + ret = of_property_read_u32(np, "min-vrefresh", + &config->min_vrefresh_option); + if (ret < 0) + config->min_vrefresh_option = 0; + return 0; }
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:49:59 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds the option to specify a maximal clock and a minimal vertical refresh rate.
What is this needed for ?
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com [uli: renamed properties, fixed transposed parsing] Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu
drivers/gpu/drm/bridge/adv7511/adv7511.h | 7 +++++++ drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 22 ++++++++++++++++++++++
You're missing updates to the DT bindings.
2 files changed, 29 insertions(+)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 73d8ccb..7f29d4f 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -271,6 +271,8 @@ enum adv7511_sync_polarity {
- @sync_pulse: Select the sync pulse
- @vsync_polarity: vsync input signal configuration
- @hsync_polarity: hsync input signal configuration
- @min_vrefresh_option: min vrefresh option
*/
- @max_freq_option: max frequency option
struct adv7511_link_config { unsigned int input_color_depth; @@ -285,6 +287,9 @@ struct adv7511_link_config { enum adv7511_input_sync_pulse sync_pulse; enum adv7511_sync_polarity vsync_polarity; enum adv7511_sync_polarity hsync_polarity;
- unsigned int min_vrefresh_option;
- unsigned int max_freq_option;
};
/** @@ -354,6 +359,8 @@ struct adv7511 { enum adv7511_sync_polarity vsync_polarity; enum adv7511_sync_polarity hsync_polarity; bool rgb;
unsigned int min_vref;
unsigned int max_freq;
struct gpio_desc *gpio_pd;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 6437b87..2938b02 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -323,6 +323,8 @@ static void adv7511_set_link_config(struct adv7511 *adv7511, adv7511->hsync_polarity = config->hsync_polarity; adv7511->vsync_polarity = config->vsync_polarity; adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
- adv7511->min_vref = config->min_vrefresh_option;
- adv7511->max_freq = config->max_freq_option;
}
static void __adv7511_power_on(struct adv7511 *adv7511) @@ -660,6 +662,16 @@ static enum drm_mode_status adv7511_mode_valid(struct adv7511 *adv7511, if (mode->clock > 165000) return MODE_CLOCK_HIGH;
- if (adv7511->max_freq) {
if (mode->clock > (adv7511->max_freq / 1000))
return MODE_CLOCK_HIGH;
- }
- if (adv7511->min_vref) {
if (drm_mode_vrefresh(mode) < adv7511->min_vref)
return MODE_BAD;
- }
- return MODE_OK;
}
@@ -1074,6 +1086,16 @@ static int adv7511_parse_dt(struct device_node *np, config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH;
- ret = of_property_read_u32(np, "max-clock",
&config->max_freq_option);
- if (ret < 0)
config->max_freq_option = 0;
- ret = of_property_read_u32(np, "min-vrefresh",
&config->min_vrefresh_option);
- if (ret < 0)
config->min_vrefresh_option = 0;
- return 0;
}
On August 20, 2018 at 11:28 AM Laurent Pinchart laurent.pinchart@ideasonboard.com wrote:
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:49:59 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds the option to specify a maximal clock and a minimal vertical refresh rate.
What is this needed for ?
Somewhere in the chain there is a component that will not tolerate clocks in excess of 135 MHz; if you don't limit it, the default for a 1920x1200 display is somewhere along 148 MHz, and the HDMI signal output is invalid.
CU Uli
Hi Ulrich,
On Tuesday, 21 August 2018 11:03:45 EEST Ulrich Hecht wrote:
On August 20, 2018 at 11:28 AM Laurent Pinchart wrote:
On Tuesday, 14 August 2018 16:49:59 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds the option to specify a maximal clock and a minimal vertical refresh rate.
What is this needed for ?
Somewhere in the chain there is a component that will not tolerate clocks in excess of 135 MHz; if you don't limit it, the default for a 1920x1200 display is somewhere along 148 MHz, and the HDMI signal output is invalid.
Do you know which component that is ?
On August 21, 2018 at 10:09 AM Laurent Pinchart laurent.pinchart@ideasonboard.com wrote:
Hi Ulrich,
On Tuesday, 21 August 2018 11:03:45 EEST Ulrich Hecht wrote:
On August 20, 2018 at 11:28 AM Laurent Pinchart wrote:
On Tuesday, 14 August 2018 16:49:59 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds the option to specify a maximal clock and a minimal vertical refresh rate.
What is this needed for ?
Somewhere in the chain there is a component that will not tolerate clocks in excess of 135 MHz; if you don't limit it, the default for a 1920x1200 display is somewhere along 148 MHz, and the HDMI signal output is invalid.
Do you know which component that is ?
Unfortunately not. It's not the ADV7511, though, that goes up to 225 MHz...
CU Uli
Hi Ulrich,
On Wednesday, 22 August 2018 12:13:59 EEST Ulrich Hecht wrote:
On August 21, 2018 at 10:09 AM Laurent Pinchart wrote:
On Tuesday, 21 August 2018 11:03:45 EEST Ulrich Hecht wrote:
On August 20, 2018 at 11:28 AM Laurent Pinchart wrote:
On Tuesday, 14 August 2018 16:49:59 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch adds the option to specify a maximal clock and a minimal vertical refresh rate.
What is this needed for ?
Somewhere in the chain there is a component that will not tolerate clocks in excess of 135 MHz; if you don't limit it, the default for a 1920x1200 display is somewhere along 148 MHz, and the HDMI signal output is invalid.
Do you know which component that is ?
Unfortunately not. It's not the ADV7511, though, that goes up to 225 MHz...
After investigation, it turns out that the THC63LVD1024 is the culprit, its datasheet reports a maximum operating frequency of 135 MHz.
Do you have any idea what the minimal refresh rate is for ?
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch corrects that the extal clock used with the fixed value is acquired from the device tree. Also, it is possible to select extal or dotclkin for R8A77995 and R8A77990. This patch adds its selection procedure.
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 12 ++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 4 +--- 3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index a903456..4e22d40 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -942,10 +942,22 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, return PTR_ERR(rcrtc->clock); }
+ sprintf(clk_name, "extal"); + clk = devm_clk_get(rcdu->dev, clk_name); + if (!IS_ERR(clk)) { + rcrtc->extclock = clk; + rcrtc->extal_use = true; + } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) { + dev_info(rcdu->dev, "can't get extal clock %u\n", + hwindex); + return -EPROBE_DEFER; + } + sprintf(clk_name, "dclkin.%u", hwindex); clk = devm_clk_get(rcdu->dev, clk_name); if (!IS_ERR(clk)) { rcrtc->extclock = clk; + rcrtc->extal_use = false; } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) { dev_info(rcdu->dev, "can't get external clock %u\n", hwindex); return -EPROBE_DEFER; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 65de551..fa27104 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -45,6 +45,7 @@ struct rcar_du_vsp; * @vsp: VSP feeding video to this CRTC * @vsp_pipe: index of the VSP pipeline feeding video to this CRTC * @lvds_ch: index of LVDS + * @extal_use: extal clock use */ struct rcar_du_crtc { struct drm_crtc crtc; @@ -69,6 +70,7 @@ struct rcar_du_crtc { struct rcar_du_vsp *vsp; unsigned int vsp_pipe; int lvds_ch; + bool extal_use; };
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h index e37db95..4899062 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h @@ -46,15 +46,13 @@ #define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) #define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0)
-/* R-Car D3 */ #define LVDPLLCR_PLLON (1 << 22) #define LVDPLLCR_PLLSEL_PLL0 (0 << 20) #define LVDPLLCR_PLLSEL_LVX (1 << 20) #define LVDPLLCR_PLLSEL_PLL1 (2 << 20) #define LVDPLLCR_CKSEL_LVX (1 << 17) #define LVDPLLCR_CKSEL_EXTAL (3 << 17) -#define LVDPLLCR_CKSEL_DU_DOTCLKIN0 (5 << 17) -#define LVDPLLCR_CKSEL_DU_DOTCLKIN1 (7 << 17) +#define LVDPLLCR_CKSEL_DU_DOTCLKIN(n) ((5 + (n) * 2) << 17) #define LVDPLLCR_OCKSEL_7 (0 << 16) #define LVDPLLCR_OCKSEL_NOT_DIVIDED (1 << 16) #define LVDPLLCR_STP_CLKOUTE1_DIS (0 << 14)
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:50:00 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
This patch corrects that the extal clock used with the fixed value is acquired from the device tree. Also, it is possible to select extal or dotclkin for R8A77995 and R8A77990. This patch adds its selection procedure.
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 12 ++++++++++++ drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_lvds_regs.h | 4 +---
DT bindings are missing for this clock.
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index a903456..4e22d40 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -942,10 +942,22 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, return PTR_ERR(rcrtc->clock); }
- sprintf(clk_name, "extal");
- clk = devm_clk_get(rcdu->dev, clk_name);
Unless I'm mistaken, this clock is specific to the LVDS encoder, it's not used by the DU. Why is it handled in the DU driver ?
- if (!IS_ERR(clk)) {
rcrtc->extclock = clk;
rcrtc->extal_use = true;
- } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) {
dev_info(rcdu->dev, "can't get extal clock %u\n",
hwindex);
return -EPROBE_DEFER;
- }
- sprintf(clk_name, "dclkin.%u", hwindex); clk = devm_clk_get(rcdu->dev, clk_name); if (!IS_ERR(clk)) { rcrtc->extclock = clk;
} else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) { dev_info(rcdu->dev, "can't get external clock %u\n", hwindex); return -EPROBE_DEFER;rcrtc->extal_use = false;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 65de551..fa27104 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -45,6 +45,7 @@ struct rcar_du_vsp;
- @vsp: VSP feeding video to this CRTC
- @vsp_pipe: index of the VSP pipeline feeding video to this CRTC
- @lvds_ch: index of LVDS
*/
- @extal_use: extal clock use
struct rcar_du_crtc { struct drm_crtc crtc; @@ -69,6 +70,7 @@ struct rcar_du_crtc { struct rcar_du_vsp *vsp; unsigned int vsp_pipe; int lvds_ch;
- bool extal_use;
This field is used in patch 04/10... It would be nice to make sure that each commit compiles when submitting a patch series.
};
#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h index e37db95..4899062 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h @@ -46,15 +46,13 @@ #define LVDPLLCR_PLLDIVCNT_148M (0x046c1 << 0) #define LVDPLLCR_PLLDIVCNT_MASK (0x7ffff << 0)
-/* R-Car D3 */ #define LVDPLLCR_PLLON (1 << 22) #define LVDPLLCR_PLLSEL_PLL0 (0 << 20) #define LVDPLLCR_PLLSEL_LVX (1 << 20) #define LVDPLLCR_PLLSEL_PLL1 (2 << 20) #define LVDPLLCR_CKSEL_LVX (1 << 17) #define LVDPLLCR_CKSEL_EXTAL (3 << 17) -#define LVDPLLCR_CKSEL_DU_DOTCLKIN0 (5 << 17) -#define LVDPLLCR_CKSEL_DU_DOTCLKIN1 (7 << 17) +#define LVDPLLCR_CKSEL_DU_DOTCLKIN(n) ((5 + (n) * 2) << 17)
This seems to belong to patch 04/10.
#define LVDPLLCR_OCKSEL_7 (0 << 16) #define LVDPLLCR_OCKSEL_NOT_DIVIDED (1 << 16) #define LVDPLLCR_STP_CLKOUTE1_DIS (0 << 14)
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com Signed-off-by: Takeshi Kihara takeshi.kihara.df@renesas.com Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu --- arch/arm64/boot/dts/renesas/r8a77995-draak.dts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts index a8e8f26..bd5c6fa 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts +++ b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts @@ -2,7 +2,7 @@ /* * Device Tree Source for the Draak board * - * Copyright (C) 2016 Renesas Electronics Corp. + * Copyright (C) 2016-2018 Renesas Electronics Corp. * Copyright (C) 2017 Glider bvba */
@@ -269,8 +269,10 @@
clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>, - <&x12_clk>; - clock-names = "du.0", "du.1", "dclkin.0"; + <&x12_clk>, + <&extal_clk>; + clock-names = "du.0", "du.1", + "dclkin.0", "extal";
ports { port@0 {
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:50:01 EEST Ulrich Hecht wrote:
From: Koji Matsuoka koji.matsuoka.xm@renesas.com
Signed-off-by: Koji Matsuoka koji.matsuoka.xm@renesas.com Signed-off-by: Takeshi Kihara takeshi.kihara.df@renesas.com Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu
arch/arm64/boot/dts/renesas/r8a77995-draak.dts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts index a8e8f26..bd5c6fa 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts +++ b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts @@ -2,7 +2,7 @@ /*
- Device Tree Source for the Draak board
- Copyright (C) 2016 Renesas Electronics Corp.
*/
- Copyright (C) 2016-2018 Renesas Electronics Corp.
- Copyright (C) 2017 Glider bvba
@@ -269,8 +269,10 @@
clocks = <&cpg CPG_MOD 724>, <&cpg CPG_MOD 723>,
<&x12_clk>;
- clock-names = "du.0", "du.1", "dclkin.0";
<&x12_clk>,
<&extal_clk>;
- clock-names = "du.0", "du.1",
"dclkin.0", "extal";
This should be moved to the LVDS encoder DT node.
ports { port@0 {
From: Jacopo Mondi jacopo+renesas@jmondi.org
The processor manual prescribes to clear reset of LVDS interface in CPG/MSSR module before display on, and to assert the same reset line at display off time, to have the module resuming in a known state.
The module is said to be in "standby state" at initialization time, and this requires, according to section 37.3.7 of the manual, to de-assert the reset to have it functional.
Based on the original patch from Koji Matsuoka koji.matsuoka.xm@renesas.com
Signed-off-by: Jacopo Mondi jacopo+renesas@jmondi.org Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu --- drivers/gpu/drm/rcar-du/rcar_lvds.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index cd55576..f6a4f9c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -14,6 +14,7 @@ #include <linux/of_device.h> #include <linux/of_graph.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/slab.h>
#include <drm/drm_atomic.h> @@ -55,6 +56,7 @@ struct rcar_lvds {
void __iomem *mmio; struct clk *clock; + struct reset_control *rst; bool enabled;
struct drm_display_mode display_mode; @@ -385,6 +387,12 @@ static void rcar_lvds_enable(struct drm_bridge *bridge) if (ret < 0) return;
+ ret = reset_control_deassert(lvds->rst); + if (ret < 0) { + clk_disable_unprepare(lvds->clock); + return; + } + /* * Hardcode the channels and control signals routing for now. * @@ -476,6 +484,7 @@ static void rcar_lvds_disable(struct drm_bridge *bridge) rcar_lvds_write(lvds, LVDCR1, 0); rcar_lvds_write(lvds, LVDPLLCR, 0);
+ reset_control_assert(lvds->rst); clk_disable_unprepare(lvds->clock);
lvds->enabled = false; @@ -692,6 +701,12 @@ static int rcar_lvds_probe(struct platform_device *pdev) return PTR_ERR(lvds->clock); }
+ lvds->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + if (IS_ERR(lvds->rst)) { + dev_err(&pdev->dev, "failed to get reset\n"); + return PTR_ERR(lvds->rst); + } + drm_bridge_add(&lvds->bridge);
return 0;
From: Kieran Bingham kieran.bingham+renesas@ideasonboard.com
The r8a77995 D3 platform has 2 LVDS channels connected to the DU.
Signed-off-by: Kieran Bingham kieran.bingham+renesas@ideasonboard.com [uli: moved lvds* into the soc node, added PM domains, resets] Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com --- arch/arm64/boot/dts/renesas/r8a77995.dtsi | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995.dtsi b/arch/arm64/boot/dts/renesas/r8a77995.dtsi index 625ba2b..b0652a0 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a77995.dtsi @@ -972,12 +972,68 @@ port@1 { reg = <1>; du_out_lvds0: endpoint { + remote-endpoint = <&lvds0_in>; }; };
port@2 { reg = <2>; du_out_lvds1: endpoint { + remote-endpoint = <&lvds1_in>; + }; + }; + }; + }; + + lvds0: lvds-encoder@feb90000 { + compatible = "renesas,r8a77995-lvds"; + reg = <0 0xfeb90000 0 0x20>; + clocks = <&cpg CPG_MOD 727>; + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; + resets = <&cpg 727>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_in: endpoint { + remote-endpoint = <&du_out_lvds0>; + }; + }; + + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; + + lvds1: lvds-encoder@feb90100 { + compatible = "renesas,r8a77995-lvds"; + reg = <0 0xfeb90100 0 0x20>; + clocks = <&cpg CPG_MOD 727>; + power-domains = <&sysc R8A77995_PD_ALWAYS_ON>; + resets = <&cpg 726>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds1_in: endpoint { + remote-endpoint = <&du_out_lvds1>; + }; + }; + + port@1 { + reg = <1>; + lvds1_out: endpoint { }; }; };
Adds LVDS decoder, HDMI encoder and connector for Draak boards.
Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com --- arch/arm64/boot/dts/renesas/r8a77995-draak.dts | 84 ++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts index bd5c6fa..157adf9 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts +++ b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts @@ -24,6 +24,41 @@ stdout-path = "serial0:115200n8"; };
+ lvds-decoder { + compatible = "thine,thc63lvd1024"; + vcc-supply = <®_3p3v>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + thc63lvd1024_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + + port@2 { + reg = <2>; + thc63lvd1024_out: endpoint { + remote-endpoint = <&adv7511_in>; + }; + }; + }; + }; + + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_out: endpoint { + remote-endpoint = <&adv7511_out>; + }; + }; + }; + vga { compatible = "vga-connector";
@@ -218,6 +253,43 @@
};
+ hdmi@39 { + compatible = "adi,adv7511w"; + reg = <0x39>, <0x3f>, <0x38>, <0x3c>; + reg-names = "main", "edid", "packet", "cec"; + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + + /* Depends on LVDS */ + max-clock = <135000000>; + min-vrefresh = <50>; + + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + adi,input-style = <1>; + adi,input-justification = "evenly"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7511_in: endpoint { + remote-endpoint = <&thc63lvd1024_out>; + }; + }; + + port@1 { + reg = <1>; + adv7511_out: endpoint { + remote-endpoint = <&hdmi_con_out>; + }; + }; + }; + }; + hdmi-decoder@4c { compatible = "adi,adv7612"; reg = <0x4c>; @@ -283,6 +355,18 @@ }; };
+&lvds0 { + status = "okay"; + + ports { + port@1 { + lvds0_out: endpoint { + remote-endpoint = <&thc63lvd1024_in>; + }; + }; + }; +}; + &ehci0 { status = "okay"; };
Hi Ulrich,
Thank you for the patch.
On Tuesday, 14 August 2018 16:50:04 EEST Ulrich Hecht wrote:
Adds LVDS decoder, HDMI encoder and connector for Draak boards.
Signed-off-by: Ulrich Hecht uli+renesas@fpond.eu Reviewed-by: Laurent Pinchart laurent.pinchart@ideasonboard.com
I'm afraid I'll have to revoke that, as it applied to the patch before the addition of the max-clock and min-vrefresh properties. Let's discuss them in replies to patch 05/10 in this series.
arch/arm64/boot/dts/renesas/r8a77995-draak.dts | 84 +++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts index bd5c6fa..157adf9 100644 --- a/arch/arm64/boot/dts/renesas/r8a77995-draak.dts +++ b/arch/arm64/boot/dts/renesas/r8a77995-draak.dts @@ -24,6 +24,41 @@ stdout-path = "serial0:115200n8"; };
- lvds-decoder {
compatible = "thine,thc63lvd1024";
vcc-supply = <®_3p3v>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
thc63lvd1024_in: endpoint {
remote-endpoint = <&lvds0_out>;
};
};
port@2 {
reg = <2>;
thc63lvd1024_out: endpoint {
remote-endpoint = <&adv7511_in>;
};
};
};
- };
- hdmi-out {
compatible = "hdmi-connector";
type = "a";
port {
hdmi_con_out: endpoint {
remote-endpoint = <&adv7511_out>;
};
};
- };
- vga { compatible = "vga-connector";
@@ -218,6 +253,43 @@
};
- hdmi@39 {
compatible = "adi,adv7511w";
reg = <0x39>, <0x3f>, <0x38>, <0x3c>;
reg-names = "main", "edid", "packet", "cec";
interrupt-parent = <&gpio1>;
interrupts = <28 IRQ_TYPE_LEVEL_LOW>;
/* Depends on LVDS */
max-clock = <135000000>;
min-vrefresh = <50>;
adi,input-depth = <8>;
adi,input-colorspace = "rgb";
adi,input-clock = "1x";
adi,input-style = <1>;
adi,input-justification = "evenly";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
adv7511_in: endpoint {
remote-endpoint = <&thc63lvd1024_out>;
};
};
port@1 {
reg = <1>;
adv7511_out: endpoint {
remote-endpoint = <&hdmi_con_out>;
};
};
};
- };
- hdmi-decoder@4c { compatible = "adi,adv7612"; reg = <0x4c>;
@@ -283,6 +355,18 @@ }; };
+&lvds0 {
- status = "okay";
- ports {
port@1 {
lvds0_out: endpoint {
remote-endpoint = <&thc63lvd1024_in>;
};
};
- };
+};
&ehci0 { status = "okay"; };
Hi Ulrich,
Thank you for the patches.
On Tuesday, 14 August 2018 16:49:54 EEST Ulrich Hecht wrote:
Hi!
This is a prototype extension of the series "R-Car D3 LVDS/HDMI support" that includes an up-port of the LVDS PLL support in the BSP.
While this is prototype-quality code, there are in my judgment no serious hacks in it. The most significant deviation in behavior between this and the BSP code is that the LVDS PLL setup is not done in two steps, but in one go as the LVDS device is enabled. This was easier to implement, and works just as fine.
Instructions for testing this are found at https://elinux.org/User:Uli/D3_HDMI_Test, including links to git trees based on renesas-drivers and drm-next, as well as config files for each.
The instructions there end with
"4. Boot kernel and observe activity on HDMI display."
Does "activity" mean that I can expect a working HDMI output with a proper image on the display ? :-)
On August 20, 2018 at 11:50 AM Laurent Pinchart laurent.pinchart@ideasonboard.com wrote: On Tuesday, 14 August 2018 16:49:54 EEST Ulrich Hecht wrote:
Instructions for testing this are found at https://elinux.org/User:Uli/D3_HDMI_Test, including links to git trees based on renesas-drivers and drm-next, as well as config files for each.
The instructions there end with
"4. Boot kernel and observe activity on HDMI display."
Does "activity" mean that I can expect a working HDMI output with a proper image on the display ? :-)
Yes, you can. :)
CU Uli
dri-devel@lists.freedesktop.org