From 73eb5476df7207d2416227703f510ae6cc5f2f5f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 2 Mar 2019 18:13:04 +0200 Subject: drm: rcar-du: Support panels connected directly to the DPAD outputs The R-Car DU driver assumes that a bridge is always connected to the DU output. This is valid for the LVDS and HDMI outputs, but the DPAD outputs can be connected directly to a panel, in which case no bridge is available. To support this use case, detect whether the entities connected to the DU DPAD outputs are encoders or panels based on the number of ports of their DT node, and retrieve the corresponding type of DRM objects. For panels, additionally create panel bridge instances. Signed-off-by: Laurent Pinchart Tested-by: Kevin Key Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi --- drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 54 +++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 8ee4e762f4e5..6c91753af7bc 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -28,13 +28,33 @@ static const struct drm_encoder_funcs encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static unsigned int rcar_du_encoder_count_ports(struct device_node *node) +{ + struct device_node *ports; + struct device_node *port; + unsigned int num_ports = 0; + + ports = of_get_child_by_name(node, "ports"); + if (!ports) + ports = of_node_get(node); + + for_each_child_of_node(ports, port) { + if (of_node_name_eq(port, "port")) + num_ports++; + } + + of_node_put(ports); + + return num_ports; +} + int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_output output, struct device_node *enc_node) { struct rcar_du_encoder *renc; struct drm_encoder *encoder; - struct drm_bridge *bridge = NULL; + struct drm_bridge *bridge; int ret; renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); @@ -48,11 +68,33 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n", enc_node, output); - /* Locate the DRM bridge from the encoder DT node. */ - bridge = of_drm_find_bridge(enc_node); - if (!bridge) { - ret = -EPROBE_DEFER; - goto done; + /* + * Locate the DRM bridge from the DT node. For the DPAD outputs, if the + * DT node has a single port, assume that it describes a panel and + * create a panel bridge. + */ + if ((output == RCAR_DU_OUTPUT_DPAD0 || + output == RCAR_DU_OUTPUT_DPAD1) && + rcar_du_encoder_count_ports(enc_node) == 1) { + struct drm_panel *panel = of_drm_find_panel(enc_node); + + if (IS_ERR(panel)) { + ret = PTR_ERR(panel); + goto done; + } + + bridge = devm_drm_panel_bridge_add(rcdu->dev, panel, + DRM_MODE_CONNECTOR_DPI); + if (IS_ERR(bridge)) { + ret = PTR_ERR(bridge); + goto done; + } + } else { + bridge = of_drm_find_bridge(enc_node); + if (!bridge) { + ret = -EPROBE_DEFER; + goto done; + } } ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, -- cgit v1.2.3 From fcb32cbab0dc9b86504405d0c432416d5c3aba91 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 14 Mar 2019 22:04:19 +0000 Subject: drm: rcar-du: crtc: Make local functions static The rcar_du_crtc_mode_valid() and rcar_du_crtc_get_crc_sources() functions are accessed only through a function pointer table. Convert the function definitions to be static to the module. Signed-off-by: Kieran Bingham Reviewed-by: Simon Horman Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 834432cafda8..ba0625fbe62e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -766,8 +766,9 @@ static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc, rcar_du_vsp_atomic_flush(rcrtc); } -enum drm_mode_status rcar_du_crtc_mode_valid(struct drm_crtc *crtc, - const struct drm_display_mode *mode) +static enum drm_mode_status +rcar_du_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); struct rcar_du_device *rcdu = rcrtc->group->dev; @@ -986,8 +987,8 @@ static int rcar_du_crtc_verify_crc_source(struct drm_crtc *crtc, return 0; } -const char *const *rcar_du_crtc_get_crc_sources(struct drm_crtc *crtc, - size_t *count) +static const char *const * +rcar_du_crtc_get_crc_sources(struct drm_crtc *crtc, size_t *count) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); -- cgit v1.2.3 From b1fed71c4a559c7cb191e2cf4942c541e77f049f Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 14 Mar 2019 22:04:20 +0000 Subject: drm: rcar-du: Remove unused prototypes The CRTC suspend and resume functions have been replaced, but the prototypes were not removed. Remove the redundant definitions. Signed-off-by: Kieran Bingham Reviewed-by: Simon Horman Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 92f7d5f3ff80..8780eddd2caa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -102,8 +102,6 @@ enum rcar_du_output { int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, unsigned int hwindex); -void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc); -void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc); void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc); -- cgit v1.2.3 From 167e535438ecc73d299340bb1269616432020dfb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 12 Mar 2019 18:18:17 +0200 Subject: drm: rcar-du: lvds: Fix post-DLL divider calculation The PLL parameters are computed by looping over the range of acceptable M, N and E values, and selecting the combination that produces the output frequency closest to the target. The internal frequency constraints are taken into account by restricting the tested values for the PLL parameters, reducing the search space. The target frequency, however, is only taken into account when computing the post-PLL divider, which can result in a 0 value for the divider when the PLL output frequency being tested is lower than half of the target frequency. Subsequent loops will produce a better set of PLL parameters, but for some of the iterations this can result in a division by 0. Fix it by clamping the divider value. We could instead restrict the E values being tested in the inner loop, but that would require additional calculation that would likely be less efficient as the E parameter can only take three different values. Fixes: c25c01361199 ("drm: rcar-du: lvds: D3/E3 support") Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- drivers/gpu/drm/rcar-du/rcar_lvds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 7ef97b2a6eda..9f5ff1acab4e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -283,7 +283,7 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk, * divider. */ fout = fvco / (1 << e) / div7; - div = DIV_ROUND_CLOSEST(fout, target); + div = max(1UL, DIV_ROUND_CLOSEST(fout, target)); diff = abs(fout / div - target); if (diff < pll->diff) { -- cgit v1.2.3 From b764f2f66ed48c7f0df2c4b1350c7973109a1d14 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 15 Mar 2019 17:01:05 +0000 Subject: drm: rcar-du: Link CRTCs to the DU device The rcar_du_crtc functions have a heavy reliance on the rcar_du_group structure, in many cases just to access the DU device context. To better separate the groups out of the CRTC handling code, give the rcar_du_crtc its own pointer to the device and remove the indirection through the group pointers. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 48 +++++++++++++++++----------------- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 2 +- 3 files changed, 27 insertions(+), 25 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index ba0625fbe62e..2da46e3dc4ae 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -32,21 +32,21 @@ static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; return rcar_du_read(rcdu, rcrtc->mmio_offset + reg); } static void rcar_du_crtc_write(struct rcar_du_crtc *rcrtc, u32 reg, u32 data) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; rcar_du_write(rcdu, rcrtc->mmio_offset + reg, data); } static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; rcar_du_write(rcdu, rcrtc->mmio_offset + reg, rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr); @@ -54,7 +54,7 @@ static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr) static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; rcar_du_write(rcdu, rcrtc->mmio_offset + reg, rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set); @@ -62,7 +62,7 @@ static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set) void rcar_du_crtc_dsysr_clr_set(struct rcar_du_crtc *rcrtc, u32 clr, u32 set) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; rcrtc->dsysr = (rcrtc->dsysr & ~clr) | set; rcar_du_write(rcdu, rcrtc->mmio_offset + DSYSR, rcrtc->dsysr); @@ -157,10 +157,9 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc, } done: - dev_dbg(rcrtc->group->dev->dev, + dev_dbg(rcrtc->dev->dev, "output:%u, fdpll:%u, n:%u, m:%u, diff:%lu\n", - dpll->output, dpll->fdpll, dpll->n, dpll->m, - best_diff); + dpll->output, dpll->fdpll, dpll->n, dpll->m, best_diff); } struct du_clk_params { @@ -212,7 +211,7 @@ static const struct soc_device_attribute rcar_du_r8a7795_es1[] = { static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) { const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode; - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; unsigned long mode_clock = mode->clock * 1000; u32 dsmr; u32 escr; @@ -277,7 +276,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) rcar_du_escr_divider(rcrtc->extclock, mode_clock, ESCR_DCLKSEL_DCLKIN, ¶ms); - dev_dbg(rcrtc->group->dev->dev, "mode clock %lu %s rate %lu\n", + dev_dbg(rcrtc->dev->dev, "mode clock %lu %s rate %lu\n", mode_clock, params.clk == rcrtc->clock ? "cpg" : "ext", params.rate); @@ -285,7 +284,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) escr = params.escr; } - dev_dbg(rcrtc->group->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr); + dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr); rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr); rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? OTAR13 : OTAR02, 0); @@ -333,7 +332,7 @@ plane_format(struct rcar_du_plane *plane) static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) { struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES]; - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; unsigned int num_planes = 0; unsigned int dptsr_planes; unsigned int hwplanes = 0; @@ -463,7 +462,7 @@ static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc) static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; if (wait_event_timeout(rcrtc->flip_wait, !rcar_du_crtc_page_flip_pending(rcrtc), @@ -493,7 +492,7 @@ static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc) rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); /* Enable the VSP compositor. */ - if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_enable(rcrtc); /* Turn vertical blanking interrupt reporting on. */ @@ -564,7 +563,7 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; struct drm_crtc *crtc = &rcrtc->crtc; u32 status; @@ -617,7 +616,7 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) drm_crtc_vblank_off(crtc); /* Disable the VSP compositor. */ - if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_disable(rcrtc); /* @@ -627,7 +626,7 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) * TODO: Find another way to stop the display for DUs that don't support * TVM sync. */ - if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_TVM_SYNC)) + if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_TVM_SYNC)) rcar_du_crtc_dsysr_clr_set(rcrtc, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH); @@ -666,7 +665,7 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(crtc->state); - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; rcar_du_crtc_get(rcrtc); @@ -694,7 +693,7 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(old_state); - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; rcar_du_crtc_stop(rcrtc); rcar_du_crtc_put(rcrtc); @@ -740,7 +739,7 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, */ rcar_du_crtc_get(rcrtc); - if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_atomic_begin(rcrtc); } @@ -762,7 +761,7 @@ static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc, spin_unlock_irqrestore(&dev->event_lock, flags); } - if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) + if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) rcar_du_vsp_atomic_flush(rcrtc); } @@ -771,7 +770,7 @@ rcar_du_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; unsigned int vbp; @@ -803,7 +802,7 @@ static const struct drm_crtc_helper_funcs crtc_helper_funcs = { static void rcar_du_crtc_crc_init(struct rcar_du_crtc *rcrtc) { - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; const char **sources; unsigned int count; int i = -1; @@ -1085,7 +1084,7 @@ static const struct drm_crtc_funcs crtc_funcs_gen3 = { static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) { struct rcar_du_crtc *rcrtc = arg; - struct rcar_du_device *rcdu = rcrtc->group->dev; + struct rcar_du_device *rcdu = rcrtc->dev; irqreturn_t ret = IRQ_NONE; u32 status; @@ -1177,6 +1176,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int swindex, init_waitqueue_head(&rcrtc->vblank_wait); spin_lock_init(&rcrtc->vblank_lock); + rcrtc->dev = rcdu; rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[hwindex]; rcrtc->index = hwindex; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 8780eddd2caa..3b7fc668996f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -25,6 +25,7 @@ struct rcar_du_vsp; /** * struct rcar_du_crtc - the CRTC, representing a DU superposition processor * @crtc: base DRM CRTC + * @dev: the DU device * @clock: the CRTC functional clock * @extclock: external pixel dot clock (optional) * @mmio_offset: offset of the CRTC registers in the DU MMIO block @@ -45,6 +46,7 @@ struct rcar_du_vsp; struct rcar_du_crtc { struct drm_crtc crtc; + struct rcar_du_device *dev; struct clk *clock; struct clk *extclock; unsigned int mmio_offset; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index 4c8bed34838c..5e4faf258c31 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -47,7 +47,7 @@ static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc) void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) { const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode; - struct rcar_du_device *rcdu = crtc->group->dev; + struct rcar_du_device *rcdu = crtc->dev; struct vsp1_du_lif_config cfg = { .width = mode->hdisplay, .height = mode->vdisplay, -- cgit v1.2.3 From 871370308675e477abd57a69ce66ca4730a4249c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 3 Mar 2019 22:29:21 +0200 Subject: drm: rcar-du: lvds: Adjust operating frequency for D3 and E3 The D3 and E3 SoCs have different pixel clock frequency limits for the LVDS encoder than the other SoCs in the Gen3 family. Adjust the mode fixup implementation accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- drivers/gpu/drm/rcar-du/rcar_lvds.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 9f5ff1acab4e..9d8058d5c20a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -531,11 +531,16 @@ static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); + int min_freq; + /* * The internal LVDS encoder has a restricted clock frequency operating - * range (31MHz to 148.5MHz). Clamp the clock accordingly. + * range, from 5MHz to 148.5MHz on D3 and E3, and from 31MHz to + * 148.5MHz on all other platforms. Clamp the clock accordingly. */ - adjusted_mode->clock = clamp(adjusted_mode->clock, 31000, 148500); + min_freq = lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL ? 5000 : 31000; + adjusted_mode->clock = clamp(adjusted_mode->clock, min_freq, 148500); return true; } -- cgit v1.2.3 From 00d082cc4ea6e42ec4fed832a1020231bb1ca150 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 6 Mar 2019 22:48:35 +0200 Subject: drm: rcar-du: lvds: Set LVEN and LVRES bits together on D3 On the D3 SoC the LVDS PHY must be enabled in the same register write that enables the LVDS output. Skip writing the LVEN bit independently on that platform, it will be set by the write that sets LVRES. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi --- drivers/gpu/drm/rcar-du/rcar_lvds.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm') diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 9d8058d5c20a..620b51aab291 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -485,9 +485,13 @@ static void rcar_lvds_enable(struct drm_bridge *bridge) } if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) { - /* Turn on the LVDS PHY. */ + /* + * Turn on the LVDS PHY. On D3, the LVEN and LVRES bit must be + * set at the same time, so don't write the register yet. + */ lvdcr0 |= LVDCR0_LVEN; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); + if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_PWD)) + rcar_lvds_write(lvds, LVDCR0, lvdcr0); } if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { -- cgit v1.2.3