We found freescale imx6 and rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they also have some
lightly differences, such as phy pll configuration, register width(imx hdmi
register is one byte, but rk3288 is 4 bytes width and can only access by word),
4K support(imx6 doesn't support 4k, but rk3288 does).
To reuse the imx-hdmi driver, we make this patch set:
(1): fix some CodingStyle warning to make checkpatch happy
(2): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
(3): move imx-hdmi to bridge/dw-hdmi, and convert it to a drm_bridge driver
(4): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
- Add documentation for rockchip dw hdmi
- add support for rockchip rk3288 hdmi
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6:
- rearrange the patch order
- move some modification to patch#6
- refactor register access without reg_shift
- move some modification from patch#5
Changes in v5:
- refactor reg-io-width
Changes in v4:
- fix checkpatch CHECK
- defer probe ddc i2c adapter
Changes in v3:
- split multi register access to one indepent patch
Changes in v2:
- use git format -M to generate these patch
Andy Yan (8):
staging: imx-drm: imx-hdmi: make checkpatch happy
staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
dt-bindings: add document for dw_hdmi
drm: bridge/dw_hdmi: add support for multi byte register width access
dt-bindings: Add documentation for rockchip dw hdmi
drm: bridge/dw_hdmi: add rockchip rk3288 support
Yakir Yang (1):
drm: bridge/dw_hdmi: convert dw-hdmi to drm_bridge mode
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 773 ++++++++++-----------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 5 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 319 +++++++++
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 266 +++++++
include/drm/bridge/dw_hdmi.h | 53 ++
11 files changed, 1081 insertions(+), 427 deletions(-)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h
--
1.9.1
CHECK: Alignment should match open parenthesis
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
CHECK: braces {} should be used on all arms of this statement
+ if (hdmi->hdmi_data.video_mode.mdvi)
[...]
+ else {
[...]
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8: None
Changes in v7: None
Changes in v6:
- rearrange the patch order
Changes in v5: None
Changes in v4:
- fix checkpatch CHECK
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 49 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index aaec6b2..79daec4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
}
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+ u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}
static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
- unsigned long pixel_clk)
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
+ __func__, pixel_clk);
return;
}
@@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
u16 coeff_b = (*csc_coeff)[1][i];
u16 coeff_c = (*csc_coeff)[2][i];
- hdmi_writeb(hdmi, coeff_a & 0xff,
- HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_c & 0xff,
- HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}
@@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
- if (hdmi_data->enc_out_format == RGB
- || hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth)
+ if (hdmi_data->enc_out_format == RGB ||
+ hdmi_data->enc_out_format == YCBCR444) {
+ if (!hdmi_data->enc_color_depth) {
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- else if (hdmi_data->enc_color_depth == 8) {
+ } else if (hdmi_data->enc_color_depth == 8) {
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10)
+ } else if (hdmi_data->enc_color_depth == 10) {
color_depth = 5;
- else if (hdmi_data->enc_color_depth == 12)
+ } else if (hdmi_data->enc_color_depth == 12) {
color_depth = 6;
- else if (hdmi_data->enc_color_depth == 16)
+ } else if (hdmi_data->enc_color_depth == 16) {
color_depth = 7;
- else
+ } else {
return;
+ }
} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
if (!hdmi_data->enc_color_depth ||
hdmi_data->enc_color_depth == 8)
@@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
else
return;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
- } else
+ } else {
return;
+ }
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
@@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
@@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
}
static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 8),
- HDMI_PHY_I2CM_DATAO_1_ADDR);
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 0),
- HDMI_PHY_I2CM_DATAO_0_ADDR);
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
- HDMI_PHY_I2CM_OPERATION_ADDR);
+ HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
@@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 1);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
+ HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
@@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
break;
if (i >= ARRAY_SIZE(curr_ctrl)) {
- dev_err(hdmi->dev,
- "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
+ dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
@@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
- (hdmi->vic == 21) || (hdmi->vic == 22) ||
- (hdmi->vic == 2) || (hdmi->vic == 3) ||
- (hdmi->vic == 17) || (hdmi->vic == 18))
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
else
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
- (hdmi->vic == 12) || (hdmi->vic == 13) ||
- (hdmi->vic == 14) || (hdmi->vic == 15) ||
- (hdmi->vic == 25) || (hdmi->vic == 26) ||
- (hdmi->vic == 27) || (hdmi->vic == 28) ||
- (hdmi->vic == 29) || (hdmi->vic == 30) ||
- (hdmi->vic == 35) || (hdmi->vic == 36) ||
- (hdmi->vic == 37) || (hdmi->vic == 38))
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
else
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
@@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
imx_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi)
+ if (hdmi->hdmi_data.video_mode.mdvi) {
dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- else {
+ } else {
dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
/* HDMI Initialization Step E - Configure audio */
@@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
+ HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
@@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
+ &imx_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Product and revision IDs */
dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(hdmi, HDMI_DESIGN_ID),
+ hdmi_readb(hdmi, HDMI_REVISION_ID),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
initialize_hdmi_ih_mutes(hdmi);
--
1.9.1
drm driver may probe before the i2c bus, so the driver should
defer probing until it is available
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4:
- defer probe ddc i2c adapter
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 79daec4..c2b035a 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1611,8 +1611,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- if (!hdmi->ddc)
+ if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
+ of_node_put(ddc_node);
+ return -EPROBE_DEFER;
+ }
of_node_put(ddc_node);
} else {
--
1.9.1
imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly differences, such as phy pll configuration,
register width, 4K support, clk useage, and the crtc mux configuration
is also platform specific.
To reuse the imx hdmi driver, split the platform specific code out
to dw_hdmi-imx.c.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8: None
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 217 +++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 255 ++++++++--------------------------
drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++
4 files changed, 322 insertions(+), 195 deletions(-)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 582c438..809027d 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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) += imx-hdmi.o dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
new file mode 100644
index 0000000..0db978e
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,217 @@
+/* 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/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#include "imx-drm.h"
+#include "imx-hdmi.h"
+
+struct imx_hdmi_priv {
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+ struct regmap *regmap;
+};
+
+static const struct 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 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 int imx_hdmi_parse_dt(struct imx_hdmi_priv *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);
+ }
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
+ return PTR_ERR(hdmi->isfr_clk);
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->iahb_clk);
+ }
+
+ return 0;
+}
+
+static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+{
+ struct imx_hdmi_priv *hdmi;
+ int ret;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return ERR_PTR(-ENOMEM);
+ hdmi->dev = &pdev->dev;
+
+ ret = imx_hdmi_parse_dt(hdmi);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return hdmi;
+}
+
+static void imx_hdmi_imx_exit(void *priv)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+
+ clk_disable_unprepare(hdmi->iahb_clk);
+}
+
+static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ 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 imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .dev_type = IMX6Q_HDMI,
+};
+
+static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .dev_type = IMX6DL_HDMI,
+};
+
+static const struct of_device_id imx_hdmi_imx_ids[] = {
+ { .compatible = "fsl,imx6q-hdmi",
+ .data = &imx6q_hdmi_drv_data
+ }, {
+ .compatible = "fsl,imx6dl-hdmi",
+ .data = &imx6dl_hdmi_drv_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+
+static int imx_hdmi_imx_probe(struct platform_device *pdev)
+{
+ const struct imx_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ plat_data = match->data;
+
+ return imx_hdmi_platform_register(pdev, plat_data);
+}
+
+static int imx_hdmi_imx_remove(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_unregister(pdev);
+}
+
+static struct platform_driver imx_hdmi_imx_platform_driver = {
+ .probe = imx_hdmi_imx_probe,
+ .remove = imx_hdmi_imx_remove,
+ .driver = {
+ .name = "dwhdmi-imx",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_hdmi_imx_ids,
+ },
+};
+
+module_platform_driver(imx_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c2b035a..c7e5f12 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,21 +16,16 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/clk.h>
#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.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 <video/imx-ipu-v3.h>
#include "imx-hdmi.h"
-#include "imx-drm.h"
#define HDMI_EDID_LEN 512
@@ -54,11 +49,6 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x0000, 0x0000, 0x0000 },
{ 0x0000, 0x2000, 0x0000, 0x0000 },
@@ -117,10 +107,10 @@ struct imx_hdmi {
enum imx_hdmi_devtype dev_type;
struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
struct hdmi_data_info hdmi_data;
+ const struct imx_hdmi_plat_data *plat_data;
+ void *priv;
int vic;
u8 edid[HDMI_EDID_LEN];
@@ -137,13 +127,6 @@ struct imx_hdmi {
int ratio;
};
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
@@ -728,76 +711,13 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
- {
- 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 },
- },
- }
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
- /* 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 int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
u8 val, msec;
+ const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
+ const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
if (prep)
return -EINVAL;
@@ -843,27 +763,27 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
- for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config[i].mpixelclock)
+ mpll_cfg[i].mpixelclock)
break;
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);
- for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl[i].mpixelclock)
+ curr_ctr[i].mpixelclock)
break;
- if (i >= ARRAY_SIZE(curr_ctrl)) {
+ if (curr_ctr[i].mpixelclock == (~0UL)) {
dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
/* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10);
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
@@ -1453,21 +1373,29 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+
+ if (hdmi->plat_data->encoder_prepare)
+ hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
static void imx_hdmi_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);
- imx_hdmi_set_ipu_di_mux(hdmi, mux);
+ if (hdmi->plat_data->encoder_commit)
+ hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
imx_hdmi_poweron(hdmi);
}
+void imx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_drm_encoder_destroy,
+ .destroy = drm_encoder_cleanup,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1483,7 +1411,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_drm_connector_destroy,
+ .destroy = imx_hdmi_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1539,12 +1467,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
- int ret;
+ struct drm_encoder *encoder = &hdmi->encoder;
+ struct device *dev = hdmi->dev;
- ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
- hdmi->dev->of_node);
- if (ret)
- return ret;
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
@@ -1564,50 +1490,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- .driver_data = IMX6Q_HDMI,
- }, {
- .name = "imx6dl-hdmi",
- .driver_data = IMX6DL_HDMI,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
- struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
-
- hdmi->dev_type = device_id->driver_data;
- }
-
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1637,40 +1529,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap))
- return PTR_ERR(hdmi->regmap);
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- ret = PTR_ERR(hdmi->isfr_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI isfr clk: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- ret = PTR_ERR(hdmi->iahb_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI iahb clk: %d\n", ret);
- goto err_isfr;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- goto err_isfr;
- }
-
+ if (hdmi->plat_data->setup)
+ hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1698,11 +1558,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ret = imx_hdmi_fb_registered(hdmi);
if (ret)
- goto err_iahb;
+ return ret;
ret = imx_hdmi_register(drm, hdmi);
if (ret)
- goto err_iahb;
+ return ret;
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
@@ -1710,13 +1570,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, hdmi);
return 0;
-
-err_iahb:
- clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
- clk_disable_unprepare(hdmi->isfr_clk);
-
- return ret;
}
static void imx_hdmi_unbind(struct device *dev, struct device *master,
@@ -1729,9 +1582,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
+ if (hdmi->plat_data->exit)
+ hdmi->plat_data->exit(hdmi->priv);
i2c_put_adapter(hdmi->ddc);
}
@@ -1751,17 +1603,32 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver imx_hdmi_driver = {
- .probe = imx_hdmi_platform_probe,
- .remove = imx_hdmi_platform_remove,
- .driver = {
- .name = "imx-hdmi",
- .owner = THIS_MODULE,
- .of_match_table = imx_hdmi_dt_ids,
- },
-};
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data)
+{
+ struct imx_hdmi *hdmi;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
-module_platform_driver(imx_hdmi_driver);
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+
+ platform_set_drvdata(pdev, hdmi);
+
+ return imx_hdmi_platform_probe(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+
+int imx_hdmi_platform_unregister(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_remove(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b6776..e67d60d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,47 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum imx_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct imx_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ enum imx_hdmi_devtype dev_type;
+
+};
+
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data);
+int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi driver out
to drm/bridge and rename imx-hdmi to dw_hdmi
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2:
- use git format -M to generate these patch
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 281 +++++++++++----------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 46 +---
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 70 ++---
include/drm/bridge/dw_hdmi.h | 57 +++++
8 files changed, 243 insertions(+), 220 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (83%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (97%)
create mode 100644 include/drm/bridge/dw_hdmi.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..26162ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,3 +3,8 @@ config DRM_PTN3460
depends on DRM
select DRM_KMS_HELPER
---help---
+
+config DRM_DW_HDMI
+ bool "Synopsys DesignWare High-Definition Multimedia Interface"
+ depends on DRM
+ select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..d8a8cfd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
similarity index 83%
rename from drivers/staging/imx-drm/imx-hdmi.c
rename to drivers/gpu/drm/bridge/dw_hdmi.c
index c7e5f12..e9f0dfe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -6,8 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
+ * Designware High-Definition Multimedia Interface (HDMI) driver
*
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
@@ -24,8 +23,9 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
-#include "imx-hdmi.h"
+#include "dw_hdmi.h"
#define HDMI_EDID_LEN 512
@@ -101,15 +101,15 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
-struct imx_hdmi {
+struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
- enum imx_hdmi_devtype dev_type;
+ enum dw_hdmi_devtype dev_type;
struct device *dev;
struct hdmi_data_info hdmi_data;
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
void *priv;
int vic;
@@ -127,17 +127,17 @@ struct imx_hdmi {
int ratio;
};
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
}
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
return readb(hdmi->regs + offset);
}
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;
@@ -145,13 +145,13 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
unsigned int value)
{
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
@@ -162,7 +162,7 @@ static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
@@ -309,7 +309,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -333,12 +333,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
hdmi_regenerate_cts(hdmi, clk_cts);
}
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, 74250000);
}
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
@@ -350,7 +350,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
* pin{31~24} <==> G[7:0]
* pin{15~8} <==> B[7:0]
*/
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
{
int color_format = 0;
u8 val;
@@ -406,12 +406,12 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
}
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
return 0;
@@ -421,7 +421,7 @@ static int is_color_space_decimation(struct imx_hdmi *hdmi)
return 0;
}
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
return 0;
@@ -431,7 +431,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
return 0;
}
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
unsigned i;
@@ -472,7 +472,7 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
HDMI_CSC_SCALE);
}
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
{
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
@@ -500,7 +500,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
HDMI_CSC_SCALE);
- imx_hdmi_update_csc_coeffs(hdmi);
+ dw_hdmi_update_csc_coeffs(hdmi);
}
/*
@@ -508,7 +508,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
* for example, if input is YCC422 mode or repeater is used,
* data should be repacked this module can be bypassed.
*/
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
{
unsigned int color_depth = 0;
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -605,40 +605,40 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_CONF);
}
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
@@ -648,7 +648,7 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -662,56 +662,56 @@ static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
}
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_ENTMDS_OFFSET,
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
}
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
}
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
HDMI_PHY_CONF0_SELDATAENPOL_MASK);
}
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDIPIF_OFFSET,
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
@@ -746,10 +746,10 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
/* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
/* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
/* PHY reset */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
@@ -796,15 +796,15 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- imx_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_power(hdmi, 1);
/* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 1);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
/* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(hdmi, 1);
- imx_hdmi_phy_gen2_pddq(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
/*Wait for PHY PLL lock */
msec = 5;
@@ -825,7 +825,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
return 0;
}
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
bool cscon = false;
@@ -836,10 +836,10 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
- imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
- imx_hdmi_phy_sel_interface_control(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+ dw_hdmi_phy_sel_interface_control(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
@@ -851,7 +851,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
return 0;
}
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{
u8 de;
@@ -870,7 +870,7 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
{
u8 val, pix_fmt, under_scan;
u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
@@ -964,7 +964,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
}
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
u8 inv_val;
@@ -1048,19 +1048,19 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
{
if (!hdmi->phy_enabled)
return;
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
u8 clkdis;
@@ -1089,13 +1089,13 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
}
}
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
int count;
u8 val;
@@ -1113,19 +1113,19 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
HDMI_IH_MUTE_FC_STAT2);
}
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
{
int ret;
@@ -1177,12 +1177,12 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */
- ret = imx_hdmi_phy_init(hdmi);
+ ret = dw_hdmi_phy_init(hdmi);
if (ret)
return ret;
/* HDMI Initialization Step B.3 */
- imx_hdmi_enable_video_path(hdmi);
+ dw_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
if (hdmi->hdmi_data.video_mode.mdvi) {
@@ -1203,7 +1203,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_video_sample(hdmi);
hdmi_tx_hdcp_config(hdmi);
- imx_hdmi_clear_overflow(hdmi);
+ dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
hdmi_enable_overflow_interrupts(hdmi);
@@ -1211,7 +1211,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);
@@ -1229,7 +1229,7 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
return 0;
}
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{
u8 ih_mute;
@@ -1281,29 +1281,29 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
}
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{
- imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+ dw_hdmi_setup(hdmi, &hdmi->previous_mode);
}
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
- imx_hdmi_phy_disable(hdmi);
+ dw_hdmi_phy_disable(hdmi);
}
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
struct edid *edid;
int ret;
@@ -1326,102 +1326,102 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return &hdmi->encoder;
}
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_setup(hdmi, mode);
+ dw_hdmi_setup(hdmi, mode);
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
}
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (mode)
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
else
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
if (hdmi->plat_data->encoder_prepare)
hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (hdmi->plat_data->encoder_commit)
hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-void imx_hdmi_connector_destroy(struct drm_connector *connector)
+void dw_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .dpms = imx_hdmi_encoder_dpms,
- .prepare = imx_hdmi_encoder_prepare,
- .commit = imx_hdmi_encoder_commit,
- .mode_set = imx_hdmi_encoder_mode_set,
- .mode_fixup = imx_hdmi_encoder_mode_fixup,
- .disable = imx_hdmi_encoder_disable,
+static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
+ .dpms = dw_hdmi_encoder_dpms,
+ .prepare = dw_hdmi_encoder_prepare,
+ .commit = dw_hdmi_encoder_commit,
+ .mode_set = dw_hdmi_encoder_mode_set,
+ .mode_fixup = dw_hdmi_encoder_mode_fixup,
+ .disable = dw_hdmi_encoder_disable,
};
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- .get_modes = imx_hdmi_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+ .get_modes = dw_hdmi_connector_get_modes,
+ .best_encoder = dw_hdmi_connector_best_encoder,
};
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1431,9 +1431,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
@@ -1447,14 +1447,14 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
HDMI_PHY_POL0);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
}
drm_helper_hpd_irq_event(hdmi->connector.dev);
}
@@ -1465,7 +1465,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = &hdmi->encoder;
struct device *dev = hdmi->dev;
@@ -1474,13 +1474,13 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ &dw_hdmi_connector_helper_funcs);
+ drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1490,10 +1490,10 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
@@ -1518,8 +1518,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
+ ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
return ret;
@@ -1556,11 +1556,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- ret = imx_hdmi_fb_registered(hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
return ret;
- ret = imx_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_register(drm, hdmi);
if (ret)
return ret;
@@ -1572,10 +1572,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
+static void dw_hdmi_unbind(struct device *dev, struct device *master,
void *data)
{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
@@ -1588,25 +1588,25 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
}
static const struct component_ops hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
+ .bind = dw_hdmi_bind,
+ .unbind = dw_hdmi_unbind,
};
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int dw_hdmi_platform_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &hdmi_ops);
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static int dw_hdmi_platform_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &hdmi_ops);
return 0;
}
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data)
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
{
- struct imx_hdmi *hdmi;
+ struct dw_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1620,17 +1620,18 @@ int imx_hdmi_platform_register(struct platform_device *pdev,
platform_set_drvdata(pdev, hdmi);
- return imx_hdmi_platform_probe(pdev);
+ return dw_hdmi_platform_probe(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-int imx_hdmi_platform_unregister(struct platform_device *pdev)
+int dw_hdmi_platform_unregister(struct platform_device *pdev)
{
- return imx_hdmi_platform_remove(pdev);
+ return dw_hdmi_platform_remove(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
similarity index 97%
rename from drivers/staging/imx-drm/imx-hdmi.h
rename to drivers/gpu/drm/bridge/dw_hdmi.h
index e67d60d..b8412a9 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -7,8 +7,8 @@
* (at your option) any later version.
*/
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
+#ifndef __DW_HDMI__
+#define __DW_HDMI__
/* Identification Registers */
#define HDMI_DESIGN_ID 0x0000
@@ -1030,46 +1030,4 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-struct imx_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
- const struct mpll_config *mpll_cfg;
- const struct curr_ctrl *cur_ctr;
- enum imx_hdmi_devtype dev_type;
-
-};
-
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data);
-int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index ab31848..560e1d3 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -50,5 +50,6 @@ config DRM_IMX_IPUV3
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
depends on DRM_IMX
+ select DRM_DW_HDMI
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 809027d..f3ecd89 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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 dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 0db978e..4b48ea6 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -10,14 +10,14 @@
#include <linux/platform_device.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 <linux/clk.h>
#include "imx-drm.h"
-#include "imx-hdmi.h"
-struct imx_hdmi_priv {
+struct imx_hdmi {
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -69,7 +69,7 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
-static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
+static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
@@ -94,9 +94,9 @@ static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
return 0;
}
-static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+static void *dw_hdmi_imx_setup(struct platform_device *pdev)
{
- struct imx_hdmi_priv *hdmi;
+ struct imx_hdmi *hdmi;
int ret;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -104,7 +104,7 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return ERR_PTR(-ENOMEM);
hdmi->dev = &pdev->dev;
- ret = imx_hdmi_parse_dt(hdmi);
+ ret = dw_hdmi_parse_dt(hdmi);
if (ret < 0)
return ERR_PTR(ret);
ret = clk_prepare_enable(hdmi->isfr_clk);
@@ -124,18 +124,18 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return hdmi;
}
-static void imx_hdmi_imx_exit(void *priv)
+static void dw_hdmi_imx_exit(void *priv)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
clk_disable_unprepare(hdmi->isfr_clk);
clk_disable_unprepare(hdmi->iahb_clk);
}
-static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
@@ -143,33 +143,33 @@ static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
-static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6Q_HDMI,
};
-static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6DL_HDMI,
};
-static const struct of_device_id imx_hdmi_imx_ids[] = {
+static const struct of_device_id dw_hdmi_imx_ids[] = {
{ .compatible = "fsl,imx6q-hdmi",
.data = &imx6q_hdmi_drv_data
}, {
@@ -178,38 +178,38 @@ static const struct of_device_id imx_hdmi_imx_ids[] = {
},
{},
};
-MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int imx_hdmi_imx_probe(struct platform_device *pdev)
+static int dw_hdmi_imx_probe(struct platform_device *pdev)
{
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
if (!pdev->dev.of_node)
return -ENODEV;
- match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ match = of_match_node(dw_hdmi_imx_ids, pdev->dev.of_node);
plat_data = match->data;
- return imx_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_platform_register(pdev, plat_data);
}
-static int imx_hdmi_imx_remove(struct platform_device *pdev)
+static int dw_hdmi_imx_remove(struct platform_device *pdev)
{
- return imx_hdmi_platform_unregister(pdev);
+ return dw_hdmi_platform_unregister(pdev);
}
-static struct platform_driver imx_hdmi_imx_platform_driver = {
- .probe = imx_hdmi_imx_probe,
- .remove = imx_hdmi_imx_remove,
+static struct platform_driver dw_hdmi_imx_platform_driver = {
+ .probe = dw_hdmi_imx_probe,
+ .remove = dw_hdmi_imx_remove,
.driver = {
.name = "dwhdmi-imx",
.owner = THIS_MODULE,
- .of_match_table = imx_hdmi_imx_ids,
+ .of_match_table = dw_hdmi_imx_ids,
},
};
-module_platform_driver(imx_hdmi_imx_platform_driver);
+module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..6683b63
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __DW_HDMI_H__
+#define __DW_HDMI_H__
+
+#include <drm/drmP.h>
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum dw_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct dw_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ enum dw_hdmi_devtype dev_type;
+
+};
+
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data);
+int dw_hdmi_platform_unregister(struct platform_device *pdev);
+#endif /* __IMX_HDMI_H__ */
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
new file mode 100644
index 0000000..0558442
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
@@ -0,0 +1,40 @@
+DesignWare HDMI bridge bindings
+
+Required properities:
+- compatible: platform specific such as:
+ * "fsl,imx6q-hdmi"
+ * "fsl,imx6dl-hdmi"
+ * "rockchip,rk3288-dw-hdmi"
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- interrupts: The HDMI interrupt number
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+
+Example:
+ hdmi: hdmi@0120000 {
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
--
1.9.1
On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width accesses (writeb,
readb) generate an imprecise external abort.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4: None
Changes in v3:
- split multi register access to one indepent patch
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 57 +++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index e9f0dfe..978c709 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -101,6 +101,11 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
+union dw_reg_ptr {
+ u32 __iomem *p32;
+ u8 __iomem *p8;
+};
+
struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -121,20 +126,43 @@ struct dw_hdmi {
struct regmap *regmap;
struct i2c_adapter *ddc;
- void __iomem *regs;
+ union dw_reg_ptr regs;
unsigned int sample_rate;
int ratio;
+
+ void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+ u8 (*read)(struct dw_hdmi *hdmi, int offset);
};
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writel(val, hdmi->regs.p32 + offset);
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs.p32 + offset);
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writeb(val, hdmi->regs.p8 + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return readb(hdmi->regs.p8 + offset);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(hdmi, val, offset);
}
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi, offset);
}
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
@@ -1499,6 +1527,23 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
struct device_node *ddc_node;
struct resource *iores;
int ret, irq;
+ u32 val = 1;
+
+ of_property_read_u32(np, "reg-io-width", &val);
+
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ break;
+ case 1:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return -EINVAL;
+ }
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
@@ -1525,9 +1570,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
+ hdmi->regs.p32 = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs.p32))
+ return PTR_ERR(hdmi->regs.p32);
if (hdmi->plat_data->setup)
hdmi->priv = hdmi->plat_data->setup(pdev);
--
1.9.1
From: Yakir Yang <[email protected]>
keep the connector & birdge in dw_hdmi.c, handle encoder
in dw_hdmi-imx.c, as most of the encoder operation are
platform specific such as crtc select and panel format
set
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification from patch#5
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 228 +++++++++++++++-------------------
drivers/staging/imx-drm/dw_hdmi-imx.c | 145 ++++++++++++++-------
include/drm/bridge/dw_hdmi.h | 13 +-
3 files changed, 199 insertions(+), 187 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 978c709..ed75147 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -11,7 +11,6 @@
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
-#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -108,7 +107,8 @@ union dw_reg_ptr {
struct dw_hdmi {
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
enum dw_hdmi_devtype dev_type;
struct device *dev;
@@ -1319,6 +1319,50 @@ static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
dw_hdmi_phy_disable(hdmi);
}
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_setup(hdmi, mode);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweroff(hdmi);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweron(hdmi);
+}
+
+static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge)
+{
+ drm_bridge_cleanup(bridge);
+ kfree(bridge);
+}
+
+static void dw_hdmi_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
@@ -1360,60 +1404,7 @@ static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
- return &hdmi->encoder;
-}
-
-static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_setup(hdmi, mode);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (mode)
- dw_hdmi_poweroff(hdmi);
- else
- dw_hdmi_poweron(hdmi);
-}
-
-static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_poweroff(hdmi);
-
- if (hdmi->plat_data->encoder_prepare)
- hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
-}
-
-static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (hdmi->plat_data->encoder_commit)
- hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
-
- dw_hdmi_poweron(hdmi);
+ return hdmi->encoder;
}
void dw_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1422,19 +1413,6 @@ void dw_hdmi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
- .dpms = dw_hdmi_encoder_dpms,
- .prepare = dw_hdmi_encoder_prepare,
- .commit = dw_hdmi_encoder_commit,
- .mode_set = dw_hdmi_encoder_mode_set,
- .mode_fixup = dw_hdmi_encoder_mode_fixup,
- .disable = dw_hdmi_encoder_disable,
-};
-
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1447,6 +1425,16 @@ static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.best_encoder = dw_hdmi_connector_best_encoder,
};
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .enable = dw_hdmi_bridge_enable,
+ .disable = dw_hdmi_bridge_disable,
+ .pre_enable = dw_hdmi_bridge_nope,
+ .post_disable = dw_hdmi_bridge_nope,
+ .mode_set = dw_hdmi_bridge_mode_set,
+ .mode_fixup = dw_hdmi_bridge_mode_fixup,
+ .destroy = dw_hdmi_bridge_destroy,
+};
+
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
@@ -1495,40 +1483,64 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
- struct drm_encoder *encoder = &hdmi->encoder;
- struct device *dev = hdmi->dev;
+ struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_bridge *bridge;
+ int ret;
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("Failed to allocate drm bridge\n");
+ return -ENOMEM;
+ }
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ hdmi->bridge = bridge;
+ bridge->driver_private = hdmi;
- drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
- hdmi->connector.encoder = &hdmi->encoder;
+ hdmi->connector.encoder = encoder;
- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
return 0;
}
-static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct resource *iores;
+ struct dw_hdmi *hdmi;
int ret, irq;
u32 val = 1;
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+ hdmi->encoder = encoder;
+
of_property_read_u32(np, "reg-io-width", &val);
switch (val) {
@@ -1574,8 +1586,6 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs.p32))
return PTR_ERR(hdmi->regs.p32);
- if (hdmi->plat_data->setup)
- hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1616,9 +1626,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-static void dw_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1626,57 +1636,15 @@ static void dw_hdmi_unbind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
- if (hdmi->plat_data->exit)
- hdmi->plat_data->exit(hdmi->priv);
- i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
- .bind = dw_hdmi_bind,
- .unbind = dw_hdmi_unbind,
-};
-
-static int dw_hdmi_platform_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int dw_hdmi_platform_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &hdmi_ops);
- return 0;
-}
-
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data)
-{
- struct dw_hdmi *hdmi;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->plat_data = plat_data;
- hdmi->dev = &pdev->dev;
- hdmi->dev_type = plat_data->dev_type;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
+ hdmi->encoder->funcs->destroy(hdmi->encoder);
- platform_set_drvdata(pdev, hdmi);
-
- return dw_hdmi_platform_probe(pdev);
-}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-
-int dw_hdmi_platform_unregister(struct platform_device *pdev)
-{
- return dw_hdmi_platform_remove(pdev);
+ i2c_put_adapter(hdmi->ddc);
}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 4b48ea6..ad71c8e 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -8,12 +8,19 @@
*/
#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 <linux/clk.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 "imx-drm.h"
@@ -22,6 +29,7 @@ struct imx_hdmi {
struct clk *isfr_clk;
struct clk *iahb_clk;
struct regmap *regmap;
+ struct drm_encoder encoder;
};
static const struct mpll_config imx_mpll_cfg[] = {
@@ -69,7 +77,7 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
-static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
+static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
@@ -94,48 +102,26 @@ static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
return 0;
}
-static void *dw_hdmi_imx_setup(struct platform_device *pdev)
+static void dw_hdmi_imx_disable(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi;
- int ret;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return ERR_PTR(-ENOMEM);
- hdmi->dev = &pdev->dev;
-
- ret = dw_hdmi_parse_dt(hdmi);
- if (ret < 0)
- return ERR_PTR(ret);
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return hdmi;
}
-static void dw_hdmi_imx_exit(void *priv)
+static bool dw_hdmi_imx_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
-
- clk_disable_unprepare(hdmi->isfr_clk);
+ return true;
+}
- clk_disable_unprepare(hdmi->iahb_clk);
+static void dw_hdmi_imx_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
}
-static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
+ 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,
@@ -143,27 +129,30 @@ static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_prepare(struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_imx_mode_fixup,
+ .mode_set = dw_hdmi_imx_mode_set,
+ .prepare = dw_hdmi_imx_prepare,
+ .commit = dw_hdmi_imx_commit,
+ .disable = dw_hdmi_imx_disable,
+};
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6Q_HDMI,
};
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6DL_HDMI,
@@ -180,23 +169,82 @@ static const struct of_device_id dw_hdmi_imx_ids[] = {
};
MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int dw_hdmi_imx_probe(struct platform_device *pdev)
+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;
+ 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_ids, pdev->dev.of_node);
plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = dw_hdmi_imx_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
- return dw_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+ clk_disable_unprepare(hdmi->iahb_clk);
+
+ 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)
{
- return dw_hdmi_platform_unregister(pdev);
+ component_del(&pdev->dev, &dw_hdmi_imx_ops);
+
+ return 0;
}
static struct platform_driver dw_hdmi_imx_platform_driver = {
@@ -212,6 +260,7 @@ static struct platform_driver dw_hdmi_imx_platform_driver = {
module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 6683b63..e26e61f 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -38,20 +38,15 @@ struct curr_ctrl {
};
struct dw_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
enum dw_hdmi_devtype dev_type;
-
};
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data);
-int dw_hdmi_platform_unregister(struct platform_device *pdev);
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v8:
- Add documentation for rockchip dw hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
new file mode 100644
index 0000000..6ea6764
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
@@ -0,0 +1,43 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks: from common clock binding: handle to hdmi clock.
+- clock-names: should be "clk" "hdcp_clk"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt. For
+ vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+ rk3288 platform
+
+Example:
+hdmi: hdmi@ff980000 {
+ compatible = "rockchip,rk3288-dw-hdmi";
+ reg = <0xff980000 0x20000>;
+ reg-io-width = <4>;
+ ddc-i2c-bus = <&i2c5>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+ clock-names = "clk", "hdcp_clk";
+ status = "disabled";
+ ports {
+ hdmi_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ hdmi_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_hdmi>;
+ };
+ hdmi_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_hdmi>;
+ };
+ };
+ };
+};
--
1.9.1
rk3288 hdmi is compatible with Designware hdmi
this patch is depend on patch by Mark Yao Add drm
driver for Rockchip Socs
see https://lkml.org/lkml/2014/10/8/201
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v8:
- add support for rockchip rk3288 hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 66 ++++--
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 319 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi.h | 1 +
3 files changed, 374 insertions(+), 12 deletions(-)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index ed75147..a8071c1 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -668,11 +668,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ u32 val;
+
+ while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
udelay(1000);
}
+ hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
return true;
}
@@ -815,24 +819,45 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
- /* RESISTANCE TERM 133Ohm Cfg */
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
- /* PREEMP Cgf 0.00 */
- hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+
+ if (hdmi->dev_type != RK3288_HDMI) {
+ /* RESISTANCE TERM 133Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ /* PREEMP Cgf 0.00 */
+ hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+ } else {
+ if (curr_ctr[i].mpixelclock <= 74250000) {
+ /* RESISTANCE TERM 100Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x0004, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ } else if (curr_ctr[i].mpixelclock <= 148500000) {
+ /* RESISTANCE TERM 100Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x0004, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
+ } else {
+ /* RESISTANCE TERM 133Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);
+ hdmi_phy_i2c_write(hdmi, 0x8039, 0x09);
+ }
+ }
/* TX/CK LVL 10 */
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- dw_hdmi_phy_enable_power(hdmi, 1);
+ if (hdmi->dev_type != RK3288_HDMI) {
+ dw_hdmi_phy_enable_power(hdmi, 1);
- /* toggle TMDS enable */
- dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_tmds(hdmi, 1);
+ /* toggle TMDS enable */
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
- /* gen2 tx power on */
- dw_hdmi_phy_gen2_txpwron(hdmi, 1);
- dw_hdmi_phy_gen2_pddq(hdmi, 0);
+ /* gen2 tx power on */
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
+ } else {
+ hdmi_writeb(hdmi, 0x6e, HDMI_PHY_CONF0);
+ }
/*Wait for PHY PLL lock */
msec = 5;
@@ -1398,6 +1423,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = container_of(connector,
+ struct dw_hdmi, connector);
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (hdmi->plat_data->mode_valid)
+ mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1422,6 +1461,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
+ .mode_valid = dw_hdmi_connector_mode_valid,
.best_encoder = dw_hdmi_connector_best_encoder,
};
@@ -1514,6 +1554,8 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+ drm_connector_register(&hdmi->connector);
+
return 0;
}
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 0000000..e5b01fc
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,319 @@
+/*
+ * 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 <linux/clk.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 clk *clk;
+ struct clk *hdcp_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+
+static const struct mpll_config rockchip_mpll_cfg[] = {
+ {
+ /* 27MHz & 36MHz & 40MHz */
+ 40000000, {
+ { 0x00b3, 0x0000},
+ { 0x2153, 0x0000},
+ { 0x40f3, 0x0000}
+ },
+ }, {
+ /* 54MHz & 65MHz */
+ 65000000, {
+ { 0x0072, 0x0001},
+ { 0x2142, 0x0001},
+ { 0x40a2, 0x0001},
+ },
+ }, {
+ 66000000, {
+ { 0x013e, 0x0003},
+ { 0x217e, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 74250000, {
+ { 0x0072, 0x0001},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 83500000, {
+ { 0x0072, 0x0001},
+ },
+ }, {
+ /* 108MHz & 106.5MHz & 146.25MHz */
+ 146250000, {
+ { 0x0051, 0x0002},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 148500000, {
+ { 0x0051, 0x0003},
+ { 0x214c, 0x0003},
+ { 0x4064, 0x0003}
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+static const struct 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 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);
+ }
+
+ hdmi->clk = devm_clk_get(hdmi->dev, "clk");
+ if (IS_ERR(hdmi->clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI clk\n");
+ return PTR_ERR(hdmi->clk);
+ }
+
+ hdmi->hdcp_clk = devm_clk_get(hdmi->dev, "hdcp_clk");
+ if (IS_ERR(hdmi->hdcp_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->hdcp_clk);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct 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_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_rockchip_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_rockchip_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void dw_hdmi_rockchip_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_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_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_rockchip_mode_fixup,
+ .mode_set = dw_hdmi_rockchip_mode_set,
+ .prepare = dw_hdmi_rockchip_prepare,
+ .commit = dw_hdmi_rockchip_commit,
+ .disable = dw_hdmi_rockchip_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,
+ .dev_type = RK3288_HDMI,
+};
+
+static const struct of_device_id dw_hdmi_rockchip_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;
+ 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_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = rockchip_hdmi_parse_dt(hdmi);
+ if (ret) {
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdcp_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI hdcp clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rockchip_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->clk);
+ clk_disable_unprepare(hdmi->hdcp_clk);
+
+ 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",
+ .owner = THIS_MODULE,
+ .of_match_table = dw_hdmi_rockchip_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index e26e61f..f72cd10 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,7 @@ enum {
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
+ RK3288_HDMI,
};
struct mpll_config {
--
1.9.1
We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they also have some
lightly differences, such as phy pll configuration, register width(imx hdmi
register is one byte, but rk3288 is 4 bytes width and can only be accessed
by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
support.
To reuse the imx-hdmi driver, we make this patch set:
(1): fix some CodingStyle warning to make checkpatch happy
(2): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
(3): move imx-hdmi to bridge/dw-hdmi, and convert it to a drm_bridge driver
(4): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
Changes in v9:
- move some phy configuration to platform driver
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
- Add documentation for rockchip dw hdmi
- add support for rockchip rk3288 hdmi
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6:
- rearrange the patch order
- move some modification to patch#6
- refactor register access without reg_shift
- move some modification from patch#5
Changes in v5:
- refactor reg-io-width
Changes in v4:
- fix checkpatch CHECK
- defer probe ddc i2c adapter
Changes in v3:
- split multi register access to one indepent patch
Changes in v2:
- use git format -M to generate these patch
Andy Yan (8):
staging: imx-drm: imx-hdmi: make checkpatch happy
staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
dt-bindings: add document for dw_hdmi
drm: bridge/dw_hdmi: add support for multi byte register width access
dt-bindings: Add documentation for rockchip dw hdmi
drm: bridge/dw_hdmi: add rockchip rk3288 support
Yakir Yang (1):
drm: bridge/dw_hdmi: convert dw-hdmi to drm_bridge mode
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 762 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 8 +-
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 328 +++++++++
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 274 ++++++++
include/drm/bridge/dw_hdmi.h | 60 ++
13 files changed, 1111 insertions(+), 425 deletions(-)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h
--
1.9.1
CHECK: Alignment should match open parenthesis
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
CHECK: braces {} should be used on all arms of this statement
+ if (hdmi->hdmi_data.video_mode.mdvi)
[...]
+ else {
[...]
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- rearrange the patch order
Changes in v5: None
Changes in v4:
- fix checkpatch CHECK
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 49 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index aaec6b2..79daec4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
}
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+ u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}
static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
- unsigned long pixel_clk)
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
+ __func__, pixel_clk);
return;
}
@@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
u16 coeff_b = (*csc_coeff)[1][i];
u16 coeff_c = (*csc_coeff)[2][i];
- hdmi_writeb(hdmi, coeff_a & 0xff,
- HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_c & 0xff,
- HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}
@@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
- if (hdmi_data->enc_out_format == RGB
- || hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth)
+ if (hdmi_data->enc_out_format == RGB ||
+ hdmi_data->enc_out_format == YCBCR444) {
+ if (!hdmi_data->enc_color_depth) {
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- else if (hdmi_data->enc_color_depth == 8) {
+ } else if (hdmi_data->enc_color_depth == 8) {
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10)
+ } else if (hdmi_data->enc_color_depth == 10) {
color_depth = 5;
- else if (hdmi_data->enc_color_depth == 12)
+ } else if (hdmi_data->enc_color_depth == 12) {
color_depth = 6;
- else if (hdmi_data->enc_color_depth == 16)
+ } else if (hdmi_data->enc_color_depth == 16) {
color_depth = 7;
- else
+ } else {
return;
+ }
} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
if (!hdmi_data->enc_color_depth ||
hdmi_data->enc_color_depth == 8)
@@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
else
return;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
- } else
+ } else {
return;
+ }
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
@@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
@@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
}
static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 8),
- HDMI_PHY_I2CM_DATAO_1_ADDR);
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 0),
- HDMI_PHY_I2CM_DATAO_0_ADDR);
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
- HDMI_PHY_I2CM_OPERATION_ADDR);
+ HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
@@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 1);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
+ HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
@@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
break;
if (i >= ARRAY_SIZE(curr_ctrl)) {
- dev_err(hdmi->dev,
- "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
+ dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
@@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
- (hdmi->vic == 21) || (hdmi->vic == 22) ||
- (hdmi->vic == 2) || (hdmi->vic == 3) ||
- (hdmi->vic == 17) || (hdmi->vic == 18))
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
else
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
- (hdmi->vic == 12) || (hdmi->vic == 13) ||
- (hdmi->vic == 14) || (hdmi->vic == 15) ||
- (hdmi->vic == 25) || (hdmi->vic == 26) ||
- (hdmi->vic == 27) || (hdmi->vic == 28) ||
- (hdmi->vic == 29) || (hdmi->vic == 30) ||
- (hdmi->vic == 35) || (hdmi->vic == 36) ||
- (hdmi->vic == 37) || (hdmi->vic == 38))
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
else
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
@@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
imx_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi)
+ if (hdmi->hdmi_data.video_mode.mdvi) {
dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- else {
+ } else {
dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
/* HDMI Initialization Step E - Configure audio */
@@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
+ HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
@@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
+ &imx_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Product and revision IDs */
dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(hdmi, HDMI_DESIGN_ID),
+ hdmi_readb(hdmi, HDMI_REVISION_ID),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
initialize_hdmi_ih_mutes(hdmi);
--
1.9.1
drm driver may probe before the i2c bus, so the driver should
defer probing until it is available
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4:
- defer probe ddc i2c adapter
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 79daec4..c2b035a 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1611,8 +1611,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- if (!hdmi->ddc)
+ if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
+ of_node_put(ddc_node);
+ return -EPROBE_DEFER;
+ }
of_node_put(ddc_node);
} else {
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
new file mode 100644
index 0000000..0558442
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
@@ -0,0 +1,40 @@
+DesignWare HDMI bridge bindings
+
+Required properities:
+- compatible: platform specific such as:
+ * "fsl,imx6q-hdmi"
+ * "fsl,imx6dl-hdmi"
+ * "rockchip,rk3288-dw-hdmi"
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- interrupts: The HDMI interrupt number
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+
+Example:
+ hdmi: hdmi@0120000 {
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
--
1.9.1
On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width accesses (writeb,
readb) generate an imprecise external abort.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4: None
Changes in v3:
- split multi register access to one indepent patch
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 57 +++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index e9f0dfe..978c709 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -101,6 +101,11 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
+union dw_reg_ptr {
+ u32 __iomem *p32;
+ u8 __iomem *p8;
+};
+
struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -121,20 +126,43 @@ struct dw_hdmi {
struct regmap *regmap;
struct i2c_adapter *ddc;
- void __iomem *regs;
+ union dw_reg_ptr regs;
unsigned int sample_rate;
int ratio;
+
+ void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+ u8 (*read)(struct dw_hdmi *hdmi, int offset);
};
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writel(val, hdmi->regs.p32 + offset);
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs.p32 + offset);
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writeb(val, hdmi->regs.p8 + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return readb(hdmi->regs.p8 + offset);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(hdmi, val, offset);
}
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi, offset);
}
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
@@ -1499,6 +1527,23 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
struct device_node *ddc_node;
struct resource *iores;
int ret, irq;
+ u32 val = 1;
+
+ of_property_read_u32(np, "reg-io-width", &val);
+
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ break;
+ case 1:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return -EINVAL;
+ }
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
@@ -1525,9 +1570,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
+ hdmi->regs.p32 = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs.p32))
+ return PTR_ERR(hdmi->regs.p32);
if (hdmi->plat_data->setup)
hdmi->priv = hdmi->plat_data->setup(pdev);
--
1.9.1
From: Yakir Yang <[email protected]>
keep the connector & birdge in dw_hdmi.c, handle encoder
in dw_hdmi-imx.c, as most of the encoder operation are
platform specific such as crtc select and panel format
set
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification from patch#5
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 228 +++++++++++++++-------------------
drivers/staging/imx-drm/dw_hdmi-imx.c | 145 ++++++++++++++-------
include/drm/bridge/dw_hdmi.h | 13 +-
3 files changed, 199 insertions(+), 187 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 978c709..ed75147 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -11,7 +11,6 @@
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
-#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -108,7 +107,8 @@ union dw_reg_ptr {
struct dw_hdmi {
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
enum dw_hdmi_devtype dev_type;
struct device *dev;
@@ -1319,6 +1319,50 @@ static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
dw_hdmi_phy_disable(hdmi);
}
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_setup(hdmi, mode);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweroff(hdmi);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweron(hdmi);
+}
+
+static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge)
+{
+ drm_bridge_cleanup(bridge);
+ kfree(bridge);
+}
+
+static void dw_hdmi_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
@@ -1360,60 +1404,7 @@ static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
- return &hdmi->encoder;
-}
-
-static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_setup(hdmi, mode);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (mode)
- dw_hdmi_poweroff(hdmi);
- else
- dw_hdmi_poweron(hdmi);
-}
-
-static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_poweroff(hdmi);
-
- if (hdmi->plat_data->encoder_prepare)
- hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
-}
-
-static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (hdmi->plat_data->encoder_commit)
- hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
-
- dw_hdmi_poweron(hdmi);
+ return hdmi->encoder;
}
void dw_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1422,19 +1413,6 @@ void dw_hdmi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
- .dpms = dw_hdmi_encoder_dpms,
- .prepare = dw_hdmi_encoder_prepare,
- .commit = dw_hdmi_encoder_commit,
- .mode_set = dw_hdmi_encoder_mode_set,
- .mode_fixup = dw_hdmi_encoder_mode_fixup,
- .disable = dw_hdmi_encoder_disable,
-};
-
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1447,6 +1425,16 @@ static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.best_encoder = dw_hdmi_connector_best_encoder,
};
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .enable = dw_hdmi_bridge_enable,
+ .disable = dw_hdmi_bridge_disable,
+ .pre_enable = dw_hdmi_bridge_nope,
+ .post_disable = dw_hdmi_bridge_nope,
+ .mode_set = dw_hdmi_bridge_mode_set,
+ .mode_fixup = dw_hdmi_bridge_mode_fixup,
+ .destroy = dw_hdmi_bridge_destroy,
+};
+
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
@@ -1495,40 +1483,64 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
- struct drm_encoder *encoder = &hdmi->encoder;
- struct device *dev = hdmi->dev;
+ struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_bridge *bridge;
+ int ret;
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("Failed to allocate drm bridge\n");
+ return -ENOMEM;
+ }
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ hdmi->bridge = bridge;
+ bridge->driver_private = hdmi;
- drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
- hdmi->connector.encoder = &hdmi->encoder;
+ hdmi->connector.encoder = encoder;
- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
return 0;
}
-static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct resource *iores;
+ struct dw_hdmi *hdmi;
int ret, irq;
u32 val = 1;
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+ hdmi->encoder = encoder;
+
of_property_read_u32(np, "reg-io-width", &val);
switch (val) {
@@ -1574,8 +1586,6 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs.p32))
return PTR_ERR(hdmi->regs.p32);
- if (hdmi->plat_data->setup)
- hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1616,9 +1626,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-static void dw_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1626,57 +1636,15 @@ static void dw_hdmi_unbind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
- if (hdmi->plat_data->exit)
- hdmi->plat_data->exit(hdmi->priv);
- i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
- .bind = dw_hdmi_bind,
- .unbind = dw_hdmi_unbind,
-};
-
-static int dw_hdmi_platform_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int dw_hdmi_platform_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &hdmi_ops);
- return 0;
-}
-
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data)
-{
- struct dw_hdmi *hdmi;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->plat_data = plat_data;
- hdmi->dev = &pdev->dev;
- hdmi->dev_type = plat_data->dev_type;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
+ hdmi->encoder->funcs->destroy(hdmi->encoder);
- platform_set_drvdata(pdev, hdmi);
-
- return dw_hdmi_platform_probe(pdev);
-}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-
-int dw_hdmi_platform_unregister(struct platform_device *pdev)
-{
- return dw_hdmi_platform_remove(pdev);
+ i2c_put_adapter(hdmi->ddc);
}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 4b48ea6..ad71c8e 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -8,12 +8,19 @@
*/
#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 <linux/clk.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 "imx-drm.h"
@@ -22,6 +29,7 @@ struct imx_hdmi {
struct clk *isfr_clk;
struct clk *iahb_clk;
struct regmap *regmap;
+ struct drm_encoder encoder;
};
static const struct mpll_config imx_mpll_cfg[] = {
@@ -69,7 +77,7 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
-static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
+static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
@@ -94,48 +102,26 @@ static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
return 0;
}
-static void *dw_hdmi_imx_setup(struct platform_device *pdev)
+static void dw_hdmi_imx_disable(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi;
- int ret;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return ERR_PTR(-ENOMEM);
- hdmi->dev = &pdev->dev;
-
- ret = dw_hdmi_parse_dt(hdmi);
- if (ret < 0)
- return ERR_PTR(ret);
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return hdmi;
}
-static void dw_hdmi_imx_exit(void *priv)
+static bool dw_hdmi_imx_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
-
- clk_disable_unprepare(hdmi->isfr_clk);
+ return true;
+}
- clk_disable_unprepare(hdmi->iahb_clk);
+static void dw_hdmi_imx_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
}
-static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
+ 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,
@@ -143,27 +129,30 @@ static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_prepare(struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_imx_mode_fixup,
+ .mode_set = dw_hdmi_imx_mode_set,
+ .prepare = dw_hdmi_imx_prepare,
+ .commit = dw_hdmi_imx_commit,
+ .disable = dw_hdmi_imx_disable,
+};
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6Q_HDMI,
};
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6DL_HDMI,
@@ -180,23 +169,82 @@ static const struct of_device_id dw_hdmi_imx_ids[] = {
};
MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int dw_hdmi_imx_probe(struct platform_device *pdev)
+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;
+ 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_ids, pdev->dev.of_node);
plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = dw_hdmi_imx_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
- return dw_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+ clk_disable_unprepare(hdmi->iahb_clk);
+
+ 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)
{
- return dw_hdmi_platform_unregister(pdev);
+ component_del(&pdev->dev, &dw_hdmi_imx_ops);
+
+ return 0;
}
static struct platform_driver dw_hdmi_imx_platform_driver = {
@@ -212,6 +260,7 @@ static struct platform_driver dw_hdmi_imx_platform_driver = {
module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 6683b63..e26e61f 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -38,20 +38,15 @@ struct curr_ctrl {
};
struct dw_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
enum dw_hdmi_devtype dev_type;
-
};
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data);
-int dw_hdmi_platform_unregister(struct platform_device *pdev);
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
IMX6 and Rockchip RK3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly differences, such as phy pll configuration,
register width, 4K support, clk useage, and the crtc mux configuration
is also platform specific.
To reuse the imx hdmi driver, split the platform specific code out
to dw_hdmi-imx.c.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8: None
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 217 +++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 255 ++++++++--------------------------
drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++
4 files changed, 322 insertions(+), 195 deletions(-)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 582c438..809027d 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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) += imx-hdmi.o dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
new file mode 100644
index 0000000..0db978e
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,217 @@
+/* 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/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#include "imx-drm.h"
+#include "imx-hdmi.h"
+
+struct imx_hdmi_priv {
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+ struct regmap *regmap;
+};
+
+static const struct 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 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 int imx_hdmi_parse_dt(struct imx_hdmi_priv *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);
+ }
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
+ return PTR_ERR(hdmi->isfr_clk);
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->iahb_clk);
+ }
+
+ return 0;
+}
+
+static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+{
+ struct imx_hdmi_priv *hdmi;
+ int ret;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return ERR_PTR(-ENOMEM);
+ hdmi->dev = &pdev->dev;
+
+ ret = imx_hdmi_parse_dt(hdmi);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return hdmi;
+}
+
+static void imx_hdmi_imx_exit(void *priv)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+
+ clk_disable_unprepare(hdmi->iahb_clk);
+}
+
+static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ 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 imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .dev_type = IMX6Q_HDMI,
+};
+
+static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .dev_type = IMX6DL_HDMI,
+};
+
+static const struct of_device_id imx_hdmi_imx_ids[] = {
+ { .compatible = "fsl,imx6q-hdmi",
+ .data = &imx6q_hdmi_drv_data
+ }, {
+ .compatible = "fsl,imx6dl-hdmi",
+ .data = &imx6dl_hdmi_drv_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+
+static int imx_hdmi_imx_probe(struct platform_device *pdev)
+{
+ const struct imx_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ plat_data = match->data;
+
+ return imx_hdmi_platform_register(pdev, plat_data);
+}
+
+static int imx_hdmi_imx_remove(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_unregister(pdev);
+}
+
+static struct platform_driver imx_hdmi_imx_platform_driver = {
+ .probe = imx_hdmi_imx_probe,
+ .remove = imx_hdmi_imx_remove,
+ .driver = {
+ .name = "dwhdmi-imx",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_hdmi_imx_ids,
+ },
+};
+
+module_platform_driver(imx_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c2b035a..c7e5f12 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,21 +16,16 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/clk.h>
#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.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 <video/imx-ipu-v3.h>
#include "imx-hdmi.h"
-#include "imx-drm.h"
#define HDMI_EDID_LEN 512
@@ -54,11 +49,6 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x0000, 0x0000, 0x0000 },
{ 0x0000, 0x2000, 0x0000, 0x0000 },
@@ -117,10 +107,10 @@ struct imx_hdmi {
enum imx_hdmi_devtype dev_type;
struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
struct hdmi_data_info hdmi_data;
+ const struct imx_hdmi_plat_data *plat_data;
+ void *priv;
int vic;
u8 edid[HDMI_EDID_LEN];
@@ -137,13 +127,6 @@ struct imx_hdmi {
int ratio;
};
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
@@ -728,76 +711,13 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
- {
- 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 },
- },
- }
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
- /* 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 int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
u8 val, msec;
+ const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
+ const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
if (prep)
return -EINVAL;
@@ -843,27 +763,27 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
- for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config[i].mpixelclock)
+ mpll_cfg[i].mpixelclock)
break;
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);
- for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl[i].mpixelclock)
+ curr_ctr[i].mpixelclock)
break;
- if (i >= ARRAY_SIZE(curr_ctrl)) {
+ if (curr_ctr[i].mpixelclock == (~0UL)) {
dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
/* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10);
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
@@ -1453,21 +1373,29 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+
+ if (hdmi->plat_data->encoder_prepare)
+ hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
static void imx_hdmi_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);
- imx_hdmi_set_ipu_di_mux(hdmi, mux);
+ if (hdmi->plat_data->encoder_commit)
+ hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
imx_hdmi_poweron(hdmi);
}
+void imx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_drm_encoder_destroy,
+ .destroy = drm_encoder_cleanup,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1483,7 +1411,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_drm_connector_destroy,
+ .destroy = imx_hdmi_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1539,12 +1467,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
- int ret;
+ struct drm_encoder *encoder = &hdmi->encoder;
+ struct device *dev = hdmi->dev;
- ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
- hdmi->dev->of_node);
- if (ret)
- return ret;
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
@@ -1564,50 +1490,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- .driver_data = IMX6Q_HDMI,
- }, {
- .name = "imx6dl-hdmi",
- .driver_data = IMX6DL_HDMI,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
- struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
-
- hdmi->dev_type = device_id->driver_data;
- }
-
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1637,40 +1529,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap))
- return PTR_ERR(hdmi->regmap);
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- ret = PTR_ERR(hdmi->isfr_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI isfr clk: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- ret = PTR_ERR(hdmi->iahb_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI iahb clk: %d\n", ret);
- goto err_isfr;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- goto err_isfr;
- }
-
+ if (hdmi->plat_data->setup)
+ hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1698,11 +1558,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ret = imx_hdmi_fb_registered(hdmi);
if (ret)
- goto err_iahb;
+ return ret;
ret = imx_hdmi_register(drm, hdmi);
if (ret)
- goto err_iahb;
+ return ret;
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
@@ -1710,13 +1570,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, hdmi);
return 0;
-
-err_iahb:
- clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
- clk_disable_unprepare(hdmi->isfr_clk);
-
- return ret;
}
static void imx_hdmi_unbind(struct device *dev, struct device *master,
@@ -1729,9 +1582,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
+ if (hdmi->plat_data->exit)
+ hdmi->plat_data->exit(hdmi->priv);
i2c_put_adapter(hdmi->ddc);
}
@@ -1751,17 +1603,32 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver imx_hdmi_driver = {
- .probe = imx_hdmi_platform_probe,
- .remove = imx_hdmi_platform_remove,
- .driver = {
- .name = "imx-hdmi",
- .owner = THIS_MODULE,
- .of_match_table = imx_hdmi_dt_ids,
- },
-};
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data)
+{
+ struct imx_hdmi *hdmi;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
-module_platform_driver(imx_hdmi_driver);
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+
+ platform_set_drvdata(pdev, hdmi);
+
+ return imx_hdmi_platform_probe(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+
+int imx_hdmi_platform_unregister(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_remove(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b6776..e67d60d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,47 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum imx_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct imx_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ enum imx_hdmi_devtype dev_type;
+
+};
+
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data);
+int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi driver out
to drm/bridge and rename imx-hdmi to dw_hdmi
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2:
- use git format -M to generate these patch
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 281 +++++++++++----------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 46 +---
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 70 ++---
include/drm/bridge/dw_hdmi.h | 57 +++++
8 files changed, 243 insertions(+), 220 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (83%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (97%)
create mode 100644 include/drm/bridge/dw_hdmi.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..26162ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,3 +3,8 @@ config DRM_PTN3460
depends on DRM
select DRM_KMS_HELPER
---help---
+
+config DRM_DW_HDMI
+ bool "Synopsys DesignWare High-Definition Multimedia Interface"
+ depends on DRM
+ select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..d8a8cfd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
similarity index 83%
rename from drivers/staging/imx-drm/imx-hdmi.c
rename to drivers/gpu/drm/bridge/dw_hdmi.c
index c7e5f12..e9f0dfe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -6,8 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
+ * Designware High-Definition Multimedia Interface (HDMI) driver
*
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
@@ -24,8 +23,9 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
-#include "imx-hdmi.h"
+#include "dw_hdmi.h"
#define HDMI_EDID_LEN 512
@@ -101,15 +101,15 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
-struct imx_hdmi {
+struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
- enum imx_hdmi_devtype dev_type;
+ enum dw_hdmi_devtype dev_type;
struct device *dev;
struct hdmi_data_info hdmi_data;
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
void *priv;
int vic;
@@ -127,17 +127,17 @@ struct imx_hdmi {
int ratio;
};
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
}
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
return readb(hdmi->regs + offset);
}
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;
@@ -145,13 +145,13 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
unsigned int value)
{
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
@@ -162,7 +162,7 @@ static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
@@ -309,7 +309,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -333,12 +333,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
hdmi_regenerate_cts(hdmi, clk_cts);
}
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, 74250000);
}
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
@@ -350,7 +350,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
* pin{31~24} <==> G[7:0]
* pin{15~8} <==> B[7:0]
*/
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
{
int color_format = 0;
u8 val;
@@ -406,12 +406,12 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
}
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
return 0;
@@ -421,7 +421,7 @@ static int is_color_space_decimation(struct imx_hdmi *hdmi)
return 0;
}
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
return 0;
@@ -431,7 +431,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
return 0;
}
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
unsigned i;
@@ -472,7 +472,7 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
HDMI_CSC_SCALE);
}
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
{
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
@@ -500,7 +500,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
HDMI_CSC_SCALE);
- imx_hdmi_update_csc_coeffs(hdmi);
+ dw_hdmi_update_csc_coeffs(hdmi);
}
/*
@@ -508,7 +508,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
* for example, if input is YCC422 mode or repeater is used,
* data should be repacked this module can be bypassed.
*/
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
{
unsigned int color_depth = 0;
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -605,40 +605,40 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_CONF);
}
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
@@ -648,7 +648,7 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -662,56 +662,56 @@ static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
}
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_ENTMDS_OFFSET,
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
}
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
}
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
HDMI_PHY_CONF0_SELDATAENPOL_MASK);
}
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDIPIF_OFFSET,
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
@@ -746,10 +746,10 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
/* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
/* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
/* PHY reset */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
@@ -796,15 +796,15 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- imx_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_power(hdmi, 1);
/* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 1);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
/* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(hdmi, 1);
- imx_hdmi_phy_gen2_pddq(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
/*Wait for PHY PLL lock */
msec = 5;
@@ -825,7 +825,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
return 0;
}
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
bool cscon = false;
@@ -836,10 +836,10 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
- imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
- imx_hdmi_phy_sel_interface_control(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+ dw_hdmi_phy_sel_interface_control(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
@@ -851,7 +851,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
return 0;
}
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{
u8 de;
@@ -870,7 +870,7 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
{
u8 val, pix_fmt, under_scan;
u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
@@ -964,7 +964,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
}
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
u8 inv_val;
@@ -1048,19 +1048,19 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
{
if (!hdmi->phy_enabled)
return;
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
u8 clkdis;
@@ -1089,13 +1089,13 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
}
}
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
int count;
u8 val;
@@ -1113,19 +1113,19 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
HDMI_IH_MUTE_FC_STAT2);
}
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
{
int ret;
@@ -1177,12 +1177,12 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */
- ret = imx_hdmi_phy_init(hdmi);
+ ret = dw_hdmi_phy_init(hdmi);
if (ret)
return ret;
/* HDMI Initialization Step B.3 */
- imx_hdmi_enable_video_path(hdmi);
+ dw_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
if (hdmi->hdmi_data.video_mode.mdvi) {
@@ -1203,7 +1203,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_video_sample(hdmi);
hdmi_tx_hdcp_config(hdmi);
- imx_hdmi_clear_overflow(hdmi);
+ dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
hdmi_enable_overflow_interrupts(hdmi);
@@ -1211,7 +1211,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);
@@ -1229,7 +1229,7 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
return 0;
}
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{
u8 ih_mute;
@@ -1281,29 +1281,29 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
}
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{
- imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+ dw_hdmi_setup(hdmi, &hdmi->previous_mode);
}
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
- imx_hdmi_phy_disable(hdmi);
+ dw_hdmi_phy_disable(hdmi);
}
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
struct edid *edid;
int ret;
@@ -1326,102 +1326,102 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return &hdmi->encoder;
}
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_setup(hdmi, mode);
+ dw_hdmi_setup(hdmi, mode);
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
}
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (mode)
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
else
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
if (hdmi->plat_data->encoder_prepare)
hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (hdmi->plat_data->encoder_commit)
hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-void imx_hdmi_connector_destroy(struct drm_connector *connector)
+void dw_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .dpms = imx_hdmi_encoder_dpms,
- .prepare = imx_hdmi_encoder_prepare,
- .commit = imx_hdmi_encoder_commit,
- .mode_set = imx_hdmi_encoder_mode_set,
- .mode_fixup = imx_hdmi_encoder_mode_fixup,
- .disable = imx_hdmi_encoder_disable,
+static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
+ .dpms = dw_hdmi_encoder_dpms,
+ .prepare = dw_hdmi_encoder_prepare,
+ .commit = dw_hdmi_encoder_commit,
+ .mode_set = dw_hdmi_encoder_mode_set,
+ .mode_fixup = dw_hdmi_encoder_mode_fixup,
+ .disable = dw_hdmi_encoder_disable,
};
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- .get_modes = imx_hdmi_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+ .get_modes = dw_hdmi_connector_get_modes,
+ .best_encoder = dw_hdmi_connector_best_encoder,
};
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1431,9 +1431,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
@@ -1447,14 +1447,14 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
HDMI_PHY_POL0);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
}
drm_helper_hpd_irq_event(hdmi->connector.dev);
}
@@ -1465,7 +1465,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = &hdmi->encoder;
struct device *dev = hdmi->dev;
@@ -1474,13 +1474,13 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ &dw_hdmi_connector_helper_funcs);
+ drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1490,10 +1490,10 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
@@ -1518,8 +1518,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
+ ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
return ret;
@@ -1556,11 +1556,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- ret = imx_hdmi_fb_registered(hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
return ret;
- ret = imx_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_register(drm, hdmi);
if (ret)
return ret;
@@ -1572,10 +1572,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
+static void dw_hdmi_unbind(struct device *dev, struct device *master,
void *data)
{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
@@ -1588,25 +1588,25 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
}
static const struct component_ops hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
+ .bind = dw_hdmi_bind,
+ .unbind = dw_hdmi_unbind,
};
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int dw_hdmi_platform_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &hdmi_ops);
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static int dw_hdmi_platform_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &hdmi_ops);
return 0;
}
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data)
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
{
- struct imx_hdmi *hdmi;
+ struct dw_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1620,17 +1620,18 @@ int imx_hdmi_platform_register(struct platform_device *pdev,
platform_set_drvdata(pdev, hdmi);
- return imx_hdmi_platform_probe(pdev);
+ return dw_hdmi_platform_probe(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-int imx_hdmi_platform_unregister(struct platform_device *pdev)
+int dw_hdmi_platform_unregister(struct platform_device *pdev)
{
- return imx_hdmi_platform_remove(pdev);
+ return dw_hdmi_platform_remove(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
similarity index 97%
rename from drivers/staging/imx-drm/imx-hdmi.h
rename to drivers/gpu/drm/bridge/dw_hdmi.h
index e67d60d..b8412a9 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -7,8 +7,8 @@
* (at your option) any later version.
*/
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
+#ifndef __DW_HDMI__
+#define __DW_HDMI__
/* Identification Registers */
#define HDMI_DESIGN_ID 0x0000
@@ -1030,46 +1030,4 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-struct imx_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
- const struct mpll_config *mpll_cfg;
- const struct curr_ctrl *cur_ctr;
- enum imx_hdmi_devtype dev_type;
-
-};
-
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data);
-int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index ab31848..560e1d3 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -50,5 +50,6 @@ config DRM_IMX_IPUV3
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
depends on DRM_IMX
+ select DRM_DW_HDMI
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 809027d..f3ecd89 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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 dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 0db978e..4b48ea6 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -10,14 +10,14 @@
#include <linux/platform_device.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 <linux/clk.h>
#include "imx-drm.h"
-#include "imx-hdmi.h"
-struct imx_hdmi_priv {
+struct imx_hdmi {
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -69,7 +69,7 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
-static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
+static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
@@ -94,9 +94,9 @@ static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
return 0;
}
-static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+static void *dw_hdmi_imx_setup(struct platform_device *pdev)
{
- struct imx_hdmi_priv *hdmi;
+ struct imx_hdmi *hdmi;
int ret;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -104,7 +104,7 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return ERR_PTR(-ENOMEM);
hdmi->dev = &pdev->dev;
- ret = imx_hdmi_parse_dt(hdmi);
+ ret = dw_hdmi_parse_dt(hdmi);
if (ret < 0)
return ERR_PTR(ret);
ret = clk_prepare_enable(hdmi->isfr_clk);
@@ -124,18 +124,18 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return hdmi;
}
-static void imx_hdmi_imx_exit(void *priv)
+static void dw_hdmi_imx_exit(void *priv)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
clk_disable_unprepare(hdmi->isfr_clk);
clk_disable_unprepare(hdmi->iahb_clk);
}
-static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
@@ -143,33 +143,33 @@ static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
-static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6Q_HDMI,
};
-static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6DL_HDMI,
};
-static const struct of_device_id imx_hdmi_imx_ids[] = {
+static const struct of_device_id dw_hdmi_imx_ids[] = {
{ .compatible = "fsl,imx6q-hdmi",
.data = &imx6q_hdmi_drv_data
}, {
@@ -178,38 +178,38 @@ static const struct of_device_id imx_hdmi_imx_ids[] = {
},
{},
};
-MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int imx_hdmi_imx_probe(struct platform_device *pdev)
+static int dw_hdmi_imx_probe(struct platform_device *pdev)
{
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
if (!pdev->dev.of_node)
return -ENODEV;
- match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ match = of_match_node(dw_hdmi_imx_ids, pdev->dev.of_node);
plat_data = match->data;
- return imx_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_platform_register(pdev, plat_data);
}
-static int imx_hdmi_imx_remove(struct platform_device *pdev)
+static int dw_hdmi_imx_remove(struct platform_device *pdev)
{
- return imx_hdmi_platform_unregister(pdev);
+ return dw_hdmi_platform_unregister(pdev);
}
-static struct platform_driver imx_hdmi_imx_platform_driver = {
- .probe = imx_hdmi_imx_probe,
- .remove = imx_hdmi_imx_remove,
+static struct platform_driver dw_hdmi_imx_platform_driver = {
+ .probe = dw_hdmi_imx_probe,
+ .remove = dw_hdmi_imx_remove,
.driver = {
.name = "dwhdmi-imx",
.owner = THIS_MODULE,
- .of_match_table = imx_hdmi_imx_ids,
+ .of_match_table = dw_hdmi_imx_ids,
},
};
-module_platform_driver(imx_hdmi_imx_platform_driver);
+module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..6683b63
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __DW_HDMI_H__
+#define __DW_HDMI_H__
+
+#include <drm/drmP.h>
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum dw_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct dw_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ enum dw_hdmi_devtype dev_type;
+
+};
+
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data);
+int dw_hdmi_platform_unregister(struct platform_device *pdev);
+#endif /* __IMX_HDMI_H__ */
--
1.9.1
rk3288 hdmi is compatible with Designware hdmi
this patch is depend on patch by Mark Yao Add drm
driver for Rockchip Socs
see https://lkml.org/lkml/2014/10/8/201
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v9:
- move some phy configuration to platform driver
Changes in v8:
- add support for rockchip rk3288 hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 45 +++-
drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 328 ++++++++++++++++++++++++++++
drivers/staging/imx-drm/dw_hdmi-imx.c | 8 +
include/drm/bridge/dw_hdmi.h | 8 +
7 files changed, 399 insertions(+), 5 deletions(-)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index ed75147..1dd1f0b 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -668,11 +668,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ u32 val;
+
+ while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
udelay(1000);
}
+ hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
return true;
}
@@ -711,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_ENTMDS_MASK);
}
+static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SPARECTRL_OFFSET,
+ HDMI_PHY_CONF0_SPARECTRL_MASK);
+}
+
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
@@ -746,6 +757,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
u8 val, msec;
const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
+ const struct sym_term *sym_term = hdmi->plat_data->sym_term;
if (prep)
return -EINVAL;
@@ -815,10 +827,17 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+
+ for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ sym_term[i].mpixelclock)
+ break;
+
/* RESISTANCE TERM 133Ohm Cfg */
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
/* PREEMP Cgf 0.00 */
- hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
+
/* TX/CK LVL 10 */
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
/* REMOVE CLK TERM */
@@ -834,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
+ if (hdmi->dev_type == RK3288_HDMI)
+ dw_hdmi_phy_enable_spare(hdmi, 1);
+
/*Wait for PHY PLL lock */
msec = 5;
do {
@@ -1398,6 +1420,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = container_of(connector,
+ struct dw_hdmi, connector);
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (hdmi->plat_data->mode_valid)
+ mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1422,6 +1458,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
+ .mode_valid = dw_hdmi_connector_mode_valid,
.best_encoder = dw_hdmi_connector_best_encoder,
};
@@ -1514,6 +1551,8 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+ drm_connector_register(&hdmi->connector);
+
return 0;
}
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
index b8412a9..30a6b28 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -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,
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0ff6682..06371ae 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -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
+ bool "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.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index b3a5193..347e65c 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,5 +4,5 @@
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchip_drm_gem.o rockchip_drm_vop.o
-
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 0000000..19b11e9
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,328 @@
+/*
+ * 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 <linux/clk.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 clk *clk;
+ struct clk *hdcp_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+
+static const struct mpll_config rockchip_mpll_cfg[] = {
+ {
+ /* 27MHz & 36MHz & 40MHz */
+ 40000000, {
+ { 0x00b3, 0x0000},
+ { 0x2153, 0x0000},
+ { 0x40f3, 0x0000}
+ },
+ }, {
+ /* 54MHz & 65MHz */
+ 65000000, {
+ { 0x0072, 0x0001},
+ { 0x2142, 0x0001},
+ { 0x40a2, 0x0001},
+ },
+ }, {
+ 66000000, {
+ { 0x013e, 0x0003},
+ { 0x217e, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 74250000, {
+ { 0x0072, 0x0001},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 83500000, {
+ { 0x0072, 0x0001},
+ },
+ }, {
+ /* 108MHz & 106.5MHz & 146.25MHz */
+ 146250000, {
+ { 0x0051, 0x0002},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 148500000, {
+ { 0x0051, 0x0003},
+ { 0x214c, 0x0003},
+ { 0x4064, 0x0003}
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+static const struct 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 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);
+ }
+
+ hdmi->clk = devm_clk_get(hdmi->dev, "clk");
+ if (IS_ERR(hdmi->clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI clk\n");
+ return PTR_ERR(hdmi->clk);
+ }
+
+ hdmi->hdcp_clk = devm_clk_get(hdmi->dev, "hdcp_clk");
+ if (IS_ERR(hdmi->hdcp_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI hdcp clk\n");
+ return PTR_ERR(hdmi->hdcp_clk);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct 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_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_rockchip_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_rockchip_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void dw_hdmi_rockchip_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_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_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_rockchip_mode_fixup,
+ .mode_set = dw_hdmi_rockchip_mode_set,
+ .prepare = dw_hdmi_rockchip_prepare,
+ .commit = dw_hdmi_rockchip_commit,
+ .disable = dw_hdmi_rockchip_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_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;
+ 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_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = rockchip_hdmi_parse_dt(hdmi);
+ if (ret) {
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdcp_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI hdcp clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rockchip_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->clk);
+ clk_disable_unprepare(hdmi->hdcp_clk);
+
+ 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",
+ .owner = THIS_MODULE,
+ .of_match_table = dw_hdmi_rockchip_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index ad71c8e..01c7265 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -77,6 +77,12 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
+static const struct 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;
@@ -149,12 +155,14 @@ static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
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,
};
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index e26e61f..b3ed764 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,7 @@ enum {
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
+ RK3288_HDMI,
};
struct mpll_config {
@@ -37,11 +38,18 @@ struct curr_ctrl {
u16 curr[RES_MAX];
};
+struct sym_term {
+ unsigned long mpixelclock;
+ u16 sym_ctr; /*clock symbol and transmitter control*/
+ u16 term; /*transmission termination value*/
+};
+
struct dw_hdmi_plat_data {
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
+ const struct sym_term *sym_term;
enum dw_hdmi_devtype dev_type;
};
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v9: None
Changes in v8:
- Add documentation for rockchip dw hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
new file mode 100644
index 0000000..6ea6764
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
@@ -0,0 +1,43 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks: from common clock binding: handle to hdmi clock.
+- clock-names: should be "clk" "hdcp_clk"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt. For
+ vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+ rk3288 platform
+
+Example:
+hdmi: hdmi@ff980000 {
+ compatible = "rockchip,rk3288-dw-hdmi";
+ reg = <0xff980000 0x20000>;
+ reg-io-width = <4>;
+ ddc-i2c-bus = <&i2c5>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+ clock-names = "clk", "hdcp_clk";
+ status = "disabled";
+ ports {
+ hdmi_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ hdmi_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_hdmi>;
+ };
+ hdmi_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_hdmi>;
+ };
+ };
+ };
+};
--
1.9.1
On 13/11/14 12:57, Andy Yan wrote:
> rk3288 hdmi is compatible with Designware hdmi
>
> this patch is depend on patch by Mark Yao Add drm
> driver for Rockchip Socs
>
> see https://lkml.org/lkml/2014/10/8/201
>
> Signed-off-by: Andy Yan <[email protected]>
> Signed-off-by: Yakir Yang <[email protected]>
>
> ---
>
> Changes in v9:
> - move some phy configuration to platform driver
>
> Changes in v8:
> - add support for rockchip rk3288 hdmi
>
> Changes in v7: None
> Changes in v6: None
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> drivers/gpu/drm/bridge/dw_hdmi.c | 45 +++-
This patch looks like it does alot to the dw_hdmi.c as well and not
just adds support for rk3288..
> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
> drivers/gpu/drm/rockchip/Kconfig | 10 +
> drivers/gpu/drm/rockchip/Makefile | 2 +-
> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 328 ++++++++++++++++++++++++++++
> drivers/staging/imx-drm/dw_hdmi-imx.c | 8 +
> include/drm/bridge/dw_hdmi.h | 8 +
> 7 files changed, 399 insertions(+), 5 deletions(-)
> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
> index ed75147..1dd1f0b 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
> @@ -668,11 +668,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
>
> static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
> {
> - while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
> + u32 val;
> +
> + while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
> if (msec-- == 0)
> return false;
> udelay(1000);
> }
> + hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
> +
> return true;
> }
>
Is this a bug fix?
> @@ -711,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
> HDMI_PHY_CONF0_ENTMDS_MASK);
> }
>
> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
> +{
> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
> + HDMI_PHY_CONF0_SPARECTRL_MASK);
> +}
> +
> static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
> {
> hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
> @@ -746,6 +757,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
> u8 val, msec;
> const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
> const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
> + const struct sym_term *sym_term = hdmi->plat_data->sym_term;
>
> if (prep)
> return -EINVAL;
> @@ -815,10 +827,17 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
>
> hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
> hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
> +
> + for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
> + if (hdmi->hdmi_data.video_mode.mpixelclock <=
> + sym_term[i].mpixelclock)
> + break;
> +
> /* RESISTANCE TERM 133Ohm Cfg */
> - hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
> + hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
> /* PREEMP Cgf 0.00 */
> - hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
> + hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
> +
All these seem generic improvements and not rk3288 specific?
> /* TX/CK LVL 10 */
> hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
> /* REMOVE CLK TERM */
> @@ -834,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
> dw_hdmi_phy_gen2_txpwron(hdmi, 1);
> dw_hdmi_phy_gen2_pddq(hdmi, 0);
>
> + if (hdmi->dev_type == RK3288_HDMI)
> + dw_hdmi_phy_enable_spare(hdmi, 1);
> +
> /*Wait for PHY PLL lock */
> msec = 5;
> do {
> @@ -1398,6 +1420,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
> return 0;
> }
>
> +static enum drm_mode_status
> +dw_hdmi_connector_mode_valid(struct drm_connector *connector,
> + struct drm_display_mode *mode)
> +{
> + struct dw_hdmi *hdmi = container_of(connector,
> + struct dw_hdmi, connector);
> + enum drm_mode_status mode_status = MODE_OK;
> +
> + if (hdmi->plat_data->mode_valid)
> + mode_status = hdmi->plat_data->mode_valid(connector, mode);
> +
> + return mode_status;
> +}
> +
This too is disjoint from rk3288 support.
> static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
> *connector)
> {
> @@ -1422,6 +1458,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
>
> static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
> .get_modes = dw_hdmi_connector_get_modes,
> + .mode_valid = dw_hdmi_connector_mode_valid,
> .best_encoder = dw_hdmi_connector_best_encoder,
> };
>
> @@ -1514,6 +1551,8 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
>
> drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
>
> + drm_connector_register(&hdmi->connector);
> +
> return 0;
> }
>
...
Please separate generic dw_hdmi.c improvements from the add rk3288 support.
Regards
ZubairLK
Hi ZubairLK:
thanks for your review.
On 2014年11月13日 21:09, Zubair Lutfullah Kakakhel wrote:
>
> On 13/11/14 12:57, Andy Yan wrote:
>> rk3288 hdmi is compatible with Designware hdmi
>>
>> this patch is depend on patch by Mark Yao Add drm
>> driver for Rockchip Socs
>>
>> see https://lkml.org/lkml/2014/10/8/201
>>
>> Signed-off-by: Andy Yan <[email protected]>
>> Signed-off-by: Yakir Yang <[email protected]>
>>
>> ---
>>
>> Changes in v9:
>> - move some phy configuration to platform driver
>>
>> Changes in v8:
>> - add support for rockchip rk3288 hdmi
>>
>> Changes in v7: None
>> Changes in v6: None
>> Changes in v5: None
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>> drivers/gpu/drm/bridge/dw_hdmi.c | 45 +++-
> This patch looks like it does alot to the dw_hdmi.c as well and not
> just adds support for rk3288..
>
>> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
>> drivers/gpu/drm/rockchip/Kconfig | 10 +
>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 328 ++++++++++++++++++++++++++++
>> drivers/staging/imx-drm/dw_hdmi-imx.c | 8 +
>> include/drm/bridge/dw_hdmi.h | 8 +
>> 7 files changed, 399 insertions(+), 5 deletions(-)
>> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>>
>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>> index ed75147..1dd1f0b 100644
>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>> @@ -668,11 +668,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
>>
>> static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
>> {
>> - while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
>> + u32 val;
>> +
>> + while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
>> if (msec-- == 0)
>> return false;
>> udelay(1000);
>> }
>> + hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
>> +
>> return true;
>> }
>>
> Is this a bug fix?
It seems like a bug fix, I don't know why it works well on imx and
jz4780
without this fix.
HDMI_IN_I2CMPHY_STAT0 is a clear on write (1 to corresponding bit)
status register
to indicate i2c operation of the hdmi phy(i2c transfer done or
err). After one register
of the phy is configured by the i2cm, we should wait for the
i2cmphydone bit set to 1,
than configure the next register, than wait for the i2cmphydone
bit set to 1....But we should
clear the indicate bit by write 1 to the corresponding bit after
the the set to 1, otherwise the bit
will hold on forever, this will give us a wrong signal in the next
wait, and as a result , the phy register can't be configured as we want.
>
>> @@ -711,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
>> HDMI_PHY_CONF0_ENTMDS_MASK);
>> }
>>
>> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
>> +{
>> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
>> + HDMI_PHY_CONF0_SPARECTRL_MASK);
>> +}
>> +
>> static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
>> {
>> hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>> @@ -746,6 +757,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
>> u8 val, msec;
>> const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
>> const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
>> + const struct sym_term *sym_term = hdmi->plat_data->sym_term;
>>
>> if (prep)
>> return -EINVAL;
>> @@ -815,10 +827,17 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
>>
>> hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
>> hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
>> +
>> + for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
>> + if (hdmi->hdmi_data.video_mode.mpixelclock <=
>> + sym_term[i].mpixelclock)
>> + break;
>> +
>> /* RESISTANCE TERM 133Ohm Cfg */
>> - hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
>> + hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
>> /* PREEMP Cgf 0.00 */
>> - hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
>> + hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
>> +
> All these seem generic improvements and not rk3288 specific?
Yes , different board needs different termination vale to get best SI.
Do you mean we should put these in a separate patch?
>
>> /* TX/CK LVL 10 */
>> hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
>> /* REMOVE CLK TERM */
>> @@ -834,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
>> dw_hdmi_phy_gen2_txpwron(hdmi, 1);
>> dw_hdmi_phy_gen2_pddq(hdmi, 0);
>>
>> + if (hdmi->dev_type == RK3288_HDMI)
>> + dw_hdmi_phy_enable_spare(hdmi, 1);
>> +
>> /*Wait for PHY PLL lock */
>> msec = 5;
>> do {
>> @@ -1398,6 +1420,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
>> return 0;
>> }
>>
>> +static enum drm_mode_status
>> +dw_hdmi_connector_mode_valid(struct drm_connector *connector,
>> + struct drm_display_mode *mode)
>> +{
>> + struct dw_hdmi *hdmi = container_of(connector,
>> + struct dw_hdmi, connector);
>> + enum drm_mode_status mode_status = MODE_OK;
>> +
>> + if (hdmi->plat_data->mode_valid)
>> + mode_status = hdmi->plat_data->mode_valid(connector, mode);
>> +
>> + return mode_status;
>> +}
>> +
> This too is disjoint from rk3288 support.
RK3288 can't support all the display mode for it can't give
all the precise clock some display mode needs.
>
>> static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
>> *connector)
>> {
>> @@ -1422,6 +1458,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
>>
>> static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
>> .get_modes = dw_hdmi_connector_get_modes,
>> + .mode_valid = dw_hdmi_connector_mode_valid,
>> .best_encoder = dw_hdmi_connector_best_encoder,
>> };
>>
>> @@ -1514,6 +1551,8 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
>>
>> drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
>>
>> + drm_connector_register(&hdmi->connector);
>> +
>> return 0;
>> }
>>
> ...
>
> Please separate generic dw_hdmi.c improvements from the add rk3288 support.
>
> Regards
> ZubairLK
>
>
>
We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they also have some
lightly differences, such as phy pll configuration, register width(imx hdmi
register is one byte, but rk3288 is 4 bytes width and can only be accessed
by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
support.
To reuse the imx-hdmi driver, we make this patch set:
(1): fix some CodingStyle warning to make checkpatch happy
(2): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
(3): move imx-hdmi to bridge/dw-hdmi, and convert it to a drm_bridge driver
(4): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
Changes in v10:
- split generic dw_hdmi.c improvements from patch#11(add rk3288 support)
- add more display mode support mpll configuration for rk3288
Changes in v9:
- move some phy configuration to platform driver
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
- Add documentation for rockchip dw hdmi
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6:
- rearrange the patch order
- move some modification to patch#6
- refactor register access without reg_shift
- move some modification from patch#5
Changes in v5:
- refactor reg-io-width
Changes in v4:
- fix checkpatch CHECK
- defer probe ddc i2c adapter
Changes in v3:
- split multi register access to one indepent patch
Changes in v2:
- use git format -M to generate these patch
Andy Yan (10):
staging: imx-drm: imx-hdmi: make checkpatch happy
staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
drm: bridge/dw_hdmi:split some phy configuration to platform driver
drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done
dt-bindings: add document for dw_hdmi
drm: bridge/dw_hdmi: add support for multi byte register width access
dt-bindings: Add documentation for rockchip dw hdmi
drm: bridge/dw_hdmi: add rockchip rk3288 support
Yakir Yang (1):
drm: bridge/dw_hdmi: convert dw-hdmi to drm_bridge mode
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 762 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 8 +-
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 274 ++++++++
include/drm/bridge/dw_hdmi.h | 60 ++
13 files changed, 1138 insertions(+), 425 deletions(-)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h
--
1.9.1
CHECK: Alignment should match open parenthesis
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
CHECK: braces {} should be used on all arms of this statement
+ if (hdmi->hdmi_data.video_mode.mdvi)
[...]
+ else {
[...]
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- rearrange the patch order
Changes in v5: None
Changes in v4:
- fix checkpatch CHECK
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 49 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index aaec6b2..79daec4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
}
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+ u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}
static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
- unsigned long pixel_clk)
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
+ __func__, pixel_clk);
return;
}
@@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
u16 coeff_b = (*csc_coeff)[1][i];
u16 coeff_c = (*csc_coeff)[2][i];
- hdmi_writeb(hdmi, coeff_a & 0xff,
- HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_c & 0xff,
- HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}
@@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
- if (hdmi_data->enc_out_format == RGB
- || hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth)
+ if (hdmi_data->enc_out_format == RGB ||
+ hdmi_data->enc_out_format == YCBCR444) {
+ if (!hdmi_data->enc_color_depth) {
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- else if (hdmi_data->enc_color_depth == 8) {
+ } else if (hdmi_data->enc_color_depth == 8) {
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10)
+ } else if (hdmi_data->enc_color_depth == 10) {
color_depth = 5;
- else if (hdmi_data->enc_color_depth == 12)
+ } else if (hdmi_data->enc_color_depth == 12) {
color_depth = 6;
- else if (hdmi_data->enc_color_depth == 16)
+ } else if (hdmi_data->enc_color_depth == 16) {
color_depth = 7;
- else
+ } else {
return;
+ }
} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
if (!hdmi_data->enc_color_depth ||
hdmi_data->enc_color_depth == 8)
@@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
else
return;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
- } else
+ } else {
return;
+ }
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
@@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
@@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
}
static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 8),
- HDMI_PHY_I2CM_DATAO_1_ADDR);
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 0),
- HDMI_PHY_I2CM_DATAO_0_ADDR);
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
- HDMI_PHY_I2CM_OPERATION_ADDR);
+ HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
@@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 1);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
+ HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
@@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
break;
if (i >= ARRAY_SIZE(curr_ctrl)) {
- dev_err(hdmi->dev,
- "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
+ dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
@@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
- (hdmi->vic == 21) || (hdmi->vic == 22) ||
- (hdmi->vic == 2) || (hdmi->vic == 3) ||
- (hdmi->vic == 17) || (hdmi->vic == 18))
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
else
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
- (hdmi->vic == 12) || (hdmi->vic == 13) ||
- (hdmi->vic == 14) || (hdmi->vic == 15) ||
- (hdmi->vic == 25) || (hdmi->vic == 26) ||
- (hdmi->vic == 27) || (hdmi->vic == 28) ||
- (hdmi->vic == 29) || (hdmi->vic == 30) ||
- (hdmi->vic == 35) || (hdmi->vic == 36) ||
- (hdmi->vic == 37) || (hdmi->vic == 38))
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
else
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
@@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
imx_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi)
+ if (hdmi->hdmi_data.video_mode.mdvi) {
dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- else {
+ } else {
dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
/* HDMI Initialization Step E - Configure audio */
@@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
+ HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
@@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
+ &imx_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Product and revision IDs */
dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(hdmi, HDMI_DESIGN_ID),
+ hdmi_readb(hdmi, HDMI_REVISION_ID),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
initialize_hdmi_ih_mutes(hdmi);
--
1.9.1
drm driver may probe before the i2c bus, so the driver should
defer probing until it is available
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4:
- defer probe ddc i2c adapter
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 79daec4..c2b035a 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1611,8 +1611,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- if (!hdmi->ddc)
+ if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
+ of_node_put(ddc_node);
+ return -EPROBE_DEFER;
+ }
of_node_put(ddc_node);
} else {
--
1.9.1
IMX6 and Rockchip RK3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly differences, such as phy pll configuration,
register width, 4K support, clk useage, and the crtc mux configuration
is also platform specific.
To reuse the imx hdmi driver, split the platform specific code out
to dw_hdmi-imx.c.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 217 +++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 255 ++++++++--------------------------
drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++
4 files changed, 322 insertions(+), 195 deletions(-)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 582c438..809027d 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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) += imx-hdmi.o dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
new file mode 100644
index 0000000..0db978e
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,217 @@
+/* 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/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#include "imx-drm.h"
+#include "imx-hdmi.h"
+
+struct imx_hdmi_priv {
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+ struct regmap *regmap;
+};
+
+static const struct 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 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 int imx_hdmi_parse_dt(struct imx_hdmi_priv *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);
+ }
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
+ return PTR_ERR(hdmi->isfr_clk);
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->iahb_clk);
+ }
+
+ return 0;
+}
+
+static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+{
+ struct imx_hdmi_priv *hdmi;
+ int ret;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return ERR_PTR(-ENOMEM);
+ hdmi->dev = &pdev->dev;
+
+ ret = imx_hdmi_parse_dt(hdmi);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return hdmi;
+}
+
+static void imx_hdmi_imx_exit(void *priv)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+
+ clk_disable_unprepare(hdmi->iahb_clk);
+}
+
+static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ 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 imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .dev_type = IMX6Q_HDMI,
+};
+
+static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .dev_type = IMX6DL_HDMI,
+};
+
+static const struct of_device_id imx_hdmi_imx_ids[] = {
+ { .compatible = "fsl,imx6q-hdmi",
+ .data = &imx6q_hdmi_drv_data
+ }, {
+ .compatible = "fsl,imx6dl-hdmi",
+ .data = &imx6dl_hdmi_drv_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+
+static int imx_hdmi_imx_probe(struct platform_device *pdev)
+{
+ const struct imx_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ plat_data = match->data;
+
+ return imx_hdmi_platform_register(pdev, plat_data);
+}
+
+static int imx_hdmi_imx_remove(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_unregister(pdev);
+}
+
+static struct platform_driver imx_hdmi_imx_platform_driver = {
+ .probe = imx_hdmi_imx_probe,
+ .remove = imx_hdmi_imx_remove,
+ .driver = {
+ .name = "dwhdmi-imx",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_hdmi_imx_ids,
+ },
+};
+
+module_platform_driver(imx_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c2b035a..c7e5f12 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,21 +16,16 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/clk.h>
#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.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 <video/imx-ipu-v3.h>
#include "imx-hdmi.h"
-#include "imx-drm.h"
#define HDMI_EDID_LEN 512
@@ -54,11 +49,6 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x0000, 0x0000, 0x0000 },
{ 0x0000, 0x2000, 0x0000, 0x0000 },
@@ -117,10 +107,10 @@ struct imx_hdmi {
enum imx_hdmi_devtype dev_type;
struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
struct hdmi_data_info hdmi_data;
+ const struct imx_hdmi_plat_data *plat_data;
+ void *priv;
int vic;
u8 edid[HDMI_EDID_LEN];
@@ -137,13 +127,6 @@ struct imx_hdmi {
int ratio;
};
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
@@ -728,76 +711,13 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
- {
- 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 },
- },
- }
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
- /* 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 int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
u8 val, msec;
+ const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
+ const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
if (prep)
return -EINVAL;
@@ -843,27 +763,27 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
- for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config[i].mpixelclock)
+ mpll_cfg[i].mpixelclock)
break;
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);
- for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl[i].mpixelclock)
+ curr_ctr[i].mpixelclock)
break;
- if (i >= ARRAY_SIZE(curr_ctrl)) {
+ if (curr_ctr[i].mpixelclock == (~0UL)) {
dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
/* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10);
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
@@ -1453,21 +1373,29 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+
+ if (hdmi->plat_data->encoder_prepare)
+ hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
static void imx_hdmi_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);
- imx_hdmi_set_ipu_di_mux(hdmi, mux);
+ if (hdmi->plat_data->encoder_commit)
+ hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
imx_hdmi_poweron(hdmi);
}
+void imx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_drm_encoder_destroy,
+ .destroy = drm_encoder_cleanup,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1483,7 +1411,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_drm_connector_destroy,
+ .destroy = imx_hdmi_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1539,12 +1467,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
- int ret;
+ struct drm_encoder *encoder = &hdmi->encoder;
+ struct device *dev = hdmi->dev;
- ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
- hdmi->dev->of_node);
- if (ret)
- return ret;
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
@@ -1564,50 +1490,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- .driver_data = IMX6Q_HDMI,
- }, {
- .name = "imx6dl-hdmi",
- .driver_data = IMX6DL_HDMI,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
- struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
-
- hdmi->dev_type = device_id->driver_data;
- }
-
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1637,40 +1529,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap))
- return PTR_ERR(hdmi->regmap);
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- ret = PTR_ERR(hdmi->isfr_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI isfr clk: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- ret = PTR_ERR(hdmi->iahb_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI iahb clk: %d\n", ret);
- goto err_isfr;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- goto err_isfr;
- }
-
+ if (hdmi->plat_data->setup)
+ hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1698,11 +1558,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ret = imx_hdmi_fb_registered(hdmi);
if (ret)
- goto err_iahb;
+ return ret;
ret = imx_hdmi_register(drm, hdmi);
if (ret)
- goto err_iahb;
+ return ret;
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
@@ -1710,13 +1570,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, hdmi);
return 0;
-
-err_iahb:
- clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
- clk_disable_unprepare(hdmi->isfr_clk);
-
- return ret;
}
static void imx_hdmi_unbind(struct device *dev, struct device *master,
@@ -1729,9 +1582,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
+ if (hdmi->plat_data->exit)
+ hdmi->plat_data->exit(hdmi->priv);
i2c_put_adapter(hdmi->ddc);
}
@@ -1751,17 +1603,32 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver imx_hdmi_driver = {
- .probe = imx_hdmi_platform_probe,
- .remove = imx_hdmi_platform_remove,
- .driver = {
- .name = "imx-hdmi",
- .owner = THIS_MODULE,
- .of_match_table = imx_hdmi_dt_ids,
- },
-};
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data)
+{
+ struct imx_hdmi *hdmi;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
-module_platform_driver(imx_hdmi_driver);
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+
+ platform_set_drvdata(pdev, hdmi);
+
+ return imx_hdmi_platform_probe(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+
+int imx_hdmi_platform_unregister(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_remove(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b6776..e67d60d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,47 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum imx_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct imx_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ enum imx_hdmi_devtype dev_type;
+
+};
+
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data);
+int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi driver out
to drm/bridge and rename imx-hdmi to dw_hdmi
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2:
- use git format -M to generate these patch
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 281 +++++++++++----------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 46 +---
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 70 ++---
include/drm/bridge/dw_hdmi.h | 57 +++++
8 files changed, 243 insertions(+), 220 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (83%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (97%)
create mode 100644 include/drm/bridge/dw_hdmi.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..26162ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,3 +3,8 @@ config DRM_PTN3460
depends on DRM
select DRM_KMS_HELPER
---help---
+
+config DRM_DW_HDMI
+ bool "Synopsys DesignWare High-Definition Multimedia Interface"
+ depends on DRM
+ select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..d8a8cfd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
similarity index 83%
rename from drivers/staging/imx-drm/imx-hdmi.c
rename to drivers/gpu/drm/bridge/dw_hdmi.c
index c7e5f12..e9f0dfe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -6,8 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
+ * Designware High-Definition Multimedia Interface (HDMI) driver
*
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
@@ -24,8 +23,9 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
-#include "imx-hdmi.h"
+#include "dw_hdmi.h"
#define HDMI_EDID_LEN 512
@@ -101,15 +101,15 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
-struct imx_hdmi {
+struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
- enum imx_hdmi_devtype dev_type;
+ enum dw_hdmi_devtype dev_type;
struct device *dev;
struct hdmi_data_info hdmi_data;
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
void *priv;
int vic;
@@ -127,17 +127,17 @@ struct imx_hdmi {
int ratio;
};
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
}
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
return readb(hdmi->regs + offset);
}
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;
@@ -145,13 +145,13 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
unsigned int value)
{
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
@@ -162,7 +162,7 @@ static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
@@ -309,7 +309,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -333,12 +333,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
hdmi_regenerate_cts(hdmi, clk_cts);
}
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, 74250000);
}
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
@@ -350,7 +350,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
* pin{31~24} <==> G[7:0]
* pin{15~8} <==> B[7:0]
*/
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
{
int color_format = 0;
u8 val;
@@ -406,12 +406,12 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
}
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
return 0;
@@ -421,7 +421,7 @@ static int is_color_space_decimation(struct imx_hdmi *hdmi)
return 0;
}
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
return 0;
@@ -431,7 +431,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
return 0;
}
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
unsigned i;
@@ -472,7 +472,7 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
HDMI_CSC_SCALE);
}
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
{
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
@@ -500,7 +500,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
HDMI_CSC_SCALE);
- imx_hdmi_update_csc_coeffs(hdmi);
+ dw_hdmi_update_csc_coeffs(hdmi);
}
/*
@@ -508,7 +508,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
* for example, if input is YCC422 mode or repeater is used,
* data should be repacked this module can be bypassed.
*/
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
{
unsigned int color_depth = 0;
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -605,40 +605,40 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_CONF);
}
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
@@ -648,7 +648,7 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -662,56 +662,56 @@ static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
}
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_ENTMDS_OFFSET,
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
}
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
}
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
HDMI_PHY_CONF0_SELDATAENPOL_MASK);
}
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDIPIF_OFFSET,
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
@@ -746,10 +746,10 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
/* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
/* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
/* PHY reset */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
@@ -796,15 +796,15 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- imx_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_power(hdmi, 1);
/* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 1);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
/* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(hdmi, 1);
- imx_hdmi_phy_gen2_pddq(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
/*Wait for PHY PLL lock */
msec = 5;
@@ -825,7 +825,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
return 0;
}
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
bool cscon = false;
@@ -836,10 +836,10 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
- imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
- imx_hdmi_phy_sel_interface_control(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+ dw_hdmi_phy_sel_interface_control(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
@@ -851,7 +851,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
return 0;
}
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{
u8 de;
@@ -870,7 +870,7 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
{
u8 val, pix_fmt, under_scan;
u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
@@ -964,7 +964,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
}
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
u8 inv_val;
@@ -1048,19 +1048,19 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
{
if (!hdmi->phy_enabled)
return;
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
u8 clkdis;
@@ -1089,13 +1089,13 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
}
}
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
int count;
u8 val;
@@ -1113,19 +1113,19 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
HDMI_IH_MUTE_FC_STAT2);
}
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
{
int ret;
@@ -1177,12 +1177,12 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */
- ret = imx_hdmi_phy_init(hdmi);
+ ret = dw_hdmi_phy_init(hdmi);
if (ret)
return ret;
/* HDMI Initialization Step B.3 */
- imx_hdmi_enable_video_path(hdmi);
+ dw_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
if (hdmi->hdmi_data.video_mode.mdvi) {
@@ -1203,7 +1203,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_video_sample(hdmi);
hdmi_tx_hdcp_config(hdmi);
- imx_hdmi_clear_overflow(hdmi);
+ dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
hdmi_enable_overflow_interrupts(hdmi);
@@ -1211,7 +1211,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);
@@ -1229,7 +1229,7 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
return 0;
}
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{
u8 ih_mute;
@@ -1281,29 +1281,29 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
}
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{
- imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+ dw_hdmi_setup(hdmi, &hdmi->previous_mode);
}
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
- imx_hdmi_phy_disable(hdmi);
+ dw_hdmi_phy_disable(hdmi);
}
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
struct edid *edid;
int ret;
@@ -1326,102 +1326,102 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return &hdmi->encoder;
}
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_setup(hdmi, mode);
+ dw_hdmi_setup(hdmi, mode);
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
}
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (mode)
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
else
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
if (hdmi->plat_data->encoder_prepare)
hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (hdmi->plat_data->encoder_commit)
hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-void imx_hdmi_connector_destroy(struct drm_connector *connector)
+void dw_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .dpms = imx_hdmi_encoder_dpms,
- .prepare = imx_hdmi_encoder_prepare,
- .commit = imx_hdmi_encoder_commit,
- .mode_set = imx_hdmi_encoder_mode_set,
- .mode_fixup = imx_hdmi_encoder_mode_fixup,
- .disable = imx_hdmi_encoder_disable,
+static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
+ .dpms = dw_hdmi_encoder_dpms,
+ .prepare = dw_hdmi_encoder_prepare,
+ .commit = dw_hdmi_encoder_commit,
+ .mode_set = dw_hdmi_encoder_mode_set,
+ .mode_fixup = dw_hdmi_encoder_mode_fixup,
+ .disable = dw_hdmi_encoder_disable,
};
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- .get_modes = imx_hdmi_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+ .get_modes = dw_hdmi_connector_get_modes,
+ .best_encoder = dw_hdmi_connector_best_encoder,
};
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1431,9 +1431,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
@@ -1447,14 +1447,14 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
HDMI_PHY_POL0);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
}
drm_helper_hpd_irq_event(hdmi->connector.dev);
}
@@ -1465,7 +1465,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = &hdmi->encoder;
struct device *dev = hdmi->dev;
@@ -1474,13 +1474,13 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ &dw_hdmi_connector_helper_funcs);
+ drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1490,10 +1490,10 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
@@ -1518,8 +1518,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
+ ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
return ret;
@@ -1556,11 +1556,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- ret = imx_hdmi_fb_registered(hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
return ret;
- ret = imx_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_register(drm, hdmi);
if (ret)
return ret;
@@ -1572,10 +1572,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
+static void dw_hdmi_unbind(struct device *dev, struct device *master,
void *data)
{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
@@ -1588,25 +1588,25 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
}
static const struct component_ops hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
+ .bind = dw_hdmi_bind,
+ .unbind = dw_hdmi_unbind,
};
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int dw_hdmi_platform_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &hdmi_ops);
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static int dw_hdmi_platform_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &hdmi_ops);
return 0;
}
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data)
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
{
- struct imx_hdmi *hdmi;
+ struct dw_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1620,17 +1620,18 @@ int imx_hdmi_platform_register(struct platform_device *pdev,
platform_set_drvdata(pdev, hdmi);
- return imx_hdmi_platform_probe(pdev);
+ return dw_hdmi_platform_probe(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-int imx_hdmi_platform_unregister(struct platform_device *pdev)
+int dw_hdmi_platform_unregister(struct platform_device *pdev)
{
- return imx_hdmi_platform_remove(pdev);
+ return dw_hdmi_platform_remove(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
similarity index 97%
rename from drivers/staging/imx-drm/imx-hdmi.h
rename to drivers/gpu/drm/bridge/dw_hdmi.h
index e67d60d..b8412a9 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -7,8 +7,8 @@
* (at your option) any later version.
*/
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
+#ifndef __DW_HDMI__
+#define __DW_HDMI__
/* Identification Registers */
#define HDMI_DESIGN_ID 0x0000
@@ -1030,46 +1030,4 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-struct imx_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
- const struct mpll_config *mpll_cfg;
- const struct curr_ctrl *cur_ctr;
- enum imx_hdmi_devtype dev_type;
-
-};
-
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data);
-int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index ab31848..560e1d3 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -50,5 +50,6 @@ config DRM_IMX_IPUV3
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
depends on DRM_IMX
+ select DRM_DW_HDMI
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 809027d..f3ecd89 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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 dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 0db978e..4b48ea6 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -10,14 +10,14 @@
#include <linux/platform_device.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 <linux/clk.h>
#include "imx-drm.h"
-#include "imx-hdmi.h"
-struct imx_hdmi_priv {
+struct imx_hdmi {
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -69,7 +69,7 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
-static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
+static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
@@ -94,9 +94,9 @@ static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
return 0;
}
-static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+static void *dw_hdmi_imx_setup(struct platform_device *pdev)
{
- struct imx_hdmi_priv *hdmi;
+ struct imx_hdmi *hdmi;
int ret;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -104,7 +104,7 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return ERR_PTR(-ENOMEM);
hdmi->dev = &pdev->dev;
- ret = imx_hdmi_parse_dt(hdmi);
+ ret = dw_hdmi_parse_dt(hdmi);
if (ret < 0)
return ERR_PTR(ret);
ret = clk_prepare_enable(hdmi->isfr_clk);
@@ -124,18 +124,18 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return hdmi;
}
-static void imx_hdmi_imx_exit(void *priv)
+static void dw_hdmi_imx_exit(void *priv)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
clk_disable_unprepare(hdmi->isfr_clk);
clk_disable_unprepare(hdmi->iahb_clk);
}
-static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
@@ -143,33 +143,33 @@ static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
-static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6Q_HDMI,
};
-static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.dev_type = IMX6DL_HDMI,
};
-static const struct of_device_id imx_hdmi_imx_ids[] = {
+static const struct of_device_id dw_hdmi_imx_ids[] = {
{ .compatible = "fsl,imx6q-hdmi",
.data = &imx6q_hdmi_drv_data
}, {
@@ -178,38 +178,38 @@ static const struct of_device_id imx_hdmi_imx_ids[] = {
},
{},
};
-MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int imx_hdmi_imx_probe(struct platform_device *pdev)
+static int dw_hdmi_imx_probe(struct platform_device *pdev)
{
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
if (!pdev->dev.of_node)
return -ENODEV;
- match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ match = of_match_node(dw_hdmi_imx_ids, pdev->dev.of_node);
plat_data = match->data;
- return imx_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_platform_register(pdev, plat_data);
}
-static int imx_hdmi_imx_remove(struct platform_device *pdev)
+static int dw_hdmi_imx_remove(struct platform_device *pdev)
{
- return imx_hdmi_platform_unregister(pdev);
+ return dw_hdmi_platform_unregister(pdev);
}
-static struct platform_driver imx_hdmi_imx_platform_driver = {
- .probe = imx_hdmi_imx_probe,
- .remove = imx_hdmi_imx_remove,
+static struct platform_driver dw_hdmi_imx_platform_driver = {
+ .probe = dw_hdmi_imx_probe,
+ .remove = dw_hdmi_imx_remove,
.driver = {
.name = "dwhdmi-imx",
.owner = THIS_MODULE,
- .of_match_table = imx_hdmi_imx_ids,
+ .of_match_table = dw_hdmi_imx_ids,
},
};
-module_platform_driver(imx_hdmi_imx_platform_driver);
+module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..6683b63
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __DW_HDMI_H__
+#define __DW_HDMI_H__
+
+#include <drm/drmP.h>
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum dw_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct dw_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ enum dw_hdmi_devtype dev_type;
+
+};
+
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data);
+int dw_hdmi_platform_unregister(struct platform_device *pdev);
+#endif /* __IMX_HDMI_H__ */
--
1.9.1
hdmi phy clock symbol and transmission termination value
can adjust platform specific to get the best SI
also add mode_valid interface for some platform may not support
all the display mode
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10:
- split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 29 +++++++++++++++++++++++++++--
drivers/staging/imx-drm/dw_hdmi-imx.c | 10 +++++++++-
include/drm/bridge/dw_hdmi.h | 7 +++++++
3 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index e9f0dfe..05e7156 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -718,6 +718,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
u8 val, msec;
const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
+ const struct sym_term *sym_term = hdmi->plat_data->sym_term;
if (prep)
return -EINVAL;
@@ -787,10 +788,17 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+
+ for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ sym_term[i].mpixelclock)
+ break;
+
/* RESISTANCE TERM 133Ohm Cfg */
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
/* PREEMP Cgf 0.00 */
- hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
+
/* TX/CK LVL 10 */
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
/* REMOVE CLK TERM */
@@ -1326,6 +1334,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = container_of(connector,
+ struct dw_hdmi, connector);
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (hdmi->plat_data->mode_valid)
+ mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1416,6 +1438,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
+ .mode_valid = dw_hdmi_connector_mode_valid,
.best_encoder = dw_hdmi_connector_best_encoder,
};
@@ -1487,6 +1510,8 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+ drm_connector_register(&hdmi->connector);
+
return 0;
}
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 4b48ea6..d693051 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -69,7 +69,13 @@ static const struct curr_ctrl imx_cur_ctr[] = {
}
};
-static int dw_hdmi_parse_dt(struct imx_hdmi *hdmi)
+static const struct 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;
@@ -156,6 +162,7 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
.encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
+ .sym_term = imx_sym_term,
.dev_type = IMX6Q_HDMI,
};
@@ -166,6 +173,7 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
.encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
+ .sym_term = imx_sym_term,
.dev_type = IMX6DL_HDMI,
};
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 6683b63..1688ec9 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -37,6 +37,12 @@ struct curr_ctrl {
u16 curr[RES_MAX];
};
+struct sym_term {
+ unsigned long mpixelclock;
+ u16 sym_ctr; /*clock symbol and transmitter control*/
+ u16 term; /*transmission termination value*/
+};
+
struct dw_hdmi_plat_data {
void * (*setup)(struct platform_device *pdev);
void (*exit)(void *priv);
@@ -47,6 +53,7 @@ struct dw_hdmi_plat_data {
struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
+ const struct sym_term *sym_term;
enum dw_hdmi_devtype dev_type;
};
--
1.9.1
HDMI_IH_I2CMPHY_STAT0 is a clear on write register, which indicates i2cm
operation status(i2c transfer done or error), every hdmi phy register
configuration must check this register to make sure the configuration
has complete. But the indication bit should be cleared after check, otherwise
the corresponding bit will hold on forever, this may give a wrong signal for
next check.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 05e7156..4f9a5c0 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -640,11 +640,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ u32 val;
+
+ while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
udelay(1000);
}
+ hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
return true;
}
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
new file mode 100644
index 0000000..0558442
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
@@ -0,0 +1,40 @@
+DesignWare HDMI bridge bindings
+
+Required properities:
+- compatible: platform specific such as:
+ * "fsl,imx6q-hdmi"
+ * "fsl,imx6dl-hdmi"
+ * "rockchip,rk3288-dw-hdmi"
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- interrupts: The HDMI interrupt number
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+
+Example:
+ hdmi: hdmi@0120000 {
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
--
1.9.1
On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width accesses (writeb,
readb) generate an imprecise external abort.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4: None
Changes in v3:
- split multi register access to one indepent patch
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 57 +++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 4f9a5c0..d7bf46d 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -101,6 +101,11 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
+union dw_reg_ptr {
+ u32 __iomem *p32;
+ u8 __iomem *p8;
+};
+
struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
@@ -121,20 +126,43 @@ struct dw_hdmi {
struct regmap *regmap;
struct i2c_adapter *ddc;
- void __iomem *regs;
+ union dw_reg_ptr regs;
unsigned int sample_rate;
int ratio;
+
+ void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+ u8 (*read)(struct dw_hdmi *hdmi, int offset);
};
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writel(val, hdmi->regs.p32 + offset);
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs.p32 + offset);
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writeb(val, hdmi->regs.p8 + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return readb(hdmi->regs.p8 + offset);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(hdmi, val, offset);
}
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi, offset);
}
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
@@ -1528,6 +1556,23 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
struct device_node *ddc_node;
struct resource *iores;
int ret, irq;
+ u32 val = 1;
+
+ of_property_read_u32(np, "reg-io-width", &val);
+
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ break;
+ case 1:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return -EINVAL;
+ }
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
@@ -1554,9 +1599,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
+ hdmi->regs.p32 = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs.p32))
+ return PTR_ERR(hdmi->regs.p32);
if (hdmi->plat_data->setup)
hdmi->priv = hdmi->plat_data->setup(pdev);
--
1.9.1
From: Yakir Yang <[email protected]>
keep the connector & birdge in dw_hdmi.c, handle encoder
in dw_hdmi-imx.c, as most of the encoder operation are
platform specific such as crtc select and panel format
set
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification from patch#5
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 228 +++++++++++++++-------------------
drivers/staging/imx-drm/dw_hdmi-imx.c | 143 ++++++++++++++-------
include/drm/bridge/dw_hdmi.h | 13 +-
3 files changed, 198 insertions(+), 186 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index d7bf46d..a2876fe 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -11,7 +11,6 @@
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
-#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -108,7 +107,8 @@ union dw_reg_ptr {
struct dw_hdmi {
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
enum dw_hdmi_devtype dev_type;
struct device *dev;
@@ -1331,6 +1331,50 @@ static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
dw_hdmi_phy_disable(hdmi);
}
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_setup(hdmi, mode);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweroff(hdmi);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweron(hdmi);
+}
+
+static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge)
+{
+ drm_bridge_cleanup(bridge);
+ kfree(bridge);
+}
+
+static void dw_hdmi_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
@@ -1386,60 +1430,7 @@ static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
- return &hdmi->encoder;
-}
-
-static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_setup(hdmi, mode);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (mode)
- dw_hdmi_poweroff(hdmi);
- else
- dw_hdmi_poweron(hdmi);
-}
-
-static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_poweroff(hdmi);
-
- if (hdmi->plat_data->encoder_prepare)
- hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
-}
-
-static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (hdmi->plat_data->encoder_commit)
- hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
-
- dw_hdmi_poweron(hdmi);
+ return hdmi->encoder;
}
void dw_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1448,19 +1439,6 @@ void dw_hdmi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
- .dpms = dw_hdmi_encoder_dpms,
- .prepare = dw_hdmi_encoder_prepare,
- .commit = dw_hdmi_encoder_commit,
- .mode_set = dw_hdmi_encoder_mode_set,
- .mode_fixup = dw_hdmi_encoder_mode_fixup,
- .disable = dw_hdmi_encoder_disable,
-};
-
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1474,6 +1452,16 @@ static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.best_encoder = dw_hdmi_connector_best_encoder,
};
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .enable = dw_hdmi_bridge_enable,
+ .disable = dw_hdmi_bridge_disable,
+ .pre_enable = dw_hdmi_bridge_nope,
+ .post_disable = dw_hdmi_bridge_nope,
+ .mode_set = dw_hdmi_bridge_mode_set,
+ .mode_fixup = dw_hdmi_bridge_mode_fixup,
+ .destroy = dw_hdmi_bridge_destroy,
+};
+
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
@@ -1522,42 +1510,66 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
- struct drm_encoder *encoder = &hdmi->encoder;
- struct device *dev = hdmi->dev;
+ struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_bridge *bridge;
+ int ret;
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("Failed to allocate drm bridge\n");
+ return -ENOMEM;
+ }
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ hdmi->bridge = bridge;
+ bridge->driver_private = hdmi;
- drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
- hdmi->connector.encoder = &hdmi->encoder;
+ hdmi->connector.encoder = encoder;
- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
drm_connector_register(&hdmi->connector);
return 0;
}
-static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct resource *iores;
+ struct dw_hdmi *hdmi;
int ret, irq;
u32 val = 1;
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+ hdmi->encoder = encoder;
+
of_property_read_u32(np, "reg-io-width", &val);
switch (val) {
@@ -1603,8 +1615,6 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs.p32))
return PTR_ERR(hdmi->regs.p32);
- if (hdmi->plat_data->setup)
- hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1645,9 +1655,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-static void dw_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1655,57 +1665,15 @@ static void dw_hdmi_unbind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
- if (hdmi->plat_data->exit)
- hdmi->plat_data->exit(hdmi->priv);
- i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
- .bind = dw_hdmi_bind,
- .unbind = dw_hdmi_unbind,
-};
-
-static int dw_hdmi_platform_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int dw_hdmi_platform_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &hdmi_ops);
- return 0;
-}
-
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data)
-{
- struct dw_hdmi *hdmi;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->plat_data = plat_data;
- hdmi->dev = &pdev->dev;
- hdmi->dev_type = plat_data->dev_type;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
+ hdmi->encoder->funcs->destroy(hdmi->encoder);
- platform_set_drvdata(pdev, hdmi);
-
- return dw_hdmi_platform_probe(pdev);
-}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-
-int dw_hdmi_platform_unregister(struct platform_device *pdev)
-{
- return dw_hdmi_platform_remove(pdev);
+ i2c_put_adapter(hdmi->ddc);
}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index d693051..01c7265 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -8,12 +8,19 @@
*/
#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 <linux/clk.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 "imx-drm.h"
@@ -22,6 +29,7 @@ struct imx_hdmi {
struct clk *isfr_clk;
struct clk *iahb_clk;
struct regmap *regmap;
+ struct drm_encoder encoder;
};
static const struct mpll_config imx_mpll_cfg[] = {
@@ -100,48 +108,26 @@ static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
return 0;
}
-static void *dw_hdmi_imx_setup(struct platform_device *pdev)
+static void dw_hdmi_imx_disable(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi;
- int ret;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return ERR_PTR(-ENOMEM);
- hdmi->dev = &pdev->dev;
-
- ret = dw_hdmi_parse_dt(hdmi);
- if (ret < 0)
- return ERR_PTR(ret);
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return hdmi;
}
-static void dw_hdmi_imx_exit(void *priv)
+static bool dw_hdmi_imx_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
-
- clk_disable_unprepare(hdmi->isfr_clk);
+ return true;
+}
- clk_disable_unprepare(hdmi->iahb_clk);
+static void dw_hdmi_imx_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
}
-static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
+ 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,
@@ -149,17 +135,24 @@ static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_prepare(struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_imx_mode_fixup,
+ .mode_set = dw_hdmi_imx_mode_set,
+ .prepare = dw_hdmi_imx_prepare,
+ .commit = dw_hdmi_imx_commit,
+ .disable = dw_hdmi_imx_disable,
+};
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.sym_term = imx_sym_term,
@@ -167,10 +160,6 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
};
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.sym_term = imx_sym_term,
@@ -188,23 +177,82 @@ static const struct of_device_id dw_hdmi_imx_ids[] = {
};
MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int dw_hdmi_imx_probe(struct platform_device *pdev)
+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;
+ 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_ids, pdev->dev.of_node);
plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = dw_hdmi_imx_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
- return dw_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+ clk_disable_unprepare(hdmi->iahb_clk);
+
+ 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)
{
- return dw_hdmi_platform_unregister(pdev);
+ component_del(&pdev->dev, &dw_hdmi_imx_ops);
+
+ return 0;
}
static struct platform_driver dw_hdmi_imx_platform_driver = {
@@ -220,6 +268,7 @@ static struct platform_driver dw_hdmi_imx_platform_driver = {
module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 1688ec9..5a88145 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -44,21 +44,16 @@ struct sym_term {
};
struct dw_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
const struct sym_term *sym_term;
enum dw_hdmi_devtype dev_type;
-
};
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data);
-int dw_hdmi_platform_unregister(struct platform_device *pdev);
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10: None
Changes in v9: None
Changes in v8:
- Add documentation for rockchip dw hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
new file mode 100644
index 0000000..6ea6764
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
@@ -0,0 +1,43 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks: from common clock binding: handle to hdmi clock.
+- clock-names: should be "clk" "hdcp_clk"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt. For
+ vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+ rk3288 platform
+
+Example:
+hdmi: hdmi@ff980000 {
+ compatible = "rockchip,rk3288-dw-hdmi";
+ reg = <0xff980000 0x20000>;
+ reg-io-width = <4>;
+ ddc-i2c-bus = <&i2c5>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+ clock-names = "clk", "hdcp_clk";
+ status = "disabled";
+ ports {
+ hdmi_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ hdmi_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_hdmi>;
+ };
+ hdmi_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_hdmi>;
+ };
+ };
+ };
+};
--
1.9.1
Rockchip RK3288 hdmi is compatible with dw_hdmi
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v10:
- add more display mode support mpll configuration for rk3288
Changes in v9:
- move some phy configuration to platform driver
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi.h | 1 +
6 files changed, 379 insertions(+), 2 deletions(-)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index a2876fe..1dd1f0b 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_ENTMDS_MASK);
}
+static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SPARECTRL_OFFSET,
+ HDMI_PHY_CONF0_SPARECTRL_MASK);
+}
+
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
@@ -846,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
+ if (hdmi->dev_type == RK3288_HDMI)
+ dw_hdmi_phy_enable_spare(hdmi, 1);
+
/*Wait for PHY PLL lock */
msec = 5;
do {
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
index b8412a9..30a6b28 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -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,
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0ff6682..06371ae 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -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
+ bool "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.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index b3a5193..347e65c 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,5 +4,5 @@
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchip_drm_gem.o rockchip_drm_vop.o
-
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 0000000..16cad75
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,355 @@
+/*
+ * 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 <linux/clk.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 clk *clk;
+ struct clk *hdcp_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+
+static const struct 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 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 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);
+ }
+
+ hdmi->clk = devm_clk_get(hdmi->dev, "clk");
+ if (IS_ERR(hdmi->clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI clk\n");
+ return PTR_ERR(hdmi->clk);
+ }
+
+ hdmi->hdcp_clk = devm_clk_get(hdmi->dev, "hdcp_clk");
+ if (IS_ERR(hdmi->hdcp_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI hdcp clk\n");
+ return PTR_ERR(hdmi->hdcp_clk);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct 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_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_rockchip_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_rockchip_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void dw_hdmi_rockchip_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_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_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_rockchip_mode_fixup,
+ .mode_set = dw_hdmi_rockchip_mode_set,
+ .prepare = dw_hdmi_rockchip_prepare,
+ .commit = dw_hdmi_rockchip_commit,
+ .disable = dw_hdmi_rockchip_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_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;
+ 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_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = rockchip_hdmi_parse_dt(hdmi);
+ if (ret) {
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdcp_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI hdcp clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rockchip_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->clk);
+ clk_disable_unprepare(hdmi->hdcp_clk);
+
+ 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",
+ .owner = THIS_MODULE,
+ .of_match_table = dw_hdmi_rockchip_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 5a88145..b3ed764 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,7 @@ enum {
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
+ RK3288_HDMI,
};
struct mpll_config {
--
1.9.1
Hi Andy,
Nice work on this patch series. Its getting better and better :).
On 14/11/14 03:27, Andy Yan wrote:
> hdmi phy clock symbol and transmission termination value
> can adjust platform specific to get the best SI
^Is this signal integrity?
Are these two disjoint features in separate patches?
>
> also add mode_valid interface for some platform may not support
> all the display mode
Sounds like another separate patch to me. :)
Also, This series is becoming quite large. With major changes and fixes mixed together.
Patch 3 splits imx-drm.
Patch 4 moves dw-drm out of imx-drm folder.
Patch 7 adds binding
Patch 9 converts to drm bridge.
Can these be placed together easily?
And in the start. i.e. patch 1, 2, 3, 4,
Then all fixes etc can come afterwards?
It helps when checking histories later as to how a driver was made and how fixes happened.
Especially when file moves happen..
Cheers,
ZubairLK
>
> Signed-off-by: Andy Yan <[email protected]>
>
> ---
>
> Changes in v10:
> - split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
>
> Changes in v9: None
> Changes in v8: None
> Changes in v7: None
> Changes in v6: None
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> drivers/gpu/drm/bridge/dw_hdmi.c | 29 +++++++++++++++++++++++++++--
> drivers/staging/imx-drm/dw_hdmi-imx.c | 10 +++++++++-
> include/drm/bridge/dw_hdmi.h | 7 +++++++
> 3 files changed, 43 insertions(+), 3 deletions(-)
>
Hi Andy
On 14/11/14 03:31, Andy Yan wrote:
> Rockchip RK3288 hdmi is compatible with dw_hdmi
>
> Signed-off-by: Andy Yan <[email protected]>
>
> ---
>
> Changes in v10:
> - add more display mode support mpll configuration for rk3288
>
> Changes in v9:
> - move some phy configuration to platform driver
>
> Changes in v8: None
> Changes in v7: None
> Changes in v6: None
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
> drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
> drivers/gpu/drm/rockchip/Kconfig | 10 +
> drivers/gpu/drm/rockchip/Makefile | 2 +-
> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
> include/drm/bridge/dw_hdmi.h | 1 +
> 6 files changed, 379 insertions(+), 2 deletions(-)
> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
> index a2876fe..1dd1f0b 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
> @@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
> HDMI_PHY_CONF0_ENTMDS_MASK);
> }
>
> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
> +{
> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
> + HDMI_PHY_CONF0_SPARECTRL_MASK);
> +}
> +
What does enable spare do? Can other future SoCs use it?
This looks like DW specific. And can be a separate commit that adds a feature to the dw hdmi driver.
Thanks
ZubairLK
> static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
> {
> hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
> @@ -846,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
> dw_hdmi_phy_gen2_txpwron(hdmi, 1);
> dw_hdmi_phy_gen2_pddq(hdmi, 0);
>
> + if (hdmi->dev_type == RK3288_HDMI)
> + dw_hdmi_phy_enable_spare(hdmi, 1);
> +
> /*Wait for PHY PLL lock */
> msec = 5;
> do {
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
> index b8412a9..30a6b28 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.h
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.h
> @@ -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,
Cheers,
ZubairLK
On 2014年11月14日 18:23, Zubair Lutfullah Kakakhel wrote:
> Hi Andy
>
> On 14/11/14 03:31, Andy Yan wrote:
>> Rockchip RK3288 hdmi is compatible with dw_hdmi
>>
>> Signed-off-by: Andy Yan <[email protected]>
>>
>> ---
>>
>> Changes in v10:
>> - add more display mode support mpll configuration for rk3288
>>
>> Changes in v9:
>> - move some phy configuration to platform driver
>>
>> Changes in v8: None
>> Changes in v7: None
>> Changes in v6: None
>> Changes in v5: None
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>> drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
>> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
>> drivers/gpu/drm/rockchip/Kconfig | 10 +
>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
>> include/drm/bridge/dw_hdmi.h | 1 +
>> 6 files changed, 379 insertions(+), 2 deletions(-)
>> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>>
>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>> index a2876fe..1dd1f0b 100644
>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>> @@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
>> HDMI_PHY_CONF0_ENTMDS_MASK);
>> }
>>
>> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
>> +{
>> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
>> + HDMI_PHY_CONF0_SPARECTRL_MASK);
>> +}
>> +
> What does enable spare do? Can other future SoCs use it?
>
> This looks like DW specific. And can be a separate commit that adds a feature to the dw hdmi driver.
Actually I am not very clearly about this bit, but RK3288 HDMI will
not work without this bit enable.
On imx6, the description about this bit is:Reserved. Spare pin control.
On rk3288, the description is: svsret/sparectrl
Both are very simple.
> Thanks
> ZubairLK
>
>> static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
>> {
>> hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>> @@ -846,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
>> dw_hdmi_phy_gen2_txpwron(hdmi, 1);
>> dw_hdmi_phy_gen2_pddq(hdmi, 0);
>>
>> + if (hdmi->dev_type == RK3288_HDMI)
>> + dw_hdmi_phy_enable_spare(hdmi, 1);
>> +
>> /*Wait for PHY PLL lock */
>> msec = 5;
>> do {
>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
>> index b8412a9..30a6b28 100644
>> --- a/drivers/gpu/drm/bridge/dw_hdmi.h
>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.h
>> @@ -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,
> Cheers,
> ZubairLK
>
>
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>
>
Hi ZubairLK:
Thanks for your review.
On 2014年11月14日 18:19, Zubair Lutfullah Kakakhel wrote:
> Hi Andy,
>
> Nice work on this patch series. Its getting better and better :).
>
> On 14/11/14 03:27, Andy Yan wrote:
>> hdmi phy clock symbol and transmission termination value
>> can adjust platform specific to get the best SI
> ^Is this signal integrity?
yes , SI is signal integrity, such as eye diagram measurement
>
> Are these two disjoint features in separate patches?
>
>> also add mode_valid interface for some platform may not support
>> all the display mode
> Sounds like another separate patch to me. :)
they can seperate
>
> Also, This series is becoming quite large. With major changes and fixes mixed together.
>
> Patch 3 splits imx-drm.
> Patch 4 moves dw-drm out of imx-drm folder.
> Patch 7 adds binding
> Patch 9 converts to drm bridge.
>
> Can these be placed together easily?
> And in the start. i.e. patch 1, 2, 3, 4,
>
> Then all fixes etc can come afterwards?
>
> It helps when checking histories later as to how a driver was made and how fixes happened.
>
> Especially when file moves happen..
Do you mean we can rearrange the patch series?
put patch 3, 4 ,7, 9 together one bye one
than followed by the fixes patches 5 ,6, 8, 11 ?
>
> Cheers,
> ZubairLK
>
>> Signed-off-by: Andy Yan <[email protected]>
>>
>> ---
>>
>> Changes in v10:
>> - split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
>>
>> Changes in v9: None
>> Changes in v8: None
>> Changes in v7: None
>> Changes in v6: None
>> Changes in v5: None
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>> drivers/gpu/drm/bridge/dw_hdmi.c | 29 +++++++++++++++++++++++++++--
>> drivers/staging/imx-drm/dw_hdmi-imx.c | 10 +++++++++-
>> include/drm/bridge/dw_hdmi.h | 7 +++++++
>> 3 files changed, 43 insertions(+), 3 deletions(-)
>>
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>
>
On 14/11/14 10:37, Andy Yan wrote:
>
> On 2014年11月14日 18:23, Zubair Lutfullah Kakakhel wrote:
>> Hi Andy
>>
>> On 14/11/14 03:31, Andy Yan wrote:
>>> Rockchip RK3288 hdmi is compatible with dw_hdmi
>>>
>>> Signed-off-by: Andy Yan <[email protected]>
>>>
>>> ---
>>>
>>> Changes in v10:
>>> - add more display mode support mpll configuration for rk3288
>>>
>>> Changes in v9:
>>> - move some phy configuration to platform driver
>>>
>>> Changes in v8: None
>>> Changes in v7: None
>>> Changes in v6: None
>>> Changes in v5: None
>>> Changes in v4: None
>>> Changes in v3: None
>>> Changes in v2: None
>>>
>>> drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
>>> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
>>> drivers/gpu/drm/rockchip/Kconfig | 10 +
>>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>>> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
>>> include/drm/bridge/dw_hdmi.h | 1 +
>>> 6 files changed, 379 insertions(+), 2 deletions(-)
>>> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>>>
>>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>>> index a2876fe..1dd1f0b 100644
>>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>>> @@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
>>> HDMI_PHY_CONF0_ENTMDS_MASK);
>>> }
>>> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
>>> +{
>>> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>>> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
>>> + HDMI_PHY_CONF0_SPARECTRL_MASK);
>>> +}
>>> +
>> What does enable spare do? Can other future SoCs use it?
>>
>> This looks like DW specific. And can be a separate commit that adds a feature to the dw hdmi driver.
> Actually I am not very clearly about this bit, but RK3288 HDMI will not work without this bit enable.
> On imx6, the description about this bit is:Reserved. Spare pin control.
> On rk3288, the description is: svsret/sparectrl
> Both are very simple.
Sounds like the IP Core in the rk3288 is slightly upgraded.
Separate this section in a different commit as it is generic DW stuff.
And add what you wrote above in the commit message.
Thanks
ZubairLK
On 14/11/14 10:53, Andy Yan wrote:
> Hi ZubairLK:
> Thanks for your review.
> On 2014年11月14日 18:19, Zubair Lutfullah Kakakhel wrote:
>> Hi Andy,
>>
>> Nice work on this patch series. Its getting better and better :).
>>
>> On 14/11/14 03:27, Andy Yan wrote:
>>> hdmi phy clock symbol and transmission termination value
>>> can adjust platform specific to get the best SI
>> ^Is this signal integrity?
> yes , SI is signal integrity, such as eye diagram measurement
>>
>> Are these two disjoint features in separate patches?
>>
>>> also add mode_valid interface for some platform may not support
>>> all the display mode
>> Sounds like another separate patch to me. :)
> they can seperate
>>
>> Also, This series is becoming quite large. With major changes and fixes mixed together.
>>
>> Patch 3 splits imx-drm.
>> Patch 4 moves dw-drm out of imx-drm folder.
>> Patch 7 adds binding
>> Patch 9 converts to drm bridge.
>>
>> Can these be placed together easily?
>> And in the start. i.e. patch 1, 2, 3, 4,
>>
>> Then all fixes etc can come afterwards?
>>
>> It helps when checking histories later as to how a driver was made and how fixes happened.
>>
>> Especially when file moves happen..
> Do you mean we can rearrange the patch series?
> put patch 3, 4 ,7, 9 together one bye one
> than followed by the fixes patches 5 ,6, 8, 11 ?
Yes. Rearrange so that the split imx-drm/imx-hdmi and conversion to drm-bridge is at the start of the series.
Then the rest are bug fixes and feature additions.
Cheers,
ZubairLK
On 2014年11月14日 18:55, Zubair Lutfullah Kakakhel wrote:
>
> On 14/11/14 10:53, Andy Yan wrote:
>> Hi ZubairLK:
>> Thanks for your review.
>> On 2014年11月14日 18:19, Zubair Lutfullah Kakakhel wrote:
>>> Hi Andy,
>>>
>>> Nice work on this patch series. Its getting better and better :).
>>>
>>> On 14/11/14 03:27, Andy Yan wrote:
>>>> hdmi phy clock symbol and transmission termination value
>>>> can adjust platform specific to get the best SI
>>> ^Is this signal integrity?
>> yes , SI is signal integrity, such as eye diagram measurement
>>> Are these two disjoint features in separate patches?
>>>
>>>> also add mode_valid interface for some platform may not support
>>>> all the display mode
>>> Sounds like another separate patch to me. :)
>> they can seperate
>>> Also, This series is becoming quite large. With major changes and fixes mixed together.
>>>
>>> Patch 3 splits imx-drm.
>>> Patch 4 moves dw-drm out of imx-drm folder.
>>> Patch 7 adds binding
>>> Patch 9 converts to drm bridge.
>>>
>>> Can these be placed together easily?
>>> And in the start. i.e. patch 1, 2, 3, 4,
>>>
>>> Then all fixes etc can come afterwards?
>>>
>>> It helps when checking histories later as to how a driver was made and how fixes happened.
>>>
>>> Especially when file moves happen..
>> Do you mean we can rearrange the patch series?
>> put patch 3, 4 ,7, 9 together one bye one
>> than followed by the fixes patches 5 ,6, 8, 11 ?
> Yes. Rearrange so that the split imx-drm/imx-hdmi and conversion to drm-bridge is at the start of the series.
> Then the rest are bug fixes and feature additions.
Can I put patch#1(make checkpatch happy) and patch#2 (defer probe) as
the first two patch.
Daniel from Google chromium think it's better to put the two slightly
changes in the front for easy review.
> Cheers,
> ZubairLK
>
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
On 14/11/14 11:08, Andy Yan wrote:
>
> On 2014年11月14日 18:55, Zubair Lutfullah Kakakhel wrote:
>>
>> On 14/11/14 10:53, Andy Yan wrote:
>>> Hi ZubairLK:
>>> Thanks for your review.
>>> On 2014年11月14日 18:19, Zubair Lutfullah Kakakhel wrote:
>>>> Hi Andy,
>>>>
>>>> Nice work on this patch series. Its getting better and better :).
>>>>
>>>> On 14/11/14 03:27, Andy Yan wrote:
>>>>> hdmi phy clock symbol and transmission termination value
>>>>> can adjust platform specific to get the best SI
>>>> ^Is this signal integrity?
>>> yes , SI is signal integrity, such as eye diagram measurement
>>>> Are these two disjoint features in separate patches?
>>>>
>>>>> also add mode_valid interface for some platform may not support
>>>>> all the display mode
>>>> Sounds like another separate patch to me. :)
>>> they can seperate
>>>> Also, This series is becoming quite large. With major changes and fixes mixed together.
>>>>
>>>> Patch 3 splits imx-drm.
>>>> Patch 4 moves dw-drm out of imx-drm folder.
>>>> Patch 7 adds binding
>>>> Patch 9 converts to drm bridge.
>>>>
>>>> Can these be placed together easily?
>>>> And in the start. i.e. patch 1, 2, 3, 4,
>>>>
>>>> Then all fixes etc can come afterwards?
>>>>
>>>> It helps when checking histories later as to how a driver was made and how fixes happened.
>>>>
>>>> Especially when file moves happen..
>>> Do you mean we can rearrange the patch series?
>>> put patch 3, 4 ,7, 9 together one bye one
>>> than followed by the fixes patches 5 ,6, 8, 11 ?
>> Yes. Rearrange so that the split imx-drm/imx-hdmi and conversion to drm-bridge is at the start of the series.
>> Then the rest are bug fixes and feature additions.
> Can I put patch#1(make checkpatch happy) and patch#2 (defer probe) as the first two patch.
> Daniel from Google chromium think it's better to put the two slightly changes in the front for easy review.
Sure.
I am not the maintainer. They have to make the final decision.
ZubairLK
On 2014年11月14日 18:53, Zubair Lutfullah Kakakhel wrote:
>
> On 14/11/14 10:37, Andy Yan wrote:
>> On 2014年11月14日 18:23, Zubair Lutfullah Kakakhel wrote:
>>> Hi Andy
>>>
>>> On 14/11/14 03:31, Andy Yan wrote:
>>>> Rockchip RK3288 hdmi is compatible with dw_hdmi
>>>>
>>>> Signed-off-by: Andy Yan <[email protected]>
>>>>
>>>> ---
>>>>
>>>> Changes in v10:
>>>> - add more display mode support mpll configuration for rk3288
>>>>
>>>> Changes in v9:
>>>> - move some phy configuration to platform driver
>>>>
>>>> Changes in v8: None
>>>> Changes in v7: None
>>>> Changes in v6: None
>>>> Changes in v5: None
>>>> Changes in v4: None
>>>> Changes in v3: None
>>>> Changes in v2: None
>>>>
>>>> drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
>>>> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
>>>> drivers/gpu/drm/rockchip/Kconfig | 10 +
>>>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>>>> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
>>>> include/drm/bridge/dw_hdmi.h | 1 +
>>>> 6 files changed, 379 insertions(+), 2 deletions(-)
>>>> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>>>>
>>>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>>>> index a2876fe..1dd1f0b 100644
>>>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>>>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>>>> @@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
>>>> HDMI_PHY_CONF0_ENTMDS_MASK);
>>>> }
>>>> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
>>>> +{
>>>> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>>>> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
>>>> + HDMI_PHY_CONF0_SPARECTRL_MASK);
>>>> +}
>>>> +
>>> What does enable spare do? Can other future SoCs use it?
>>>
>>> This looks like DW specific. And can be a separate commit that adds a feature to the dw hdmi driver.
>> Actually I am not very clearly about this bit, but RK3288 HDMI will not work without this bit enable.
>> On imx6, the description about this bit is:Reserved. Spare pin control.
>> On rk3288, the description is: svsret/sparectrl
>> Both are very simple.
> Sounds like the IP Core in the rk3288 is slightly upgraded.
> Separate this section in a different commit as it is generic DW stuff.
>
> And add what you wrote above in the commit message.
Only Separate function dw_hdmi_phy_enale_spare ? not include
if (hdmi->dev_type == rk3288_hdmi)
dw_hdmi_enable_phy_spare(hdmi, 1);
?
>
> Thanks
> ZubairLK
>
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
On 14/11/14 11:13, Andy Yan wrote:
>
> On 2014年11月14日 18:53, Zubair Lutfullah Kakakhel wrote:
>>
>> On 14/11/14 10:37, Andy Yan wrote:
>>> On 2014年11月14日 18:23, Zubair Lutfullah Kakakhel wrote:
>>>> Hi Andy
>>>>
>>>> On 14/11/14 03:31, Andy Yan wrote:
>>>>> Rockchip RK3288 hdmi is compatible with dw_hdmi
>>>>>
>>>>> Signed-off-by: Andy Yan <[email protected]>
>>>>>
>>>>> ---
>>>>>
>>>>> Changes in v10:
>>>>> - add more display mode support mpll configuration for rk3288
>>>>>
>>>>> Changes in v9:
>>>>> - move some phy configuration to platform driver
>>>>>
>>>>> Changes in v8: None
>>>>> Changes in v7: None
>>>>> Changes in v6: None
>>>>> Changes in v5: None
>>>>> Changes in v4: None
>>>>> Changes in v3: None
>>>>> Changes in v2: None
>>>>>
>>>>> drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
>>>>> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
>>>>> drivers/gpu/drm/rockchip/Kconfig | 10 +
>>>>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>>>>> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
>>>>> include/drm/bridge/dw_hdmi.h | 1 +
>>>>> 6 files changed, 379 insertions(+), 2 deletions(-)
>>>>> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>>>>>
>>>>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>>>>> index a2876fe..1dd1f0b 100644
>>>>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>>>>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>>>>> @@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
>>>>> HDMI_PHY_CONF0_ENTMDS_MASK);
>>>>> }
>>>>> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
>>>>> +{
>>>>> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>>>>> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
>>>>> + HDMI_PHY_CONF0_SPARECTRL_MASK);
>>>>> +}
>>>>> +
>>>> What does enable spare do? Can other future SoCs use it?
>>>>
>>>> This looks like DW specific. And can be a separate commit that adds a feature to the dw hdmi driver.
>>> Actually I am not very clearly about this bit, but RK3288 HDMI will not work without this bit enable.
>>> On imx6, the description about this bit is:Reserved. Spare pin control.
>>> On rk3288, the description is: svsret/sparectrl
>>> Both are very simple.
>> Sounds like the IP Core in the rk3288 is slightly upgraded.
>> Separate this section in a different commit as it is generic DW stuff.
>>
>> And add what you wrote above in the commit message.
> Only Separate function dw_hdmi_phy_enale_spare ? not include
> if (hdmi->dev_type == rk3288_hdmi)
> dw_hdmi_enable_phy_spare(hdmi, 1);
> ?
Yes. Separate dw_hdmi_phy_enable_spare and its associated defines
HDMI_PHY_CONF0_SPARECTRL_OFFSET
HDMI_PHY_CONF0_SPARECTRL_MASK
in the header
as one commit.
The if (hdmi->dev_type == rk3288_hdmi) code is part of the add rk3288 support.
ZubairLK
On 2014年11月14日 19:16, Zubair Lutfullah Kakakhel wrote:
>
> On 14/11/14 11:13, Andy Yan wrote:
>> On 2014年11月14日 18:53, Zubair Lutfullah Kakakhel wrote:
>>> On 14/11/14 10:37, Andy Yan wrote:
>>>> On 2014年11月14日 18:23, Zubair Lutfullah Kakakhel wrote:
>>>>> Hi Andy
>>>>>
>>>>> On 14/11/14 03:31, Andy Yan wrote:
>>>>>> Rockchip RK3288 hdmi is compatible with dw_hdmi
>>>>>>
>>>>>> Signed-off-by: Andy Yan <[email protected]>
>>>>>>
>>>>>> ---
>>>>>>
>>>>>> Changes in v10:
>>>>>> - add more display mode support mpll configuration for rk3288
>>>>>>
>>>>>> Changes in v9:
>>>>>> - move some phy configuration to platform driver
>>>>>>
>>>>>> Changes in v8: None
>>>>>> Changes in v7: None
>>>>>> Changes in v6: None
>>>>>> Changes in v5: None
>>>>>> Changes in v4: None
>>>>>> Changes in v3: None
>>>>>> Changes in v2: None
>>>>>>
>>>>>> drivers/gpu/drm/bridge/dw_hdmi.c | 10 +
>>>>>> drivers/gpu/drm/bridge/dw_hdmi.h | 3 +-
>>>>>> drivers/gpu/drm/rockchip/Kconfig | 10 +
>>>>>> drivers/gpu/drm/rockchip/Makefile | 2 +-
>>>>>> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
>>>>>> include/drm/bridge/dw_hdmi.h | 1 +
>>>>>> 6 files changed, 379 insertions(+), 2 deletions(-)
>>>>>> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>>>>>> index a2876fe..1dd1f0b 100644
>>>>>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>>>>>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>>>>>> @@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
>>>>>> HDMI_PHY_CONF0_ENTMDS_MASK);
>>>>>> }
>>>>>> +static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
>>>>>> +{
>>>>>> + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
>>>>>> + HDMI_PHY_CONF0_SPARECTRL_OFFSET,
>>>>>> + HDMI_PHY_CONF0_SPARECTRL_MASK);
>>>>>> +}
>>>>>> +
>>>>> What does enable spare do? Can other future SoCs use it?
>>>>>
>>>>> This looks like DW specific. And can be a separate commit that adds a feature to the dw hdmi driver.
>>>> Actually I am not very clearly about this bit, but RK3288 HDMI will not work without this bit enable.
>>>> On imx6, the description about this bit is:Reserved. Spare pin control.
>>>> On rk3288, the description is: svsret/sparectrl
>>>> Both are very simple.
>>> Sounds like the IP Core in the rk3288 is slightly upgraded.
>>> Separate this section in a different commit as it is generic DW stuff.
>>>
>>> And add what you wrote above in the commit message.
>> Only Separate function dw_hdmi_phy_enale_spare ? not include
>> if (hdmi->dev_type == rk3288_hdmi)
>> dw_hdmi_enable_phy_spare(hdmi, 1);
>> ?
> Yes. Separate dw_hdmi_phy_enable_spare and its associated defines
> HDMI_PHY_CONF0_SPARECTRL_OFFSET
> HDMI_PHY_CONF0_SPARECTRL_MASK
> in the header
> as one commit.
>
>
> The if (hdmi->dev_type == rk3288_hdmi) code is part of the add rk3288 support.
>
> ZubairLK
Many thanks :-)
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they also have some
lightly differences, such as phy pll configuration, register width(imx hdmi
register is one byte, but rk3288 is 4 bytes width and can only be accessed
by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
support.
To reuse the imx-hdmi driver, we make this patch set:
(1): fix some CodingStyle warning to make checkpatch happy
(2): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
(3): move imx-hdmi to bridge/dw-hdmi, and convert it to a drm_bridge driver
(4): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
Changes in v11:
- rearrange the patch order
- squash patch <split some phy configuration to platform driver>
- split some modification form patch <dw_hdmi: add rk3288 support>
Changes in v10:
- split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
- add more display mode support mpll configuration for rk3288
Changes in v9:
- move some phy configuration to platform driver
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
- Add documentation for rockchip dw hdmi
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6:
- rearrange the patch order
- move some modification from patch#5
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4:
- fix checkpatch CHECK
- defer probe ddc i2c adapter
Changes in v3:
- split multi-register access to one indepent patch
Changes in v2:
- use git format -M to generate these patch
Andy Yan (11):
staging: imx-drm: imx-hdmi: make checkpatch happy
staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
dt-bindings: add document for dw_hdmi
drm: bridge/dw_hdmi: add support for multi-byte register width access
drm: bridge/dw_hdmi: add mode_valid support
drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done
drm: bridge/dw_hdmi: add function dw_hdmi_phy_enable_spare
dt-bindings: Add documentation for rockchip dw hdmi
drm: bridge/dw_hdmi: add rockchip rk3288 support
Yakir Yang (1):
drm: bridge/dw_hdmi: convert dw-hdmi to drm_bridge mode
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 762 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 8 +-
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 274 ++++++++
include/drm/bridge/dw_hdmi.h | 60 ++
13 files changed, 1138 insertions(+), 425 deletions(-)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h
--
1.9.1
CHECK: Alignment should match open parenthesis
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
CHECK: braces {} should be used on all arms of this statement
+ if (hdmi->hdmi_data.video_mode.mdvi)
[...]
+ else {
[...]
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- rearrange the patch order
Changes in v5: None
Changes in v4:
- fix checkpatch CHECK
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 49 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index aaec6b2..79daec4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
}
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+ u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}
static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
- unsigned long pixel_clk)
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
+ __func__, pixel_clk);
return;
}
@@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
u16 coeff_b = (*csc_coeff)[1][i];
u16 coeff_c = (*csc_coeff)[2][i];
- hdmi_writeb(hdmi, coeff_a & 0xff,
- HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_c & 0xff,
- HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}
@@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
- if (hdmi_data->enc_out_format == RGB
- || hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth)
+ if (hdmi_data->enc_out_format == RGB ||
+ hdmi_data->enc_out_format == YCBCR444) {
+ if (!hdmi_data->enc_color_depth) {
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- else if (hdmi_data->enc_color_depth == 8) {
+ } else if (hdmi_data->enc_color_depth == 8) {
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10)
+ } else if (hdmi_data->enc_color_depth == 10) {
color_depth = 5;
- else if (hdmi_data->enc_color_depth == 12)
+ } else if (hdmi_data->enc_color_depth == 12) {
color_depth = 6;
- else if (hdmi_data->enc_color_depth == 16)
+ } else if (hdmi_data->enc_color_depth == 16) {
color_depth = 7;
- else
+ } else {
return;
+ }
} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
if (!hdmi_data->enc_color_depth ||
hdmi_data->enc_color_depth == 8)
@@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
else
return;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
- } else
+ } else {
return;
+ }
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
@@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
@@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
}
static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 8),
- HDMI_PHY_I2CM_DATAO_1_ADDR);
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 0),
- HDMI_PHY_I2CM_DATAO_0_ADDR);
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
- HDMI_PHY_I2CM_OPERATION_ADDR);
+ HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
@@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 1);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
+ HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
@@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
break;
if (i >= ARRAY_SIZE(curr_ctrl)) {
- dev_err(hdmi->dev,
- "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
+ dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
@@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
- (hdmi->vic == 21) || (hdmi->vic == 22) ||
- (hdmi->vic == 2) || (hdmi->vic == 3) ||
- (hdmi->vic == 17) || (hdmi->vic == 18))
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
else
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
- (hdmi->vic == 12) || (hdmi->vic == 13) ||
- (hdmi->vic == 14) || (hdmi->vic == 15) ||
- (hdmi->vic == 25) || (hdmi->vic == 26) ||
- (hdmi->vic == 27) || (hdmi->vic == 28) ||
- (hdmi->vic == 29) || (hdmi->vic == 30) ||
- (hdmi->vic == 35) || (hdmi->vic == 36) ||
- (hdmi->vic == 37) || (hdmi->vic == 38))
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
else
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
@@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
imx_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi)
+ if (hdmi->hdmi_data.video_mode.mdvi) {
dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- else {
+ } else {
dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
/* HDMI Initialization Step E - Configure audio */
@@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
+ HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
@@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
+ &imx_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Product and revision IDs */
dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(hdmi, HDMI_DESIGN_ID),
+ hdmi_readb(hdmi, HDMI_REVISION_ID),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
initialize_hdmi_ih_mutes(hdmi);
--
1.9.1
drm driver may probe before the i2c bus, so the driver should
defer probing until it is available
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4:
- defer probe ddc i2c adapter
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 79daec4..c2b035a 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1611,8 +1611,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- if (!hdmi->ddc)
+ if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
+ of_node_put(ddc_node);
+ return -EPROBE_DEFER;
+ }
of_node_put(ddc_node);
} else {
--
1.9.1
IMX6 and Rockchip RK3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly differences, such as phy pll configuration,
register width, 4K support, clk useage, and the crtc mux configuration
is also platform specific.
To reuse the imx hdmi driver, split the platform specific code out
to dw_hdmi-imx.c.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11:
- squash patch <split some phy configuration to platform driver>
Changes in v10:
- split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
Changes in v9: None
Changes in v8: None
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 225 ++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 267 +++++++++-------------------------
drivers/staging/imx-drm/imx-hdmi.h | 50 +++++++
4 files changed, 347 insertions(+), 197 deletions(-)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 582c438..809027d 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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) += imx-hdmi.o dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
new file mode 100644
index 0000000..7154c96
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,225 @@
+/* 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/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#include "imx-drm.h"
+#include "imx-hdmi.h"
+
+struct imx_hdmi_priv {
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+ struct regmap *regmap;
+};
+
+static const struct 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 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 sym_term imx_sym_term[] = {
+ /*pixelclk symbol term*/
+ { 148500000, 0x800d, 0x0005 },
+ { ~0UL, 0x0000, 0x0000 }
+};
+
+static int imx_hdmi_parse_dt(struct imx_hdmi_priv *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);
+ }
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
+ return PTR_ERR(hdmi->isfr_clk);
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->iahb_clk);
+ }
+
+ return 0;
+}
+
+static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+{
+ struct imx_hdmi_priv *hdmi;
+ int ret;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return ERR_PTR(-ENOMEM);
+ hdmi->dev = &pdev->dev;
+
+ ret = imx_hdmi_parse_dt(hdmi);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(hdmi->dev,
+ "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ return hdmi;
+}
+
+static void imx_hdmi_imx_exit(void *priv)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+
+ clk_disable_unprepare(hdmi->iahb_clk);
+}
+
+static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+{
+ struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ 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 imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .sym_term = imx_sym_term,
+ .dev_type = IMX6Q_HDMI,
+};
+
+static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = imx_hdmi_imx_setup,
+ .exit = imx_hdmi_imx_exit,
+ .encoder_commit = imx_hdmi_imx_encoder_commit,
+ .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+ .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 imx_hdmi_imx_ids[] = {
+ { .compatible = "fsl,imx6q-hdmi",
+ .data = &imx6q_hdmi_drv_data
+ }, {
+ .compatible = "fsl,imx6dl-hdmi",
+ .data = &imx6dl_hdmi_drv_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+
+static int imx_hdmi_imx_probe(struct platform_device *pdev)
+{
+ const struct imx_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ plat_data = match->data;
+
+ return imx_hdmi_platform_register(pdev, plat_data);
+}
+
+static int imx_hdmi_imx_remove(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_unregister(pdev);
+}
+
+static struct platform_driver imx_hdmi_imx_platform_driver = {
+ .probe = imx_hdmi_imx_probe,
+ .remove = imx_hdmi_imx_remove,
+ .driver = {
+ .name = "dwhdmi-imx",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_hdmi_imx_ids,
+ },
+};
+
+module_platform_driver(imx_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c2b035a..ba4e392 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,21 +16,16 @@
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/clk.h>
#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.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 <video/imx-ipu-v3.h>
#include "imx-hdmi.h"
-#include "imx-drm.h"
#define HDMI_EDID_LEN 512
@@ -54,11 +49,6 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x0000, 0x0000, 0x0000 },
{ 0x0000, 0x2000, 0x0000, 0x0000 },
@@ -117,10 +107,10 @@ struct imx_hdmi {
enum imx_hdmi_devtype dev_type;
struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
struct hdmi_data_info hdmi_data;
+ const struct imx_hdmi_plat_data *plat_data;
+ void *priv;
int vic;
u8 edid[HDMI_EDID_LEN];
@@ -137,13 +127,6 @@ struct imx_hdmi {
int ratio;
};
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
@@ -728,76 +711,14 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
- {
- 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 },
- },
- }
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
- /* 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 int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
u8 val, msec;
+ const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
+ const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
+ const struct sym_term *sym_term = hdmi->plat_data->sym_term;
if (prep)
return -EINVAL;
@@ -843,34 +764,41 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
- for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config[i].mpixelclock)
+ mpll_cfg[i].mpixelclock)
break;
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);
- for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl[i].mpixelclock)
+ curr_ctr[i].mpixelclock)
break;
- if (i >= ARRAY_SIZE(curr_ctrl)) {
+ if (curr_ctr[i].mpixelclock == (~0UL)) {
dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
/* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10);
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+
+ for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ sym_term[i].mpixelclock)
+ break;
+
/* RESISTANCE TERM 133Ohm Cfg */
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
/* PREEMP Cgf 0.00 */
- hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
+
/* TX/CK LVL 10 */
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
/* REMOVE CLK TERM */
@@ -1453,21 +1381,29 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
imx_hdmi_poweroff(hdmi);
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+
+ if (hdmi->plat_data->encoder_prepare)
+ hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
static void imx_hdmi_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);
- imx_hdmi_set_ipu_di_mux(hdmi, mux);
+ if (hdmi->plat_data->encoder_commit)
+ hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
imx_hdmi_poweron(hdmi);
}
+void imx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_drm_encoder_destroy,
+ .destroy = drm_encoder_cleanup,
};
static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1483,7 +1419,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_drm_connector_destroy,
+ .destroy = imx_hdmi_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1539,12 +1475,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
- int ret;
+ struct drm_encoder *encoder = &hdmi->encoder;
+ struct device *dev = hdmi->dev;
- ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
- hdmi->dev->of_node);
- if (ret)
- return ret;
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
@@ -1564,50 +1498,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- .driver_data = IMX6Q_HDMI,
- }, {
- .name = "imx6dl-hdmi",
- .driver_data = IMX6DL_HDMI,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
- struct imx_hdmi *hdmi;
struct resource *iores;
int ret, irq;
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
-
- hdmi->dev_type = device_id->driver_data;
- }
-
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1637,40 +1537,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap))
- return PTR_ERR(hdmi->regmap);
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- ret = PTR_ERR(hdmi->isfr_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI isfr clk: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- ret = PTR_ERR(hdmi->iahb_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI iahb clk: %d\n", ret);
- goto err_isfr;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- goto err_isfr;
- }
-
+ if (hdmi->plat_data->setup)
+ hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1698,11 +1566,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ret = imx_hdmi_fb_registered(hdmi);
if (ret)
- goto err_iahb;
+ return ret;
ret = imx_hdmi_register(drm, hdmi);
if (ret)
- goto err_iahb;
+ return ret;
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
@@ -1710,13 +1578,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, hdmi);
return 0;
-
-err_iahb:
- clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
- clk_disable_unprepare(hdmi->isfr_clk);
-
- return ret;
}
static void imx_hdmi_unbind(struct device *dev, struct device *master,
@@ -1729,9 +1590,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
+ if (hdmi->plat_data->exit)
+ hdmi->plat_data->exit(hdmi->priv);
i2c_put_adapter(hdmi->ddc);
}
@@ -1751,17 +1611,32 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver imx_hdmi_driver = {
- .probe = imx_hdmi_platform_probe,
- .remove = imx_hdmi_platform_remove,
- .driver = {
- .name = "imx-hdmi",
- .owner = THIS_MODULE,
- .of_match_table = imx_hdmi_dt_ids,
- },
-};
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data)
+{
+ struct imx_hdmi *hdmi;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+
+ platform_set_drvdata(pdev, hdmi);
-module_platform_driver(imx_hdmi_driver);
+ return imx_hdmi_platform_probe(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+
+int imx_hdmi_platform_unregister(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_remove(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b6776..dba45c1 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,54 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum imx_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct sym_term {
+ unsigned long mpixelclock;
+ u16 sym_ctr; /*clock symbol and transmitter control*/
+ u16 term; /*transmission termination value*/
+};
+
+struct imx_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ const struct sym_term *sym_term;
+ enum imx_hdmi_devtype dev_type;
+
+};
+
+int imx_hdmi_platform_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data);
+int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi driver out
to drm/bridge and rename imx-hdmi to dw_hdmi
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2:
- use git format -M to generate these patch
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 281 +++++++++++----------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 53 +---
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 70 ++---
include/drm/bridge/dw_hdmi.h | 64 +++++
8 files changed, 250 insertions(+), 227 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (83%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (97%)
create mode 100644 include/drm/bridge/dw_hdmi.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..26162ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,3 +3,8 @@ config DRM_PTN3460
depends on DRM
select DRM_KMS_HELPER
---help---
+
+config DRM_DW_HDMI
+ bool "Synopsys DesignWare High-Definition Multimedia Interface"
+ depends on DRM
+ select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..d8a8cfd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
similarity index 83%
rename from drivers/staging/imx-drm/imx-hdmi.c
rename to drivers/gpu/drm/bridge/dw_hdmi.c
index ba4e392..1a9026b 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -6,8 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
+ * Designware High-Definition Multimedia Interface (HDMI) driver
*
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
@@ -24,8 +23,9 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
-#include "imx-hdmi.h"
+#include "dw_hdmi.h"
#define HDMI_EDID_LEN 512
@@ -101,15 +101,15 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
-struct imx_hdmi {
+struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder encoder;
- enum imx_hdmi_devtype dev_type;
+ enum dw_hdmi_devtype dev_type;
struct device *dev;
struct hdmi_data_info hdmi_data;
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
void *priv;
int vic;
@@ -127,17 +127,17 @@ struct imx_hdmi {
int ratio;
};
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
}
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
return readb(hdmi->regs + offset);
}
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;
@@ -145,13 +145,13 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
unsigned int value)
{
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
@@ -162,7 +162,7 @@ static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
@@ -309,7 +309,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -333,12 +333,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
hdmi_regenerate_cts(hdmi, clk_cts);
}
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, 74250000);
}
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
@@ -350,7 +350,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
* pin{31~24} <==> G[7:0]
* pin{15~8} <==> B[7:0]
*/
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
{
int color_format = 0;
u8 val;
@@ -406,12 +406,12 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
}
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
return 0;
@@ -421,7 +421,7 @@ static int is_color_space_decimation(struct imx_hdmi *hdmi)
return 0;
}
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
return 0;
@@ -431,7 +431,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
return 0;
}
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
unsigned i;
@@ -472,7 +472,7 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
HDMI_CSC_SCALE);
}
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
{
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
@@ -500,7 +500,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
HDMI_CSC_SCALE);
- imx_hdmi_update_csc_coeffs(hdmi);
+ dw_hdmi_update_csc_coeffs(hdmi);
}
/*
@@ -508,7 +508,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
* for example, if input is YCC422 mode or repeater is used,
* data should be repacked this module can be bypassed.
*/
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
{
unsigned int color_depth = 0;
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -605,40 +605,40 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_CONF);
}
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
@@ -648,7 +648,7 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -662,56 +662,56 @@ static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
}
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_ENTMDS_OFFSET,
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
}
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
}
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
HDMI_PHY_CONF0_SELDATAENPOL_MASK);
}
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDIPIF_OFFSET,
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
@@ -747,10 +747,10 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
/* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
/* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
/* PHY reset */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
@@ -804,15 +804,15 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- imx_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_power(hdmi, 1);
/* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 1);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
/* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(hdmi, 1);
- imx_hdmi_phy_gen2_pddq(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
/*Wait for PHY PLL lock */
msec = 5;
@@ -833,7 +833,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
return 0;
}
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
bool cscon = false;
@@ -844,10 +844,10 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
- imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
- imx_hdmi_phy_sel_interface_control(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+ dw_hdmi_phy_sel_interface_control(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
@@ -859,7 +859,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
return 0;
}
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{
u8 de;
@@ -878,7 +878,7 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
{
u8 val, pix_fmt, under_scan;
u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
@@ -972,7 +972,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
}
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
u8 inv_val;
@@ -1056,19 +1056,19 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
{
if (!hdmi->phy_enabled)
return;
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
u8 clkdis;
@@ -1097,13 +1097,13 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
}
}
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
int count;
u8 val;
@@ -1121,19 +1121,19 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
HDMI_IH_MUTE_FC_STAT2);
}
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
{
int ret;
@@ -1185,12 +1185,12 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */
- ret = imx_hdmi_phy_init(hdmi);
+ ret = dw_hdmi_phy_init(hdmi);
if (ret)
return ret;
/* HDMI Initialization Step B.3 */
- imx_hdmi_enable_video_path(hdmi);
+ dw_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
if (hdmi->hdmi_data.video_mode.mdvi) {
@@ -1211,7 +1211,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_video_sample(hdmi);
hdmi_tx_hdcp_config(hdmi);
- imx_hdmi_clear_overflow(hdmi);
+ dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
hdmi_enable_overflow_interrupts(hdmi);
@@ -1219,7 +1219,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);
@@ -1237,7 +1237,7 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
return 0;
}
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{
u8 ih_mute;
@@ -1289,29 +1289,29 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
}
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{
- imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+ dw_hdmi_setup(hdmi, &hdmi->previous_mode);
}
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
- imx_hdmi_phy_disable(hdmi);
+ dw_hdmi_phy_disable(hdmi);
}
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
struct edid *edid;
int ret;
@@ -1334,102 +1334,102 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return &hdmi->encoder;
}
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_setup(hdmi, mode);
+ dw_hdmi_setup(hdmi, mode);
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
}
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
{
}
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (mode)
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
else
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
if (hdmi->plat_data->encoder_prepare)
hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
}
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
if (hdmi->plat_data->encoder_commit)
hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-void imx_hdmi_connector_destroy(struct drm_connector *connector)
+void dw_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .dpms = imx_hdmi_encoder_dpms,
- .prepare = imx_hdmi_encoder_prepare,
- .commit = imx_hdmi_encoder_commit,
- .mode_set = imx_hdmi_encoder_mode_set,
- .mode_fixup = imx_hdmi_encoder_mode_fixup,
- .disable = imx_hdmi_encoder_disable,
+static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
+ .dpms = dw_hdmi_encoder_dpms,
+ .prepare = dw_hdmi_encoder_prepare,
+ .commit = dw_hdmi_encoder_commit,
+ .mode_set = dw_hdmi_encoder_mode_set,
+ .mode_fixup = dw_hdmi_encoder_mode_fixup,
+ .disable = dw_hdmi_encoder_disable,
};
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- .get_modes = imx_hdmi_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+ .get_modes = dw_hdmi_connector_get_modes,
+ .best_encoder = dw_hdmi_connector_best_encoder,
};
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1439,9 +1439,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
@@ -1455,14 +1455,14 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
HDMI_PHY_POL0);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
}
drm_helper_hpd_irq_event(hdmi->connector.dev);
}
@@ -1473,7 +1473,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = &hdmi->encoder;
struct device *dev = hdmi->dev;
@@ -1482,13 +1482,13 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+ drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ &dw_hdmi_connector_helper_funcs);
+ drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = &hdmi->encoder;
@@ -1498,10 +1498,10 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
@@ -1526,8 +1526,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
+ ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
return ret;
@@ -1564,11 +1564,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- ret = imx_hdmi_fb_registered(hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
return ret;
- ret = imx_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_register(drm, hdmi);
if (ret)
return ret;
@@ -1580,10 +1580,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
+static void dw_hdmi_unbind(struct device *dev, struct device *master,
void *data)
{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
@@ -1596,25 +1596,25 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
}
static const struct component_ops hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
+ .bind = dw_hdmi_bind,
+ .unbind = dw_hdmi_unbind,
};
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int dw_hdmi_platform_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &hdmi_ops);
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static int dw_hdmi_platform_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &hdmi_ops);
return 0;
}
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data)
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
{
- struct imx_hdmi *hdmi;
+ struct dw_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1628,17 +1628,18 @@ int imx_hdmi_platform_register(struct platform_device *pdev,
platform_set_drvdata(pdev, hdmi);
- return imx_hdmi_platform_probe(pdev);
+ return dw_hdmi_platform_probe(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_register);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-int imx_hdmi_platform_unregister(struct platform_device *pdev)
+int dw_hdmi_platform_unregister(struct platform_device *pdev)
{
- return imx_hdmi_platform_remove(pdev);
+ return dw_hdmi_platform_remove(pdev);
}
-EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
similarity index 97%
rename from drivers/staging/imx-drm/imx-hdmi.h
rename to drivers/gpu/drm/bridge/dw_hdmi.h
index dba45c1..b8412a9 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -7,8 +7,8 @@
* (at your option) any later version.
*/
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
+#ifndef __DW_HDMI__
+#define __DW_HDMI__
/* Identification Registers */
#define HDMI_DESIGN_ID 0x0000
@@ -1030,53 +1030,4 @@ enum {
HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
};
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-struct sym_term {
- unsigned long mpixelclock;
- u16 sym_ctr; /*clock symbol and transmitter control*/
- u16 term; /*transmission termination value*/
-};
-
-struct imx_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
- const struct mpll_config *mpll_cfg;
- const struct curr_ctrl *cur_ctr;
- const struct sym_term *sym_term;
- enum imx_hdmi_devtype dev_type;
-
-};
-
-int imx_hdmi_platform_register(struct platform_device *pdev,
- const struct imx_hdmi_plat_data *plat_data);
-int imx_hdmi_platform_unregister(struct platform_device *pdev);
#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index ab31848..560e1d3 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -50,5 +50,6 @@ config DRM_IMX_IPUV3
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
depends on DRM_IMX
+ select DRM_DW_HDMI
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 809027d..f3ecd89 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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 dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 7154c96..375d40c 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -10,14 +10,14 @@
#include <linux/platform_device.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 <linux/clk.h>
#include "imx-drm.h"
-#include "imx-hdmi.h"
-struct imx_hdmi_priv {
+struct imx_hdmi {
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -75,7 +75,7 @@ static const struct sym_term imx_sym_term[] = {
{ ~0UL, 0x0000, 0x0000 }
};
-static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
+static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
@@ -100,9 +100,9 @@ static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi)
return 0;
}
-static void *imx_hdmi_imx_setup(struct platform_device *pdev)
+static void *dw_hdmi_imx_setup(struct platform_device *pdev)
{
- struct imx_hdmi_priv *hdmi;
+ struct imx_hdmi *hdmi;
int ret;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -110,7 +110,7 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return ERR_PTR(-ENOMEM);
hdmi->dev = &pdev->dev;
- ret = imx_hdmi_parse_dt(hdmi);
+ ret = dw_hdmi_imx_parse_dt(hdmi);
if (ret < 0)
return ERR_PTR(ret);
ret = clk_prepare_enable(hdmi->isfr_clk);
@@ -130,18 +130,18 @@ static void *imx_hdmi_imx_setup(struct platform_device *pdev)
return hdmi;
}
-static void imx_hdmi_imx_exit(void *priv)
+static void dw_hdmi_imx_exit(void *priv)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
clk_disable_unprepare(hdmi->isfr_clk);
clk_disable_unprepare(hdmi->iahb_clk);
}
-static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
{
- struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv;
+ struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
@@ -149,35 +149,35 @@ static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void imx_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
+ struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
-static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.sym_term = imx_sym_term,
.dev_type = IMX6Q_HDMI,
};
-static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = imx_hdmi_imx_setup,
- .exit = imx_hdmi_imx_exit,
- .encoder_commit = imx_hdmi_imx_encoder_commit,
- .encoder_prepare = imx_hdmi_imx_encoder_prepare,
+static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .setup = dw_hdmi_imx_setup,
+ .exit = dw_hdmi_imx_exit,
+ .encoder_commit = dw_hdmi_imx_encoder_commit,
+ .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.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 imx_hdmi_imx_ids[] = {
+static const struct of_device_id dw_hdmi_imx_ids[] = {
{ .compatible = "fsl,imx6q-hdmi",
.data = &imx6q_hdmi_drv_data
}, {
@@ -186,38 +186,38 @@ static const struct of_device_id imx_hdmi_imx_ids[] = {
},
{},
};
-MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids);
+MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int imx_hdmi_imx_probe(struct platform_device *pdev)
+static int dw_hdmi_imx_probe(struct platform_device *pdev)
{
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
if (!pdev->dev.of_node)
return -ENODEV;
- match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node);
+ match = of_match_node(dw_hdmi_imx_ids, pdev->dev.of_node);
plat_data = match->data;
- return imx_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_platform_register(pdev, plat_data);
}
-static int imx_hdmi_imx_remove(struct platform_device *pdev)
+static int dw_hdmi_imx_remove(struct platform_device *pdev)
{
- return imx_hdmi_platform_unregister(pdev);
+ return dw_hdmi_platform_unregister(pdev);
}
-static struct platform_driver imx_hdmi_imx_platform_driver = {
- .probe = imx_hdmi_imx_probe,
- .remove = imx_hdmi_imx_remove,
+static struct platform_driver dw_hdmi_imx_platform_driver = {
+ .probe = dw_hdmi_imx_probe,
+ .remove = dw_hdmi_imx_remove,
.driver = {
.name = "dwhdmi-imx",
.owner = THIS_MODULE,
- .of_match_table = imx_hdmi_imx_ids,
+ .of_match_table = dw_hdmi_imx_ids,
},
};
-module_platform_driver(imx_hdmi_imx_platform_driver);
+module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..bb98f1a
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __DW_HDMI_H__
+#define __DW_HDMI_H__
+
+#include <drm/drmP.h>
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum dw_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct sym_term {
+ unsigned long mpixelclock;
+ u16 sym_ctr; /*clock symbol and transmitter control*/
+ u16 term; /*transmission termination value*/
+};
+
+struct dw_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
+ void (*encoder_prepare)(struct drm_connector *connector,
+ struct drm_encoder *encoder);
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ const struct sym_term *sym_term;
+ enum dw_hdmi_devtype dev_type;
+
+};
+
+int dw_hdmi_platform_register(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data);
+int dw_hdmi_platform_unregister(struct platform_device *pdev);
+#endif /* __IMX_HDMI_H__ */
--
1.9.1
From: Yakir Yang <[email protected]>
keep the connector & birdge in dw_hdmi.c, handle encoder
in dw_hdmi-imx.c, as most of the encoder operation are
platform specific such as crtc select and panel format
set
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification from patch#5
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 228 +++++++++++++++-------------------
drivers/staging/imx-drm/dw_hdmi-imx.c | 143 ++++++++++++++-------
include/drm/bridge/dw_hdmi.h | 13 +-
3 files changed, 198 insertions(+), 186 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 1a9026b..08b56ea 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -11,7 +11,6 @@
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
-#include <linux/component.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -103,7 +102,8 @@ struct hdmi_data_info {
struct dw_hdmi {
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
enum dw_hdmi_devtype dev_type;
struct device *dev;
@@ -1299,6 +1299,50 @@ static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
dw_hdmi_phy_disable(hdmi);
}
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_setup(hdmi, mode);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweroff(hdmi);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweron(hdmi);
+}
+
+static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge)
+{
+ drm_bridge_cleanup(bridge);
+ kfree(bridge);
+}
+
+static void dw_hdmi_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
static enum drm_connector_status dw_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
@@ -1340,60 +1384,7 @@ static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
- return &hdmi->encoder;
-}
-
-static void dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_setup(hdmi, mode);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool dw_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void dw_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void dw_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (mode)
- dw_hdmi_poweroff(hdmi);
- else
- dw_hdmi_poweron(hdmi);
-}
-
-static void dw_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- dw_hdmi_poweroff(hdmi);
-
- if (hdmi->plat_data->encoder_prepare)
- hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder);
-}
-
-static void dw_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
- struct dw_hdmi *hdmi = container_of(encoder, struct dw_hdmi, encoder);
-
- if (hdmi->plat_data->encoder_commit)
- hdmi->plat_data->encoder_commit(hdmi->priv, encoder);
-
- dw_hdmi_poweron(hdmi);
+ return hdmi->encoder;
}
void dw_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1402,19 +1393,6 @@ void dw_hdmi_connector_destroy(struct drm_connector *connector)
drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs dw_hdmi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static struct drm_encoder_helper_funcs dw_hdmi_encoder_helper_funcs = {
- .dpms = dw_hdmi_encoder_dpms,
- .prepare = dw_hdmi_encoder_prepare,
- .commit = dw_hdmi_encoder_commit,
- .mode_set = dw_hdmi_encoder_mode_set,
- .mode_fixup = dw_hdmi_encoder_mode_fixup,
- .disable = dw_hdmi_encoder_disable,
-};
-
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
@@ -1427,6 +1405,16 @@ static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.best_encoder = dw_hdmi_connector_best_encoder,
};
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .enable = dw_hdmi_bridge_enable,
+ .disable = dw_hdmi_bridge_disable,
+ .pre_enable = dw_hdmi_bridge_nope,
+ .post_disable = dw_hdmi_bridge_nope,
+ .mode_set = dw_hdmi_bridge_mode_set,
+ .mode_fixup = dw_hdmi_bridge_mode_fixup,
+ .destroy = dw_hdmi_bridge_destroy,
+};
+
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
@@ -1475,39 +1463,63 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
- struct drm_encoder *encoder = &hdmi->encoder;
- struct device *dev = hdmi->dev;
+ struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_bridge *bridge;
+ int ret;
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("Failed to allocate drm bridge\n");
+ return -ENOMEM;
+ }
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ hdmi->bridge = bridge;
+ bridge->driver_private = hdmi;
- drm_encoder_helper_add(&hdmi->encoder, &dw_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &dw_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
- hdmi->connector.encoder = &hdmi->encoder;
+ hdmi->connector.encoder = encoder;
- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
return 0;
}
-static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
- struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct resource *iores;
+ struct dw_hdmi *hdmi;
int ret, irq;
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+ hdmi->encoder = encoder;
+
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1537,8 +1549,6 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
- if (hdmi->plat_data->setup)
- hdmi->priv = hdmi->plat_data->setup(pdev);
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1579,9 +1589,9 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
return 0;
}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-static void dw_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1589,57 +1599,15 @@ static void dw_hdmi_unbind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
- if (hdmi->plat_data->exit)
- hdmi->plat_data->exit(hdmi->priv);
- i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
- .bind = dw_hdmi_bind,
- .unbind = dw_hdmi_unbind,
-};
-
-static int dw_hdmi_platform_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int dw_hdmi_platform_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &hdmi_ops);
- return 0;
-}
-
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data)
-{
- struct dw_hdmi *hdmi;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->plat_data = plat_data;
- hdmi->dev = &pdev->dev;
- hdmi->dev_type = plat_data->dev_type;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
+ hdmi->encoder->funcs->destroy(hdmi->encoder);
- platform_set_drvdata(pdev, hdmi);
-
- return dw_hdmi_platform_probe(pdev);
-}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_register);
-
-int dw_hdmi_platform_unregister(struct platform_device *pdev)
-{
- return dw_hdmi_platform_remove(pdev);
+ i2c_put_adapter(hdmi->ddc);
}
-EXPORT_SYMBOL_GPL(dw_hdmi_platform_unregister);
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index 375d40c..01c7265 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -8,12 +8,19 @@
*/
#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 <linux/clk.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 "imx-drm.h"
@@ -22,6 +29,7 @@ struct imx_hdmi {
struct clk *isfr_clk;
struct clk *iahb_clk;
struct regmap *regmap;
+ struct drm_encoder encoder;
};
static const struct mpll_config imx_mpll_cfg[] = {
@@ -100,48 +108,26 @@ static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
return 0;
}
-static void *dw_hdmi_imx_setup(struct platform_device *pdev)
+static void dw_hdmi_imx_disable(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi;
- int ret;
-
- hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return ERR_PTR(-ENOMEM);
- hdmi->dev = &pdev->dev;
-
- ret = dw_hdmi_imx_parse_dt(hdmi);
- if (ret < 0)
- return ERR_PTR(ret);
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- return ERR_PTR(ret);
- }
-
- return hdmi;
}
-static void dw_hdmi_imx_exit(void *priv)
+static bool dw_hdmi_imx_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
-
- clk_disable_unprepare(hdmi->isfr_clk);
+ return true;
+}
- clk_disable_unprepare(hdmi->iahb_clk);
+static void dw_hdmi_imx_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
}
-static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
+static void dw_hdmi_imx_commit(struct drm_encoder *encoder)
{
- struct imx_hdmi *hdmi = (struct imx_hdmi *)priv;
+ 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,
@@ -149,17 +135,24 @@ static void dw_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder)
mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
}
-static void dw_hdmi_imx_encoder_prepare(struct drm_connector *connector,
- struct drm_encoder *encoder)
+static void dw_hdmi_imx_prepare(struct drm_encoder *encoder)
{
imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
}
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_imx_mode_fixup,
+ .mode_set = dw_hdmi_imx_mode_set,
+ .prepare = dw_hdmi_imx_prepare,
+ .commit = dw_hdmi_imx_commit,
+ .disable = dw_hdmi_imx_disable,
+};
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.sym_term = imx_sym_term,
@@ -167,10 +160,6 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
};
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
- .setup = dw_hdmi_imx_setup,
- .exit = dw_hdmi_imx_exit,
- .encoder_commit = dw_hdmi_imx_encoder_commit,
- .encoder_prepare = dw_hdmi_imx_encoder_prepare,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.sym_term = imx_sym_term,
@@ -188,23 +177,82 @@ static const struct of_device_id dw_hdmi_imx_ids[] = {
};
MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
-static int dw_hdmi_imx_probe(struct platform_device *pdev)
+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;
+ 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_ids, pdev->dev.of_node);
plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = dw_hdmi_imx_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
- return dw_hdmi_platform_register(pdev, plat_data);
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+ clk_disable_unprepare(hdmi->iahb_clk);
+
+ 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)
{
- return dw_hdmi_platform_unregister(pdev);
+ component_del(&pdev->dev, &dw_hdmi_imx_ops);
+
+ return 0;
}
static struct platform_driver dw_hdmi_imx_platform_driver = {
@@ -220,6 +268,7 @@ static struct platform_driver dw_hdmi_imx_platform_driver = {
module_platform_driver(dw_hdmi_imx_platform_driver);
MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index bb98f1a..1e618f3 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -44,21 +44,16 @@ struct sym_term {
};
struct dw_hdmi_plat_data {
- void * (*setup)(struct platform_device *pdev);
- void (*exit)(void *priv);
- void (*encoder_commit)(void *priv, struct drm_encoder *encoder);
- void (*encoder_prepare)(struct drm_connector *connector,
- struct drm_encoder *encoder);
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
const struct sym_term *sym_term;
enum dw_hdmi_devtype dev_type;
-
};
-int dw_hdmi_platform_register(struct platform_device *pdev,
- const struct dw_hdmi_plat_data *plat_data);
-int dw_hdmi_platform_unregister(struct platform_device *pdev);
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data);
#endif /* __IMX_HDMI_H__ */
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
new file mode 100644
index 0000000..0558442
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
@@ -0,0 +1,40 @@
+DesignWare HDMI bridge bindings
+
+Required properities:
+- compatible: platform specific such as:
+ * "fsl,imx6q-hdmi"
+ * "fsl,imx6dl-hdmi"
+ * "rockchip,rk3288-dw-hdmi"
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- interrupts: The HDMI interrupt number
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+
+Example:
+ hdmi: hdmi@0120000 {
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
--
1.9.1
On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width accesses (writeb,
readb) generate an imprecise external abort.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4: None
Changes in v3:
- split multi-register access to one indepent patch
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 57 +++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 08b56ea..24a66ff 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -100,6 +100,11 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
+union dw_reg_ptr {
+ u32 __iomem *p32;
+ u8 __iomem *p8;
+};
+
struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder *encoder;
@@ -121,20 +126,43 @@ struct dw_hdmi {
struct regmap *regmap;
struct i2c_adapter *ddc;
- void __iomem *regs;
+ union dw_reg_ptr regs;
unsigned int sample_rate;
int ratio;
+
+ void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+ u8 (*read)(struct dw_hdmi *hdmi, int offset);
};
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writel(val, hdmi->regs.p32 + offset);
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs.p32 + offset);
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writeb(val, hdmi->regs.p8 + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return readb(hdmi->regs.p8 + offset);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(hdmi, val, offset);
}
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi, offset);
}
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
@@ -1508,6 +1536,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
struct resource *iores;
struct dw_hdmi *hdmi;
int ret, irq;
+ u32 val = 1;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1520,6 +1549,22 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->ratio = 100;
hdmi->encoder = encoder;
+ of_property_read_u32(np, "reg-io-width", &val);
+
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ break;
+ case 1:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return -EINVAL;
+ }
+
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1545,9 +1590,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
+ hdmi->regs.p32 = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs.p32))
+ return PTR_ERR(hdmi->regs.p32);
/* Product and revision IDs */
dev_info(dev,
--
1.9.1
some platform may not support all the display mode,
add mode_valid interface check it
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 24a66ff..e94f6bb 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -1406,6 +1406,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = container_of(connector,
+ struct dw_hdmi, connector);
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (hdmi->plat_data->mode_valid)
+ mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1430,6 +1444,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
+ .mode_valid = dw_hdmi_connector_mode_valid,
.best_encoder = dw_hdmi_connector_best_encoder,
};
@@ -1632,6 +1647,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
dev_set_drvdata(dev, hdmi);
+ drm_connector_register(&hdmi->connector);
+
return 0;
}
EXPORT_SYMBOL_GPL(dw_hdmi_bind);
--
1.9.1
HDMI_IH_I2CMPHY_STAT0 is a clear on write register, which indicates i2cm
operation status(i2c transfer done or error), every hdmi phy register
configuration must check this register to make sure the configuration
has complete. But the indication bit should be cleared after check, otherwise
the corresponding bit will hold on forever, this may give a wrong signal for
next check.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11:
- split form patch <dw_hdmi: add rk3288 support>
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index e94f6bb..d5d5207 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -668,11 +668,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ u32 val;
+
+ while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
udelay(1000);
}
+ hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
return true;
}
--
1.9.1
RK3288 HDMI will not work without the spare bit of
HDMI_PHY_CONF0 enable
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11:
- split from patch <dw_hdmi: add rk3288 support>
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 7 +++++++
drivers/gpu/drm/bridge/dw_hdmi.h | 3 ++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index d5d5207..87f0327 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_ENTMDS_MASK);
}
+static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SPARECTRL_OFFSET,
+ HDMI_PHY_CONF0_SPARECTRL_MASK);
+}
+
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
index b8412a9..30a6b28 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -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,
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8:
- Add documentation for rockchip dw hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
new file mode 100644
index 0000000..6ea6764
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
@@ -0,0 +1,43 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: physical base address of the controller and length
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks: from common clock binding: handle to hdmi clock.
+- clock-names: should be "clk" "hdcp_clk"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt. For
+ vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+ rk3288 platform
+
+Example:
+hdmi: hdmi@ff980000 {
+ compatible = "rockchip,rk3288-dw-hdmi";
+ reg = <0xff980000 0x20000>;
+ reg-io-width = <4>;
+ ddc-i2c-bus = <&i2c5>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+ clock-names = "clk", "hdcp_clk";
+ status = "disabled";
+ ports {
+ hdmi_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ hdmi_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_hdmi>;
+ };
+ hdmi_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_hdmi>;
+ };
+ };
+ };
+};
--
1.9.1
Rockchip RK3288 hdmi is compatible with dw_hdmi
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v11: None
Changes in v10:
- add more display mode support mpll configuration for rk3288
Changes in v9:
- move some phy configuration to platform driver
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 3 +
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi.h | 1 +
5 files changed, 370 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 87f0327..5a0a498 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -853,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
+ if (hdmi->dev_type == RK3288_HDMI)
+ dw_hdmi_phy_enable_spare(hdmi, 1);
+
/*Wait for PHY PLL lock */
msec = 5;
do {
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0ff6682..06371ae 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -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
+ bool "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.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index b3a5193..347e65c 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,5 +4,5 @@
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchip_drm_gem.o rockchip_drm_vop.o
-
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 0000000..16cad75
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,355 @@
+/*
+ * 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 <linux/clk.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 clk *clk;
+ struct clk *hdcp_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+
+static const struct 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 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 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);
+ }
+
+ hdmi->clk = devm_clk_get(hdmi->dev, "clk");
+ if (IS_ERR(hdmi->clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI clk\n");
+ return PTR_ERR(hdmi->clk);
+ }
+
+ hdmi->hdcp_clk = devm_clk_get(hdmi->dev, "hdcp_clk");
+ if (IS_ERR(hdmi->hdcp_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI hdcp clk\n");
+ return PTR_ERR(hdmi->hdcp_clk);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct 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_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_rockchip_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_rockchip_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void dw_hdmi_rockchip_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_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_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_rockchip_mode_fixup,
+ .mode_set = dw_hdmi_rockchip_mode_set,
+ .prepare = dw_hdmi_rockchip_prepare,
+ .commit = dw_hdmi_rockchip_commit,
+ .disable = dw_hdmi_rockchip_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_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;
+ 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_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = rockchip_hdmi_parse_dt(hdmi);
+ if (ret) {
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdcp_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI hdcp clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rockchip_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->clk);
+ clk_disable_unprepare(hdmi->hdcp_clk);
+
+ 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",
+ .owner = THIS_MODULE,
+ .of_match_table = dw_hdmi_rockchip_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 1e618f3..33bbae2 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,7 @@ enum {
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
+ RK3288_HDMI,
};
struct mpll_config {
--
1.9.1
On Fri, Nov 14, 2014 at 9:38 PM, Andy Yan <[email protected]> wrote:
> CHECK: Alignment should match open parenthesis
> + if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
> + (hdmi->vic == 12) || (hdmi->vic == 13) ||
>
> CHECK: braces {} should be used on all arms of this statement
> + if (hdmi->hdmi_data.video_mode.mdvi)
> [...]
> + else {
> [...]
>
> Signed-off-by: Andy Yan <[email protected]>
Reviewed-by: Daniel Kurtz <[email protected]>
>
> ---
>
> Changes in v11: None
> Changes in v10: None
> Changes in v9: None
> Changes in v8: None
> Changes in v7: None
> Changes in v6:
> - rearrange the patch order
>
> Changes in v5: None
> Changes in v4:
> - fix checkpatch CHECK
>
> Changes in v3: None
> Changes in v2: None
>
> drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++-------------------
> 1 file changed, 48 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
> index aaec6b2..79daec4 100644
> --- a/drivers/staging/imx-drm/imx-hdmi.c
> +++ b/drivers/staging/imx-drm/imx-hdmi.c
> @@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
> }
>
> static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
> - u8 shift, u8 mask)
> + u8 shift, u8 mask)
> {
> hdmi_modb(hdmi, data << shift, mask, reg);
> }
> @@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
> }
>
> static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
> - unsigned long pixel_clk)
> + unsigned long pixel_clk)
> {
> unsigned int clk_n, clk_cts;
>
> @@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
>
> if (!clk_cts) {
> dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
> - __func__, pixel_clk);
> + __func__, pixel_clk);
> return;
> }
>
> @@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
> u16 coeff_b = (*csc_coeff)[1][i];
> u16 coeff_c = (*csc_coeff)[2][i];
>
> - hdmi_writeb(hdmi, coeff_a & 0xff,
> - HDMI_CSC_COEF_A1_LSB + i * 2);
> + hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
> hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
> hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
> hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
> - hdmi_writeb(hdmi, coeff_c & 0xff,
> - HDMI_CSC_COEF_C1_LSB + i * 2);
> + hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
> hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
> }
>
> @@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
> struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
> u8 val, vp_conf;
>
> - if (hdmi_data->enc_out_format == RGB
> - || hdmi_data->enc_out_format == YCBCR444) {
> - if (!hdmi_data->enc_color_depth)
> + if (hdmi_data->enc_out_format == RGB ||
> + hdmi_data->enc_out_format == YCBCR444) {
> + if (!hdmi_data->enc_color_depth) {
> output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
> - else if (hdmi_data->enc_color_depth == 8) {
> + } else if (hdmi_data->enc_color_depth == 8) {
> color_depth = 4;
> output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
> - } else if (hdmi_data->enc_color_depth == 10)
> + } else if (hdmi_data->enc_color_depth == 10) {
> color_depth = 5;
> - else if (hdmi_data->enc_color_depth == 12)
> + } else if (hdmi_data->enc_color_depth == 12) {
> color_depth = 6;
> - else if (hdmi_data->enc_color_depth == 16)
> + } else if (hdmi_data->enc_color_depth == 16) {
> color_depth = 7;
> - else
> + } else {
> return;
> + }
> } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
> if (!hdmi_data->enc_color_depth ||
> hdmi_data->enc_color_depth == 8)
> @@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
> else
> return;
> output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
> - } else
> + } else {
> return;
> + }
>
> /* set the packetizer registers */
> val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
> @@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
> }
>
> static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
> - unsigned char bit)
> + unsigned char bit)
> {
> hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
> HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
> }
>
> static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
> - unsigned char bit)
> + unsigned char bit)
> {
> hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
> HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
> }
>
> static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
> - unsigned char bit)
> + unsigned char bit)
> {
> hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
> HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
> }
>
> static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
> - unsigned char bit)
> + unsigned char bit)
> {
> hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
> }
>
> static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
> - unsigned char bit)
> + unsigned char bit)
> {
> hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
> }
> @@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
> }
>
> static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
> - unsigned char addr)
> + unsigned char addr)
> {
> hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
> hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
> hdmi_writeb(hdmi, (unsigned char)(data >> 8),
> - HDMI_PHY_I2CM_DATAO_1_ADDR);
> + HDMI_PHY_I2CM_DATAO_1_ADDR);
> hdmi_writeb(hdmi, (unsigned char)(data >> 0),
> - HDMI_PHY_I2CM_DATAO_0_ADDR);
> + HDMI_PHY_I2CM_DATAO_0_ADDR);
> hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
> - HDMI_PHY_I2CM_OPERATION_ADDR);
> + HDMI_PHY_I2CM_OPERATION_ADDR);
> hdmi_phy_wait_i2c_done(hdmi, 1000);
> }
>
> static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
> - unsigned char addr)
> + unsigned char addr)
> {
> __hdmi_phy_i2c_write(hdmi, data, addr);
> return 0;
> @@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
>
> hdmi_phy_test_clear(hdmi, 1);
> hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
> - HDMI_PHY_I2CM_SLAVE_ADDR);
> + HDMI_PHY_I2CM_SLAVE_ADDR);
> hdmi_phy_test_clear(hdmi, 0);
>
> /* PLL/MPLL Cfg - always match on final entry */
> @@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
> break;
>
> if (i >= ARRAY_SIZE(curr_ctrl)) {
> - dev_err(hdmi->dev,
> - "Pixel clock %d - unsupported by HDMI\n",
> - hdmi->hdmi_data.video_mode.mpixelclock);
> + dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
> + hdmi->hdmi_data.video_mode.mpixelclock);
> return -EINVAL;
> }
>
> @@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
> }
>
> if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
> - (hdmi->vic == 21) || (hdmi->vic == 22) ||
> - (hdmi->vic == 2) || (hdmi->vic == 3) ||
> - (hdmi->vic == 17) || (hdmi->vic == 18))
> + (hdmi->vic == 21) || (hdmi->vic == 22) ||
> + (hdmi->vic == 2) || (hdmi->vic == 3) ||
> + (hdmi->vic == 17) || (hdmi->vic == 18))
> hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
> else
> hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
>
> if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
> - (hdmi->vic == 12) || (hdmi->vic == 13) ||
> - (hdmi->vic == 14) || (hdmi->vic == 15) ||
> - (hdmi->vic == 25) || (hdmi->vic == 26) ||
> - (hdmi->vic == 27) || (hdmi->vic == 28) ||
> - (hdmi->vic == 29) || (hdmi->vic == 30) ||
> - (hdmi->vic == 35) || (hdmi->vic == 36) ||
> - (hdmi->vic == 37) || (hdmi->vic == 38))
> + (hdmi->vic == 12) || (hdmi->vic == 13) ||
> + (hdmi->vic == 14) || (hdmi->vic == 15) ||
> + (hdmi->vic == 25) || (hdmi->vic == 26) ||
> + (hdmi->vic == 27) || (hdmi->vic == 28) ||
> + (hdmi->vic == 29) || (hdmi->vic == 30) ||
> + (hdmi->vic == 35) || (hdmi->vic == 36) ||
> + (hdmi->vic == 37) || (hdmi->vic == 38))
> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
> else
> hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
> @@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
> imx_hdmi_enable_video_path(hdmi);
>
> /* not for DVI mode */
> - if (hdmi->hdmi_data.video_mode.mdvi)
> + if (hdmi->hdmi_data.video_mode.mdvi) {
> dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
> - else {
> + } else {
> dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
>
> /* HDMI Initialization Step E - Configure audio */
> @@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
> dev_dbg(hdmi->dev, "EVENT=plugout\n");
>
> hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
> - HDMI_PHY_POL0);
> + HDMI_PHY_POL0);
>
> imx_hdmi_poweroff(hdmi);
> }
> @@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
> DRM_MODE_ENCODER_TMDS);
>
> drm_connector_helper_add(&hdmi->connector,
> - &imx_hdmi_connector_helper_funcs);
> + &imx_hdmi_connector_helper_funcs);
> drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
> DRM_MODE_CONNECTOR_HDMIA);
>
> @@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> /* Product and revision IDs */
> dev_info(dev,
> - "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
> - hdmi_readb(hdmi, HDMI_DESIGN_ID),
> - hdmi_readb(hdmi, HDMI_REVISION_ID),
> - hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
> - hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
> + "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
> + hdmi_readb(hdmi, HDMI_DESIGN_ID),
> + hdmi_readb(hdmi, HDMI_REVISION_ID),
> + hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
> + hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
>
> initialize_hdmi_ih_mutes(hdmi);
>
> --
> 1.9.1
>
--
Daniel Kurtz | Software Engineer | [email protected] | 650.204.0722
On Fri, Nov 14, 2014 at 9:39 PM, Andy Yan <[email protected]> wrote:
> drm driver may probe before the i2c bus, so the driver should
> defer probing until it is available
>
> Signed-off-by: Andy Yan <[email protected]>
>
> ---
>
> Changes in v11: None
> Changes in v10: None
> Changes in v9: None
> Changes in v8: None
> Changes in v7: None
> Changes in v6: None
> Changes in v5: None
> Changes in v4:
> - defer probe ddc i2c adapter
>
> Changes in v3: None
> Changes in v2: None
>
> drivers/staging/imx-drm/imx-hdmi.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
> index 79daec4..c2b035a 100644
> --- a/drivers/staging/imx-drm/imx-hdmi.c
> +++ b/drivers/staging/imx-drm/imx-hdmi.c
> @@ -1611,8 +1611,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
> ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
> if (ddc_node) {
> hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
> - if (!hdmi->ddc)
> + if (!hdmi->ddc) {
> dev_dbg(hdmi->dev, "failed to read ddc node\n");
> + of_node_put(ddc_node);
> + return -EPROBE_DEFER;
> + }
Nit: You could move "of_node_put()" above "if (!hdmi->ddc)", and not
need it in two places.
Either way, this one is:
Reviewed-by: Daniel Kurtz <[email protected]>
>
> of_node_put(ddc_node);
> } else {
> --
> 1.9.1
>
--
Daniel Kurtz | Software Engineer | [email protected] | 650.204.0722
On Fri, Nov 14, 2014 at 9:37 PM, Andy Yan <[email protected]> wrote:
>
> We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
> use the interface compatible Designware HDMI IP, but they also have some
> lightly differences, such as phy pll configuration, register width(imx hdmi
> register is one byte, but rk3288 is 4 bytes width and can only be accessed
> by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
> support.
>
> To reuse the imx-hdmi driver, we make this patch set:
> (1): fix some CodingStyle warning to make checkpatch happy
> (2): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
> (3): move imx-hdmi to bridge/dw-hdmi, and convert it to a drm_bridge driver
> (4): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
>
> Changes in v11:
> - rearrange the patch order
> - squash patch <split some phy configuration to platform driver>
> - split some modification form patch <dw_hdmi: add rk3288 support>
>
> Changes in v10:
> - split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
> - add more display mode support mpll configuration for rk3288
>
> Changes in v9:
> - move some phy configuration to platform driver
>
> Changes in v8:
> - correct some spelling mistake
> - modify ddc-i2c-bus and interrupt description
> - Add documentation for rockchip dw hdmi
>
> Changes in v7:
> - remove unused variables from structure dw_hdmi
> - remove a wrong modification
> - add copyrights for dw_hdmi-imx.c
>
> Changes in v6:
> - rearrange the patch order
> - move some modification from patch#5
> - move some modification to patch#6
> - refactor register access without reg_shift
>
> Changes in v5:
> - refactor reg-io-width
>
> Changes in v4:
> - fix checkpatch CHECK
> - defer probe ddc i2c adapter
>
> Changes in v3:
> - split multi-register access to one indepent patch
>
> Changes in v2:
> - use git format -M to generate these patch
>
> Andy Yan (11):
> staging: imx-drm: imx-hdmi: make checkpatch happy
> staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
> staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
> staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
> dt-bindings: add document for dw_hdmi
> drm: bridge/dw_hdmi: add support for multi-byte register width access
> drm: bridge/dw_hdmi: add mode_valid support
> drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done
> drm: bridge/dw_hdmi: add function dw_hdmi_phy_enable_spare
> dt-bindings: Add documentation for rockchip dw hdmi
> drm: bridge/dw_hdmi: add rockchip rk3288 support
>
> Yakir Yang (1):
> drm: bridge/dw_hdmi: convert dw-hdmi to drm_bridge mode
Patch 1 & 2 are:
Reviewed-by: Daniel Kurtz <[email protected]>
I think these first two are ready (or will be, after a small nit fix to #2).
Since they are independent of the imx/dw_hdmi split, can we get them
accepted first, to help shrink Andy's patch set?
Thanks,
-djk
>
> .../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
> .../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
> drivers/gpu/drm/bridge/Kconfig | 5 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> .../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 762 +++++++++------------
> .../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 8 +-
> drivers/gpu/drm/rockchip/Kconfig | 10 +
> drivers/gpu/drm/rockchip/Makefile | 2 +-
> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++
> drivers/staging/imx-drm/Kconfig | 1 +
> drivers/staging/imx-drm/Makefile | 2 +-
> drivers/staging/imx-drm/dw_hdmi-imx.c | 274 ++++++++
> include/drm/bridge/dw_hdmi.h | 60 ++
> 13 files changed, 1138 insertions(+), 425 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
> create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
> rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
> rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
> create mode 100644 include/drm/bridge/dw_hdmi.h
>
> --
> 1.9.1
>
--
Daniel Kurtz | Software Engineer | [email protected] | 650.204.0722
On Fri, Nov 14, 2014 at 7:13 PM, Zubair Lutfullah Kakakhel
<[email protected]> wrote:
>
>
> On 14/11/14 11:08, Andy Yan wrote:
>>
>> On 2014年11月14日 18:55, Zubair Lutfullah Kakakhel wrote:
>>>
>>> On 14/11/14 10:53, Andy Yan wrote:
>>>> Hi ZubairLK:
>>>> Thanks for your review.
>>>> On 2014年11月14日 18:19, Zubair Lutfullah Kakakhel wrote:
>>>>> Hi Andy,
>>>>>
>>>>> Nice work on this patch series. Its getting better and better :).
>>>>>
>>>>> On 14/11/14 03:27, Andy Yan wrote:
>>>>>> hdmi phy clock symbol and transmission termination value
>>>>>> can adjust platform specific to get the best SI
>>>>> ^Is this signal integrity?
>>>> yes , SI is signal integrity, such as eye diagram measurement
>>>>> Are these two disjoint features in separate patches?
>>>>>
>>>>>> also add mode_valid interface for some platform may not support
>>>>>> all the display mode
>>>>> Sounds like another separate patch to me. :)
>>>> they can seperate
>>>>> Also, This series is becoming quite large. With major changes and fixes mixed together.
>>>>>
>>>>> Patch 3 splits imx-drm.
>>>>> Patch 4 moves dw-drm out of imx-drm folder.
>>>>> Patch 7 adds binding
>>>>> Patch 9 converts to drm bridge.
>>>>>
>>>>> Can these be placed together easily?
>>>>> And in the start. i.e. patch 1, 2, 3, 4,
>>>>>
>>>>> Then all fixes etc can come afterwards?
>>>>>
>>>>> It helps when checking histories later as to how a driver was made and how fixes happened.
>>>>>
>>>>> Especially when file moves happen..
>>>> Do you mean we can rearrange the patch series?
>>>> put patch 3, 4 ,7, 9 together one bye one
>>>> than followed by the fixes patches 5 ,6, 8, 11 ?
>>> Yes. Rearrange so that the split imx-drm/imx-hdmi and conversion to drm-bridge is at the start of the series.
>>> Then the rest are bug fixes and feature additions.
>> Can I put patch#1(make checkpatch happy) and patch#2 (defer probe) as the first two patch.
>> Daniel from Google chromium think it's better to put the two slightly changes in the front for easy review.
Sorry, I didn't see this conversation before my earlier emails.
I was suggesting to Andy to arrange his patches like this:
(1) fixes that directly apply to imx-drm as it is today.
(2) split out the "generic dw_hdmi" parts from imx-hdmi into dw_hdmi.c
(3) convert dw_hdmi.c to a drm_bridge
(4) move the dw_hdmi.c bridge implementation to drm/bridge
(5) modifications to dw_hdmi.c required to support hdmi on rk3288
(5) add rk3288-hdmi.c to drm/rockchip (at least whenever drm/rockchip lands)
The idea being that we can start landing the patches for (1) even
while we are still debating / reviewing (2)+ upstream.
> Sure.
>
> I am not the maintainer. They have to make the final decision.
imx-drm is still in staging. I do not see anyone listed explicitly
under MAINTAINERS for drivers/staging/imx-drm, so by default I guess
it falls back to gregkh (drivers/staging/)?
The "Commit" field in git log seems to back this up.
Although, based on Author, I think we also want the opinions of
Philipp Zabel and Russel King.
Thanks,
-djk
>
> ZubairLK
On Sat, Nov 15, 2014 at 06:07:50PM +0800, Daniel Kurtz wrote:
> On Fri, Nov 14, 2014 at 7:13 PM, Zubair Lutfullah Kakakhel
> <[email protected]> wrote:
> >
> >
> > On 14/11/14 11:08, Andy Yan wrote:
> >>
> >> On 2014年11月14日 18:55, Zubair Lutfullah Kakakhel wrote:
> >>>
> >>> On 14/11/14 10:53, Andy Yan wrote:
> >>>> Hi ZubairLK:
> >>>> Thanks for your review.
> >>>> On 2014年11月14日 18:19, Zubair Lutfullah Kakakhel wrote:
> >>>>> Hi Andy,
> >>>>>
> >>>>> Nice work on this patch series. Its getting better and better :).
> >>>>>
> >>>>> On 14/11/14 03:27, Andy Yan wrote:
> >>>>>> hdmi phy clock symbol and transmission termination value
> >>>>>> can adjust platform specific to get the best SI
> >>>>> ^Is this signal integrity?
> >>>> yes , SI is signal integrity, such as eye diagram measurement
> >>>>> Are these two disjoint features in separate patches?
> >>>>>
> >>>>>> also add mode_valid interface for some platform may not support
> >>>>>> all the display mode
> >>>>> Sounds like another separate patch to me. :)
> >>>> they can seperate
> >>>>> Also, This series is becoming quite large. With major changes and fixes mixed together.
> >>>>>
> >>>>> Patch 3 splits imx-drm.
> >>>>> Patch 4 moves dw-drm out of imx-drm folder.
> >>>>> Patch 7 adds binding
> >>>>> Patch 9 converts to drm bridge.
> >>>>>
> >>>>> Can these be placed together easily?
> >>>>> And in the start. i.e. patch 1, 2, 3, 4,
> >>>>>
> >>>>> Then all fixes etc can come afterwards?
> >>>>>
> >>>>> It helps when checking histories later as to how a driver was made and how fixes happened.
> >>>>>
> >>>>> Especially when file moves happen..
> >>>> Do you mean we can rearrange the patch series?
> >>>> put patch 3, 4 ,7, 9 together one bye one
> >>>> than followed by the fixes patches 5 ,6, 8, 11 ?
> >>> Yes. Rearrange so that the split imx-drm/imx-hdmi and conversion to drm-bridge is at the start of the series.
> >>> Then the rest are bug fixes and feature additions.
> >> Can I put patch#1(make checkpatch happy) and patch#2 (defer probe) as the first two patch.
> >> Daniel from Google chromium think it's better to put the two slightly changes in the front for easy review.
>
> Sorry, I didn't see this conversation before my earlier emails.
>
> I was suggesting to Andy to arrange his patches like this:
> (1) fixes that directly apply to imx-drm as it is today.
> (2) split out the "generic dw_hdmi" parts from imx-hdmi into dw_hdmi.c
> (3) convert dw_hdmi.c to a drm_bridge
> (4) move the dw_hdmi.c bridge implementation to drm/bridge
> (5) modifications to dw_hdmi.c required to support hdmi on rk3288
> (5) add rk3288-hdmi.c to drm/rockchip (at least whenever drm/rockchip lands)
>
> The idea being that we can start landing the patches for (1) even
> while we are still debating / reviewing (2)+ upstream.
>
> > Sure.
> >
> > I am not the maintainer. They have to make the final decision.
>
> imx-drm is still in staging. I do not see anyone listed explicitly
> under MAINTAINERS for drivers/staging/imx-drm, so by default I guess
> it falls back to gregkh (drivers/staging/)?
> The "Commit" field in git log seems to back this up.
>
> Although, based on Author, I think we also want the opinions of
> Philipp Zabel and Russel King.
Once the wranglings on the patch series are complete, I do intend to test
it on the platforms I have - and remember that I do have the ALSA based
audio and CEC bits as well, some of which will probably need a little bit
of re-work.
All in all, I welcome the renaming of this to include a reference to
DesignWare - I've always thought it's a mistake that the HDMI interface
in iMX6 was not named with a "dw" prefix as the docs contain references
to it being a DesignWare IP module.
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
On Sat, Nov 15, 2014 at 10:12:18AM +0000, Russell King - ARM Linux wrote:
> Once the wranglings on the patch series are complete, I do intend to test
> it on the platforms I have - and remember that I do have the ALSA based
> audio and CEC bits as well, some of which will probably need a little bit
> of re-work.
>
> All in all, I welcome the renaming of this to include a reference to
> DesignWare - I've always thought it's a mistake that the HDMI interface
> in iMX6 was not named with a "dw" prefix as the docs contain references
> to it being a DesignWare IP module.
One thing I would ask is that the subsequent submissions do not thread
onto the previous submission.
It may seem a good idea (people claim that it allows the previous reviews
to be trivially found) but these people forget an important side effect
from this behaviour - when looking at the message index in a threaded
mail reader (like mutt), each reply to a thread moves the subject line
by three characters to the right. What this means is that after about
five or six iterations of the submission, there is no longer any subject
line visible.
Moreover, it means that with lesser iterations, it becomes much more
difficult to see /any/ of the review thread structure.
I would suggest that if you do want to "connect" the subsequent
submissions, please use the same reference message for each submission.
In other words, rather than:
v1 0/2
+-> v1 1/2
+-> v1 2/2
+-> v2 0/2
+-> v2 1/2
+-> v2 2/2
+-> v3 0/2
+-> v3 1/2
+-> v3 2/2
...
This is done instead:
v1 0/2
+-> v1 1/2
+-> v1 2/2
+-> v2 0/2
| +-> v2 1/2
| +-> v2 2/2
+-> v3 0/2
| +-> v3 1/2
| +-> v3 2/2
...
which is a compromise between threading the messages together, and
keeping stopping the thread pushing the subject line completely off
the right hand side of the screen.
In this case, I'd suggest a reference of:
[email protected]
which is the v8 covering message which started this big thread.
Thanks.
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
On 2014年11月15日 13:41, Daniel Kurtz wrote:
> On Fri, Nov 14, 2014 at 9:39 PM, Andy Yan <[email protected]> wrote:
>> drm driver may probe before the i2c bus, so the driver should
>> defer probing until it is available
>>
>> Signed-off-by: Andy Yan <[email protected]>
>>
>> ---
>>
>> Changes in v11: None
>> Changes in v10: None
>> Changes in v9: None
>> Changes in v8: None
>> Changes in v7: None
>> Changes in v6: None
>> Changes in v5: None
>> Changes in v4:
>> - defer probe ddc i2c adapter
>>
>> Changes in v3: None
>> Changes in v2: None
>>
>> drivers/staging/imx-drm/imx-hdmi.c | 5 ++++-
>> 1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
>> index 79daec4..c2b035a 100644
>> --- a/drivers/staging/imx-drm/imx-hdmi.c
>> +++ b/drivers/staging/imx-drm/imx-hdmi.c
>> @@ -1611,8 +1611,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
>> ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
>> if (ddc_node) {
>> hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
>> - if (!hdmi->ddc)
>> + if (!hdmi->ddc) {
>> dev_dbg(hdmi->dev, "failed to read ddc node\n");
>> + of_node_put(ddc_node);
>> + return -EPROBE_DEFER;
>> + }
> Nit: You could move "of_node_put()" above "if (!hdmi->ddc)", and not
> need it in two places.
thanks, I will take your advice
>
> Either way, this one is:
> Reviewed-by: Daniel Kurtz <[email protected]>
>
>> of_node_put(ddc_node);
>> } else {
>> --
>> 1.9.1
>>
>
>
We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they also have some
lightly differences, such as phy pll configuration, register width(imx hdmi
register is one byte, but rk3288 is 4 bytes width and can only be accessed
by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
support.
To reuse the imx-hdmi driver, we make this patch set:
(1): fix some CodingStyle warning to make checkpatch happy
(2): convert imx-hdmi to drm_bridge
(3): move imx-hdmi to bridge/dw_hdmi, and split platform specific code
(4): extend dw_hdmi.c to support rk3288 hdmi
(5): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
Changes in v12:
- refactor of_node_put(ddc_node)
- squash patch <convert dw_hdmi to drm_bridge> & <split imx soc specific code from imx-hdmi>
- add comment for the depend on patch
Changes in v11:
- squash patch <split some phy configuration to platform driver>
- split form patch <dw_hdmi: add rk3288 support>
- split from patch <dw_hdmi: add rk3288 support>
Changes in v10:
- split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
- add more display mode support mpll configuration for rk3288
Changes in v9:
- move some phy configuration to platform driver
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
- Add documentation for rockchip dw hdmi
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6:
- rearrange the patch order
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4:
- fix checkpatch CHECK
- defer probe ddc i2c adapter
Changes in v3:
- split multi-register access to one indepent patch
Changes in v2:
- use git format -M to generate these patch
Andy Yan (11):
staging: imx-drm: imx-hdmi: make checkpatch happy
staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
staging: imx-drm: imx-hdmi: convert imx-hdmi to drm_bridge mode
staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
dt-bindings: add document for dw_hdmi
drm: bridge/dw_hdmi: add support for multi-byte register width access
drm: bridge/dw_hdmi: add mode_valid support
drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done
drm: bridge/dw_hdmi: add function dw_hdmi_phy_enable_spare
dt-bindings: Add documentation for rockchip dw hdmi
drm: bridge/dw_hdmi: add rockchip rk3288 support
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 767 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 7 +-
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 274 ++++++++
include/drm/bridge/dw_hdmi.h | 60 ++
13 files changed, 1139 insertions(+), 428 deletions(-)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h
--
1.9.1
CHECK: Alignment should match open parenthesis
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
CHECK: braces {} should be used on all arms of this statement
+ if (hdmi->hdmi_data.video_mode.mdvi)
[...]
+ else {
[...]
Signed-off-by: Andy Yan <[email protected]>
Reviewed-by: Daniel Kurtz <[email protected]>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- rearrange the patch order
Changes in v5: None
Changes in v4:
- fix checkpatch CHECK
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 49 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index aaec6b2..79daec4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
}
static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+ u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}
static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
- unsigned long pixel_clk)
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
+ __func__, pixel_clk);
return;
}
@@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
u16 coeff_b = (*csc_coeff)[1][i];
u16 coeff_c = (*csc_coeff)[2][i];
- hdmi_writeb(hdmi, coeff_a & 0xff,
- HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_c & 0xff,
- HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}
@@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
- if (hdmi_data->enc_out_format == RGB
- || hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth)
+ if (hdmi_data->enc_out_format == RGB ||
+ hdmi_data->enc_out_format == YCBCR444) {
+ if (!hdmi_data->enc_color_depth) {
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- else if (hdmi_data->enc_color_depth == 8) {
+ } else if (hdmi_data->enc_color_depth == 8) {
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10)
+ } else if (hdmi_data->enc_color_depth == 10) {
color_depth = 5;
- else if (hdmi_data->enc_color_depth == 12)
+ } else if (hdmi_data->enc_color_depth == 12) {
color_depth = 6;
- else if (hdmi_data->enc_color_depth == 16)
+ } else if (hdmi_data->enc_color_depth == 16) {
color_depth = 7;
- else
+ } else {
return;
+ }
} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
if (!hdmi_data->enc_color_depth ||
hdmi_data->enc_color_depth == 8)
@@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
else
return;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
- } else
+ } else {
return;
+ }
/* set the packetizer registers */
val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
@@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
}
static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
@@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
}
static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 8),
- HDMI_PHY_I2CM_DATAO_1_ADDR);
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 0),
- HDMI_PHY_I2CM_DATAO_0_ADDR);
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
- HDMI_PHY_I2CM_OPERATION_ADDR);
+ HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
@@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 1);
hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
+ HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
@@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
break;
if (i >= ARRAY_SIZE(curr_ctrl)) {
- dev_err(hdmi->dev,
- "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
+ dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
@@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
- (hdmi->vic == 21) || (hdmi->vic == 22) ||
- (hdmi->vic == 2) || (hdmi->vic == 3) ||
- (hdmi->vic == 17) || (hdmi->vic == 18))
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
else
hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
- (hdmi->vic == 12) || (hdmi->vic == 13) ||
- (hdmi->vic == 14) || (hdmi->vic == 15) ||
- (hdmi->vic == 25) || (hdmi->vic == 26) ||
- (hdmi->vic == 27) || (hdmi->vic == 28) ||
- (hdmi->vic == 29) || (hdmi->vic == 30) ||
- (hdmi->vic == 35) || (hdmi->vic == 36) ||
- (hdmi->vic == 37) || (hdmi->vic == 38))
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
else
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
@@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
imx_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi)
+ if (hdmi->hdmi_data.video_mode.mdvi) {
dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- else {
+ } else {
dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
/* HDMI Initialization Step E - Configure audio */
@@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
+ HDMI_PHY_POL0);
imx_hdmi_poweroff(hdmi);
}
@@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS);
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
+ &imx_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
/* Product and revision IDs */
dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(hdmi, HDMI_DESIGN_ID),
+ hdmi_readb(hdmi, HDMI_REVISION_ID),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
initialize_hdmi_ih_mutes(hdmi);
--
1.9.1
drm driver may probe before the i2c bus, so the driver should
defer probing until it is available
Signed-off-by: Andy Yan <[email protected]>
Reviewed-by: Daniel Kurtz <[email protected]>
---
Changes in v12:
- refactor of_node_put(ddc_node)
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4:
- defer probe ddc i2c adapter
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 79daec4..8029a07 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1611,10 +1611,12 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- if (!hdmi->ddc)
+ of_node_put(ddc_node);
+ if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
+ return -EPROBE_DEFER;
+ }
- of_node_put(ddc_node);
} else {
dev_dbg(hdmi->dev, "no ddc property found\n");
}
--
1.9.1
IMX6 and Rockchip RK3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly differences, such as phy pll configuration,
register width, 4K support, clk useage, and the crtc mux configuration
is also platform specific.
To reuse the imx hdmi driver, convert it to drm_bridge
Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
Changes in v12:
- squash patch <convert dw_hdmi to drm_bridge>
Changes in v11:
- squash patch <split some phy configuration to platform driver>
Changes in v10:
- split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
Changes in v9: None
Changes in v8: None
Changes in v7:
- remove unused variables from structure dw_hdmi
- remove a wrong modification
- add copyrights for dw_hdmi-imx.c
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/staging/imx-drm/imx-hdmi.c | 498 +++++++++++++++++++++++--------------
1 file changed, 314 insertions(+), 184 deletions(-)
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 8029a07..c42da29 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -23,6 +23,7 @@
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.h>
+#include <drm/drm_of.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
@@ -111,16 +112,24 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
+struct imx_hdmi_plat_data {
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ const struct sym_term *sym_term;
+ enum imx_hdmi_devtype dev_type;
+};
+
struct imx_hdmi {
struct drm_connector connector;
- struct drm_encoder encoder;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
enum imx_hdmi_devtype dev_type;
struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
struct hdmi_data_info hdmi_data;
+ const struct imx_hdmi_plat_data *plat_data;
+ void *priv;
int vic;
u8 edid[HDMI_EDID_LEN];
@@ -137,12 +146,13 @@ struct imx_hdmi {
int ratio;
};
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
+struct imx_hdmi_priv {
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
{
@@ -743,7 +753,7 @@ struct mpll_config {
} res[RES_MAX];
};
-static const struct mpll_config mpll_config[] = {
+static const struct mpll_config imx_mpll_cfg[] = {
{
45250000, {
{ 0x01e0, 0x0000 },
@@ -776,7 +786,7 @@ struct curr_ctrl {
u16 curr[RES_MAX];
};
-static const struct curr_ctrl curr_ctrl[] = {
+static const struct curr_ctrl imx_cur_ctr[] = {
/* pixelclk bpp8 bpp10 bpp12 */
{
54000000, { 0x091c, 0x091c, 0x06dc },
@@ -793,11 +803,26 @@ static const struct curr_ctrl curr_ctrl[] = {
}
};
+struct sym_term {
+ unsigned long mpixelclock;
+ u16 sym_ctr; /*clock symbol and transmitter control*/
+ u16 term; /*transmission termination value*/
+};
+
+static const struct sym_term imx_sym_term[] = {
+ /*pixelclk symbol term*/
+ { 148500000, 0x800d, 0x0005 },
+ { ~0UL, 0x0000, 0x0000 }
+};
+
static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
u8 val, msec;
+ const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg;
+ const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr;
+ const struct sym_term *sym_term = hdmi->plat_data->sym_term;
if (prep)
return -EINVAL;
@@ -843,34 +868,41 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_phy_test_clear(hdmi, 0);
/* PLL/MPLL Cfg - always match on final entry */
- for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+ for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config[i].mpixelclock)
+ mpll_cfg[i].mpixelclock)
break;
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);
- for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+ for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl[i].mpixelclock)
+ curr_ctr[i].mpixelclock)
break;
- if (i >= ARRAY_SIZE(curr_ctrl)) {
+ if (curr_ctr[i].mpixelclock == (~0UL)) {
dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
hdmi->hdmi_data.video_mode.mpixelclock);
return -EINVAL;
}
/* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10);
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+
+ for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ sym_term[i].mpixelclock)
+ break;
+
/* RESISTANCE TERM 133Ohm Cfg */
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
/* PREEMP Cgf 0.00 */
- hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
+
/* TX/CK LVL 10 */
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
/* REMOVE CLK TERM */
@@ -1371,6 +1403,50 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
imx_hdmi_phy_disable(hdmi);
}
+static void imx_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct imx_hdmi *hdmi = bridge->driver_private;
+
+ imx_hdmi_setup(hdmi, mode);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool imx_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void imx_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct imx_hdmi *hdmi = bridge->driver_private;
+
+ imx_hdmi_poweroff(hdmi);
+}
+
+static void imx_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct imx_hdmi *hdmi = bridge->driver_private;
+
+ imx_hdmi_poweron(hdmi);
+}
+
+static void imx_hdmi_bridge_destroy(struct drm_bridge *bridge)
+{
+ drm_bridge_cleanup(bridge);
+ kfree(bridge);
+}
+
+static void imx_hdmi_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
*connector, bool force)
{
@@ -1412,78 +1488,20 @@ static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
connector);
- return &hdmi->encoder;
-}
-
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
- imx_hdmi_setup(hdmi, mode);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
- if (mode)
- imx_hdmi_poweroff(hdmi);
- else
- imx_hdmi_poweron(hdmi);
-}
-
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
- imx_hdmi_poweroff(hdmi);
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+ return hdmi->encoder;
}
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+static void imx_hdmi_connector_destroy(struct drm_connector *connector)
{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
- int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
-
- imx_hdmi_set_ipu_di_mux(hdmi, mux);
-
- imx_hdmi_poweron(hdmi);
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
}
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .dpms = imx_hdmi_encoder_dpms,
- .prepare = imx_hdmi_encoder_prepare,
- .commit = imx_hdmi_encoder_commit,
- .mode_set = imx_hdmi_encoder_mode_set,
- .mode_fixup = imx_hdmi_encoder_mode_fixup,
- .disable = imx_hdmi_encoder_disable,
-};
-
static struct drm_connector_funcs imx_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = imx_hdmi_connector_detect,
- .destroy = imx_drm_connector_destroy,
+ .destroy = imx_hdmi_connector_destroy,
};
static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1491,6 +1509,16 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
.best_encoder = imx_hdmi_connector_best_encoder,
};
+struct drm_bridge_funcs imx_hdmi_bridge_funcs = {
+ .enable = imx_hdmi_bridge_enable,
+ .disable = imx_hdmi_bridge_disable,
+ .pre_enable = imx_hdmi_bridge_nope,
+ .post_disable = imx_hdmi_bridge_nope,
+ .mode_set = imx_hdmi_bridge_mode_set,
+ .mode_fixup = imx_hdmi_bridge_mode_fixup,
+ .destroy = imx_hdmi_bridge_destroy,
+};
+
static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
{
struct imx_hdmi *hdmi = dev_id;
@@ -1539,74 +1567,62 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
{
+ struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_bridge *bridge;
int ret;
- ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
- hdmi->dev->of_node);
- if (ret)
- return ret;
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("Failed to allocate drm bridge\n");
+ return -ENOMEM;
+ }
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ hdmi->bridge = bridge;
+ bridge->driver_private = hdmi;
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ ret = drm_bridge_init(drm, bridge, &imx_hdmi_bridge_funcs);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
&imx_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
- hdmi->connector.encoder = &hdmi->encoder;
+ hdmi->connector.encoder = encoder;
- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
return 0;
}
-static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- .driver_data = IMX6Q_HDMI,
- }, {
- .name = "imx6dl-hdmi",
- .driver_data = IMX6DL_HDMI,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+int _imx_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct imx_hdmi_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
- struct imx_hdmi *hdmi;
struct resource *iores;
+ struct imx_hdmi *hdmi;
int ret, irq;
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
return -ENOMEM;
- hdmi->dev = dev;
+ hdmi->plat_data = plat_data;
+ hdmi->dev = &pdev->dev;
+ hdmi->dev_type = plat_data->dev_type;
hdmi->sample_rate = 48000;
hdmi->ratio = 100;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
-
- hdmi->dev_type = device_id->driver_data;
- }
+ hdmi->encoder = encoder;
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
@@ -1636,40 +1652,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap))
- return PTR_ERR(hdmi->regmap);
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- ret = PTR_ERR(hdmi->isfr_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI isfr clk: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- ret = PTR_ERR(hdmi->iahb_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI iahb clk: %d\n", ret);
- goto err_isfr;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- goto err_isfr;
- }
-
/* Product and revision IDs */
dev_info(dev,
"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
@@ -1697,11 +1679,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
ret = imx_hdmi_fb_registered(hdmi);
if (ret)
- goto err_iahb;
+ return ret;
ret = imx_hdmi_register(drm, hdmi);
if (ret)
- goto err_iahb;
+ return ret;
/* Unmute interrupts */
hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
@@ -1709,17 +1691,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, hdmi);
return 0;
-
-err_iahb:
- clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
- clk_disable_unprepare(hdmi->isfr_clk);
-
- return ret;
}
+EXPORT_SYMBOL_GPL(_imx_hdmi_bind);
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
+void _imx_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
@@ -1727,42 +1702,197 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
+ hdmi->encoder->funcs->destroy(hdmi->encoder);
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
i2c_put_adapter(hdmi->ddc);
}
+EXPORT_SYMBOL_GPL(_imx_hdmi_unbind);
+
+static int imx_hdmi_parse_dt(struct imx_hdmi_priv *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);
+ }
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
+ return PTR_ERR(hdmi->isfr_clk);
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->iahb_clk);
+ }
+
+ return 0;
+}
+
+static void imx_hdmi_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static bool imx_hdmi_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
-static const struct component_ops hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
+static void imx_hdmi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void imx_hdmi_commit(struct drm_encoder *encoder)
+{
+ struct imx_hdmi_priv *hdmi = container_of(encoder,
+ struct imx_hdmi_priv,
+ 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 imx_hdmi_prepare(struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+ .mode_fixup = imx_hdmi_mode_fixup,
+ .mode_set = imx_hdmi_mode_set,
+ .prepare = imx_hdmi_prepare,
+ .commit = imx_hdmi_commit,
+ .disable = imx_hdmi_disable,
+};
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static struct imx_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 imx_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 int imx_hdmi_platform_probe(struct platform_device *pdev)
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+{ .compatible = "fsl,imx6q-hdmi", .data = &imx6q_hdmi_drv_data},
+{ .compatible = "fsl,imx6dl-hdmi", .data = &imx6dl_hdmi_drv_data, },
+{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static int imx_hdmi_bind(struct device *dev, struct device *master,
+ void *data)
{
- return component_add(&pdev->dev, &hdmi_ops);
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct imx_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+ struct drm_device *drm = data;
+ struct drm_encoder *encoder;
+ struct imx_hdmi_priv *hdmi;
+ 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(imx_hdmi_dt_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = imx_hdmi_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return _imx_hdmi_bind(dev, master, data, encoder, plat_data);
}
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
{
- component_del(&pdev->dev, &hdmi_ops);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct imx_hdmi_priv *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+ clk_disable_unprepare(hdmi->iahb_clk);
+
+ return _imx_hdmi_unbind(dev, master, data);
+}
+
+static const struct component_ops imx_hdmi_ops = {
+ .bind = imx_hdmi_bind,
+ .unbind = imx_hdmi_unbind,
+};
+
+static int imx_hdmi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_hdmi_ops);
+}
+
+static int imx_hdmi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_hdmi_ops);
+
return 0;
}
-static struct platform_driver imx_hdmi_driver = {
- .probe = imx_hdmi_platform_probe,
- .remove = imx_hdmi_platform_remove,
+static struct platform_driver imx_hdmi_platform_driver = {
+ .probe = imx_hdmi_probe,
+ .remove = imx_hdmi_remove,
.driver = {
.name = "imx-hdmi",
.owner = THIS_MODULE,
.of_match_table = imx_hdmi_dt_ids,
},
};
-
-module_platform_driver(imx_hdmi_driver);
+module_platform_driver(imx_hdmi_platform_driver);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:imx-hdmi");
--
1.9.1
the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi driver out
to drm/bridge and rename imx-hdmi to dw_hdmi
handle encoder in dw_hdmi-imx.c, as most of the encoder
operation are platform specific such as crtc select and
panel format set
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2:
- use git format -M to generate these patch
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 544 +++++----------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 4 +-
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 274 +++++++++++
include/drm/bridge/dw_hdmi.h | 57 +++
8 files changed, 470 insertions(+), 418 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (73%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f..26162ef 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -3,3 +3,8 @@ config DRM_PTN3460
depends on DRM
select DRM_KMS_HELPER
---help---
+
+config DRM_DW_HDMI
+ bool "Synopsys DesignWare High-Definition Multimedia Interface"
+ depends on DRM
+ select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1..d8a8cfd 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
similarity index 73%
rename from drivers/staging/imx-drm/imx-hdmi.c
rename to drivers/gpu/drm/bridge/dw_hdmi.c
index c42da29..f904bb4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -6,21 +6,15 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
+ * Designware High-Definition Multimedia Interface (HDMI) driver
*
* Copyright (C) 2010, Guennadi Liakhovetski <[email protected]>
*/
-
-#include <linux/component.h>
+#include <linux/module.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/clk.h>
#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of_device.h>
#include <drm/drm_of.h>
@@ -28,10 +22,9 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder_slave.h>
-#include <video/imx-ipu-v3.h>
+#include <drm/bridge/dw_hdmi.h>
-#include "imx-hdmi.h"
-#include "imx-drm.h"
+#include "dw_hdmi.h"
#define HDMI_EDID_LEN 512
@@ -55,11 +48,6 @@ enum hdmi_datamap {
YCbCr422_12B = 0x12,
};
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
static const u16 csc_coeff_default[3][4] = {
{ 0x2000, 0x0000, 0x0000, 0x0000 },
{ 0x0000, 0x2000, 0x0000, 0x0000 },
@@ -112,23 +100,16 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
-struct imx_hdmi_plat_data {
- const struct mpll_config *mpll_cfg;
- const struct curr_ctrl *cur_ctr;
- const struct sym_term *sym_term;
- enum imx_hdmi_devtype dev_type;
-};
-
-struct imx_hdmi {
+struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
- enum imx_hdmi_devtype dev_type;
+ enum dw_hdmi_devtype dev_type;
struct device *dev;
struct hdmi_data_info hdmi_data;
- const struct imx_hdmi_plat_data *plat_data;
+ const struct dw_hdmi_plat_data *plat_data;
void *priv;
int vic;
@@ -146,25 +127,17 @@ struct imx_hdmi {
int ratio;
};
-struct imx_hdmi_priv {
- struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
- struct regmap *regmap;
- struct drm_encoder encoder;
-};
-
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
writeb(val, hdmi->regs + offset);
}
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
return readb(hdmi->regs + offset);
}
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;
@@ -172,13 +145,13 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
u8 shift, u8 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
unsigned int value)
{
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
@@ -189,7 +162,7 @@ static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
@@ -336,7 +309,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
return (cts * ratio) / 100;
}
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;
@@ -360,12 +333,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
hdmi_regenerate_cts(hdmi, clk_cts);
}
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, 74250000);
}
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
{
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
}
@@ -377,7 +350,7 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
* pin{31~24} <==> G[7:0]
* pin{15~8} <==> B[7:0]
*/
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
{
int color_format = 0;
u8 val;
@@ -433,12 +406,12 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
}
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
}
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
return 0;
@@ -448,7 +421,7 @@ static int is_color_space_decimation(struct imx_hdmi *hdmi)
return 0;
}
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{
if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
return 0;
@@ -458,7 +431,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
return 0;
}
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
{
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
unsigned i;
@@ -499,7 +472,7 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
HDMI_CSC_SCALE);
}
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
{
int color_depth = 0;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
@@ -527,7 +500,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
HDMI_CSC_SCALE);
- imx_hdmi_update_csc_coeffs(hdmi);
+ dw_hdmi_update_csc_coeffs(hdmi);
}
/*
@@ -535,7 +508,7 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
* for example, if input is YCC422 mode or repeater is used,
* data should be repacked this module can be bypassed.
*/
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
{
unsigned int color_depth = 0;
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
@@ -632,40 +605,40 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_CONF);
}
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
@@ -675,7 +648,7 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -689,133 +662,56 @@ static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
}
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_PDZ_OFFSET,
HDMI_PHY_CONF0_PDZ_MASK);
}
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_ENTMDS_OFFSET,
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
}
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
}
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
HDMI_PHY_CONF0_SELDATAENPOL_MASK);
}
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_SELDIPIF_OFFSET,
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-static const struct 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 },
- },
- }
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-static const struct 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 },
- }
-};
-
-struct sym_term {
- unsigned long mpixelclock;
- u16 sym_ctr; /*clock symbol and transmitter control*/
- u16 term; /*transmission termination value*/
-};
-
-static const struct sym_term imx_sym_term[] = {
- /*pixelclk symbol term*/
- { 148500000, 0x800d, 0x0005 },
- { ~0UL, 0x0000, 0x0000 }
-};
-
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
unsigned char res, int cscon)
{
unsigned res_idx, i;
@@ -851,10 +747,10 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
/* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
/* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
/* PHY reset */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
@@ -908,15 +804,15 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
- imx_hdmi_phy_enable_power(hdmi, 1);
+ dw_hdmi_phy_enable_power(hdmi, 1);
/* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 1);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
/* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(hdmi, 1);
- imx_hdmi_phy_gen2_pddq(hdmi, 0);
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
/*Wait for PHY PLL lock */
msec = 5;
@@ -937,7 +833,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
return 0;
}
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
bool cscon = false;
@@ -948,10 +844,10 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
- imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
- imx_hdmi_phy_sel_interface_control(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+ dw_hdmi_phy_sel_interface_control(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
/* Enable CSC */
ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
@@ -963,7 +859,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
return 0;
}
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{
u8 de;
@@ -982,7 +878,7 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
{
u8 val, pix_fmt, under_scan;
u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
@@ -1076,7 +972,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
}
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
u8 inv_val;
@@ -1160,19 +1056,19 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
{
if (!hdmi->phy_enabled)
return;
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
hdmi->phy_enabled = false;
}
/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
u8 clkdis;
@@ -1201,13 +1097,13 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
}
}
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
int count;
u8 val;
@@ -1225,19 +1121,19 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
HDMI_IH_MUTE_FC_STAT2);
}
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
{
int ret;
@@ -1289,12 +1185,12 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */
- ret = imx_hdmi_phy_init(hdmi);
+ ret = dw_hdmi_phy_init(hdmi);
if (ret)
return ret;
/* HDMI Initialization Step B.3 */
- imx_hdmi_enable_video_path(hdmi);
+ dw_hdmi_enable_video_path(hdmi);
/* not for DVI mode */
if (hdmi->hdmi_data.video_mode.mdvi) {
@@ -1315,7 +1211,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_video_sample(hdmi);
hdmi_tx_hdcp_config(hdmi);
- imx_hdmi_clear_overflow(hdmi);
+ dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
hdmi_enable_overflow_interrupts(hdmi);
@@ -1323,7 +1219,7 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
}
/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);
@@ -1341,7 +1237,7 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
return 0;
}
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{
u8 ih_mute;
@@ -1393,73 +1289,73 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
}
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
{
- imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+ dw_hdmi_setup(hdmi, &hdmi->previous_mode);
}
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
- imx_hdmi_phy_disable(hdmi);
+ dw_hdmi_phy_disable(hdmi);
}
-static void imx_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct imx_hdmi *hdmi = bridge->driver_private;
+ struct dw_hdmi *hdmi = bridge->driver_private;
- imx_hdmi_setup(hdmi, mode);
+ dw_hdmi_setup(hdmi, mode);
/* Store the display mode for plugin/DKMS poweron events */
memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
}
-static bool imx_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
-static void imx_hdmi_bridge_disable(struct drm_bridge *bridge)
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
{
- struct imx_hdmi *hdmi = bridge->driver_private;
+ struct dw_hdmi *hdmi = bridge->driver_private;
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
}
-static void imx_hdmi_bridge_enable(struct drm_bridge *bridge)
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
{
- struct imx_hdmi *hdmi = bridge->driver_private;
+ struct dw_hdmi *hdmi = bridge->driver_private;
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
}
-static void imx_hdmi_bridge_destroy(struct drm_bridge *bridge)
+static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge)
{
drm_bridge_cleanup(bridge);
kfree(bridge);
}
-static void imx_hdmi_bridge_nope(struct drm_bridge *bridge)
+static void dw_hdmi_bridge_nope(struct drm_bridge *bridge)
{
/* do nothing */
}
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
- *connector, bool force)
+static enum drm_connector_status
+dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
struct edid *edid;
int ret;
@@ -1482,46 +1378,46 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
connector);
return hdmi->encoder;
}
-static void imx_hdmi_connector_destroy(struct drm_connector *connector)
+static void dw_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- .destroy = imx_hdmi_connector_destroy,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
};
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- .get_modes = imx_hdmi_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+ .get_modes = dw_hdmi_connector_get_modes,
+ .best_encoder = dw_hdmi_connector_best_encoder,
};
-struct drm_bridge_funcs imx_hdmi_bridge_funcs = {
- .enable = imx_hdmi_bridge_enable,
- .disable = imx_hdmi_bridge_disable,
- .pre_enable = imx_hdmi_bridge_nope,
- .post_disable = imx_hdmi_bridge_nope,
- .mode_set = imx_hdmi_bridge_mode_set,
- .mode_fixup = imx_hdmi_bridge_mode_fixup,
- .destroy = imx_hdmi_bridge_destroy,
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .enable = dw_hdmi_bridge_enable,
+ .disable = dw_hdmi_bridge_disable,
+ .pre_enable = dw_hdmi_bridge_nope,
+ .post_disable = dw_hdmi_bridge_nope,
+ .mode_set = dw_hdmi_bridge_mode_set,
+ .mode_fixup = dw_hdmi_bridge_mode_fixup,
+ .destroy = dw_hdmi_bridge_destroy,
};
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
@@ -1531,9 +1427,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
- struct imx_hdmi *hdmi = dev_id;
+ struct dw_hdmi *hdmi = dev_id;
u8 intr_stat;
u8 phy_int_pol;
@@ -1547,14 +1443,14 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
- imx_hdmi_poweron(hdmi);
+ dw_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");
hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
HDMI_PHY_POL0);
- imx_hdmi_poweroff(hdmi);
+ dw_hdmi_poweroff(hdmi);
}
drm_helper_hpd_irq_event(hdmi->connector.dev);
}
@@ -1565,7 +1461,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = hdmi->encoder;
struct drm_bridge *bridge;
@@ -1580,7 +1476,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
hdmi->bridge = bridge;
bridge->driver_private = hdmi;
- ret = drm_bridge_init(drm, bridge, &imx_hdmi_bridge_funcs);
+ ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return -EINVAL;
@@ -1590,8 +1486,8 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+ &dw_hdmi_connector_helper_funcs);
+ drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
hdmi->connector.encoder = encoder;
@@ -1601,16 +1497,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
return 0;
}
-int _imx_hdmi_bind(struct device *dev, struct device *master,
+int dw_hdmi_bind(struct device *dev, struct device *master,
void *data, struct drm_encoder *encoder,
- const struct imx_hdmi_plat_data *plat_data)
+ const struct dw_hdmi_plat_data *plat_data)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct device_node *ddc_node;
struct resource *iores;
- struct imx_hdmi *hdmi;
+ struct dw_hdmi *hdmi;
int ret, irq;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
@@ -1641,8 +1537,8 @@ int _imx_hdmi_bind(struct device *dev, struct device *master,
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
+ ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
return ret;
@@ -1677,11 +1573,11 @@ int _imx_hdmi_bind(struct device *dev, struct device *master,
/* Clear Hotplug interrupts */
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
- ret = imx_hdmi_fb_registered(hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
return ret;
- ret = imx_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_register(drm, hdmi);
if (ret)
return ret;
@@ -1692,11 +1588,11 @@ int _imx_hdmi_bind(struct device *dev, struct device *master,
return 0;
}
-EXPORT_SYMBOL_GPL(_imx_hdmi_bind);
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-void _imx_hdmi_unbind(struct device *dev, struct device *master, void *data)
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
@@ -1706,193 +1602,11 @@ void _imx_hdmi_unbind(struct device *dev, struct device *master, void *data)
i2c_put_adapter(hdmi->ddc);
}
-EXPORT_SYMBOL_GPL(_imx_hdmi_unbind);
-
-static int imx_hdmi_parse_dt(struct imx_hdmi_priv *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);
- }
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
- return PTR_ERR(hdmi->isfr_clk);
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
- return PTR_ERR(hdmi->iahb_clk);
- }
-
- return 0;
-}
-
-static void imx_hdmi_disable(struct drm_encoder *encoder)
-{
-
-}
-
-static bool imx_hdmi_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void imx_hdmi_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
-
-}
-
-static void imx_hdmi_commit(struct drm_encoder *encoder)
-{
- struct imx_hdmi_priv *hdmi = container_of(encoder,
- struct imx_hdmi_priv,
- 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 imx_hdmi_prepare(struct drm_encoder *encoder)
-{
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
-}
-
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .mode_fixup = imx_hdmi_mode_fixup,
- .mode_set = imx_hdmi_mode_set,
- .prepare = imx_hdmi_prepare,
- .commit = imx_hdmi_commit,
- .disable = imx_hdmi_disable,
-};
-
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
-};
-
-static struct imx_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 imx_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 imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx6q_hdmi_drv_data},
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx6dl_hdmi_drv_data, },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
-static int imx_hdmi_bind(struct device *dev, struct device *master,
- void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- const struct imx_hdmi_plat_data *plat_data;
- const struct of_device_id *match;
- struct drm_device *drm = data;
- struct drm_encoder *encoder;
- struct imx_hdmi_priv *hdmi;
- 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(imx_hdmi_dt_ids, pdev->dev.of_node);
- plat_data = match->data;
- hdmi->dev = &pdev->dev;
- encoder = &hdmi->encoder;
- platform_set_drvdata(pdev, hdmi);
-
- ret = imx_hdmi_parse_dt(hdmi);
- if (ret < 0)
- return ret;
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
- return ret;
- }
-
- encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
-
- drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
-
- return _imx_hdmi_bind(dev, master, data, encoder, plat_data);
-}
-
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct imx_hdmi_priv *hdmi = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(hdmi->isfr_clk);
- clk_disable_unprepare(hdmi->iahb_clk);
-
- return _imx_hdmi_unbind(dev, master, data);
-}
-
-static const struct component_ops imx_hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
-};
-
-static int imx_hdmi_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &imx_hdmi_ops);
-}
-
-static int imx_hdmi_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &imx_hdmi_ops);
-
- return 0;
-}
-
-static struct platform_driver imx_hdmi_platform_driver = {
- .probe = imx_hdmi_probe,
- .remove = imx_hdmi_remove,
- .driver = {
- .name = "imx-hdmi",
- .owner = THIS_MODULE,
- .of_match_table = imx_hdmi_dt_ids,
- },
-};
-module_platform_driver(imx_hdmi_platform_driver);
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_AUTHOR("Andy Yan <[email protected]>");
MODULE_AUTHOR("Yakir Yang <[email protected]>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
similarity index 99%
rename from drivers/staging/imx-drm/imx-hdmi.h
rename to drivers/gpu/drm/bridge/dw_hdmi.h
index 39b6776..04d8ebe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -7,8 +7,8 @@
* (at your option) any later version.
*/
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
+#ifndef __DW_HDMI_H__
+#define __DW_HDMI_H__
/* Identification Registers */
#define HDMI_DESIGN_ID 0x0000
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index ab31848..560e1d3 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -50,5 +50,6 @@ config DRM_IMX_IPUV3
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
depends on DRM_IMX
+ select DRM_DW_HDMI
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 582c438..f3ecd89 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -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
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
new file mode 100644
index 0000000..d975d18
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,274 @@
+/* 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 <linux/clk.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 "imx-drm.h"
+
+struct imx_hdmi {
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+static const struct 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 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 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);
+ }
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n");
+ return PTR_ERR(hdmi->isfr_clk);
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n");
+ return PTR_ERR(hdmi->iahb_clk);
+ }
+
+ return 0;
+}
+
+static void dw_hdmi_imx_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_imx_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_imx_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void dw_hdmi_imx_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_prepare(struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_imx_mode_fixup,
+ .mode_set = dw_hdmi_imx_mode_set,
+ .prepare = dw_hdmi_imx_prepare,
+ .commit = dw_hdmi_imx_commit,
+ .disable = dw_hdmi_imx_disable,
+};
+
+static struct drm_encoder_funcs imx_hdmi_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;
+ 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;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = dw_hdmi_imx_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &imx_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->isfr_clk);
+ clk_disable_unprepare(hdmi->iahb_clk);
+
+ 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",
+ .owner = THIS_MODULE,
+ .of_match_table = dw_hdmi_imx_dt_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..1001470
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __DW_HDMI__
+#define __DW_HDMI__
+
+#include <drm/drmP.h>
+
+enum {
+ RES_8,
+ RES_10,
+ RES_12,
+ RES_MAX,
+};
+
+enum dw_hdmi_devtype {
+ IMX6Q_HDMI,
+ IMX6DL_HDMI,
+};
+
+struct mpll_config {
+ unsigned long mpixelclock;
+ struct {
+ u16 cpce;
+ u16 gmp;
+ } res[RES_MAX];
+};
+
+struct curr_ctrl {
+ unsigned long mpixelclock;
+ u16 curr[RES_MAX];
+};
+
+struct sym_term {
+ unsigned long mpixelclock;
+ u16 sym_ctr; /*clock symbol and transmitter control*/
+ u16 term; /*transmission termination value*/
+};
+
+struct dw_hdmi_plat_data {
+ const struct mpll_config *mpll_cfg;
+ const struct curr_ctrl *cur_ctr;
+ const struct sym_term *sym_term;
+ enum dw_hdmi_devtype dev_type;
+};
+
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data);
+#endif /* __IMX_HDMI_H__ */
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8:
- correct some spelling mistake
- modify ddc-i2c-bus and interrupt description
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
diff --git a/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
new file mode 100644
index 0000000..107c1ca
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
@@ -0,0 +1,40 @@
+DesignWare HDMI bridge bindings
+
+Required properities:
+- compatible: platform specific such as:
+ * "fsl,imx6q-hdmi"
+ * "fsl,imx6dl-hdmi"
+ * "rockchip,rk3288-dw-hdmi"
+- reg: Physical base address and length of the controller's registers.
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- interrupts: The HDMI interrupt number
+
+Optional properties
+- reg-io-width: the width of the reg:1,4, default set to 1 if not present
+
+Example:
+ hdmi: hdmi@0120000 {
+ compatible = "fsl,imx6q-hdmi";
+ reg = <0x00120000 0x9000>;
+ interrupts = <0 115 0x04>;
+ gpr = <&gpr>;
+ clocks = <&clks 123>, <&clks 124>;
+ clock-names = "iahb", "isfr";
+ ddc-i2c-bus = <&i2c2>;
+
+ port@0 {
+ reg = <0>;
+
+ hdmi_mux_0: endpoint {
+ remote-endpoint = <&ipu1_di0_hdmi>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ hdmi_mux_1: endpoint {
+ remote-endpoint = <&ipu1_di1_hdmi>;
+ };
+ };
+ };
--
1.9.1
On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width accesses (writeb,
readb) generate an imprecise external abort.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6:
- move some modification to patch#6
- refactor register access without reg_shift
Changes in v5:
- refactor reg-io-width
Changes in v4: None
Changes in v3:
- split multi-register access to one indepent patch
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 57 +++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index f904bb4..229aa7a 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -100,6 +100,11 @@ struct hdmi_data_info {
struct hdmi_vmode video_mode;
};
+union dw_reg_ptr {
+ u32 __iomem *p32;
+ u8 __iomem *p8;
+};
+
struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder *encoder;
@@ -121,20 +126,43 @@ struct dw_hdmi {
struct regmap *regmap;
struct i2c_adapter *ddc;
- void __iomem *regs;
+ union dw_reg_ptr regs;
unsigned int sample_rate;
int ratio;
+
+ void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+ u8 (*read)(struct dw_hdmi *hdmi, int offset);
};
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writel(val, hdmi->regs.p32 + offset);
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs.p32 + offset);
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writeb(val, hdmi->regs.p8 + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return readb(hdmi->regs.p8 + offset);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(hdmi, val, offset);
}
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi, offset);
}
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
@@ -1508,6 +1536,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
struct resource *iores;
struct dw_hdmi *hdmi;
int ret, irq;
+ u32 val = 1;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1520,6 +1549,22 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->ratio = 100;
hdmi->encoder = encoder;
+ of_property_read_u32(np, "reg-io-width", &val);
+
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ break;
+ case 1:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return -EINVAL;
+ }
+
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
@@ -1544,9 +1589,9 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
return ret;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
+ hdmi->regs.p32 = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs.p32))
+ return PTR_ERR(hdmi->regs.p32);
/* Product and revision IDs */
dev_info(dev,
--
1.9.1
some platform may not support all the display mode,
add mode_valid interface check it
also add drm_connector_register which add a debugfs
interface for dump display modes and edid information
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 17 +++++++++++++++++
include/drm/bridge/dw_hdmi.h | 2 ++
2 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 229aa7a..7b32bb8 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -1406,6 +1406,20 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
return 0;
}
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = container_of(connector,
+ struct dw_hdmi, connector);
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (hdmi->plat_data->mode_valid)
+ mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
*connector)
{
@@ -1430,6 +1444,7 @@ static struct drm_connector_funcs dw_hdmi_connector_funcs = {
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
.get_modes = dw_hdmi_connector_get_modes,
+ .mode_valid = dw_hdmi_connector_mode_valid,
.best_encoder = dw_hdmi_connector_best_encoder,
};
@@ -1631,6 +1646,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
dev_set_drvdata(dev, hdmi);
+ drm_connector_register(&hdmi->connector);
+
return 0;
}
EXPORT_SYMBOL_GPL(dw_hdmi_bind);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 1001470..ed358f0 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -44,6 +44,8 @@ struct sym_term {
};
struct dw_hdmi_plat_data {
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
const struct mpll_config *mpll_cfg;
const struct curr_ctrl *cur_ctr;
const struct sym_term *sym_term;
--
1.9.1
HDMI_IH_I2CMPHY_STAT0 is a clear on write register, which indicates i2cm
operation status(i2c transfer done or error), every hdmi phy register
configuration must check this register to make sure the configuration
has complete. But the indication bit should be cleared after check, otherwise
the corresponding bit will hold on forever, this may give a wrong signal for
next check.
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11:
- split form patch <dw_hdmi: add rk3288 support>
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 7b32bb8..898488d 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -668,11 +668,15 @@ static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ u32 val;
+
+ while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
udelay(1000);
}
+ hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
return true;
}
--
1.9.1
RK3288 HDMI will not work without the spare bit of
HDMI_PHY_CONF0 enable
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11:
- split from patch <dw_hdmi: add rk3288 support>
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 7 +++++++
drivers/gpu/drm/bridge/dw_hdmi.h | 3 ++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 898488d..c63bdf9 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -715,6 +715,13 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_ENTMDS_MASK);
}
+static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SPARECTRL_OFFSET,
+ HDMI_PHY_CONF0_SPARECTRL_MASK);
+}
+
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
index 04d8ebe..9900f24 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.h
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -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,
--
1.9.1
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8:
- Add documentation for rockchip dw hdmi
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
.../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
diff --git a/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
new file mode 100644
index 0000000..0735464
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
@@ -0,0 +1,43 @@
+Rockchip specific extensions to the Synopsys Designware HDMI
+================================
+
+Required properties:
+- compatible: "rockchip,rk3288-dw-hdmi";
+- reg: Physical base address and length of the controller's registers.
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- clocks: from common clock binding: handle to hdmi clock.
+- clock-names: should be "clk" "hdcp_clk"
+- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
+- interrupts: HDMI interrupt number
+- ports: contain a port node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt. For
+ vopb,set the reg = <0> and set the reg = <1> for vopl.
+- reg-io-width: the width of the reg:1,4, the value should be 4 on
+ rk3288 platform
+
+Example:
+hdmi: hdmi@ff980000 {
+ compatible = "rockchip,rk3288-dw-hdmi";
+ reg = <0xff980000 0x20000>;
+ reg-io-width = <4>;
+ ddc-i2c-bus = <&i2c5>;
+ rockchip,grf = <&grf>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
+ clock-names = "clk", "hdcp_clk";
+ status = "disabled";
+ ports {
+ hdmi_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ hdmi_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_hdmi>;
+ };
+ hdmi_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_hdmi>;
+ };
+ };
+ };
+};
--
1.9.1
Rockchip RK3288 hdmi is compatible with dw_hdmi
this patch is depend on patch by Mark Yao Add drm
driver for Rockchip Socs
see https://lkml.org/lkml/2014/10/8/201
Signed-off-by: Andy Yan <[email protected]>
---
Changes in v12:
- add comment for the depend on patch
Changes in v11: None
Changes in v10:
- add more display mode support mpll configuration for rk3288
Changes in v9:
- move some phy configuration to platform driver
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None
drivers/gpu/drm/bridge/dw_hdmi.c | 3 +
drivers/gpu/drm/rockchip/Kconfig | 10 +
drivers/gpu/drm/rockchip/Makefile | 2 +-
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi.h | 1 +
5 files changed, 370 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index c63bdf9..7df5f38 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -853,6 +853,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
+ if (hdmi->dev_type == RK3288_HDMI)
+ dw_hdmi_phy_enable_spare(hdmi, 1);
+
/*Wait for PHY PLL lock */
msec = 5;
do {
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 0ff6682..06371ae 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -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
+ bool "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.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index b3a5193..347e65c 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,5 +4,5 @@
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchip_drm_gem.o rockchip_drm_vop.o
-
+rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 0000000..16cad75
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,355 @@
+/*
+ * 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 <linux/clk.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 clk *clk;
+ struct clk *hdcp_clk;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+
+static const struct 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 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 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);
+ }
+
+ hdmi->clk = devm_clk_get(hdmi->dev, "clk");
+ if (IS_ERR(hdmi->clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI clk\n");
+ return PTR_ERR(hdmi->clk);
+ }
+
+ hdmi->hdcp_clk = devm_clk_get(hdmi->dev, "hdcp_clk");
+ if (IS_ERR(hdmi->hdcp_clk)) {
+ dev_err(hdmi->dev, "Unable to get HDMI hdcp clk\n");
+ return PTR_ERR(hdmi->hdcp_clk);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct 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_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_rockchip_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_rockchip_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void dw_hdmi_rockchip_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_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_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_rockchip_mode_fixup,
+ .mode_set = dw_hdmi_rockchip_mode_set,
+ .prepare = dw_hdmi_rockchip_prepare,
+ .commit = dw_hdmi_rockchip_commit,
+ .disable = dw_hdmi_rockchip_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_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;
+ 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_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+ platform_set_drvdata(pdev, hdmi);
+
+ ret = rockchip_hdmi_parse_dt(hdmi);
+ if (ret) {
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdcp_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI hdcp clock: %d\n", ret);
+ return ret;
+ }
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rockchip_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(hdmi->clk);
+ clk_disable_unprepare(hdmi->hdcp_clk);
+
+ 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",
+ .owner = THIS_MODULE,
+ .of_match_table = dw_hdmi_rockchip_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <[email protected]>");
+MODULE_AUTHOR("Yakir Yang <[email protected]>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index ed358f0..1755c33 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -22,6 +22,7 @@ enum {
enum dw_hdmi_devtype {
IMX6Q_HDMI,
IMX6DL_HDMI,
+ RK3288_HDMI,
};
struct mpll_config {
--
1.9.1
Hi Andy,
On 24/11/14 14:17, Andy Yan wrote:
> Hi ZubairLK, Russel King, Greg Kroah-Hartman , Philipp Zabel and Daniel:
> Do you have any further opinions or suggestions about the
> the current patch set?
I have reviewed the patches as much as I could.
They look good to me.
But I don't know the inner details of DRM to be able to comment further.
Please do cc me in further patches.
Also, my mail client makes these patches look like the new series gets cascaded in the older patch 8 series.
It could be just my thunderbird. But please start a new thread when you send a new series.
Thank-you
ZubairLK
> On 2014年11月17日 18:53, Andy Yan wrote:
>> We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
>> use the interface compatible Designware HDMI IP, but they also have some
>> lightly differences, such as phy pll configuration, register width(imx hdmi
>> register is one byte, but rk3288 is 4 bytes width and can only be accessed
>> by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
>> support.
Hi ZubairLK, Russel King, Greg Kroah-Hartman , Philipp Zabel and Daniel:
Do you have any further opinions or suggestions about the
the current patch set?
On 2014年11月17日 18:53, Andy Yan wrote:
> We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
> use the interface compatible Designware HDMI IP, but they also have some
> lightly differences, such as phy pll configuration, register width(imx hdmi
> register is one byte, but rk3288 is 4 bytes width and can only be accessed
> by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
> support.
>
> To reuse the imx-hdmi driver, we make this patch set:
> (1): fix some CodingStyle warning to make checkpatch happy
> (2): convert imx-hdmi to drm_bridge
> (3): move imx-hdmi to bridge/dw_hdmi, and split platform specific code
> (4): extend dw_hdmi.c to support rk3288 hdmi
> (5): add rockchip rk3288 platform specific code dw_hdmi-rockchip.c
>
> Changes in v12:
> - refactor of_node_put(ddc_node)
> - squash patch <convert dw_hdmi to drm_bridge> & <split imx soc specific code from imx-hdmi>
> - add comment for the depend on patch
>
> Changes in v11:
> - squash patch <split some phy configuration to platform driver>
> - split form patch <dw_hdmi: add rk3288 support>
> - split from patch <dw_hdmi: add rk3288 support>
>
> Changes in v10:
> - split generic dw_hdmi.c improvements from patch#11 (add rk3288 support)
> - add more display mode support mpll configuration for rk3288
>
> Changes in v9:
> - move some phy configuration to platform driver
>
> Changes in v8:
> - correct some spelling mistake
> - modify ddc-i2c-bus and interrupt description
> - Add documentation for rockchip dw hdmi
>
> Changes in v7:
> - remove unused variables from structure dw_hdmi
> - remove a wrong modification
> - add copyrights for dw_hdmi-imx.c
>
> Changes in v6:
> - rearrange the patch order
> - move some modification to patch#6
> - refactor register access without reg_shift
>
> Changes in v5:
> - refactor reg-io-width
>
> Changes in v4:
> - fix checkpatch CHECK
> - defer probe ddc i2c adapter
>
> Changes in v3:
> - split multi-register access to one indepent patch
>
> Changes in v2:
> - use git format -M to generate these patch
>
> Andy Yan (11):
> staging: imx-drm: imx-hdmi: make checkpatch happy
> staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
> staging: imx-drm: imx-hdmi: convert imx-hdmi to drm_bridge mode
> staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
> dt-bindings: add document for dw_hdmi
> drm: bridge/dw_hdmi: add support for multi-byte register width access
> drm: bridge/dw_hdmi: add mode_valid support
> drm: bridge/dw_hdmi: clear i2cmphy_stat0 reg in hdmi_phy_wait_i2c_done
> drm: bridge/dw_hdmi: add function dw_hdmi_phy_enable_spare
> dt-bindings: Add documentation for rockchip dw hdmi
> drm: bridge/dw_hdmi: add rockchip rk3288 support
>
> .../devicetree/bindings/drm/bridge/dw_hdmi.txt | 40 ++
> .../devicetree/bindings/video/dw_hdmi-rockchip.txt | 43 ++
> drivers/gpu/drm/bridge/Kconfig | 5 +
> drivers/gpu/drm/bridge/Makefile | 1 +
> .../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 767 +++++++++------------
> .../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 7 +-
> drivers/gpu/drm/rockchip/Kconfig | 10 +
> drivers/gpu/drm/rockchip/Makefile | 2 +-
> drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 355 ++++++++++
> drivers/staging/imx-drm/Kconfig | 1 +
> drivers/staging/imx-drm/Makefile | 2 +-
> drivers/staging/imx-drm/dw_hdmi-imx.c | 274 ++++++++
> include/drm/bridge/dw_hdmi.h | 60 ++
> 13 files changed, 1139 insertions(+), 428 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw_hdmi.txt
> create mode 100644 Documentation/devicetree/bindings/video/dw_hdmi-rockchip.txt
> rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (70%)
> rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (99%)
> create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
> create mode 100644 include/drm/bridge/dw_hdmi.h
>
Hi ZubairLK:
On 2014年11月24日 22:22, Zubair Lutfullah Kakakhel wrote:
> Hi Andy,
>
> On 24/11/14 14:17, Andy Yan wrote:
>> Hi ZubairLK, Russel King, Greg Kroah-Hartman , Philipp Zabel and Daniel:
>> Do you have any further opinions or suggestions about the
>> the current patch set?
> I have reviewed the patches as much as I could.
>
> They look good to me.
>
> But I don't know the inner details of DRM to be able to comment further.
>
> Please do cc me in further patches.
Thanks very much for your carefully review work.
And if you have further ideas , please let me know.
>
> Also, my mail client makes these patches look like the new series gets cascaded in the older patch 8 series.
>
> It could be just my thunderbird. But please start a new thread when you send a new series.
I do these by taking Russell King's advice in PATCH#10(use the same
reference message id).
>
> Thank-you
> ZubairLK
>
>> On 2014年11月17日 18:53, Andy Yan wrote:
>>> We found Freescale imx6 and Rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS)
>>> use the interface compatible Designware HDMI IP, but they also have some
>>> lightly differences, such as phy pll configuration, register width(imx hdmi
>>> register is one byte, but rk3288 is 4 bytes width and can only be accessed
>>> by word), 4K support(imx6 doesn't support 4k, but rk3288 does), and HDMI2.0
>>> support.
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
Hi Andy,
On Mon, Nov 17, 2014 at 8:53 AM, Andy Yan <[email protected]> wrote:
> Andy Yan (11):
> staging: imx-drm: imx-hdmi: make checkpatch happy
> staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
> staging: imx-drm: imx-hdmi: convert imx-hdmi to drm_bridge mode
> staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
imx-drm has moved out of staging.
Please see Phillip's patch:
http://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-next&id=6556f7f82b9c401950d703072c0d8137b6f9f516
So you need to re-submit your series against drm-next.
Hi Fabio:
On 2014年11月26日 10:14, Fabio Estevam wrote:
> Hi Andy,
>
> On Mon, Nov 17, 2014 at 8:53 AM, Andy Yan <[email protected]> wrote:
>
>> Andy Yan (11):
>> staging: imx-drm: imx-hdmi: make checkpatch happy
>> staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter
>> staging: imx-drm: imx-hdmi: convert imx-hdmi to drm_bridge mode
>> staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw_hdmi
> imx-drm has moved out of staging.
>
> Please see Phillip's patch:
> http://cgit.freedesktop.org/~airlied/linux/commit/?h=drm-next&id=6556f7f82b9c401950d703072c0d8137b6f9f516
>
> So you need to re-submit your series against drm-next.
>
>
Thanks very much for you pointing out this, I will re-submit my
patch set against drm-next soon.