<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Dec 17, 2022 at 2:30 AM Liu Ying <<a href="mailto:victor.liu@nxp.com">victor.liu@nxp.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Fri, 2022-12-16 at 22:07 +0100, Lucas Stach wrote:<br>
> Add a simple wrapper driver for the DWC HDMI bridge driver that<br>
> implements the few bits that are necessary to abstract the i.MX8MP<br>
> SoC integration.<br>
> <br>
> Signed-off-by: Lucas Stach <<a href="mailto:l.stach@pengutronix.de" target="_blank">l.stach@pengutronix.de</a>><br>
> Reviewed-by: Laurent Pinchart <<a href="mailto:laurent.pinchart@ideasonboard.com" target="_blank">laurent.pinchart@ideasonboard.com</a>><br>
> Tested-by: Marek Vasut <<a href="mailto:marex@denx.de" target="_blank">marex@denx.de</a>><br></blockquote><div><br></div><div>Tested-by: Adam Ford <<a href="mailto:aford173@gmail.com">aford173@gmail.com</a>> #imx8mp-beacon</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> ---<br>
>  drivers/gpu/drm/bridge/imx/Kconfig       |   9 ++<br>
>  drivers/gpu/drm/bridge/imx/Makefile      |   2 +<br>
>  drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c | 140<br>
> +++++++++++++++++++++++<br>
>  3 files changed, 151 insertions(+)<br>
>  create mode 100644 drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c<br>
> <br>
<br>
Can you please provide a changelog since this is v2?<br>
<br>
> diff --git a/drivers/gpu/drm/bridge/imx/Kconfig<br>
> b/drivers/gpu/drm/bridge/imx/Kconfig<br>
> index 608f47f41bcd..d828d8bfd893 100644<br>
> --- a/drivers/gpu/drm/bridge/imx/Kconfig<br>
> +++ b/drivers/gpu/drm/bridge/imx/Kconfig<br>
> @@ -44,4 +44,13 @@ config DRM_IMX8QXP_PIXEL_LINK_TO_DPI<br>
>         Choose this to enable pixel link to display pixel<br>
> interface(PXL2DPI)<br>
>         found in Freescale i.MX8qxp processor.<br>
>  <br>
> +config DRM_IMX8MP_DW_HDMI_BRIDGE<br>
<br>
Sort the config names alphabetically please.<br>
<br>
> +     tristate "i.MX8MP HDMI bridge support"<br>
<br>
To show the prompts in this Kconfig file in a consistent fashion,<br>
please add 'Freescale' before 'i.MX8MP'.<br>
<br>
> +     depends on OF<br>
> +     depends on COMMON_CLK<br>
> +     select DRM_DW_HDMI<br>
> +     help<br>
> +       Choose this to enable support for the internal HDMI encoder<br>
> found<br>
> +       on the i.MX8MP SoC.<br>
> +<br>
>  endif # ARCH_MXC || COMPILE_TEST<br>
> diff --git a/drivers/gpu/drm/bridge/imx/Makefile<br>
> b/drivers/gpu/drm/bridge/imx/Makefile<br>
> index aa90ec8d5433..03b0074ae538 100644<br>
> --- a/drivers/gpu/drm/bridge/imx/Makefile<br>
> +++ b/drivers/gpu/drm/bridge/imx/Makefile<br>
> @@ -7,3 +7,5 @@ obj-$(CONFIG_DRM_IMX8QXP_LDB) += imx8qxp-ldb.o<br>
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_COMBINER) += imx8qxp-pixel-combiner.o<br>
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK) += imx8qxp-pixel-link.o<br>
>  obj-$(CONFIG_DRM_IMX8QXP_PIXEL_LINK_TO_DPI) += imx8qxp-pxl2dpi.o<br>
> +<br>
> +obj-$(CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE) += imx8mp-hdmi.o<br>
<br>
Sort the config names alphabetically.<br>
<br>
> diff --git a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c<br>
> b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c<br>
> new file mode 100644<br>
> index 000000000000..06849b817aed<br>
> --- /dev/null<br>
> +++ b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c<br>
> @@ -0,0 +1,140 @@<br>
> +// SPDX-License-Identifier: GPL-2.0+<br>
> +<br>
> +/*<br>
> + * Copyright (C) 2022 Pengutronix, Lucas Stach <<br>
> <a href="mailto:kernel@pengutronix.de" target="_blank">kernel@pengutronix.de</a>><br>
> + */<br>
> +<br>
> +#include <drm/bridge/dw_hdmi.h><br>
> +#include <drm/drm_modes.h><br>
> +#include <linux/clk.h><br>
> +#include <linux/mod_devicetable.h><br>
> +#include <linux/module.h><br>
> +#include <linux/platform_device.h><br>
<br>
Header files in linux/ come before those in drm/.<br>
<br>
> +<br>
> +struct imx8mp_hdmi {<br>
> +     struct dw_hdmi_plat_data plat_data;<br>
> +     struct dw_hdmi *dw_hdmi;<br>
> +     struct clk *pixclk;<br>
> +     struct clk *fdcc;<br>
> +};<br>
> +<br>
> +static enum drm_mode_status<br>
> +imx8mp_hdmi_mode_valid(struct dw_hdmi *dw_hdmi, void *data,<br>
> +                    const struct drm_display_info *info,<br>
> +                    const struct drm_display_mode *mode)<br>
> +{<br>
> +     struct imx8mp_hdmi *hdmi = (struct imx8mp_hdmi *)data;<br>
> +<br>
> +     if (mode->clock < 13500)<br>
> +             return MODE_CLOCK_LOW;<br>
> +<br>
> +     if (mode->clock > 297000)<br>
> +             return MODE_CLOCK_HIGH;<br>
> +<br>
> +     if (clk_round_rate(hdmi->pixclk, mode->clock * 1000) !=<br>
> +         mode->clock * 1000)<br>
> +             return MODE_CLOCK_RANGE;<br>
> +<br>
> +     /* We don't support double-clocked and Interlaced modes */<br>
> +     if ((mode->flags & DRM_MODE_FLAG_DBLCLK) ||<br>
> +         (mode->flags & DRM_MODE_FLAG_INTERLACE))<br>
> +             return MODE_BAD;<br>
> +<br>
> +     return MODE_OK;<br>
> +}<br>
> +<br>
> +static int imx8mp_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data,<br>
> +                             const struct drm_display_info *display,<br>
> +                             const struct drm_display_mode *mode)<br>
> +{<br>
> +     return 0;<br>
> +}<br>
> +<br>
> +static void imx8mp_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void<br>
> *data)<br>
> +{<br>
> +}<br>
> +<br>
> +static void im8mp_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void<br>
> *data)<br>
> +{<br>
> +     /*<br>
> +      * Just release PHY core from reset, all other power management<br>
> is done<br>
> +      * by the PHY driver.<br>
> +      */<br>
> +     dw_hdmi_phy_gen1_reset(hdmi);<br>
> +<br>
> +     dw_hdmi_phy_setup_hpd(hdmi, data);<br>
> +}<br>
> +<br>
> +static const struct dw_hdmi_phy_ops imx8mp_hdmi_phy_ops = {<br>
> +     .init           = imx8mp_hdmi_phy_init,<br>
> +     .disable        = imx8mp_hdmi_phy_disable,<br>
> +     .setup_hpd      = im8mp_hdmi_phy_setup_hpd,<br>
> +     .read_hpd       = dw_hdmi_phy_read_hpd,<br>
> +     .update_hpd     = dw_hdmi_phy_update_hpd,<br>
> +};<br>
> +<br>
> +static int imx8mp_dw_hdmi_probe(struct platform_device *pdev)<br>
> +{<br>
> +     struct device *dev = &pdev->dev;<br>
> +     struct dw_hdmi_plat_data *plat_data;<br>
> +     struct imx8mp_hdmi *hdmi;<br>
> +     int ret;<br>
<br>
Please fix this build warning:<br>
<br>
drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c: In function<br>
‘imx8mp_dw_hdmi_probe’:<br>
drivers/gpu/drm/bridge/imx/imx8mp-hdmi.c:80:13: warning: unused<br>
variable ‘ret’ [-Wunused-variable]<br>
   80 |         int ret;<br>
      |             ^~~<br>
<br>
> +<br>
> +     hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);<br>
> +     if (!hdmi)<br>
> +             return -ENOMEM;<br>
> +<br>
> +     plat_data = &hdmi->plat_data;<br>
> +<br>
> +     hdmi->pixclk = devm_clk_get(dev, "pix");<br>
> +     if (IS_ERR(hdmi->pixclk))<br>
> +             return dev_err_probe(dev, PTR_ERR(hdmi->pixclk),<br>
> +                                  "Unable to get pixel clock\n");<br>
> +<br>
> +     hdmi->fdcc = devm_clk_get_enabled(dev, "fdcc");<br>
> +     if (IS_ERR(hdmi->fdcc))<br>
> +             return dev_err_probe(dev, PTR_ERR(hdmi->fdcc),<br>
> +                                  "Unable to get FDCC clock\n");<br>
<br>
Similar to Laurent's comment on v1 here, why does fdcc clock need to be<br>
always enabled? <br>
<br>
> +<br>
> +     plat_data->mode_valid = imx8mp_hdmi_mode_valid;<br>
> +     plat_data->phy_ops = &imx8mp_hdmi_phy_ops;<br>
> +     plat_data->phy_name = "SAMSUNG HDMI TX PHY";<br>
> +     plat_data->priv_data = hdmi;<br>
<br>
Need to set plat_data->phy_force_vendor to be true? Or, you rely on<br>
reading the HDMI_CONFIG2_ID register to determine the phy type?<br>
<br>
> +<br>
> +     hdmi->dw_hdmi = dw_hdmi_probe(pdev, plat_data);<br>
> +     if (IS_ERR(hdmi->dw_hdmi))<br>
> +             return PTR_ERR(hdmi->dw_hdmi);<br>
> +<br>
> +     platform_set_drvdata(pdev, hdmi);<br>
> +<br>
> +     return 0;<br>
> +}<br>
> +<br>
> +static int imx8mp_dw_hdmi_remove(struct platform_device *pdev)<br>
> +{<br>
> +     struct imx8mp_hdmi *hdmi = platform_get_drvdata(pdev);<br>
> +<br>
> +     dw_hdmi_remove(hdmi->dw_hdmi);<br>
> +<br>
> +     return 0;<br>
> +}<br>
> +<br>
> +static const struct of_device_id imx8mp_dw_hdmi_of_table[] = {<br>
> +     { .compatible = "fsl,imx8mp-hdmi" },<br>
> +     { /* Sentinel */ },<br>
<br>
Nitpick: ',' after the sentinel is not needed since it's the last one.<br>
<br>
Regards,<br>
Liu Ying<br>
<br>
> +};<br>
> +MODULE_DEVICE_TABLE(of, imx8mp_dw_hdmi_of_table);<br>
> +<br>
> +static struct platform_driver imx8mp_dw_hdmi_platform_driver = {<br>
> +     .probe          = imx8mp_dw_hdmi_probe,<br>
> +     .remove         = imx8mp_dw_hdmi_remove,<br>
> +     .driver         = {<br>
> +             .name   = "imx8mp-dw-hdmi",<br>
> +             .of_match_table = imx8mp_dw_hdmi_of_table,<br>
> +     },<br>
> +};<br>
> +<br>
> +module_platform_driver(imx8mp_dw_hdmi_platform_driver);<br>
> +<br>
> +MODULE_DESCRIPTION("i.MX8MP HDMI encoder driver");<br>
> +MODULE_LICENSE("GPL");<br>
<br>
</blockquote></div></div>