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

Commit a02b5a15 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'imx-drm-next-2016-08-12' of git://git.pengutronix.de/git/pza/linux into drm-next

imx-drm updates and encoder atomic_mode_set helper callback

- add pixel clock and DE polarity configuration from device tree
  using display timing bindings for parallel and LVDS output
- cleanup/remove trivial functions
- cleanup and fixes in preparation for capture support
- add atomic_mode_set helper and use it in imx-ldb - this is an
  alternative to the encoder mode_set callback that passes the
  crtc and connector state instead of just the mode. It allows
  drivers to get information from the attached connector without
  having to iterate over all connectors
- add drm_bridge support to imx-ldb, for bridges attached via LVDS

* tag 'imx-drm-next-2016-08-12' of git://git.pengutronix.de/git/pza/linux:
  drm/imx-ldb: Add support to drm-bridge
  drm/imx: imx-ldb: use encoder atomic_mode_set callback
  drm/atomic-helper: Add atomic_mode_set helper callback
  drm/imx: Remove imx_drm_handle_vblank()
  gpu: ipu-v3: Add missing IDMAC channel names
  gpu: ipu-v3: rename CSI client device
  gpu: ipu-v3: Fix IRT usage
  gpu: ipu-v3: Fix CSI data format for 16-bit media bus formats
  gpu: ipu-v3: set correct full sensor frame for PAL/NTSC
  gpu: ipu-v3: Add VDI input IDMAC channels
  gpu: ipu-v3: Add ipu_get_num()
  gpu: ipu-cpmem: Add ipu_cpmem_get_burstsize()
  gpu: ipu-cpmem: Add ipu_cpmem_set_uv_offset()
  drm/imx: Remove imx_drm_crtc_id()
  drm/imx: Remove imx_drm_crtc_vblank_get/_put()
  drm/imx: convey the pixelclk-active and de-active flags from DT to the ipu-di driver
  drm: add a helper function to extract 'de-active' and 'pixelclk-active' from DT
parents c13eb931 dc80d703
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -886,8 +886,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
		 * Each encoder has at most one connector (since we always steal
		 * it away), so we won't call mode_set hooks twice.
		 */
		if (funcs && funcs->mode_set)
		if (funcs && funcs->atomic_mode_set) {
			funcs->atomic_mode_set(encoder, new_crtc_state,
					       connector->state);
		} else if (funcs && funcs->mode_set) {
			funcs->mode_set(encoder, mode, adjusted_mode);
		}

		drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
	}
+19 −1
Original line number Diff line number Diff line
@@ -657,6 +657,21 @@ void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
}
EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);

void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
{
	*bus_flags = 0;
	if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
		*bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
	if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
		*bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;

	if (vm->flags & DISPLAY_FLAGS_DE_LOW)
		*bus_flags |= DRM_BUS_FLAG_DE_LOW;
	if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
		*bus_flags |= DRM_BUS_FLAG_DE_HIGH;
}
EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);

#ifdef CONFIG_OF
/**
 * of_get_drm_display_mode - get a drm_display_mode from devicetree
@@ -672,7 +687,8 @@ EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
 * 0 on success, a negative errno code when no of videomode node was found.
 */
int of_get_drm_display_mode(struct device_node *np,
			    struct drm_display_mode *dmode, int index)
			    struct drm_display_mode *dmode, u32 *bus_flags,
			    int index)
{
	struct videomode vm;
	int ret;
@@ -682,6 +698,8 @@ int of_get_drm_display_mode(struct device_node *np,
		return ret;

	drm_display_mode_from_videomode(&vm, dmode);
	if (bus_flags)
		drm_bus_flags_from_videomode(&vm, bus_flags);

	pr_debug("%s: got %dx%d display mode from %s\n",
		of_node_full_name(np), vm.hactive, vm.vactive, np->name);
+0 −24
Original line number Diff line number Diff line
@@ -58,12 +58,6 @@ static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
#endif

unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
{
	return drm_crtc_index(crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_id);

static void imx_drm_driver_lastclose(struct drm_device *drm)
{
	struct imx_drm_device *imxdrm = drm->dev_private;
@@ -90,24 +84,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
	return 0;
}

int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
{
	return drm_crtc_vblank_get(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);

void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
{
	drm_crtc_vblank_put(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);

void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
{
	drm_crtc_handle_vblank(imx_drm_crtc->crtc);
}
EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);

static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
	struct imx_drm_device *imxdrm = drm->dev_private;
+0 −6
Original line number Diff line number Diff line
@@ -13,8 +13,6 @@ struct drm_plane;
struct imx_drm_crtc;
struct platform_device;

unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc);

struct imx_crtc_state {
	struct drm_crtc_state			base;
	u32					bus_format;
@@ -44,10 +42,6 @@ int imx_drm_init_drm(struct platform_device *pdev,
		int preferred_bpp);
int imx_drm_exit_drm(void);

int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);

void imx_drm_mode_config_init(struct drm_device *drm);

struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
+96 −55
Original line number Diff line number Diff line
@@ -57,7 +57,11 @@ struct imx_ldb_channel {
	struct imx_ldb *ldb;
	struct drm_connector connector;
	struct drm_encoder encoder;

	/* Defines what is connected to the ldb, only one at a time */
	struct drm_panel *panel;
	struct drm_bridge *bridge;

	struct device_node *child;
	struct i2c_adapter *ddc;
	int chno;
@@ -66,6 +70,7 @@ struct imx_ldb_channel {
	struct drm_display_mode mode;
	int mode_valid;
	u32 bus_format;
	u32 bus_flags;
};

static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c)
@@ -251,11 +256,13 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
	drm_panel_enable(imx_ldb_ch->panel);
}

static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
			 struct drm_display_mode *orig_mode,
			 struct drm_display_mode *mode)
static void
imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
				struct drm_crtc_state *crtc_state,
				struct drm_connector_state *connector_state)
{
	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
	struct drm_display_mode *mode = &crtc_state->adjusted_mode;
	struct imx_ldb *ldb = imx_ldb_ch->ldb;
	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
	unsigned long serial_clk;
@@ -297,17 +304,11 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
	}

	if (!bus_format) {
		struct drm_connector *connector;

		drm_for_each_connector(connector, encoder->dev) {
		struct drm_connector *connector = connector_state->connector;
		struct drm_display_info *di = &connector->display_info;

			if (connector->encoder == encoder &&
			    di->num_bus_formats) {
		if (di->num_bus_formats)
			bus_format = di->bus_formats[0];
				break;
			}
		}
	}
	imx_ldb_ch_set_bus_format(imx_ldb_ch, bus_format);
}
@@ -379,8 +380,13 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
	u32 bus_format = imx_ldb_ch->bus_format;

	/* Bus format description in DT overrides connector display info. */
	if (!bus_format && di->num_bus_formats)
	if (!bus_format && di->num_bus_formats) {
		bus_format = di->bus_formats[0];
		imx_crtc_state->bus_flags = di->bus_flags;
	} else {
		bus_format = imx_ldb_ch->bus_format;
		imx_crtc_state->bus_flags = imx_ldb_ch->bus_flags;
	}
	switch (bus_format) {
	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
		imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
@@ -420,7 +426,7 @@ static const struct drm_encoder_funcs imx_ldb_encoder_funcs = {
};

static const struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
	.mode_set = imx_ldb_encoder_mode_set,
	.atomic_mode_set = imx_ldb_encoder_atomic_mode_set,
	.enable = imx_ldb_encoder_enable,
	.disable = imx_ldb_encoder_disable,
	.atomic_check = imx_ldb_encoder_atomic_check,
@@ -466,10 +472,30 @@ static int imx_ldb_register(struct drm_device *drm,
	drm_encoder_init(drm, encoder, &imx_ldb_encoder_funcs,
			 DRM_MODE_ENCODER_LVDS, NULL);

	if (imx_ldb_ch->bridge) {
		imx_ldb_ch->bridge->encoder = encoder;

		imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
		ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
		if (ret) {
			DRM_ERROR("Failed to initialize bridge with drm\n");
			return ret;
		}
	} else {
		/*
		 * We want to add the connector whenever there is no bridge
		 * that brings its own, not only when there is a panel. For
		 * historical reasons, the ldb driver can also work without
		 * a panel.
		 */
		drm_connector_helper_add(&imx_ldb_ch->connector,
				&imx_ldb_connector_helper_funcs);
		drm_connector_init(drm, &imx_ldb_ch->connector,
			   &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
				&imx_ldb_connector_funcs,
				DRM_MODE_CONNECTOR_LVDS);
		drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
				encoder);
	}

	if (imx_ldb_ch->panel) {
		ret = drm_panel_attach(imx_ldb_ch->panel,
@@ -478,8 +504,6 @@ static int imx_ldb_register(struct drm_device *drm,
			return ret;
	}

	drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, encoder);

	return 0;
}

@@ -548,6 +572,46 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);

static int imx_ldb_panel_ddc(struct device *dev,
		struct imx_ldb_channel *channel, struct device_node *child)
{
	struct device_node *ddc_node;
	const u8 *edidp;
	int ret;

	ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
	if (ddc_node) {
		channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
		of_node_put(ddc_node);
		if (!channel->ddc) {
			dev_warn(dev, "failed to get ddc i2c adapter\n");
			return -EPROBE_DEFER;
		}
	}

	if (!channel->ddc) {
		/* if no DDC available, fallback to hardcoded EDID */
		dev_dbg(dev, "no ddc available\n");

		edidp = of_get_property(child, "edid",
					&channel->edid_len);
		if (edidp) {
			channel->edid = kmemdup(edidp,
						channel->edid_len,
						GFP_KERNEL);
		} else if (!channel->panel) {
			/* fallback to display-timings node */
			ret = of_get_drm_display_mode(child,
						      &channel->mode,
						      &channel->bus_flags,
						      OF_USE_NATIVE_MODE);
			if (!ret)
				channel->mode_valid = 1;
		}
	}
	return 0;
}

static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
	struct drm_device *drm = data;
@@ -555,7 +619,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
	const struct of_device_id *of_id =
			of_match_device(imx_ldb_dt_ids, dev);
	struct device_node *child;
	const u8 *edidp;
	struct imx_ldb *imx_ldb;
	int dual;
	int ret;
@@ -605,7 +668,6 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)

	for_each_child_of_node(np, child) {
		struct imx_ldb_channel *channel;
		struct device_node *ddc_node;
		struct device_node *ep;
		int bus_format;

@@ -638,46 +700,25 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)

			remote = of_graph_get_remote_port_parent(ep);
			of_node_put(ep);
			if (remote)
			if (remote) {
				channel->panel = of_drm_find_panel(remote);
			else
				channel->bridge = of_drm_find_bridge(remote);
			} else
				return -EPROBE_DEFER;
			of_node_put(remote);
			if (!channel->panel) {
				dev_err(dev, "panel not found: %s\n",
					remote->full_name);
				return -EPROBE_DEFER;
			}
		}

		ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0);
		if (ddc_node) {
			channel->ddc = of_find_i2c_adapter_by_node(ddc_node);
			of_node_put(ddc_node);
			if (!channel->ddc) {
				dev_warn(dev, "failed to get ddc i2c adapter\n");
			if (!channel->panel && !channel->bridge) {
				dev_err(dev, "panel/bridge not found: %s\n",
					remote->full_name);
				return -EPROBE_DEFER;
			}
		}

		if (!channel->ddc) {
			/* if no DDC available, fallback to hardcoded EDID */
			dev_dbg(dev, "no ddc available\n");

			edidp = of_get_property(child, "edid",
						&channel->edid_len);
			if (edidp) {
				channel->edid = kmemdup(edidp,
							channel->edid_len,
							GFP_KERNEL);
			} else if (!channel->panel) {
				/* fallback to display-timings node */
				ret = of_get_drm_display_mode(child,
							      &channel->mode,
							      OF_USE_NATIVE_MODE);
				if (!ret)
					channel->mode_valid = 1;
			}
		/* panel ddc only if there is no bridge */
		if (!channel->bridge) {
			ret = imx_ldb_panel_ddc(dev, channel, child);
			if (ret)
				return ret;
		}

		bus_format = of_get_bus_format(dev, child);
Loading