* [PATCH v7 0/7] dw-hdmi: convert imx hdmi to bridge/dw-hdmi @ 2014-11-11 12:12 Andy Yan 2014-11-11 12:12 ` [PATCH v7 3/7] staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi Andy Yan 2014-11-11 12:12 ` [PATCH v7 7/7] dt-bindings: add document for dw-hdmi Andy Yan 0 siblings, 2 replies; 6+ messages in thread From: Andy Yan @ 2014-11-11 12:12 UTC (permalink / raw) To: airlied, Zubair.Kakakhel, rmk+kernel, fabio.estevam, heiko, djkurtz, ykk Cc: devel, devicetree, Pawel Moll, Arnd Bergmann, Ian Campbell, Greg Kroah-Hartman, Josh Boyer, Dave Airlie, linux-kernel, dri-devel, Inki Dae, Rob Herring, Sean Paul, Philipp Zabel, Kumar Gala, Grant Likely, Andy Yan, Mark Rutland, Shawn Guo, Lucas Stach We found freescale imx5 and rockchip rk3288 and Ingenic JZ4780 (Xburst/MIPS) use the interface compatible Designware HDMI IP, but they also have some lightly differences, such as phy pll configuration, register width(imx hdmi register is one byte, but rk3288 is 4 bytes width and can only access by word), 4K support(imx6 doesn't support 4k, but rk3288 does). To reuse the imx-hdmi driver, we do this patch set: (1): fix some CodingStyle warning to make checkpatch happy (2): split out imx-soc code from imx-hdmi to dw_hdmi-imx.c (3): move imx-hdmi to bridge/dw-hdmi, and convert it to a drm_bridge driver And we will add rockchip platform specific code dw_hdmi-rockchip.c later, which is depend on drm-rockchip. Changes in v7: - remove unused variables from structure dw_hdmi - remove a wrong modification - add copyrights for dw_hdmi-imx.c Changes in v6: - rearrange the patch order - move some modification to patch#6 - refactor register access without reg_shift - move some modification from patch#5 Changes in v5: - refactor reg-io-width Changes in v4: - fix checkpatch CHECK - defer probe ddc i2c adapter Changes in v3: - split multi register access to one indepent patch Changes in v2: - use git format -M to generate these patch Andy Yan (6): staging: imx-drm: imx-hdmi: make checkpatch happy staging: imx-drm: imx-hdmi: return defer if can't get ddc i2c adapter staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi staging: imx-drm: imx-hdmi: move imx-hdmi to bridge/dw-hdmi drm: bridge/dw-hdmi: add support for multi byte register width access dt-bindings: add document for dw-hdmi Yakir Yang (1): drm: bridge/dw-hdmi: convert dw-hdmi to drm_bridge mode .../devicetree/bindings/drm/bridge/dw-hdmi.txt | 38 ++ drivers/gpu/drm/bridge/Kconfig | 5 + drivers/gpu/drm/bridge/Makefile | 1 + .../imx-hdmi.c => gpu/drm/bridge/dw_hdmi.c} | 723 +++++++++------------ .../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 | 266 ++++++++ include/drm/bridge/dw_hdmi.h | 52 ++ 9 files changed, 670 insertions(+), 423 deletions(-) create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt 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 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 3/7] staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi 2014-11-11 12:12 [PATCH v7 0/7] dw-hdmi: convert imx hdmi to bridge/dw-hdmi Andy Yan @ 2014-11-11 12:12 ` Andy Yan 2014-11-11 12:12 ` [PATCH v7 7/7] dt-bindings: add document for dw-hdmi Andy Yan 1 sibling, 0 replies; 6+ messages in thread From: Andy Yan @ 2014-11-11 12:12 UTC (permalink / raw) To: airlied, Zubair.Kakakhel, rmk+kernel, fabio.estevam, heiko, djkurtz, ykk Cc: devel, devicetree, Josh Boyer, Greg Kroah-Hartman, linux-kernel, Rob Herring, Philipp Zabel, Grant Likely, Andy Yan, Shawn Guo imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS) use the interface compatible Designware HDMI IP, but they also have some lightly differences, such as phy pll configuration, register width, 4K support, clk useage, and the crtc mux configuration is also platform specific. To reuse the imx hdmi driver, split the platform specific code out to dw_hdmi-imx.c. Signed-off-by: Andy Yan <andy.yan@rock-chips.com> --- Changes in v7: - remove unused variables from structure dw_hdmi - remove a wrong modification - add copyrights for dw_hdmi-imx.c Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/staging/imx-drm/Makefile | 2 +- drivers/staging/imx-drm/dw_hdmi-imx.c | 217 +++++++++++++++++++++++++++++ drivers/staging/imx-drm/imx-hdmi.c | 255 ++++++++-------------------------- drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++ 4 files changed, 322 insertions(+), 195 deletions(-) create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index 582c438..809027d 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o -obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o +obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o dw_hdmi-imx.o diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c new file mode 100644 index 0000000..0db978e --- /dev/null +++ b/drivers/staging/imx-drm/dw_hdmi-imx.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <video/imx-ipu-v3.h> +#include <linux/regmap.h> +#include <linux/clk.h> + +#include "imx-drm.h" +#include "imx-hdmi.h" + +struct imx_hdmi_priv { + struct device *dev; + struct clk *isfr_clk; + struct clk *iahb_clk; + struct regmap *regmap; +}; + +static const struct mpll_config imx_mpll_cfg[] = { + { + 45250000, { + { 0x01e0, 0x0000 }, + { 0x21e1, 0x0000 }, + { 0x41e2, 0x0000 } + }, + }, { + 92500000, { + { 0x0140, 0x0005 }, + { 0x2141, 0x0005 }, + { 0x4142, 0x0005 }, + }, + }, { + 148500000, { + { 0x00a0, 0x000a }, + { 0x20a1, 0x000a }, + { 0x40a2, 0x000a }, + }, + }, { + ~0UL, { + { 0x00a0, 0x000a }, + { 0x2001, 0x000f }, + { 0x4002, 0x000f }, + }, + } +}; + +static const struct curr_ctrl imx_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { + 54000000, { 0x091c, 0x091c, 0x06dc }, + }, { + 58400000, { 0x091c, 0x06dc, 0x06dc }, + }, { + 72000000, { 0x06dc, 0x06dc, 0x091c }, + }, { + 74250000, { 0x06dc, 0x0b5c, 0x091c }, + }, { + 118800000, { 0x091c, 0x091c, 0x06dc }, + }, { + 216000000, { 0x06dc, 0x0b5c, 0x091c }, + } +}; + +static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi) +{ + struct device_node *np = hdmi->dev->of_node; + + hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); + if (IS_ERR(hdmi->regmap)) { + dev_err(hdmi->dev, "Unable to get gpr\n"); + return PTR_ERR(hdmi->regmap); + } + + hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); + if (IS_ERR(hdmi->isfr_clk)) { + dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n"); + return PTR_ERR(hdmi->isfr_clk); + } + + hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); + if (IS_ERR(hdmi->iahb_clk)) { + dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n"); + return PTR_ERR(hdmi->iahb_clk); + } + + return 0; +} + +static void *imx_hdmi_imx_setup(struct platform_device *pdev) +{ + struct imx_hdmi_priv *hdmi; + int ret; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return ERR_PTR(-ENOMEM); + hdmi->dev = &pdev->dev; + + ret = imx_hdmi_parse_dt(hdmi); + if (ret < 0) + return ERR_PTR(ret); + ret = clk_prepare_enable(hdmi->isfr_clk); + if (ret) { + dev_err(hdmi->dev, + "Cannot enable HDMI isfr clock: %d\n", ret); + return ERR_PTR(ret); + } + + ret = clk_prepare_enable(hdmi->iahb_clk); + if (ret) { + dev_err(hdmi->dev, + "Cannot enable HDMI iahb clock: %d\n", ret); + return ERR_PTR(ret); + } + + return hdmi; +} + +static void imx_hdmi_imx_exit(void *priv) +{ + struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv; + + clk_disable_unprepare(hdmi->isfr_clk); + + clk_disable_unprepare(hdmi->iahb_clk); +} + +static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder) +{ + struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv; + int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); + + regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, + IMX6Q_GPR3_HDMI_MUX_CTL_MASK, + mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); +} + +static void imx_hdmi_imx_encoder_prepare(struct drm_connector *connector, + struct drm_encoder *encoder) +{ + imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); +} + +static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = { + .setup = imx_hdmi_imx_setup, + .exit = imx_hdmi_imx_exit, + .encoder_commit = imx_hdmi_imx_encoder_commit, + .encoder_prepare = imx_hdmi_imx_encoder_prepare, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .dev_type = IMX6Q_HDMI, +}; + +static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = { + .setup = imx_hdmi_imx_setup, + .exit = imx_hdmi_imx_exit, + .encoder_commit = imx_hdmi_imx_encoder_commit, + .encoder_prepare = imx_hdmi_imx_encoder_prepare, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .dev_type = IMX6DL_HDMI, +}; + +static const struct of_device_id imx_hdmi_imx_ids[] = { + { .compatible = "fsl,imx6q-hdmi", + .data = &imx6q_hdmi_drv_data + }, { + .compatible = "fsl,imx6dl-hdmi", + .data = &imx6dl_hdmi_drv_data + }, + {}, +}; +MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids); + +static int imx_hdmi_imx_probe(struct platform_device *pdev) +{ + const struct imx_hdmi_plat_data *plat_data; + const struct of_device_id *match; + + if (!pdev->dev.of_node) + return -ENODEV; + + match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node); + plat_data = match->data; + + return imx_hdmi_platform_register(pdev, plat_data); +} + +static int imx_hdmi_imx_remove(struct platform_device *pdev) +{ + return imx_hdmi_platform_unregister(pdev); +} + +static struct platform_driver imx_hdmi_imx_platform_driver = { + .probe = imx_hdmi_imx_probe, + .remove = imx_hdmi_imx_remove, + .driver = { + .name = "dwhdmi-imx", + .owner = THIS_MODULE, + .of_match_table = imx_hdmi_imx_ids, + }, +}; + +module_platform_driver(imx_hdmi_imx_platform_driver); + +MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>"); +MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:dwhdmi-imx"); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index c2b035a..c7e5f12 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -16,21 +16,16 @@ #include <linux/irq.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/clk.h> #include <linux/hdmi.h> -#include <linux/regmap.h> -#include <linux/mfd/syscon.h> -#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/of_device.h> +#include <drm/drm_of.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_encoder_slave.h> -#include <video/imx-ipu-v3.h> #include "imx-hdmi.h" -#include "imx-drm.h" #define HDMI_EDID_LEN 512 @@ -54,11 +49,6 @@ enum hdmi_datamap { YCbCr422_12B = 0x12, }; -enum imx_hdmi_devtype { - IMX6Q_HDMI, - IMX6DL_HDMI, -}; - static const u16 csc_coeff_default[3][4] = { { 0x2000, 0x0000, 0x0000, 0x0000 }, { 0x0000, 0x2000, 0x0000, 0x0000 }, @@ -117,10 +107,10 @@ struct imx_hdmi { enum imx_hdmi_devtype dev_type; struct device *dev; - struct clk *isfr_clk; - struct clk *iahb_clk; struct hdmi_data_info hdmi_data; + const struct imx_hdmi_plat_data *plat_data; + void *priv; int vic; u8 edid[HDMI_EDID_LEN]; @@ -137,13 +127,6 @@ struct imx_hdmi { int ratio; }; -static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di) -{ - regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, - IMX6Q_GPR3_HDMI_MUX_CTL_MASK, - ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); -} - static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) { writeb(val, hdmi->regs + offset); @@ -728,76 +711,13 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } -enum { - RES_8, - RES_10, - RES_12, - RES_MAX, -}; - -struct mpll_config { - unsigned long mpixelclock; - struct { - u16 cpce; - u16 gmp; - } res[RES_MAX]; -}; - -static const struct mpll_config mpll_config[] = { - { - 45250000, { - { 0x01e0, 0x0000 }, - { 0x21e1, 0x0000 }, - { 0x41e2, 0x0000 } - }, - }, { - 92500000, { - { 0x0140, 0x0005 }, - { 0x2141, 0x0005 }, - { 0x4142, 0x0005 }, - }, - }, { - 148500000, { - { 0x00a0, 0x000a }, - { 0x20a1, 0x000a }, - { 0x40a2, 0x000a }, - }, - }, { - ~0UL, { - { 0x00a0, 0x000a }, - { 0x2001, 0x000f }, - { 0x4002, 0x000f }, - }, - } -}; - -struct curr_ctrl { - unsigned long mpixelclock; - u16 curr[RES_MAX]; -}; - -static const struct curr_ctrl curr_ctrl[] = { - /* pixelclk bpp8 bpp10 bpp12 */ - { - 54000000, { 0x091c, 0x091c, 0x06dc }, - }, { - 58400000, { 0x091c, 0x06dc, 0x06dc }, - }, { - 72000000, { 0x06dc, 0x06dc, 0x091c }, - }, { - 74250000, { 0x06dc, 0x0b5c, 0x091c }, - }, { - 118800000, { 0x091c, 0x091c, 0x06dc }, - }, { - 216000000, { 0x06dc, 0x0b5c, 0x091c }, - } -}; - static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, unsigned char res, int cscon) { unsigned res_idx, i; u8 val, msec; + const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg; + const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr; if (prep) return -EINVAL; @@ -843,27 +763,27 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, hdmi_phy_test_clear(hdmi, 0); /* PLL/MPLL Cfg - always match on final entry */ - for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++) + for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) if (hdmi->hdmi_data.video_mode.mpixelclock <= - mpll_config[i].mpixelclock) + mpll_cfg[i].mpixelclock) break; - hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); - hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); + hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06); + hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15); - for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++) + for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++) if (hdmi->hdmi_data.video_mode.mpixelclock <= - curr_ctrl[i].mpixelclock) + curr_ctr[i].mpixelclock) break; - if (i >= ARRAY_SIZE(curr_ctrl)) { + if (curr_ctr[i].mpixelclock == (~0UL)) { dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", hdmi->hdmi_data.video_mode.mpixelclock); return -EINVAL; } /* CURRCTRL */ - hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10); + hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10); hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); @@ -1453,21 +1373,29 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); imx_hdmi_poweroff(hdmi); - imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); + + if (hdmi->plat_data->encoder_prepare) + hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder); } static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) { struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); - int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); - imx_hdmi_set_ipu_di_mux(hdmi, mux); + if (hdmi->plat_data->encoder_commit) + hdmi->plat_data->encoder_commit(hdmi->priv, encoder); imx_hdmi_poweron(hdmi); } +void imx_hdmi_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { - .destroy = imx_drm_encoder_destroy, + .destroy = drm_encoder_cleanup, }; static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { @@ -1483,7 +1411,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_hdmi_connector_detect, - .destroy = imx_drm_connector_destroy, + .destroy = imx_hdmi_connector_destroy, }; static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { @@ -1539,12 +1467,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) { - int ret; + struct drm_encoder *encoder = &hdmi->encoder; + struct device *dev = hdmi->dev; - ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder, - hdmi->dev->of_node); - if (ret) - return ret; + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; @@ -1564,50 +1490,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) return 0; } -static struct platform_device_id imx_hdmi_devtype[] = { - { - .name = "imx6q-hdmi", - .driver_data = IMX6Q_HDMI, - }, { - .name = "imx6dl-hdmi", - .driver_data = IMX6DL_HDMI, - }, { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype); - -static const struct of_device_id imx_hdmi_dt_ids[] = { -{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], }, -{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], }, -{ /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); - static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); - const struct of_device_id *of_id = - of_match_device(imx_hdmi_dt_ids, dev); + struct imx_hdmi *hdmi = platform_get_drvdata(pdev); struct drm_device *drm = data; struct device_node *np = dev->of_node; struct device_node *ddc_node; - struct imx_hdmi *hdmi; struct resource *iores; int ret, irq; - hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; - - hdmi->dev = dev; - hdmi->sample_rate = 48000; - hdmi->ratio = 100; - - if (of_id) { - const struct platform_device_id *device_id = of_id->data; - - hdmi->dev_type = device_id->driver_data; - } - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); @@ -1637,40 +1529,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); - hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); - if (IS_ERR(hdmi->regmap)) - return PTR_ERR(hdmi->regmap); - - hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); - if (IS_ERR(hdmi->isfr_clk)) { - ret = PTR_ERR(hdmi->isfr_clk); - dev_err(hdmi->dev, - "Unable to get HDMI isfr clk: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(hdmi->isfr_clk); - if (ret) { - dev_err(hdmi->dev, - "Cannot enable HDMI isfr clock: %d\n", ret); - return ret; - } - - hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); - if (IS_ERR(hdmi->iahb_clk)) { - ret = PTR_ERR(hdmi->iahb_clk); - dev_err(hdmi->dev, - "Unable to get HDMI iahb clk: %d\n", ret); - goto err_isfr; - } - - ret = clk_prepare_enable(hdmi->iahb_clk); - if (ret) { - dev_err(hdmi->dev, - "Cannot enable HDMI iahb clock: %d\n", ret); - goto err_isfr; - } - + if (hdmi->plat_data->setup) + hdmi->priv = hdmi->plat_data->setup(pdev); /* Product and revision IDs */ dev_info(dev, "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", @@ -1698,11 +1558,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) ret = imx_hdmi_fb_registered(hdmi); if (ret) - goto err_iahb; + return ret; ret = imx_hdmi_register(drm, hdmi); if (ret) - goto err_iahb; + return ret; /* Unmute interrupts */ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); @@ -1710,13 +1570,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) dev_set_drvdata(dev, hdmi); return 0; - -err_iahb: - clk_disable_unprepare(hdmi->iahb_clk); -err_isfr: - clk_disable_unprepare(hdmi->isfr_clk); - - return ret; } static void imx_hdmi_unbind(struct device *dev, struct device *master, @@ -1729,9 +1582,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master, hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->encoder.funcs->destroy(&hdmi->encoder); - - clk_disable_unprepare(hdmi->iahb_clk); - clk_disable_unprepare(hdmi->isfr_clk); + if (hdmi->plat_data->exit) + hdmi->plat_data->exit(hdmi->priv); i2c_put_adapter(hdmi->ddc); } @@ -1751,17 +1603,32 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev) return 0; } -static struct platform_driver imx_hdmi_driver = { - .probe = imx_hdmi_platform_probe, - .remove = imx_hdmi_platform_remove, - .driver = { - .name = "imx-hdmi", - .owner = THIS_MODULE, - .of_match_table = imx_hdmi_dt_ids, - }, -}; +int imx_hdmi_platform_register(struct platform_device *pdev, + const struct imx_hdmi_plat_data *plat_data) +{ + struct imx_hdmi *hdmi; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; -module_platform_driver(imx_hdmi_driver); + hdmi->plat_data = plat_data; + hdmi->dev = &pdev->dev; + hdmi->dev_type = plat_data->dev_type; + hdmi->sample_rate = 48000; + hdmi->ratio = 100; + + platform_set_drvdata(pdev, hdmi); + + return imx_hdmi_platform_probe(pdev); +} +EXPORT_SYMBOL_GPL(imx_hdmi_platform_register); + +int imx_hdmi_platform_unregister(struct platform_device *pdev) +{ + return imx_hdmi_platform_remove(pdev); +} +EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister); MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); 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 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v7 7/7] dt-bindings: add document for dw-hdmi 2014-11-11 12:12 [PATCH v7 0/7] dw-hdmi: convert imx hdmi to bridge/dw-hdmi Andy Yan 2014-11-11 12:12 ` [PATCH v7 3/7] staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi Andy Yan @ 2014-11-11 12:12 ` Andy Yan [not found] ` <1415707952-11415-8-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> 1 sibling, 1 reply; 6+ messages in thread From: Andy Yan @ 2014-11-11 12:12 UTC (permalink / raw) To: airlied, Zubair.Kakakhel, rmk+kernel, fabio.estevam, heiko, djkurtz, ykk Cc: Andy Yan, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree, linux-kernel Signed-off-by: Andy Yan <andy.yan@rock-chips.com> --- Changes in v7: None Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None .../devicetree/bindings/drm/bridge/dw-hdmi.txt | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt diff --git a/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt new file mode 100644 index 0000000..aa7ed17 --- /dev/null +++ b/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt @@ -0,0 +1,38 @@ +DesignWare HDMI bridge bindings + +Required properities: +- compatibel: platform specific such as "fsl,imx6q-hdmi","fsl,imx6dl-hdmi" + "rockchip,rk3288-dw-hdmi" +- reg: physical base address of the controller and length +- ddc-i2c-bus: the ddc i2c bus +- interrupts: The interrupt number to the cpu + +Optional properties +- reg-io-width: the width of the reg:1,4, default set to 1 if not present + +Example: + hdmi: hdmi@0120000 { + compatible = "fsl,imx6q-hdmi"; + reg = <0x00120000 0x9000>; + interrupts = <0 115 0x04>; + gpr = <&gpr>; + clocks = <&clks 123>, <&clks 124>; + clock-names = "iahb", "isfr"; + ddc-i2c-bus = <&i2c2>; + + port@0 { + reg = <0>; + + hdmi_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_hdmi>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_hdmi>; + }; + }; + }; -- 1.9.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
[parent not found: <1415707952-11415-8-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* Re: [PATCH v7 7/7] dt-bindings: add document for dw-hdmi [not found] ` <1415707952-11415-8-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> @ 2014-11-11 12:24 ` Mark Rutland 2014-11-11 13:33 ` Andy Yan 0 siblings, 1 reply; 6+ messages in thread From: Mark Rutland @ 2014-11-11 12:24 UTC (permalink / raw) To: Andy Yan Cc: airlied-cv59FeDIM0c@public.gmane.org, Zubair.Kakakhel-1AXoQHu6uovQT0dZR+AlfA@public.gmane.org, rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org, fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org, heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org, djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org, ykk-TNX95d0MmH7DzftRWevZcw@public.gmane.org, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org On Tue, Nov 11, 2014 at 12:12:32PM +0000, Andy Yan wrote: > Signed-off-by: Andy Yan <andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> > --- > > Changes in v7: None > Changes in v6: None > Changes in v5: None > Changes in v4: None > Changes in v3: None > Changes in v2: None > > .../devicetree/bindings/drm/bridge/dw-hdmi.txt | 38 ++++++++++++++++++++++ > 1 file changed, 38 insertions(+) > create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt > > diff --git a/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt > new file mode 100644 > index 0000000..aa7ed17 > --- /dev/null > +++ b/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt > @@ -0,0 +1,38 @@ > +DesignWare HDMI bridge bindings > + > +Required properities: > +- compatibel: platform specific such as "fsl,imx6q-hdmi","fsl,imx6dl-hdmi" > + "rockchip,rk3288-dw-hdmi" s/compatibel/compatible/ This should include the _precise_ strings you expect. Please format this as a list, e.g. - compatible: should contain one of: * "fsl,imx6q-hdmi" * "fsl,imx6dl-hdmi" * "rockchip,rk3288-dw-hdmi" > +- reg: physical base address of the controller and length > +- ddc-i2c-bus: the ddc i2c bus > +- interrupts: The interrupt number to the cpu Does the device only have one interrupt? Just describe what this logically is, and don't mention the CPU. It'll be plumbed through an interrupt controller anyhow. > + > +Optional properties > +- reg-io-width: the width of the reg:1,4, default set to 1 if not present I don't understand this description. Could you elaborate on this? > + > +Example: > + hdmi: hdmi@0120000 { > + compatible = "fsl,imx6q-hdmi"; > + reg = <0x00120000 0x9000>; > + interrupts = <0 115 0x04>; > + gpr = <&gpr>; > + clocks = <&clks 123>, <&clks 124>; > + clock-names = "iahb", "isfr"; These three properties weren't mentioned in the binding. > + ddc-i2c-bus = <&i2c2>; > + > + port@0 { > + reg = <0>; > + > + hdmi_mux_0: endpoint { > + remote-endpoint = <&ipu1_di0_hdmi>; > + }; > + }; Please mention the graphics bindings that require graph info. THanks, Mark. > + > + port@1 { > + reg = <1>; > + > + hdmi_mux_1: endpoint { > + remote-endpoint = <&ipu1_di1_hdmi>; > + }; > + }; > + }; > -- > 1.9.1 > > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7 7/7] dt-bindings: add document for dw-hdmi 2014-11-11 12:24 ` Mark Rutland @ 2014-11-11 13:33 ` Andy Yan 0 siblings, 0 replies; 6+ messages in thread From: Andy Yan @ 2014-11-11 13:33 UTC (permalink / raw) To: Mark Rutland Cc: airlied@linux.ie, Zubair.Kakakhel@imgtec.com, rmk+kernel@arm.linux.org.uk, fabio.estevam@freescale.com, heiko@sntech.de, djkurtz@chromium.org, ykk@rock-chips.com, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Sorry, it seems that there is somethings wrong whit my network. This version maybe sent twice. On 2014年11月11日 20:24, Mark Rutland wrote: > On Tue, Nov 11, 2014 at 12:12:32PM +0000, Andy Yan wrote: >> Signed-off-by: Andy Yan <andy.yan@rock-chips.com> >> --- >> >> Changes in v7: None >> Changes in v6: None >> Changes in v5: None >> Changes in v4: None >> Changes in v3: None >> Changes in v2: None >> >> .../devicetree/bindings/drm/bridge/dw-hdmi.txt | 38 ++++++++++++++++++++++ >> 1 file changed, 38 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt >> >> diff --git a/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt b/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt >> new file mode 100644 >> index 0000000..aa7ed17 >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/drm/bridge/dw-hdmi.txt >> @@ -0,0 +1,38 @@ >> +DesignWare HDMI bridge bindings >> + >> +Required properities: >> +- compatibel: platform specific such as "fsl,imx6q-hdmi","fsl,imx6dl-hdmi" >> + "rockchip,rk3288-dw-hdmi" > s/compatibel/compatible/ thanks, I will correct it next version. > > This should include the _precise_ strings you expect. Please format this > as a list, e.g. > > - compatible: should contain one of: > * "fsl,imx6q-hdmi" > * "fsl,imx6dl-hdmi" > * "rockchip,rk3288-dw-hdmi" > I will do as your suggestion in next version >> +- reg: physical base address of the controller and length >> +- ddc-i2c-bus: the ddc i2c bus >> +- interrupts: The interrupt number to the cpu > Does the device only have one interrupt? Just describe what this > logically is, and don't mention the CPU. It'll be plumbed through an > interrupt controller anyhow. this device only have on interrupt for hot plug and other things. >> + >> +Optional properties >> +- reg-io-width: the width of the reg:1,4, default set to 1 if not present > I don't understand this description. Could you elaborate on this? this property is platform specific , it is used to describe the register width. on imx6, the hdmi register is one byte width, which means the first register address is 0x0000, the second is 0x0001, but on rk3288, the register is 4 bytes width, the first register address is 0x0000, and the second is 0x0004 > >> + >> +Example: >> + hdmi: hdmi@0120000 { >> + compatible = "fsl,imx6q-hdmi"; >> + reg = <0x00120000 0x9000>; >> + interrupts = <0 115 0x04>; >> + gpr = <&gpr>; >> + clocks = <&clks 123>, <&clks 124>; >> + clock-names = "iahb", "isfr"; > These three properties weren't mentioned in the binding. gpr,clocks, port are platform specific property, on rk3288, the grf have the similar function as gpr on imx. And the clock also have different name on the two platforms. the port also different, on imx, the port is ipuxxx, but on rk3288, the port is vopx, these properties will be mentioned in platform dt binding. > >> + ddc-i2c-bus = <&i2c2>; >> + >> + port@0 { >> + reg = <0>; >> + >> + hdmi_mux_0: endpoint { >> + remote-endpoint = <&ipu1_di0_hdmi>; >> + }; >> + }; > Please mention the graphics bindings that require graph info. > > THanks, > Mark. > >> + >> + port@1 { >> + reg = <1>; >> + >> + hdmi_mux_1: endpoint { >> + remote-endpoint = <&ipu1_di1_hdmi>; >> + }; >> + }; >> + }; >> -- >> 1.9.1 >> >> > > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 1/7] staging: imx-drm: imx-hdmi: make checkpatch happy @ 2014-11-11 12:50 Andy Yan [not found] ` <1415710229-11935-1-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> 0 siblings, 1 reply; 6+ messages in thread From: Andy Yan @ 2014-11-11 12:50 UTC (permalink / raw) To: airlied-cv59FeDIM0c, heiko-4mtYJXux2i+zQB+pC5nmwQ, fabio.estevam-KZfg59tc24xl57MIdRCFDg, rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ Cc: Greg Kroah-Hartman, Grant Likely, Rob Herring, Philipp Zabel, Shawn Guo, Andy yan, Josh Boyer, Sean Paul, Inki Dae, Dave Airlie, Arnd Bergmann, Lucas Stach, Zubair.Kakakhel-1AXoQHu6uovQT0dZR+AlfA, djkurtz-hpIqsD4AKlfQT0dZR+AlfA, ykk-TNX95d0MmH7DzftRWevZcw, linux-kernel-u79uwXL29TY76Z2rM5mHXA, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b, devicetree-u79uwXL29TY76Z2rM5mHXA, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, jay.xu-TNX95d0MmH7DzftRWevZcw 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 <andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> --- Changes in v7: None Changes in v6: - rearrange the patch order Changes in v5: None Changes in v4: - fix checkpatch CHECK Changes in v3: None Changes in v2: None drivers/staging/imx-drm/imx-hdmi.c | 97 +++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index aaec6b2..79daec4 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -163,7 +163,7 @@ static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) } static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, - u8 shift, u8 mask) + u8 shift, u8 mask) { hdmi_modb(hdmi, data << shift, mask, reg); } @@ -327,7 +327,7 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, } static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, - unsigned long pixel_clk) + unsigned long pixel_clk) { unsigned int clk_n, clk_cts; @@ -338,7 +338,7 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, if (!clk_cts) { dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", - __func__, pixel_clk); + __func__, pixel_clk); return; } @@ -477,13 +477,11 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) u16 coeff_b = (*csc_coeff)[1][i]; u16 coeff_c = (*csc_coeff)[2][i]; - hdmi_writeb(hdmi, coeff_a & 0xff, - HDMI_CSC_COEF_A1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2); hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); - hdmi_writeb(hdmi, coeff_c & 0xff, - HDMI_CSC_COEF_C1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2); hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); } @@ -535,21 +533,22 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; u8 val, vp_conf; - if (hdmi_data->enc_out_format == RGB - || hdmi_data->enc_out_format == YCBCR444) { - if (!hdmi_data->enc_color_depth) + if (hdmi_data->enc_out_format == RGB || + hdmi_data->enc_out_format == YCBCR444) { + if (!hdmi_data->enc_color_depth) { output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - else if (hdmi_data->enc_color_depth == 8) { + } else if (hdmi_data->enc_color_depth == 8) { color_depth = 4; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; - } else if (hdmi_data->enc_color_depth == 10) + } else if (hdmi_data->enc_color_depth == 10) { color_depth = 5; - else if (hdmi_data->enc_color_depth == 12) + } else if (hdmi_data->enc_color_depth == 12) { color_depth = 6; - else if (hdmi_data->enc_color_depth == 16) + } else if (hdmi_data->enc_color_depth == 16) { color_depth = 7; - else + } else { return; + } } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { if (!hdmi_data->enc_color_depth || hdmi_data->enc_color_depth == 8) @@ -561,8 +560,9 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) else return; output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; - } else + } else { return; + } /* set the packetizer registers */ val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & @@ -623,34 +623,34 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) } static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); } static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi, - unsigned char bit) + unsigned char bit) { hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); } @@ -666,21 +666,21 @@ static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec) } static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, - unsigned char addr) + unsigned char addr) { hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); hdmi_writeb(hdmi, (unsigned char)(data >> 8), - HDMI_PHY_I2CM_DATAO_1_ADDR); + HDMI_PHY_I2CM_DATAO_1_ADDR); hdmi_writeb(hdmi, (unsigned char)(data >> 0), - HDMI_PHY_I2CM_DATAO_0_ADDR); + HDMI_PHY_I2CM_DATAO_0_ADDR); hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, - HDMI_PHY_I2CM_OPERATION_ADDR); + HDMI_PHY_I2CM_OPERATION_ADDR); hdmi_phy_wait_i2c_done(hdmi, 1000); } static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, - unsigned char addr) + unsigned char addr) { __hdmi_phy_i2c_write(hdmi, data, addr); return 0; @@ -839,7 +839,7 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, hdmi_phy_test_clear(hdmi, 1); hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, - HDMI_PHY_I2CM_SLAVE_ADDR); + HDMI_PHY_I2CM_SLAVE_ADDR); hdmi_phy_test_clear(hdmi, 0); /* PLL/MPLL Cfg - always match on final entry */ @@ -857,9 +857,8 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, break; if (i >= ARRAY_SIZE(curr_ctrl)) { - dev_err(hdmi->dev, - "Pixel clock %d - unsupported by HDMI\n", - hdmi->hdmi_data.video_mode.mpixelclock); + dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", + hdmi->hdmi_data.video_mode.mpixelclock); return -EINVAL; } @@ -1223,21 +1222,21 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) } if ((hdmi->vic == 6) || (hdmi->vic == 7) || - (hdmi->vic == 21) || (hdmi->vic == 22) || - (hdmi->vic == 2) || (hdmi->vic == 3) || - (hdmi->vic == 17) || (hdmi->vic == 18)) + (hdmi->vic == 21) || (hdmi->vic == 22) || + (hdmi->vic == 2) || (hdmi->vic == 3) || + (hdmi->vic == 17) || (hdmi->vic == 18)) hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; else hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; if ((hdmi->vic == 10) || (hdmi->vic == 11) || - (hdmi->vic == 12) || (hdmi->vic == 13) || - (hdmi->vic == 14) || (hdmi->vic == 15) || - (hdmi->vic == 25) || (hdmi->vic == 26) || - (hdmi->vic == 27) || (hdmi->vic == 28) || - (hdmi->vic == 29) || (hdmi->vic == 30) || - (hdmi->vic == 35) || (hdmi->vic == 36) || - (hdmi->vic == 37) || (hdmi->vic == 38)) + (hdmi->vic == 12) || (hdmi->vic == 13) || + (hdmi->vic == 14) || (hdmi->vic == 15) || + (hdmi->vic == 25) || (hdmi->vic == 26) || + (hdmi->vic == 27) || (hdmi->vic == 28) || + (hdmi->vic == 29) || (hdmi->vic == 30) || + (hdmi->vic == 35) || (hdmi->vic == 36) || + (hdmi->vic == 37) || (hdmi->vic == 38)) hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; else hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; @@ -1266,9 +1265,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) imx_hdmi_enable_video_path(hdmi); /* not for DVI mode */ - if (hdmi->hdmi_data.video_mode.mdvi) + if (hdmi->hdmi_data.video_mode.mdvi) { dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); - else { + } else { dev_dbg(hdmi->dev, "%s CEA mode\n", __func__); /* HDMI Initialization Step E - Configure audio */ @@ -1525,7 +1524,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) dev_dbg(hdmi->dev, "EVENT=plugout\n"); hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, - HDMI_PHY_POL0); + HDMI_PHY_POL0); imx_hdmi_poweroff(hdmi); } @@ -1554,7 +1553,7 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) DRM_MODE_ENCODER_TMDS); drm_connector_helper_add(&hdmi->connector, - &imx_hdmi_connector_helper_funcs); + &imx_hdmi_connector_helper_funcs); drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -1671,11 +1670,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) /* Product and revision IDs */ dev_info(dev, - "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", - hdmi_readb(hdmi, HDMI_DESIGN_ID), - hdmi_readb(hdmi, HDMI_REVISION_ID), - hdmi_readb(hdmi, HDMI_PRODUCT_ID0), - hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); + "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", + hdmi_readb(hdmi, HDMI_DESIGN_ID), + hdmi_readb(hdmi, HDMI_REVISION_ID), + hdmi_readb(hdmi, HDMI_PRODUCT_ID0), + hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); initialize_hdmi_ih_mutes(hdmi); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 6+ messages in thread
[parent not found: <1415710229-11935-1-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org>]
* [PATCH v7 3/7] staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi [not found] ` <1415710229-11935-1-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> @ 2014-11-11 12:52 ` Andy Yan 0 siblings, 0 replies; 6+ messages in thread From: Andy Yan @ 2014-11-11 12:52 UTC (permalink / raw) To: airlied-cv59FeDIM0c, heiko-4mtYJXux2i+zQB+pC5nmwQ, fabio.estevam-KZfg59tc24xl57MIdRCFDg, rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ Cc: Greg Kroah-Hartman, Grant Likely, Rob Herring, Philipp Zabel, Shawn Guo, Andy yan, Josh Boyer, Sean Paul, Inki Dae, Dave Airlie, Arnd Bergmann, Lucas Stach, Zubair.Kakakhel-1AXoQHu6uovQT0dZR+AlfA, djkurtz-hpIqsD4AKlfQT0dZR+AlfA, ykk-TNX95d0MmH7DzftRWevZcw, linux-kernel-u79uwXL29TY76Z2rM5mHXA, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b, devicetree-u79uwXL29TY76Z2rM5mHXA, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, jay.xu-TNX95d0MmH7DzftRWevZcw imx6 and rockchip rk3288 and JZ4780 (Ingenic Xburst/MIPS) use the interface compatible Designware HDMI IP, but they also have some lightly differences, such as phy pll configuration, register width, 4K support, clk useage, and the crtc mux configuration is also platform specific. To reuse the imx hdmi driver, split the platform specific code out to dw_hdmi-imx.c. Signed-off-by: Andy Yan <andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> --- Changes in v7: - remove unused variables from structure dw_hdmi - remove a wrong modification - add copyrights for dw_hdmi-imx.c Changes in v6: None Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: None drivers/staging/imx-drm/Makefile | 2 +- drivers/staging/imx-drm/dw_hdmi-imx.c | 217 +++++++++++++++++++++++++++++ drivers/staging/imx-drm/imx-hdmi.c | 255 ++++++++-------------------------- drivers/staging/imx-drm/imx-hdmi.h | 43 ++++++ 4 files changed, 322 insertions(+), 195 deletions(-) create mode 100644 drivers/staging/imx-drm/dw_hdmi-imx.c diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index 582c438..809027d 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o -obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o +obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o dw_hdmi-imx.o diff --git a/drivers/staging/imx-drm/dw_hdmi-imx.c b/drivers/staging/imx-drm/dw_hdmi-imx.c new file mode 100644 index 0000000..0db978e --- /dev/null +++ b/drivers/staging/imx-drm/dw_hdmi-imx.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <video/imx-ipu-v3.h> +#include <linux/regmap.h> +#include <linux/clk.h> + +#include "imx-drm.h" +#include "imx-hdmi.h" + +struct imx_hdmi_priv { + struct device *dev; + struct clk *isfr_clk; + struct clk *iahb_clk; + struct regmap *regmap; +}; + +static const struct mpll_config imx_mpll_cfg[] = { + { + 45250000, { + { 0x01e0, 0x0000 }, + { 0x21e1, 0x0000 }, + { 0x41e2, 0x0000 } + }, + }, { + 92500000, { + { 0x0140, 0x0005 }, + { 0x2141, 0x0005 }, + { 0x4142, 0x0005 }, + }, + }, { + 148500000, { + { 0x00a0, 0x000a }, + { 0x20a1, 0x000a }, + { 0x40a2, 0x000a }, + }, + }, { + ~0UL, { + { 0x00a0, 0x000a }, + { 0x2001, 0x000f }, + { 0x4002, 0x000f }, + }, + } +}; + +static const struct curr_ctrl imx_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { + 54000000, { 0x091c, 0x091c, 0x06dc }, + }, { + 58400000, { 0x091c, 0x06dc, 0x06dc }, + }, { + 72000000, { 0x06dc, 0x06dc, 0x091c }, + }, { + 74250000, { 0x06dc, 0x0b5c, 0x091c }, + }, { + 118800000, { 0x091c, 0x091c, 0x06dc }, + }, { + 216000000, { 0x06dc, 0x0b5c, 0x091c }, + } +}; + +static int imx_hdmi_parse_dt(struct imx_hdmi_priv *hdmi) +{ + struct device_node *np = hdmi->dev->of_node; + + hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); + if (IS_ERR(hdmi->regmap)) { + dev_err(hdmi->dev, "Unable to get gpr\n"); + return PTR_ERR(hdmi->regmap); + } + + hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); + if (IS_ERR(hdmi->isfr_clk)) { + dev_err(hdmi->dev, "Unable to get HDMI isfr clk\n"); + return PTR_ERR(hdmi->isfr_clk); + } + + hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); + if (IS_ERR(hdmi->iahb_clk)) { + dev_err(hdmi->dev, "Unable to get HDMI iahb clk\n"); + return PTR_ERR(hdmi->iahb_clk); + } + + return 0; +} + +static void *imx_hdmi_imx_setup(struct platform_device *pdev) +{ + struct imx_hdmi_priv *hdmi; + int ret; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return ERR_PTR(-ENOMEM); + hdmi->dev = &pdev->dev; + + ret = imx_hdmi_parse_dt(hdmi); + if (ret < 0) + return ERR_PTR(ret); + ret = clk_prepare_enable(hdmi->isfr_clk); + if (ret) { + dev_err(hdmi->dev, + "Cannot enable HDMI isfr clock: %d\n", ret); + return ERR_PTR(ret); + } + + ret = clk_prepare_enable(hdmi->iahb_clk); + if (ret) { + dev_err(hdmi->dev, + "Cannot enable HDMI iahb clock: %d\n", ret); + return ERR_PTR(ret); + } + + return hdmi; +} + +static void imx_hdmi_imx_exit(void *priv) +{ + struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv; + + clk_disable_unprepare(hdmi->isfr_clk); + + clk_disable_unprepare(hdmi->iahb_clk); +} + +static void imx_hdmi_imx_encoder_commit(void *priv, struct drm_encoder *encoder) +{ + struct imx_hdmi_priv *hdmi = (struct imx_hdmi_priv *)priv; + int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); + + regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, + IMX6Q_GPR3_HDMI_MUX_CTL_MASK, + mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); +} + +static void imx_hdmi_imx_encoder_prepare(struct drm_connector *connector, + struct drm_encoder *encoder) +{ + imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); +} + +static struct imx_hdmi_plat_data imx6q_hdmi_drv_data = { + .setup = imx_hdmi_imx_setup, + .exit = imx_hdmi_imx_exit, + .encoder_commit = imx_hdmi_imx_encoder_commit, + .encoder_prepare = imx_hdmi_imx_encoder_prepare, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .dev_type = IMX6Q_HDMI, +}; + +static struct imx_hdmi_plat_data imx6dl_hdmi_drv_data = { + .setup = imx_hdmi_imx_setup, + .exit = imx_hdmi_imx_exit, + .encoder_commit = imx_hdmi_imx_encoder_commit, + .encoder_prepare = imx_hdmi_imx_encoder_prepare, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .dev_type = IMX6DL_HDMI, +}; + +static const struct of_device_id imx_hdmi_imx_ids[] = { + { .compatible = "fsl,imx6q-hdmi", + .data = &imx6q_hdmi_drv_data + }, { + .compatible = "fsl,imx6dl-hdmi", + .data = &imx6dl_hdmi_drv_data + }, + {}, +}; +MODULE_DEVICE_TABLE(of, imx_hdmi_imx_dt_ids); + +static int imx_hdmi_imx_probe(struct platform_device *pdev) +{ + const struct imx_hdmi_plat_data *plat_data; + const struct of_device_id *match; + + if (!pdev->dev.of_node) + return -ENODEV; + + match = of_match_node(imx_hdmi_imx_ids, pdev->dev.of_node); + plat_data = match->data; + + return imx_hdmi_platform_register(pdev, plat_data); +} + +static int imx_hdmi_imx_remove(struct platform_device *pdev) +{ + return imx_hdmi_platform_unregister(pdev); +} + +static struct platform_driver imx_hdmi_imx_platform_driver = { + .probe = imx_hdmi_imx_probe, + .remove = imx_hdmi_imx_remove, + .driver = { + .name = "dwhdmi-imx", + .owner = THIS_MODULE, + .of_match_table = imx_hdmi_imx_ids, + }, +}; + +module_platform_driver(imx_hdmi_imx_platform_driver); + +MODULE_AUTHOR("Andy Yan <andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org>"); +MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:dwhdmi-imx"); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index c2b035a..c7e5f12 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -16,21 +16,16 @@ #include <linux/irq.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/clk.h> #include <linux/hdmi.h> -#include <linux/regmap.h> -#include <linux/mfd/syscon.h> -#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <linux/of_device.h> +#include <drm/drm_of.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> #include <drm/drm_encoder_slave.h> -#include <video/imx-ipu-v3.h> #include "imx-hdmi.h" -#include "imx-drm.h" #define HDMI_EDID_LEN 512 @@ -54,11 +49,6 @@ enum hdmi_datamap { YCbCr422_12B = 0x12, }; -enum imx_hdmi_devtype { - IMX6Q_HDMI, - IMX6DL_HDMI, -}; - static const u16 csc_coeff_default[3][4] = { { 0x2000, 0x0000, 0x0000, 0x0000 }, { 0x0000, 0x2000, 0x0000, 0x0000 }, @@ -117,10 +107,10 @@ struct imx_hdmi { enum imx_hdmi_devtype dev_type; struct device *dev; - struct clk *isfr_clk; - struct clk *iahb_clk; struct hdmi_data_info hdmi_data; + const struct imx_hdmi_plat_data *plat_data; + void *priv; int vic; u8 edid[HDMI_EDID_LEN]; @@ -137,13 +127,6 @@ struct imx_hdmi { int ratio; }; -static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di) -{ - regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, - IMX6Q_GPR3_HDMI_MUX_CTL_MASK, - ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); -} - static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) { writeb(val, hdmi->regs + offset); @@ -728,76 +711,13 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } -enum { - RES_8, - RES_10, - RES_12, - RES_MAX, -}; - -struct mpll_config { - unsigned long mpixelclock; - struct { - u16 cpce; - u16 gmp; - } res[RES_MAX]; -}; - -static const struct mpll_config mpll_config[] = { - { - 45250000, { - { 0x01e0, 0x0000 }, - { 0x21e1, 0x0000 }, - { 0x41e2, 0x0000 } - }, - }, { - 92500000, { - { 0x0140, 0x0005 }, - { 0x2141, 0x0005 }, - { 0x4142, 0x0005 }, - }, - }, { - 148500000, { - { 0x00a0, 0x000a }, - { 0x20a1, 0x000a }, - { 0x40a2, 0x000a }, - }, - }, { - ~0UL, { - { 0x00a0, 0x000a }, - { 0x2001, 0x000f }, - { 0x4002, 0x000f }, - }, - } -}; - -struct curr_ctrl { - unsigned long mpixelclock; - u16 curr[RES_MAX]; -}; - -static const struct curr_ctrl curr_ctrl[] = { - /* pixelclk bpp8 bpp10 bpp12 */ - { - 54000000, { 0x091c, 0x091c, 0x06dc }, - }, { - 58400000, { 0x091c, 0x06dc, 0x06dc }, - }, { - 72000000, { 0x06dc, 0x06dc, 0x091c }, - }, { - 74250000, { 0x06dc, 0x0b5c, 0x091c }, - }, { - 118800000, { 0x091c, 0x091c, 0x06dc }, - }, { - 216000000, { 0x06dc, 0x0b5c, 0x091c }, - } -}; - static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, unsigned char res, int cscon) { unsigned res_idx, i; u8 val, msec; + const struct mpll_config *mpll_cfg = hdmi->plat_data->mpll_cfg; + const struct curr_ctrl *curr_ctr = hdmi->plat_data->cur_ctr; if (prep) return -EINVAL; @@ -843,27 +763,27 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, hdmi_phy_test_clear(hdmi, 0); /* PLL/MPLL Cfg - always match on final entry */ - for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++) + for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) if (hdmi->hdmi_data.video_mode.mpixelclock <= - mpll_config[i].mpixelclock) + mpll_cfg[i].mpixelclock) break; - hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); - hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); + hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].cpce, 0x06); + hdmi_phy_i2c_write(hdmi, mpll_cfg[i].res[res_idx].gmp, 0x15); - for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++) + for (i = 0; curr_ctr[i].mpixelclock != (~0UL); i++) if (hdmi->hdmi_data.video_mode.mpixelclock <= - curr_ctrl[i].mpixelclock) + curr_ctr[i].mpixelclock) break; - if (i >= ARRAY_SIZE(curr_ctrl)) { + if (curr_ctr[i].mpixelclock == (~0UL)) { dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", hdmi->hdmi_data.video_mode.mpixelclock); return -EINVAL; } /* CURRCTRL */ - hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10); + hdmi_phy_i2c_write(hdmi, curr_ctr[i].curr[res_idx], 0x10); hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); @@ -1453,21 +1373,29 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); imx_hdmi_poweroff(hdmi); - imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); + + if (hdmi->plat_data->encoder_prepare) + hdmi->plat_data->encoder_prepare(&hdmi->connector, encoder); } static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) { struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); - int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder); - imx_hdmi_set_ipu_di_mux(hdmi, mux); + if (hdmi->plat_data->encoder_commit) + hdmi->plat_data->encoder_commit(hdmi->priv, encoder); imx_hdmi_poweron(hdmi); } +void imx_hdmi_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { - .destroy = imx_drm_encoder_destroy, + .destroy = drm_encoder_cleanup, }; static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { @@ -1483,7 +1411,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_hdmi_connector_detect, - .destroy = imx_drm_connector_destroy, + .destroy = imx_hdmi_connector_destroy, }; static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { @@ -1539,12 +1467,10 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) { - int ret; + struct drm_encoder *encoder = &hdmi->encoder; + struct device *dev = hdmi->dev; - ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder, - hdmi->dev->of_node); - if (ret) - return ret; + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; @@ -1564,50 +1490,16 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) return 0; } -static struct platform_device_id imx_hdmi_devtype[] = { - { - .name = "imx6q-hdmi", - .driver_data = IMX6Q_HDMI, - }, { - .name = "imx6dl-hdmi", - .driver_data = IMX6DL_HDMI, - }, { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype); - -static const struct of_device_id imx_hdmi_dt_ids[] = { -{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], }, -{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], }, -{ /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); - static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); - const struct of_device_id *of_id = - of_match_device(imx_hdmi_dt_ids, dev); + struct imx_hdmi *hdmi = platform_get_drvdata(pdev); struct drm_device *drm = data; struct device_node *np = dev->of_node; struct device_node *ddc_node; - struct imx_hdmi *hdmi; struct resource *iores; int ret, irq; - hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); - if (!hdmi) - return -ENOMEM; - - hdmi->dev = dev; - hdmi->sample_rate = 48000; - hdmi->ratio = 100; - - if (of_id) { - const struct platform_device_id *device_id = of_id->data; - - hdmi->dev_type = device_id->driver_data; - } - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); @@ -1637,40 +1529,8 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); - hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); - if (IS_ERR(hdmi->regmap)) - return PTR_ERR(hdmi->regmap); - - hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); - if (IS_ERR(hdmi->isfr_clk)) { - ret = PTR_ERR(hdmi->isfr_clk); - dev_err(hdmi->dev, - "Unable to get HDMI isfr clk: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(hdmi->isfr_clk); - if (ret) { - dev_err(hdmi->dev, - "Cannot enable HDMI isfr clock: %d\n", ret); - return ret; - } - - hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); - if (IS_ERR(hdmi->iahb_clk)) { - ret = PTR_ERR(hdmi->iahb_clk); - dev_err(hdmi->dev, - "Unable to get HDMI iahb clk: %d\n", ret); - goto err_isfr; - } - - ret = clk_prepare_enable(hdmi->iahb_clk); - if (ret) { - dev_err(hdmi->dev, - "Cannot enable HDMI iahb clock: %d\n", ret); - goto err_isfr; - } - + if (hdmi->plat_data->setup) + hdmi->priv = hdmi->plat_data->setup(pdev); /* Product and revision IDs */ dev_info(dev, "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", @@ -1698,11 +1558,11 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) ret = imx_hdmi_fb_registered(hdmi); if (ret) - goto err_iahb; + return ret; ret = imx_hdmi_register(drm, hdmi); if (ret) - goto err_iahb; + return ret; /* Unmute interrupts */ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); @@ -1710,13 +1570,6 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) dev_set_drvdata(dev, hdmi); return 0; - -err_iahb: - clk_disable_unprepare(hdmi->iahb_clk); -err_isfr: - clk_disable_unprepare(hdmi->isfr_clk); - - return ret; } static void imx_hdmi_unbind(struct device *dev, struct device *master, @@ -1729,9 +1582,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master, hdmi->connector.funcs->destroy(&hdmi->connector); hdmi->encoder.funcs->destroy(&hdmi->encoder); - - clk_disable_unprepare(hdmi->iahb_clk); - clk_disable_unprepare(hdmi->isfr_clk); + if (hdmi->plat_data->exit) + hdmi->plat_data->exit(hdmi->priv); i2c_put_adapter(hdmi->ddc); } @@ -1751,17 +1603,32 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev) return 0; } -static struct platform_driver imx_hdmi_driver = { - .probe = imx_hdmi_platform_probe, - .remove = imx_hdmi_platform_remove, - .driver = { - .name = "imx-hdmi", - .owner = THIS_MODULE, - .of_match_table = imx_hdmi_dt_ids, - }, -}; +int imx_hdmi_platform_register(struct platform_device *pdev, + const struct imx_hdmi_plat_data *plat_data) +{ + struct imx_hdmi *hdmi; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; -module_platform_driver(imx_hdmi_driver); + hdmi->plat_data = plat_data; + hdmi->dev = &pdev->dev; + hdmi->dev_type = plat_data->dev_type; + hdmi->sample_rate = 48000; + hdmi->ratio = 100; + + platform_set_drvdata(pdev, hdmi); + + return imx_hdmi_platform_probe(pdev); +} +EXPORT_SYMBOL_GPL(imx_hdmi_platform_register); + +int imx_hdmi_platform_unregister(struct platform_device *pdev) +{ + return imx_hdmi_platform_remove(pdev); +} +EXPORT_SYMBOL_GPL(imx_hdmi_platform_unregister); MODULE_AUTHOR("Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>"); 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 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-11-11 13:33 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-11-11 12:12 [PATCH v7 0/7] dw-hdmi: convert imx hdmi to bridge/dw-hdmi Andy Yan 2014-11-11 12:12 ` [PATCH v7 3/7] staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi Andy Yan 2014-11-11 12:12 ` [PATCH v7 7/7] dt-bindings: add document for dw-hdmi Andy Yan [not found] ` <1415707952-11415-8-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> 2014-11-11 12:24 ` Mark Rutland 2014-11-11 13:33 ` Andy Yan -- strict thread matches above, loose matches on Subject: below -- 2014-11-11 12:50 [PATCH v7 1/7] staging: imx-drm: imx-hdmi: make checkpatch happy Andy Yan [not found] ` <1415710229-11935-1-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org> 2014-11-11 12:52 ` [PATCH v7 3/7] staging: imx-drm: imx-hdmi: split imx soc specific code from imx-hdmi Andy Yan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).