ec1c6ff81e
On R-Car D3 and E3, the LVDS encoder provides the dot (pixel) clock to the DU, regardless of whether the LVDS output is used or not. When using the DPAD (RGB) output, the DU driver thus enables and disables the LVDS PLL manually, while when using the LVDS output, it lets the LVDS bridge driver handle the PLL configuration internally as part of the atomic enable and disable operations. This causes an issue when using the LVDS output. As bridges are disabled before CRTCs, the current implementation violates the enable/disable sequences documented in the hardware datasheet, which requires the dot clock to be enabled before the CRTC is started and disabled after it gets stopped. Fix the problem by enabling/disabling the LVDS PLL manually from the DU regardless of which output is used, and skipping the PLL handling in the LVDS bridge atomic enable and disable operations. This is however not enough. Disabling the LVDS encoder while leaving the PLL on still results in a vertical blanking wait timeout when disabling the DU. Investigation showed that the culprit is the LVEN bit. For an unclear reason, clearing the bit when disabling the LVDS encoder blocks vertical blanking interrupts. We thus have to delay disabling the whole LVDS encoder, not just disabling the PLL, until the DU is disabled. We could split the LVDS disable sequence by clearing the LVRES bit in the LVDS bridge atomic disable handler, and delaying the rest of the operations, in order to disable the LVDS output at bridge atomic disable time, before stopping the CRTC. This would make the code more complex, without a clear benefit, so keep the implementation simple(r). Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Reviewed-by: Tomi Valkeinen <tomi.valkeinen+renesas@ideasonboard.com>
42 lines
1.0 KiB
C
42 lines
1.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* R-Car LVDS Encoder
|
|
*
|
|
* Copyright (C) 2013-2018 Renesas Electronics Corporation
|
|
*
|
|
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
|
*/
|
|
|
|
#ifndef __RCAR_LVDS_H__
|
|
#define __RCAR_LVDS_H__
|
|
|
|
struct drm_bridge;
|
|
|
|
#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
|
|
int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq,
|
|
bool dot_clk_only);
|
|
void rcar_lvds_pclk_disable(struct drm_bridge *bridge, bool dot_clk_only);
|
|
bool rcar_lvds_dual_link(struct drm_bridge *bridge);
|
|
bool rcar_lvds_is_connected(struct drm_bridge *bridge);
|
|
#else
|
|
static inline int rcar_lvds_pclk_enable(struct drm_bridge *bridge,
|
|
unsigned long freq, bool dot_clk_only)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
static inline void rcar_lvds_pclk_disable(struct drm_bridge *bridge,
|
|
bool dot_clock_only)
|
|
{
|
|
}
|
|
static inline bool rcar_lvds_dual_link(struct drm_bridge *bridge)
|
|
{
|
|
return false;
|
|
}
|
|
static inline bool rcar_lvds_is_connected(struct drm_bridge *bridge)
|
|
{
|
|
return false;
|
|
}
|
|
#endif /* CONFIG_DRM_RCAR_LVDS */
|
|
|
|
#endif /* __RCAR_LVDS_H__ */
|