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

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
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/component.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <video/of_display_timing.h> #include <video/of_display_timing.h>
#include <video/of_videomode.h> #include <video/of_videomode.h>
...@@ -962,16 +963,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { ...@@ -962,16 +963,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
.best_encoder = exynos_dp_best_encoder, .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) static bool find_bridge(const char *compat, struct bridge_init *bridge)
{ {
bridge->client = NULL; bridge->client = NULL;
...@@ -1099,7 +1090,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) ...@@ -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 = { static struct exynos_drm_display_ops exynos_dp_display_ops = {
.initialize = exynos_dp_initialize,
.create_connector = exynos_dp_create_connector, .create_connector = exynos_dp_create_connector,
.dpms = exynos_dp_dpms, .dpms = exynos_dp_dpms,
}; };
...@@ -1221,8 +1211,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) ...@@ -1221,8 +1211,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
return 0; 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 resource *res;
struct exynos_dp_device *dp; struct exynos_dp_device *dp;
...@@ -1282,21 +1274,40 @@ static int exynos_dp_probe(struct platform_device *pdev) ...@@ -1282,21 +1274,40 @@ static int exynos_dp_probe(struct platform_device *pdev)
} }
disable_irq(dp->irq); disable_irq(dp->irq);
dp->drm_dev = drm_dev;
exynos_dp_display.ctx = dp; exynos_dp_display.ctx = dp;
platform_set_drvdata(pdev, &exynos_dp_display); 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_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; return 0;
} }
......
...@@ -19,21 +19,19 @@ ...@@ -19,21 +19,19 @@
#include "exynos_drm_fbdev.h" #include "exynos_drm_fbdev.h"
static LIST_HEAD(exynos_drm_subdrv_list); 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 exynos_drm_display *display)
{ {
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct exynos_drm_manager *manager;
int ret; int ret;
unsigned long possible_crtcs = 0; unsigned long possible_crtcs = 0;
/* Find possible crtcs for this display */ ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
list_for_each_entry(manager, &exynos_drm_manager_list, list) if (ret < 0)
if (manager->type == display->type) return ret;
possible_crtcs |= 1 << manager->pipe;
possible_crtcs |= 1 << ret;
/* create and initialize a encoder for this sub driver. */ /* create and initialize a encoder for this sub driver. */
encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
...@@ -57,127 +55,29 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, ...@@ -57,127 +55,29 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev,
return ret; return ret;
} }
static int exynos_drm_subdrv_probe(struct drm_device *dev, int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
struct exynos_drm_subdrv *subdrv)
{ {
if (subdrv->probe) { if (!subdrv)
int ret; return -EINVAL;
subdrv->drm_dev = dev;
/* list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
* 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;
}
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
static void exynos_drm_subdrv_remove(struct drm_device *dev, int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
struct exynos_drm_subdrv *subdrv)
{
if (subdrv->remove)
subdrv->remove(dev, subdrv->dev);
}
int exynos_drm_initialize_managers(struct drm_device *dev)
{ {
struct exynos_drm_manager *manager, *n; if (!subdrv)
int ret, pipe = 0; return -EINVAL;
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;
}
}
manager->drm_dev = dev; list_del(&subdrv->list);
manager->pipe = pipe++;
ret = exynos_drm_crtc_create(manager);
if (ret) {
DRM_ERROR("CRTC create [%d] failed with %d\n",
manager->type, ret);
goto err;
}
}
return 0; 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; struct exynos_drm_subdrv *subdrv, *n;
int err; int err;
...@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev) ...@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev)
return -EINVAL; return -EINVAL;
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { 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) { if (err) {
DRM_DEBUG("exynos drm subdrv probe failed.\n"); DRM_DEBUG("exynos drm subdrv probe failed.\n");
list_del(&subdrv->list); list_del(&subdrv->list);
continue; continue;
} }
} }
}
return 0; 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; struct exynos_drm_subdrv *subdrv;
...@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev) ...@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev)
} }
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
exynos_drm_subdrv_remove(dev, subdrv); if (subdrv->remove)
subdrv->remove(dev, subdrv->dev);
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister); EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
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;
}
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);
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
{ {
......
...@@ -368,6 +368,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager) ...@@ -368,6 +368,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
return -ENOMEM; return -ENOMEM;
} }
manager->crtc = &exynos_crtc->drm_crtc;
crtc = &exynos_crtc->drm_crtc; crtc = &exynos_crtc->drm_crtc;
private->crtc[manager->pipe] = crtc; private->crtc[manager->pipe] = crtc;
...@@ -491,3 +492,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) ...@@ -491,3 +492,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
manager->ops->wait_for_vblank(manager); 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;
}
...@@ -32,4 +32,8 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos); ...@@ -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_enable(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_disable(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 #endif
...@@ -248,7 +248,7 @@ enum { ...@@ -248,7 +248,7 @@ enum {
FIMD_PORT_WRB, 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; struct device_node *np, *ep;
...@@ -301,7 +301,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) ...@@ -301,7 +301,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
return 0; 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; struct exynos_dpi *ctx;
int ret; int ret;
...@@ -318,15 +318,17 @@ int exynos_dpi_probe(struct device *dev) ...@@ -318,15 +318,17 @@ int exynos_dpi_probe(struct device *dev)
if (ret < 0) if (ret < 0)
return ret; return ret;
exynos_drm_display_register(&exynos_dpi_display); return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
return 0;
} }
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_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; return 0;
} }
This diff is collapsed.
...@@ -122,7 +122,6 @@ struct exynos_drm_overlay { ...@@ -122,7 +122,6 @@ struct exynos_drm_overlay {
* Exynos DRM Display Structure. * Exynos DRM Display Structure.
* - this structure is common to analog tv, digital tv and lcd panel. * - this structure is common to analog tv, digital tv and lcd panel.
* *
* @initialize: initializes the display with drm_dev
* @remove: cleans up the display for removal * @remove: cleans up the display for removal
* @mode_fixup: fix mode data comparing to hw specific display mode. * @mode_fixup: fix mode data comparing to hw specific display mode.
* @mode_set: convert drm_display_mode to hw specific display mode and * @mode_set: convert drm_display_mode to hw specific display mode and
...@@ -133,8 +132,6 @@ struct exynos_drm_overlay { ...@@ -133,8 +132,6 @@ struct exynos_drm_overlay {
*/ */
struct exynos_drm_display; struct exynos_drm_display;
struct exynos_drm_display_ops { struct exynos_drm_display_ops {
int (*initialize)(struct exynos_drm_display *display,
struct drm_device *drm_dev);
int (*create_connector)(struct exynos_drm_display *display, int (*create_connector)(struct exynos_drm_display *display,
struct drm_encoder *encoder); struct drm_encoder *encoder);
void (*remove)(struct exynos_drm_display *display); void (*remove)(struct exynos_drm_display *display);
...@@ -172,8 +169,6 @@ struct exynos_drm_display { ...@@ -172,8 +169,6 @@ struct exynos_drm_display {
/* /*
* Exynos drm manager ops * Exynos drm manager ops
* *
* @initialize: initializes the manager with drm_dev
* @remove: cleans up the manager for removal
* @dpms: control device power. * @dpms: control device power.
* @mode_fixup: fix mode data before applying it * @mode_fixup: fix mode data before applying it
* @mode_set: set the given mode to the manager * @mode_set: set the given mode to the manager
...@@ -189,9 +184,6 @@ struct exynos_drm_display { ...@@ -189,9 +184,6 @@ struct exynos_drm_display {
*/ */
struct exynos_drm_manager; struct exynos_drm_manager;
struct exynos_drm_manager_ops { struct exynos_drm_manager_ops {
int (*initialize)(struct exynos_drm_manager *mgr,
struct drm_device *drm_dev, int pipe);
void (*remove)(struct exynos_drm_manager *mgr);
void (*dpms)(struct exynos_drm_manager *mgr, int mode); void (*dpms)(struct exynos_drm_manager *mgr, int mode);
bool (*mode_fixup)(struct exynos_drm_manager *mgr, bool (*mode_fixup)(struct exynos_drm_manager *mgr,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
...@@ -215,6 +207,7 @@ struct exynos_drm_manager_ops { ...@@ -215,6 +207,7 @@ struct exynos_drm_manager_ops {
* @list: the list entry for this manager * @list: the list entry for this manager
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
* @drm_dev: pointer to the drm device * @drm_dev: pointer to the drm device
* @crtc: crtc object.
* @pipe: the pipe number for this crtc/manager * @pipe: the pipe number for this crtc/manager
* @ops: pointer to callbacks for exynos drm specific functionality * @ops: pointer to callbacks for exynos drm specific functionality
* @ctx: A pointer to the manager's implementation specific context * @ctx: A pointer to the manager's implementation specific context
...@@ -223,6 +216,7 @@ struct exynos_drm_manager { ...@@ -223,6 +216,7 @@ struct exynos_drm_manager {
struct list_head list; struct list_head list;
enum exynos_drm_output_type type; enum exynos_drm_output_type type;
struct drm_device *drm_dev; struct drm_device *drm_dev;
struct drm_crtc *crtc;
int pipe; int pipe;
struct exynos_drm_manager_ops *ops; struct exynos_drm_manager_ops *ops;
void *ctx; void *ctx;
...@@ -254,6 +248,7 @@ struct drm_exynos_file_private { ...@@ -254,6 +248,7 @@ struct drm_exynos_file_private {
* otherwise default one. * otherwise default one.
* @da_space_size: size of device address space. * @da_space_size: size of device address space.
* if 0 then default value is used for it. * if 0 then default value is used for it.
* @pipe: the pipe number for this crtc/manager.
*/ */
struct exynos_drm_private { struct exynos_drm_private {
struct drm_fb_helper *fb_helper; struct drm_fb_helper *fb_helper;
...@@ -271,6 +266,8 @@ struct exynos_drm_private { ...@@ -271,6 +266,8 @@ struct exynos_drm_private {
unsigned long da_start; unsigned long da_start;
unsigned long da_space_size; unsigned long da_space_size;
unsigned int pipe;
}; };
/* /*
...@@ -302,39 +299,14 @@ struct exynos_drm_subdrv { ...@@ -302,39 +299,14 @@ struct exynos_drm_subdrv {
struct drm_file *file); struct drm_file *file);
}; };
/* /* This function would be called by non kms drivers such as g2d and ipp. */
* this function calls a probe callback registered to sub driver list and
* create its own encoder and connector and then set drm_device object
* to global one.
*/
int exynos_drm_device_register(struct drm_device *dev);
/*
* this function calls a remove callback registered to sub driver list and
* destroy its own encoder and connetor.
*/
int exynos_drm_device_unregister(struct drm_device *dev);
int exynos_drm_initialize_managers(struct drm_device *dev);
void exynos_drm_remove_managers(struct drm_device *dev);
int exynos_drm_initialize_displays(struct drm_device *dev);
void exynos_drm_remove_displays(struct drm_device *dev);
int exynos_drm_manager_register(struct exynos_drm_manager *manager);
int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
int exynos_drm_display_register(struct exynos_drm_display *display);
int exynos_drm_display_unregister(struct exynos_drm_display *display);
/*
* this function would be called by sub drivers such as display controller
* or hdmi driver to register this sub driver object to exynos drm driver
* and when a sub driver is registered to exynos drm driver a probe callback
* of the sub driver is called and creates its own encoder and connector.
*/
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv); int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
/* this function removes subdrv list from exynos drm driver */ /* this function removes subdrv list from exynos drm driver */
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv); int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
int exynos_drm_device_subdrv_probe(struct drm_device *dev);
int exynos_drm_device_subdrv_remove(struct drm_device *dev);
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
...@@ -360,18 +332,45 @@ int exynos_platform_device_ipp_register(void); ...@@ -360,18 +332,45 @@ int exynos_platform_device_ipp_register(void);
void exynos_platform_device_ipp_unregister(void); void exynos_platform_device_ipp_unregister(void);
#ifdef CONFIG_DRM_EXYNOS_DPI #ifdef CONFIG_DRM_EXYNOS_DPI
int exynos_dpi_probe(struct device *dev); int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
int exynos_dpi_remove(struct device *dev); int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
#else #else
static inline int exynos_dpi_probe(struct device *dev) { return 0; } static inline int exynos_dpi_probe(struct drm_device *drm_dev,
static inline int exynos_dpi_remove(struct device *dev) { return 0; } struct device *dev) { return 0; }
static inline int exynos_dpi_remove(struct drm_device *drm_dev,
struct device *dev) { return 0; }
static inline struct device_node
*exynos_dpi_of_find_panel_node(struct device *dev)
{ return NULL; }
#endif #endif
/*
* this function registers exynos drm vidi platform device/driver.
*/
int exynos_drm_probe_vidi(void);
/*
* this function unregister exynos drm vidi platform device/driver.
*/
void exynos_drm_remove_vidi(void);
/* This function creates a encoder and a connector, and initializes them. */
int exynos_drm_create_enc_conn(struct drm_device *dev,
struct exynos_drm_display *display);
struct component_ops;
int exynos_drm_component_add(struct device *dev,
const struct component_ops *ops);
void exynos_drm_component_del(struct device *dev,
const struct component_ops *ops);
extern struct platform_driver fimd_driver;
extern struct platform_driver dp_driver; extern struct platform_driver dp_driver;
extern struct platform_driver dsi_driver; extern struct platform_driver dsi_driver;
extern struct platform_driver fimd_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver; extern struct platform_driver mixer_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver exynos_drm_common_hdmi_driver; extern struct platform_driver exynos_drm_common_hdmi_driver;
extern struct platform_driver vidi_driver; extern struct platform_driver vidi_driver;
extern struct platform_driver g2d_driver; extern struct platform_driver g2d_driver;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/component.h>
#include <video/mipi_display.h> #include <video/mipi_display.h>
#include <video/videomode.h> #include <video/videomode.h>
...@@ -1378,6 +1379,74 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) ...@@ -1378,6 +1379,74 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
return ret; return ret;
} }
static int exynos_dsi_bind(struct device *dev, struct device *master,
void *data)
{
struct drm_device *drm_dev = data;
struct exynos_dsi *dsi;
int ret;
ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display);
if (ret) {
DRM_ERROR("Encoder create [%d] failed with %d\n",
exynos_dsi_display.type, ret);
return ret;
}
dsi = exynos_dsi_display.ctx;
return mipi_dsi_host_register(&dsi->dsi_host);
}
static void exynos_dsi_unbind(struct device *dev, struct device *master,
void *data)
{
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
struct drm_encoder *encoder = dsi->encoder;
exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
mipi_dsi_host_unregister(&dsi->dsi_host);
encoder->funcs->destroy(encoder);
drm_connector_cleanup(&dsi->connector);
}
#if CONFIG_PM_SLEEP
static int exynos_dsi_resume(struct device *dev)
{
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
if (dsi->state & DSIM_STATE_ENABLED) {
dsi->state &= ~DSIM_STATE_ENABLED;
exynos_dsi_enable(dsi);
}
return 0;
}
static int exynos_dsi_suspend(struct device *dev)
{
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
if (dsi->state & DSIM_STATE_ENABLED) {
exynos_dsi_disable(dsi);
dsi->state |= DSIM_STATE_ENABLED;
}
return 0;
}
#endif
static const struct dev_pm_ops exynos_dsi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
};
static const struct component_ops exynos_dsi_component_ops = {
.bind = exynos_dsi_bind,
.unbind = exynos_dsi_unbind,
};
static int exynos_dsi_probe(struct platform_device *pdev) static int exynos_dsi_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
...@@ -1455,53 +1524,16 @@ static int exynos_dsi_probe(struct platform_device *pdev) ...@@ -1455,53 +1524,16 @@ static int exynos_dsi_probe(struct platform_device *pdev)
exynos_dsi_display.ctx = dsi; exynos_dsi_display.ctx = dsi;
platform_set_drvdata(pdev, &exynos_dsi_display); platform_set_drvdata(pdev, &exynos_dsi_display);
exynos_drm_display_register(&exynos_dsi_display);
return mipi_dsi_host_register(&dsi->dsi_host); return exynos_drm_component_add(&pdev->dev, &exynos_dsi_component_ops);
} }
static int exynos_dsi_remove(struct platform_device *pdev) static int exynos_dsi_remove(struct platform_device *pdev)
{ {
struct exynos_dsi *dsi = exynos_dsi_display.ctx; exynos_drm_component_del(&pdev->dev, &exynos_dsi_component_ops);
exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
exynos_drm_display_unregister(&exynos_dsi_display);
mipi_dsi_host_unregister(&dsi->dsi_host);
return 0; return 0;
} }
#if CONFIG_PM_SLEEP
static int exynos_dsi_resume(struct device *dev)
{
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
if (dsi->state & DSIM_STATE_ENABLED) {
dsi->state &= ~DSIM_STATE_ENABLED;
exynos_dsi_enable(dsi);
}
return 0;
}
static int exynos_dsi_suspend(struct device *dev)
{
struct exynos_dsi *dsi = exynos_dsi_display.ctx;
if (dsi->state & DSIM_STATE_ENABLED) {
exynos_dsi_disable(dsi);
dsi->state |= DSIM_STATE_ENABLED;
}
return 0;
}
#endif
static const struct dev_pm_ops exynos_dsi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
};
static struct of_device_id exynos_dsi_of_match[] = { static struct of_device_id exynos_dsi_of_match[] = {
{ .compatible = "samsung,exynos4210-mipi-dsi" }, { .compatible = "samsung,exynos4210-mipi-dsi" },
{ } { }
......
...@@ -19,10 +19,12 @@ ...@@ -19,10 +19,12 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/component.h>
#include <video/of_display_timing.h> #include <video/of_display_timing.h>
#include <video/of_videomode.h> #include <video/of_videomode.h>
#include <video/samsung_fimd.h> #include <video/samsung_fimd.h>
#include <drm/drm_panel.h>
#include <drm/exynos_drm.h> #include <drm/exynos_drm.h>
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
...@@ -186,12 +188,14 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) ...@@ -186,12 +188,14 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
} }
static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
struct drm_device *drm_dev, int pipe) struct drm_device *drm_dev)
{ {
struct fimd_context *ctx = mgr->ctx; struct fimd_context *ctx = mgr->ctx;
struct exynos_drm_private *priv;
priv = drm_dev->dev_private;
ctx->drm_dev = drm_dev; mgr->drm_dev = ctx->drm_dev = drm_dev;
ctx->pipe = pipe; mgr->pipe = ctx->pipe = priv->pipe++;
/* /*
* enable drm irq mode. * enable drm irq mode.
...@@ -832,8 +836,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) ...@@ -832,8 +836,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
} }
static struct exynos_drm_manager_ops fimd_manager_ops = { static struct exynos_drm_manager_ops fimd_manager_ops = {
.initialize = fimd_mgr_initialize,
.remove = fimd_mgr_remove,
.dpms = fimd_dpms, .dpms = fimd_dpms,
.mode_fixup = fimd_mode_fixup, .mode_fixup = fimd_mode_fixup,
.mode_set = fimd_mode_set, .mode_set = fimd_mode_set,
...@@ -878,10 +880,12 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) ...@@ -878,10 +880,12 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int fimd_probe(struct platform_device *pdev) static int fimd_bind(struct device *dev, struct device *master, void *data)
{ {
struct device *dev = &pdev->dev; struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm_dev = data;
struct fimd_context *ctx; struct fimd_context *ctx;
struct device_node *dn;
struct resource *res; struct resource *res;
int win; int win;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -939,11 +943,19 @@ static int fimd_probe(struct platform_device *pdev) ...@@ -939,11 +943,19 @@ static int fimd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &fimd_manager); platform_set_drvdata(pdev, &fimd_manager);
fimd_manager.ctx = ctx; fimd_manager.ctx = ctx;
exynos_drm_manager_register(&fimd_manager); fimd_mgr_initialize(&fimd_manager, drm_dev);
exynos_dpi_probe(ctx->dev); exynos_drm_crtc_create(&fimd_manager);
pm_runtime_enable(dev); dn = exynos_dpi_of_find_panel_node(&pdev->dev);
if (dn) {
/*
* It should be called after exynos_drm_crtc_create call
* because exynos_dpi_probe call will try to find same lcd
* type of manager to setup possible_crtcs.
*/
exynos_dpi_probe(drm_dev, dev);
}
for (win = 0; win < WINDOWS_NR; win++) for (win = 0; win < WINDOWS_NR; win++)
fimd_clear_win(ctx, win); fimd_clear_win(ctx, win);
...@@ -951,18 +963,59 @@ static int fimd_probe(struct platform_device *pdev) ...@@ -951,18 +963,59 @@ static int fimd_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int fimd_remove(struct platform_device *pdev) static void fimd_unbind(struct device *dev, struct device *master,
void *data)
{ {
struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
struct drm_crtc *crtc = mgr->crtc;
struct device_node *dn;
fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
exynos_dpi_remove(&pdev->dev); dn = exynos_dpi_of_find_panel_node(dev);
if (dn)
exynos_dpi_remove(mgr->drm_dev, dev);
exynos_drm_manager_unregister(&fimd_manager); fimd_mgr_remove(mgr);
fimd_dpms(mgr, DRM_MODE_DPMS_OFF); crtc->funcs->destroy(crtc);
}
static const struct component_ops fimd_component_ops = {
.bind = fimd_bind,
.unbind = fimd_unbind,
};
static int fimd_probe(struct platform_device *pdev)
{
struct device_node *dn;
/* Check if fimd node has port node. */
dn = exynos_dpi_of_find_panel_node(&pdev->dev);
if (dn) {
struct drm_panel *panel;
/*
* Do not bind if there is the port node but a drm_panel
* isn't added to panel_list yet.
* In this case, fimd_probe will be called by defered probe
* again after the drm_panel is added to panel_list.
*/
panel = of_drm_find_panel(dn);
if (!panel)
return -EPROBE_DEFER;
}
pm_runtime_enable(&pdev->dev);
return exynos_drm_component_add(&pdev->dev, &fimd_component_ops);
}
static int fimd_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
exynos_drm_component_del(&pdev->dev, &fimd_component_ops);
return 0; return 0;
} }
......
...@@ -51,6 +51,7 @@ struct vidi_context { ...@@ -51,6 +51,7 @@ struct vidi_context {
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_connector connector; struct drm_connector connector;
struct exynos_drm_subdrv subdrv;
struct vidi_win_data win_data[WINDOWS_NR]; struct vidi_win_data win_data[WINDOWS_NR];
struct edid *raw_edid; struct edid *raw_edid;
unsigned int clkdiv; unsigned int clkdiv;
...@@ -294,14 +295,13 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) ...@@ -294,14 +295,13 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
} }
static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
struct drm_device *drm_dev, int pipe) struct drm_device *drm_dev)
{ {
struct vidi_context *ctx = mgr->ctx; struct vidi_context *ctx = mgr->ctx;
struct exynos_drm_private *priv = drm_dev->dev_private;
DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe); mgr->drm_dev = ctx->drm_dev = drm_dev;
mgr->pipe = ctx->pipe = priv->pipe++;
ctx->drm_dev = drm_dev;
ctx->pipe = pipe;
/* /*
* enable drm irq mode. * enable drm irq mode.
...@@ -324,7 +324,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, ...@@ -324,7 +324,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
} }
static struct exynos_drm_manager_ops vidi_manager_ops = { static struct exynos_drm_manager_ops vidi_manager_ops = {
.initialize = vidi_mgr_initialize,
.dpms = vidi_dpms, .dpms = vidi_dpms,
.commit = vidi_commit, .commit = vidi_commit,
.enable_vblank = vidi_enable_vblank, .enable_vblank = vidi_enable_vblank,
...@@ -579,13 +578,38 @@ static struct exynos_drm_display vidi_display = { ...@@ -579,13 +578,38 @@ static struct exynos_drm_display vidi_display = {
.ops = &vidi_display_ops, .ops = &vidi_display_ops,
}; };
static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
{
struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
struct vidi_context *ctx = mgr->ctx;
struct drm_crtc *crtc = ctx->crtc;
int ret;
vidi_mgr_initialize(mgr, drm_dev);
ret = exynos_drm_crtc_create(&vidi_manager);
if (ret) {
DRM_ERROR("failed to create crtc.\n");
return ret;
}
ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display);
if (ret) {
crtc->funcs->destroy(crtc);
DRM_ERROR("failed to create encoder and connector.\n");
return ret;
}
return 0;
}
static int vidi_probe(struct platform_device *pdev) static int vidi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct exynos_drm_subdrv *subdrv;
struct vidi_context *ctx; struct vidi_context *ctx;
int ret; int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
...@@ -600,28 +624,43 @@ static int vidi_probe(struct platform_device *pdev) ...@@ -600,28 +624,43 @@ static int vidi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &vidi_manager); platform_set_drvdata(pdev, &vidi_manager);
ret = device_create_file(dev, &dev_attr_connection); subdrv = &ctx->subdrv;
if (ret < 0) subdrv->dev = &pdev->dev;
DRM_INFO("failed to create connection sysfs.\n"); subdrv->probe = vidi_subdrv_probe;
ret = exynos_drm_subdrv_register(subdrv);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register drm vidi device\n");
return ret;
}
exynos_drm_manager_register(&vidi_manager); ret = device_create_file(&pdev->dev, &dev_attr_connection);
exynos_drm_display_register(&vidi_display); if (ret < 0) {
exynos_drm_subdrv_unregister(subdrv);
DRM_INFO("failed to create connection sysfs.\n");
}
return 0; return 0;
} }
static int vidi_remove(struct platform_device *pdev) static int vidi_remove(struct platform_device *pdev)
{ {
struct vidi_context *ctx = platform_get_drvdata(pdev); struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
struct vidi_context *ctx = mgr->ctx;
exynos_drm_display_unregister(&vidi_display); struct drm_encoder *encoder = ctx->encoder;
exynos_drm_manager_unregister(&vidi_manager); struct drm_crtc *crtc = mgr->crtc;
if (ctx->raw_edid != (struct edid *)fake_edid_info) { if (ctx->raw_edid != (struct edid *)fake_edid_info) {
kfree(ctx->raw_edid); kfree(ctx->raw_edid);
ctx->raw_edid = NULL; ctx->raw_edid = NULL;
return -EINVAL;
} }
crtc->funcs->destroy(crtc);
encoder->funcs->destroy(encoder);
drm_connector_cleanup(&ctx->connector);
return 0; return 0;
} }
...@@ -633,3 +672,31 @@ struct platform_driver vidi_driver = { ...@@ -633,3 +672,31 @@ struct platform_driver vidi_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
}; };
int exynos_drm_probe_vidi(void)
{
struct platform_device *pdev;
int ret;
pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
ret = platform_driver_register(&vidi_driver);
if (ret) {
platform_device_unregister(pdev);
return ret;
}
return ret;
}
void exynos_drm_remove_vidi(void)
{
struct vidi_context *ctx = vidi_manager.ctx;
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
struct platform_device *pdev = to_platform_device(subdrv->dev);
platform_driver_unregister(&vidi_driver);
platform_device_unregister(pdev);
}
...@@ -36,10 +36,12 @@ ...@@ -36,10 +36,12 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <linux/component.h>
#include <drm/exynos_drm.h> #include <drm/exynos_drm.h>
#include "exynos_drm_drv.h" #include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_mixer.h" #include "exynos_mixer.h"
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -928,16 +930,6 @@ static int hdmi_create_connector(struct exynos_drm_display *display, ...@@ -928,16 +930,6 @@ static int hdmi_create_connector(struct exynos_drm_display *display,
return 0; return 0;
} }
static int hdmi_initialize(struct exynos_drm_display *display,
struct drm_device *drm_dev)
{
struct hdmi_context *hdata = display->ctx;
hdata->drm_dev = drm_dev;
return 0;
}
static void hdmi_mode_fixup(struct exynos_drm_display *display, static void hdmi_mode_fixup(struct exynos_drm_display *display,
struct drm_connector *connector, struct drm_connector *connector,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,
...@@ -1913,7 +1905,6 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode) ...@@ -1913,7 +1905,6 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
} }
static struct exynos_drm_display_ops hdmi_display_ops = { static struct exynos_drm_display_ops hdmi_display_ops = {
.initialize = hdmi_initialize,
.create_connector = hdmi_create_connector, .create_connector = hdmi_create_connector,
.mode_fixup = hdmi_mode_fixup, .mode_fixup = hdmi_mode_fixup,
.mode_set = hdmi_mode_set, .mode_set = hdmi_mode_set,
...@@ -2047,15 +2038,41 @@ static struct of_device_id hdmi_match_types[] = { ...@@ -2047,15 +2038,41 @@ static struct of_device_id hdmi_match_types[] = {
} }
}; };
static int hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm_dev = data;
struct hdmi_context *hdata;
hdata = hdmi_display.ctx;
hdata->drm_dev = drm_dev;
return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
}
static void hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct exynos_drm_display *display = get_hdmi_display(dev);
struct drm_encoder *encoder = display->encoder;
struct hdmi_context *hdata = display->ctx;
encoder->funcs->destroy(encoder);
drm_connector_cleanup(&hdata->connector);
}
static const struct component_ops hdmi_component_ops = {
.bind = hdmi_bind,
.unbind = hdmi_unbind,
};
static int hdmi_probe(struct platform_device *pdev) static int hdmi_probe(struct platform_device *pdev)
{ {
struct device_node *ddc_node, *phy_node;
struct s5p_hdmi_platform_data *pdata;
struct hdmi_driver_data *drv_data;
const struct of_device_id *match;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct hdmi_context *hdata; struct hdmi_context *hdata;
struct s5p_hdmi_platform_data *pdata;
struct resource *res; struct resource *res;
const struct of_device_id *match;
struct device_node *ddc_node, *phy_node;
struct hdmi_driver_data *drv_data;
int ret; int ret;
if (!dev->of_node) if (!dev->of_node)
...@@ -2149,11 +2166,9 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -2149,11 +2166,9 @@ static int hdmi_probe(struct platform_device *pdev)
} }
pm_runtime_enable(dev); pm_runtime_enable(dev);
hdmi_display.ctx = hdata; hdmi_display.ctx = hdata;
exynos_drm_display_register(&hdmi_display);
return 0; return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
err_hdmiphy: err_hdmiphy:
put_device(&hdata->hdmiphy_port->dev); put_device(&hdata->hdmiphy_port->dev);
...@@ -2164,14 +2179,14 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -2164,14 +2179,14 @@ static int hdmi_probe(struct platform_device *pdev)
static int hdmi_remove(struct platform_device *pdev) static int hdmi_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct hdmi_context *hdata = hdmi_display.ctx;
struct exynos_drm_display *display = get_hdmi_display(dev);
struct hdmi_context *hdata = display->ctx;
put_device(&hdata->hdmiphy_port->dev); put_device(&hdata->hdmiphy_port->dev);
put_device(&hdata->ddc_adpt->dev); put_device(&hdata->ddc_adpt->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
return 0; return 0;
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/component.h>
#include <drm/exynos_drm.h> #include <drm/exynos_drm.h>
...@@ -830,13 +831,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx) ...@@ -830,13 +831,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
} }
static int mixer_initialize(struct exynos_drm_manager *mgr, static int mixer_initialize(struct exynos_drm_manager *mgr,
struct drm_device *drm_dev, int pipe) struct drm_device *drm_dev)
{ {
int ret; int ret;
struct mixer_context *mixer_ctx = mgr->ctx; struct mixer_context *mixer_ctx = mgr->ctx;
struct exynos_drm_private *priv;
priv = drm_dev->dev_private;
mixer_ctx->drm_dev = drm_dev; mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
mixer_ctx->pipe = pipe; mgr->pipe = mixer_ctx->pipe = priv->pipe++;
/* acquire resources: regs, irqs, clocks */ /* acquire resources: regs, irqs, clocks */
ret = mixer_resources_init(mixer_ctx); ret = mixer_resources_init(mixer_ctx);
...@@ -1142,8 +1145,6 @@ int mixer_check_mode(struct drm_display_mode *mode) ...@@ -1142,8 +1145,6 @@ int mixer_check_mode(struct drm_display_mode *mode)
} }
static struct exynos_drm_manager_ops mixer_manager_ops = { static struct exynos_drm_manager_ops mixer_manager_ops = {
.initialize = mixer_initialize,
.remove = mixer_mgr_remove,
.dpms = mixer_dpms, .dpms = mixer_dpms,
.enable_vblank = mixer_enable_vblank, .enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank, .disable_vblank = mixer_disable_vblank,
...@@ -1200,11 +1201,13 @@ static struct of_device_id mixer_match_types[] = { ...@@ -1200,11 +1201,13 @@ static struct of_device_id mixer_match_types[] = {
} }
}; };
static int mixer_probe(struct platform_device *pdev) static int mixer_bind(struct device *dev, struct device *manager, void *data)
{ {
struct device *dev = &pdev->dev; struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm_dev = data;
struct mixer_context *ctx; struct mixer_context *ctx;
struct mixer_drv_data *drv; struct mixer_drv_data *drv;
int ret;
dev_info(dev, "probe start\n"); dev_info(dev, "probe start\n");
...@@ -1233,20 +1236,49 @@ static int mixer_probe(struct platform_device *pdev) ...@@ -1233,20 +1236,49 @@ static int mixer_probe(struct platform_device *pdev)
atomic_set(&ctx->wait_vsync_event, 0); atomic_set(&ctx->wait_vsync_event, 0);
mixer_manager.ctx = ctx; mixer_manager.ctx = ctx;
ret = mixer_initialize(&mixer_manager, drm_dev);
if (ret)
return ret;
platform_set_drvdata(pdev, &mixer_manager); platform_set_drvdata(pdev, &mixer_manager);
exynos_drm_manager_register(&mixer_manager); ret = exynos_drm_crtc_create(&mixer_manager);
if (ret) {
mixer_mgr_remove(&mixer_manager);
return ret;
}
pm_runtime_enable(dev); pm_runtime_enable(dev);
return 0; return 0;
} }
static int mixer_remove(struct platform_device *pdev) static void mixer_unbind(struct device *dev, struct device *master, void *data)
{ {
dev_info(&pdev->dev, "remove successful\n"); struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
struct drm_crtc *crtc = mgr->crtc;
dev_info(dev, "remove successful\n");
mixer_mgr_remove(mgr);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(dev);
crtc->funcs->destroy(crtc);
}
static const struct component_ops mixer_component_ops = {
.bind = mixer_bind,
.unbind = mixer_unbind,
};
static int mixer_probe(struct platform_device *pdev)
{
return exynos_drm_component_add(&pdev->dev, &mixer_component_ops);
}
static int mixer_remove(struct platform_device *pdev)
{
exynos_drm_component_del(&pdev->dev, &mixer_component_ops);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment