aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c')
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c108
1 files changed, 90 insertions, 18 deletions
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 8677c8271678..c14f88893868 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <drm/bridge/dw_hdmi.h>
#include <drm/drm_edid.h>
@@ -50,6 +51,10 @@
#define RK3399_GRF_SOC_CON20 0x6250
#define RK3399_HDMI_LCDC_SEL BIT(6)
+#define RK3568_GRF_VO_CON1 0x0364
+#define RK3568_HDMI_SDAIN_MSK BIT(15)
+#define RK3568_HDMI_SCLIN_MSK BIT(14)
+
#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
/**
@@ -67,15 +72,22 @@ struct rockchip_hdmi_chip_data {
struct rockchip_hdmi {
struct device *dev;
struct regmap *regmap;
- struct drm_encoder encoder;
+ struct rockchip_encoder encoder;
const struct rockchip_hdmi_chip_data *chip_data;
- struct clk *vpll_clk;
+ struct clk *ref_clk;
struct clk *grf_clk;
struct dw_hdmi *hdmi;
+ struct regulator *avdd_0v9;
+ struct regulator *avdd_1v8;
struct phy *phy;
};
-#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
+{
+ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
+
+ return container_of(rkencoder, struct rockchip_hdmi, encoder);
+}
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
{
@@ -196,14 +208,15 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
return PTR_ERR(hdmi->regmap);
}
- hdmi->vpll_clk = devm_clk_get(hdmi->dev, "vpll");
- if (PTR_ERR(hdmi->vpll_clk) == -ENOENT) {
- hdmi->vpll_clk = NULL;
- } else if (PTR_ERR(hdmi->vpll_clk) == -EPROBE_DEFER) {
+ hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "ref");
+ if (!hdmi->ref_clk)
+ hdmi->ref_clk = devm_clk_get_optional(hdmi->dev, "vpll");
+
+ if (PTR_ERR(hdmi->ref_clk) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
- } else if (IS_ERR(hdmi->vpll_clk)) {
- DRM_DEV_ERROR(hdmi->dev, "failed to get vpll clock\n");
- return PTR_ERR(hdmi->vpll_clk);
+ } else if (IS_ERR(hdmi->ref_clk)) {
+ DRM_DEV_ERROR(hdmi->dev, "failed to get reference clock\n");
+ return PTR_ERR(hdmi->ref_clk);
}
hdmi->grf_clk = devm_clk_get(hdmi->dev, "grf");
@@ -216,6 +229,14 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
return PTR_ERR(hdmi->grf_clk);
}
+ hdmi->avdd_0v9 = devm_regulator_get(hdmi->dev, "avdd-0v9");
+ if (IS_ERR(hdmi->avdd_0v9))
+ return PTR_ERR(hdmi->avdd_0v9);
+
+ hdmi->avdd_1v8 = devm_regulator_get(hdmi->dev, "avdd-1v8");
+ if (IS_ERR(hdmi->avdd_1v8))
+ return PTR_ERR(hdmi->avdd_1v8);
+
return 0;
}
@@ -257,7 +278,7 @@ static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
{
struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
- clk_set_rate(hdmi->vpll_clk, adj_mode->clock * 1000);
+ clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
}
static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
@@ -467,6 +488,19 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
.use_drm_infoframe = true,
};
+static struct rockchip_hdmi_chip_data rk3568_chip_data = {
+ .lcdsel_grf_reg = -1,
+};
+
+static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = {
+ .mode_valid = dw_hdmi_rockchip_mode_valid,
+ .mpll_cfg = rockchip_mpll_cfg,
+ .cur_ctr = rockchip_cur_ctr,
+ .phy_config = rockchip_phy_config,
+ .phy_data = &rk3568_chip_data,
+ .use_drm_infoframe = true,
+};
+
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
{ .compatible = "rockchip,rk3228-dw-hdmi",
.data = &rk3228_hdmi_drv_data
@@ -480,6 +514,9 @@ static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
{ .compatible = "rockchip,rk3399-dw-hdmi",
.data = &rk3399_hdmi_drv_data
},
+ { .compatible = "rockchip,rk3568-dw-hdmi",
+ .data = &rk3568_hdmi_drv_data
+ },
{},
};
MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
@@ -511,9 +548,12 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
hdmi->chip_data = plat_data->phy_data;
plat_data->phy_data = hdmi;
- encoder = &hdmi->encoder;
+ encoder = &hdmi->encoder.encoder;
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder,
+ dev->of_node, 0, 0);
+
/*
* If we failed to find the CRTC(s) which this encoder is
* supposed to be connected to, it's because the CRTC has
@@ -537,11 +577,31 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
return ret;
}
- ret = clk_prepare_enable(hdmi->vpll_clk);
+ ret = regulator_enable(hdmi->avdd_0v9);
+ if (ret) {
+ DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd0v9: %d\n", ret);
+ goto err_avdd_0v9;
+ }
+
+ ret = regulator_enable(hdmi->avdd_1v8);
if (ret) {
- DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI vpll: %d\n",
+ DRM_DEV_ERROR(hdmi->dev, "failed to enable avdd1v8: %d\n", ret);
+ goto err_avdd_1v8;
+ }
+
+ ret = clk_prepare_enable(hdmi->ref_clk);
+ if (ret) {
+ DRM_DEV_ERROR(hdmi->dev, "Failed to enable HDMI reference clock: %d\n",
ret);
- return ret;
+ goto err_clk;
+ }
+
+ if (hdmi->chip_data == &rk3568_chip_data) {
+ regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1,
+ HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK |
+ RK3568_HDMI_SCLIN_MSK,
+ RK3568_HDMI_SDAIN_MSK |
+ RK3568_HDMI_SCLIN_MSK));
}
drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
@@ -557,10 +617,19 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
*/
if (IS_ERR(hdmi->hdmi)) {
ret = PTR_ERR(hdmi->hdmi);
- drm_encoder_cleanup(encoder);
- clk_disable_unprepare(hdmi->vpll_clk);
+ goto err_bind;
}
+ return 0;
+
+err_bind:
+ drm_encoder_cleanup(encoder);
+ clk_disable_unprepare(hdmi->ref_clk);
+err_clk:
+ regulator_disable(hdmi->avdd_1v8);
+err_avdd_1v8:
+ regulator_disable(hdmi->avdd_0v9);
+err_avdd_0v9:
return ret;
}
@@ -570,7 +639,10 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
dw_hdmi_unbind(hdmi->hdmi);
- clk_disable_unprepare(hdmi->vpll_clk);
+ clk_disable_unprepare(hdmi->ref_clk);
+
+ regulator_disable(hdmi->avdd_1v8);
+ regulator_disable(hdmi->avdd_0v9);
}
static const struct component_ops dw_hdmi_rockchip_ops = {