From: Philipp Zabel Date: Wed, 6 Jul 2016 12:49:24 +0000 (+0200) Subject: drm/imx: store internal bus configuration in crtc state X-Git-Tag: v4.8-rc1~62^2~17^2~8 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=49f98bc4d44a4;p=karo-tx-linux.git drm/imx: store internal bus configuration in crtc state The internal bus configuration is imx-drm specific crtc state. Store it in imx_crtc_state and let the encoder atomic_check callbacks determine bus_flags, bus_format and the sync pins, possibly taking into account the mode and the connector display info. The custom imx_drm_encoder structure can be replaced again with drm_encoder. Signed-off-by: Philipp Zabel --- diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index dce1ea5f52a8..359cd2765552 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -22,14 +22,17 @@ #include "imx-drm.h" -#define imx_enc_to_imx_hdmi(x) container_of(x, struct imx_hdmi, imx_encoder) - struct imx_hdmi { struct device *dev; - struct imx_drm_encoder imx_encoder; + struct drm_encoder encoder; struct regmap *regmap; }; +static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e) +{ + return container_of(e, struct imx_hdmi, encoder); +} + static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = { { 45250000, { @@ -113,8 +116,7 @@ static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder) static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_hdmi *hdmi = imx_enc_to_imx_hdmi(imx_encoder); + struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder); int mux = drm_of_encoder_active_port_id(hdmi->dev->of_node, encoder); regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, @@ -122,9 +124,23 @@ static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder) mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); } +static int dw_hdmi_imx_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); + + imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + imx_crtc_state->di_hsync_pin = 2; + imx_crtc_state->di_vsync_pin = 3; + + return 0; +} + static const struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = { .enable = dw_hdmi_imx_encoder_enable, .disable = dw_hdmi_imx_encoder_disable, + .atomic_check = dw_hdmi_imx_atomic_check, }; static const struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { @@ -205,10 +221,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master, match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node); plat_data = match->data; hdmi->dev = &pdev->dev; - encoder = &hdmi->imx_encoder.encoder; - hdmi->imx_encoder.bus_format = MEDIA_BUS_FMT_RGB888_1X24; - hdmi->imx_encoder.di_hsync_pin = 2; - hdmi->imx_encoder.di_vsync_pin = 3; + encoder = &hdmi->encoder; irq = platform_get_irq(pdev, 0); if (irq < 0) diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index 39cef15c699b..07d33e45f90f 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -15,15 +15,18 @@ struct platform_device; unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc); -struct imx_drm_encoder { - struct drm_encoder encoder; +struct imx_crtc_state { + struct drm_crtc_state base; u32 bus_format; u32 bus_flags; int di_hsync_pin; int di_vsync_pin; }; -#define enc_to_imx_enc(x) container_of(x, struct imx_drm_encoder, encoder) +static inline struct imx_crtc_state *to_imx_crtc_state(struct drm_crtc_state *s) +{ + return container_of(s, struct imx_crtc_state, base); +} struct imx_drm_crtc_helper_funcs { int (*enable_vblank)(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 9c48c4b23a8c..9ac833540080 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -51,15 +52,13 @@ #define LDB_BGREF_RMODE_INT (1 << 15) #define con_to_imx_ldb_ch(x) container_of(x, struct imx_ldb_channel, connector) -#define imx_enc_to_imx_ldb_ch(x) \ - container_of(x, struct imx_ldb_channel, imx_encoder) struct imx_ldb; struct imx_ldb_channel { struct imx_ldb *ldb; struct drm_connector connector; - struct imx_drm_encoder imx_encoder; + struct drm_encoder encoder; struct drm_panel *panel; struct device_node *child; struct i2c_adapter *ddc; @@ -68,8 +67,14 @@ struct imx_ldb_channel { int edid_len; struct drm_display_mode mode; int mode_valid; + u32 bus_format; }; +static inline struct imx_ldb_channel *enc_to_imx_ldb_ch(struct drm_encoder *e) +{ + return container_of(e, struct imx_ldb_channel, encoder); +} + struct bus_mux { int reg; int shift; @@ -94,25 +99,22 @@ static enum drm_connector_status imx_ldb_connector_detect( return connector_status_connected; } -static void imx_ldb_bus_format_translation(struct imx_ldb_channel *imx_ldb_ch, - u32 bus_format) +static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch, + u32 bus_format) { struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; switch (bus_format) { case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: - imx_ldb_ch->imx_encoder.bus_format = MEDIA_BUS_FMT_RGB666_1X18; break; case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: - imx_ldb_ch->imx_encoder.bus_format = MEDIA_BUS_FMT_RGB888_1X24; if (imx_ldb_ch->chno == 0 || dual) ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24; if (imx_ldb_ch->chno == 1 || dual) ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24; break; case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: - imx_ldb_ch->imx_encoder.bus_format = MEDIA_BUS_FMT_RGB888_1X24; if (imx_ldb_ch->chno == 0 || dual) ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 | LDB_BIT_MAP_CH0_JEIDA; @@ -130,12 +132,7 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && imx_ldb_ch->panel->funcs->get_modes) { - struct drm_display_info *di = &connector->display_info; - num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); - if (!imx_ldb_ch->imx_encoder.bus_format && di->num_bus_formats) - imx_ldb_bus_format_translation(imx_ldb_ch, - di->bus_formats[0]); if (num_modes > 0) return num_modes; } @@ -169,7 +166,7 @@ static struct drm_encoder *imx_ldb_connector_best_encoder( { struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); - return &imx_ldb_ch->imx_encoder.encoder; + return &imx_ldb_ch->encoder; } static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, @@ -202,8 +199,7 @@ static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno, static void imx_ldb_encoder_enable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_ldb_channel *imx_ldb_ch = imx_enc_to_imx_ldb_ch(imx_encoder); + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder); @@ -256,13 +252,13 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *orig_mode, struct drm_display_mode *mode) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_ldb_channel *imx_ldb_ch = imx_enc_to_imx_ldb_ch(imx_encoder); + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; unsigned long serial_clk; unsigned long di_clk = mode->clock * 1000; int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder); + u32 bus_format = imx_ldb_ch->bus_format; if (mode->clock > 170000) { dev_warn(ldb->dev, @@ -284,24 +280,41 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, } /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ - if (imx_ldb_ch == &ldb->channel[0]) { + if (imx_ldb_ch == &ldb->channel[0] || dual) { if (mode->flags & DRM_MODE_FLAG_NVSYNC) ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW; else if (mode->flags & DRM_MODE_FLAG_PVSYNC) ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW; } - if (imx_ldb_ch == &ldb->channel[1]) { + if (imx_ldb_ch == &ldb->channel[1] || dual) { if (mode->flags & DRM_MODE_FLAG_NVSYNC) ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW; else if (mode->flags & DRM_MODE_FLAG_PVSYNC) ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW; } + + if (!bus_format) { + struct drm_connector_state *conn_state; + struct drm_connector *connector; + int i; + + for_each_connector_in_state(encoder->crtc->state->state, + connector, conn_state, i) { + struct drm_display_info *di = &connector->display_info; + + if (conn_state->crtc == encoder->crtc && + di->num_bus_formats) { + bus_format = di->bus_formats[0]; + break; + } + } + } + imx_ldb_ch_set_bus_format(imx_ldb_ch, bus_format); } static void imx_ldb_encoder_disable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_ldb_channel *imx_ldb_ch = imx_enc_to_imx_ldb_ch(imx_encoder); + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int mux, ret; @@ -356,6 +369,37 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) drm_panel_unprepare(imx_ldb_ch->panel); } +static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); + struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); + struct drm_display_info *di = &conn_state->connector->display_info; + u32 bus_format = imx_ldb_ch->bus_format; + + /* Bus format description in DT overrides connector display info. */ + if (!bus_format && di->num_bus_formats) + bus_format = di->bus_formats[0]; + switch (bus_format) { + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18; + break; + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24; + break; + default: + return -EINVAL; + } + + imx_crtc_state->di_hsync_pin = 2; + imx_crtc_state->di_vsync_pin = 3; + + return 0; +} + + static const struct drm_connector_funcs imx_ldb_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, @@ -379,6 +423,7 @@ static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { .mode_set = imx_ldb_encoder_mode_set, .enable = imx_ldb_encoder_enable, .disable = imx_ldb_encoder_disable, + .atomic_check = imx_ldb_encoder_atomic_check, }; static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) @@ -400,10 +445,10 @@ static int imx_ldb_register(struct drm_device *drm, struct imx_ldb_channel *imx_ldb_ch) { struct imx_ldb *ldb = imx_ldb_ch->ldb; + struct drm_encoder *encoder = &imx_ldb_ch->encoder; int ret; - ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->imx_encoder.encoder, - imx_ldb_ch->child); + ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child); if (ret) return ret; @@ -417,10 +462,9 @@ static int imx_ldb_register(struct drm_device *drm, return ret; } - drm_encoder_helper_add(&imx_ldb_ch->imx_encoder.encoder, - &imx_ldb_encoder_helper_funcs); - drm_encoder_init(drm, &imx_ldb_ch->imx_encoder.encoder, - &imx_ldb_encoder_funcs, DRM_MODE_ENCODER_LVDS, NULL); + drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs); + drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs, + DRM_MODE_ENCODER_LVDS, NULL); drm_connector_helper_add(&imx_ldb_ch->connector, &imx_ldb_connector_helper_funcs); @@ -430,8 +474,7 @@ static int imx_ldb_register(struct drm_device *drm, if (imx_ldb_ch->panel) drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector); - drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, - &imx_ldb_ch->imx_encoder.encoder); + drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder); return 0; } @@ -648,10 +691,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) bus_format); return bus_format; } - imx_ldb_bus_format_translation(channel, bus_format); - - channel->imx_encoder.di_hsync_pin = 2; - channel->imx_encoder.di_vsync_pin = 3; + channel->bus_format = bus_format; ret = imx_ldb_register(drm, channel); if (ret) @@ -676,8 +716,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, continue; channel->connector.funcs->destroy(&channel->connector); - channel->imx_encoder.encoder.funcs->destroy( - &channel->imx_encoder.encoder); + channel->encoder.funcs->destroy(&channel->encoder); kfree(channel->edid); i2c_put_adapter(channel->ddc); diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index cd92aac5c3bc..520b31228a6f 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -99,7 +99,6 @@ #define TVE_TVDAC_TEST_MODE_MASK (0x7 << 0) #define con_to_tve(x) container_of(x, struct imx_tve, connector) -#define imx_enc_to_tve(x) container_of(x, struct imx_tve, imx_encoder) enum { TVE_MODE_TVOUT, @@ -108,11 +107,13 @@ enum { struct imx_tve { struct drm_connector connector; - struct imx_drm_encoder imx_encoder; + struct drm_encoder encoder; struct device *dev; spinlock_t lock; /* register lock */ bool enabled; int mode; + int di_hsync_pin; + int di_vsync_pin; struct regmap *regmap; struct regulator *dac_reg; @@ -123,6 +124,11 @@ struct imx_tve { struct clk *di_clk; }; +static inline struct imx_tve *enc_to_tve(struct drm_encoder *e) +{ + return container_of(e, struct imx_tve, encoder); +} + static void tve_lock(void *__tve) __acquires(&tve->lock) { @@ -270,15 +276,14 @@ static struct drm_encoder *imx_tve_connector_best_encoder( { struct imx_tve *tve = con_to_tve(connector); - return &tve->imx_encoder.encoder; + return &tve->encoder; } static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *orig_mode, struct drm_display_mode *mode) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_tve *tve = imx_enc_to_tve(imx_encoder); + struct imx_tve *tve = enc_to_tve(encoder); unsigned long rounded_rate; unsigned long rate; int div = 1; @@ -315,20 +320,32 @@ static void imx_tve_encoder_mode_set(struct drm_encoder *encoder, static void imx_tve_encoder_enable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_tve *tve = imx_enc_to_tve(imx_encoder); + struct imx_tve *tve = enc_to_tve(encoder); tve_enable(tve); } static void imx_tve_encoder_disable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_tve *tve = imx_enc_to_tve(imx_encoder); + struct imx_tve *tve = enc_to_tve(encoder); tve_disable(tve); } +static int imx_tve_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); + struct imx_tve *tve = enc_to_tve(encoder); + + imx_crtc_state->bus_format = MEDIA_BUS_FMT_GBR888_1X24; + imx_crtc_state->di_hsync_pin = tve->di_hsync_pin; + imx_crtc_state->di_vsync_pin = tve->di_vsync_pin; + + return 0; +} + static const struct drm_connector_funcs imx_tve_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, @@ -353,6 +370,7 @@ static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { .mode_set = imx_tve_encoder_mode_set, .enable = imx_tve_encoder_enable, .disable = imx_tve_encoder_disable, + .atomic_check = imx_tve_atomic_check, }; static irqreturn_t imx_tve_irq_handler(int irq, void *data) @@ -470,14 +488,12 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) encoder_type = tve->mode == TVE_MODE_VGA ? DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC; - ret = imx_drm_encoder_parse_of(drm, &tve->imx_encoder.encoder, - tve->dev->of_node); + ret = imx_drm_encoder_parse_of(drm, &tve->encoder, tve->dev->of_node); if (ret) return ret; - drm_encoder_helper_add(&tve->imx_encoder.encoder, - &imx_tve_encoder_helper_funcs); - drm_encoder_init(drm, &tve->imx_encoder.encoder, &imx_tve_encoder_funcs, + drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs); + drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs, encoder_type, NULL); drm_connector_helper_add(&tve->connector, @@ -485,8 +501,7 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_mode_connector_attach_encoder(&tve->connector, - &tve->imx_encoder.encoder); + drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); return 0; } @@ -564,7 +579,7 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) if (tve->mode == TVE_MODE_VGA) { ret = of_property_read_u32(np, "fsl,hsync-pin", - &tve->imx_encoder.di_hsync_pin); + &tve->di_hsync_pin); if (ret < 0) { dev_err(dev, "failed to get vsync pin\n"); @@ -572,14 +587,12 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) } ret |= of_property_read_u32(np, "fsl,vsync-pin", - &tve->imx_encoder.di_vsync_pin); + &tve->di_vsync_pin); if (ret < 0) { dev_err(dev, "failed to get vsync pin\n"); return ret; } - - tve->imx_encoder.bus_format = MEDIA_BUS_FMT_GBR888_1X24; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -668,7 +681,7 @@ static void imx_tve_unbind(struct device *dev, struct device *master, struct imx_tve *tve = dev_get_drvdata(dev); tve->connector.funcs->destroy(&tve->connector); - tve->imx_encoder.encoder.funcs->destroy(&tve->imx_encoder.encoder); + tve->encoder.funcs->destroy(&tve->encoder); if (!IS_ERR(tve->dac_reg)) regulator_disable(tve->dac_reg); diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index 274b0e2f917c..2791ef070e2e 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -75,13 +75,56 @@ static void ipu_crtc_disable(struct drm_crtc *crtc) spin_unlock_irq(&crtc->dev->event_lock); } +static void imx_drm_crtc_reset(struct drm_crtc *crtc) +{ + struct imx_crtc_state *state; + + if (crtc->state) { + if (crtc->state->mode_blob) + drm_property_unreference_blob(crtc->state->mode_blob); + + state = to_imx_crtc_state(crtc->state); + memset(state, 0, sizeof(*state)); + } else { + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return; + crtc->state = &state->base; + } + + state->base.crtc = crtc; +} + +static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct imx_crtc_state *state; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); + + WARN_ON(state->base.crtc != crtc); + state->base.crtc = crtc; + + return &state->base; +} + +static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + __drm_atomic_helper_crtc_destroy_state(state); + kfree(to_imx_crtc_state(state)); +} + static const struct drm_crtc_funcs ipu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = drm_crtc_cleanup, .page_flip = drm_atomic_helper_page_flip, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .reset = imx_drm_crtc_reset, + .atomic_duplicate_state = imx_drm_crtc_duplicate_state, + .atomic_destroy_state = imx_drm_crtc_destroy_state, }; static irqreturn_t ipu_irq_handler(int irq, void *dev_id) @@ -142,9 +185,9 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_encoder *encoder; - struct imx_drm_encoder *imx_encoder = NULL; struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); struct drm_display_mode *mode = &crtc->state->adjusted_mode; + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state); struct ipu_di_signal_cfg sig_cfg = {}; unsigned long encoder_types = 0; @@ -154,10 +197,8 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) mode->vdisplay); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { + if (encoder->crtc == crtc) encoder_types |= BIT(encoder->encoder_type); - imx_encoder = enc_to_imx_enc(encoder); - } } dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n", @@ -176,20 +217,20 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc) else sig_cfg.clkflags = 0; - sig_cfg.enable_pol = !(imx_encoder->bus_flags & DRM_BUS_FLAG_DE_LOW); + sig_cfg.enable_pol = !(imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_LOW); /* Default to driving pixel data on negative clock edges */ - sig_cfg.clk_pol = !!(imx_encoder->bus_flags & + sig_cfg.clk_pol = !!(imx_crtc_state->bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE); - sig_cfg.bus_format = imx_encoder->bus_format; + sig_cfg.bus_format = imx_crtc_state->bus_format; sig_cfg.v_to_h_sync = 0; - sig_cfg.hsync_pin = imx_encoder->di_hsync_pin; - sig_cfg.vsync_pin = imx_encoder->di_vsync_pin; + sig_cfg.hsync_pin = imx_crtc_state->di_hsync_pin; + sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin; drm_display_mode_to_videomode(mode, &sig_cfg.mode); ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, mode->flags & DRM_MODE_FLAG_INTERLACE, - imx_encoder->bus_format, mode->hdisplay); + imx_crtc_state->bus_format, mode->hdisplay); ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); } diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 4a2942ecec17..9da60df5efa7 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -27,19 +27,23 @@ #include "imx-drm.h" #define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector) -#define imx_enc_to_imxpd(x) \ - container_of(x, struct imx_parallel_display, imx_encoder) struct imx_parallel_display { struct drm_connector connector; - struct imx_drm_encoder imx_encoder; + struct drm_encoder encoder; struct device *dev; void *edid; int edid_len; + u32 bus_format; struct drm_display_mode mode; struct drm_panel *panel; }; +static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e) +{ + return container_of(e, struct imx_parallel_display, encoder); +} + static enum drm_connector_status imx_pd_connector_detect( struct drm_connector *connector, bool force) { @@ -54,12 +58,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) if (imxpd->panel && imxpd->panel->funcs && imxpd->panel->funcs->get_modes) { - struct drm_display_info *di = &connector->display_info; - num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); - if (!imxpd->imx_encoder.bus_format && di->num_bus_formats) - imxpd->imx_encoder.bus_format = di->bus_formats[0]; - imxpd->imx_encoder.bus_flags = di->bus_flags; if (num_modes > 0) return num_modes; } @@ -89,13 +88,12 @@ static struct drm_encoder *imx_pd_connector_best_encoder( { struct imx_parallel_display *imxpd = con_to_imxpd(connector); - return &imxpd->imx_encoder.encoder; + return &imxpd->encoder; } static void imx_pd_encoder_enable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_parallel_display *imxpd = imx_enc_to_imxpd(imx_encoder); + struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); drm_panel_prepare(imxpd->panel); drm_panel_enable(imxpd->panel); @@ -103,13 +101,31 @@ static void imx_pd_encoder_enable(struct drm_encoder *encoder) static void imx_pd_encoder_disable(struct drm_encoder *encoder) { - struct imx_drm_encoder *imx_encoder = enc_to_imx_enc(encoder); - struct imx_parallel_display *imxpd = imx_enc_to_imxpd(imx_encoder); + struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); drm_panel_disable(imxpd->panel); drm_panel_unprepare(imxpd->panel); } +static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); + struct drm_display_info *di = &conn_state->connector->display_info; + struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + + imx_crtc_state->bus_flags = di->bus_flags; + if (!imxpd->bus_format && di->num_bus_formats) + imx_crtc_state->bus_format = di->bus_formats[0]; + else + imx_crtc_state->bus_format = imxpd->bus_format; + imx_crtc_state->di_hsync_pin = 2; + imx_crtc_state->di_vsync_pin = 3; + + return 0; +} + static const struct drm_connector_funcs imx_pd_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, @@ -132,15 +148,16 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = { static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { .enable = imx_pd_encoder_enable, .disable = imx_pd_encoder_disable, + .atomic_check = imx_pd_encoder_atomic_check, }; static int imx_pd_register(struct drm_device *drm, struct imx_parallel_display *imxpd) { + struct drm_encoder *encoder = &imxpd->encoder; int ret; - ret = imx_drm_encoder_parse_of(drm, &imxpd->imx_encoder.encoder, - imxpd->dev->of_node); + ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node); if (ret) return ret; @@ -151,10 +168,9 @@ static int imx_pd_register(struct drm_device *drm, */ imxpd->connector.dpms = DRM_MODE_DPMS_OFF; - drm_encoder_helper_add(&imxpd->imx_encoder.encoder, - &imx_pd_encoder_helper_funcs); - drm_encoder_init(drm, &imxpd->imx_encoder.encoder, - &imx_pd_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs); + drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); drm_connector_helper_add(&imxpd->connector, &imx_pd_connector_helper_funcs); @@ -164,8 +180,7 @@ static int imx_pd_register(struct drm_device *drm, if (imxpd->panel) drm_panel_attach(imxpd->panel, &imxpd->connector); - drm_mode_connector_attach_encoder(&imxpd->connector, - &imxpd->imx_encoder.encoder); + drm_mode_connector_attach_encoder(&imxpd->connector, encoder); return 0; } @@ -200,9 +215,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) else if (!strcmp(fmt, "lvds666")) bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; } - imxpd->imx_encoder.bus_format = bus_format; - imxpd->imx_encoder.di_hsync_pin = 2; - imxpd->imx_encoder.di_vsync_pin = 3; + imxpd->bus_format = bus_format; /* port@1 is the output port */ ep = of_graph_get_endpoint_by_regs(np, 1, -1); @@ -235,7 +248,7 @@ static void imx_pd_unbind(struct device *dev, struct device *master, { struct imx_parallel_display *imxpd = dev_get_drvdata(dev); - imxpd->imx_encoder.encoder.funcs->destroy(&imxpd->imx_encoder.encoder); + imxpd->encoder.funcs->destroy(&imxpd->encoder); imxpd->connector.funcs->destroy(&imxpd->connector); kfree(imxpd->edid);