Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: rcar-du: Add support for LVDS mode selection

Retrieve the LVDS mode from the panel and configure the LVDS encoder
accordingly. LVDS mode selection is static as LVDS panels can't be
hot-plugged on any of the device supported by the driver. Support for
dynamic mode selection can be implemented in the future when needed.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

+49 -2
+27
drivers/gpu/drm/rcar-du/rcar_du_encoder.c
··· 98 98 struct drm_connector_state *conn_state) 99 99 { 100 100 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 101 + struct drm_display_info *info = &conn_state->connector->display_info; 102 + enum rcar_lvds_mode mode; 101 103 102 104 rcar_du_crtc_route_output(crtc_state->crtc, renc->output); 103 105 ··· 113 111 } 114 112 115 113 renc->connector = to_rcar_connector(conn_state->connector); 114 + 115 + if (!info->num_bus_formats || !info->bus_formats) { 116 + dev_err(encoder->dev->dev, "no LVDS bus format reported\n"); 117 + return; 118 + } 119 + 120 + switch (info->bus_formats[0]) { 121 + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 122 + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: 123 + mode = RCAR_LVDS_MODE_JEIDA; 124 + break; 125 + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: 126 + mode = RCAR_LVDS_MODE_VESA; 127 + break; 128 + default: 129 + dev_err(encoder->dev->dev, 130 + "unsupported LVDS bus format 0x%04x\n", 131 + info->bus_formats[0]); 132 + return; 133 + } 134 + 135 + if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB) 136 + mode |= RCAR_LVDS_MODE_MIRROR; 137 + 138 + rcar_du_lvdsenc_set_mode(renc->lvds, mode); 116 139 } 117 140 118 141 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+9 -2
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
··· 31 31 bool enabled; 32 32 33 33 enum rcar_lvds_input input; 34 + enum rcar_lvds_mode mode; 34 35 }; 35 36 36 37 static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data) ··· 62 61 /* Select the input, hardcode mode 0, enable LVDS operation and turn 63 62 * bias circuitry on. 64 63 */ 65 - lvdcr0 = LVDCR0_BEN | LVDCR0_LVEN; 64 + lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN; 66 65 if (rcrtc->index == 2) 67 66 lvdcr0 |= LVDCR0_DUSEL; 68 67 rcar_lvds_write(lvds, LVDCR0, lvdcr0); ··· 115 114 * Turn the PLL on, set it to LVDS normal mode, wait for the startup 116 115 * delay and turn the output on. 117 116 */ 118 - lvdcr0 = LVDCR0_PLLON; 117 + lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON; 119 118 rcar_lvds_write(lvds, LVDCR0, lvdcr0); 120 119 121 120 lvdcr0 |= LVDCR0_PWD; ··· 210 209 mode->clock = clamp(mode->clock, 30000, 150000); 211 210 else 212 211 mode->clock = clamp(mode->clock, 25175, 148500); 212 + } 213 + 214 + void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds, 215 + enum rcar_lvds_mode mode) 216 + { 217 + lvds->mode = mode; 213 218 } 214 219 215 220 static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
+13
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
··· 26 26 RCAR_LVDS_INPUT_DU2, 27 27 }; 28 28 29 + /* Keep in sync with the LVDCR0.LVMD hardware register values. */ 30 + enum rcar_lvds_mode { 31 + RCAR_LVDS_MODE_JEIDA = 0, 32 + RCAR_LVDS_MODE_MIRROR = 1, 33 + RCAR_LVDS_MODE_VESA = 4, 34 + }; 35 + 29 36 #if IS_ENABLED(CONFIG_DRM_RCAR_LVDS) 30 37 int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu); 38 + void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds, 39 + enum rcar_lvds_mode mode); 31 40 int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, 32 41 struct drm_crtc *crtc, bool enable); 33 42 void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds, ··· 45 36 static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu) 46 37 { 47 38 return 0; 39 + } 40 + static inline void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds, 41 + enum rcar_lvds_mode mode) 42 + { 48 43 } 49 44 static inline int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, 50 45 struct drm_crtc *crtc, bool enable)