Commit 612c6bd5 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'exynos-drm-next-for-v4.20' of...

Merge tag 'exynos-drm-next-for-v4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next

Add out-bridge support
- This patch series enables out-bridge for LVDS bridge device support,
  and also includes two cleanups and one relevant dt binding update
  for this.

Add Samsung 16x16 tiled format support
- This patch series adds Samsung 16x16 tiled format to scaler and
  gsc drivers. As for this, it adds Samsung specific format to
  drm_forcc.h header. For the git-pull request with relevant patches,
  I requested ack-by[1] to relevant maintainers but there was no any response.
  I'm pretty sure no problem to go to mainline though Exynos tree
  because the only user of it is Exynos.
(airlied: this looked fine to me)

[1] https://patchwork.freedesktop.org/patch/243921/



Add configurable plane alpha and pixel blend mode support
- This patch series makes mixer driver to be configuragle for
  pixel blend mode and plane alpha, which also includes one fixup
  to set all default values correctly after reset.

One cleanup
- This patch replaces drm_atomic_helper_suspend/resume() with
  drm_mode_config_helper_suspend/resume() to remove exynos specific
  suspend_state.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Inki Dae <inki.dae@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1538380891-24040-1-git-send-email-inki.dae@samsung.com
parents b20b515a 6ac99a32
Loading
Loading
Loading
Loading
+6 −19
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ Required properties:
  - samsung,pll-clock-frequency: specifies frequency of the oscillator clock
  - #address-cells, #size-cells: should be set respectively to <1> and <0>
    according to DSI host bindings (see MIPI DSI bindings [1])
  - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
    mode
  - samsung,esc-clock-frequency: specifies DSI frequency in escape mode

Optional properties:
  - power-domains: a phandle to DSIM power domain node
@@ -29,25 +32,9 @@ Child nodes:
  Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).

Video interfaces:
  Device node can contain video interface port nodes according to [2].
  The following are properties specific to those nodes:

  port node inbound:
    - reg: (required) must be 0.
  port node outbound:
    - reg: (required) must be 1.

  endpoint node connected from mic node (reg = 0):
    - remote-endpoint: specifies the endpoint in mic node. This node is required
		       for Exynos5433 mipi dsi. So mic can access to panel node
		       throughout this dsi node.
  endpoint node connected to panel node (reg = 1):
    - remote-endpoint: specifies the endpoint in panel node. This node is
		       required in all kinds of exynos mipi dsi to represent
		       the connection between mipi dsi and panel.
    - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
      mode
    - samsung,esc-clock-frequency: specifies DSI frequency in escape mode
  Device node can contain following video interface port nodes according to [2]:
  0: RGB input,
  1: DSI output

[1]: Documentation/devicetree/bindings/display/mipi-dsi-bus.txt
[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+2 −24
Original line number Diff line number Diff line
@@ -149,37 +149,15 @@ static struct drm_driver exynos_drm_driver = {
static int exynos_drm_suspend(struct device *dev)
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
	struct exynos_drm_private *private;

	if (!drm_dev)
		return 0;

	private = drm_dev->dev_private;

	drm_kms_helper_poll_disable(drm_dev);
	exynos_drm_fbdev_suspend(drm_dev);
	private->suspend_state = drm_atomic_helper_suspend(drm_dev);
	if (IS_ERR(private->suspend_state)) {
		exynos_drm_fbdev_resume(drm_dev);
		drm_kms_helper_poll_enable(drm_dev);
		return PTR_ERR(private->suspend_state);
	}

	return 0;
	return  drm_mode_config_helper_suspend(drm_dev);
}

static void exynos_drm_resume(struct device *dev)
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
	struct exynos_drm_private *private;

	if (!drm_dev)
		return;

	private = drm_dev->dev_private;
	drm_atomic_helper_resume(drm_dev, private->suspend_state);
	exynos_drm_fbdev_resume(drm_dev);
	drm_kms_helper_poll_enable(drm_dev);
	drm_mode_config_helper_resume(drm_dev);
}

static const struct dev_pm_ops exynos_drm_pm_ops = {
+2 −1
Original line number Diff line number Diff line
@@ -92,6 +92,8 @@ struct exynos_drm_plane {
#define EXYNOS_DRM_PLANE_CAP_SCALE	(1 << 1)
#define EXYNOS_DRM_PLANE_CAP_ZPOS	(1 << 2)
#define EXYNOS_DRM_PLANE_CAP_TILE	(1 << 3)
#define EXYNOS_DRM_PLANE_CAP_PIX_BLEND	(1 << 4)
#define EXYNOS_DRM_PLANE_CAP_WIN_BLEND	(1 << 5)

/*
 * Exynos DRM plane configuration structure.
@@ -195,7 +197,6 @@ struct drm_exynos_file_private {
 */
struct exynos_drm_private {
	struct drm_fb_helper *fb_helper;
	struct drm_atomic_state *suspend_state;

	struct device *g2d_dev;
	struct device *dma_dev;
+63 −44
Original line number Diff line number Diff line
@@ -255,6 +255,7 @@ struct exynos_dsi {
	struct mipi_dsi_host dsi_host;
	struct drm_connector connector;
	struct drm_panel *panel;
	struct drm_bridge *out_bridge;
	struct device *dev;

	void __iomem *reg_base;
@@ -279,7 +280,7 @@ struct exynos_dsi {
	struct list_head transfer_list;

	const struct exynos_dsi_driver_data *driver_data;
	struct device_node *bridge_node;
	struct device_node *in_bridge_node;
};

#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
@@ -1382,29 +1383,37 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
		return;

	pm_runtime_get_sync(dsi->dev);

	dsi->state |= DSIM_STATE_ENABLED;

	if (dsi->panel) {
		ret = drm_panel_prepare(dsi->panel);
	if (ret < 0) {
		dsi->state &= ~DSIM_STATE_ENABLED;
		pm_runtime_put_sync(dsi->dev);
		return;
		if (ret < 0)
			goto err_put_sync;
	} else {
		drm_bridge_pre_enable(dsi->out_bridge);
	}

	exynos_dsi_set_display_mode(dsi);
	exynos_dsi_set_display_enable(dsi, true);

	if (dsi->panel) {
		ret = drm_panel_enable(dsi->panel);
	if (ret < 0) {
		dsi->state &= ~DSIM_STATE_ENABLED;
		exynos_dsi_set_display_enable(dsi, false);
		drm_panel_unprepare(dsi->panel);
		pm_runtime_put_sync(dsi->dev);
		return;
		if (ret < 0)
			goto err_display_disable;
	} else {
		drm_bridge_enable(dsi->out_bridge);
	}

	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
	return;

err_display_disable:
	exynos_dsi_set_display_enable(dsi, false);
	drm_panel_unprepare(dsi->panel);

err_put_sync:
	dsi->state &= ~DSIM_STATE_ENABLED;
	pm_runtime_put(dsi->dev);
}

static void exynos_dsi_disable(struct drm_encoder *encoder)
@@ -1417,11 +1426,11 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
	dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;

	drm_panel_disable(dsi->panel);
	drm_bridge_disable(dsi->out_bridge);
	exynos_dsi_set_display_enable(dsi, false);
	drm_panel_unprepare(dsi->panel);

	drm_bridge_post_disable(dsi->out_bridge);
	dsi->state &= ~DSIM_STATE_ENABLED;

	pm_runtime_put_sync(dsi->dev);
}

@@ -1499,7 +1508,30 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
				  struct mipi_dsi_device *device)
{
	struct exynos_dsi *dsi = host_to_dsi(host);
	struct drm_device *drm = dsi->connector.dev;
	struct drm_encoder *encoder = &dsi->encoder;
	struct drm_device *drm = encoder->dev;
	struct drm_bridge *out_bridge;

	out_bridge  = of_drm_find_bridge(device->dev.of_node);
	if (out_bridge) {
		drm_bridge_attach(encoder, out_bridge, NULL);
		dsi->out_bridge = out_bridge;
		encoder->bridge = NULL;
	} else {
		int ret = exynos_dsi_create_connector(encoder);

		if (ret) {
			DRM_ERROR("failed to create connector ret = %d\n", ret);
			drm_encoder_cleanup(encoder);
			return ret;
		}

		dsi->panel = of_drm_find_panel(device->dev.of_node);
		if (dsi->panel) {
			drm_panel_attach(dsi->panel, &dsi->connector);
			dsi->connector.status = connector_status_connected;
		}
	}

	/*
	 * This is a temporary solution and should be made by more generic way.
@@ -1518,14 +1550,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
	dsi->lanes = device->lanes;
	dsi->format = device->format;
	dsi->mode_flags = device->mode_flags;
	dsi->panel = of_drm_find_panel(device->dev.of_node);
	if (IS_ERR(dsi->panel))
		dsi->panel = NULL;

	if (dsi->panel) {
		drm_panel_attach(dsi->panel, &dsi->connector);
		dsi->connector.status = connector_status_connected;
	}
	exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
			!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);

@@ -1541,18 +1565,20 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
				  struct mipi_dsi_device *device)
{
	struct exynos_dsi *dsi = host_to_dsi(host);
	struct drm_device *drm = dsi->connector.dev;

	mutex_lock(&drm->mode_config.mutex);
	struct drm_device *drm = dsi->encoder.dev;

	if (dsi->panel) {
		mutex_lock(&drm->mode_config.mutex);
		exynos_dsi_disable(&dsi->encoder);
		drm_panel_detach(dsi->panel);
		dsi->panel = NULL;
		dsi->connector.status = connector_status_disconnected;
	}

		mutex_unlock(&drm->mode_config.mutex);
	} else {
		if (dsi->out_bridge->funcs->detach)
			dsi->out_bridge->funcs->detach(dsi->out_bridge);
		dsi->out_bridge = NULL;
	}

	if (drm->mode_config.poll_enabled)
		drm_kms_helper_hotplug_event(drm);
@@ -1634,7 +1660,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
	if (ret < 0)
		return ret;

	dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
	dsi->in_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);

	return 0;
}
@@ -1645,7 +1671,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
	struct drm_encoder *encoder = dev_get_drvdata(dev);
	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
	struct drm_device *drm_dev = data;
	struct drm_bridge *bridge;
	struct drm_bridge *in_bridge;
	int ret;

	drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
@@ -1657,17 +1683,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
	if (ret < 0)
		return ret;

	ret = exynos_dsi_create_connector(encoder);
	if (ret) {
		DRM_ERROR("failed to create connector ret = %d\n", ret);
		drm_encoder_cleanup(encoder);
		return ret;
	}

	if (dsi->bridge_node) {
		bridge = of_drm_find_bridge(dsi->bridge_node);
		if (bridge)
			drm_bridge_attach(encoder, bridge, NULL);
	if (dsi->in_bridge_node) {
		in_bridge = of_drm_find_bridge(dsi->in_bridge_node);
		if (in_bridge)
			drm_bridge_attach(encoder, in_bridge, NULL);
	}

	return mipi_dsi_host_register(&dsi->dsi_host);
@@ -1786,7 +1805,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
{
	struct exynos_dsi *dsi = platform_get_drvdata(pdev);

	of_node_put(dsi->bridge_node);
	of_node_put(dsi->in_bridge_node);

	pm_runtime_disable(&pdev->dev);

+0 −17
Original line number Diff line number Diff line
@@ -270,20 +270,3 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
	private->fb_helper = NULL;
}
void exynos_drm_fbdev_suspend(struct drm_device *dev)
{
	struct exynos_drm_private *private = dev->dev_private;

	console_lock();
	drm_fb_helper_set_suspend(private->fb_helper, 1);
	console_unlock();
}

void exynos_drm_fbdev_resume(struct drm_device *dev)
{
	struct exynos_drm_private *private = dev->dev_private;

	console_lock();
	drm_fb_helper_set_suspend(private->fb_helper, 0);
	console_unlock();
}
Loading