Commit 6d23abf5 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'exynos-drm-next' of...

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
parents 19ea5da0 dd65a686
...@@ -147,11 +147,13 @@ static void decon_commit(struct exynos_drm_crtc *crtc) ...@@ -147,11 +147,13 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
writel(val, ctx->addr + DECON_CMU); 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 */ /* lcd on and use command if */
val = VIDOUT_LCD_ON; val = VIDOUT_LCD_ON;
if (ctx->out_type & IFTYPE_I80) { if (ctx->out_type & IFTYPE_I80) {
val |= VIDOUT_COMMAND_IF; val |= VIDOUT_COMMAND_IF;
decon_setup_trigger(ctx);
} else { } else {
val |= VIDOUT_RGB_IF; val |= VIDOUT_RGB_IF;
} }
...@@ -376,9 +378,6 @@ static void decon_swreset(struct decon_context *ctx) ...@@ -376,9 +378,6 @@ static void decon_swreset(struct decon_context *ctx)
writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1); writel(VIDCON1_VCLK_RUN_VDEN_DISABLE, ctx->addr + DECON_VIDCON1);
writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN, writel(CRCCTRL_CRCEN | CRCCTRL_CRCSTART_F | CRCCTRL_CRCCLKEN,
ctx->addr + DECON_CRCCTRL); ctx->addr + DECON_CRCCTRL);
if (ctx->out_type & IFTYPE_I80)
decon_setup_trigger(ctx);
} }
static void decon_enable(struct exynos_drm_crtc *crtc) static void decon_enable(struct exynos_drm_crtc *crtc)
...@@ -434,13 +433,12 @@ static void decon_te_irq_handler(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; 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; return;
if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags)) if (test_and_clear_bit(BIT_WIN_UPDATED, &ctx->flags))
decon_set_bits(ctx, DECON_TRIGCON, TRIGCON_SWTRIGCMD, ~0); 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) 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) ...@@ -573,6 +571,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
/* clear */ /* clear */
writel(val, ctx->addr + DECON_VIDINTCON1); writel(val, ctx->addr + DECON_VIDINTCON1);
drm_crtc_handle_vblank(&ctx->crtc->base);
} }
out: out:
...@@ -648,9 +647,8 @@ static int exynos5433_decon_probe(struct platform_device *pdev) ...@@ -648,9 +647,8 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
if (ctx->out_type & IFTYPE_HDMI) { if (ctx->out_type & IFTYPE_HDMI) {
ctx->first_win = 1; ctx->first_win = 1;
ctx->out_type = IFTYPE_I80;
} else if (of_get_child_by_name(dev->of_node, "i80-if-timings")) { } 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++) { for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) {
......
...@@ -233,20 +233,15 @@ void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc, ...@@ -233,20 +233,15 @@ void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&crtc->dev->event_lock, flags); spin_lock_irqsave(&crtc->dev->event_lock, flags);
e = exynos_crtc->event; e = exynos_crtc->event;
if (e && e->base.file_priv == file) { if (e && e->base.file_priv == file) {
exynos_crtc->event = NULL; 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); atomic_dec(&exynos_crtc->pending_update);
} }
spin_unlock_irqrestore(&crtc->dev->event_lock, flags); spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
if (e && e->base.file_priv == file)
drm_event_cancel_free(crtc->dev, &e->base);
} }
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <video/of_videomode.h> #include <video/of_videomode.h>
...@@ -164,67 +165,6 @@ static const struct drm_encoder_funcs exynos_dpi_encoder_funcs = { ...@@ -164,67 +165,6 @@ static const struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
.destroy = drm_encoder_cleanup, .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 { enum {
FIMD_PORT_IN0, FIMD_PORT_IN0,
FIMD_PORT_IN1, FIMD_PORT_IN1,
...@@ -237,12 +177,7 @@ static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev) ...@@ -237,12 +177,7 @@ static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
{ {
struct device_node *np, *ep; struct device_node *np, *ep;
np = of_graph_get_port_by_reg(dev->of_node, FIMD_PORT_RGB); ep = of_graph_get_endpoint_by_regs(dev->of_node, FIMD_PORT_RGB, 0);
if (!np)
return NULL;
ep = of_graph_get_endpoint_by_reg(np, 0);
of_node_put(np);
if (!ep) if (!ep)
return NULL; return NULL;
......
...@@ -431,6 +431,7 @@ static struct drm_driver exynos_drm_driver = { ...@@ -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_import_sg_table = exynos_drm_gem_prime_import_sg_table,
.gem_prime_vmap = exynos_drm_gem_prime_vmap, .gem_prime_vmap = exynos_drm_gem_prime_vmap,
.gem_prime_vunmap = exynos_drm_gem_prime_vunmap, .gem_prime_vunmap = exynos_drm_gem_prime_vunmap,
.gem_prime_mmap = exynos_drm_gem_prime_mmap,
.ioctls = exynos_ioctls, .ioctls = exynos_ioctls,
.num_ioctls = ARRAY_SIZE(exynos_ioctls), .num_ioctls = ARRAY_SIZE(exynos_ioctls),
.fops = &exynos_drm_driver_fops, .fops = &exynos_drm_driver_fops,
......
...@@ -1632,50 +1632,6 @@ static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = { ...@@ -1632,50 +1632,6 @@ static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); 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, static int exynos_dsi_of_read_u32(const struct device_node *np,
const char *propname, u32 *out_value) const char *propname, u32 *out_value)
{ {
...@@ -1697,7 +1653,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) ...@@ -1697,7 +1653,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
{ {
struct device *dev = dsi->dev; struct device *dev = dsi->dev;
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct device_node *port, *ep; struct device_node *ep;
int ret; int ret;
ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency", 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) ...@@ -1705,16 +1661,9 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
if (ret < 0) if (ret < 0)
return ret; return ret;
port = of_graph_get_port_by_reg(node, DSI_PORT_OUT); ep = of_graph_get_endpoint_by_regs(node, DSI_PORT_OUT, 0);
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);
if (!ep) { if (!ep) {
dev_err(dev, "no endpoint specified in output port\n"); dev_err(dev, "no output port with endpoint specified\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -97,20 +97,9 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, ...@@ -97,20 +97,9 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
&exynos_fb->exynos_gem[0]->base, handle); &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 = { static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
.destroy = exynos_drm_fb_destroy, .destroy = exynos_drm_fb_destroy,
.create_handle = exynos_drm_fb_create_handle, .create_handle = exynos_drm_fb_create_handle,
.dirty = exynos_drm_fb_dirty,
}; };
struct drm_framebuffer * struct drm_framebuffer *
......
...@@ -397,9 +397,16 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) ...@@ -397,9 +397,16 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc)
static u32 fimd_calc_clkdiv(struct fimd_context *ctx, static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
{ {
unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; unsigned long ideal_clk;
u32 clkdiv; 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) { if (ctx->i80_if) {
/* /*
* The frame done interrupt should be occurred prior to the * The frame done interrupt should be occurred prior to the
......
...@@ -383,8 +383,8 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev, ...@@ -383,8 +383,8 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
return; return;
out: out:
exynos_gem_unmap_sgt_from_dma(drm_dev, g2d_userptr->sgt, dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl,
DMA_BIDIRECTIONAL); g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);
pages = frame_vector_pages(g2d_userptr->vec); pages = frame_vector_pages(g2d_userptr->vec);
if (!IS_ERR(pages)) { if (!IS_ERR(pages)) {
...@@ -501,10 +501,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, ...@@ -501,10 +501,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
g2d_userptr->sgt = sgt; g2d_userptr->sgt = sgt;
ret = exynos_gem_map_sgt_with_dma(drm_dev, g2d_userptr->sgt, if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL)) {
if (ret < 0) {
DRM_ERROR("failed to map sgt with dma region.\n"); DRM_ERROR("failed to map sgt with dma region.\n");
ret = -ENOMEM;
goto err_sg_free_table; goto err_sg_free_table;
} }
......
...@@ -378,28 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data, ...@@ -378,28 +378,6 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
return 0; 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) void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{ {
exynos_drm_gem_destroy(to_exynos_gem(obj)); exynos_drm_gem_destroy(to_exynos_gem(obj));
...@@ -503,22 +481,12 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -503,22 +481,12 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
} }
} }
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 exynos_drm_gem *exynos_gem = to_exynos_gem(obj);
struct drm_gem_object *obj;
int ret; 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); DRM_DEBUG_KMS("flags = 0x%x\n", exynos_gem->flags);
/* non-cachable as default. */ /* non-cachable as default. */
...@@ -543,6 +511,26 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -543,6 +511,26 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return ret; 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 */ /* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj) 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) ...@@ -617,3 +605,15 @@ void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{ {
/* Nothing to do */ /* 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);
}
...@@ -121,16 +121,6 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); ...@@ -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. */ /* 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); 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 */ /* low-level interface prime helpers */
struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj); struct sg_table *exynos_drm_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object * struct drm_gem_object *
...@@ -139,5 +129,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, ...@@ -139,5 +129,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev,
struct sg_table *sgt); struct sg_table *sgt);
void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj); void *exynos_drm_gem_prime_vmap(struct drm_gem_object *obj);
void exynos_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); 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 #endif
...@@ -146,6 +146,7 @@ struct hdmi_context { ...@@ -146,6 +146,7 @@ struct hdmi_context {
struct clk **clk_muxes; struct clk **clk_muxes;
struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)];
struct regulator *reg_hdmi_en; struct regulator *reg_hdmi_en;
struct exynos_drm_clk phy_clk;
}; };
static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e) 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) ...@@ -1445,7 +1446,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
static void hdmi_conf_apply(struct hdmi_context *hdata) static void hdmi_conf_apply(struct hdmi_context *hdata)
{ {
hdmiphy_conf_apply(hdata);
hdmi_start(hdata, false); hdmi_start(hdata, false);
hdmi_conf_init(hdata); hdmi_conf_init(hdata);
hdmi_audio_init(hdata); hdmi_audio_init(hdata);
...@@ -1478,10 +1478,8 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on) ...@@ -1478,10 +1478,8 @@ static void hdmi_set_refclk(struct hdmi_context *hdata, bool on)
SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0); 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) if (hdata->powered)
return; return;
...@@ -1497,11 +1495,40 @@ static void hdmi_enable(struct drm_encoder *encoder) ...@@ -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_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN);
hdmi_conf_apply(hdata); hdmiphy_conf_apply(hdata);
hdata->powered = true; 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) static void hdmi_disable(struct drm_encoder *encoder)
{ {
struct hdmi_context *hdata = encoder_to_hdmi(encoder); struct hdmi_context *hdata = encoder_to_hdmi(encoder);
...@@ -1525,22 +1552,9 @@ static void hdmi_disable(struct drm_encoder *encoder) ...@@ -1525,22 +1552,9 @@ static void hdmi_disable(struct drm_encoder *encoder)
if (funcs && funcs->disable) if (funcs && funcs->disable)
(*funcs->disable)(crtc); (*funcs->disable)(crtc);
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
cancel_delayed_work(&hdata->hotplug_work); cancel_delayed_work(&hdata->hotplug_work);
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN); hdmiphy_disable(hdata);
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 const struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = { 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) ...@@ -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) static int hdmi_resources_init(struct hdmi_context *hdata)
{ {
struct device *dev = hdata->dev; struct device *dev = hdata->dev;
...@@ -1658,7 +1683,8 @@ static int hdmi_resources_init(struct hdmi_context *hdata) ...@@ -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); ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
if (ret) { if (ret) {
DRM_ERROR("failed to get regulators\n"); if (ret != -EPROBE_DEFER)
DRM_ERROR("failed to get regulators\n");
return ret; return ret;
} }
...@@ -1710,6 +1736,10 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -1710,6 +1736,10 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
if (pipe < 0) if (pipe < 0)
return pipe; 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; encoder->possible_crtcs = 1 << pipe;
DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
...@@ -1777,7 +1807,8 @@ static int hdmi_probe(struct platform_device *pdev) ...@@ -1777,7 +1807,8 @@ static int hdmi_probe(struct platform_device *pdev)
ret = hdmi_resources_init(hdata); ret = hdmi_resources_init(hdata);
if (ret) { if (ret) {
DRM_ERROR("hdmi_resources_init failed\n"); if (ret != -EPROBE_DEFER)
DRM_ERROR("hdmi_resources_init failed\n");
return ret; return ret;
} }
......
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