Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49f98bc4 authored by Philipp Zabel's avatar Philipp Zabel
Browse files

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: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent e41c5c24
Loading
Loading
Loading
Loading
+22 −9
Original line number Diff line number Diff line
@@ -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)
+6 −3
Original line number Diff line number Diff line
@@ -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);
+75 −36
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
@@ -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,7 +99,7 @@ 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,
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;
@@ -102,17 +107,14 @@ static void imx_ldb_bus_format_translation(struct imx_ldb_channel *imx_ldb_ch,

	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);
+34 −21
Original line number Diff line number Diff line
@@ -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);
+54 −13
Original line number Diff line number Diff line
@@ -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);
}

Loading