From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
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