Commit cf6d100d authored by Heiko Stuebner's avatar Heiko Stuebner Committed by Andrzej Hajda
Browse files

drm/rockchip: dsi: add dual mipi support



Add the Rockchip-sepcific dual-dsi setup and hook it into the VOP as well.
As described in the general dual-dsi devicetree binding, the panel should
define two input ports and point each of them to one of the used dsi-
controllers, as well as declare one of them as clock-master.
This is used to determine the dual-dsi state and get access to both
controller instances.

v6:
  handle master+slave component in dsi-attach
v5:
  use driver-internal mechanism to find dual dsi slave
v4:
  add component directly in probe when adding empty dsi slave controller

Signed-off-by: default avatarHeiko Stuebner <heiko@sntech.de>
Reviewed-by: default avatarAndrzej Hajda <a.hajda@samsung.com>
Signed-off-by: default avatarAndrzej Hajda <a.hajda@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181001123845.11818-8-heiko@sntech.de
parent 739838b5
Loading
Loading
Loading
Loading
+137 −0
Original line number Diff line number Diff line
@@ -218,6 +218,10 @@ struct dw_mipi_dsi_rockchip {
	struct clk *grf_clk;
	struct clk *phy_cfg_clk;

	/* dual-channel */
	bool is_slave;
	struct dw_mipi_dsi_rockchip *slave;

	unsigned int lane_mbps; /* per lane */
	u16 input_div;
	u16 feedback_div;
@@ -226,6 +230,7 @@ struct dw_mipi_dsi_rockchip {
	struct dw_mipi_dsi *dmd;
	const struct rockchip_dw_dsi_chip_data *cdata;
	struct dw_mipi_dsi_plat_data pdata;
	int devcnt;
};

struct dphy_pll_parameter_map {
@@ -602,6 +607,8 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
	}

	s->output_type = DRM_MODE_CONNECTOR_DSI;
	if (dsi->slave)
		s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL;

	return 0;
}
@@ -617,6 +624,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
		return;

	pm_runtime_get_sync(dsi->dev);
	if (dsi->slave)
		pm_runtime_get_sync(dsi->slave->dev);

	/*
	 * For the RK3399, the clk of grf must be enabled before writing grf
@@ -630,6 +639,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
	}

	dw_mipi_dsi_rockchip_config(dsi, mux);
	if (dsi->slave)
		dw_mipi_dsi_rockchip_config(dsi->slave, mux);

	clk_disable_unprepare(dsi->grf_clk);
}
@@ -638,6 +649,8 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
{
	struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);

	if (dsi->slave)
		pm_runtime_put(dsi->slave->dev);
	pm_runtime_put(dsi->dev);
}

@@ -673,14 +686,113 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
	return 0;
}

static struct device
*dw_mipi_dsi_rockchip_find_second(struct dw_mipi_dsi_rockchip *dsi)
{
	const struct of_device_id *match;
	struct device_node *node = NULL, *local;

	match = of_match_device(dsi->dev->driver->of_match_table, dsi->dev);

	local = of_graph_get_remote_node(dsi->dev->of_node, 1, 0);
	if (!local)
		return NULL;

	while ((node = of_find_compatible_node(node, NULL,
					       match->compatible))) {
		struct device_node *remote;

		/* found ourself */
		if (node == dsi->dev->of_node)
			continue;

		remote = of_graph_get_remote_node(node, 1, 0);
		if (!remote)
			continue;

		/* same display device in port1-ep0 for both */
		if (remote == local) {
			struct dw_mipi_dsi_rockchip *dsi2;
			struct platform_device *pdev;

			pdev = of_find_device_by_node(node);

			/*
			 * we have found the second, so will either return it
			 * or return with an error. In any case won't need the
			 * nodes anymore nor continue the loop.
			 */
			of_node_put(remote);
			of_node_put(node);
			of_node_put(local);

			if (!pdev)
				return ERR_PTR(-EPROBE_DEFER);

			dsi2 = platform_get_drvdata(pdev);
			if (!dsi2) {
				platform_device_put(pdev);
				return ERR_PTR(-EPROBE_DEFER);
			}

			return &pdev->dev;
		}

		of_node_put(remote);
	}

	of_node_put(local);

	return NULL;
}

static int dw_mipi_dsi_rockchip_bind(struct device *dev,
				     struct device *master,
				     void *data)
{
	struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
	struct drm_device *drm_dev = data;
	struct device *second;
	bool master1, master2;
	int ret;

	second = dw_mipi_dsi_rockchip_find_second(dsi);
	if (IS_ERR(second))
		return PTR_ERR(second);

	if (second) {
		master1 = of_property_read_bool(dsi->dev->of_node,
						"clock-master");
		master2 = of_property_read_bool(second->of_node,
						"clock-master");

		if (master1 && master2) {
			DRM_DEV_ERROR(dsi->dev, "only one clock-master allowed\n");
			return -EINVAL;
		}

		if (!master1 && !master2) {
			DRM_DEV_ERROR(dsi->dev, "no clock-master defined\n");
			return -EINVAL;
		}

		/* we are the slave in dual-DSI */
		if (!master1) {
			dsi->is_slave = true;
			return 0;
		}

		dsi->slave = dev_get_drvdata(second);
		if (!dsi->slave) {
			DRM_DEV_ERROR(dev, "could not get slaves data\n");
			return -ENODEV;
		}

		dsi->slave->is_slave = true;
		dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd);
		put_device(second);
	}

	ret = clk_prepare_enable(dsi->pllref_clk);
	if (ret) {
		DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
@@ -708,6 +820,9 @@ static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
{
	struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);

	if (dsi->is_slave)
		return;

	dw_mipi_dsi_unbind(dsi->dmd);

	clk_disable_unprepare(dsi->pllref_clk);
@@ -722,6 +837,7 @@ static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
					    struct mipi_dsi_device *device)
{
	struct dw_mipi_dsi_rockchip *dsi = priv_data;
	struct device *second;
	int ret;

	ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops);
@@ -731,6 +847,19 @@ static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
		return ret;
	}

	second = dw_mipi_dsi_rockchip_find_second(dsi);
	if (IS_ERR(second))
		return PTR_ERR(second);
	if (second) {
		ret = component_add(second, &dw_mipi_dsi_rockchip_ops);
		if (ret) {
			DRM_DEV_ERROR(second,
				      "Failed to register component: %d\n",
				      ret);
			return ret;
		}
	}

	return 0;
}

@@ -738,6 +867,11 @@ static int dw_mipi_dsi_rockchip_host_detach(void *priv_data,
					    struct mipi_dsi_device *device)
{
	struct dw_mipi_dsi_rockchip *dsi = priv_data;
	struct device *second;

	second = dw_mipi_dsi_rockchip_find_second(dsi);
	if (second && !IS_ERR(second))
		component_del(second, &dw_mipi_dsi_rockchip_ops);

	component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);

@@ -846,6 +980,9 @@ static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
{
	struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);

	if (dsi->devcnt == 0)
		component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);

	dw_mipi_dsi_remove(dsi->dmd);

	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ struct rockchip_crtc_state {
	int output_type;
	int output_mode;
	int output_bpc;
	int output_flags;
};
#define to_rockchip_crtc_state(s) \
		container_of(s, struct rockchip_crtc_state, base)
+3 −0
Original line number Diff line number Diff line
@@ -916,6 +916,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
		   BIT(VSYNC_POSITIVE) : 0;
	VOP_REG_SET(vop, output, pin_pol, pin_pol);
	VOP_REG_SET(vop, output, mipi_dual_channel_en, 0);

	switch (s->output_type) {
	case DRM_MODE_CONNECTOR_LVDS:
@@ -933,6 +934,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
	case DRM_MODE_CONNECTOR_DSI:
		VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
		VOP_REG_SET(vop, output, mipi_en, 1);
		VOP_REG_SET(vop, output, mipi_dual_channel_en,
			    !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL));
		break;
	case DRM_MODE_CONNECTOR_DisplayPort:
		pin_pol &= ~BIT(DCLK_INVERT);
+4 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ struct vop_output {
	struct vop_reg edp_en;
	struct vop_reg hdmi_en;
	struct vop_reg mipi_en;
	struct vop_reg mipi_dual_channel_en;
	struct vop_reg rgb_en;
};

@@ -214,6 +215,9 @@ struct vop_data {
/* for use special outface */
#define ROCKCHIP_OUT_MODE_AAAA	15

/* output flags */
#define ROCKCHIP_OUTPUT_DSI_DUAL	BIT(0)

enum alpha_mode {
	ALPHA_STRAIGHT,
	ALPHA_INVERSE,
+1 −0
Original line number Diff line number Diff line
@@ -634,6 +634,7 @@ static const struct vop_output rk3399_output = {
	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
	.mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
};

static const struct vop_data rk3399_vop_big = {