From 08f87f769b595151be1afeff53e144f543faa614 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 06 Dec 2023 09:51:13 +0000 Subject: [PATCH] add dts config --- kernel/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 139 insertions(+), 23 deletions(-) diff --git a/kernel/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/kernel/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 5073622..016b877 100644 --- a/kernel/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/kernel/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -5,11 +5,12 @@ #include <linux/component.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> -#include <drm/drm_of.h> -#include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_simple_kms_helper.h> #include "sun8i_dw_hdmi.h" #include "sun8i_tcon_top.h" @@ -28,15 +29,27 @@ .mode_set = sun8i_dw_hdmi_encoder_mode_set, }; -static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - static enum drm_mode_status -sun8i_dw_hdmi_mode_valid(struct drm_connector *connector, - const struct drm_display_mode *mode) +sun8i_dw_hdmi_mode_valid_a83t(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) { if (mode->clock > 297000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static enum drm_mode_status +sun8i_dw_hdmi_mode_valid_h6(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + /* + * Controller support maximum of 594 MHz, which correlates to + * 4K@60Hz 4:4:4 or RGB. + */ + if (mode->clock > 594000) return MODE_CLOCK_HIGH; return MODE_OK; @@ -80,10 +93,34 @@ return crtcs; } +static int sun8i_dw_hdmi_find_connector_pdev(struct device *dev, + struct platform_device **pdev_out) +{ + struct platform_device *pdev; + struct device_node *remote; + + remote = of_graph_get_remote_node(dev->of_node, 1, -1); + if (!remote) + return -ENODEV; + + if (!of_device_is_compatible(remote, "hdmi-connector")) { + of_node_put(remote); + return -ENODEV; + } + + pdev = of_find_device_by_node(remote); + of_node_put(remote); + if (!pdev) + return -ENODEV; + + *pdev_out = pdev; + return 0; +} + static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = to_platform_device(dev), *connector_pdev; struct dw_hdmi_plat_data *plat_data; struct drm_device *drm = data; struct device_node *phy_node; @@ -101,6 +138,8 @@ plat_data = &hdmi->plat_data; hdmi->dev = &pdev->dev; encoder = &hdmi->encoder; + + hdmi->quirks = of_device_get_match_data(dev); encoder->possible_crtcs = sun8i_dw_hdmi_find_possible_crtcs(drm, dev->of_node); @@ -125,10 +164,36 @@ return PTR_ERR(hdmi->clk_tmds); } + hdmi->regulator = devm_regulator_get(dev, "hvcc"); + if (IS_ERR(hdmi->regulator)) { + dev_err(dev, "Couldn't get regulator\n"); + return PTR_ERR(hdmi->regulator); + } + + ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev); + if (!ret) { + hdmi->ddc_en = gpiod_get_optional(&connector_pdev->dev, + "ddc-en", GPIOD_OUT_HIGH); + platform_device_put(connector_pdev); + + if (IS_ERR(hdmi->ddc_en)) { + dev_err(dev, "Couldn't get ddc-en gpio\n"); + return PTR_ERR(hdmi->ddc_en); + } + } + + ret = regulator_enable(hdmi->regulator); + if (ret) { + dev_err(dev, "Failed to enable regulator\n"); + goto err_unref_ddc_en; + } + + gpiod_set_value(hdmi->ddc_en, 1); + ret = reset_control_deassert(hdmi->rst_ctrl); if (ret) { dev_err(dev, "Could not deassert ctrl reset control\n"); - return ret; + goto err_disable_ddc_en; } ret = clk_prepare_enable(hdmi->clk_tmds); @@ -144,23 +209,23 @@ goto err_disable_clk_tmds; } - ret = sun8i_hdmi_phy_probe(hdmi, phy_node); + ret = sun8i_hdmi_phy_get(hdmi, phy_node); of_node_put(phy_node); if (ret) { dev_err(dev, "Couldn't get the HDMI PHY\n"); goto err_disable_clk_tmds; } + ret = sun8i_hdmi_phy_init(hdmi->phy); + if (ret) + goto err_disable_clk_tmds; + drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs); - drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); + drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); - sun8i_hdmi_phy_init(hdmi->phy); - - plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid; - plat_data->phy_ops = sun8i_hdmi_phy_get_ops(); - plat_data->phy_name = "sun8i_dw_hdmi_phy"; - plat_data->phy_data = hdmi->phy; + plat_data->mode_valid = hdmi->quirks->mode_valid; + plat_data->use_drm_infoframe = hdmi->quirks->use_drm_infoframe; + sun8i_hdmi_phy_set_ops(hdmi->phy, plat_data); platform_set_drvdata(pdev, hdmi); @@ -179,11 +244,16 @@ cleanup_encoder: drm_encoder_cleanup(encoder); - sun8i_hdmi_phy_remove(hdmi); err_disable_clk_tmds: clk_disable_unprepare(hdmi->clk_tmds); err_assert_ctrl_reset: reset_control_assert(hdmi->rst_ctrl); +err_disable_ddc_en: + gpiod_set_value(hdmi->ddc_en, 0); + regulator_disable(hdmi->regulator); +err_unref_ddc_en: + if (hdmi->ddc_en) + gpiod_put(hdmi->ddc_en); return ret; } @@ -194,9 +264,14 @@ struct sun8i_dw_hdmi *hdmi = dev_get_drvdata(dev); dw_hdmi_unbind(hdmi->hdmi); - sun8i_hdmi_phy_remove(hdmi); + sun8i_hdmi_phy_deinit(hdmi->phy); clk_disable_unprepare(hdmi->clk_tmds); reset_control_assert(hdmi->rst_ctrl); + gpiod_set_value(hdmi->ddc_en, 0); + regulator_disable(hdmi->regulator); + + if (hdmi->ddc_en) + gpiod_put(hdmi->ddc_en); } static const struct component_ops sun8i_dw_hdmi_ops = { @@ -216,8 +291,24 @@ return 0; } +static const struct sun8i_dw_hdmi_quirks sun8i_a83t_quirks = { + .mode_valid = sun8i_dw_hdmi_mode_valid_a83t, +}; + +static const struct sun8i_dw_hdmi_quirks sun50i_h6_quirks = { + .mode_valid = sun8i_dw_hdmi_mode_valid_h6, + .use_drm_infoframe = true, +}; + static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = { - { .compatible = "allwinner,sun8i-a83t-dw-hdmi" }, + { + .compatible = "allwinner,sun8i-a83t-dw-hdmi", + .data = &sun8i_a83t_quirks, + }, + { + .compatible = "allwinner,sun50i-h6-dw-hdmi", + .data = &sun50i_h6_quirks, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids); @@ -230,7 +321,32 @@ .of_match_table = sun8i_dw_hdmi_dt_ids, }, }; -module_platform_driver(sun8i_dw_hdmi_pltfm_driver); + +static int __init sun8i_dw_hdmi_init(void) +{ + int ret; + + ret = platform_driver_register(&sun8i_dw_hdmi_pltfm_driver); + if (ret) + return ret; + + ret = platform_driver_register(&sun8i_hdmi_phy_driver); + if (ret) { + platform_driver_unregister(&sun8i_dw_hdmi_pltfm_driver); + return ret; + } + + return ret; +} + +static void __exit sun8i_dw_hdmi_exit(void) +{ + platform_driver_unregister(&sun8i_dw_hdmi_pltfm_driver); + platform_driver_unregister(&sun8i_hdmi_phy_driver); +} + +module_init(sun8i_dw_hdmi_init); +module_exit(sun8i_dw_hdmi_exit); MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>"); MODULE_DESCRIPTION("Allwinner DW HDMI bridge"); -- Gitblit v1.6.2