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

Commit f37cd5e8 authored by Inki Dae's avatar Inki Dae Committed by Inki Dae
Browse files

drm/exynos: add component framework support



This patch adds component framework support to resolve
the probe order issue.

Until now, exynos drm had used codes specific to exynos drm
to resolve that issue so with this patch, the specific codes
are removed.

Signed-off-by: default avatarInki Dae <inki.dae@samsung.com>
parent 121692eb
Loading
Loading
Loading
Loading
+28 −17
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/component.h>
#include <linux/phy/phy.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
@@ -962,16 +963,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
	.best_encoder = exynos_dp_best_encoder,
};

static int exynos_dp_initialize(struct exynos_drm_display *display,
				struct drm_device *drm_dev)
{
	struct exynos_dp_device *dp = display->ctx;

	dp->drm_dev = drm_dev;

	return 0;
}

static bool find_bridge(const char *compat, struct bridge_init *bridge)
{
	bridge->client = NULL;
@@ -1099,7 +1090,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
}

static struct exynos_drm_display_ops exynos_dp_display_ops = {
	.initialize = exynos_dp_initialize,
	.create_connector = exynos_dp_create_connector,
	.dpms = exynos_dp_dpms,
};
@@ -1221,8 +1211,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
	return 0;
}

static int exynos_dp_probe(struct platform_device *pdev)
static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct drm_device *drm_dev = data;
	struct resource *res;
	struct exynos_dp_device *dp;

@@ -1282,21 +1274,40 @@ static int exynos_dp_probe(struct platform_device *pdev)
	}
	disable_irq(dp->irq);

	dp->drm_dev = drm_dev;
	exynos_dp_display.ctx = dp;

	platform_set_drvdata(pdev, &exynos_dp_display);
	exynos_drm_display_register(&exynos_dp_display);

	return 0;
	return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display);
}

static int exynos_dp_remove(struct platform_device *pdev)
static void exynos_dp_unbind(struct device *dev, struct device *master,
				void *data)
{
	struct exynos_drm_display *display = platform_get_drvdata(pdev);
	struct exynos_drm_display *display = dev_get_drvdata(dev);
	struct exynos_dp_device *dp = display->ctx;
	struct drm_encoder *encoder = dp->encoder;

	exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
	exynos_drm_display_unregister(&exynos_dp_display);

	encoder->funcs->destroy(encoder);
	drm_connector_cleanup(&dp->connector);
}

static const struct component_ops exynos_dp_ops = {
	.bind	= exynos_dp_bind,
	.unbind	= exynos_dp_unbind,
};

static int exynos_dp_probe(struct platform_device *pdev)
{
	return exynos_drm_component_add(&pdev->dev, &exynos_dp_ops);
}

static int exynos_dp_remove(struct platform_device *pdev)
{
	exynos_drm_component_del(&pdev->dev, &exynos_dp_ops);
	return 0;
}

+36 −180
Original line number Diff line number Diff line
@@ -19,21 +19,19 @@
#include "exynos_drm_fbdev.h"

static LIST_HEAD(exynos_drm_subdrv_list);
static LIST_HEAD(exynos_drm_manager_list);
static LIST_HEAD(exynos_drm_display_list);

static int exynos_drm_create_enc_conn(struct drm_device *dev,
int exynos_drm_create_enc_conn(struct drm_device *dev,
					struct exynos_drm_display *display)
{
	struct drm_encoder *encoder;
	struct exynos_drm_manager *manager;
	int ret;
	unsigned long possible_crtcs = 0;

	/* Find possible crtcs for this display */
	list_for_each_entry(manager, &exynos_drm_manager_list, list)
		if (manager->type == display->type)
			possible_crtcs |= 1 << manager->pipe;
	ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
	if (ret < 0)
		return ret;

	possible_crtcs |= 1 << ret;

	/* create and initialize a encoder for this sub driver. */
	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
@@ -57,127 +55,29 @@ err_destroy_encoder:
	return ret;
}

static int exynos_drm_subdrv_probe(struct drm_device *dev,
					struct exynos_drm_subdrv *subdrv)
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
{
	if (subdrv->probe) {
		int ret;

		subdrv->drm_dev = dev;
	if (!subdrv)
		return -EINVAL;

		/*
		 * this probe callback would be called by sub driver
		 * after setting of all resources to this sub driver,
		 * such as clock, irq and register map are done or by load()
		 * of exynos drm driver.
		 *
		 * P.S. note that this driver is considered for modularization.
		 */
		ret = subdrv->probe(dev, subdrv->dev);
		if (ret)
			return ret;
	}
	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);

	return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);

static void exynos_drm_subdrv_remove(struct drm_device *dev,
				      struct exynos_drm_subdrv *subdrv)
{
	if (subdrv->remove)
		subdrv->remove(dev, subdrv->dev);
}

int exynos_drm_initialize_managers(struct drm_device *dev)
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
{
	struct exynos_drm_manager *manager, *n;
	int ret, pipe = 0;

	list_for_each_entry(manager, &exynos_drm_manager_list, list) {
		if (manager->ops->initialize) {
			ret = manager->ops->initialize(manager, dev, pipe);
			if (ret) {
				DRM_ERROR("Mgr init [%d] failed with %d\n",
						manager->type, ret);
				goto err;
			}
		}
	if (!subdrv)
		return -EINVAL;

		manager->drm_dev = dev;
		manager->pipe = pipe++;
	list_del(&subdrv->list);

		ret = exynos_drm_crtc_create(manager);
		if (ret) {
			DRM_ERROR("CRTC create [%d] failed with %d\n",
					manager->type, ret);
			goto err;
		}
	}
	return 0;

err:
	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
		if (pipe-- > 0)
			exynos_drm_manager_unregister(manager);
		else
			list_del(&manager->list);
	}
	return ret;
}

void exynos_drm_remove_managers(struct drm_device *dev)
{
	struct exynos_drm_manager *manager, *n;

	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
		exynos_drm_manager_unregister(manager);
}

int exynos_drm_initialize_displays(struct drm_device *dev)
{
	struct exynos_drm_display *display, *n;
	int ret, initialized = 0;

	list_for_each_entry(display, &exynos_drm_display_list, list) {
		if (display->ops->initialize) {
			ret = display->ops->initialize(display, dev);
			if (ret) {
				DRM_ERROR("Display init [%d] failed with %d\n",
						display->type, ret);
				goto err;
			}
		}

		initialized++;

		ret = exynos_drm_create_enc_conn(dev, display);
		if (ret) {
			DRM_ERROR("Encoder create [%d] failed with %d\n",
					display->type, ret);
			goto err;
		}
	}
	return 0;

err:
	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
		if (initialized-- > 0)
			exynos_drm_display_unregister(display);
		else
			list_del(&display->list);
	}
	return ret;
}

void exynos_drm_remove_displays(struct drm_device *dev)
{
	struct exynos_drm_display *display, *n;

	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
		exynos_drm_display_unregister(display);
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);

int exynos_drm_device_register(struct drm_device *dev)
int exynos_drm_device_subdrv_probe(struct drm_device *dev)
{
	struct exynos_drm_subdrv *subdrv, *n;
	int err;
@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev)
		return -EINVAL;

	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
		err = exynos_drm_subdrv_probe(dev, subdrv);
		if (subdrv->probe) {
			subdrv->drm_dev = dev;

			/*
			 * this probe callback would be called by sub driver
			 * after setting of all resources to this sub driver,
			 * such as clock, irq and register map are done.
			 */
			err = subdrv->probe(dev, subdrv->dev);
			if (err) {
				DRM_DEBUG("exynos drm subdrv probe failed.\n");
				list_del(&subdrv->list);
				continue;
			}
		}
	}

	return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_device_register);
EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);

int exynos_drm_device_unregister(struct drm_device *dev)
int exynos_drm_device_subdrv_remove(struct drm_device *dev)
{
	struct exynos_drm_subdrv *subdrv;

@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev)
	}

	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
		exynos_drm_subdrv_remove(dev, subdrv);
	}

	return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);

int exynos_drm_manager_register(struct exynos_drm_manager *manager)
{
	BUG_ON(!manager->ops);
	list_add_tail(&manager->list, &exynos_drm_manager_list);
	return 0;
}

int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
{
	if (manager->ops->remove)
		manager->ops->remove(manager);

	list_del(&manager->list);
	return 0;
}

int exynos_drm_display_register(struct exynos_drm_display *display)
{
	BUG_ON(!display->ops);
	list_add_tail(&display->list, &exynos_drm_display_list);
	return 0;
}

int exynos_drm_display_unregister(struct exynos_drm_display *display)
{
	if (display->ops->remove)
		display->ops->remove(display);

	list_del(&display->list);
	return 0;
}

int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
{
	if (!subdrv)
		return -EINVAL;

	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);

	return 0;
		if (subdrv->remove)
			subdrv->remove(dev, subdrv->dev);
	}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);

int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
{
	if (!subdrv)
		return -EINVAL;

	list_del(&subdrv->list);

	return 0;
}
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);

int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
{
+17 −0
Original line number Diff line number Diff line
@@ -368,6 +368,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
		return -ENOMEM;
	}

	manager->crtc = &exynos_crtc->drm_crtc;
	crtc = &exynos_crtc->drm_crtc;

	private->crtc[manager->pipe] = crtc;
@@ -491,3 +492,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
			manager->ops->wait_for_vblank(manager);
	}
}

int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
					unsigned int out_type)
{
	struct drm_crtc *crtc;

	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
		struct exynos_drm_crtc *exynos_crtc;

		exynos_crtc = to_exynos_crtc(crtc);
		if (exynos_crtc->manager->type == out_type)
			return exynos_crtc->manager->pipe;
	}

	return -EPERM;
}
+4 −0
Original line number Diff line number Diff line
@@ -32,4 +32,8 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);

/* This function gets pipe value to crtc device matched with out_type. */
int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
					unsigned int out_type);

#endif
+9 −7
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ enum {
	FIMD_PORT_WRB,
};

static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
{
	struct device_node *np, *ep;

@@ -301,7 +301,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
	return 0;
}

int exynos_dpi_probe(struct device *dev)
int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
{
	struct exynos_dpi *ctx;
	int ret;
@@ -318,15 +318,17 @@ int exynos_dpi_probe(struct device *dev)
	if (ret < 0)
		return ret;

	exynos_drm_display_register(&exynos_dpi_display);

	return 0;
	return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
}

int exynos_dpi_remove(struct device *dev)
int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
{
	struct drm_encoder *encoder = exynos_dpi_display.encoder;
	struct exynos_dpi *ctx = exynos_dpi_display.ctx;

	exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
	exynos_drm_display_unregister(&exynos_dpi_display);
	encoder->funcs->destroy(encoder);
	drm_connector_cleanup(&ctx->connector);

	return 0;
}
Loading