You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'imx-drm-next-2015-01-09' of git://git.pengutronix.de/git/pza/linux into drm-next
imx-drm mode fixup support, imx-hdmi bridge conversion and imx-drm cleanup - Implement mode_fixup for a DI vertical timing limitation - Use generic DRM OF helpers in DRM core - Convert imx-hdmi to dw_hdmi drm_bridge and add rockchip driver - Add DC use counter to fix multi-display support - Simplify handling of DI clock flags - A few small fixes and cleanup * tag 'imx-drm-next-2015-01-09' of git://git.pengutronix.de/git/pza/linux: (26 commits) imx-drm: core: handling of DI clock flags to ipu_crtc_mode_set() gpu: ipu-di: Switch to DIV_ROUND_CLOSEST for DI clock divider calc gpu: ipu-v3: Use videomode in struct ipu_di_signal_cfg imx-drm: encoder prepare/mode_set must use adjusted mode imx-drm: ipuv3-crtc: Implement mode_fixup drm_modes: add drm_display_mode_to_videomode gpu: ipu-di: remove some non-functional code gpu: ipu-di: Add ipu_di_adjust_videomode() drm: rockchip: export functions needed by rockchip dw_hdmi bridge driver drm: bridge/dw_hdmi: request interrupt only after initializing the mutes drm: bridge/dw_hdmi: add rockchip rk3288 support dt-bindings: Add documentation for rockchip dw hdmi drm: bridge/dw_hdmi: add function dw_hdmi_phy_enable_spare drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done drm: bridge/dw_hdmi: add mode_valid support drm: bridge/dw_hdmi: add support for multi-byte register width access dt-bindings: add document for dw_hdmi drm: imx: imx-hdmi: move imx-hdmi to bridge/dw_hdmi drm: imx: imx-hdmi: split phy configuration to platform driver drm: imx: imx-hdmi: convert imx-hdmi to drm_bridge mode ...
This commit is contained in:
@@ -3,3 +3,8 @@ config DRM_PTN3460
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER
|
||||
---help---
|
||||
|
||||
config DRM_DW_HDMI
|
||||
tristate
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ccflags-y := -Iinclude/drm
|
||||
|
||||
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
|
||||
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -837,7 +837,8 @@ enum {
|
||||
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
|
||||
HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
|
||||
HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
|
||||
HDMI_PHY_CONF0_SPARECTRL = 0x20,
|
||||
HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
|
||||
HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
|
||||
HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
|
||||
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
|
||||
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
|
||||
@@ -1029,4 +1030,5 @@ enum {
|
||||
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
|
||||
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
|
||||
};
|
||||
|
||||
#endif /* __IMX_HDMI_H__ */
|
||||
@@ -615,6 +615,46 @@ void drm_display_mode_from_videomode(const struct videomode *vm,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
|
||||
|
||||
/**
|
||||
* drm_display_mode_to_videomode - fill in @vm using @dmode,
|
||||
* @dmode: drm_display_mode structure to use as source
|
||||
* @vm: videomode structure to use as destination
|
||||
*
|
||||
* Fills out @vm using the display mode specified in @dmode.
|
||||
*/
|
||||
void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
|
||||
struct videomode *vm)
|
||||
{
|
||||
vm->hactive = dmode->hdisplay;
|
||||
vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
|
||||
vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
|
||||
vm->hback_porch = dmode->htotal - dmode->hsync_end;
|
||||
|
||||
vm->vactive = dmode->vdisplay;
|
||||
vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
|
||||
vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
|
||||
vm->vback_porch = dmode->vtotal - dmode->vsync_end;
|
||||
|
||||
vm->pixelclock = dmode->clock * 1000;
|
||||
|
||||
vm->flags = 0;
|
||||
if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
|
||||
else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
|
||||
if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
|
||||
else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
|
||||
if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
vm->flags |= DISPLAY_FLAGS_INTERLACED;
|
||||
if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
|
||||
if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_get_drm_display_mode - get a drm_display_mode from devicetree
|
||||
|
||||
@@ -49,6 +49,7 @@ config DRM_IMX_IPUV3
|
||||
|
||||
config DRM_IMX_HDMI
|
||||
tristate "Freescale i.MX DRM HDMI"
|
||||
select DRM_DW_HDMI
|
||||
depends on DRM_IMX
|
||||
help
|
||||
Choose this if you want to use HDMI on i.MX6.
|
||||
|
||||
@@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
|
||||
|
||||
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
|
||||
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
|
||||
obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
|
||||
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
#include <video/imx-ipu-v3.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
|
||||
#include "imx-drm.h"
|
||||
|
||||
struct imx_hdmi {
|
||||
struct device *dev;
|
||||
struct drm_encoder encoder;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
|
||||
{
|
||||
45250000, {
|
||||
{ 0x01e0, 0x0000 },
|
||||
{ 0x21e1, 0x0000 },
|
||||
{ 0x41e2, 0x0000 }
|
||||
},
|
||||
}, {
|
||||
92500000, {
|
||||
{ 0x0140, 0x0005 },
|
||||
{ 0x2141, 0x0005 },
|
||||
{ 0x4142, 0x0005 },
|
||||
},
|
||||
}, {
|
||||
148500000, {
|
||||
{ 0x00a0, 0x000a },
|
||||
{ 0x20a1, 0x000a },
|
||||
{ 0x40a2, 0x000a },
|
||||
},
|
||||
}, {
|
||||
~0UL, {
|
||||
{ 0x00a0, 0x000a },
|
||||
{ 0x2001, 0x000f },
|
||||
{ 0x4002, 0x000f },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
|
||||
/* pixelclk bpp8 bpp10 bpp12 */
|
||||
{
|
||||
54000000, { 0x091c, 0x091c, 0x06dc },
|
||||
}, {
|
||||
58400000, { 0x091c, 0x06dc, 0x06dc },
|
||||
}, {
|
||||
72000000, { 0x06dc, 0x06dc, 0x091c },
|
||||
}, {
|
||||
74250000, { 0x06dc, 0x0b5c, 0x091c },
|
||||
}, {
|
||||
118800000, { 0x091c, 0x091c, 0x06dc },
|
||||
}, {
|
||||
216000000, { 0x06dc, 0x0b5c, 0x091c },
|
||||
}
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_sym_term imx_sym_term[] = {
|
||||
/*pixelclk symbol term*/
|
||||
{ 148500000, 0x800d, 0x0005 },
|
||||
{ ~0UL, 0x0000, 0x0000 }
|
||||
};
|
||||
|
||||
static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
|
||||
{
|
||||
struct device_node *np = hdmi->dev->of_node;
|
||||
|
||||
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
|
||||
if (IS_ERR(hdmi->regmap)) {
|
||||
dev_err(hdmi->dev, "Unable to get gpr\n");
|
||||
return PTR_ERR(hdmi->regmap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
static bool dw_hdmi_imx_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
|
||||
int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
|
||||
|
||||
regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
|
||||
IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
|
||||
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
|
||||
}
|
||||
|
||||
static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
|
||||
}
|
||||
|
||||
static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
|
||||
.mode_fixup = dw_hdmi_imx_encoder_mode_fixup,
|
||||
.mode_set = dw_hdmi_imx_encoder_mode_set,
|
||||
.prepare = dw_hdmi_imx_encoder_prepare,
|
||||
.commit = dw_hdmi_imx_encoder_commit,
|
||||
.disable = dw_hdmi_imx_encoder_disable,
|
||||
};
|
||||
|
||||
static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
|
||||
.mpll_cfg = imx_mpll_cfg,
|
||||
.cur_ctr = imx_cur_ctr,
|
||||
.sym_term = imx_sym_term,
|
||||
.dev_type = IMX6Q_HDMI,
|
||||
};
|
||||
|
||||
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
|
||||
.mpll_cfg = imx_mpll_cfg,
|
||||
.cur_ctr = imx_cur_ctr,
|
||||
.sym_term = imx_sym_term,
|
||||
.dev_type = IMX6DL_HDMI,
|
||||
};
|
||||
|
||||
static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-hdmi",
|
||||
.data = &imx6q_hdmi_drv_data
|
||||
}, {
|
||||
.compatible = "fsl,imx6dl-hdmi",
|
||||
.data = &imx6dl_hdmi_drv_data
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
|
||||
|
||||
static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
const struct dw_hdmi_plat_data *plat_data;
|
||||
const struct of_device_id *match;
|
||||
struct drm_device *drm = data;
|
||||
struct drm_encoder *encoder;
|
||||
struct imx_hdmi *hdmi;
|
||||
struct resource *iores;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
|
||||
plat_data = match->data;
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENXIO;
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (encoder->possible_crtcs == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = dw_hdmi_imx_parse_dt(hdmi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
|
||||
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
|
||||
}
|
||||
|
||||
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
return dw_hdmi_unbind(dev, master, data);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_imx_ops = {
|
||||
.bind = dw_hdmi_imx_bind,
|
||||
.unbind = dw_hdmi_imx_unbind,
|
||||
};
|
||||
|
||||
static int dw_hdmi_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
return component_add(&pdev->dev, &dw_hdmi_imx_ops);
|
||||
}
|
||||
|
||||
static int dw_hdmi_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_del(&pdev->dev, &dw_hdmi_imx_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dw_hdmi_imx_platform_driver = {
|
||||
.probe = dw_hdmi_imx_probe,
|
||||
.remove = dw_hdmi_imx_remove,
|
||||
.driver = {
|
||||
.name = "dwhdmi-imx",
|
||||
.of_match_table = dw_hdmi_imx_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dw_hdmi_imx_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
|
||||
MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:dwhdmi-imx");
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
#include "imx-drm.h"
|
||||
|
||||
@@ -46,7 +47,6 @@ struct imx_drm_crtc {
|
||||
struct drm_crtc *crtc;
|
||||
int pipe;
|
||||
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
|
||||
struct device_node *port;
|
||||
};
|
||||
|
||||
static int legacyfb_depth = 16;
|
||||
@@ -116,8 +116,7 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
|
||||
helper = &imx_crtc->imx_drm_helper_funcs;
|
||||
if (helper->set_interface_pix_fmt)
|
||||
return helper->set_interface_pix_fmt(encoder->crtc,
|
||||
encoder->encoder_type, interface_pix_fmt,
|
||||
hsync_pin, vsync_pin);
|
||||
interface_pix_fmt, hsync_pin, vsync_pin);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
|
||||
@@ -365,9 +364,10 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
|
||||
|
||||
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
|
||||
imx_drm_crtc->pipe = imxdrm->pipes++;
|
||||
imx_drm_crtc->port = port;
|
||||
imx_drm_crtc->crtc = crtc;
|
||||
|
||||
crtc->port = port;
|
||||
|
||||
imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
|
||||
|
||||
*new_crtc = imx_drm_crtc;
|
||||
@@ -408,75 +408,19 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
|
||||
|
||||
/*
|
||||
* Find the DRM CRTC possible mask for the connected endpoint.
|
||||
*
|
||||
* The encoder possible masks are defined by their position in the
|
||||
* mode_config crtc_list. This means that CRTCs must not be added
|
||||
* or removed once the DRM device has been fully initialised.
|
||||
*/
|
||||
static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
|
||||
struct device_node *endpoint)
|
||||
{
|
||||
struct device_node *port;
|
||||
unsigned i;
|
||||
|
||||
port = of_graph_get_remote_port(endpoint);
|
||||
if (!port)
|
||||
return 0;
|
||||
of_node_put(port);
|
||||
|
||||
for (i = 0; i < MAX_CRTC; i++) {
|
||||
struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
|
||||
|
||||
if (imx_drm_crtc && imx_drm_crtc->port == port)
|
||||
return drm_crtc_mask(imx_drm_crtc->crtc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_node *imx_drm_of_get_next_endpoint(
|
||||
const struct device_node *parent, struct device_node *prev)
|
||||
{
|
||||
struct device_node *node = of_graph_get_next_endpoint(parent, prev);
|
||||
|
||||
of_node_put(prev);
|
||||
return node;
|
||||
}
|
||||
|
||||
int imx_drm_encoder_parse_of(struct drm_device *drm,
|
||||
struct drm_encoder *encoder, struct device_node *np)
|
||||
{
|
||||
struct imx_drm_device *imxdrm = drm->dev_private;
|
||||
struct device_node *ep = NULL;
|
||||
uint32_t crtc_mask = 0;
|
||||
int i;
|
||||
uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np);
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
u32 mask;
|
||||
|
||||
ep = imx_drm_of_get_next_endpoint(np, ep);
|
||||
if (!ep)
|
||||
break;
|
||||
|
||||
mask = imx_drm_find_crtc_mask(imxdrm, ep);
|
||||
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (mask == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
crtc_mask |= mask;
|
||||
}
|
||||
|
||||
of_node_put(ep);
|
||||
if (i == 0)
|
||||
return -ENOENT;
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (crtc_mask == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
encoder->possible_crtcs = crtc_mask;
|
||||
|
||||
@@ -487,6 +431,15 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
|
||||
|
||||
static struct device_node *imx_drm_of_get_next_endpoint(
|
||||
const struct device_node *parent, struct device_node *prev)
|
||||
{
|
||||
struct device_node *node = of_graph_get_next_endpoint(parent, prev);
|
||||
|
||||
of_node_put(prev);
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* @node: device tree node containing encoder input ports
|
||||
* @encoder: drm_encoder
|
||||
@@ -510,7 +463,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
|
||||
|
||||
port = of_graph_get_remote_port(ep);
|
||||
of_node_put(port);
|
||||
if (port == imx_crtc->port) {
|
||||
if (port == imx_crtc->crtc->port) {
|
||||
ret = of_graph_parse_endpoint(ep, &endpoint);
|
||||
return ret ? ret : endpoint.port;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
|
||||
struct imx_drm_crtc_helper_funcs {
|
||||
int (*enable_vblank)(struct drm_crtc *crtc);
|
||||
void (*disable_vblank)(struct drm_crtc *crtc);
|
||||
int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
|
||||
int (*set_interface_pix_fmt)(struct drm_crtc *crtc,
|
||||
u32 pix_fmt, int hsync_pin, int vsync_pin);
|
||||
const struct drm_crtc_helper_funcs *crtc_helper_funcs;
|
||||
const struct drm_crtc_funcs *crtc_funcs;
|
||||
|
||||
@@ -163,7 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
|
||||
struct imx_ldb *ldb = imx_ldb_ch->ldb;
|
||||
struct drm_display_mode *mode = &encoder->crtc->mode;
|
||||
struct drm_display_mode *mode = &encoder->crtc->hwmode;
|
||||
u32 pixel_fmt;
|
||||
unsigned long serial_clk;
|
||||
unsigned long di_clk = mode->clock * 1000;
|
||||
@@ -241,8 +241,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
|
||||
}
|
||||
|
||||
static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
struct drm_display_mode *orig_mode,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
|
||||
struct imx_ldb *ldb = imx_ldb_ch->ldb;
|
||||
@@ -574,6 +574,8 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
|
||||
|
||||
channel->connector.funcs->destroy(&channel->connector);
|
||||
channel->encoder.funcs->destroy(&channel->encoder);
|
||||
|
||||
kfree(channel->edid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -307,8 +307,8 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
|
||||
}
|
||||
|
||||
static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
struct drm_display_mode *orig_mode,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct imx_tve *tve = enc_to_tve(encoder);
|
||||
unsigned long rounded_rate;
|
||||
|
||||
@@ -46,7 +46,6 @@ struct ipu_crtc {
|
||||
struct drm_framebuffer *newfb;
|
||||
int irq;
|
||||
u32 interface_pix_fmt;
|
||||
unsigned long di_clkflags;
|
||||
int di_hsync_pin;
|
||||
int di_vsync_pin;
|
||||
};
|
||||
@@ -141,47 +140,51 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_encoder *encoder;
|
||||
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
|
||||
int ret;
|
||||
struct ipu_di_signal_cfg sig_cfg = {};
|
||||
unsigned long encoder_types = 0;
|
||||
u32 out_pixel_fmt;
|
||||
int ret;
|
||||
|
||||
dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
|
||||
mode->hdisplay);
|
||||
dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
|
||||
mode->vdisplay);
|
||||
|
||||
out_pixel_fmt = ipu_crtc->interface_pix_fmt;
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
|
||||
if (encoder->crtc == crtc)
|
||||
encoder_types |= BIT(encoder->encoder_type);
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
sig_cfg.interlaced = 1;
|
||||
if (mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
sig_cfg.Hsync_pol = 1;
|
||||
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
sig_cfg.Vsync_pol = 1;
|
||||
dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
|
||||
__func__, encoder_types);
|
||||
|
||||
/*
|
||||
* If we have DAC, TVDAC or LDB, then we need the IPU DI clock
|
||||
* to be the same as the LDB DI clock.
|
||||
*/
|
||||
if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
|
||||
BIT(DRM_MODE_ENCODER_TVDAC) |
|
||||
BIT(DRM_MODE_ENCODER_LVDS)))
|
||||
sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
|
||||
else
|
||||
sig_cfg.clkflags = 0;
|
||||
|
||||
out_pixel_fmt = ipu_crtc->interface_pix_fmt;
|
||||
|
||||
sig_cfg.enable_pol = 1;
|
||||
sig_cfg.clk_pol = 0;
|
||||
sig_cfg.width = mode->hdisplay;
|
||||
sig_cfg.height = mode->vdisplay;
|
||||
sig_cfg.pixel_fmt = out_pixel_fmt;
|
||||
sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
|
||||
sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
|
||||
sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
|
||||
|
||||
sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
|
||||
sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
|
||||
sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
|
||||
sig_cfg.pixelclock = mode->clock * 1000;
|
||||
sig_cfg.clkflags = ipu_crtc->di_clkflags;
|
||||
|
||||
sig_cfg.v_to_h_sync = 0;
|
||||
|
||||
sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
|
||||
sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
|
||||
|
||||
ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
|
||||
out_pixel_fmt, mode->hdisplay);
|
||||
drm_display_mode_to_videomode(mode, &sig_cfg.mode);
|
||||
|
||||
ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
|
||||
mode->flags & DRM_MODE_FLAG_INTERLACE,
|
||||
out_pixel_fmt, mode->hdisplay);
|
||||
if (ret) {
|
||||
dev_err(ipu_crtc->dev,
|
||||
"initializing display controller failed with %d\n",
|
||||
@@ -237,6 +240,18 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
|
||||
struct videomode vm;
|
||||
int ret;
|
||||
|
||||
drm_display_mode_to_videomode(adjusted_mode, &vm);
|
||||
|
||||
ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
drm_display_mode_from_videomode(&vm, adjusted_mode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -275,7 +290,7 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
|
||||
ipu_crtc->newfb = NULL;
|
||||
}
|
||||
|
||||
static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
|
||||
static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
|
||||
u32 pixfmt, int hsync_pin, int vsync_pin)
|
||||
{
|
||||
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
|
||||
@@ -284,19 +299,6 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
|
||||
ipu_crtc->di_hsync_pin = hsync_pin;
|
||||
ipu_crtc->di_vsync_pin = vsync_pin;
|
||||
|
||||
switch (encoder_type) {
|
||||
case DRM_MODE_ENCODER_DAC:
|
||||
case DRM_MODE_ENCODER_TVDAC:
|
||||
case DRM_MODE_ENCODER_LVDS:
|
||||
ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
|
||||
IPU_DI_CLKMODE_EXT;
|
||||
break;
|
||||
case DRM_MODE_ENCODER_TMDS:
|
||||
case DRM_MODE_ENCODER_NONE:
|
||||
ipu_crtc->di_clkflags = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,8 +130,8 @@ static void imx_pd_encoder_commit(struct drm_encoder *encoder)
|
||||
}
|
||||
|
||||
static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
struct drm_display_mode *orig_mode,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -257,6 +257,8 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
|
||||
|
||||
imxpd->encoder.funcs->destroy(&imxpd->encoder);
|
||||
imxpd->connector.funcs->destroy(&imxpd->connector);
|
||||
|
||||
kfree(imxpd->edid);
|
||||
}
|
||||
|
||||
static const struct component_ops imx_pd_ops = {
|
||||
@@ -272,6 +274,7 @@ static int imx_pd_probe(struct platform_device *pdev)
|
||||
static int imx_pd_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_del(&pdev->dev, &imx_pd_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,3 +15,13 @@ config DRM_ROCKCHIP
|
||||
management to userspace. This driver does not provide
|
||||
2D or 3D acceleration; acceleration is performed by other
|
||||
IP found on the SoC.
|
||||
|
||||
config ROCKCHIP_DW_HDMI
|
||||
tristate "Rockchip specific extensions for Synopsys DW HDMI"
|
||||
depends on DRM_ROCKCHIP
|
||||
select DRM_DW_HDMI
|
||||
help
|
||||
This selects support for Rockchip SoC specific extensions
|
||||
for the Synopsys DesignWare HDMI driver. If you want to
|
||||
enable HDMI on RK3288 based SoC, you should selet this
|
||||
option.
|
||||
|
||||
@@ -5,4 +5,6 @@
|
||||
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
|
||||
rockchip_drm_gem.o
|
||||
|
||||
obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
|
||||
|
||||
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder_slave.h>
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
|
||||
#include "rockchip_drm_drv.h"
|
||||
#include "rockchip_drm_vop.h"
|
||||
|
||||
#define GRF_SOC_CON6 0x025c
|
||||
#define HDMI_SEL_VOP_LIT (1 << 4)
|
||||
|
||||
struct rockchip_hdmi {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct drm_encoder encoder;
|
||||
};
|
||||
|
||||
#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
|
||||
|
||||
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
|
||||
{
|
||||
27000000, {
|
||||
{ 0x00b3, 0x0000},
|
||||
{ 0x2153, 0x0000},
|
||||
{ 0x40f3, 0x0000}
|
||||
},
|
||||
}, {
|
||||
36000000, {
|
||||
{ 0x00b3, 0x0000},
|
||||
{ 0x2153, 0x0000},
|
||||
{ 0x40f3, 0x0000}
|
||||
},
|
||||
}, {
|
||||
40000000, {
|
||||
{ 0x00b3, 0x0000},
|
||||
{ 0x2153, 0x0000},
|
||||
{ 0x40f3, 0x0000}
|
||||
},
|
||||
}, {
|
||||
54000000, {
|
||||
{ 0x0072, 0x0001},
|
||||
{ 0x2142, 0x0001},
|
||||
{ 0x40a2, 0x0001},
|
||||
},
|
||||
}, {
|
||||
65000000, {
|
||||
{ 0x0072, 0x0001},
|
||||
{ 0x2142, 0x0001},
|
||||
{ 0x40a2, 0x0001},
|
||||
},
|
||||
}, {
|
||||
66000000, {
|
||||
{ 0x013e, 0x0003},
|
||||
{ 0x217e, 0x0002},
|
||||
{ 0x4061, 0x0002}
|
||||
},
|
||||
}, {
|
||||
74250000, {
|
||||
{ 0x0072, 0x0001},
|
||||
{ 0x2145, 0x0002},
|
||||
{ 0x4061, 0x0002}
|
||||
},
|
||||
}, {
|
||||
83500000, {
|
||||
{ 0x0072, 0x0001},
|
||||
},
|
||||
}, {
|
||||
108000000, {
|
||||
{ 0x0051, 0x0002},
|
||||
{ 0x2145, 0x0002},
|
||||
{ 0x4061, 0x0002}
|
||||
},
|
||||
}, {
|
||||
106500000, {
|
||||
{ 0x0051, 0x0002},
|
||||
{ 0x2145, 0x0002},
|
||||
{ 0x4061, 0x0002}
|
||||
},
|
||||
}, {
|
||||
146250000, {
|
||||
{ 0x0051, 0x0002},
|
||||
{ 0x2145, 0x0002},
|
||||
{ 0x4061, 0x0002}
|
||||
},
|
||||
}, {
|
||||
148500000, {
|
||||
{ 0x0051, 0x0003},
|
||||
{ 0x214c, 0x0003},
|
||||
{ 0x4064, 0x0003}
|
||||
},
|
||||
}, {
|
||||
~0UL, {
|
||||
{ 0x00a0, 0x000a },
|
||||
{ 0x2001, 0x000f },
|
||||
{ 0x4002, 0x000f },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
||||
/* pixelclk bpp8 bpp10 bpp12 */
|
||||
{
|
||||
40000000, { 0x0018, 0x0018, 0x0018 },
|
||||
}, {
|
||||
65000000, { 0x0028, 0x0028, 0x0028 },
|
||||
}, {
|
||||
66000000, { 0x0038, 0x0038, 0x0038 },
|
||||
}, {
|
||||
74250000, { 0x0028, 0x0038, 0x0038 },
|
||||
}, {
|
||||
83500000, { 0x0028, 0x0038, 0x0038 },
|
||||
}, {
|
||||
146250000, { 0x0038, 0x0038, 0x0038 },
|
||||
}, {
|
||||
148500000, { 0x0000, 0x0038, 0x0038 },
|
||||
}, {
|
||||
~0UL, { 0x0000, 0x0000, 0x0000},
|
||||
}
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_sym_term rockchip_sym_term[] = {
|
||||
/*pixelclk symbol term*/
|
||||
{ 74250000, 0x8009, 0x0004 },
|
||||
{ 148500000, 0x8029, 0x0004 },
|
||||
{ 297000000, 0x8039, 0x0005 },
|
||||
{ ~0UL, 0x0000, 0x0000 }
|
||||
};
|
||||
|
||||
static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
|
||||
{
|
||||
struct device_node *np = hdmi->dev->of_node;
|
||||
|
||||
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
|
||||
if (IS_ERR(hdmi->regmap)) {
|
||||
dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
|
||||
return PTR_ERR(hdmi->regmap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
|
||||
int pclk = mode->clock * 1000;
|
||||
bool valid = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
|
||||
if (pclk == mpll_cfg[i].mpixelclock) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (valid) ? MODE_OK : MODE_BAD;
|
||||
}
|
||||
|
||||
static struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
|
||||
u32 val;
|
||||
int mux;
|
||||
|
||||
mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
|
||||
if (mux)
|
||||
val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
|
||||
else
|
||||
val = HDMI_SEL_VOP_LIT << 16;
|
||||
|
||||
regmap_write(hdmi->regmap, GRF_SOC_CON6, val);
|
||||
dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
|
||||
(mux) ? "LIT" : "BIG");
|
||||
}
|
||||
|
||||
static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
|
||||
ROCKCHIP_OUT_MODE_AAAA);
|
||||
}
|
||||
|
||||
static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
|
||||
.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
|
||||
.mode_set = dw_hdmi_rockchip_encoder_mode_set,
|
||||
.prepare = dw_hdmi_rockchip_encoder_prepare,
|
||||
.commit = dw_hdmi_rockchip_encoder_commit,
|
||||
.disable = dw_hdmi_rockchip_encoder_disable,
|
||||
};
|
||||
|
||||
static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
|
||||
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
||||
.mpll_cfg = rockchip_mpll_cfg,
|
||||
.cur_ctr = rockchip_cur_ctr,
|
||||
.sym_term = rockchip_sym_term,
|
||||
.dev_type = RK3288_HDMI,
|
||||
};
|
||||
|
||||
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
|
||||
{ .compatible = "rockchip,rk3288-dw-hdmi",
|
||||
.data = &rockchip_hdmi_drv_data
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
|
||||
|
||||
static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
const struct dw_hdmi_plat_data *plat_data;
|
||||
const struct of_device_id *match;
|
||||
struct drm_device *drm = data;
|
||||
struct drm_encoder *encoder;
|
||||
struct rockchip_hdmi *hdmi;
|
||||
struct resource *iores;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
if (!hdmi)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
|
||||
plat_data = match->data;
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENXIO;
|
||||
|
||||
platform_set_drvdata(pdev, hdmi);
|
||||
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
* supposed to be connected to, it's because the CRTC has
|
||||
* not been registered yet. Defer probing, and hope that
|
||||
* the required CRTC is added later.
|
||||
*/
|
||||
if (encoder->possible_crtcs == 0)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = rockchip_hdmi_parse_dt(hdmi);
|
||||
if (ret) {
|
||||
dev_err(hdmi->dev, "Unable to parse OF data\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
|
||||
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
|
||||
}
|
||||
|
||||
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
return dw_hdmi_unbind(dev, master, data);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_rockchip_ops = {
|
||||
.bind = dw_hdmi_rockchip_bind,
|
||||
.unbind = dw_hdmi_rockchip_unbind,
|
||||
};
|
||||
|
||||
static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
|
||||
{
|
||||
return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
|
||||
}
|
||||
|
||||
static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
|
||||
.probe = dw_hdmi_rockchip_probe,
|
||||
.remove = dw_hdmi_rockchip_remove,
|
||||
.driver = {
|
||||
.name = "dwhdmi-rockchip",
|
||||
.of_match_table = dw_hdmi_rockchip_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
|
||||
|
||||
MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
|
||||
MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:dwhdmi-rockchip");
|
||||
@@ -390,6 +390,7 @@ int rockchip_drm_encoder_get_mux_id(struct device_node *node,
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_encoder_get_mux_id);
|
||||
|
||||
static int compare_of(struct device *dev, void *data)
|
||||
{
|
||||
|
||||
@@ -735,6 +735,7 @@ int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_drm_crtc_mode_config);
|
||||
|
||||
static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user