Skip to content

Commit

Permalink
drm: rcar-du: Add support for LVDS mode selection
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Laurent Pinchart committed Apr 4, 2017
1 parent bf7149f commit e947ecc
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
27 changes: 27 additions & 0 deletions drivers/gpu/drm/rcar-du/rcar_du_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
struct drm_display_info *info = &conn_state->connector->display_info;
enum rcar_lvds_mode mode;

rcar_du_crtc_route_output(crtc_state->crtc, renc->output);

Expand All @@ -111,6 +113,31 @@ static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
}

renc->connector = to_rcar_connector(conn_state->connector);

if (!info->num_bus_formats || !info->bus_formats) {
dev_err(encoder->dev->dev, "no LVDS bus format reported\n");
return;
}

switch (info->bus_formats[0]) {
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
mode = RCAR_LVDS_MODE_JEIDA;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
mode = RCAR_LVDS_MODE_VESA;
break;
default:
dev_err(encoder->dev->dev,
"unsupported LVDS bus format 0x%04x\n",
info->bus_formats[0]);
return;
}

if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
mode |= RCAR_LVDS_MODE_MIRROR;

rcar_du_lvdsenc_set_mode(renc->lvds, mode);
}

static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
Expand Down
11 changes: 9 additions & 2 deletions drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct rcar_du_lvdsenc {
bool enabled;

enum rcar_lvds_input input;
enum rcar_lvds_mode mode;
};

static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
Expand Down Expand Up @@ -61,7 +62,7 @@ static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
/* Select the input, hardcode mode 0, enable LVDS operation and turn
* bias circuitry on.
*/
lvdcr0 = LVDCR0_BEN | LVDCR0_LVEN;
lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_BEN | LVDCR0_LVEN;
if (rcrtc->index == 2)
lvdcr0 |= LVDCR0_DUSEL;
rcar_lvds_write(lvds, LVDCR0, lvdcr0);
Expand Down Expand Up @@ -114,7 +115,7 @@ static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
* Turn the PLL on, set it to LVDS normal mode, wait for the startup
* delay and turn the output on.
*/
lvdcr0 = LVDCR0_PLLON;
lvdcr0 = (lvds->mode << LVDCR0_LVMD_SHIFT) | LVDCR0_PLLON;
rcar_lvds_write(lvds, LVDCR0, lvdcr0);

lvdcr0 |= LVDCR0_PWD;
Expand Down Expand Up @@ -211,6 +212,12 @@ void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
mode->clock = clamp(mode->clock, 25175, 148500);
}

void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
enum rcar_lvds_mode mode)
{
lvds->mode = mode;
}

static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
struct platform_device *pdev)
{
Expand Down
13 changes: 13 additions & 0 deletions drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,17 @@ enum rcar_lvds_input {
RCAR_LVDS_INPUT_DU2,
};

/* Keep in sync with the LVDCR0.LVMD hardware register values. */
enum rcar_lvds_mode {
RCAR_LVDS_MODE_JEIDA = 0,
RCAR_LVDS_MODE_MIRROR = 1,
RCAR_LVDS_MODE_VESA = 4,
};

#if IS_ENABLED(CONFIG_DRM_RCAR_LVDS)
int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu);
void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
enum rcar_lvds_mode mode);
int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
struct drm_crtc *crtc, bool enable);
void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
Expand All @@ -37,6 +46,10 @@ static inline int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
{
return 0;
}
static inline void rcar_du_lvdsenc_set_mode(struct rcar_du_lvdsenc *lvds,
enum rcar_lvds_mode mode)
{
}
static inline int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds,
struct drm_crtc *crtc, bool enable)
{
Expand Down

0 comments on commit e947ecc

Please sign in to comment.