summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-05-12 03:10:53 +0300
committerDave Airlie <airlied@redhat.com>2016-05-12 03:10:53 +0300
commit6d23abf58a9afd3bc28aaf0384155b04c4b77912 (patch)
tree4ba843ececa274bca4b5b484ca7fd44dd9760551 /drivers/gpu
parent19ea5da07a1f315191212e094ec44fb1caec9580 (diff)
parentdd65a6867454117ecaeb8944dc231a4737681782 (diff)
downloadlinux-6d23abf58a9afd3bc28aaf0384155b04c4b77912.tar.xz
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summary: - expose HDMI-PHY clock to other drivers. . this patch was included in below patch series but I missed. http://www.spinics.net/lists/dri-devel/msg103097.html - some fixups about DECON5433 driver . this patch corrects vblank handling and fixes up trigger configuration. - use generic functions - gem_prime_mmap and dma_buf_mmap. - use DMA-Mapping API instead of specific one. - some code cleanups and fixeups. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos/decon5433: fix trigger configuration drm/exynos/dsi: use of_graph_get_endpoint_by_regs helper drm/exynos/dpi: use of_graph_get_endpoint_by_regs helper drm/exynos: Nuke dummy fb->dirty callback drm/exynos: use directly DMA mapping APIs on g2d drm/exynos/hdmi: Don't print error on deferral due to regulators drm/exynos: fix imported dma-buf to be mapped drm/exynos: support gem_prime_mmap drm/exynos: fimd: harden fimd_calc_clkdiv() drm/exynos: fix cancel page flip code drm/exynos/decon5433: do not use unnecessary software trigger drm/exynos/decon5433: handle vblank in vblank interrupt drm/exynos/hdmi: expose HDMI-PHY clock as pipeline clock
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/exynos/exynos5433_drm_decon.c16
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c15
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c69
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c57
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c9
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c70
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h12
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c73
11 files changed, 120 insertions, 223 deletions
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
index 4ab5bfc23647..ac21b4000835 100644
--- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
+++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c
@@ -147,11 +147,13 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
writel(val, ctx->addr + DECON_CMU);
+ if (ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))
+ decon_setup_trigger(ctx);
+
/* lcd on and use command if */
val = VIDOUT_LCD_ON;
if (ctx->out_type & IFTYPE_I80) {
val |= VIDOUT_COMMAND_IF;
- decon_setup_trigger(ctx);
} else {
val |= VIDOUT_RGB_IF;
}
@@ -376,9 +378,6 @@ static void decon_swreset(struct decon_context *ctx)
writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1);
writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN,
ctx->addr + DECON_CRCCTRL);
-
- if (ctx->out_type & IFTYPE_I80)
- decon_setup_trigger(ctx);
}
static void decon_enable(struct exynos_drm_crtc *crtc)
@@ -434,13 +433,12 @@ static void decon_te_irq_handler(struct exynos_drm_crtc *crtc)
{
struct decon_context *ctx = crtc->ctx;
- if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags))
+ if (!test_bit(BIT_CLKS_ENABLED, &ctx->flags) ||
+ (ctx->out_type & I80_HW_TRG))
return;
if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0);
-
- drm_crtc_handle_vblank(&ctx->crtc->base);
}
static void decon_clear_channels(struct exynos_drm_crtc *crtc)
@@ -573,6 +571,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
/* clear */
writel(val, ctx->addr + DECON_VIDINTCON1);
+ drm_crtc_handle_vblank(&ctx->crtc->base);
}
out:
@@ -648,9 +647,8 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
if (ctx->out_type & IFTYPE_HDMI) {
ctx->first_win = 1;
- ctx->out_type = IFTYPE_I80;
} else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) {
- ctx->out_type = IFTYPE_I80;
+ ctx->out_type |= IFTYPE_I80;
}
for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 50dd33d5045d..785ffa6cc309 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -233,20 +233,15 @@ void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
unsigned long flags;
spin_lock_irqsave(&crtc->dev->event_lock, flags);
+
e = exynos_crtc->event;
if (e && e->base.file_priv == file) {
exynos_crtc->event = NULL;
- /*
- * event will be destroyed by core part
- * so below line should be removed later with core changes
- */
- e->base.destroy(&e->base);
- /*
- * event_space will be increased by core part
- * so below line should be removed later with core changes.
- */
- file->event_space += sizeof(e->event);
atomic_dec(&exynos_crtc->pending_update);
}
+
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+ if (e && e->base.file_priv == file)
+ drm_event_cancel_free(crtc->dev, &e->base);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 75e570f45259..5e38e749ac17 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -15,6 +15,7 @@
#include <drm/drm_panel.h>
#include <drm/drm_atomic_helper.h>
+#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <video/of_videomode.h>
@@ -164,67 +165,6 @@ static const struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-/* of_* functions will be removed after merge of of_graph patches */
-static struct device_node *
-of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
-{
- struct device_node *np;
-
- for_each_child_of_node(parent, np) {
- u32 r;
-
- if (!np->name || of_node_cmp(np->name, name))
- continue;
-
- if (of_property_read_u32(np, "reg", &r) < 0)
- r = 0;
-
- if (reg == r)
- break;
- }
-
- return np;
-}
-
-static struct device_node *of_graph_get_port_by_reg(struct device_node *parent,
- u32 reg)
-{
- struct device_node *ports, *port;
-
- ports = of_get_child_by_name(parent, "ports");
- if (ports)
- parent = ports;
-
- port = of_get_child_by_name_reg(parent, "port", reg);
-
- of_node_put(ports);
-
- return port;
-}
-
-static struct device_node *
-of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg)
-{
- return of_get_child_by_name_reg(port, "endpoint", reg);
-}
-
-static struct device_node *
-of_graph_get_remote_port_parent(const struct device_node *node)
-{
- struct device_node *np;
- unsigned int depth;
-
- np = of_parse_phandle(node, "remote-endpoint", 0);
-
- /* Walk 3 levels up only if there is 'ports' node. */
- for (depth = 3; depth && np; depth--) {
- np = of_get_next_parent(np);
- if (depth == 2 && of_node_cmp(np->name, "ports"))
- break;
- }
- return np;
-}
-
enum {
FIMD_PORT_IN0,
FIMD_PORT_IN1,
@@ -237,12 +177,7 @@ static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
{
struct device_node *np, *ep;
- np = of_graph_get_port_by_reg(dev->of_node, FIMD_PORT_RGB);
- if (!np)
- return NULL;
-
- ep = of_graph_get_endpoint_by_reg(np, 0);
- of_node_put(np);
+ ep = of_graph_get_endpoint_by_regs(dev->of_node, FIMD_PORT_RGB, 0);
if (!ep)
return NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 8ff355ddcf51..6c4dd49de993 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -431,6 +431,7 @@ static struct drm_driver exynos_drm_driver = {
.gem_prime_import_sg_table = exynos_drm_gem_prime_import_sg_table,
.gem_prime_vmap = exynos_drm_gem_prime_vmap,
.gem_prime_vunmap = exynos_drm_gem_prime_vunmap,
+ .gem_prime_mmap = exynos_drm_gem_prime_mmap,
.ioctls = exynos_ioctls,
.num_ioctls = ARRAY_SIZE(exynos_ioctls),
.fops = &exynos_drm_driver_fops,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 72c3565d22ee..601ecf8006a7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1632,50 +1632,6 @@ static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
-/* of_* functions will be removed after merge of of_graph patches */
-static struct device_node *
-of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
-{
- struct device_node *np;
-
- for_each_child_of_node(parent, np) {
- u32 r;
-
- if (!np->name || of_node_cmp(np->name, name))
- continue;
-
- if (of_property_read_u32(np, "reg", &r) < 0)
- r = 0;
-
- if (reg == r)
- break;
- }
-
- return np;
-}
-
-static struct device_node *of_graph_get_port_by_reg(struct device_node *parent,
- u32 reg)
-{
- struct device_node *ports, *port;
-
- ports = of_get_child_by_name(parent, "ports");
- if (ports)
- parent = ports;
-
- port = of_get_child_by_name_reg(parent, "port", reg);
-
- of_node_put(ports);
-
- return port;
-}
-
-static struct device_node *
-of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg)
-{
- return of_get_child_by_name_reg(port, "endpoint", reg);
-}
-
static int exynos_dsi_of_read_u32(const struct device_node *np,
const char *propname, u32 *out_value)
{
@@ -1697,7 +1653,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
{
struct device *dev = dsi->dev;
struct device_node *node = dev->of_node;
- struct device_node *port, *ep;
+ struct device_node *ep;
int ret;
ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
@@ -1705,16 +1661,9 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
if (ret < 0)
return ret;
- port = of_graph_get_port_by_reg(node, DSI_PORT_OUT);
- if (!port) {
- dev_err(dev, "no output port specified\n");
- return -EINVAL;
- }
-
- ep = of_graph_get_endpoint_by_reg(port, 0);
- of_node_put(port);
+ ep = of_graph_get_endpoint_by_regs(node, DSI_PORT_OUT, 0);
if (!ep) {
- dev_err(dev, "no endpoint specified in output port\n");
+ dev_err(dev, "no output port with endpoint specified\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 81cc5537cf25..f851a40ac6cb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -97,20 +97,9 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
&exynos_fb->exynos_gem[0]->base, handle);
}
-static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
- struct drm_file *file_priv, unsigned flags,
- unsigned color, struct drm_clip_rect *clips,
- unsigned num_clips)
-{
- /* TODO */
-
- return 0;
-}
-
static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
.destroy = exynos_drm_fb_destroy,
.create_handle = exynos_drm_fb_create_handle,
- .dirty = exynos_drm_fb_dirty,
};
struct drm_framebuffer *
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index cec508f9a335..3efe1aa89416 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -397,9 +397,16 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
const struct drm_display_mode *mode)
{
- unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
+ unsigned long ideal_clk;
u32 clkdiv;
+ if (mode->clock == 0) {
+ DRM_ERROR("Mode has zero clock value.\n");
+ return 0xff;
+ }
+
+ ideal_clk = mode->clock * 1000;
+
if (ctx->i80_if) {
/*
* The frame done interrupt should be occurred prior to the
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 193d3602dffb..493552368295 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -383,8 +383,8 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
return;
out:
- exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr->sgt,
- DMA_BIDIRECTIONAL);
+ dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl,
+ g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);
pages = frame_vector_pages(g2d_userptr->vec);
if (!IS_ERR(pages)) {
@@ -501,10 +501,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
g2d_userptr->sgt = sgt;
- ret = exynos_gem_map_sgt_with_dma(drm_dev, g2d_userptr->sgt,
- DMA_BIDIRECTIONAL);
- if (ret < 0) {
+ if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL)) {
DRM_ERROR("failed to map sgt with dma region.\n");
+ ret = -ENOMEM;
goto err_sg_free_table;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 6fb98f4c3544..72d9414bd944 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -378,28 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
return 0;
}
-int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,
- struct sg_table *sgt,
- enum dma_data_direction dir)
-{
- int nents;
-
- nents = dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, dir);
- if (!nents) {
- DRM_ERROR("failed to map sgl with dma.\n");
- return nents;
- }
-
- return 0;
-}
-
-void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
- struct sg_table *sgt,
- enum dma_data_direction dir)
-{
- dma_unmap_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents, dir);
-}
-
void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{
exynos_drm_gem_destroy(to_exynos_gem(obj));
@@ -503,22 +481,12 @@ out:
}
}
-int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+static int exynos_drm_gem_mmap_obj(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
{
- struct exynos_drm_gem *exynos_gem;
- struct drm_gem_object *obj;
+ struct exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
int ret;
- /* set vm_area_struct. */
- ret = drm_gem_mmap(filp, vma);
- if (ret < 0) {
- DRM_ERROR("failed to mmap.\n");
- return ret;
- }
-
- obj = vma->vm_private_data;
- exynos_gem = to_exynos_gem(obj);
-
DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags);
/* non-cachable as default. */
@@ -543,6 +511,26 @@ err_close_vm:
return ret;
}
+int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ /* set vm_area_struct. */
+ ret = drm_gem_mmap(filp, vma);
+ if (ret < 0) {
+ DRM_ERROR("failed to mmap.\n");
+ return ret;
+ }
+
+ obj = vma->vm_private_data;
+
+ if (obj->import_attach)
+ return dma_buf_mmap(obj->dma_buf, vma, 0);
+
+ return exynos_drm_gem_mmap_obj(obj, vma);
+}
+
/* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
@@ -617,3 +605,15 @@ void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{
/* Nothing to do */
}
+
+int exynos_drm_gem_prime_mmap(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
+{
+ int ret;
+
+ ret = drm_gem_mmap_obj(obj, obj->size, vma);
+ if (ret < 0)
+ return ret;
+
+ return exynos_drm_gem_mmap_obj(obj, vma);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 00223052b87b..78100742281d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -121,16 +121,6 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
/* set vm_flags and we can change the vm attribute to other one at here. */
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
-/* map sgt with dma region. */
-int exynos_gem_map_sgt_with_dma(struct drm_device *drm_dev,
- struct sg_table *sgt,
- enum dma_data_direction dir);
-
-/* unmap sgt from dma region. */
-void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
- struct sg_table *sgt,
- enum dma_data_direction dir);
-
/* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *
@@ -139,5 +129,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
struct sg_table *sgt);
void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj);
void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+int exynos_drm_gem_prime_mmap(struct drm_gem_object *obj,
+ struct vm_area_struct *vma);
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 0f87acb4cf21..6cd09944405f 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -146,6 +146,7 @@ struct hdmi_context {
struct clk **clk_muxes;
struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
struct regulator *reg_hdmi_en;
+ struct exynos_drm_clk phy_clk;
};
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
@@ -1445,7 +1446,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
static void hdmi_conf_apply(struct hdmi_context *hdata)
{
- hdmiphy_conf_apply(hdata);
hdmi_start(hdata, false);
hdmi_conf_init(hdata);
hdmi_audio_init(hdata);
@@ -1478,10 +1478,8 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on)
SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0);
}
-static void hdmi_enable(struct drm_encoder *encoder)
+static void hdmiphy_enable(struct hdmi_context *hdata)
{
- struct hdmi_context *hdata = encoder_to_hdmi(encoder);
-
if (hdata->powered)
return;
@@ -1497,11 +1495,40 @@ static void hdmi_enable(struct drm_encoder *encoder)
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
- hdmi_conf_apply(hdata);
+ hdmiphy_conf_apply(hdata);
hdata->powered = true;
}
+static void hdmiphy_disable(struct hdmi_context *hdata)
+{
+ if (!hdata->powered)
+ return;
+
+ hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
+
+ hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
+
+ hdmi_set_refclk(hdata, false);
+
+ regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
+ PMU_HDMI_PHY_ENABLE_BIT, 0);
+
+ regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
+
+ pm_runtime_put_sync(hdata->dev);
+
+ hdata->powered = false;
+}
+
+static void hdmi_enable(struct drm_encoder *encoder)
+{
+ struct hdmi_context *hdata = encoder_to_hdmi(encoder);
+
+ hdmiphy_enable(hdata);
+ hdmi_conf_apply(hdata);
+}
+
static void hdmi_disable(struct drm_encoder *encoder)
{
struct hdmi_context *hdata = encoder_to_hdmi(encoder);
@@ -1525,22 +1552,9 @@ static void hdmi_disable(struct drm_encoder *encoder)
if (funcs && funcs->disable)
(*funcs->disable)(crtc);
- hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
-
cancel_delayed_work(&hdata->hotplug_work);
- hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN);
-
- hdmi_set_refclk(hdata, false);
-
- regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
- PMU_HDMI_PHY_ENABLE_BIT, 0);
-
- regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
-
- pm_runtime_put_sync(hdata->dev);
-
- hdata->powered = false;
+ hdmiphy_disable(hdata);
}
static const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
@@ -1625,6 +1639,17 @@ static int hdmi_clk_init(struct hdmi_context *hdata)
}
+static void hdmiphy_clk_enable(struct exynos_drm_clk *clk, bool enable)
+{
+ struct hdmi_context *hdata = container_of(clk, struct hdmi_context,
+ phy_clk);
+
+ if (enable)
+ hdmiphy_enable(hdata);
+ else
+ hdmiphy_disable(hdata);
+}
+
static int hdmi_resources_init(struct hdmi_context *hdata)
{
struct device *dev = hdata->dev;
@@ -1658,7 +1683,8 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
}
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
if (ret) {
- DRM_ERROR("failed to get regulators\n");
+ if (ret != -EPROBE_DEFER)
+ DRM_ERROR("failed to get regulators\n");
return ret;
}
@@ -1710,6 +1736,10 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
if (pipe < 0)
return pipe;
+ hdata->phy_clk.enable = hdmiphy_clk_enable;
+
+ exynos_drm_crtc_from_pipe(drm_dev, pipe)->pipe_clk = &hdata->phy_clk;
+
encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
@@ -1777,7 +1807,8 @@ static int hdmi_probe(struct platform_device *pdev)
ret = hdmi_resources_init(hdata);
if (ret) {
- DRM_ERROR("hdmi_resources_init failed\n");
+ if (ret != -EPROBE_DEFER)
+ DRM_ERROR("hdmi_resources_init failed\n");
return ret;
}