2014-11-05 12:55:33

by Andy Yan

[permalink] [raw]
Subject: [PATCH V2 0/2] make imx hdmi publicly used by dw hdmi compatible platform

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 difference, 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 do this patch set:
patch (1): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
patch (2): move imx-hdmi to bridge/, and rename to dw-hdmi to
make this driver indepent of drm-imx . And we will add rockchip
platform specific code dw_hdmi-rockchip.c later, this is depend
on drm-rockchip.

Changes in V2:
- use git format-patch -M to generate these patch
- remove change-id
- remove from

Andy Yan (2):
imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
move imx-hdmi to bridge/dw-hdmi

drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 964 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 0
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 214 +++++
include/drm/bridge/dw_hdmi.h | 114 +++
8 files changed, 760 insertions(+), 541 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (57%)
rename drivers/{staging/imx-drm/imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} (100%)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h

--
1.9.1


2014-11-05 12:55:45

by Andy Yan

[permalink] [raw]
Subject: [PATCH 1/2] imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi

imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly difference, such as phy pll configuration,
register width(imx hdmi register is one byte, but rk3288 is 4
bytes width), 4K support(imx6 doesn't support 4k, but rk3288 does),
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]>
---
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 214 ++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 726 ++++++++++++++--------------------
include/drm/bridge/dw_hdmi.h | 114 ++++++
4 files changed, 634 insertions(+), 422 deletions(-)
create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c
create mode 100644 include/drm/bridge/dw_hdmi.h

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..71ac859
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,214 @@
+/*
+ * 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 <drm/bridge/dw_hdmi.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+
+#include "imx-drm.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_set_crtc_mux(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,
+ .set_crtc_mux = imx_hdmi_imx_set_crtc_mux,
+ .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,
+ .set_crtc_mux = imx_hdmi_imx_set_crtc_mux,
+ .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_pltfm_register(pdev, plat_data);
+}
+
+static int imx_hdmi_imx_remove(struct platform_device *pdev)
+{
+ return imx_hdmi_pltfm_unregister(pdev);
+}
+
+static struct platform_driver imx_hdmi_imx_pltfm_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_pltfm_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 aaec6b2..138706c 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,23 +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 <drm/bridge/dw_hdmi.h>

#include "imx-hdmi.h"
-#include "imx-drm.h"
-
-#define HDMI_EDID_LEN 512

#define RGB 0
#define YCBCR444 1
@@ -54,11 +47,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 },
@@ -89,72 +77,44 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
{ 0x6756, 0x78ab, 0x2000, 0x0200 }
};

-struct hdmi_vmode {
- bool mdvi;
- bool mhsyncpolarity;
- bool mvsyncpolarity;
- bool minterlaced;
- bool mdataenablepolarity;
-
- unsigned int mpixelclock;
- unsigned int mpixelrepetitioninput;
- unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
- unsigned int enc_in_format;
- unsigned int enc_out_format;
- unsigned int enc_color_depth;
- unsigned int colorimetry;
- unsigned int pix_repet_factor;
- unsigned int hdcp_enable;
- struct hdmi_vmode video_mode;
-};
-
-struct imx_hdmi {
- struct drm_connector connector;
- struct drm_encoder encoder;
-
- enum imx_hdmi_devtype dev_type;
- struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
-
- struct hdmi_data_info hdmi_data;
- int vic;
-
- u8 edid[HDMI_EDID_LEN];
- bool cable_plugin;
+/*On rockchip platform, no-word access to the hdmi
+ * register will causes an imprecise external abort
+ */
+static inline void hdmi_writel(struct imx_hdmi *hdmi, u32 val, int offset)
+{
+ writel(val, hdmi->regs + (offset << 2));
+}

- bool phy_enabled;
- struct drm_display_mode previous_mode;
+static inline u32 hdmi_readl(struct imx_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs + (offset << 2));
+}

- struct regmap *regmap;
- struct i2c_adapter *ddc;
- void __iomem *regs;
+static void hdmi_modl(struct imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
+{
+ u32 val = hdmi_readl(hdmi, reg) & ~mask;

- unsigned int sample_rate;
- int ratio;
-};
+ val |= data & mask;
+ hdmi_writel(hdmi, val, reg);
+}

-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
+static void hdmi_mask_writel(struct imx_hdmi *hdmi, u32 data, unsigned int reg,
+ u32 shift, u32 mask)
{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+ hdmi_modl(hdmi, data << shift, mask, reg);
}

-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+static inline void hdmi_writeb(struct imx_hdmi *hdmi, u32 val, int offset)
{
writeb(val, hdmi->regs + offset);
}

-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+static inline u32 hdmi_readb(struct imx_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 imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;

@@ -162,8 +122,8 @@ 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,
- u8 shift, u8 mask)
+static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u32 data, unsigned int reg,
+ u32 shift, u32 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -171,22 +131,22 @@ static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
unsigned int value)
{
- hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
- hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
- hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
+ hdmi->write(hdmi, value & 0xff, HDMI_AUD_N1);
+ hdmi->write(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
+ hdmi->write(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);

/* nshift factor = 0 */
- hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
+ hdmi->mod(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
}

static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
{
/* Must be set/cleared first */
- hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+ hdmi->mod(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);

- hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
- hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+ hdmi->write(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+ hdmi->write(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+ hdmi->write(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
}

@@ -323,6 +283,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}
if (ratio == 100)
return cts;
+
return (cts * ratio) / 100;
}

@@ -338,7 +299,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;
}

@@ -408,19 +369,19 @@ static void hdmi_video_sample(struct imx_hdmi *hdmi)
val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
- hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
+ hdmi->write(hdmi, val, HDMI_TX_INVID0);

/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
- hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
+ hdmi->write(hdmi, val, HDMI_TX_INSTUFFING);
+ hdmi->write(hdmi, 0x0, HDMI_TX_GYDATA0);
+ hdmi->write(hdmi, 0x0, HDMI_TX_GYDATA1);
+ hdmi->write(hdmi, 0x0, HDMI_TX_RCRDATA0);
+ hdmi->write(hdmi, 0x0, HDMI_TX_RCRDATA1);
+ hdmi->write(hdmi, 0x0, HDMI_TX_BCBDATA0);
+ hdmi->write(hdmi, 0x0, HDMI_TX_BCBDATA1);
}

static int is_color_space_conversion(struct imx_hdmi *hdmi)
@@ -477,17 +438,17 @@ 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->write(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->write(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+ hdmi->write(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+ hdmi->write(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+ hdmi->write(hdmi, coeff_c & 0xff,
HDMI_CSC_COEF_C1_LSB + i * 2);
- hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+ hdmi->write(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
}

- hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+ hdmi->mod(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
HDMI_CSC_SCALE);
}

@@ -515,8 +476,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
return;

/* Configure the CSC registers */
- hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
- hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+ hdmi->write(hdmi, interpolation | decimation, HDMI_CSC_CFG);
+ hdmi->mod(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
HDMI_CSC_SCALE);

imx_hdmi_update_csc_coeffs(hdmi);
@@ -535,21 +496,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 +523,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) &
@@ -570,9 +533,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
((hdmi_data->pix_repet_factor <<
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
- hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
+ hdmi->write(hdmi, val, HDMI_VP_PR_CD);

- hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+ hdmi->mod(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);

/* Data from pixel repeater block */
@@ -584,14 +547,14 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
}

- hdmi_modb(hdmi, vp_conf,
+ hdmi->mod(hdmi, vp_conf,
HDMI_VP_CONF_PR_EN_MASK |
HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);

- hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+ hdmi->mod(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);

- hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
+ hdmi->write(hdmi, remap_size, HDMI_VP_REMAP);

if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
@@ -609,55 +572,55 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
return;
}

- hdmi_modb(hdmi, vp_conf,
+ hdmi->mod(hdmi, vp_conf,
HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);

- hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ hdmi->mod(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
HDMI_VP_STUFF_PP_STUFFING_MASK |
HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);

- hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+ hdmi->mod(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
HDMI_VP_CONF);
}

static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
unsigned char bit)
{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+ hdmi->mod(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)
{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+ hdmi->mod(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)
{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+ hdmi->mod(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)
{
- hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
+ hdmi->write(hdmi, bit, HDMI_PHY_TST1);
}

static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
unsigned char bit)
{
- hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
+ hdmi->write(hdmi, bit, HDMI_PHY_TST2);
}

static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ while ((hdmi->read(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
if (msec-- == 0)
return false;
udelay(1000);
@@ -668,13 +631,13 @@ 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)
{
- 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->write(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+ hdmi->write(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+ hdmi->write(hdmi, (unsigned char)(data >> 8),
HDMI_PHY_I2CM_DATAO_1_ADDR);
- hdmi_writeb(hdmi, (unsigned char)(data >> 0),
+ hdmi->write(hdmi, (unsigned char)(data >> 0),
HDMI_PHY_I2CM_DATAO_0_ADDR);
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+ hdmi->write(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
@@ -688,116 +651,53 @@ static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,

static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi->mask_write(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)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi->mask_write(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)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi->mask_write(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)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi->mask_write(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)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi->mask_write(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)
{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ hdmi->mask_write(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 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;
@@ -823,7 +723,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
else
val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;

- hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
+ hdmi->write(hdmi, val, HDMI_MC_FLOWCTRL);

/* gen2 tx power off */
imx_hdmi_phy_gen2_txpwron(hdmi, 0);
@@ -832,39 +732,38 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
imx_hdmi_phy_gen2_pddq(hdmi, 1);

/* PHY reset */
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+ hdmi->write(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+ hdmi->write(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);

- hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+ hdmi->write(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);

hdmi_phy_test_clear(hdmi, 1);
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+ hdmi->write(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
HDMI_PHY_I2CM_SLAVE_ADDR);
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_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);

- 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);
-
- 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);
+ "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);
@@ -890,7 +789,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
/*Wait for PHY PLL lock */
msec = 5;
do {
- val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ val = hdmi->read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
if (!val)
break;

@@ -942,12 +841,12 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;

/* disable rx detect */
- hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+ hdmi->mod(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);

- hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
+ hdmi->mod(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);

- hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+ hdmi->mod(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
}

@@ -977,7 +876,7 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;

- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
+ hdmi->write(hdmi, val, HDMI_FC_AVICONF0);

/* AVI Data Byte 2 -Set the Aspect Ratio */
if (aspect_16_9) {
@@ -1009,16 +908,16 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
}

val = colorimetry | coded_ratio | act_ratio;
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
+ hdmi->write(hdmi, val, HDMI_FC_AVICONF1);

/* AVI Data Byte 3 */
val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
HDMI_FC_AVICONF2_SCALING_NONE;
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
+ hdmi->write(hdmi, val, HDMI_FC_AVICONF2);

/* AVI Data Byte 4 */
- hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
+ hdmi->write(hdmi, hdmi->vic, HDMI_FC_AVIVID);

/* AVI Data Byte 5- set up input and output pixel repetition */
val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
@@ -1027,22 +926,22 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
- hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
+ hdmi->write(hdmi, val, HDMI_FC_PRCONF);

/* IT Content and quantization range = don't care */
val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
+ hdmi->write(hdmi, val, HDMI_FC_AVICONF3);

/* AVI Data Bytes 6-13 */
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
+ hdmi->write(hdmi, 0, HDMI_FC_AVIETB0);
+ hdmi->write(hdmi, 0, HDMI_FC_AVIETB1);
+ hdmi->write(hdmi, 0, HDMI_FC_AVISBB0);
+ hdmi->write(hdmi, 0, HDMI_FC_AVISBB1);
+ hdmi->write(hdmi, 0, HDMI_FC_AVIELB0);
+ hdmi->write(hdmi, 0, HDMI_FC_AVIELB1);
+ hdmi->write(hdmi, 0, HDMI_FC_AVISRB0);
+ hdmi->write(hdmi, 0, HDMI_FC_AVISRB1);
}

static void hdmi_av_composer(struct imx_hdmi *hdmi,
@@ -1091,42 +990,42 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);

- hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+ hdmi->write(hdmi, inv_val, HDMI_FC_INVIDCONF);

/* Set up horizontal active pixel width */
- hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
- hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+ hdmi->write(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+ hdmi->write(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);

/* Set up vertical active lines */
- hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
- hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
+ hdmi->write(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+ hdmi->write(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);

/* Set up horizontal blanking pixel region width */
hblank = mode->htotal - mode->hdisplay;
- hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
- hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+ hdmi->write(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+ hdmi->write(hdmi, hblank, HDMI_FC_INHBLANK0);

/* Set up vertical blanking pixel region width */
vblank = mode->vtotal - mode->vdisplay;
- hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+ hdmi->write(hdmi, vblank, HDMI_FC_INVBLANK);

/* Set up HSYNC active edge delay width (in pixel clks) */
h_de_hs = mode->hsync_start - mode->hdisplay;
- hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
- hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+ hdmi->write(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+ hdmi->write(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);

/* Set up VSYNC active edge delay (in lines) */
v_de_vs = mode->vsync_start - mode->vdisplay;
- hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+ hdmi->write(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);

/* Set up HSYNC active pulse width (in pixel clks) */
hsync_len = mode->hsync_end - mode->hsync_start;
- hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
- hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+ hdmi->write(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+ hdmi->write(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);

/* Set up VSYNC active edge delay (in lines) */
vsync_len = mode->vsync_end - mode->vsync_start;
- hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
+ hdmi->write(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}

static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
@@ -1146,33 +1045,33 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
u8 clkdis;

/* control period minimum duration */
- hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
- hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
- hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
+ hdmi->write(hdmi, 12, HDMI_FC_CTRLDUR);
+ hdmi->write(hdmi, 32, HDMI_FC_EXCTRLDUR);
+ hdmi->write(hdmi, 1, HDMI_FC_EXCTRLSPAC);

/* Set to fill TMDS data channels */
- hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
- hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
- hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
+ hdmi->write(hdmi, 0x0B, HDMI_FC_CH0PREAM);
+ hdmi->write(hdmi, 0x16, HDMI_FC_CH1PREAM);
+ hdmi->write(hdmi, 0x21, HDMI_FC_CH2PREAM);

/* Enable pixel clock and tmds data path */
clkdis = 0x7F;
clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->write(hdmi, clkdis, HDMI_MC_CLKDIS);

clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->write(hdmi, clkdis, HDMI_MC_CLKDIS);

/* Enable csc path */
if (is_color_space_conversion(hdmi)) {
clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->write(hdmi, clkdis, HDMI_MC_CLKDIS);
}
}

static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
{
- hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+ hdmi->mod(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
}

/* Workaround to clear the overflow condition */
@@ -1182,27 +1081,27 @@ static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
u8 val;

/* TMDS software reset */
- hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+ hdmi->write(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);

- val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+ val = hdmi->read(hdmi, HDMI_FC_INVIDCONF);
if (hdmi->dev_type == IMX6DL_HDMI) {
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+ hdmi->write(hdmi, val, HDMI_FC_INVIDCONF);
return;
}

for (count = 0; count < 4; count++)
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+ hdmi->write(hdmi, val, HDMI_FC_INVIDCONF);
}

static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
{
- hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
- hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
+ hdmi->write(hdmi, 0, HDMI_FC_MASK2);
+ hdmi->write(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}

static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
{
- hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+ hdmi->write(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
HDMI_IH_MUTE_FC_STAT2);
}

@@ -1223,21 +1122,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 +1165,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 */
@@ -1294,18 +1193,18 @@ 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)
{
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+ hdmi->write(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);

- hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+ hdmi->write(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
HDMI_PHY_I2CM_CTLINT_ADDR);

/* enable cable hot plug irq */
- hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+ hdmi->write(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);

/* Clear Hotplug interrupts */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+ hdmi->write(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);

return 0;
}
@@ -1321,45 +1220,45 @@ static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
*
* Disable top level interrupt bits in HDMI block
*/
- ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+ ih_mute = hdmi->read(hdmi, HDMI_IH_MUTE) |
HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;

- hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+ hdmi->write(hdmi, ih_mute, HDMI_IH_MUTE);

/* by default mask all interrupts */
- hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
- hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
- hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
- hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
- hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
- hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
- hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
- hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
- hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
- hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
- hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
+ hdmi->write(hdmi, 0xff, HDMI_VP_MASK);
+ hdmi->write(hdmi, 0xff, HDMI_FC_MASK0);
+ hdmi->write(hdmi, 0xff, HDMI_FC_MASK1);
+ hdmi->write(hdmi, 0xff, HDMI_FC_MASK2);
+ hdmi->write(hdmi, 0xff, HDMI_PHY_MASK0);
+ hdmi->write(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
+ hdmi->write(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+ hdmi->write(hdmi, 0xff, HDMI_AUD_INT);
+ hdmi->write(hdmi, 0xff, HDMI_AUD_SPDIFINT);
+ hdmi->write(hdmi, 0xff, HDMI_AUD_HBR_MASK);
+ hdmi->write(hdmi, 0xff, HDMI_GP_MASK);
+ hdmi->write(hdmi, 0xff, HDMI_A_APIINTMSK);
+ hdmi->write(hdmi, 0xff, HDMI_CEC_MASK);
+ hdmi->write(hdmi, 0xff, HDMI_I2CM_INT);
+ hdmi->write(hdmi, 0xff, HDMI_I2CM_CTLINT);

/* Disable interrupts in the IH_MUTE_* registers */
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+ hdmi->write(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);

/* Enable top level interrupt bits in HDMI block */
ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
- hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+ hdmi->write(hdmi, ih_mute, HDMI_IH_MUTE);
}

static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
@@ -1378,7 +1277,7 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
connector);

- return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+ return hdmi->read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}

@@ -1454,21 +1353,40 @@ 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->set_crtc_mux)
+ hdmi->plat_data->set_crtc_mux(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 int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+ connector);
+ if (hdmi->plat_data->mode_valid)
+ return hdmi->plat_data->mode_valid(connector, mode);
+
+ return MODE_OK;
+}
+
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 = {
@@ -1484,11 +1402,12 @@ 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 = {
.get_modes = imx_hdmi_connector_get_modes,
+ .mode_valid = imx_hdmi_connector_mode_valid,
.best_encoder = imx_hdmi_connector_best_encoder,
};

@@ -1497,9 +1416,9 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
struct imx_hdmi *hdmi = dev_id;
u8 intr_stat;

- intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+ intr_stat = hdmi->read(hdmi, HDMI_IH_PHY_STAT0);
if (intr_stat)
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi->write(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);

return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
}
@@ -1510,21 +1429,21 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
u8 intr_stat;
u8 phy_int_pol;

- intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+ intr_stat = hdmi->read(hdmi, HDMI_IH_PHY_STAT0);

- phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
+ phy_int_pol = hdmi->read(hdmi, HDMI_PHY_POL0);

if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
if (phy_int_pol & HDMI_PHY_HPD) {
dev_dbg(hdmi->dev, "EVENT=plugin\n");

- hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ hdmi->mod(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);

imx_hdmi_poweron(hdmi);
} else {
dev_dbg(hdmi->dev, "EVENT=plugout\n");

- hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
+ hdmi->mod(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
HDMI_PHY_POL0);

imx_hdmi_poweroff(hdmi);
@@ -1532,20 +1451,18 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
drm_helper_hpd_irq_event(hdmi->connector.dev);
}

- hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi->write(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+ hdmi->write(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);

return IRQ_HANDLED;
}

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;

@@ -1554,7 +1471,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);

@@ -1565,55 +1482,47 @@ 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;
+ u32 val;
+
+ if (!of_property_read_u32(np, "reg-io-width", &val)) {
+ switch (val) {
+ case 4:
+ hdmi->write = hdmi_writel;
+ hdmi->read = hdmi_readl;
+ hdmi->mod = hdmi_modl;
+ hdmi->mask_write = hdmi_mask_writel;
+ break;
+ default:
+ hdmi->write = hdmi_writeb;
+ hdmi->read = hdmi_readb;
+ hdmi->mod = hdmi_modb;
+ hdmi->mask_write = hdmi_mask_writeb;
+ break;
+ }
+ } else {
+ hdmi->write = hdmi_writeb;
+ hdmi->read = hdmi_readb;
+ hdmi->mod = hdmi_modb;
+ hdmi->mask_write = hdmi_mask_writeb;
}

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 {
@@ -1635,47 +1544,15 @@ 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",
- 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->read(hdmi, HDMI_DESIGN_ID),
+ hdmi->read(hdmi, HDMI_REVISION_ID),
+ hdmi->read(hdmi, HDMI_PRODUCT_ID0),
+ hdmi->read(hdmi, HDMI_PRODUCT_ID1));

initialize_hdmi_ih_mutes(hdmi);

@@ -1689,32 +1566,25 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
* Configure registers related to HDMI interrupt
* generation before registering IRQ.
*/
- hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
+ hdmi->write(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);

/* Clear Hotplug interrupts */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+ hdmi->write(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);

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);
+ hdmi->write(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);

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,
@@ -1723,13 +1593,12 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
struct imx_hdmi *hdmi = dev_get_drvdata(dev);

/* Disable all interrupts */
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi->write(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);

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);
}

@@ -1749,17 +1618,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_pltfm_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data)
+{
+ struct imx_hdmi *hdmi;

-module_platform_driver(imx_hdmi_driver);
+ 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);
+
+ return imx_hdmi_platform_probe(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_pltfm_register);
+
+int imx_hdmi_pltfm_unregister(struct platform_device *pdev)
+{
+ return imx_hdmi_platform_remove(pdev);
+}
+EXPORT_SYMBOL_GPL(imx_hdmi_pltfm_unregister);

MODULE_AUTHOR("Sascha Hauer <[email protected]>");
MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
new file mode 100644
index 0000000..e7e8285
--- /dev/null
+++ b/include/drm/bridge/dw_hdmi.h
@@ -0,0 +1,114 @@
+/*
+ * 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>
+
+#define HDMI_EDID_LEN 512
+
+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 hdmi_vmode {
+ bool mdvi;
+ bool mhsyncpolarity;
+ bool mvsyncpolarity;
+ bool minterlaced;
+ bool mdataenablepolarity;
+
+ unsigned int mpixelclock;
+ unsigned int mpixelrepetitioninput;
+ unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+ unsigned int enc_in_format;
+ unsigned int enc_out_format;
+ unsigned int enc_color_depth;
+ unsigned int colorimetry;
+ unsigned int pix_repet_factor;
+ unsigned int hdcp_enable;
+ struct hdmi_vmode video_mode;
+};
+
+
+struct imx_hdmi {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+
+ enum imx_hdmi_devtype dev_type;
+ struct device *dev;
+
+ struct hdmi_data_info hdmi_data;
+ const struct imx_hdmi_plat_data *plat_data;
+ void *priv;
+
+ int vic;
+
+ u8 edid[HDMI_EDID_LEN];
+ bool cable_plugin;
+
+ bool phy_enabled;
+ struct drm_display_mode previous_mode;
+
+ struct i2c_adapter *ddc;
+ void __iomem *regs;
+
+ unsigned int sample_rate;
+ int ratio;
+
+ void (*write)(struct imx_hdmi *hdmi, u32 val, int offset);
+ u32 (*read)(struct imx_hdmi *hdmi, int offset);
+ void (*mod)(struct imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg);
+ void (*mask_write)(struct imx_hdmi *hdmi, u32 data, unsigned int reg,
+ u32 shift, u32 mask);
+};
+
+struct imx_hdmi_plat_data {
+ void * (*setup)(struct platform_device *pdev);
+ void (*exit)(void *priv);
+ void (*set_crtc_mux)(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_pltfm_register(struct platform_device *pdev,
+ const struct imx_hdmi_plat_data *plat_data);
+int imx_hdmi_pltfm_unregister(struct platform_device *pdev);
+#endif /* __IMX_HDMI_H__ */
--
1.9.1

2014-11-05 13:42:09

by Philipp Zabel

[permalink] [raw]
Subject: Re: [PATCH 1/2] imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi

Hi Andy,

I think separating the core from the SoC specific part is a good step
into the right direction.

Am Mittwoch, den 05.11.2014, 20:55 +0800 schrieb Andy Yan:
> imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS)
> use the interface compatible Designware HDMI IP, but they
> also have some lightly difference, such as phy pll configuration,
> register width(imx hdmi register is one byte, but rk3288 is 4
> bytes width), 4K support(imx6 doesn't support 4k, but rk3288 does),
> 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]>
[...]
> +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);
> + }

Surely this IP core needs to be clocked regardless of the SoC? How are
clocks controlled on rk3288 and jz4780?

[...]
> +/*On rockchip platform, no-word access to the hdmi
> + * register will causes an imprecise external abort
> + */
> +static inline void hdmi_writel(struct imx_hdmi *hdmi, u32 val, int offset)
> +{
> + writel(val, hdmi->regs + (offset << 2));
> +}
>
> - bool phy_enabled;
> - struct drm_display_mode previous_mode;
> +static inline u32 hdmi_readl(struct imx_hdmi *hdmi, int offset)
> +{
> + return readl(hdmi->regs + (offset << 2));
> +}
>
> - struct regmap *regmap;
> - struct i2c_adapter *ddc;
> - void __iomem *regs;
> +static void hdmi_modl(struct imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
> +{
> + u32 val = hdmi_readl(hdmi, reg) & ~mask;
>
> - unsigned int sample_rate;
> - int ratio;
> -};
> + val |= data & mask;
> + hdmi_writel(hdmi, val, reg);
> +}
>
> -static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
> +static void hdmi_mask_writel(struct imx_hdmi *hdmi, u32 data, unsigned int reg,
> + u32 shift, u32 mask)
> {
> - regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
> - IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
> - ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
> + hdmi_modl(hdmi, data << shift, mask, reg);
> }
>
> -static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
> +static inline void hdmi_writeb(struct imx_hdmi *hdmi, u32 val, int offset)
> {
> writeb(val, hdmi->regs + offset);
> }
>
> -static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
> +static inline u32 hdmi_readb(struct imx_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 imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
> {
> u8 val = hdmi_readb(hdmi, reg) & ~mask;

Do you really need to use readl instead of readb? In my opinion it would
be better then to convert the driver to use regmap for register access
(in a separate patch) and then let the SoC specific driver extension
provide the regmap to the core driver.

[...]
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> new file mode 100644
> index 0000000..e7e8285
> --- /dev/null
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -0,0 +1,114 @@
> +/*
> + * 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>
> +
> +#define HDMI_EDID_LEN 512
> +
> +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];
> +};

For a header file in include/drm/bridge maybe these struct names are a
bit too generic now.

regards
Philipp

2014-11-06 12:51:58

by Andy Yan

[permalink] [raw]
Subject: [PATCH V3 0/4] dw-hdmi: make imx hdmi publicly used by dw hdmi compatible platform

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 difference, 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 do this patch set:
patch (1): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
patch (2): move imx-hdmi to bridge/, and rename to dw-hdmi to
patch (3): add multi byte register access support
make this driver indepent of drm-imx . And we will add rockchip
platform specific code dw_hdmi-rockchip.c later, this is depend
on drm-rockchip.

Changes in V3:
- refactor multi byte register access, and split it
to one indepent patch
- convert it to a drm_bridge driver

Changes in V2:
- use git format-patch -M to generate these patch
- remove change-id
- remove from


Andy Yan (3):
imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
dw-hdmi: move imx-hdmi to bridge/dw-hdmi
dw-hdmi: add support for multi byte register width access

ykk (1):
dw-hdmi: convert dw-hdmi to drm_bridge mode

drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 619 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 5 +-
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 263 +++++++++
include/drm/bridge/dw_hdmi.h | 52 ++
8 files changed, 575 insertions(+), 373 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (75%)
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

--
1.9.1

2014-11-06 12:53:17

by Andy Yan

[permalink] [raw]
Subject: [PATCH V3 1/4] imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi

imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly difference, 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]>
---
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 214 ++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 257 ++++++++--------------------------
drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++
4 files changed, 320 insertions(+), 196 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..5422679
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,214 @@
+/*
+ * 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 aaec6b2..cd9cf86 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,23 +16,17 @@
#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
+#define HDMI_EDID_LEN 512

#define RGB 0
#define YCBCR444 1
@@ -54,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 },
@@ -121,6 +110,8 @@ struct imx_hdmi {
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 +128,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 +712,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,20 +764,19 @@ 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_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);

- 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);
-
- 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);
@@ -864,7 +784,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
}

/* 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);
@@ -1454,21 +1374,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 = {
@@ -1484,7 +1412,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 = {
@@ -1540,12 +1468,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;

@@ -1565,50 +1491,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);
@@ -1635,40 +1527,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",
@@ -1696,11 +1556,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);
@@ -1708,13 +1568,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,
@@ -1727,9 +1580,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);
}

@@ -1749,17 +1601,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..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

2014-11-06 12:54:06

by Andy Yan

[permalink] [raw]
Subject: [PATCH V3 2/4] dw-hdmi: move imx-hdmi to bridge/dw-hdmi

the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi drvier out
to drm/bridge and rename imx-hdmi to dw-hdmi

Signed-off-by: Andy Yan <[email protected]>
---
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 279 +++++++++++----------
.../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, 242 insertions(+), 219 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 cd9cf86..e561286 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]>
*/
@@ -23,8 +22,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

@@ -100,17 +100,17 @@ 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 clk *isfr_clk;
struct clk *iahb_clk;

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;

@@ -128,17 +128,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;

@@ -146,13 +146,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);
@@ -163,7 +163,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);
@@ -310,7 +310,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;
@@ -334,12 +334,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);
}
@@ -351,7 +351,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;
@@ -407,12 +407,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;
@@ -422,7 +422,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;
@@ -432,7 +432,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;
@@ -475,7 +475,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;
@@ -503,7 +503,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);
}

/*
@@ -511,7 +511,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;
@@ -606,40 +606,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)
@@ -649,7 +649,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);
@@ -663,56 +663,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);
@@ -797,15 +797,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;
@@ -826,7 +826,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;
@@ -837,10 +837,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);
@@ -852,7 +852,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;

@@ -871,7 +871,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;
@@ -965,7 +965,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;
@@ -1049,19 +1049,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;

@@ -1090,13 +1090,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;
@@ -1114,19 +1114,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;

@@ -1178,12 +1178,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)
@@ -1204,7 +1204,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);

@@ -1212,7 +1212,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);
@@ -1230,7 +1230,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;

@@ -1282,29 +1282,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;
@@ -1327,102 +1327,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);
@@ -1432,9 +1432,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;

@@ -1448,14 +1448,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);
}
@@ -1466,7 +1466,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;
@@ -1475,13 +1475,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;
@@ -1491,10 +1491,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;
@@ -1516,8 +1516,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;
@@ -1554,11 +1554,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;

@@ -1570,10 +1570,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);
@@ -1586,25 +1586,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)
@@ -1618,17 +1618,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");
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 5422679..d205874 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -7,14 +7,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;
@@ -66,7 +66,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;

@@ -91,9 +91,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);
@@ -101,7 +101,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);
@@ -121,18 +121,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,
@@ -140,33 +140,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
}, {
@@ -175,38 +175,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

2014-11-06 12:54:57

by Andy Yan

[permalink] [raw]
Subject: [PATCH V3 3/4] dw-hdmi: add support for multi byte register width access

On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width access (writeb,
readb) generate an imprecise external abort.

Signed-off-by: Andy Yan <[email protected]>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 53 ++++++++++++++++++++++++++++++++++++----
1 file changed, 48 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index e561286..a34f928 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -126,19 +126,42 @@ struct dw_hdmi {

unsigned int sample_rate;
int ratio;
+ void (*write)(u8 val, void __iomem *addr);
+ u8 (*read)(void __iomem *addr);
+ int reg_shift;
};

+static void dw_hdmi_writel(u8 val, void __iomem *addr)
+{
+ writel(val, addr);
+}
+
+static u8 dw_hdmi_readl(void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static void dw_hdmi_writeb(u8 val, void __iomem *addr)
+{
+ writeb(val, addr);
+}
+
+static u8 dw_hdmi_readb(void __iomem *addr)
+{
+ return readb(addr);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(val, hdmi->regs + (offset << hdmi->reg_shift));
}

static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi->regs + (offset << hdmi->reg_shift));
}

-static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;

@@ -146,8 +169,8 @@ static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}

-static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u32 data, unsigned int reg,
+ u32 shift, u32 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -1500,6 +1523,26 @@ 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;
+
+ if (!of_property_read_u32(np, "reg-io-width", &val)) {
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ hdmi->reg_shift = 2;
+ break;
+ default:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ hdmi->reg_shift = 0;
+ break;
+ }
+ } else {
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ hdmi->reg_shift = 0;
+ }

ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
--
1.9.1

2014-11-06 12:56:13

by Andy Yan

[permalink] [raw]
Subject: [PATCH V3 4/4] dw-hdmi: convert dw-hdmi to drm_bridge mode

From: ykk <[email protected]>

dw-hdmi is under drm/bridge, so it should be the bridge mode.
hange off the encoder to dw_hdmi-imx.c, keep the connector &
birdge in dw_hdmi.c

Signed-off-by: ykk <[email protected]>
Signed-off-by: Andy Yan <[email protected]>
---
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 a34f928..7d051ee 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>
@@ -102,7 +101,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;
@@ -1315,6 +1315,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)
{
@@ -1356,60 +1400,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)
@@ -1418,19 +1409,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,
@@ -1443,6 +1421,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;
@@ -1491,40 +1479,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;

+ 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;
+
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 4:
@@ -1570,8 +1582,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",
@@ -1612,9 +1622,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);

@@ -1622,57 +1632,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:imx-hdmi");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index d205874..76cf406 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -5,12 +5,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"

@@ -19,6 +26,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[] = {
@@ -91,48 +99,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,
@@ -140,27 +126,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,
@@ -177,23 +166,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_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 = {
@@ -209,6 +257,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

2014-11-06 15:55:23

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH V3 4/4] dw-hdmi: convert dw-hdmi to drm_bridge mode

On Thu, Nov 06, 2014 at 07:26:16PM +0800, Andy Yan wrote:
> From: ykk <[email protected]>

We need a "real" name here, sorry.

>
> dw-hdmi is under drm/bridge, so it should be the bridge mode.
> hange off the encoder to dw_hdmi-imx.c, keep the connector &
> birdge in dw_hdmi.c
>
> Signed-off-by: ykk <[email protected]>

Same here.

thanks,

greg k-h

2014-11-07 02:22:07

by Andy Yan

[permalink] [raw]
Subject: Re: [PATCH V3 4/4] dw-hdmi: convert dw-hdmi to drm_bridge mode


On 2014年11月06日 23:54, Greg Kroah-Hartman wrote:
> On Thu, Nov 06, 2014 at 07:26:16PM +0800, Andy Yan wrote:
>> From: ykk <[email protected]>
> We need a "real" name here, sorry.
>
>> dw-hdmi is under drm/bridge, so it should be the bridge mode.
>> hange off the encoder to dw_hdmi-imx.c, keep the connector &
>> birdge in dw_hdmi.c
>>
>> Signed-off-by: ykk <[email protected]>
> Same here.
>
> thanks,
>
> greg k-h
>
>
>
Sorry, these will be fixed in V4. And tks for you pointing it out.

2014-11-07 02:48:25

by Andy Yan

[permalink] [raw]
Subject: Re: [PATCH 1/2] imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi


On 2014年11月05日 21:41, Philipp Zabel wrote:
> Hi Andy,
>
> I think separating the core from the SoC specific part is a good step
> into the right direction.
>
> Am Mittwoch, den 05.11.2014, 20:55 +0800 schrieb Andy Yan:
>> imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS)
>> use the interface compatible Designware HDMI IP, but they
>> also have some lightly difference, such as phy pll configuration,
>> register width(imx hdmi register is one byte, but rk3288 is 4
>> bytes width), 4K support(imx6 doesn't support 4k, but rk3288 does),
>> 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]>
> [...]
>> +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);
>> + }
> Surely this IP core needs to be clocked regardless of the SoC? How are
> clocks controlled on rk3288 and jz4780?
yes, this IP core need to be clocked. But different Soc has different
usage of the clk, on freescale imx platform one clk is used for isfr,
one is used for iahb,
but on rockchip rk3288, one clk is used for control logic , the another
is used for hdcp.
I am not sure how are the clocks on jz4780

>
> [...]
>> +/*On rockchip platform, no-word access to the hdmi
>> + * register will causes an imprecise external abort
>> + */
>> +static inline void hdmi_writel(struct imx_hdmi *hdmi, u32 val, int offset)
>> +{
>> + writel(val, hdmi->regs + (offset << 2));
>> +}
>>
>> - bool phy_enabled;
>> - struct drm_display_mode previous_mode;
>> +static inline u32 hdmi_readl(struct imx_hdmi *hdmi, int offset)
>> +{
>> + return readl(hdmi->regs + (offset << 2));
>> +}
>>
>> - struct regmap *regmap;
>> - struct i2c_adapter *ddc;
>> - void __iomem *regs;
>> +static void hdmi_modl(struct imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
>> +{
>> + u32 val = hdmi_readl(hdmi, reg) & ~mask;
>>
>> - unsigned int sample_rate;
>> - int ratio;
>> -};
>> + val |= data & mask;
>> + hdmi_writel(hdmi, val, reg);
>> +}
>>
>> -static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
>> +static void hdmi_mask_writel(struct imx_hdmi *hdmi, u32 data, unsigned int reg,
>> + u32 shift, u32 mask)
>> {
>> - regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
>> - IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
>> - ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
>> + hdmi_modl(hdmi, data << shift, mask, reg);
>> }
>>
>> -static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
>> +static inline void hdmi_writeb(struct imx_hdmi *hdmi, u32 val, int offset)
>> {
>> writeb(val, hdmi->regs + offset);
>> }
>>
>> -static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
>> +static inline u32 hdmi_readb(struct imx_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 imx_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
>> {
>> u8 val = hdmi_readb(hdmi, reg) & ~mask;
> Do you really need to use readl instead of readb? In my opinion it would
> be better then to convert the driver to use regmap for register access
> (in a separate patch) and then let the SoC specific driver extension
> provide the regmap to the core driver.
Rockchip RK3288 can only access the hdmi register by 32bit(readl/writel)
byte access(readb/writeb) will cause an imprecise external abort

I refactor the register access in PATCH V3, if you have any
suggestion,please
tell me.
>
> [...]
>> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
>> new file mode 100644
>> index 0000000..e7e8285
>> --- /dev/null
>> +++ b/include/drm/bridge/dw_hdmi.h
>> @@ -0,0 +1,114 @@
>> +/*
>> + * 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>
>> +
>> +#define HDMI_EDID_LEN 512
>> +
>> +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];
>> +};
> For a header file in include/drm/bridge maybe these struct names are a
> bit too generic now.
>
> regards
> Philipp
>
>
>
>
>

2014-11-07 11:28:21

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 0/6] dw-hdmi: make imx hdmi publicly used by dw hdmi compatible platform

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 difference, 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 do this patch set:
patch (1): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c
patch (2): move imx-hdmi to bridge/, and rename to dw-hdmi to
make this driver indepent of drm-imx .
And we will add rockchip platform specific code dw_hdmi-rockchip.c later,
this is depend on drm-rockchip.

Changes in V4:
- return defer if can't get ddc i2c adapter
- fix checkpatch warns

Changes in V3:
- refactor multi byte register access, and split it
to one indepent patch
- convert it to a drm_bridge driver

Changes in V2:
- use git format-patch -M to generate these patch
- remove change-id
- remove from

Andy Yan (5):
imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi
dw-hdmi: move imx-hdmi to bridge/dw-hdmi
dw-hdmi: make checkpatch happy
dw-hdmi: return defer if can't get ddc i2c adapter
dw-hdmi: add support for multi byte register width access

Yakir Yang (1):
dw-hdmi: convert dw-hdmi to drm_bridge mode

drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 717 +++++++++------------
.../imx-hdmi.h => gpu/drm/bridge/dw_hdmi.h} | 5 +-
drivers/staging/imx-drm/Kconfig | 1 +
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 263 ++++++++
include/drm/bridge/dw_hdmi.h | 52 ++
8 files changed, 625 insertions(+), 421 deletions(-)
rename drivers/{staging/imx-drm/imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} (71%)
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

--
1.9.1

2014-11-07 11:31:07

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 1/6] imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi

imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS)
use the interface compatible Designware HDMI IP, but they
also have some lightly difference, 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]>
---
drivers/staging/imx-drm/Makefile | 2 +-
drivers/staging/imx-drm/dw_hdmi-imx.c | 214 ++++++++++++++++++++++++++++
drivers/staging/imx-drm/imx-hdmi.c | 257 ++++++++--------------------------
drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++
4 files changed, 320 insertions(+), 196 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..5422679
--- /dev/null
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -0,0 +1,214 @@
+/*
+ * 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 aaec6b2..cd9cf86 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -16,23 +16,17 @@
#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
+#define HDMI_EDID_LEN 512

#define RGB 0
#define YCBCR444 1
@@ -54,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 },
@@ -121,6 +110,8 @@ struct imx_hdmi {
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 +128,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 +712,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,20 +764,19 @@ 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_cfg[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15);

- 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);
-
- 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);
@@ -864,7 +784,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
}

/* 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);
@@ -1454,21 +1374,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 = {
@@ -1484,7 +1412,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 = {
@@ -1540,12 +1468,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;

@@ -1565,50 +1491,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);
@@ -1635,40 +1527,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",
@@ -1696,11 +1556,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);
@@ -1708,13 +1568,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,
@@ -1727,9 +1580,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);
}

@@ -1749,17 +1601,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..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

2014-11-07 11:33:01

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 2/6] dw-hdmi: move imx-hdmi to bridge/dw-hdmi

the original imx hdmi driver is under staging/imx-drm,
which depends on imx-drm, so move the imx hdmi drvier out
to drm/bridge and rename imx-hdmi to dw-hdmi

Signed-off-by: Andy Yan <[email protected]>
---
drivers/gpu/drm/bridge/Kconfig | 5 +
drivers/gpu/drm/bridge/Makefile | 1 +
.../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 279 +++++++++++----------
.../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, 242 insertions(+), 219 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 cd9cf86..e561286 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]>
*/
@@ -23,8 +22,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

@@ -100,17 +100,17 @@ 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 clk *isfr_clk;
struct clk *iahb_clk;

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;

@@ -128,17 +128,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;

@@ -146,13 +146,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);
@@ -163,7 +163,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);
@@ -310,7 +310,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;
@@ -334,12 +334,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);
}
@@ -351,7 +351,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;
@@ -407,12 +407,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;
@@ -422,7 +422,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;
@@ -432,7 +432,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;
@@ -475,7 +475,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;
@@ -503,7 +503,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);
}

/*
@@ -511,7 +511,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;
@@ -606,40 +606,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)
@@ -649,7 +649,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);
@@ -663,56 +663,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);
@@ -797,15 +797,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;
@@ -826,7 +826,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;
@@ -837,10 +837,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);
@@ -852,7 +852,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;

@@ -871,7 +871,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;
@@ -965,7 +965,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;
@@ -1049,19 +1049,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;

@@ -1090,13 +1090,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;
@@ -1114,19 +1114,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;

@@ -1178,12 +1178,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)
@@ -1204,7 +1204,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);

@@ -1212,7 +1212,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);
@@ -1230,7 +1230,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;

@@ -1282,29 +1282,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;
@@ -1327,102 +1327,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);
@@ -1432,9 +1432,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;

@@ -1448,14 +1448,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);
}
@@ -1466,7 +1466,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;
@@ -1475,13 +1475,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;
@@ -1491,10 +1491,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;
@@ -1516,8 +1516,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;
@@ -1554,11 +1554,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;

@@ -1570,10 +1570,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);
@@ -1586,25 +1586,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)
@@ -1618,17 +1618,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");
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 5422679..d205874 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -7,14 +7,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;
@@ -66,7 +66,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;

@@ -91,9 +91,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);
@@ -101,7 +101,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);
@@ -121,18 +121,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,
@@ -140,33 +140,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
}, {
@@ -175,38 +175,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

2014-11-07 11:33:59

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 3/6] dw-hdmi: make checkpatch happy

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]>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 99 ++++++++++++++++++++--------------------
1 file changed, 49 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index e561286..693a379 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -146,8 +146,8 @@ static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
hdmi_writeb(hdmi, val, reg);
}

-static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u32 data, unsigned int reg,
+ u32 shift, u32 mask)
{
hdmi_modb(hdmi, data << shift, mask, reg);
}
@@ -311,7 +311,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
}

static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
- unsigned long pixel_clk)
+ unsigned long pixel_clk)
{
unsigned int clk_n, clk_cts;

@@ -322,7 +322,7 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,

if (!clk_cts) {
dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
+ __func__, pixel_clk);
return;
}

@@ -461,13 +461,11 @@ static void dw_hdmi_update_csc_coeffs(struct dw_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);
}

@@ -519,21 +517,22 @@ static void hdmi_video_packetize(struct dw_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)
@@ -545,8 +544,9 @@ static void hdmi_video_packetize(struct dw_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) &
@@ -607,34 +607,34 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
}

static inline void hdmi_phy_test_clear(struct dw_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 dw_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 dw_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 dw_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
}

static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
- unsigned char bit)
+ unsigned char bit)
{
hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
}
@@ -650,21 +650,21 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
}

static void __hdmi_phy_i2c_write(struct dw_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 dw_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+ unsigned char addr)
{
__hdmi_phy_i2c_write(hdmi, data, addr);
return 0;
@@ -760,7 +760,7 @@ static int hdmi_phy_configure(struct dw_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 */
@@ -777,9 +777,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
break;

if (curr_ctr[i].mpixelclock == (~0UL)) {
- 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;
}

@@ -1143,21 +1142,21 @@ static int dw_hdmi_setup(struct dw_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;
@@ -1186,9 +1185,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
dw_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 */
@@ -1453,7 +1452,7 @@ static irqreturn_t dw_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);

dw_hdmi_poweroff(hdmi);
}
@@ -1480,7 +1479,7 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
DRM_MODE_ENCODER_TMDS);

drm_connector_helper_add(&hdmi->connector,
- &dw_hdmi_connector_helper_funcs);
+ &dw_hdmi_connector_helper_funcs);
drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);

@@ -1531,11 +1530,11 @@ static int dw_hdmi_bind(struct device *dev, struct device *master, void *data)
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",
- 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

2014-11-07 11:34:50

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 4/6] dw-hdmi: return defer if can't get ddc i2c adapter

drm driver may probe before the i2c bus, so the driver should
defer probing untill it is avaliable

Signed-off-by: Andy Yan <[email protected]>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index 693a379..df76a8c 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -1503,8 +1503,11 @@ static int dw_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

2014-11-07 11:35:47

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 5/6] dw-hdmi: add support for multi byte register width access

On rockchip rk3288, only word(32-bit) accesses are
permitted for hdmi registers. Byte width access (writeb,
readb) generates an imprecise external abort.

Signed-off-by: Andy Yan <[email protected]>
---
drivers/gpu/drm/bridge/dw_hdmi.c | 49 +++++++++++++++++++++++++++++++++++++---
1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
index df76a8c..9867642 100644
--- a/drivers/gpu/drm/bridge/dw_hdmi.c
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -126,19 +126,42 @@ struct dw_hdmi {

unsigned int sample_rate;
int ratio;
+ void (*write)(u8 val, void __iomem *addr);
+ u8 (*read)(void __iomem *addr);
+ int reg_shift;
};

+static void dw_hdmi_writel(u8 val, void __iomem *addr)
+{
+ writel(val, addr);
+}
+
+static u8 dw_hdmi_readl(void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static void dw_hdmi_writeb(u8 val, void __iomem *addr)
+{
+ writeb(val, addr);
+}
+
+static u8 dw_hdmi_readb(void __iomem *addr)
+{
+ return readb(addr);
+}
+
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- writeb(val, hdmi->regs + offset);
+ hdmi->write(val, hdmi->regs + (offset << hdmi->reg_shift));
}

static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return readb(hdmi->regs + offset);
+ return hdmi->read(hdmi->regs + (offset << hdmi->reg_shift));
}

-static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+static void hdmi_modb(struct dw_hdmi *hdmi, u32 data, u32 mask, unsigned reg)
{
u8 val = hdmi_readb(hdmi, reg) & ~mask;

@@ -1499,6 +1522,26 @@ 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;
+
+ if (!of_property_read_u32(np, "reg-io-width", &val)) {
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ hdmi->reg_shift = 2;
+ break;
+ default:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ hdmi->reg_shift = 0;
+ break;
+ }
+ } else {
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ hdmi->reg_shift = 0;
+ }

ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
--
1.9.1

2014-11-07 11:36:48

by Andy Yan

[permalink] [raw]
Subject: [PATCH V4 6/6] dw-hdmi: convert dw-hdmi to drm_bridge mode

From: Yakir Yang <[email protected]>

dw-hdmi is under drm/bridge, so it should be the bridge mode.
hange off the encoder to dw_hdmi-imx.c, keep the connector &
birdge in dw_hdmi.c

Signed-off-by: Andy Yan <[email protected]>
Signed-off-by: Yakir Yang <[email protected]>
---
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 9867642..4d25f8f 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>
@@ -102,7 +101,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;
@@ -1314,6 +1314,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)
{
@@ -1355,60 +1399,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)
@@ -1417,19 +1408,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,
@@ -1442,6 +1420,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;
@@ -1490,40 +1478,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;

+ 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;
+
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 4:
@@ -1572,8 +1584,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",
@@ -1614,9 +1624,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);

@@ -1624,57 +1634,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:imx-hdmi");
diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c
index d205874..76cf406 100644
--- a/drivers/staging/imx-drm/dw_hdmi-imx.c
+++ b/drivers/staging/imx-drm/dw_hdmi-imx.c
@@ -5,12 +5,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"

@@ -19,6 +26,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[] = {
@@ -91,48 +99,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,
@@ -140,27 +126,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,
@@ -177,23 +166,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_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 = {
@@ -209,6 +257,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

2014-11-07 11:45:51

by Lucas Stach

[permalink] [raw]
Subject: Re: [PATCH V4 5/6] dw-hdmi: add support for multi byte register width access

Am Freitag, den 07.11.2014, 19:35 +0800 schrieb Andy Yan:
> On rockchip rk3288, only word(32-bit) accesses are
> permitted for hdmi registers. Byte width access (writeb,
> readb) generates an imprecise external abort.
>
> Signed-off-by: Andy Yan <[email protected]>
> ---
> drivers/gpu/drm/bridge/dw_hdmi.c | 49 +++++++++++++++++++++++++++++++++++++---
> 1 file changed, 46 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
> index df76a8c..9867642 100644
> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
> @@ -126,19 +126,42 @@ struct dw_hdmi {
[...]
> + u32 val;
> +
> + if (!of_property_read_u32(np, "reg-io-width", &val)) {
> + switch (val) {
> + case 4:
> + hdmi->write = dw_hdmi_writel;
> + hdmi->read = dw_hdmi_readl;
> + hdmi->reg_shift = 2;
> + break;
> + default:
> + hdmi->write = dw_hdmi_writeb;
> + hdmi->read = dw_hdmi_readb;
> + hdmi->reg_shift = 0;
> + break;
> + }
> + } else {
> + hdmi->write = dw_hdmi_writeb;
> + hdmi->read = dw_hdmi_readb;
> + hdmi->reg_shift = 0;
> + }
>
> ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
> if (ddc_node) {

This should throw an error if the property value in devicetree is not
recognized. This could be simplified like this:

u32 val = 1;

// this won't touch val if it can't find the property
of_property_read_u32(np, "reg-io-width", &val)


switch (val) {
case 4:
hdmi->write = dw_hdmi_writel;
hdmi->read = dw_hdmi_readl;
hdmi->reg_shift = 2;
break;
case 1:
hdmi->write = dw_hdmi_writeb;
hdmi->read = dw_hdmi_readb;
hdmi->reg_shift = 0;
break;
default:
dev_err(dev, "unrecognized value for reg-io-width");
// error handling
}

Also the DT binding doc for this property is missing.

Regards,
Lucas
--
Pengutronix e.K. | Lucas Stach |
Industrial Linux Solutions | http://www.pengutronix.de/ |

2014-11-08 03:19:58

by Andy Yan

[permalink] [raw]
Subject: Re: [PATCH V4 5/6] dw-hdmi: add support for multi byte register width access


On 2014年11月07日 19:45, Lucas Stach wrote:
> Am Freitag, den 07.11.2014, 19:35 +0800 schrieb Andy Yan:
>> On rockchip rk3288, only word(32-bit) accesses are
>> permitted for hdmi registers. Byte width access (writeb,
>> readb) generates an imprecise external abort.
>>
>> Signed-off-by: Andy Yan <[email protected]>
>> ---
>> drivers/gpu/drm/bridge/dw_hdmi.c | 49 +++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 46 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
>> index df76a8c..9867642 100644
>> --- a/drivers/gpu/drm/bridge/dw_hdmi.c
>> +++ b/drivers/gpu/drm/bridge/dw_hdmi.c
>> @@ -126,19 +126,42 @@ struct dw_hdmi {
> [...]
>> + u32 val;
>> +
>> + if (!of_property_read_u32(np, "reg-io-width", &val)) {
>> + switch (val) {
>> + case 4:
>> + hdmi->write = dw_hdmi_writel;
>> + hdmi->read = dw_hdmi_readl;
>> + hdmi->reg_shift = 2;
>> + break;
>> + default:
>> + hdmi->write = dw_hdmi_writeb;
>> + hdmi->read = dw_hdmi_readb;
>> + hdmi->reg_shift = 0;
>> + break;
>> + }
>> + } else {
>> + hdmi->write = dw_hdmi_writeb;
>> + hdmi->read = dw_hdmi_readb;
>> + hdmi->reg_shift = 0;
>> + }
>>
>> ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
>> if (ddc_node) {
> This should throw an error if the property value in devicetree is not
> recognized. This could be simplified like this:
>
> u32 val = 1;
>
> // this won't touch val if it can't find the property
> of_property_read_u32(np, "reg-io-width", &val)
>
>
> switch (val) {
> case 4:
> hdmi->write = dw_hdmi_writel;
> hdmi->read = dw_hdmi_readl;
> hdmi->reg_shift = 2;
> break;
> case 1:
> hdmi->write = dw_hdmi_writeb;
> hdmi->read = dw_hdmi_readb;
> hdmi->reg_shift = 0;
> break;
> default:
> dev_err(dev, "unrecognized value for reg-io-width");
> // error handling
> }
>
> Also the DT binding doc for this property is missing.
>
> Regards,
> Lucas
thanks for your suggestion, I will take it.
this properity is optional, I will add it to DT binding doc