Hi all,
this adds support for the HDMI output pipeline on the i.MX8MP. It currently depends on the i.MX8MP HDMI power domain series [1] and support for the new LCDIF [2] in the i.MX8MP. I guess the implementation presented here also still has some warts that require fixing and the individual patches most likely need to go through different maintainer trees, so I don't expect this series to be applied right away.
However this complete series should allow people to test it more easily and provide feedback on the implementation with the full picture available.
Compared to downstream this implementation actually allows to power down the separate HDMI PHY power domain when the display is inactive or no HDMI cable is connected.
Regards, Lucas
[1] https://lore.kernel.org/all/20220406153402.1265474-1-l.stach@pengutronix.de/ [2] https://lore.kernel.org/all/20220322142853.125880-1-marex@denx.de/
Lucas Stach (10): drm/bridge: dw-hdmi: add low-active PHY reset dt-bindings: display: imx: add binding for i.MX8MP HDMI TX drm/imx: add bridge wrapper driver for i.MX8MP DWC HDMI dt-bindings: display: imx: add binding for i.MX8MP HDMI PVI drm/imx: add driver for HDMI TX Parallel Video Interface dt-bindings: phy: add binding for the i.MX8MP HDMI PHY phy: freescale: add Samsung HDMI PHY arm64: dts: imx8mp: add HDMI irqsteer arm64: dts: imx8mp: add HDMI display pipeline arm64: dts: imx8mp-evk: enable HDMI
.../display/imx/fsl,imx8mp-hdmi-pvi.yaml | 83 ++ .../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 ++ .../bindings/phy/fsl,imx8mp-hdmi-phy.yaml | 62 + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 19 + arch/arm64/boot/dts/freescale/imx8mp.dtsi | 93 ++ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 + drivers/gpu/drm/imx/Kconfig | 1 + drivers/gpu/drm/imx/Makefile | 2 + drivers/gpu/drm/imx/bridge/Kconfig | 18 + drivers/gpu/drm/imx/bridge/Makefile | 4 + drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c | 209 +++ drivers/gpu/drm/imx/bridge/imx-hdmi.c | 128 ++ drivers/phy/freescale/Kconfig | 7 + drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 1145 +++++++++++++++++ include/drm/bridge/dw_hdmi.h | 1 + 16 files changed, 1852 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml create mode 100644 drivers/gpu/drm/imx/bridge/Kconfig create mode 100644 drivers/gpu/drm/imx/bridge/Makefile create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi.c create mode 100644 drivers/phy/freescale/phy-fsl-samsung-hdmi.c
Allow vendor PHY implementations to reset PHYs with different polarity than the current Gen2 reset.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++++++ include/drm/bridge/dw_hdmi.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4befc104d220..7600f26aab27 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1365,6 +1365,13 @@ void dw_hdmi_phy_reset(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+void dw_hdmi_phy_reset_active_low(struct dw_hdmi *hdmi) +{ + hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ); + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ); +} +EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset_active_low); + void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address) { hdmi_phy_test_clear(hdmi, 1); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 2a1f85f9a8a3..9b3d52a1e62a 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -190,6 +190,7 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable); void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable); void dw_hdmi_phy_reset(struct dw_hdmi *hdmi); +void dw_hdmi_phy_reset_active_low(struct dw_hdmi *hdmi);
enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, void *data);
Hi Lucas,
On 06/04/2022 18:01, Lucas Stach wrote:
Allow vendor PHY implementations to reset PHYs with different polarity than the current Gen2 reset.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++++++ include/drm/bridge/dw_hdmi.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4befc104d220..7600f26aab27 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1365,6 +1365,13 @@ void dw_hdmi_phy_reset(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+void dw_hdmi_phy_reset_active_low(struct dw_hdmi *hdmi) +{
- hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+} +EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset_active_low);
- void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address) { hdmi_phy_test_clear(hdmi, 1);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 2a1f85f9a8a3..9b3d52a1e62a 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -190,6 +190,7 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable); void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable); void dw_hdmi_phy_reset(struct dw_hdmi *hdmi); +void dw_hdmi_phy_reset_active_low(struct dw_hdmi *hdmi);
enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, void *data);
This has already been submitted at https://lore.kernel.org/r/800262112191a720639ba321be18f0926d4e1d2a.164923043...
Hi Neil,
Am Donnerstag, dem 07.04.2022 um 10:30 +0200 schrieb Neil Armstrong:
Hi Lucas,
On 06/04/2022 18:01, Lucas Stach wrote:
Allow vendor PHY implementations to reset PHYs with different polarity than the current Gen2 reset.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++++++ include/drm/bridge/dw_hdmi.h | 1 + 2 files changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 4befc104d220..7600f26aab27 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1365,6 +1365,13 @@ void dw_hdmi_phy_reset(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+void dw_hdmi_phy_reset_active_low(struct dw_hdmi *hdmi) +{
- hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+} +EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset_active_low);
- void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address) { hdmi_phy_test_clear(hdmi, 1);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 2a1f85f9a8a3..9b3d52a1e62a 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -190,6 +190,7 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable); void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable); void dw_hdmi_phy_reset(struct dw_hdmi *hdmi); +void dw_hdmi_phy_reset_active_low(struct dw_hdmi *hdmi);
enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, void *data);
This has already been submitted at https://lore.kernel.org/r/800262112191a720639ba321be18f0926d4e1d2a.164923043...
Thanks for the pointer, seems I missed this series. I'll switch to this function instead.
Regards, Lucas
The HDMI TX controller on the i.MX8MP SoC is a Synopsys designware IP core with a little bit of SoC integration around it.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- .../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml
diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml new file mode 100644 index 000000000000..578062b6d64d --- /dev/null +++ b/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/imx/fsl,imx8mp-hdmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MP DWC HDMI TX Encoder + +maintainers: + - Lucas Stach l.stach@pengutronix.de + +description: | + The HDMI transmitter is a Synopsys DesignWare HDMI 2.0 TX controller IP. + +allOf: + - $ref: ../bridge/synopsys,dw-hdmi.yaml# + +properties: + compatible: + enum: + - fsl,imx8mp-hdmi + + reg: + maxItems: 1 + + reg-io-width: + const: 1 + + clocks: + maxItems: 4 + + clock-names: + items: + - {} + - {} + - const: cec + - const: pix + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - power-domains + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/clock/imx8mp-clock.h> + #include <dt-bindings/power/imx8mp-power.h> + + hdmi@32fd8000 { + compatible = "fsl,imx8mp-hdmi"; + reg = <0x32fd8000 0x7eff>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_REF_266M>, + <&clk IMX8MP_CLK_32K>, + <&hdmi_tx_phy>; + clock-names = "iahb", "isfr", "cec", "pix"; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX>; + reg-io-width = <1>; + };
On Wed, 06 Apr 2022 18:01:15 +0200, Lucas Stach wrote:
The HDMI TX controller on the i.MX8MP SoC is a Synopsys designware IP core with a little bit of SoC integration around it.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
.../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors: Error: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.example.dts:36.45-46 syntax error FATAL ERROR: Unable to parse input tree make[1]: *** [scripts/Makefile.lib:364: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1401: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit.
Am Mittwoch, dem 06.04.2022 um 15:08 -0500 schrieb Rob Herring:
On Wed, 06 Apr 2022 18:01:15 +0200, Lucas Stach wrote:
The HDMI TX controller on the i.MX8MP SoC is a Synopsys designware IP core with a little bit of SoC integration around it.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
.../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors: Error: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.example.dts:36.45-46 syntax error FATAL ERROR: Unable to parse input tree make[1]: *** [scripts/Makefile.lib:364: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1401: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
Those failures are caused by the example referencing the power domain defines, that are only added in a dependency of this series. They build fine with all the dependencies applied, so please don't let this bot failure prevent you from looking at the actual bindings.
Regards, Lucas
On Thu, Apr 07, 2022 at 11:15:26AM +0200, Lucas Stach wrote:
Am Mittwoch, dem 06.04.2022 um 15:08 -0500 schrieb Rob Herring:
On Wed, 06 Apr 2022 18:01:15 +0200, Lucas Stach wrote:
The HDMI TX controller on the i.MX8MP SoC is a Synopsys designware IP core with a little bit of SoC integration around it.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
.../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors: Error: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.example.dts:36.45-46 syntax error FATAL ERROR: Unable to parse input tree make[1]: *** [scripts/Makefile.lib:364: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1401: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
Those failures are caused by the example referencing the power domain defines, that are only added in a dependency of this series. They build fine with all the dependencies applied, so please don't let this bot failure prevent you from looking at the actual bindings.
I review the failures. It otherwise looks fine.
Rob
Add a simple wrapper driver for the DWC HDMI bridge driver that implements the few bits that are necessary to abstract the i.MX8MP SoC integration.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- drivers/gpu/drm/imx/Kconfig | 1 + drivers/gpu/drm/imx/Makefile | 2 + drivers/gpu/drm/imx/bridge/Kconfig | 10 ++ drivers/gpu/drm/imx/bridge/Makefile | 3 + drivers/gpu/drm/imx/bridge/imx-hdmi.c | 128 ++++++++++++++++++++++++++ 5 files changed, 144 insertions(+) create mode 100644 drivers/gpu/drm/imx/bridge/Kconfig create mode 100644 drivers/gpu/drm/imx/bridge/Makefile create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi.c
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig index bb9738c7c825..88b054c095c6 100644 --- a/drivers/gpu/drm/imx/Kconfig +++ b/drivers/gpu/drm/imx/Kconfig @@ -42,3 +42,4 @@ config DRM_IMX_HDMI Choose this if you want to use HDMI on i.MX6.
source "drivers/gpu/drm/imx/dcss/Kconfig" +source "drivers/gpu/drm/imx/bridge/Kconfig" diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile index b644deffe948..861403d11af6 100644 --- a/drivers/gpu/drm/imx/Makefile +++ b/drivers/gpu/drm/imx/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o obj-$(CONFIG_DRM_IMX_DCSS) += dcss/ + +obj-y += bridge/ diff --git a/drivers/gpu/drm/imx/bridge/Kconfig b/drivers/gpu/drm/imx/bridge/Kconfig new file mode 100644 index 000000000000..8b02dc5606ba --- /dev/null +++ b/drivers/gpu/drm/imx/bridge/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +config DRM_IMX_DW_HDMI_BRIDGE + tristate "HDMI encoder support" + depends on (ARCH_MXC && ARM64) || COMPILE_TEST + depends on DRM && OF + select DRM_DW_HDMI + help + Enable support for the internal HDMI encoder on i.MX8MP SoC + diff --git a/drivers/gpu/drm/imx/bridge/Makefile b/drivers/gpu/drm/imx/bridge/Makefile new file mode 100644 index 000000000000..1cfe9623c0d8 --- /dev/null +++ b/drivers/gpu/drm/imx/bridge/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DRM_IMX_DW_HDMI_BRIDGE) += imx-hdmi.o diff --git a/drivers/gpu/drm/imx/bridge/imx-hdmi.c b/drivers/gpu/drm/imx/bridge/imx-hdmi.c new file mode 100644 index 000000000000..2e72f83be108 --- /dev/null +++ b/drivers/gpu/drm/imx/bridge/imx-hdmi.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Copyright (C) 2022 Pengutronix, Lucas Stach kernel@pengutronix.de + */ + +#include <drm/bridge/dw_hdmi.h> +#include <drm/drm_modes.h> +#include <linux/clk.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +struct imx_hdmi { + struct dw_hdmi_plat_data plat_data; + struct dw_hdmi *dw_hdmi; + struct clk *pixclk; +}; + +static enum drm_mode_status +imx8mp_hdmi_mode_valid(struct dw_hdmi *dw_hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct imx_hdmi *hdmi = (struct imx_hdmi *)data; + + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + + if (mode->clock > 297000) + return MODE_CLOCK_HIGH; + + if (clk_round_rate(hdmi->pixclk, mode->clock * 1000) != + mode->clock * 1000) + return MODE_CLOCK_RANGE; + + /* We don't support double-clocked and Interlaced modes */ + if ((mode->flags & DRM_MODE_FLAG_DBLCLK) || + (mode->flags & DRM_MODE_FLAG_INTERLACE)) + return MODE_BAD; + + return MODE_OK; +} + +static int imx8mp_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data, + const struct drm_display_info *display, + const struct drm_display_mode *mode) +{ + /* + * Just release PHY core from reset, all other power management is done + * by the PHY driver. + */ + dw_hdmi_phy_reset_active_low(dw_hdmi); + + return 0; +} + +static void imx8mp_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data) +{ +} + +static const struct dw_hdmi_phy_ops imx8mp_hdmi_phy_ops = { + .init = imx8mp_hdmi_phy_init, + .disable = imx8mp_hdmi_phy_disable, + .read_hpd = dw_hdmi_phy_read_hpd, + .update_hpd = dw_hdmi_phy_update_hpd, + .setup_hpd = dw_hdmi_phy_setup_hpd, +}; + +static int imx_dw_hdmi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dw_hdmi_plat_data *plat_data; + struct imx_hdmi *hdmi; + + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + plat_data = &hdmi->plat_data; + + hdmi->pixclk = devm_clk_get(dev, "pix"); + if (IS_ERR(hdmi->pixclk)) + return dev_err_probe(dev, PTR_ERR(hdmi->pixclk), + "Unable to get pixel clock\n"); + + plat_data->mode_valid = imx8mp_hdmi_mode_valid; + plat_data->phy_ops = &imx8mp_hdmi_phy_ops; + plat_data->phy_name = "SAMSUNG HDMI TX PHY"; + plat_data->priv_data = hdmi; + + hdmi->dw_hdmi = dw_hdmi_probe(pdev, plat_data); + if (IS_ERR(hdmi->dw_hdmi)) + return PTR_ERR(hdmi->dw_hdmi); + + platform_set_drvdata(pdev, hdmi); + + return 0; +} + +static int imx_dw_hdmi_remove(struct platform_device *pdev) +{ + struct dw_hdmi *hdmi = platform_get_drvdata(pdev); + + dw_hdmi_remove(hdmi); + + return 0; +} + +static const struct of_device_id imx_dw_hdmi_of_table[] = { + { .compatible = "fsl,imx8mp-hdmi" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx_dw_hdmi_of_table); + +static struct platform_driver im_dw_hdmi_platform_driver = { + .probe = imx_dw_hdmi_probe, + .remove = imx_dw_hdmi_remove, + .driver = { + .name = "imx-dw-hdmi", + .of_match_table = imx_dw_hdmi_of_table, + }, +}; + +module_platform_driver(im_dw_hdmi_platform_driver); + +MODULE_DESCRIPTION("i.MX8M HDMI encoder driver"); +MODULE_LICENSE("GPL");
On Mi, 2022-04-06 at 18:01 +0200, Lucas Stach wrote:
Add a simple wrapper driver for the DWC HDMI bridge driver that implements the few bits that are necessary to abstract the i.MX8MP SoC integration.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
Reviewed-by: Philipp Zabel p.zabel@pengutronix.de
regards Philipp
Add binding for the i.MX8MP HDMI parallel video interface block.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- .../display/imx/fsl,imx8mp-hdmi-pvi.yaml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml
diff --git a/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml b/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml new file mode 100644 index 000000000000..bf25d29c03ab --- /dev/null +++ b/Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/imx/fsl,imx8mp-hdmi-pvi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MP HDMI Parallel Video Interface + +maintainers: + - Lucas Stach l.stach@pengutronix.de + +description: | + The HDMI parallel video interface is timing and sync generator block in the + i.MX8MP SoC, that sits between the video source and the HDMI TX controller. + +properties: + compatible: + enum: + - fsl,imx8mp-hdmi-pvi + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: | + This device has two video ports. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Input from the LCDIF controller. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Output to the HDMI TX controller + + anyOf: + - required: + - port@0 + - required: + - port@1 + +required: + - compatible + - reg + - power-domains + - ports + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/imx8mp-clock.h> + #include <dt-bindings/power/imx8mp-power.h> + + display-bridge@32fc4000 { + compatible = "fsl,imx8mp-hdmi-pvi"; + reg = <0x32fc4000 0x40>; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_PVI>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + pvi_from_lcdif3: endpoint { + remote-endpoint = <&lcdif3_to_pvi>; + }; + }; + + port@1 { + reg = <1>; + pvi_to_hdmi_tx: endpoint { + remote-endpoint = <&hdmi_tx_from_pvi>; + }; + }; + }; + };
On Wed, 06 Apr 2022 18:01:17 +0200, Lucas Stach wrote:
Add binding for the i.MX8MP HDMI parallel video interface block.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
.../display/imx/fsl,imx8mp-hdmi-pvi.yaml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors: Error: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.example.dts:26.45-46 syntax error FATAL ERROR: Unable to parse input tree make[1]: *** [scripts/Makefile.lib:364: Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1401: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit.
This IP block is found in the HDMI subsystem of the i.MX8MP SoC. It has a full timing generator and can switch between different video sources. On the i.MX8MP however the only supported source is the LCDIF. The block just needs to be powered up and told about the polarity of the video sync signals to act in bypass mode.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- drivers/gpu/drm/imx/bridge/Kconfig | 8 + drivers/gpu/drm/imx/bridge/Makefile | 1 + drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c | 209 ++++++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c
diff --git a/drivers/gpu/drm/imx/bridge/Kconfig b/drivers/gpu/drm/imx/bridge/Kconfig index 8b02dc5606ba..486e4b2ad81a 100644 --- a/drivers/gpu/drm/imx/bridge/Kconfig +++ b/drivers/gpu/drm/imx/bridge/Kconfig @@ -8,3 +8,11 @@ config DRM_IMX_DW_HDMI_BRIDGE help Enable support for the internal HDMI encoder on i.MX8MP SoC
+config DRM_IMX_HDMI_PVI + tristate "HDMI encoder support" + depends on (ARCH_MXC && ARM64) || COMPILE_TEST + depends on DRM && OF + help + Enable support for the internal HDMI TX Parallel Video Interface + found on the i.MX8MP SoC. + diff --git a/drivers/gpu/drm/imx/bridge/Makefile b/drivers/gpu/drm/imx/bridge/Makefile index 1cfe9623c0d8..512ea98722b8 100644 --- a/drivers/gpu/drm/imx/bridge/Makefile +++ b/drivers/gpu/drm/imx/bridge/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DRM_IMX_DW_HDMI_BRIDGE) += imx-hdmi.o +obj-$(CONFIG_DRM_IMX_HDMI_PVI) += imx-hdmi-pvi.o diff --git a/drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c b/drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c new file mode 100644 index 000000000000..cdf296858062 --- /dev/null +++ b/drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Copyright (C) 2022 Pengutronix, Lucas Stach kernel@pengutronix.de + */ + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_crtc.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/pm_runtime.h> + +#define HTX_PVI_CTL 0x0 +#define PVI_CTL_OP_VSYNC_POL BIT(18) +#define PVI_CTL_OP_HSYNC_POL BIT(17) +#define PVI_CTL_OP_DE_POL BIT(16) +#define PVI_CTL_INP_VSYNC_POL BIT(14) +#define PVI_CTL_INP_HSYNC_POL BIT(13) +#define PVI_CTL_INP_DE_POL BIT(12) +#define PVI_CTL_INPUT_LCDIF BIT(2) +#define PVI_CTL_EN BIT(0) + +struct imx_hdmi_pvi { + struct drm_bridge bridge; + struct device *dev; + struct drm_bridge *next_bridge; + void __iomem *regs; +}; + +static inline struct imx_hdmi_pvi * +to_imx_hdmi_pvi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct imx_hdmi_pvi, bridge); +} + +static int imx_hdmi_pvi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct imx_hdmi_pvi *pvi = to_imx_hdmi_pvi(bridge); + + return drm_bridge_attach(bridge->encoder, pvi->next_bridge, bridge, flags); +} + +static void imx_hdmi_pvi_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct drm_atomic_state *state = bridge_state->base.state; + struct imx_hdmi_pvi *pvi = to_imx_hdmi_pvi(bridge); + struct drm_connector_state *conn_state; + const struct drm_display_mode *mode; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + u32 bus_flags, val; + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + if (WARN_ON(!connector)) + return; + + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + + if (WARN_ON(pm_runtime_resume_and_get(pvi->dev))) + return; + + mode = &crtc_state->adjusted_mode; + + val = PVI_CTL_INPUT_LCDIF; + + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + val |= PVI_CTL_OP_VSYNC_POL | PVI_CTL_INP_VSYNC_POL; + + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + val |= PVI_CTL_OP_HSYNC_POL | PVI_CTL_INP_HSYNC_POL; + + if (pvi->next_bridge->timings) + bus_flags = pvi->next_bridge->timings->input_bus_flags; + else if (bridge_state) + bus_flags = bridge_state->input_bus_cfg.flags; + + if (bus_flags & DRM_BUS_FLAG_DE_HIGH) + val |= PVI_CTL_OP_DE_POL | PVI_CTL_INP_DE_POL; + + writel(val, pvi->regs + HTX_PVI_CTL); + val |= PVI_CTL_EN; + writel(val, pvi->regs + HTX_PVI_CTL); +} + +static void imx_hdmi_pvi_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state) +{ + struct imx_hdmi_pvi *pvi = to_imx_hdmi_pvi(bridge); + + writel(0x0, pvi->regs + HTX_PVI_CTL); + + pm_runtime_put(pvi->dev); +} + +static u32 *pvi_bridge_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct imx_hdmi_pvi *pvi = to_imx_hdmi_pvi(bridge); + struct drm_bridge *next_bridge = pvi->next_bridge; + struct drm_bridge_state *next_state; + + if (!next_bridge->funcs->atomic_get_input_bus_fmts) + return 0; + + next_state = drm_atomic_get_new_bridge_state(crtc_state->state, + next_bridge); + + return next_bridge->funcs->atomic_get_input_bus_fmts(next_bridge, + next_state, + crtc_state, + conn_state, + output_fmt, + num_input_fmts); +} + +static const struct drm_bridge_funcs imx_hdmi_pvi_bridge_funcs = { + .attach = imx_hdmi_pvi_bridge_attach, + .atomic_enable = imx_hdmi_pvi_bridge_enable, + .atomic_disable = imx_hdmi_pvi_bridge_disable, + .atomic_get_input_bus_fmts = pvi_bridge_get_input_bus_fmts, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, +}; + +static int imx_hdmi_pvi_probe(struct platform_device *pdev) +{ + struct device_node *remote; + struct imx_hdmi_pvi *pvi; + + pvi = devm_kzalloc(&pdev->dev, sizeof(*pvi), GFP_KERNEL); + if (!pvi) + return -ENOMEM; + + platform_set_drvdata(pdev, pvi); + pvi->dev = &pdev->dev; + + pvi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pvi->regs)) + return PTR_ERR(pvi->regs); + + /* Get the next bridge in the pipeline. */ + remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1); + if (!remote) + return -EINVAL; + + pvi->next_bridge = of_drm_find_bridge(remote); + of_node_put(remote); + + if (!pvi->next_bridge) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, + "could not find next bridge\n"); + + /* Register the bridge. */ + pvi->bridge.funcs = &imx_hdmi_pvi_bridge_funcs; + pvi->bridge.of_node = pdev->dev.of_node; + pvi->bridge.timings = pvi->next_bridge->timings; + + drm_bridge_add(&pvi->bridge); + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static int imx_hdmi_pvi_remove(struct platform_device *pdev) +{ + struct imx_hdmi_pvi *pvi = platform_get_drvdata(pdev); + + drm_bridge_remove(&pvi->bridge); + + return 0; +} + +static const struct of_device_id imx_hdmi_pvi_match[] = { + { + .compatible = "fsl,imx8mp-hdmi-pvi", + }, { + /* sentinel */ + }, +}; +MODULE_DEVICE_TABLE(of, imx_hdmi_pvi_match); + +static struct platform_driver imx_hdmi_pvi_driver = { + .probe = imx_hdmi_pvi_probe, + .remove = imx_hdmi_pvi_remove, + .driver = { + .name = "imx-hdmi-pvi", + .of_match_table = imx_hdmi_pvi_match, + }, +}; +module_platform_driver(imx_hdmi_pvi_driver); + +MODULE_DESCRIPTION("i.MX8MP HDMI TX Parallel Video Interface bridge driver"); +MODULE_LICENSE("GPL");
On Mi, 2022-04-06 at 18:01 +0200, Lucas Stach wrote:
This IP block is found in the HDMI subsystem of the i.MX8MP SoC. It has a full timing generator and can switch between different video sources. On the i.MX8MP however the only supported source is the LCDIF. The block just needs to be powered up and told about the polarity of the video sync signals to act in bypass mode.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
[...]
+static void imx_hdmi_pvi_bridge_enable(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state)
+{
- struct drm_atomic_state *state = bridge_state->base.state;
- struct imx_hdmi_pvi *pvi = to_imx_hdmi_pvi(bridge);
- struct drm_connector_state *conn_state;
- const struct drm_display_mode *mode;
- struct drm_crtc_state *crtc_state;
- struct drm_connector *connector;
- u32 bus_flags, val;
- connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
- if (WARN_ON(!connector))
return;
- conn_state = drm_atomic_get_new_connector_state(state, connector);
- if (WARN_ON(!conn_state))
return;
- crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
- if (WARN_ON(!crtc_state))
return;
Can those happen at all, and if so, should they be caught at atomic_check time?
- if (WARN_ON(pm_runtime_resume_and_get(pvi->dev)))
return;
Should be pm_runtime_get_sync(), since the error is ignored.
Otherwise the pm_runtime_put() in imx_hdmi_pvi_bridge_disable() will double-decrement the usage counter in case this failed.
regards Philipp
Add a DT binding for the HDMI PHY found on the i.MX8MP SoC.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- .../bindings/phy/fsl,imx8mp-hdmi-phy.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml new file mode 100644 index 000000000000..bc21c073e92a --- /dev/null +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/fsl,imx8mp-hdmi-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MP HDMI PHY binding + +maintainers: + - Lucas Stach l.stach@pengutronix.de + +properties: + compatible: + enum: + - fsl,imx8mp-hdmi-phy + + reg: + maxItems: 1 + + "#clock-cells": + const: 0 + + clocks: + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: apb + - const: ref + + "#phy-cells": + const: 0 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - "#clock-cells" + - clocks + - clock-names + - power-domains + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/imx8mp-clock.h> + #include <dt-bindings/power/imx8mp-power.h> + + phy@32fdff00 { + compatible = "fsl,imx8mp-hdmi-phy"; + reg = <0x32fdff00 0x100>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_24M>; + clock-names = "apb", "ref"; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX_PHY>; + #clock-cells = <0>; + #phy-cells = <0>; + };
On Wed, 06 Apr 2022 18:01:19 +0200, Lucas Stach wrote:
Add a DT binding for the HDMI PHY found on the i.MX8MP SoC.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
.../bindings/phy/fsl,imx8mp-hdmi-phy.yaml | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors: Error: Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.example.dts:29.45-46 syntax error FATAL ERROR: Unable to parse input tree make[1]: *** [scripts/Makefile.lib:364: Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1401: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit.
This adds the driver for the Samsung HDMI PHY found on the i.MX8MP SoC.
Heavily based on the PHY implementation in the downstream kernel written by Sandor Yu Sandor.yu@nxp.com, but also cleaned up quite a bit and extended to support runtime PM.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- FIXME: The PHY configuration could be cleaned up further, it currently has a lot of register writes that are same across all supported modes. --- drivers/phy/freescale/Kconfig | 7 + drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 1145 ++++++++++++++++++ 3 files changed, 1153 insertions(+) create mode 100644 drivers/phy/freescale/phy-fsl-samsung-hdmi.c
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index f9c54cd02036..f80c92eb7c55 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -26,6 +26,13 @@ config PHY_FSL_IMX8M_PCIE Enable this to add support for the PCIE PHY as found on i.MX8M family of SOCs.
+config PHY_FSL_SAMSUNG_HDMI_PHY + tristate "Samsung HDMI PHY support" + depends on OF && HAS_IOMEM + select GENERIC_PHY + help + Enable this to add support for the Samsung HDMI PHY in i.MX8MP. + endif
config PHY_FSL_LYNX_28G diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile index 3518d5dbe8a7..46a26929376d 100644 --- a/drivers/phy/freescale/Makefile +++ b/drivers/phy/freescale/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o +obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c new file mode 100644 index 000000000000..70317a7fb845 --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c @@ -0,0 +1,1145 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Copyright 2022 Pengutronix, Lucas Stach kernel@pengutronix.de + */ + +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#define HDMI_TX_CONTROL0 0x200 +#define HDMI_TX_CONTROL_PHY_PWRDWN BIT(3) + +#define PHY_REG_33 0x84 +#define REG33_MODE_SET_DONE BIT(7) +#define REG33_FIX_DA BIT(1) + +#define PHY_REG_34 0x88 +#define REG34_PHY_READY BIT(7) +#define REG34_PLL_LOCK BIT(6) +#define REG34_PHY_CLK_READY BIT(5) + + +#define PHY_PLL_REGS_NUM 48 + +struct phy_config { + u32 clk_rate; + u8 regs[PHY_PLL_REGS_NUM]; +}; + +const struct phy_config phy_pll_cfg[] = { + { 22250000, { + 0x00, 0xD1, 0x4B, 0xF1, 0x89, 0x88, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x15, 0x25, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 23750000, { + 0x00, 0xD1, 0x50, 0xF1, 0x86, 0x85, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x03, 0x25, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + },{ + 24000000, { + 0x00, 0xD1, 0x50, 0xF0, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x01, 0x25, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + },{ + 24024000, { + 0x00, 0xD1, 0x50, 0xF1, 0x99, 0x02, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x00, 0x25, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 25175000, { + 0x00, 0xD1, 0x54, 0xFC, 0xCC, 0x91, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xF5, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 25200000, { + 0x00, 0xD1, 0x54, 0xF0, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xF4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 26750000, { + 0x00, 0xD1, 0x5A, 0xF2, 0x89, 0x88, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xE6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 27000000, { + 0x00, 0xD1, 0x5A, 0xF0, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 27027000, { + 0x00, 0xD1, 0x5A, 0xF2, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 29500000, { + 0x00, 0xD1, 0x62, 0xF4, 0x95, 0x08, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xD1, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 30750000, { + 0x00, 0xD1, 0x66, 0xF4, 0x82, 0x01, 0x88, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xC8, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 30888000, { + 0x00, 0xD1, 0x66, 0xF4, 0x99, 0x18, 0x88, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xC7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 33750000, { + 0x00, 0xD1, 0x70, 0xF4, 0x82, 0x01, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xB7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8F, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 35000000, { + 0x00, 0xD1, 0x58, 0xB8, 0x8B, 0x88, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xB0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8B, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 36000000, { + 0x00, 0xD1, 0x5A, 0xB0, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xAB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8B, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 36036000, { + 0x00, 0xD1, 0x5A, 0xB2, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0xAB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8B, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 40000000, { + 0x00, 0xD1, 0x64, 0xB0, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x9A, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x8B, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 43200000, { + 0x00, 0xD1, 0x5A, 0x90, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x8F, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x89, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 43243200, { + 0x00, 0xD1, 0x5A, 0x92, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x8F, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x89, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 44500000, { + 0x00, 0xD1, 0x5C, 0x92, 0x98, 0x11, 0x84, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x8B, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x89, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 47000000, { + 0x00, 0xD1, 0x62, 0x94, 0x95, 0x82, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x83, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x89, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 47500000, { + 0x00, 0xD1, 0x63, 0x96, 0xA1, 0x82, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x00, 0x82, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x89, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 50349650, { + 0x00, 0xD1, 0x54, 0x7C, 0xC3, 0x8F, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xF5, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 50400000, { + 0x00, 0xD1, 0x54, 0x70, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xF4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 53250000, { + 0x00, 0xD1, 0x58, 0x72, 0x84, 0x03, 0x82, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xE7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 53500000, { + 0x00, 0xD1, 0x5A, 0x72, 0x89, 0x88, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xE6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 54000000, { + 0x00, 0xD1, 0x5A, 0x70, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 54054000, { + 0x00, 0xD1, 0x5A, 0x72, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 59000000, { + 0x00, 0xD1, 0x62, 0x74, 0x95, 0x08, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xD1, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 59340659, { + 0x00, 0xD1, 0x62, 0x74, 0xDB, 0x52, 0x88, 0x47, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xD0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 59400000, { + 0x00, 0xD1, 0x63, 0x70, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xCF, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 61500000, { + 0x00, 0xD1, 0x66, 0x74, 0x82, 0x01, 0x88, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xC8, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 63500000, { + 0x00, 0xD1, 0x69, 0x74, 0x89, 0x08, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xC2, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x87, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 67500000, { + 0x00, 0xD1, 0x54, 0x52, 0x87, 0x03, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xB7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 70000000, { + 0x00, 0xD1, 0x58, 0x58, 0x8B, 0x88, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xB0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 72000000, { + 0x00, 0xD1, 0x5A, 0x50, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xAB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 72072000, { + 0x00, 0xD1, 0x5A, 0x52, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xAB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 74176000, { + 0x00, 0xD1, 0x5D, 0x58, 0xDB, 0xA2, 0x88, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 74250000, { + 0x00, 0xD1, 0x5C, 0x52, 0x90, 0x0D, 0x84, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 78500000, { + 0x00, 0xD1, 0x62, 0x54, 0x87, 0x01, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x9D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 80000000, { + 0x00, 0xD1, 0x64, 0x50, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x9A, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 82000000, { + 0x00, 0xD1, 0x66, 0x54, 0x82, 0x01, 0x88, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x96, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 82500000, { + 0x00, 0xD1, 0x67, 0x54, 0x88, 0x01, 0x90, 0x49, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x95, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 89000000, { + 0x00, 0xD1, 0x70, 0x54, 0x84, 0x83, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x8B, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 90000000, { + 0x00, 0xD1, 0x70, 0x54, 0x82, 0x01, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x89, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x85, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 94000000, { + 0x00, 0xD1, 0x4E, 0x32, 0xA7, 0x10, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x83, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 95000000, { + 0x00, 0xD1, 0x50, 0x31, 0x86, 0x85, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x82, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 98901099, { + 0x00, 0xD1, 0x52, 0x3A, 0xDB, 0x4C, 0x88, 0x47, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x7D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 99000000, { + 0x00, 0xD1, 0x52, 0x32, 0x82, 0x01, 0x88, 0x47, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x7D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 100699300, { + 0x00, 0xD1, 0x54, 0x3C, 0xC3, 0x8F, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xF5, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 100800000, { + 0x00, 0xD1, 0x54, 0x30, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xF4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 102500000, { + 0x00, 0xD1, 0x55, 0x32, 0x8C, 0x05, 0x90, 0x4B, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xF0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 104750000, { + 0x00, 0xD1, 0x57, 0x32, 0x98, 0x07, 0x90, 0x49, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xEB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 106500000, { + 0x00, 0xD1, 0x58, 0x32, 0x84, 0x03, 0x82, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xE7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 107000000, { + 0x00, 0xD1, 0x5A, 0x32, 0x89, 0x88, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xE6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 108000000, { + 0x00, 0xD1, 0x5A, 0x30, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 108108000, { + 0x00, 0xD1, 0x5A, 0x32, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 118000000, { + 0x00, 0xD1, 0x62, 0x34, 0x95, 0x08, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xD1, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 118800000, { + 0x00, 0xD1, 0x63, 0x30, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xCF, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 123000000, { + 0x00, 0xD1, 0x66, 0x34, 0x82, 0x01, 0x88, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xC8, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 127000000, { + 0x00, 0xD1, 0x69, 0x34, 0x89, 0x08, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xC2, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 135000000, { + 0x00, 0xD1, 0x70, 0x34, 0x82, 0x01, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xB7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 135580000, { + 0x00, 0xD1, 0x71, 0x39, 0xE9, 0x82, 0x9C, 0x5B, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xB6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 137520000, { + 0x00, 0xD1, 0x72, 0x38, 0x99, 0x10, 0x85, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xB3, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 138750000, { + 0x00, 0xD1, 0x73, 0x35, 0x88, 0x05, 0x90, 0x4D, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xB2, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 140000000, { + 0x00, 0xD1, 0x75, 0x36, 0xA7, 0x90, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xB0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 144000000, { + 0x00, 0xD1, 0x78, 0x30, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xAB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 148352000, { + 0x00, 0xD1, 0x7B, 0x35, 0xDB, 0x39, 0x90, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xA6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 148500000, { + 0x00, 0xD1, 0x7B, 0x35, 0x84, 0x03, 0x90, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xA6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 154000000, { + 0x00, 0xD1, 0x40, 0x18, 0x83, 0x01, 0x00, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0xA0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 157000000, { + 0x00, 0xD1, 0x41, 0x11, 0xA7, 0x14, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x9D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 160000000, { + 0x00, 0xD1, 0x42, 0x12, 0xA1, 0x20, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x9A, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 162000000, { + 0x00, 0xD1, 0x43, 0x18, 0x8B, 0x08, 0x96, 0x55, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x98, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 164000000, { + 0x00, 0xD1, 0x45, 0x11, 0x83, 0x82, 0x90, 0x4B, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x96, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 165000000, { + 0x00, 0xD1, 0x45, 0x11, 0x84, 0x81, 0x90, 0x4B, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x95, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 180000000, { + 0x00, 0xD1, 0x4B, 0x10, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x89, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 185625000, { + 0x00, 0xD1, 0x4E, 0x12, 0x9A, 0x95, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x85, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 188000000, { + 0x00, 0xD1, 0x4E, 0x12, 0xA7, 0x10, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x83, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 198000000, { + 0x00, 0xD1, 0x52, 0x12, 0x82, 0x01, 0x88, 0x47, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x7D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 205000000, { + 0x00, 0xD1, 0x55, 0x12, 0x8C, 0x05, 0x90, 0x4B, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xF0, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 209500000, { + 0x00, 0xD1, 0x57, 0x12, 0x98, 0x07, 0x90, 0x49, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xEB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 213000000, { + 0x00, 0xD1, 0x58, 0x12, 0x84, 0x03, 0x82, 0x41, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xE7, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 216000000, { + 0x00, 0xD1, 0x5A, 0x10, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 216216000, { + 0x00, 0xD1, 0x5A, 0x12, 0xFD, 0x0C, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xE4, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 237600000, { + 0x00, 0xD1, 0x63, 0x10, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xCF, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 254000000, { + 0x00, 0xD1, 0x69, 0x14, 0x89, 0x08, 0x80, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xC2, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 277500000, { + 0x00, 0xD1, 0x73, 0x15, 0x88, 0x05, 0x90, 0x4D, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xB2, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 288000000, { + 0x00, 0xD1, 0x78, 0x10, 0x00, 0x00, 0x80, 0x00, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xAB, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 297000000, { + 0x00, 0xD1, 0x7B, 0x15, 0x84, 0x03, 0x90, 0x45, + 0x4F, 0x30, 0x33, 0x65, 0x30, 0xA6, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 165000000, { + 0x00, 0xD1, 0x45, 0x11, 0x84, 0x81, 0x90, 0x4B, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x95, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 185625000, { + 0x00, 0xD1, 0x4E, 0x12, 0xB4, 0x95, 0x88, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x85, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 198000000, { + 0x00, 0xD1, 0x52, 0x12, 0x84, 0x01, 0x88, 0x47, + 0x4F, 0x30, 0x33, 0x65, 0x20, 0x7D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x81, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 90000000, { + 0x00, 0xD1, 0x4B, 0x32, 0x84, 0x00, 0x88, 0x40, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x89, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { + 99000000, { + 0x00, 0xD1, 0x52, 0x32, 0x84, 0x01, 0x88, 0x47, + 0x4F, 0x30, 0x33, 0x65, 0x10, 0x7D, 0x24, 0x80, + 0x6C, 0xF2, 0x67, 0x00, 0x10, 0x83, 0x30, 0x32, + 0x60, 0x8F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE0, 0x83, 0x0F, 0x3E, 0xF8, 0x00, 0x00, + }, + }, { /* sentinel */ }, +}; + + +struct fsl_samsung_hdmi_phy { + struct device *dev; + void __iomem *regs; + struct clk *apbclk; + struct clk *refclk; + + /* clk provider */ + struct clk_hw hw; + const struct phy_config *cur_cfg; +}; + +static inline struct fsl_samsung_hdmi_phy * +to_fsl_samsung_hdmi_phy(struct clk_hw *hw) +{ + return container_of(hw, struct fsl_samsung_hdmi_phy, hw); +} + +static void fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, + const struct phy_config *cfg) +{ + int i; + + /* HDMI PHY init */ + writeb(REG33_FIX_DA, phy->regs + PHY_REG_33); + + for (i = 0; i < PHY_PLL_REGS_NUM; i++) + writeb(cfg->regs[i], phy->regs + i * 4); + + writeb(REG33_FIX_DA | REG33_MODE_SET_DONE , phy->regs + PHY_REG_33); +} + +static int phy_clk_prepare(struct clk_hw *hw) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + int ret = 0; + u8 val; + + return 0; + ret = readb_poll_timeout(phy->regs + PHY_REG_34, val, + val & REG34_PLL_LOCK, + 20, 20000); + if (ret) + dev_err(phy->dev, "PLL failed to lock\n"); + + return ret; +} + +static unsigned long phy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + + if (!phy->cur_cfg) + return 0; + + return phy->cur_cfg->clk_rate; +} + +static long phy_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) +{ + const struct phy_config *phy_cfg = phy_pll_cfg; + + for (; phy_cfg->clk_rate != 0; phy_cfg++) + if (phy_cfg->clk_rate == rate) + break; + + if (phy_cfg->clk_rate == 0) + return -EINVAL; + + return phy_cfg->clk_rate; +} + +static int phy_clk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + const struct phy_config *phy_cfg = phy_pll_cfg; + int ret = 0; + u8 val; + + for (; phy_cfg->clk_rate != 0; phy_cfg++) + if (phy_cfg->clk_rate == rate) + break; + + if (phy_cfg->clk_rate == 0) + return -EINVAL; + + phy->cur_cfg = phy_cfg; + + fsl_samsung_hdmi_phy_configure(phy, phy_cfg); + + ret = readb_poll_timeout(phy->regs + PHY_REG_34, val, + val & REG34_PLL_LOCK, + 50, 20000); + if (ret) + dev_err(phy->dev, "PLL failed to lock\n"); + + return ret; +} + +static const struct clk_ops phy_clk_ops = { + .prepare = phy_clk_prepare, + .recalc_rate = phy_clk_recalc_rate, + .round_rate = phy_clk_round_rate, + .set_rate = phy_clk_set_rate, +}; + +static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy) +{ + struct device *dev = phy->dev; + struct device_node *np = dev->of_node; + struct clk_init_data init; + const char *parent_name; + struct clk *phyclk; + int ret; + + parent_name = __clk_get_name(phy->refclk); + + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + init.name = "hdmi_pclk"; + init.ops = &phy_clk_ops; + + phy->hw.init = &init; + + phyclk = devm_clk_register(dev, &phy->hw); + if (IS_ERR(phyclk)) + return dev_err_probe(dev, PTR_ERR(phyclk), + "failed to register clock\n"); + + ret = of_clk_add_provider(np, of_clk_src_simple_get, phyclk); + if (ret) + return dev_err_probe(dev, ret, + "failed to register clock provider\n"); + + return 0; +} + +static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev) +{ + struct fsl_samsung_hdmi_phy *phy; + int ret; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + platform_set_drvdata(pdev, phy); + phy->dev = &pdev->dev; + + phy->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->regs)) + return PTR_ERR(phy->regs); + + phy->apbclk = devm_clk_get(phy->dev, "apb"); + if (IS_ERR(phy->apbclk)) + return dev_err_probe(phy->dev, PTR_ERR(phy->apbclk), + "failed to get apb clk\n"); + + phy->refclk = devm_clk_get(phy->dev, "ref"); + if (IS_ERR(phy->refclk)) + return dev_err_probe(phy->dev, PTR_ERR(phy->refclk), + "failed to get ref clk\n"); + + ret = clk_prepare_enable(phy->apbclk); + if (ret) { + dev_err(phy->dev, "failed to enable apbclk\n"); + return ret; + } + + pm_runtime_get_noresume(phy->dev); + pm_runtime_set_active(phy->dev); + pm_runtime_enable(phy->dev); + + ret = phy_clk_register(phy); + if (ret) { + dev_err(&pdev->dev, "register clk failed\n"); + goto register_clk_failed; + } + + pm_runtime_put(phy->dev); + + return 0; + +register_clk_failed: + clk_disable_unprepare(phy->apbclk); + + return ret; +} + +static int fsl_samsung_hdmi_phy_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + + return 0; +} + +#ifdef CONFIG_PM +static int fsl_samsung_hdmi_phy_suspend(struct device *dev) +{ + struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); + + clk_disable_unprepare(phy->apbclk); + + return 0; +} + +static int fsl_samsung_hdmi_phy_resume(struct device *dev) +{ + struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(phy->apbclk); + if (ret) { + dev_err(phy->dev, "failed to enable apbclk\n"); + return ret; + } + + if (phy->cur_cfg) + fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); + + return 0; + +} +#endif + +static const struct dev_pm_ops fsl_samsung_hdmi_phy_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_samsung_hdmi_phy_suspend, + fsl_samsung_hdmi_phy_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static const struct of_device_id fsl_samsung_hdmi_phy_of_match[] = { + { + .compatible = "fsl,imx8mp-hdmi-phy", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, fsl_samsung_hdmi_phy_of_match); + +static struct platform_driver fsl_samsung_hdmi_phy_driver = { + .probe = fsl_samsung_hdmi_phy_probe, + .remove = fsl_samsung_hdmi_phy_remove, + .driver = { + .name = "fsl-samsung-hdmi-phy", + .of_match_table = fsl_samsung_hdmi_phy_of_match, + .pm = &fsl_samsung_hdmi_phy_pm_ops, + }, +}; +module_platform_driver(fsl_samsung_hdmi_phy_driver); + +MODULE_AUTHOR("Sandor Yu Sandor.yu@nxp.com"); +MODULE_DESCRIPTION("SAMSUNG HDMI 2.0 Transmitter PHY Driver"); +MODULE_LICENSE("GPL v2");
Hi Lucas,
On Mi, 2022-04-06 at 18:01 +0200, Lucas Stach wrote:
This adds the driver for the Samsung HDMI PHY found on the i.MX8MP SoC.
Heavily based on the PHY implementation in the downstream kernel written by Sandor Yu Sandor.yu@nxp.com, but also cleaned up quite a bit and extended to support runtime PM.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
FIXME: The PHY configuration could be cleaned up further, it currently has a lot of register writes that are same across all supported modes.
Agreed.
[...]
drivers/phy/freescale/Kconfig | 7 + Â drivers/phy/freescale/Makefile | 1 + Â drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 1145 ++++++++++++++++++ Â 3 files changed, 1153 insertions(+) Â create mode 100644 drivers/phy/freescale/phy-fsl-samsung-hdmi.c
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index f9c54cd02036..f80c92eb7c55 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -26,6 +26,13 @@ config PHY_FSL_IMX8M_PCIE  Enable this to add support for the PCIE PHY as found on  i.MX8M family of SOCs.  +config PHY_FSL_SAMSUNG_HDMI_PHY
- tristate "Samsung HDMI PHY support"
- depends on OF && HAS_IOMEM
- select GENERIC_PHY
Why select GENERIC_PHY when all the driver does is register a clock?
[...]
+struct fsl_samsung_hdmi_phy {
- struct device *dev;
- void __iomem *regs;
- struct clk *apbclk;
- struct clk *refclk;
refclk isn't really used beyond phy_clk_register, it doesn't have to be stored in struct fsl_samsung_hdmi_phy.
- /* clk provider */
- struct clk_hw hw;
- const struct phy_config *cur_cfg;
+};
+static inline struct fsl_samsung_hdmi_phy * +to_fsl_samsung_hdmi_phy(struct clk_hw *hw) +{
- return container_of(hw, struct fsl_samsung_hdmi_phy, hw);
+}
+static void fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy,
const struct phy_config *cfg)
+{
- int i;
- /* HDMI PHY init */
- writeb(REG33_FIX_DA, phy->regs + PHY_REG_33);
- for (i = 0; i < PHY_PLL_REGS_NUM; i++)
writeb(cfg->regs[i], phy->regs + i * 4);
- writeb(REG33_FIX_DA | REG33_MODE_SET_DONE , phy->regs + PHY_REG_33);
+}
+static int phy_clk_prepare(struct clk_hw *hw) +{
- struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- int ret = 0;
- u8 val;
- return 0;
I'd say remove this line or pyh_clk_prepare().
- ret = readb_poll_timeout(phy->regs + PHY_REG_34, val,
val & REG34_PLL_LOCK,
20, 20000);
- if (ret)
dev_err(phy->dev, "PLL failed to lock\n");
- return ret;
+}
+static unsigned long phy_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- if (!phy->cur_cfg)
return 0;
- return phy->cur_cfg->clk_rate;
+}
+static long phy_clk_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long *parent_rate)
+{
- const struct phy_config *phy_cfg = phy_pll_cfg;
- for (; phy_cfg->clk_rate != 0; phy_cfg++)
if (phy_cfg->clk_rate == rate)
* @round_rate: Given a target rate as input, returns the closest rate actually * supported by the clock. The parent rate is an input/output * parameter.
This should round, not -EINVAL on unsupported rates.
break;
- if (phy_cfg->clk_rate == 0)
return -EINVAL;
- return phy_cfg->clk_rate;
+}
+static int phy_clk_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
+{
- struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- const struct phy_config *phy_cfg = phy_pll_cfg;
- int ret = 0;
Unnecessary initialization.
- u8 val;
- for (; phy_cfg->clk_rate != 0; phy_cfg++)
if (phy_cfg->clk_rate == rate)
break;
- if (phy_cfg->clk_rate == 0)
return -EINVAL;
- phy->cur_cfg = phy_cfg;
- fsl_samsung_hdmi_phy_configure(phy, phy_cfg);
- ret = readb_poll_timeout(phy->regs + PHY_REG_34, val,
val & REG34_PLL_LOCK,
50, 20000);
- if (ret)
dev_err(phy->dev, "PLL failed to lock\n");
- return ret;
+}
+static const struct clk_ops phy_clk_ops = {
- .prepare = phy_clk_prepare,
- .recalc_rate = phy_clk_recalc_rate,
- .round_rate = phy_clk_round_rate,
- .set_rate = phy_clk_set_rate,
+};
+static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy) +{
- struct device *dev = phy->dev;
- struct device_node *np = dev->of_node;
- struct clk_init_data init;
- const char *parent_name;
- struct clk *phyclk;
- int ret;
- parent_name = __clk_get_name(phy->refclk);
- init.parent_names = &parent_name;
- init.num_parents = 1;
- init.flags = 0;
- init.name = "hdmi_pclk";
- init.ops = &phy_clk_ops;
- phy->hw.init = &init;
- phyclk = devm_clk_register(dev, &phy->hw);
- if (IS_ERR(phyclk))
return dev_err_probe(dev, PTR_ERR(phyclk),
"failed to register clock\n");
- ret = of_clk_add_provider(np, of_clk_src_simple_get, phyclk);
- if (ret)
return dev_err_probe(dev, ret,
"failed to register clock provider\n");
- return 0;
+}
+static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev) +{
- struct fsl_samsung_hdmi_phy *phy;
- int ret;
- phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
- if (!phy)
return -ENOMEM;
- platform_set_drvdata(pdev, phy);
- phy->dev = &pdev->dev;
- phy->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(phy->regs))
return PTR_ERR(phy->regs);
- phy->apbclk = devm_clk_get(phy->dev, "apb");
- if (IS_ERR(phy->apbclk))
return dev_err_probe(phy->dev, PTR_ERR(phy->apbclk),
"failed to get apb clk\n");
- phy->refclk = devm_clk_get(phy->dev, "ref");
- if (IS_ERR(phy->refclk))
return dev_err_probe(phy->dev, PTR_ERR(phy->refclk),
"failed to get ref clk\n");
- ret = clk_prepare_enable(phy->apbclk);
- if (ret) {
dev_err(phy->dev, "failed to enable apbclk\n");
return ret;
- }
- pm_runtime_get_noresume(phy->dev);
- pm_runtime_set_active(phy->dev);
- pm_runtime_enable(phy->dev);
- ret = phy_clk_register(phy);
- if (ret) {
dev_err(&pdev->dev, "register clk failed\n");
goto register_clk_failed;
- }
- pm_runtime_put(phy->dev);
- return 0;
+register_clk_failed:
- clk_disable_unprepare(phy->apbclk);
- return ret;
+}
+static int fsl_samsung_hdmi_phy_remove(struct platform_device *pdev) +{
- of_clk_del_provider(pdev->dev.of_node);
- return 0;
+}
+#ifdef CONFIG_PM +static int fsl_samsung_hdmi_phy_suspend(struct device *dev) +{
- struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev);
- clk_disable_unprepare(phy->apbclk);
- return 0;
+}
+static int fsl_samsung_hdmi_phy_resume(struct device *dev) +{
- struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev);
- int ret;
- ret = clk_prepare_enable(phy->apbclk);
- if (ret) {
dev_err(phy->dev, "failed to enable apbclk\n");
return ret;
- }
- if (phy->cur_cfg)
fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
Not checking PLL lock during resume?
regards Philipp
Hi Lucas,
On Wed, Apr 06, 2022 at 06:01:20PM +0200, Lucas Stach wrote:
+static unsigned long phy_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- if (!phy->cur_cfg)
return 0;
- return phy->cur_cfg->clk_rate;
+}
This means that the clock will return 0 at initialization, which will throw the rate accounting in the CCF off.
Returning 0 here isn't valid. Surely that phy has a default configuration at boot that you could use to initialize a rate?
See https://lore.kernel.org/linux-clk/20220408091037.2041955-1-maxime@cerno.tech...
Maxime
Hi Maxime,
Am Montag, dem 11.04.2022 um 13:59 +0200 schrieb Maxime Ripard:
Hi Lucas,
On Wed, Apr 06, 2022 at 06:01:20PM +0200, Lucas Stach wrote:
+static unsigned long phy_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- if (!phy->cur_cfg)
return 0;
- return phy->cur_cfg->clk_rate;
+}
This means that the clock will return 0 at initialization, which will throw the rate accounting in the CCF off.
Returning 0 here isn't valid. Surely that phy has a default configuration at boot that you could use to initialize a rate?
See https://lore.kernel.org/linux-clk/20220408091037.2041955-1-maxime@cerno.tech...
Thanks for the hint. I don't know the full history of this and surely I can use the register reset defaults to initialize the clock rate, but it still seems odd. A powered down clock generator, like the PLL in this PHY, is not actually putting out a clock at any rate, so 0 for the rate seems natural, so it's kind of a bad pitfall if the CCF can't deal with that.
Regards, Lucas
On Mon, Apr 11, 2022 at 02:20:22PM +0200, Lucas Stach wrote:
Hi Maxime,
Am Montag, dem 11.04.2022 um 13:59 +0200 schrieb Maxime Ripard:
Hi Lucas,
On Wed, Apr 06, 2022 at 06:01:20PM +0200, Lucas Stach wrote:
+static unsigned long phy_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
+{
- struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
- if (!phy->cur_cfg)
return 0;
- return phy->cur_cfg->clk_rate;
+}
This means that the clock will return 0 at initialization, which will throw the rate accounting in the CCF off.
Returning 0 here isn't valid. Surely that phy has a default configuration at boot that you could use to initialize a rate?
See https://lore.kernel.org/linux-clk/20220408091037.2041955-1-maxime@cerno.tech...
Thanks for the hint. I don't know the full history of this and surely I can use the register reset defaults to initialize the clock rate, but it still seems odd. A powered down clock generator, like the PLL in this PHY, is not actually putting out a clock at any rate, so 0 for the rate seems natural, so it's kind of a bad pitfall if the CCF can't deal with that.
Yeah, it's what that whole discussion has been about, but my understanding is that clk_get_rate() (and thus .recalc_rate) don't necessarily return the actual output rate in hardware, but the rate that would be output if the clock was enabled.
Anyway, I've ping'd Stephen on IRC to see if he can clarifies this, we won't have an issue on this before then I'm afraid :)
Maxime
The HDMI irqsteer is a secondary interrupt controller within the HDMI subsystem that maps all HDMI peripheral IRQs into a single upstream IRQ line.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index cbe75b816b43..6b7b5ba32b48 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -1074,6 +1074,19 @@ hdmi_blk_ctrl: blk-ctrl@32fc0000 { "hdmi-tx", "hdmi-tx-phy"; #power-domain-cells = <1>; }; + + irqsteer_hdmi: interrupt-controller@32fc2000 { + compatible = "fsl,imx-irqsteer"; + reg = <0x32fc2000 0x44>; + interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <1>; + fsl,channel = <1>; + fsl,num-irqs = <64>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>; + clock-names = "ipg"; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_IRQSTEER>; + }; };
gpu3d: gpu@38000000 {
This adds the DT nodes for all the peripherals that make up the HDMI display pipeline.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- arch/arm64/boot/dts/freescale/imx8mp.dtsi | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 6b7b5ba32b48..a41da99e9537 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -1087,6 +1087,86 @@ irqsteer_hdmi: interrupt-controller@32fc2000 { clock-names = "ipg"; power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_IRQSTEER>; }; + + hdmi_pvi: display-bridge@32fc4000 { + compatible = "fsl,imx8mp-hdmi-pvi"; + reg = <0x32fc4000 0x40>; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_PVI>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + pvi_from_lcdif3: endpoint { + remote-endpoint = <&lcdif3_to_pvi>; + }; + }; + + port@1 { + reg = <1>; + pvi_to_hdmi_tx: endpoint { + remote-endpoint = <&hdmi_tx_from_pvi>; + }; + }; + }; + }; + + lcdif3: display-controller@32fc6000 { + compatible = "fsl,imx8mp-lcdif"; + reg = <0x32fc6000 0x238>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&irqsteer_hdmi>; + clocks = <&hdmi_tx_phy>, + <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_ROOT>; + clock-names = "pix", "axi", "disp_axi"; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_LCDIF>; + + port { + lcdif3_to_pvi: endpoint { + remote-endpoint = <&pvi_from_lcdif3>; + }; + }; + }; + + hdmi_tx: hdmi@32fd8000 { + compatible = "fsl,imx8mp-hdmi"; + reg = <0x32fd8000 0x7eff>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&irqsteer_hdmi>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_REF_266M>, + <&clk IMX8MP_CLK_32K>, + <&hdmi_tx_phy>; + clock-names = "iahb", "isfr", "cec", "pix"; + assigned-clocks = <&clk IMX8MP_CLK_HDMI_REF_266M>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX>; + reg-io-width = <1>; + status = "disabled"; + + port { + hdmi_tx_from_pvi: endpoint { + remote-endpoint = <&pvi_to_hdmi_tx>; + }; + }; + }; + + hdmi_tx_phy: phy@32fdff00 { + compatible = "fsl,imx8mp-hdmi-phy"; + reg = <0x32fdff00 0x100>; + clocks = <&clk IMX8MP_CLK_HDMI_APB>, + <&clk IMX8MP_CLK_HDMI_24M>; + clock-names = "apb", "ref"; + assigned-clocks = <&clk IMX8MP_CLK_HDMI_24M>; + assigned-clock-parents = <&clk IMX8MP_CLK_24M>; + power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX_PHY>; + #clock-cells = <0>; + #phy-cells = <0>; + status = "disabled"; + }; };
gpu3d: gpu@38000000 {
Hi Lucas,
Am Mittwoch, 6. April 2022, 18:01:22 CEST schrieb Lucas Stach:
This adds the DT nodes for all the peripherals that make up the HDMI display pipeline.
Signed-off-by: Lucas Stach l.stach@pengutronix.de
arch/arm64/boot/dts/freescale/imx8mp.dtsi | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 6b7b5ba32b48..a41da99e9537 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -1087,6 +1087,86 @@ irqsteer_hdmi: interrupt-controller@32fc2000 { clock-names = "ipg"; power-domains = <&hdmi_blk_ctrl
IMX8MP_HDMIBLK_PD_IRQSTEER>;
};
hdmi_pvi: display-bridge@32fc4000 {
compatible = "fsl,imx8mp-hdmi-
pvi";
reg = <0x32fc4000 0x40>;
power-domains = <&hdmi_blk_ctrl
IMX8MP_HDMIBLK_PD_PVI>;
This should be disabled by default as well. Unless 'hdmi_tx: hdmi@32fd8000' is enabled, this results in the warning: imx-hdmi-pvi: probe of 32fc4000.display-bridge failed with error -22
Best regards Alexander
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
pvi_from_lcdif3: endpoint {
remote-endpoint = <&lcdif3_to_pvi>;
};
};
port@1 {
reg = <1>;
pvi_to_hdmi_tx: endpoint {
remote-endpoint = <&hdmi_tx_from_pvi>;
};
};
};
};
lcdif3: display-controller@32fc6000 {
compatible = "fsl,imx8mp-lcdif";
reg = <0x32fc6000 0x238>;
interrupts = <8
IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent =
<&irqsteer_hdmi>;
clocks = <&hdmi_tx_phy>,
<&clk
IMX8MP_CLK_HDMI_APB>,
<&clk
IMX8MP_CLK_HDMI_ROOT>;
clock-names = "pix", "axi",
"disp_axi";
power-domains = <&hdmi_blk_ctrl
IMX8MP_HDMIBLK_PD_LCDIF>;
port {
lcdif3_to_pvi: endpoint
{
remote-
endpoint = <&pvi_from_lcdif3>;
};
};
};
hdmi_tx: hdmi@32fd8000 {
compatible = "fsl,imx8mp-hdmi";
reg = <0x32fd8000 0x7eff>;
interrupts = <0
IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent =
<&irqsteer_hdmi>;
clocks = <&clk
IMX8MP_CLK_HDMI_APB>,
<&clk
IMX8MP_CLK_HDMI_REF_266M>,
<&clk IMX8MP_CLK_32K>,
<&hdmi_tx_phy>;
clock-names = "iahb", "isfr",
"cec", "pix";
assigned-clocks = <&clk
IMX8MP_CLK_HDMI_REF_266M>;
assigned-clock-parents = <&clk
IMX8MP_SYS_PLL1_266M>;
power-domains = <&hdmi_blk_ctrl
IMX8MP_HDMIBLK_PD_HDMI_TX>;
reg-io-width = <1>;
status = "disabled";
port {
hdmi_tx_from_pvi:
endpoint {
remote-
endpoint = <&pvi_to_hdmi_tx>;
};
};
};
hdmi_tx_phy: phy@32fdff00 {
compatible = "fsl,imx8mp-hdmi-
phy";
reg = <0x32fdff00 0x100>;
clocks = <&clk
IMX8MP_CLK_HDMI_APB>,
<&clk
IMX8MP_CLK_HDMI_24M>;
clock-names = "apb", "ref";
assigned-clocks = <&clk
IMX8MP_CLK_HDMI_24M>;
assigned-clock-parents = <&clk
IMX8MP_CLK_24M>;
power-domains = <&hdmi_blk_ctrl
IMX8MP_HDMIBLK_PD_HDMI_TX_PHY>;
#clock-cells = <0>;
#phy-cells = <0>;
status = "disabled";
};
};
gpu3d: gpu@38000000 {
Enable the DT nodes for HDMI TX and PHY and add the pinctrl for the few involved pins that are configurable.
Signed-off-by: Lucas Stach l.stach@pengutronix.de --- arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts index 4c3ac4214a2c..fdf851865ba9 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts @@ -197,6 +197,16 @@ ethphy1: ethernet-phy@1 { }; };
+&hdmi_tx { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi>; + status = "okay"; +}; + +&hdmi_tx_phy { + status = "okay"; +}; + &i2c1 { clock-frequency = <400000>; pinctrl-names = "default"; @@ -465,6 +475,15 @@ MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19 >; };
+ pinctrl_hdmi: hdmigrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x1c3 + MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x1c3 + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x19 + MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x19 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3
On Wed, Apr 6, 2022 at 9:01 AM Lucas Stach l.stach@pengutronix.de wrote:
Hi all,
this adds support for the HDMI output pipeline on the i.MX8MP. It currently depends on the i.MX8MP HDMI power domain series [1] and support for the new LCDIF [2] in the i.MX8MP. I guess the implementation presented here also still has some warts that require fixing and the individual patches most likely need to go through different maintainer trees, so I don't expect this series to be applied right away.
However this complete series should allow people to test it more easily and provide feedback on the implementation with the full picture available.
Compared to downstream this implementation actually allows to power down the separate HDMI PHY power domain when the display is inactive or no HDMI cable is connected.
Regards, Lucas
[1] https://lore.kernel.org/all/20220406153402.1265474-1-l.stach@pengutronix.de/ [2] https://lore.kernel.org/all/20220322142853.125880-1-marex@denx.de/
Lucas Stach (10): drm/bridge: dw-hdmi: add low-active PHY reset dt-bindings: display: imx: add binding for i.MX8MP HDMI TX drm/imx: add bridge wrapper driver for i.MX8MP DWC HDMI dt-bindings: display: imx: add binding for i.MX8MP HDMI PVI drm/imx: add driver for HDMI TX Parallel Video Interface dt-bindings: phy: add binding for the i.MX8MP HDMI PHY phy: freescale: add Samsung HDMI PHY arm64: dts: imx8mp: add HDMI irqsteer arm64: dts: imx8mp: add HDMI display pipeline arm64: dts: imx8mp-evk: enable HDMI
.../display/imx/fsl,imx8mp-hdmi-pvi.yaml | 83 ++ .../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 ++ .../bindings/phy/fsl,imx8mp-hdmi-phy.yaml | 62 + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 19 + arch/arm64/boot/dts/freescale/imx8mp.dtsi | 93 ++ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 + drivers/gpu/drm/imx/Kconfig | 1 + drivers/gpu/drm/imx/Makefile | 2 + drivers/gpu/drm/imx/bridge/Kconfig | 18 + drivers/gpu/drm/imx/bridge/Makefile | 4 + drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c | 209 +++ drivers/gpu/drm/imx/bridge/imx-hdmi.c | 128 ++ drivers/phy/freescale/Kconfig | 7 + drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 1145 +++++++++++++++++ include/drm/bridge/dw_hdmi.h | 1 + 16 files changed, 1852 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml create mode 100644 drivers/gpu/drm/imx/bridge/Kconfig create mode 100644 drivers/gpu/drm/imx/bridge/Makefile create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi.c create mode 100644 drivers/phy/freescale/phy-fsl-samsung-hdmi.c
-- 2.30.2
Lucas,
Thanks for consolidating this - It's been difficult to try to merge these for testing.
I still have not been able to apply these to origin/master or imx/master - what are you basing off of here?
Best Regards,
Tim I
Hi Tim,
Am Mittwoch, dem 06.04.2022 um 09:10 -0700 schrieb Tim Harvey:
On Wed, Apr 6, 2022 at 9:01 AM Lucas Stach l.stach@pengutronix.de wrote:
Hi all,
this adds support for the HDMI output pipeline on the i.MX8MP. It currently depends on the i.MX8MP HDMI power domain series [1] and support for the new LCDIF [2] in the i.MX8MP. I guess the implementation presented here also still has some warts that require fixing and the individual patches most likely need to go through different maintainer trees, so I don't expect this series to be applied right away.
However this complete series should allow people to test it more easily and provide feedback on the implementation with the full picture available.
Compared to downstream this implementation actually allows to power down the separate HDMI PHY power domain when the display is inactive or no HDMI cable is connected.
Regards, Lucas
[1] https://lore.kernel.org/all/20220406153402.1265474-1-l.stach@pengutronix.de/ [2] https://lore.kernel.org/all/20220322142853.125880-1-marex@denx.de/
Lucas Stach (10): drm/bridge: dw-hdmi: add low-active PHY reset dt-bindings: display: imx: add binding for i.MX8MP HDMI TX drm/imx: add bridge wrapper driver for i.MX8MP DWC HDMI dt-bindings: display: imx: add binding for i.MX8MP HDMI PVI drm/imx: add driver for HDMI TX Parallel Video Interface dt-bindings: phy: add binding for the i.MX8MP HDMI PHY phy: freescale: add Samsung HDMI PHY arm64: dts: imx8mp: add HDMI irqsteer arm64: dts: imx8mp: add HDMI display pipeline arm64: dts: imx8mp-evk: enable HDMI
.../display/imx/fsl,imx8mp-hdmi-pvi.yaml | 83 ++ .../bindings/display/imx/fsl,imx8mp-hdmi.yaml | 72 ++ .../bindings/phy/fsl,imx8mp-hdmi-phy.yaml | 62 + arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 19 + arch/arm64/boot/dts/freescale/imx8mp.dtsi | 93 ++ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 + drivers/gpu/drm/imx/Kconfig | 1 + drivers/gpu/drm/imx/Makefile | 2 + drivers/gpu/drm/imx/bridge/Kconfig | 18 + drivers/gpu/drm/imx/bridge/Makefile | 4 + drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c | 209 +++ drivers/gpu/drm/imx/bridge/imx-hdmi.c | 128 ++ drivers/phy/freescale/Kconfig | 7 + drivers/phy/freescale/Makefile | 1 + drivers/phy/freescale/phy-fsl-samsung-hdmi.c | 1145 +++++++++++++++++ include/drm/bridge/dw_hdmi.h | 1 + 16 files changed, 1852 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi-pvi.yaml create mode 100644 Documentation/devicetree/bindings/display/imx/fsl,imx8mp-hdmi.yaml create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mp-hdmi-phy.yaml create mode 100644 drivers/gpu/drm/imx/bridge/Kconfig create mode 100644 drivers/gpu/drm/imx/bridge/Makefile create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi-pvi.c create mode 100644 drivers/gpu/drm/imx/bridge/imx-hdmi.c create mode 100644 drivers/phy/freescale/phy-fsl-samsung-hdmi.c
-- 2.30.2
Lucas,
Thanks for consolidating this - It's been difficult to try to merge these for testing.
I still have not been able to apply these to origin/master or imx/master - what are you basing off of here?
This HDMI series depends on the HDMI blk-ctrl ([1] in this cover letter), which in turn depends on the GPCv2 i.MX8MP support series ([1] in the HDMI blk-ctrl cover letter), which should apply cleanly or with minimal fuzz to 5.18-rc1.
Regards, Lucas
Hello Lucas,
Am Mittwoch, 6. April 2022, 18:01:13 CEST schrieb Lucas Stach:
Hi all,
this adds support for the HDMI output pipeline on the i.MX8MP. It currently depends on the i.MX8MP HDMI power domain series [1] and support for the new LCDIF [2] in the i.MX8MP. I guess the implementation presented here also still has some warts that require fixing and the individual patches most likely need to go through different maintainer trees, so I don't expect this series to be applied right away.
However this complete series should allow people to test it more easily and provide feedback on the implementation with the full picture available.
Compared to downstream this implementation actually allows to power down the separate HDMI PHY power domain when the display is inactive or no HDMI cable is connected.
Thanks for these patches. I tried using them on my imx8mp based board (TQMa8MPxL + MBa8MPxL) but failed to get the display showing anything. I noticed several things though:
* For some reason the HDMI PHY PLL does not lock. I get the error
fsl-samsung-hdmi-phy 32fdff00.phy: PLL failed to lock
Increasing timeout does not change anything.
* The HDMI bridge wants to use bus format 0x200f which is not supported by lcdif.
lcdif 32fc6000.display-controller: Unknown media bus format 0x200f
I wonder which part in the DRM chain choses to use this. But even hard limiting to 0x100a the screen stayed in suspend
* If the drivers are built as modules I get a hard lockup during boot. Using built-in drivers or 'clk_ignore_unused' workarounds this.
* DDC does actually work. The display is detected and EDID can be read.
* Sometimes I get the following error: ------------[ cut here ]------------ [CRTC:33:crtc-0] vblank wait timed out WARNING: CPU: 2 PID: 151 at drivers/gpu/drm/drm_atomic_helper.c:1529 drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc Modules linked in: caamhash_desc caamalg_desc crypto_engine rng_core mcp320x dw_hdmi_cec authenc libdes dw100 videobuf2_dma_contig lcdif crct10dif_ce phy_fsl_samsung_hdmi v4l2_mem2mem imx_sdma flexcan imx8mm_thermal can_dev caam error pwm_fan fuse ipv6 CPU: 2 PID: 151 Comm: kworker/u8:7 Not tainted 5.18.0-rc2-next-20220412+ #165 d226098cac46ded24901c7090f909ca8f5098eb0 Hardware name: TQ-Systems i.MX8MPlus TQMa8MPxL on MBa8MPxL (DT) Workqueue: events_unbound deferred_probe_work_func pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc lr : drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc sp : ffff80000a133430 x29: ffff80000a133430 x28: 0000000000000000 x27: 0000000000000000 x26: 0000000000000000 x25: 0000000000000001 x24: ffff80000935f030 x23: ffff00000433e000 x22: ffff0000029e7000 x21: 0000000000000001 x20: ffff000002e7fb48 x19: 0000000000000000 x18: 0000000000000001 x17: 4d554e5145530065 x16: 6c75646f6d3d4d45 x15: 5453595342555300 x14: 0000000000000000 x13: 0a74756f2064656d x12: 6974207469617720 x11: 0000000000000000 x10: 000000000000003a x9 : ffff80000a133430 x8 : 00000000ffffffff x7 : 6974207469617720 x6 : 6b6e616c6276205d x5 : ffff00007fb91b00 x4 : 0000000000000000 x3 : 0000000000000027 x2 : 0000000000000023 x1 : 0000000000000000 x0 : 0000000000000000 Call trace: drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc drm_atomic_helper_commit_tail_rpm+0x80/0xa0 commit_tail+0xcc/0x1f0 drm_atomic_helper_commit+0x13c/0x370 drm_atomic_commit+0xa4/0xe0 drm_client_modeset_commit_atomic+0x1fc/0x250 drm_client_modeset_commit_locked+0x58/0xa0 drm_client_modeset_commit+0x2c/0x50 __drm_fb_helper_restore_fbdev_mode_unlocked+0xec/0x140 drm_fb_helper_set_par+0x38/0x6c fbcon_init+0x264/0x5e4 visual_init+0xc8/0x15c do_bind_con_driver.isra.0+0x20c/0x470 do_take_over_console+0x44/0x60 do_fbcon_takeover+0x80/0x140 fbcon_fb_registered+0x1c4/0x260 do_register_framebuffer+0x1e0/0x2d0 register_framebuffer+0x2c/0x50 __drm_fb_helper_initial_config_and_unlock+0x9c/0x130 drm_fbdev_client_hotplug+0x1a8/0x20c drm_fbdev_generic_setup+0xc0/0x1d0 lcdif_probe+0x7c/0xa0 [lcdif e756925430e957a7bc9e6376ad5964e4b1cb143e] platform_probe+0x64/0x100 call_driver_probe+0x28/0x130 really_probe+0x178/0x310 __driver_probe_device+0xfc/0x144 driver_probe_device+0x38/0x12c __device_attach_driver+0xd4/0x180 bus_for_each_drv+0x74/0xc4 __device_attach+0xd8/0x1e0 device_initial_probe+0x10/0x20 bus_probe_device+0x90/0xa0 deferred_probe_work_func+0x9c/0xf0 process_one_work+0x1d0/0x330 worker_thread+0x68/0x390 kthread+0xec/0xfc ret_from_fork+0x10/0x20 ---[ end trace 0000000000000000 ]---
But given that the PLL did not lock I assume this is not too surprising.
Best regards, Alexander
Hi Alexander,
Am Dienstag, dem 12.04.2022 um 11:18 +0200 schrieb Alexander Stein:
Hello Lucas,
Am Mittwoch, 6. April 2022, 18:01:13 CEST schrieb Lucas Stach:
Hi all,
this adds support for the HDMI output pipeline on the i.MX8MP. It currently depends on the i.MX8MP HDMI power domain series [1] and support for the new LCDIF [2] in the i.MX8MP. I guess the implementation presented here also still has some warts that require fixing and the individual patches most likely need to go through different maintainer trees, so I don't expect this series to be applied right away.
However this complete series should allow people to test it more easily and provide feedback on the implementation with the full picture available.
Compared to downstream this implementation actually allows to power down the separate HDMI PHY power domain when the display is inactive or no HDMI cable is connected.
Thanks for these patches. I tried using them on my imx8mp based board (TQMa8MPxL + MBa8MPxL) but failed to get the display showing anything. I noticed several things though:
- For some reason the HDMI PHY PLL does not lock. I get the error
fsl-samsung-hdmi-phy 32fdff00.phy: PLL failed to lock
Increasing timeout does not change anything.
- The HDMI bridge wants to use bus format 0x200f which is not supported by
lcdif.
lcdif 32fc6000.display-controller: Unknown media bus format 0x200f
I wonder which part in the DRM chain choses to use this.
Do have a 4k HDMI display connected that wants to do YUV input? That's something I have to admit I didn't test yet and would be likely to cause this bus format selection.
But even hard limiting to 0x100a the screen stayed in suspend
- If the drivers are built as modules I get a hard lockup during boot. Using
built-in drivers or 'clk_ignore_unused' workarounds this.
DDC does actually work. The display is detected and EDID can be read.
Sometimes I get the following error:
------------[ cut here ]------------ [CRTC:33:crtc-0] vblank wait timed out WARNING: CPU: 2 PID: 151 at drivers/gpu/drm/drm_atomic_helper.c:1529 drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc Modules linked in: caamhash_desc caamalg_desc crypto_engine rng_core mcp320x dw_hdmi_cec authenc libdes dw100 videobuf2_dma_contig lcdif crct10dif_ce phy_fsl_samsung_hdmi v4l2_mem2mem imx_sdma flexcan imx8mm_thermal can_dev caam error pwm_fan fuse ipv6 CPU: 2 PID: 151 Comm: kworker/u8:7 Not tainted 5.18.0-rc2-next-20220412+ #165 d226098cac46ded24901c7090f909ca8f5098eb0 Hardware name: TQ-Systems i.MX8MPlus TQMa8MPxL on MBa8MPxL (DT) Workqueue: events_unbound deferred_probe_work_func pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc lr : drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc sp : ffff80000a133430 x29: ffff80000a133430 x28: 0000000000000000 x27: 0000000000000000 x26: 0000000000000000 x25: 0000000000000001 x24: ffff80000935f030 x23: ffff00000433e000 x22: ffff0000029e7000 x21: 0000000000000001 x20: ffff000002e7fb48 x19: 0000000000000000 x18: 0000000000000001 x17: 4d554e5145530065 x16: 6c75646f6d3d4d45 x15: 5453595342555300 x14: 0000000000000000 x13: 0a74756f2064656d x12: 6974207469617720 x11: 0000000000000000 x10: 000000000000003a x9 : ffff80000a133430 x8 : 00000000ffffffff x7 : 6974207469617720 x6 : 6b6e616c6276205d x5 : ffff00007fb91b00 x4 : 0000000000000000 x3 : 0000000000000027 x2 : 0000000000000023 x1 : 0000000000000000 x0 : 0000000000000000 Call trace: drm_atomic_helper_wait_for_vblanks.part.0+0x2ac/0x2fc drm_atomic_helper_commit_tail_rpm+0x80/0xa0 commit_tail+0xcc/0x1f0 drm_atomic_helper_commit+0x13c/0x370 drm_atomic_commit+0xa4/0xe0 drm_client_modeset_commit_atomic+0x1fc/0x250 drm_client_modeset_commit_locked+0x58/0xa0 drm_client_modeset_commit+0x2c/0x50 __drm_fb_helper_restore_fbdev_mode_unlocked+0xec/0x140 drm_fb_helper_set_par+0x38/0x6c fbcon_init+0x264/0x5e4 visual_init+0xc8/0x15c do_bind_con_driver.isra.0+0x20c/0x470 do_take_over_console+0x44/0x60 do_fbcon_takeover+0x80/0x140 fbcon_fb_registered+0x1c4/0x260 do_register_framebuffer+0x1e0/0x2d0 register_framebuffer+0x2c/0x50 __drm_fb_helper_initial_config_and_unlock+0x9c/0x130 drm_fbdev_client_hotplug+0x1a8/0x20c drm_fbdev_generic_setup+0xc0/0x1d0 lcdif_probe+0x7c/0xa0 [lcdif e756925430e957a7bc9e6376ad5964e4b1cb143e] platform_probe+0x64/0x100 call_driver_probe+0x28/0x130 really_probe+0x178/0x310 __driver_probe_device+0xfc/0x144 driver_probe_device+0x38/0x12c __device_attach_driver+0xd4/0x180 bus_for_each_drv+0x74/0xc4 __device_attach+0xd8/0x1e0 device_initial_probe+0x10/0x20 bus_probe_device+0x90/0xa0 deferred_probe_work_func+0x9c/0xf0 process_one_work+0x1d0/0x330 worker_thread+0x68/0x390 kthread+0xec/0xfc ret_from_fork+0x10/0x20 ---[ end trace 0000000000000000 ]---
But given that the PLL did not lock I assume this is not too surprising.
Yes, that's just the fallout of the LCDIF not seeing any pixel clock.
You could aid me in diagnosing this by posting the output of /sys/kernel/debug/clk/clk_summary and /sys/kernel/debug/pm_genpd/pm_genpd_summary when the system is in this failed state.
Regards, Lucas
dri-devel@lists.freedesktop.org