Commit d68ba7ba authored by Andy Yan's avatar Andy Yan Committed by Dmitry Baryshkov
Browse files

drm/rockchip: Add RK3588 DPTX output support



Add driver extension for Synopsys DesignWare DPTX IP used
on Rockchip RK3588 SoC.

Signed-off-by: default avatarAndy Yan <andy.yan@rock-chips.com>
Acked-by: default avatarDmitry Baryshkov <lumag@kernel.org>
Tested-by: default avatarNicolas Frattaroli <nicolas.frattaroli@collabora.com>
Reviewed-by: default avatarHeiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20250822063959.692098-4-andyshrk@163.com


Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
parent 86eecc3a
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ config DRM_ROCKCHIP
	select VIDEOMODE_HELPERS
	select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP
	select DRM_DISPLAY_DP_AUX_BUS if ROCKCHIP_ANALOGIX_DP
	select DRM_DW_DP if ROCKCHIP_DW_DP
	select DRM_DW_HDMI if ROCKCHIP_DW_HDMI
	select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP
	select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI
@@ -60,6 +61,14 @@ config ROCKCHIP_CDN_DP
	  RK3399 based SoC, you should select this
	  option.

config ROCKCHIP_DW_DP
	bool "Rockchip specific extensions for Synopsys DW DP"
	help
	  This selects support for Rockchip SoC specific extensions
	  to enable Synopsys DesignWare Cores based DisplayPort transmit
	  controller support on Rockchip SoC, If you want to enable DP on
	  rk3588 based SoC, you should select this option.

config ROCKCHIP_DW_HDMI
	bool "Rockchip specific extensions for Synopsys DW HDMI"
	help
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) += dw_hdmi_qp-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) += dw-mipi-dsi2-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_DW_DP) += dw_dp-rockchip.o
rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o
+150 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
 *
 * Author: Zhang Yubing <yubing.zhang@rock-chips.com>
 * Author: Andy Yan <andy.yan@rock-chips.com>
 */

#include <linux/component.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <drm/bridge/dw_dp.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>

#include <linux/media-bus-format.h>
#include <linux/videodev2.h>

#include "rockchip_drm_drv.h"
#include "rockchip_drm_vop.h"

struct rockchip_dw_dp {
	struct dw_dp *base;
	struct device *dev;
	struct rockchip_encoder encoder;
};

static int dw_dp_encoder_atomic_check(struct drm_encoder *encoder,
				      struct drm_crtc_state *crtc_state,
				      struct drm_connector_state *conn_state)
{
	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
	struct drm_atomic_state *state = conn_state->state;
	struct drm_display_info *di = &conn_state->connector->display_info;
	struct drm_bridge *bridge  = drm_bridge_chain_get_first_bridge(encoder);
	struct drm_bridge_state *bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
	u32 bus_format = bridge_state->input_bus_cfg.format;

	switch (bus_format) {
	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
		s->output_mode = ROCKCHIP_OUT_MODE_YUV420;
		break;
	case MEDIA_BUS_FMT_YUYV10_1X20:
	case MEDIA_BUS_FMT_YUYV8_1X16:
		s->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY;
		break;
	case MEDIA_BUS_FMT_RGB101010_1X30:
	case MEDIA_BUS_FMT_RGB888_1X24:
	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
	case MEDIA_BUS_FMT_YUV10_1X30:
	case MEDIA_BUS_FMT_YUV8_1X24:
	default:
		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
		break;
	}

	s->output_type = DRM_MODE_CONNECTOR_DisplayPort;
	s->bus_format = bus_format;
	s->bus_flags = di->bus_flags;
	s->color_space = V4L2_COLORSPACE_DEFAULT;

	return 0;
}

static const struct drm_encoder_helper_funcs dw_dp_encoder_helper_funcs = {
	.atomic_check		= dw_dp_encoder_atomic_check,
};

static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *data)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct dw_dp_plat_data plat_data;
	struct drm_device *drm_dev = data;
	struct rockchip_dw_dp *dp;
	struct drm_encoder *encoder;
	struct drm_connector *connector;
	int ret;

	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
	if (!dp)
		return -ENOMEM;

	dp->dev = dev;
	platform_set_drvdata(pdev, dp);

	plat_data.max_link_rate = 810000;
	encoder = &dp->encoder.encoder;
	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
	rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder, dev->of_node, 0, 0);

	ret = drmm_encoder_init(drm_dev, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
	if (ret)
		return ret;
	drm_encoder_helper_add(encoder, &dw_dp_encoder_helper_funcs);

	dp->base = dw_dp_bind(dev, encoder, &plat_data);
	if (IS_ERR(dp->base)) {
		ret = PTR_ERR(dp->base);
		return ret;
	}

	connector = drm_bridge_connector_init(drm_dev, encoder);
	if (IS_ERR(connector)) {
		ret = PTR_ERR(connector);
		return dev_err_probe(dev, ret, "Failed to init bridge connector");
	}

	drm_connector_attach_encoder(connector, encoder);

	return 0;
}

static const struct component_ops dw_dp_rockchip_component_ops = {
	.bind = dw_dp_rockchip_bind,
};

static int dw_dp_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;

	return component_add(dev, &dw_dp_rockchip_component_ops);
}

static void dw_dp_remove(struct platform_device *pdev)
{
	struct rockchip_dw_dp *dp = platform_get_drvdata(pdev);

	component_del(dp->dev, &dw_dp_rockchip_component_ops);
}

static const struct of_device_id dw_dp_of_match[] = {
	{ .compatible = "rockchip,rk3588-dp", },
	{}
};
MODULE_DEVICE_TABLE(of, dw_dp_of_match);

struct platform_driver dw_dp_driver = {
	.probe	= dw_dp_probe,
	.remove = dw_dp_remove,
	.driver = {
		.name = "dw-dp",
		.of_match_table = dw_dp_of_match,
	},
};
+1 −0
Original line number Diff line number Diff line
@@ -529,6 +529,7 @@ static int __init rockchip_drm_init(void)
	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
				CONFIG_ROCKCHIP_ANALOGIX_DP);
	ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
	ADD_ROCKCHIP_SUB_DRIVER(dw_dp_driver, CONFIG_ROCKCHIP_DW_DP);
	ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
				CONFIG_ROCKCHIP_DW_HDMI);
	ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver,
+1 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ int rockchip_drm_encoder_set_crtc_endpoint_id(struct rockchip_encoder *rencoder,
					      struct device_node *np, int port, int reg);
int rockchip_drm_endpoint_is_subdriver(struct device_node *ep);
extern struct platform_driver cdn_dp_driver;
extern struct platform_driver dw_dp_driver;
extern struct platform_driver dw_hdmi_rockchip_pltfm_driver;
extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver;
extern struct platform_driver dw_mipi_dsi_rockchip_driver;