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
This commit is contained in:
commit
6d23abf58a
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue