Skip to contentSkip to conversation

Initial support for Cadence MHDP(HDMI/DP)

PATCH In review [email protected] 3 participants 15 messages Jun 1, 2020 – Jun 4, 2020

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

cover Initial support for Cadence MHDP(HDMI/DP)

From: Sandor Yu <[email protected]>

The patch set initial support for Cadence MHDP(HDMI/DP) drm bridge driver and iMX8MQ HDMI/DP.

The first patch drm/rockchip: prepare common code for cdns and rk dpi/dp driver is from the link https://patchwork.kernel.org/patch/10788309/
that still in reviewing.

Files in drm/bridge/cadence compose with serveral parties, drm bridge driver, Audio and API functions.
-cdns-dp-core.c: Displayport bridge driver -cdns-hdmi-core.c: HDMI bridge driver -cdns-mhdp-audio.c: DP/HDMI Audio -cdns-mhdp-common.c: MHDP common API functions -cdns-mhdp-dp.c: MHDP DP API functions -cdns-mhdp-hdmi.c: MHDP HDMI API functions

Sandor Yu (7):
drm/rockchip: prepare common code for cdns and rk dpi/dp driver
drm: bridge: cadence: Create cadence fold
drm: bridge: cadence: initial support for MHDP DP bridge driver
drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport
drm: bridge: cadence: Initial support for MHDP HDMI bridge driver
drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI
dt-bindings: display: Document Cadence MHDP HDMI/DP bindings

 .../bindings/display/bridge/cdns,mhdp.yaml    |  46 +
 .../devicetree/bindings/display/imx/mhdp.yaml |  59 ++
 drivers/gpu/drm/bridge/Kconfig                |   2 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/cadence/Kconfig        |  15 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   5 +
 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530 ++++++++++
 .../gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 600 +++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 298 ++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.c | 682 +++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |  40 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c | 206 ++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   | 330 ++++++
 drivers/gpu/drm/imx/Kconfig                   |   1 +
 drivers/gpu/drm/imx/Makefile                  |   1 +
 drivers/gpu/drm/imx/mhdp/Kconfig              |   9 +
 drivers/gpu/drm/imx/mhdp/Makefile             |   4 +
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c   | 390 +++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 588 +++++++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c   | 142 +++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h      | 148 +++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/Makefile             |   2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        | 247 ++---
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |  44 +-
 drivers/gpu/drm/rockchip/cdn-dp-reg.c         | 960 ------------------
 .../drm/bridge/cdns-mhdp.h                    | 257 ++++-
 27 files changed, 4464 insertions(+), 1144 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/mhdp.yaml
 create mode 100644 drivers/gpu/drm/bridge/cadence/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/cadence/Makefile
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/Kconfig
 create mode 100644 drivers/gpu/drm/imx/mhdp/Makefile
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
 delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 rename drivers/gpu/drm/rockchip/cdn-dp-reg.h => include/drm/bridge/cdns-mhdp.h (64%)
Signature · 1 line
2.17.1
#1 lore raw

PATCH 1/7 drm/rockchip: prepare common code for cdns and rk dpi/dp driver

From: Sandor Yu <[email protected]>

- Extracted common fields from cdn_dp_device to a new cdns_mhdp_device structure which will be used by two separate drivers later on.
- Moved some datatypes (audio_format, audio_info, vic_pxl_encoding_format, video_info) from cdn-dp-core.c to cdn-dp-reg.h.
- Changed prefixes from cdn_dp to cdns_mhdp
cdn -> cdns to match the other Cadence's drivers
dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
this registers map can be a HDMI (which is internally different, but the interface for commands, events is pretty much the same).
- Modified cdn-dp-core.c to use the new driver structure and new function names.
- writel and readl are replaced by cdns_mhdp_bus_write and cdns_mhdp_bus_read.

---
 drivers/gpu/drm/rockchip/cdn-dp-core.c | 240 ++++++------
 drivers/gpu/drm/rockchip/cdn-dp-core.h |  44 +--
 drivers/gpu/drm/rockchip/cdn-dp-reg.c  | 488 +++++++++++++------------
 drivers/gpu/drm/rockchip/cdn-dp-reg.h  | 133 +++++--
 4 files changed, 483 insertions(+), 422 deletions(-)
drivers/gpu/drm/rockchip/cdn-dp-core.c +128 -112
index eed594bd38d3..b6aa21779608 100644
@@ -26,7 +26,7 @@
 #include "rockchip_drm_vop.h"
 
 #define connector_to_dp(c) \
-		container_of(c, struct cdn_dp_device, connector)
+		container_of(c, struct cdn_dp_device, mhdp.connector.base)
 
 #define encoder_to_dp(c) \
 		container_of(c, struct cdn_dp_device, encoder)
@@ -61,17 +61,18 @@ MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids);
 static int cdn_dp_grf_write(struct cdn_dp_device *dp,
 			    unsigned int reg, unsigned int val)
 {
+	struct device *dev = dp->mhdp.dev;
 	int ret;
 
 	ret = clk_prepare_enable(dp->grf_clk);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n");
+		DRM_DEV_ERROR(dev, "Failed to prepare_enable grf clock\n");
 		return ret;
 	}
 
 	ret = regmap_write(dp->grf, reg, val);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
+		DRM_DEV_ERROR(dev, "Could not write to GRF: %d\n", ret);
 		return ret;
 	}
 
@@ -82,24 +83,25 @@ static int cdn_dp_grf_write(struct cdn_dp_device *dp,
 
 static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
 {
+	struct device *dev = dp->mhdp.dev;
 	int ret;
 	unsigned long rate;
 
 	ret = clk_prepare_enable(dp->pclk);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret);
+		DRM_DEV_ERROR(dev, "cannot enable dp pclk %d\n", ret);
 		goto err_pclk;
 	}
 
 	ret = clk_prepare_enable(dp->core_clk);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret);
+		DRM_DEV_ERROR(dev, "cannot enable core_clk %d\n", ret);
 		goto err_core_clk;
 	}
 
-	ret = pm_runtime_get_sync(dp->dev);
+	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret);
+		DRM_DEV_ERROR(dev, "cannot get pm runtime %d\n", ret);
 		goto err_pm_runtime_get;
 	}
 
@@ -112,18 +114,18 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
 
 	rate = clk_get_rate(dp->core_clk);
 	if (!rate) {
-		DRM_DEV_ERROR(dp->dev, "get clk rate failed\n");
+		DRM_DEV_ERROR(dev, "get clk rate failed\n");
 		ret = -EINVAL;
 		goto err_set_rate;
 	}
 
-	cdn_dp_set_fw_clk(dp, rate);
-	cdn_dp_clock_reset(dp);
+	cdns_mhdp_set_fw_clk(&dp->mhdp, rate);
+	cdns_mhdp_clock_reset(&dp->mhdp);
 
 	return 0;
 
 err_set_rate:
-	pm_runtime_put(dp->dev);
+	pm_runtime_put(dev);
 err_pm_runtime_get:
 	clk_disable_unprepare(dp->core_clk);
 err_core_clk:
@@ -134,7 +136,7 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
 
 static void cdn_dp_clk_disable(struct cdn_dp_device *dp)
 {
-	pm_runtime_put_sync(dp->dev);
+	pm_runtime_put_sync(dp->mhdp.dev);
 	clk_disable_unprepare(dp->pclk);
 	clk_disable_unprepare(dp->core_clk);
 }
@@ -167,7 +169,7 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count)
 	u8 value;
 
 	*sink_count = 0;
-	ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1);
+	ret = drm_dp_dpcd_read(&dp->mhdp.dp.aux, DP_SINK_COUNT, &value, 1);
 	if (ret)
 		return ret;
 
@@ -191,12 +193,13 @@ static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp)
 
 static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
 {
+	struct device *dev = dp->mhdp.dev;
 	unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS);
 	struct cdn_dp_port *port;
 	u8 sink_count = 0;
 
 	if (dp->active_port < 0 || dp->active_port >= dp->ports) {
-		DRM_DEV_ERROR(dp->dev, "active_port is wrong!\n");
+		DRM_DEV_ERROR(dev, "active_port is wrong!\n");
 		return false;
 	}
 
@@ -218,7 +221,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
 		usleep_range(5000, 10000);
 	}
 
-	DRM_DEV_ERROR(dp->dev, "Get sink capability timed out\n");
+	DRM_DEV_ERROR(dev, "Get sink capability timed out\n");
 	return false;
 }
 
@@ -260,7 +263,8 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector)
 	mutex_lock(&dp->lock);
 	edid = dp->edid;
 	if (edid) {
-		DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n",
+		DRM_DEV_DEBUG_KMS(dp->mhdp.dev,
+				  "got edid: width[%d] x height[%d]\n",
 				  edid->width_cm, edid->height_cm);
 
 		dp->sink_has_audio = drm_detect_monitor_audio(edid);
@@ -278,7 +282,8 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
 				       struct drm_display_mode *mode)
 {
 	struct cdn_dp_device *dp = connector_to_dp(connector);
-	struct drm_display_info *display_info = &dp->connector.display_info;
+	struct drm_display_info *display_info =
+		&dp->mhdp.connector.base.display_info;
 	u32 requested, actual, rate, sink_max, source_max = 0;
 	u8 lanes, bpc;
 
@@ -301,11 +306,11 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
 	requested = mode->clock * bpc * 3 / 1000;
 
 	source_max = dp->lanes;
-	sink_max = drm_dp_max_lane_count(dp->dpcd);
+	sink_max = drm_dp_max_lane_count(dp->mhdp.dp.dpcd);
 	lanes = min(source_max, sink_max);
 
-	source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE);
-	sink_max = drm_dp_max_link_rate(dp->dpcd);
+	source_max = CDNS_DP_MAX_LINK_RATE;
+	sink_max = drm_dp_max_link_rate(dp->mhdp.dp.dpcd);
 	rate = min(source_max, sink_max);
 
 	actual = rate * lanes / 100;
@@ -314,7 +319,7 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
 	actual = actual * 8 / 10;
 
 	if (requested > actual) {
-		DRM_DEV_DEBUG_KMS(dp->dev,
+		DRM_DEV_DEBUG_KMS(dp->mhdp.dev,
 				  "requested=%d, actual=%d, clock=%d\n",
 				  requested, actual, mode->clock);
 		return MODE_CLOCK_HIGH;
@@ -334,59 +339,62 @@ static int cdn_dp_firmware_init(struct cdn_dp_device *dp)
 	const u32 *iram_data, *dram_data;
 	const struct firmware *fw = dp->fw;
 	const struct cdn_firmware_header *hdr;
+	struct device *dev = dp->mhdp.dev;
 
 	hdr = (struct cdn_firmware_header *)fw->data;
 	if (fw->size != le32_to_cpu(hdr->size_bytes)) {
-		DRM_DEV_ERROR(dp->dev, "firmware is invalid\n");
+		DRM_DEV_ERROR(dev, "firmware is invalid\n");
 		return -EINVAL;
 	}
 
 	iram_data = (const u32 *)(fw->data + hdr->header_size);
 	dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size);
 
-	ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size,
-				   dram_data, hdr->dram_size);
+	ret = cdns_mhdp_load_firmware(&dp->mhdp, iram_data, hdr->iram_size,
+				      dram_data, hdr->dram_size);
 	if (ret)
 		return ret;
 
-	ret = cdn_dp_set_firmware_active(dp, true);
+	ret = cdns_mhdp_set_firmware_active(&dp->mhdp, true);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret);
+		DRM_DEV_ERROR(dev, "active ucpu failed: %d\n", ret);
 		return ret;
 	}
 
-	return cdn_dp_event_config(dp);
+	return cdns_mhdp_event_config(&dp->mhdp);
 }
 
 static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
 {
+	struct cdns_mhdp_device *mhdp = &dp->mhdp;
 	int ret;
 
 	if (!cdn_dp_check_sink_connection(dp))
 		return -ENODEV;
 
-	ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd,
+	ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd,
 			       DP_RECEIVER_CAP_SIZE);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "Failed to get caps %d\n", ret);
 		return ret;
 	}
 
 	kfree(dp->edid);
-	dp->edid = drm_do_get_edid(&dp->connector,
-				   cdn_dp_get_edid_block, dp);
+	dp->edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_mhdp_get_edid_block, mhdp);
 	return 0;
 }
 
 static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 {
+	struct device *dev = dp->mhdp.dev;
 	union extcon_property_value property;
 	int ret;
 
 	if (!port->phy_enabled) {
 		ret = phy_power_on(port->phy);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n",
+			DRM_DEV_ERROR(dev, "phy power on failed: %d\n",
 				      ret);
 			goto err_phy;
 		}
@@ -396,28 +404,28 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 	ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
 			       DPTX_HPD_SEL_MASK | DPTX_HPD_SEL);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to write HPD_SEL %d\n", ret);
 		goto err_power_on;
 	}
 
-	ret = cdn_dp_get_hpd_status(dp);
+	ret = cdns_mhdp_read_hpd(&dp->mhdp);
 	if (ret <= 0) {
 		if (!ret)
-			DRM_DEV_ERROR(dp->dev, "hpd does not exist\n");
+			DRM_DEV_ERROR(dev, "hpd does not exist\n");
 		goto err_power_on;
 	}
 
 	ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
 				  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "get property failed\n");
+		DRM_DEV_ERROR(dev, "get property failed\n");
 		goto err_power_on;
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
-	ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval);
+	ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n",
+		DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
 			      ret);
 		goto err_power_on;
 	}
@@ -427,7 +435,7 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 
 err_power_on:
 	if (phy_power_off(port->phy))
-		DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret);
+		DRM_DEV_ERROR(dev, "phy power off failed: %d", ret);
 	else
 		port->phy_enabled = false;
 
@@ -445,7 +453,8 @@ static int cdn_dp_disable_phy(struct cdn_dp_device *dp,
 	if (port->phy_enabled) {
 		ret = phy_power_off(port->phy);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret);
+			DRM_DEV_ERROR(dp->mhdp.dev,
+				      "phy power off failed: %d", ret);
 			return ret;
 		}
 	}
@@ -469,16 +478,16 @@ static int cdn_dp_disable(struct cdn_dp_device *dp)
 	ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
 			       DPTX_HPD_SEL_MASK | DPTX_HPD_DEL);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n",
+		DRM_DEV_ERROR(dp->mhdp.dev, "Failed to clear hpd sel %d\n",
 			      ret);
 		return ret;
 	}
 
-	cdn_dp_set_firmware_active(dp, false);
+	cdns_mhdp_set_firmware_active(&dp->mhdp, false);
 	cdn_dp_clk_disable(dp);
 	dp->active = false;
-	dp->max_lanes = 0;
-	dp->max_rate = 0;
+	dp->mhdp.dp.rate = 0;
+	dp->mhdp.dp.num_lanes = 0;
 	if (!dp->connected) {
 		kfree(dp->edid);
 		dp->edid = NULL;
@@ -491,11 +500,11 @@ static int cdn_dp_enable(struct cdn_dp_device *dp)
 {
 	int ret, i, lanes;
 	struct cdn_dp_port *port;
+	struct device *dev = dp->mhdp.dev;
 
 	port = cdn_dp_connected_port(dp);
 	if (!port) {
-		DRM_DEV_ERROR(dp->dev,
-			      "Can't enable without connection\n");
+		DRM_DEV_ERROR(dev, "Can't enable without connection\n");
 		return -ENODEV;
 	}
 
@@ -508,7 +517,7 @@ static int cdn_dp_enable(struct cdn_dp_device *dp)
 
 	ret = cdn_dp_firmware_init(dp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret);
+		DRM_DEV_ERROR(dp->mhdp.dev, "firmware init failed: %d", ret);
 		goto err_clk_disable;
 	}
 
@@ -542,8 +551,9 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
 				    struct drm_display_mode *adjusted)
 {
 	struct cdn_dp_device *dp = encoder_to_dp(encoder);
-	struct drm_display_info *display_info = &dp->connector.display_info;
-	struct video_info *video = &dp->video_info;
+	struct drm_display_info *display_info =
+		&dp->mhdp.connector.base.display_info;
+	struct video_info *video = &dp->mhdp.video_info;
 
 	switch (display_info->bpc) {
 	case 10:
@@ -561,20 +571,20 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
 	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
 	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
 
-	memcpy(&dp->mode, adjusted, sizeof(*mode));
+	memcpy(&dp->mhdp.mode, adjusted, sizeof(*mode));
 }
 
 static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
 {
 	u8 link_status[DP_LINK_STATUS_SIZE];
 	struct cdn_dp_port *port = cdn_dp_connected_port(dp);
-	u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd);
+	u8 sink_lanes = drm_dp_max_lane_count(dp->mhdp.dp.dpcd);
 
-	if (!port || !dp->max_rate || !dp->max_lanes)
+	if (!port || !dp->mhdp.dp.rate || !dp->mhdp.dp.num_lanes)
 		return false;
 
-	if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status,
-			     DP_LINK_STATUS_SIZE)) {
+	if (drm_dp_dpcd_read(&dp->mhdp.dp.aux, DP_LANE0_1_STATUS, link_status,
+				DP_LINK_STATUS_SIZE)) {
 		DRM_ERROR("Failed to get link status\n");
 		return false;
 	}
@@ -586,15 +596,16 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
 static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
 {
 	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+	struct device *dev = dp->mhdp.dev;
 	int ret, val;
 
-	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
+	ret = drm_of_encoder_active_endpoint_id(dev->of_node, encoder);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
+		DRM_DEV_ERROR(dev, "Could not get vop id, %d", ret);
 		return;
 	}
 
-	DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
+	DRM_DEV_DEBUG_KMS(dev, "vop %s output to cdn-dp\n",
 			  (ret) ? "LIT" : "BIG");
 	if (ret)
 		val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
@@ -609,33 +620,33 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
 
 	ret = cdn_dp_enable(dp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n",
+		DRM_DEV_ERROR(dev, "Failed to enable encoder %d\n",
 			      ret);
 		goto out;
 	}
 	if (!cdn_dp_check_link_status(dp)) {
-		ret = cdn_dp_train_link(dp);
+		ret = cdns_mhdp_train_link(&dp->mhdp);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "Failed link train %d\n", ret);
+			DRM_DEV_ERROR(dev, "Failed link train %d\n", ret);
 			goto out;
 		}
 	}
 
-	ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+	ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_IDLE);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to idle video %d\n", ret);
 		goto out;
 	}
 
-	ret = cdn_dp_config_video(dp);
+	ret = cdns_mhdp_config_video(&dp->mhdp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to config video %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to config video %d\n", ret);
 		goto out;
 	}
 
-	ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
+	ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_VALID);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to valid video %d\n", ret);
 		goto out;
 	}
 out:
@@ -651,7 +662,8 @@ static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
 	if (dp->active) {
 		ret = cdn_dp_disable(dp);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n",
+			DRM_DEV_ERROR(dp->mhdp.dev,
+				      "Failed to disable encoder %d\n",
 				      ret);
 		}
 	}
@@ -695,7 +707,7 @@ static const struct drm_encoder_funcs cdn_dp_encoder_funcs = {
 
 static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 {
-	struct device *dev = dp->dev;
+	struct device *dev = dp->mhdp.dev;
 	struct device_node *np = dev->of_node;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *res;
@@ -707,10 +719,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	dp->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(dp->regs)) {
+	dp->mhdp.regs_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dp->mhdp.regs_base)) {
 		DRM_DEV_ERROR(dev, "ioremap reg failed\n");
-		return PTR_ERR(dp->regs);
+		return PTR_ERR(dp->mhdp.regs_base);
 	}
 
 	dp->core_clk = devm_clk_get(dev, "core-clk");
@@ -725,10 +737,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 		return PTR_ERR(dp->pclk);
 	}
 
-	dp->spdif_clk = devm_clk_get(dev, "spdif");
-	if (IS_ERR(dp->spdif_clk)) {
+	dp->mhdp.spdif_clk = devm_clk_get(dev, "spdif");
+	if (IS_ERR(dp->mhdp.spdif_clk)) {
 		DRM_DEV_ERROR(dev, "cannot get spdif_clk\n");
-		return PTR_ERR(dp->spdif_clk);
+		return PTR_ERR(dp->mhdp.spdif_clk);
 	}
 
 	dp->grf_clk = devm_clk_get(dev, "grf");
@@ -737,10 +749,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 		return PTR_ERR(dp->grf_clk);
 	}
 
-	dp->spdif_rst = devm_reset_control_get(dev, "spdif");
-	if (IS_ERR(dp->spdif_rst)) {
+	dp->mhdp.spdif_rst = devm_reset_control_get(dev, "spdif");
+	if (IS_ERR(dp->mhdp.spdif_rst)) {
 		DRM_DEV_ERROR(dev, "no spdif reset control found\n");
-		return PTR_ERR(dp->spdif_rst);
+		return PTR_ERR(dp->mhdp.spdif_rst);
 	}
 
 	dp->dptx_rst = devm_reset_control_get(dev, "dptx");
@@ -787,7 +799,7 @@ static int cdn_dp_audio_hw_params(struct device *dev,  void *data,
 		audio.format = AFMT_I2S;
 		break;
 	case HDMI_SPDIF:
-		audio.format = AFMT_SPDIF;
+		audio.format = AFMT_SPDIF_INT;
 		break;
 	default:
 		DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
@@ -795,9 +807,9 @@ static int cdn_dp_audio_hw_params(struct device *dev,  void *data,
 		goto out;
 	}
 
-	ret = cdn_dp_audio_config(dp, &audio);
+	ret = cdns_mhdp_audio_config(&dp->mhdp, &audio);
 	if (!ret)
-		dp->audio_info = audio;
+		dp->mhdp.audio_info = audio;
 
 out:
 	mutex_unlock(&dp->lock);
@@ -813,9 +825,9 @@ static void cdn_dp_audio_shutdown(struct device *dev, void *data)
 	if (!dp->active)
 		goto out;
 
-	ret = cdn_dp_audio_stop(dp, &dp->audio_info);
+	ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->mhdp.audio_info);
 	if (!ret)
-		dp->audio_info.format = AFMT_UNUSED;
+		dp->mhdp.audio_info.format = AFMT_UNUSED;
 out:
 	mutex_unlock(&dp->lock);
 }
@@ -832,7 +844,7 @@ static int cdn_dp_audio_digital_mute(struct device *dev, void *data,
 		goto out;
 	}
 
-	ret = cdn_dp_audio_mute(dp, enable);
+	ret = cdns_mhdp_audio_mute(&dp->mhdp, enable);
 
 out:
 	mutex_unlock(&dp->lock);
@@ -844,7 +856,8 @@ static int cdn_dp_audio_get_eld(struct device *dev, void *data,
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
 
-	memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len));
+	memcpy(buf, dp->mhdp.connector.base.eld,
+	       min(sizeof(dp->mhdp.connector.base.eld), len));
 
 	return 0;
 }
@@ -866,11 +879,11 @@ static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp,
 		.max_i2s_channels = 8,
 	};
 
-	dp->audio_pdev = platform_device_register_data(
-			 dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
-			 &codec_data, sizeof(codec_data));
+	dp->mhdp.audio_pdev = platform_device_register_data(
+			      dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
+			      &codec_data, sizeof(codec_data));
 
-	return PTR_ERR_OR_ZERO(dp->audio_pdev);
+	return PTR_ERR_OR_ZERO(dp->mhdp.audio_pdev);
 }
 
 static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
@@ -878,6 +891,7 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
 	int ret;
 	unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS);
 	unsigned long sleep = 1000;
+	struct device *dev = dp->mhdp.dev;
 
 	WARN_ON(!mutex_is_locked(&dp->lock));
 
@@ -888,13 +902,13 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
 	mutex_unlock(&dp->lock);
 
 	while (time_before(jiffies, timeout)) {
-		ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev);
+		ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dev);
 		if (ret == -ENOENT) {
 			msleep(sleep);
 			sleep *= 2;
 			continue;
 		} else if (ret) {
-			DRM_DEV_ERROR(dp->dev,
+			DRM_DEV_ERROR(dev,
 				      "failed to request firmware: %d\n", ret);
 			goto out;
 		}
@@ -904,7 +918,7 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
 		goto out;
 	}
 
-	DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n");
+	DRM_DEV_ERROR(dev, "Timed out trying to load firmware\n");
 	ret = -ETIMEDOUT;
 out:
 	mutex_lock(&dp->lock);
@@ -915,8 +929,9 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 {
 	struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device,
 						event_work);
-	struct drm_connector *connector = &dp->connector;
+	struct drm_connector *connector = &dp->mhdp.connector.base;
 	enum drm_connector_status old_status;
+	struct device *dev = dp->mhdp.dev;
 
 	int ret;
 
@@ -933,44 +948,45 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 
 	/* Not connected, notify userspace to disable the block */
 	if (!cdn_dp_connected_port(dp)) {
-		DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n");
+		DRM_DEV_INFO(dev, "Not connected. Disabling cdn\n");
 		dp->connected = false;
 
 	/* Connected but not enabled, enable the block */
 	} else if (!dp->active) {
-		DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n");
+		DRM_DEV_INFO(dev, "Connected, not enabled. Enabling cdn\n");
 		ret = cdn_dp_enable(dp);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "Enable dp failed %d\n", ret);
+			DRM_DEV_ERROR(dev, "Enable dp failed %d\n", ret);
 			dp->connected = false;
 		}
 
 	/* Enabled and connected to a dongle without a sink, notify userspace */
 	} else if (!cdn_dp_check_sink_connection(dp)) {
-		DRM_DEV_INFO(dp->dev, "Connected without sink. Assert hpd\n");
+		DRM_DEV_INFO(dev, "Connected without sink. Assert hpd\n");
 		dp->connected = false;
 
 	/* Enabled and connected with a sink, re-train if requested */
 	} else if (!cdn_dp_check_link_status(dp)) {
-		unsigned int rate = dp->max_rate;
-		unsigned int lanes = dp->max_lanes;
-		struct drm_display_mode *mode = &dp->mode;
+		unsigned int rate = dp->mhdp.dp.rate;
+		unsigned int lanes = dp->mhdp.dp.num_lanes;
+		struct drm_display_mode *mode = &dp->mhdp.mode;
 
-		DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n");
-		ret = cdn_dp_train_link(dp);
+		DRM_DEV_INFO(dev, "Connected with sink. Re-train link\n");
+		ret = cdns_mhdp_train_link(&dp->mhdp);
 		if (ret) {
 			dp->connected = false;
-			DRM_DEV_ERROR(dp->dev, "Train link failed %d\n", ret);
+			DRM_DEV_ERROR(dev, "Train link failed %d\n", ret);
 			goto out;
 		}
 
 		/* If training result is changed, update the video config */
 		if (mode->clock &&
-		    (rate != dp->max_rate || lanes != dp->max_lanes)) {
-			ret = cdn_dp_config_video(dp);
+		    (rate != dp->mhdp.dp.rate ||
+		     lanes != dp->mhdp.dp.num_lanes)) {
+			ret = cdns_mhdp_config_video(&dp->mhdp);
 			if (ret) {
 				dp->connected = false;
-				DRM_DEV_ERROR(dp->dev,
+				DRM_DEV_ERROR(dev,
 					      "Failed to config video %d\n",
 					      ret);
 			}
@@ -1039,7 +1055,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 
 	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
 
-	connector = &dp->connector;
+	connector = &dp->mhdp.connector.base;
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
 	connector->dpms = DRM_MODE_DPMS_OFF;
 
@@ -1063,7 +1079,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 		port = dp->port[i];
 
 		port->event_nb.notifier_call = cdn_dp_pd_event;
-		ret = devm_extcon_register_notifier(dp->dev, port->extcon,
+		ret = devm_extcon_register_notifier(dp->mhdp.dev, port->extcon,
 						    EXTCON_DISP_DP,
 						    &port->event_nb);
 		if (ret) {
@@ -1090,7 +1106,7 @@ static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &dp->encoder;
-	struct drm_connector *connector = &dp->connector;
+	struct drm_connector *connector = &dp->mhdp.connector.base;
 
 	cancel_work_sync(&dp->event_work);
 	cdn_dp_encoder_disable(encoder);
@@ -1150,7 +1166,7 @@ static int cdn_dp_probe(struct platform_device *pdev)
 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
 	if (!dp)
 		return -ENOMEM;
-	dp->dev = dev;
+	dp->mhdp.dev = dev;
 
 	match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node);
 	dp_data = (struct cdn_dp_data *)match->data;
@@ -1194,8 +1210,8 @@ static int cdn_dp_remove(struct platform_device *pdev)
 {
 	struct cdn_dp_device *dp = platform_get_drvdata(pdev);
 
-	platform_device_unregister(dp->audio_pdev);
-	cdn_dp_suspend(dp->dev);
+	platform_device_unregister(dp->mhdp.audio_pdev);
+	cdn_dp_suspend(dp->mhdp.dev);
 	component_del(&pdev->dev, &cdn_dp_component_ops);
 
 	return 0;
@@ -1205,7 +1221,7 @@ static void cdn_dp_shutdown(struct platform_device *pdev)
 {
 	struct cdn_dp_device *dp = platform_get_drvdata(pdev);
 
-	cdn_dp_suspend(dp->dev);
+	cdn_dp_suspend(dp->mhdp.dev);
 }
 
 static const struct dev_pm_ops cdn_dp_pm_ops = {
drivers/gpu/drm/rockchip/cdn-dp-core.h +2 -42

82 lines not on this page · raw message

drivers/gpu/drm/rockchip/cdn-dp-reg.c +245 -243

1,060 lines not on this page · raw message

drivers/gpu/drm/rockchip/cdn-dp-reg.h +108 -25

170 lines not on this page · raw message

Signature · 1 line
2.17.1
#2 lore raw

Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver

HI Sandor Yu

Quoted 17 lines · On Mon, 1 Jun 2020 at 07:29, <[email protected]> wrote:

From: Sandor Yu <[email protected]>

- Extracted common fields from cdn_dp_device to a new cdns_mhdp_device structure which will be used by two separate drivers later on.
- Moved some datatypes (audio_format, audio_info, vic_pxl_encoding_format, video_info) from cdn-dp-core.c to cdn-dp-reg.h.
- Changed prefixes from cdn_dp to cdns_mhdp
cdn -> cdns to match the other Cadence's drivers
dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
this registers map can be a HDMI (which is internally different, but the interface for commands, events is pretty much the same).
- Modified cdn-dp-core.c to use the new driver structure and new function names.
- writel and readl are replaced by cdns_mhdp_bus_write and cdns_mhdp_bus_read.

The high-level idea is great - split, refactor and reuse the existing drivers.

Although looking at the patches themselves - they seems to be doing multiple things at once.
As indicated by the extensive list in the commit log.

I would suggest splitting those up a bit, roughly in line of the itemisation as per the commit message.

Here is one hand wavy way to chunk this patch:
1) use put_unalligned*
2) 'use local variable dev' style of changes (as seem in cdn_dp_clk_enable)
3) add writel/readl wrappers
4) hookup struct cdns_mhdp_device, keep dp->mhdp detail internal.
The cdn-dp-reg.h function names/signatures will stay the same.
5) finalize the helpers - use mhdp directly, rename

HTH
Emil

Examples:
4)
static int cdn_dp_mailbox_read(struct cdn_dp_device *dp) {
+" struct cdns_mhdp_device *mhdp = dp->mhdp;
int val, ret;

- ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+ ret = readx_poll_timeout(readl, mhdp->regs_base + MAILBOX_EMPTY_ADDR,
...
return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
}

5)
-static int cdn_dp_mailbox_read(struct cdn_dp_device *dp) +static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
{
- struct cdns_mhdp_device *mhdp = dp->mhdp;
int val, ret;
...
- return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
+ return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff; }

#3 lore raw

Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver

Quoted 27 lines · Emil Velikov
Quoted 17 lines · On Mon, 1 Jun 2020 at 07:29, <[email protected]> wrote:

From: Sandor Yu <[email protected]>

- Extracted common fields from cdn_dp_device to a new cdns_mhdp_device structure which will be used by two separate drivers later on.
- Moved some datatypes (audio_format, audio_info, vic_pxl_encoding_format, video_info) from cdn-dp-core.c to cdn-dp-reg.h.
- Changed prefixes from cdn_dp to cdns_mhdp
cdn -> cdns to match the other Cadence's drivers
dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
this registers map can be a HDMI (which is internally different, but the interface for commands, events is pretty much the same).
- Modified cdn-dp-core.c to use the new driver structure and new function names.
- writel and readl are replaced by cdns_mhdp_bus_write and cdns_mhdp_bus_read.

The high-level idea is great - split, refactor and reuse the existing drivers.

Although looking at the patches themselves - they seems to be doing multiple things at once.
As indicated by the extensive list in the commit log.

I would suggest splitting those up a bit, roughly in line of the itemisation as per the commit message.

Quoted 7 lines

Here is one hand wavy way to chunk this patch:
1) use put_unalligned*
2) 'use local variable dev' style of changes (as seem in cdn_dp_clk_enable)
3) add writel/readl wrappers
4) hookup struct cdns_mhdp_device, keep dp->mhdp detail internal.
The cdn-dp-reg.h function names/signatures will stay the same.
5) finalize the helpers - use mhdp directly, rename

I second this, otherwise review is very hard.

Quoted 23 lines

Examples:
4)
static int cdn_dp_mailbox_read(struct cdn_dp_device *dp) {

+"  struct cdns_mhdp_device *mhdp = dp->mhdp;
   int val, ret;
drivers/gpu/drm/rockchip/cdn-dp-reg.c +1 -1
-  ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+  ret = readx_poll_timeout(readl, mhdp->regs_base + MAILBOX_EMPTY_ADDR,
...
   return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
 }

5)

drivers/gpu/drm/rockchip/cdn-dp-reg.c +2 -3
-static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
+static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
 {
-  struct cdns_mhdp_device *mhdp = dp->mhdp;
   int val, ret;
...
-  return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
+  return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
 }
Signature · 3 lines
Regards,

Laurent Pinchart
author
#4 lore raw

RE: [EXT] Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver

Quoted 58 lines

-----Original Message-----
From: Laurent Pinchart <[email protected]>
Sent: Wednesday, June 3, 2020 7:29 AM
To: Emil Velikov <[email protected]>
Cc: Sandor Yu <[email protected]>; Andrzej Hajda <[email protected]>; Neil Armstrong <[email protected]>; Jonas Karlman <[email protected]>; Jernej Skrabec <[email protected]>; Heiko Stübner <[email protected]>; Sandy Huang <[email protected]>; [email protected]; ML dri-devel <[email protected]>; linux-rockchip <[email protected]>; Linux-Kernel@Vger. Kernel. Org <[email protected]>; LAKML <[email protected]>; dl-linux-imx <[email protected]>
Subject: [EXT] Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver

Caution: EXT Email

Quoted 5 lines · Emil Velikov
Quoted 4 lines · On Mon, 1 Jun 2020 at 07:29, <[email protected]> wrote:

From: Sandor Yu <[email protected]>

- Extracted common fields from cdn_dp_device to a new

cdns_mhdp_device

Quoted 2 lines
Quoted 2 lines

structure which will be used by two separate drivers later on.
- Moved some datatypes (audio_format, audio_info,

vic_pxl_encoding_format,

Quoted 20 lines
Quoted 11 lines

video_info) from cdn-dp-core.c to cdn-dp-reg.h.
- Changed prefixes from cdn_dp to cdns_mhdp
cdn -> cdns to match the other Cadence's drivers
dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
this registers map can be a HDMI (which is internally different, but the interface for commands, events is pretty much the same).
- Modified cdn-dp-core.c to use the new driver structure and new function names.
- writel and readl are replaced by cdns_mhdp_bus_write and cdns_mhdp_bus_read.

The high-level idea is great - split, refactor and reuse the existing drivers.

Although looking at the patches themselves - they seems to be doing multiple things at once.
As indicated by the extensive list in the commit log.

I would suggest splitting those up a bit, roughly in line of the itemisation as per the commit message.

Quoted 8 lines

Here is one hand wavy way to chunk this patch:
1) use put_unalligned*
2) 'use local variable dev' style of changes (as seem in
cdn_dp_clk_enable)
3) add writel/readl wrappers
4) hookup struct cdns_mhdp_device, keep dp->mhdp detail internal.
The cdn-dp-reg.h function names/signatures will stay the same.
5) finalize the helpers - use mhdp directly, rename

Quoted 2 lines

I second this, otherwise review is very hard.

I will split the patch later, thanks.

Quoted 27 lines
Quoted 13 lines

Examples:
4)
static int cdn_dp_mailbox_read(struct cdn_dp_device *dp) {

+"  struct cdns_mhdp_device *mhdp = dp->mhdp;
   int val, ret;
(quoted diff) +2 -1
-  ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+  ret = readx_poll_timeout(readl, mhdp->regs_base +
+ MAILBOX_EMPTY_ADDR,
...
   return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;  }

5)

drivers/gpu/drm/rockchip/cdn-dp-reg.c void cdn_dp_clock_reset(struct cdn_dp_device *dp) · line 100

Quoted 9 lines
drivers/gpu/drm/rockchip/cdn-dp-reg.c +2 -3
-static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
+static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
 {
-  struct cdns_mhdp_device *mhdp = dp->mhdp;
   int val, ret;
...
-  return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
+  return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
 }

--
Regards,

Laurent Pinchart

#5 lore raw

PATCH 2/7 drm: bridge: cadence: Create cadence fold

In reply to [email protected]

From: Sandor Yu <[email protected]>

Create new directory drm/bridge/cadence. Cadence MHDP DP and HDMI bridge dirver will added later.

drm/rockchip/cdn-dp-reg.c will separate to three files.
- cdns-mhdp-common.c: Provide basic MHDP register read/write via mailbox. public firmware load, event, edid and HPD functions that will be refered in MHDP DP and HDMI drivers.
- cdns-hdp-audio.c: MHDP Audio specific functions
- cdns-mhdp-dp.c: MHDP DP specific functions, DPCD and link traning functions.

---
 drivers/gpu/drm/bridge/Kconfig                |   2 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/cadence/Kconfig        |   7 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   3 +
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 198 +++++++++
 .../cadence/cdns-mhdp-common.c}               | 418 ++++--------------
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |  23 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c | 174 ++++++++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/Makefile             |   2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        |   2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |   2 +-
 .../drm/bridge/cdns-mhdp.h                    |   9 +-
 13 files changed, 494 insertions(+), 348 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/cadence/Makefile
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
 rename drivers/gpu/drm/{rockchip/cdn-dp-reg.c => bridge/cadence/cdns-mhdp-common.c} (64%)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
 rename drivers/gpu/drm/rockchip/cdn-dp-reg.h => include/drm/bridge/cdns-mhdp.h (98%)
drivers/gpu/drm/bridge/Kconfig +2 -0
index aaed2347ace9..c764150fb228 100644
@@ -184,6 +184,8 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
 source "drivers/gpu/drm/bridge/adv7511/Kconfig"
 
+source "drivers/gpu/drm/bridge/cadence/Kconfig"
+
 source "drivers/gpu/drm/bridge/synopsys/Kconfig"
 
 endmenu
drivers/gpu/drm/bridge/Makefile +1 -0
index 6fb062b5b0f0..5d61c1d43b67 100644
@@ -20,4 +20,5 @@ obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
 obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o
 
 obj-y += analogix/
+obj-y += cadence/
 obj-y += synopsys/
drivers/gpu/drm/bridge/cadence/Kconfig new file +7 -0
new file mode 100644
index 000000000000..48c1b0f77dc6
@@ -0,0 +1,7 @@
+config DRM_CDNS_MHDP
+	tristate "Cadence MHDP COMMON API driver"
+	select DRM_KMS_HELPER
+	select DRM_PANEL_BRIDGE
+	depends on OF
+	help
+	  Support Cadence MHDP API library.
drivers/gpu/drm/bridge/cadence/Makefile new file +3 -0
new file mode 100644
index 000000000000..ddb2ba4fb852
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c new file +198 -0

198 lines not on this page · raw message

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c renamed from drivers/gpu/drm/rockchip/cdn-dp-reg.c +78 -340

503 lines not on this page · raw message

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h new file +23 -0
new file mode 100644
index 000000000000..1f093a2deaa7
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef _CDNS_MHDP_H_
+#define _CDNS_MHDP_H_
+
+#include <drm/bridge/cdns-mhdp.h>
+
+/* mhdp common */
+u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset);
+void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset);
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
+				  u8 opcode, u16 size, u8 *message);
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
+					  u8 *buff, u16 buff_size);
+int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
+					      u8 module_id, u8 opcode, u16 req_size);
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
+int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
+				   u8 start_bit, u8 bits_no, u32 val);
+
+#endif
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c new file +174 -0

174 lines not on this page · raw message

drivers/gpu/drm/rockchip/Kconfig +1 -0
index 310aa1546893..af1e9ac5c5ef 100644
@@ -30,6 +30,7 @@ config ROCKCHIP_ANALOGIX_DP
 config ROCKCHIP_CDN_DP
 	bool "Rockchip cdn DP"
 	depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m)
+	depends on DRM_CDNS_MHDP
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the cdn DP driver. If you want to enable Dp on
drivers/gpu/drm/rockchip/Makefile +1 -1
index 17a9e7eb2130..bd013659404f 100644
@@ -8,7 +8,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
-rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
+rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
drivers/gpu/drm/rockchip/cdn-dp-core.c +1 -1
index b6aa21779608..06fd82b217b6 100644
@@ -15,6 +15,7 @@
 
 #include <sound/hdmi-codec.h>
 
+#include <drm/bridge/cdns-mhdp.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_edid.h>
@@ -22,7 +23,6 @@
 #include <drm/drm_probe_helper.h>
 
 #include "cdn-dp-core.h"
-#include "cdn-dp-reg.h"
 #include "rockchip_drm_vop.h"
 
 #define connector_to_dp(c) \
drivers/gpu/drm/rockchip/cdn-dp-core.h +1 -1
index d5dcb75b2398..8b1b15b92503 100644
@@ -7,11 +7,11 @@
 #ifndef _CDN_DP_CORE_H
 #define _CDN_DP_CORE_H
 
+#include <drm/bridge/cdns-mhdp.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
 
-#include "cdn-dp-reg.h"
 #include "rockchip_drm_drv.h"
 
 #define MAX_PHY		2
include/drm/bridge/cdns-mhdp.h renamed from drivers/gpu/drm/rockchip/cdn-dp-reg.h +4 -5
similarity index 98%
rename from drivers/gpu/drm/rockchip/cdn-dp-reg.h
rename to include/drm/bridge/cdns-mhdp.h
index 3c1235ff8e1c..c8170e6048f7 100644
@@ -4,11 +4,12 @@
  * Author: Chris Zhong <[email protected]>
  */
 
-#ifndef _CDN_DP_REG_H
-#define _CDN_DP_REG_H
+#ifndef CDNS_MHDP_H_
+#define CDNS_MHDP_H_
 
 #include <drm/drm_bridge.h>
 #include <drm/drm_connector.h>
+#include <drm/drm_dp_helper.h>
 #include <linux/bitops.h>
 
 #define ADDR_IMEM		0x10000
@@ -529,8 +530,6 @@ struct cdns_mhdp_device {
 	};
 };
 
-int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
-int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
 void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
 int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
@@ -554,4 +553,4 @@ int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
 int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
 			   struct audio_info *audio);
 
-#endif /* _CDN_DP_REG_H */
+#endif /* CDNS_MHDP_H_ */
Signature · 1 line
2.17.1
#6 lore raw

PATCH 3/7 drm: bridge: cadence: initial support for MHDP DP bridge driver

In reply to [email protected]

From: Sandor Yu <[email protected]>

This adds initial support for MHDP DP bridge driver. Basic DP functions are supported, that include:
-Video mode set on-the-fly
-Cable hotplug detect
-MAX support resolution to 3096x2160@60fps -Support DP audio
-EDID read via AUX

---
 drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   1 +
 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530 ++++++++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 100 ++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.c |  42 +-
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |   3 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c |  34 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        |   7 +-
 include/drm/bridge/cdns-mhdp.h                |  52 +-
 9 files changed, 740 insertions(+), 33 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
drivers/gpu/drm/bridge/cadence/Kconfig +4 -0
index 48c1b0f77dc6..b7b8d30b18b6 100644
@@ -5,3 +5,7 @@ config DRM_CDNS_MHDP
 	depends on OF
 	help
 	  Support Cadence MHDP API library.
+
+config DRM_CDNS_DP
+	tristate "Cadence DP DRM driver"
+	depends on DRM_CDNS_MHDP
drivers/gpu/drm/bridge/cadence/Makefile +1 -0
index ddb2ba4fb852..cb3c88311a64 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
 obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +530 -0

530 lines not on this page · raw message

drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c +100 -0

109 lines not on this page · raw message

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +12 -30

51 lines not on this page · raw message

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h +3 -0
index 1f093a2deaa7..b122bf5f0bdf 100644
@@ -20,4 +20,7 @@ int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
 int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
 				   u8 start_bit, u8 bits_no, u32 val);
 
+/* Audio */
+int cdns_mhdp_register_audio_driver(struct device *dev);
+void cdns_mhdp_unregister_audio_driver(struct device *dev);
 #endif
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +33 -1
index c8160f321aca..8fea072a5568 100644
@@ -108,7 +108,9 @@ static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
 		if (ret)
 			goto err_training_start;
 
-		if (event[1] & EQ_PHASE_FINISHED)
+		if (event[1] & CLK_RECOVERY_FAILED)
+			DRM_DEV_ERROR(mhdp->dev, "clock recovery failed\n");
+		else if (event[1] & EQ_PHASE_FINISHED)
 			return 0;
 	}
 
@@ -172,3 +174,33 @@ int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_train_link);
+
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp)
+{
+	u8 msg[8];
+	int ret;
+
+	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
+	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
+	msg[2] = VOLTAGE_LEVEL_2;
+	msg[3] = PRE_EMPHASIS_LEVEL_3;
+	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+	msg[5] = FAST_LT_NOT_SUPPORT;
+	msg[6] = mhdp->lane_mapping;
+	msg[7] = ENHANCED;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_SET_HOST_CAPABILITIES,
+				     sizeof(msg), msg);
+	if (ret)
+		goto err_set_host_cap;
+
+	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
+					AUX_HOST_INVERT);
+
+err_set_host_cap:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
drivers/gpu/drm/rockchip/cdn-dp-core.c +6 -1
index 06fd82b217b6..d94d22650899 100644
@@ -423,7 +423,12 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
-	ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
+
+	if (property.intval)
+		dp->mhdp.lane_mapping = LANE_MAPPING_FLIPPED;
+	else
+		dp->mhdp.lane_mapping = LANE_MAPPING_NORMAL;
+	ret = cdns_mhdp_set_host_cap(&dp->mhdp);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
 			      ret);
include/drm/bridge/cdns-mhdp.h +51 -1

107 lines not on this page · raw message

Signature · 1 line
2.17.1
#7 lore raw

Re: [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver

Hi Sandor,

Thank you for the patch.

Quoted 276 lines · On Mon, Jun 01, 2020 at 02:17:33PM +0800, [email protected] wrote:

From: Sandor Yu <[email protected]>

This adds initial support for MHDP DP bridge driver. Basic DP functions are supported, that include:
-Video mode set on-the-fly
-Cable hotplug detect
-MAX support resolution to 3096x2160@60fps -Support DP audio
-EDID read via AUX

---
 drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   1 +
 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530 ++++++++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 100 ++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.c |  42 +-
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |   3 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c |  34 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        |   7 +-
 include/drm/bridge/cdns-mhdp.h                |  52 +-
 9 files changed, 740 insertions(+), 33 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
drivers/gpu/drm/bridge/cadence/Kconfig +4 -0
index 48c1b0f77dc6..b7b8d30b18b6 100644
@@ -5,3 +5,7 @@ config DRM_CDNS_MHDP
 	depends on OF
 	help
 	  Support Cadence MHDP API library.
+
+config DRM_CDNS_DP
+	tristate "Cadence DP DRM driver"
+	depends on DRM_CDNS_MHDP
drivers/gpu/drm/bridge/cadence/Makefile +1 -0
index ddb2ba4fb852..cb3c88311a64 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
 obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +225 -0
new file mode 100644
index 000000000000..b2fe8fdc64ed
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence Display Port Interface (DP) driver
+ *
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ *
+ */
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+#include "cdns-mhdp-common.h"
+
+/*
+ * This function only implements native DPDC reads and writes
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
+		struct drm_dp_aux_msg *msg)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
+	bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+	int ret;
+
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		return msg->size;
+	}
+
+	if (!native) {
+		dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
+		return -EINVAL;
+	}
+
+	/* msg sanity check */
+	if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
+		dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
+						__func__, msg->size, (unsigned int)msg->request);
+		return -EINVAL;
+	}
+
+	if (msg->request == DP_AUX_NATIVE_WRITE) {
+		const u8 *buf = msg->buffer;
+		int i;
+		for (i = 0; i < msg->size; ++i) {
+			ret = cdns_mhdp_dpcd_write(mhdp,
+						   msg->address + i, buf[i]);
+			if (!ret)
+				continue;
+
+			DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
+
+			return ret;
+		}
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+
+	if (msg->request == DP_AUX_NATIVE_READ) {
+		ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
+		if (ret < 0)
+			return -EIO;
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+	return 0;
+}
+
+static int dp_aux_init(struct cdns_mhdp_device *mhdp,
+		  struct device *dev)
+{
+	int ret;
+
+	mhdp->dp.aux.name = "imx_dp_aux";
+	mhdp->dp.aux.dev = dev;
+	mhdp->dp.aux.transfer = dp_aux_transfer;
+
+	ret = drm_dp_aux_register(&mhdp->dp.aux);
+
+	return ret;
+}
+
+static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
+{
+	drm_dp_aux_unregister(&mhdp->dp.aux);
+	return 0;
+}
+
+static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	/* reset pixel clk */
+	val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
+	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
+	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
+}
+
+static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	cdns_mhdp_plat_call(mhdp, pclk_rate);
+
+	/* delay for DP FW stable after pixel clock relock */
+	msleep(50);
+
+	dp_pixel_clk_reset(mhdp);
+
+	/* Get DP Caps  */
+	ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd,
+			       DP_RECEIVER_CAP_SIZE);
+	if (ret < 0) {
+		DRM_ERROR("Failed to get caps %d\n", ret);
+		return;
+	}
+
+	mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd);
+	mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd);
+
+	/* check the max link rate */
+	if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE)
+		mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE;
+
+	/* Initialize link rate/num_lanes as panel max link rate/max_num_lanes */
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	/* Video off */
+	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+		return;
+	}
+
+	/* Line swaping */
+	mhdp->lane_mapping = mhdp->plat_data->lane_mapping;
+	cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
+
+	/* Set DP host capability */
+	ret = cdns_mhdp_set_host_cap(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
+		return;
+	}
+
+	ret = cdns_mhdp_config_video(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
+		return;
+	}
+
+	return;
+}
+
+/* -----------------------------------------------------------------------------
+ * DP TX Setup
+ */
+static enum drm_connector_status
+cdns_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdns_mhdp_device *mhdp = container_of(connector,
+					struct cdns_mhdp_device, connector.base);
+	u8 hpd = 0xf;
+
+	hpd = cdns_mhdp_read_hpd(mhdp);
+	if (hpd == 1)
+		/* Cable Connected */
+		return connector_status_connected;
+	else if (hpd == 0)
+		/* Cable Disconnedted */
+		return connector_status_disconnected;
+	else {
+		/* Cable status unknown */
+		DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+		return connector_status_unknown;
+	}
+}
+
+static int cdns_dp_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdns_mhdp_device *mhdp = container_of(connector,
+					struct cdns_mhdp_device, connector.base);
+	int num_modes = 0;
+	struct edid *edid;
+
+	edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_mhdp_get_edid_block, mhdp);
+	if (edid) {
+		dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+			 edid->header[0], edid->header[1],
+			 edid->header[2], edid->header[3],
+			 edid->header[4], edid->header[5],
+			 edid->header[6], edid->header[7]);
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	if (num_modes == 0)
+		DRM_ERROR("Invalid edid\n");
+	return num_modes;
+}
+
+static const struct drm_connector_funcs cdns_dp_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = cdns_dp_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 235

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
+	.get_modes = cdns_dp_connector_get_modes,
+};
+
+static int cdns_dp_bridge_attach(struct drm_bridge *bridge,
+				 enum drm_bridge_attach_flags flags)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_connector *connector = &mhdp->connector.base;

New bridge drivers need to support operation without creating a connector when the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is set in the flags argument. For an example of how this is done, please see
https://lore.kernel.org/dri-devel/20200526011505.31884-23-laurent.pinchart+renesas@ideasonboard.com/

Quoted 280 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +280 -0
+
+	connector->interlace_allowed = 1;
+
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
+
+	drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
+			   DRM_MODE_CONNECTOR_DisplayPort);
+
+	drm_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
+
+static enum drm_mode_status
+cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_mode *mode)
+{
+	enum drm_mode_status mode_status = MODE_OK;
+
+	/* We don't support double-clocked modes */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+			mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_BAD;
+
+	/* MAX support pixel clock rate 594MHz */
+	if (mode->clock > 594000)
+		return MODE_CLOCK_HIGH;
+
+	/* 4096x2160 is not supported */
+	if (mode->hdisplay > 3840)
+		return MODE_BAD_HVALUE;
+
+	if (mode->vdisplay > 2160)
+		return MODE_BAD_VVALUE;
+
+	return mode_status;
+}
+
+static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
+				    const struct drm_display_mode *orig_mode,
+				    const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_display_info *display_info = &mhdp->connector.base.display_info;
+	struct video_info *video = &mhdp->video_info;
+
+	switch (display_info->bpc) {
+	case 10:
+		video->color_depth = 10;
+		break;
+	case 6:
+		video->color_depth = 6;
+		break;
+	default:
+		video->color_depth = 8;
+		break;
+	}
+
+	video->color_fmt = PXL_RGB;
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
+	memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+
+	mutex_lock(&mhdp->lock);
+	cdns_dp_mode_set(mhdp);
+	mutex_unlock(&mhdp->lock);
+}
+
+static void cdn_dp_bridge_enable(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	int ret;
+
+	/* Link trainning */
+	ret = cdns_mhdp_train_link(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
+		return;
+	}
+
+	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+		return;
+	}
+}
+
+static void cdn_dp_bridge_disable(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+
+	cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+}
+
+static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
+	.attach = cdns_dp_bridge_attach,
+	.enable = cdn_dp_bridge_enable,
+	.disable = cdn_dp_bridge_disable,
+	.mode_set = cdns_dp_bridge_mode_set,
+	.mode_valid = cdns_dp_bridge_mode_valid,
+};
+
+static void hotplug_work_func(struct work_struct *work)
+{
+	struct cdns_mhdp_device *mhdp = container_of(work,
+					   struct cdns_mhdp_device, hotplug_work.work);
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	drm_helper_hpd_irq_event(connector->dev);
+
+	if (connector->status == connector_status_connected) {
+		/* Cable connedted  */
+		DRM_INFO("HDMI/DP Cable Plug In\n");
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	} else if (connector->status == connector_status_disconnected) {
+		/* Cable Disconnedted  */
+		DRM_INFO("HDMI/DP Cable Plug Out\n");
+		enable_irq(mhdp->irq[IRQ_IN]);
+	}
+}
+
+static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
+{
+	struct cdns_mhdp_device *mhdp = data;
+
+	disable_irq_nosync(irq);
+
+	mod_delayed_work(system_wq, &mhdp->hotplug_work,
+			msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+	return IRQ_HANDLED;
+}
+
+static int __cdns_dp_probe(struct platform_device *pdev,
+		struct cdns_mhdp_device *mhdp)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *iores = NULL;
+	int ret;
+
+	mutex_init(&mhdp->lock);
+
+	INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (iores) {
+		mhdp->regs_base = devm_ioremap(dev, iores->start,
+					       resource_size(iores));
+		if (IS_ERR(mhdp->regs_base))
+			return -ENOMEM;
+	}
+
+	mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+	if (mhdp->irq[IRQ_IN] < 0) {
+		dev_info(dev, "No plug_in irq number\n");
+	}
+
+	mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+	if (mhdp->irq[IRQ_OUT] < 0) {
+		dev_info(dev, "No plug_out irq number\n");
+	}
+
+	cdns_mhdp_plat_call(mhdp, power_on);
+
+	cdns_mhdp_plat_call(mhdp, firmware_init);
+
+	/* DP FW alive check */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO dp FW running\n");
+		return -ENXIO;
+	}
+
+	/* DP PHY init before AUX init */
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	/* Enable Hotplug Detect IRQ thread */
+	irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+					NULL, cdns_dp_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+
+	if (ret) {
+		dev_err(dev, "can't claim irq %d\n",
+				mhdp->irq[IRQ_IN]);
+		return -EINVAL;
+	}
+
+	irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+					NULL, cdns_dp_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+
+	if (ret) {
+		dev_err(dev, "can't claim irq %d\n",
+				mhdp->irq[IRQ_OUT]);
+		return -EINVAL;
+	}
+
+	if (cdns_mhdp_read_hpd(mhdp))
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	else
+		enable_irq(mhdp->irq[IRQ_IN]);
+
+	mhdp->bridge.base.driver_private = mhdp;
+	mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs;
+#ifdef CONFIG_OF
+	mhdp->bridge.base.of_node = dev->of_node;
+#endif
+
+	dev_set_drvdata(dev, mhdp);
+
+	/* register audio driver */
+	cdns_mhdp_register_audio_driver(dev);
+
+	dp_aux_init(mhdp, dev);
+
+	return 0;
+}
+
+static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
+{
+	dp_aux_destroy(mhdp);
+	cdns_mhdp_unregister_audio_driver(mhdp->dev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int cdns_dp_probe(struct platform_device *pdev,
+		  struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_dp_probe(pdev, mhdp);
+	if (ret)
+		return ret;
+
+	drm_bridge_add(&mhdp->bridge.base);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_probe);
+
+void cdns_dp_remove(struct platform_device *pdev)
+{
+	struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+
+	drm_bridge_remove(&mhdp->bridge.base);
+
+	__cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+		struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_dp_probe(pdev, mhdp);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0);
+	if (ret) {
+		cdns_dp_remove(pdev);
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return ret;
+	}
+
+	return 0;

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 525

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+}
+EXPORT_SYMBOL_GPL(cdns_dp_bind);
+
+void cdns_dp_unbind(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	__cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_unbind);

Do we really need to support the component framework, can't we just support the DRM bridge API ?

Quoted 375 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +5 -0
+
+MODULE_AUTHOR("Sandor Yu <[email protected]>");
+MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdns-dp");
drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c +100 -0
index 8f51de0672ab..fdd4bcd0d33c 100644
@@ -2,6 +2,9 @@
 /*
  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
  * Author: Chris Zhong <[email protected]>
+ *
+ * Cadence MHDP Audio driver
+ *
  */
 #include <linux/clk.h>
 #include <linux/reset.h>
@@ -196,3 +199,100 @@ int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_audio_config);
+
+static int audio_hw_params(struct device *dev,  void *data,
+				  struct hdmi_codec_daifmt *daifmt,
+				  struct hdmi_codec_params *params)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct audio_info audio = {
+		.sample_width = params->sample_width,
+		.sample_rate = params->sample_rate,
+		.channels = params->channels,
+		.connector_type = mhdp->connector.base.connector_type,
+	};
+	int ret;
+
+	switch (daifmt->fmt) {
+	case HDMI_I2S:
+		audio.format = AFMT_I2S;
+		break;
+	case HDMI_SPDIF:
+		audio.format = AFMT_SPDIF_EXT;
+		break;
+	default:
+		DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cdns_mhdp_audio_config(mhdp, &audio);
+	if (!ret)
+		mhdp->audio_info = audio;
+
+out:
+	return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
+	if (!ret)
+		mhdp->audio_info.format = AFMT_UNUSED;
+}
+
+static int audio_digital_mute(struct device *dev, void *data,
+				     bool enable)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = cdns_mhdp_audio_mute(mhdp, enable);
+
+	return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+				u8 *buf, size_t len)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	memcpy(buf, mhdp->connector.base.eld,
+	       min(sizeof(mhdp->connector.base.eld), len));
+
+	return 0;
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+	.hw_params = audio_hw_params,
+	.audio_shutdown = audio_shutdown,
+	.digital_mute = audio_digital_mute,
+	.get_eld = audio_get_eld,
+};
+
+int cdns_mhdp_register_audio_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct hdmi_codec_pdata codec_data = {
+		.i2s = 1,
+		.spdif = 1,
+		.ops = &audio_codec_ops,
+		.max_i2s_channels = 8,
+	};
+
+	mhdp->audio_pdev = platform_device_register_data(
+			      dev, HDMI_CODEC_DRV_NAME, 1,
+			      &codec_data, sizeof(codec_data));
+
+	return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
+}
+
+void cdns_mhdp_unregister_audio_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	platform_device_unregister(mhdp->audio_pdev);
+}
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +12 -30
index efb39cf5f48b..9fd4546c6914 100644
@@ -357,36 +357,6 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
 }
 EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
 
-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
-{
-	u8 msg[8];
-	int ret;
-
-	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
-	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
-	msg[2] = VOLTAGE_LEVEL_2;
-	msg[3] = PRE_EMPHASIS_LEVEL_3;
-	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
-	msg[5] = FAST_LT_NOT_SUPPORT;
-	msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
-	msg[7] = ENHANCED;
-
-	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
-				     DPTX_SET_HOST_CAPABILITIES,
-				     sizeof(msg), msg);
-	if (ret)
-		goto err_set_host_cap;
-
-	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
-					AUX_HOST_INVERT);
-
-err_set_host_cap:
-	if (ret)
-		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
-	return ret;
-}
-EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
-
 int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
 {
 	u8 msg[5];
@@ -698,3 +668,15 @@ int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_config_video);
+
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
+{
+	return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val);
+}
+EXPORT_SYMBOL(cdns_phy_reg_write);
+
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
+{
+	return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2));
+}
+EXPORT_SYMBOL(cdns_phy_reg_read);
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h +3 -0
index 1f093a2deaa7..b122bf5f0bdf 100644
@@ -20,4 +20,7 @@ int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
 int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
 				   u8 start_bit, u8 bits_no, u32 val);
 
+/* Audio */
+int cdns_mhdp_register_audio_driver(struct device *dev);
+void cdns_mhdp_unregister_audio_driver(struct device *dev);
 #endif
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +33 -1
index c8160f321aca..8fea072a5568 100644
@@ -108,7 +108,9 @@ static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
 		if (ret)
 			goto err_training_start;
 
-		if (event[1] & EQ_PHASE_FINISHED)
+		if (event[1] & CLK_RECOVERY_FAILED)
+			DRM_DEV_ERROR(mhdp->dev, "clock recovery failed\n");
+		else if (event[1] & EQ_PHASE_FINISHED)
 			return 0;
 	}
 
@@ -172,3 +174,33 @@ int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_train_link);
+
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp)
+{
+	u8 msg[8];
+	int ret;
+
+	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
+	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
+	msg[2] = VOLTAGE_LEVEL_2;
+	msg[3] = PRE_EMPHASIS_LEVEL_3;
+	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+	msg[5] = FAST_LT_NOT_SUPPORT;
+	msg[6] = mhdp->lane_mapping;
+	msg[7] = ENHANCED;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_SET_HOST_CAPABILITIES,
+				     sizeof(msg), msg);
+	if (ret)
+		goto err_set_host_cap;
+
+	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
+					AUX_HOST_INVERT);
+
+err_set_host_cap:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
drivers/gpu/drm/rockchip/cdn-dp-core.c +6 -1
index 06fd82b217b6..d94d22650899 100644
@@ -423,7 +423,12 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
-	ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
+
+	if (property.intval)
+		dp->mhdp.lane_mapping = LANE_MAPPING_FLIPPED;
+	else
+		dp->mhdp.lane_mapping = LANE_MAPPING_NORMAL;
+	ret = cdns_mhdp_set_host_cap(&dp->mhdp);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
 			      ret);
include/drm/bridge/cdns-mhdp.h +51 -1
index c8170e6048f7..6ffb97e17fae 100644
@@ -14,6 +14,7 @@
 
 #define ADDR_IMEM		0x10000
 #define ADDR_DMEM		0x20000
+#define ADDR_PHY_AFE	0x80000
 
 /* APB CFG addr */
 #define APB_CTRL			0
@@ -81,6 +82,10 @@
 #define SOURCE_PIF_SW_RESET		0x30834
 
 /* bellow registers need access by mailbox */
+
+/* source phy comp */
+#define LANES_CONFIG			0x0814
+
 /* source car addr */
 #define SOURCE_HDTX_CAR			0x0900
 #define SOURCE_DPTX_CAR			0x0904
@@ -424,6 +429,16 @@
 /* Reference cycles when using lane clock as reference */
 #define LANE_REF_CYC				0x8000
 
+#define HOTPLUG_DEBOUNCE_MS		200
+
+#define IRQ_IN    0
+#define IRQ_OUT   1
+#define IRQ_NUM   2
+
+#define cdns_mhdp_plat_call(mhdp, operation)			\
+	(!(mhdp) ? -ENODEV : (((mhdp)->plat_data && (mhdp)->plat_data->operation) ?	\
+	 (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD))
+
 enum voltage_swing_level {
 	VOLTAGE_LEVEL_0,
 	VOLTAGE_LEVEL_1,
@@ -504,9 +519,29 @@ struct cdns_mhdp_connector {
 	struct cdns_mhdp_bridge *bridge;
 };
 
+struct cdns_plat_data {
+	/* Vendor PHY support */
+	int (*bind)(struct platform_device *pdev,
+			struct drm_encoder *encoder,
+			struct cdns_mhdp_device *mhdp);
+	void (*unbind)(struct device *dev);
+
+	int (*phy_set)(struct cdns_mhdp_device *mhdp);
+	bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp);
+	int (*firmware_init)(struct cdns_mhdp_device *mhdp);
+	void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
+
+	int (*power_on)(struct cdns_mhdp_device *mhdp);
+	int (*power_off)(struct cdns_mhdp_device *mhdp);
+
+	char *plat_name;
+	int lane_mapping;
+};
+
 struct cdns_mhdp_device {
 	struct device *dev;
 	struct cdns_mhdp_connector connector;
+	struct cdns_mhdp_bridge	bridge;
 
 	void __iomem *regs_base;
 	struct reset_control *spdif_rst;
@@ -520,6 +555,11 @@ struct cdns_mhdp_device {
 
 	unsigned int fw_version;
 
+	struct delayed_work hotplug_work;
+	u32 lane_mapping;
+	bool power_up;
+	struct mutex lock;
+	int irq[IRQ_NUM];
 	union {
 		struct _dp_data {
 			u32 rate;
@@ -528,6 +568,8 @@ struct cdns_mhdp_device {
 			u8 dpcd[DP_RECEIVER_CAP_SIZE];
 		} dp;
 	};
+	const struct cdns_plat_data *plat_data;
+
 };
 
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
@@ -535,7 +577,7 @@ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
 int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
 			    u32 i_size, const u32 *d_mem, u32 d_size);
 int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip);
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
 u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp);
@@ -547,10 +589,18 @@ int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
 int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
 int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
+bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
 			 struct audio_info *audio);
 int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
 int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
 			   struct audio_info *audio);
 
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+
+/* DP  */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+		struct cdns_mhdp_device *mhdp);
+void cdns_dp_unbind(struct device *dev);
 #endif /* CDNS_MHDP_H_ */
Signature · 3 lines
Regards,

Laurent Pinchart
author
#8 lore raw

RE: [EXT] Re: [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver

Quoted 326 lines

-----Original Message-----
From: Laurent Pinchart <[email protected]>
Sent: Wednesday, June 3, 2020 7:35 AM
To: Sandor Yu <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; dl-linux-imx <[email protected]>
Subject: [EXT] Re: [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver

Caution: EXT Email

Hi Sandor,

Thank you for the patch.

Quoted 7 lines · On Mon, Jun 01, 2020 at 02:17:33PM +0800, [email protected] wrote:

From: Sandor Yu <[email protected]>

This adds initial support for MHDP DP bridge driver. Basic DP functions are supported, that include:
-Video mode set on-the-fly
-Cable hotplug detect
-MAX support resolution to 3096x2160@60fps -Support DP audio

-EDID

Quoted 8 lines

read via AUX

---
 drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   1 +
 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530

++++++++++++++++++ .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c

|

Quoted 59 lines

100 ++++ .../gpu/drm/bridge/cadence/cdns-mhdp-common.c | 42 +-

 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |   3 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c |  34 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        |   7 +-
 include/drm/bridge/cdns-mhdp.h                |  52 +-
 9 files changed, 740 insertions(+), 33 deletions(-)  create mode

100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

drivers/gpu/drm/bridge/cadence/Kconfig +4 -0
index 48c1b0f77dc6..b7b8d30b18b6 100644
@@ -5,3 +5,7 @@ config DRM_CDNS_MHDP
      depends on OF
      help
        Support Cadence MHDP API library.
+
+config DRM_CDNS_DP
+     tristate "Cadence DP DRM driver"
+     depends on DRM_CDNS_MHDP
drivers/gpu/drm/bridge/cadence/Makefile +0 -0
index ddb2ba4fb852..cb3c88311a64 100644
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only  cdns_mhdp_drmcore-y :=

cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o

drivers/gpu/drm/bridge/cadence/Makefile +1 -0
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
 obj-$(CONFIG_DRM_CDNS_MHDP)          += cdns_mhdp_drmcore.o
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +21 -0
new file mode 100644
index 000000000000..b2fe8fdc64ed
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence Display Port Interface (DP) driver
+ *
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ *
+ */
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mutex.h>

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 31

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+#include <linux/of_device.h>
+
+#include "cdns-mhdp-common.h"
+
+/*
+ * This function only implements native DPDC reads and writes  */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
+             struct drm_dp_aux_msg *msg) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
+     bool native = msg->request & (DP_AUX_NATIVE_WRITE &

DP_AUX_NATIVE_READ);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +6 -0
+     int ret;
+
+     /* Ignore address only message */
+     if ((msg->size == 0) || (msg->buffer == NULL)) {
+             msg->reply = native ?
+                     DP_AUX_NATIVE_REPLY_ACK :

DP_AUX_I2C_REPLY_ACK;

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 5 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +5 -0
+             return msg->size;
+     }
+
+     if (!native) {
+             dev_err(mhdp->dev, "%s: only native messages

supported\n", __func__);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +6 -0
+             return -EINVAL;
+     }
+
+     /* msg sanity check */
+     if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
+             dev_err(mhdp->dev, "%s: invalid msg: size(%zu),

request(%x)\n",

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 49

Quoted 1 line
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +1 -0
+                                             __func__, msg->size,

(unsigned int)msg->request);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 9 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +9 -0
+             return -EINVAL;
+     }
+
+     if (msg->request == DP_AUX_NATIVE_WRITE) {
+             const u8 *buf = msg->buffer;
+             int i;
+             for (i = 0; i < msg->size; ++i) {
+                     ret = cdns_mhdp_dpcd_write(mhdp,
+                                                msg->address + i,

buf[i]);

Quoted 4 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +4 -0
+                     if (!ret)
+                             continue;
+
+                     DRM_DEV_ERROR(mhdp->dev, "Failed to write

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+ DPCD\n");
+
+                     return ret;
+             }
+             msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+             return msg->size;
+     }
+
+     if (msg->request == DP_AUX_NATIVE_READ) {
+             ret = cdns_mhdp_dpcd_read(mhdp, msg->address,

msg->buffer, msg->size);

Quoted 37 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +37 -0
+             if (ret < 0)
+                     return -EIO;
+             msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+             return msg->size;
+     }
+     return 0;
+}
+
+static int dp_aux_init(struct cdns_mhdp_device *mhdp,
+               struct device *dev)
+{
+     int ret;
+
+     mhdp->dp.aux.name = "imx_dp_aux";
+     mhdp->dp.aux.dev = dev;
+     mhdp->dp.aux.transfer = dp_aux_transfer;
+
+     ret = drm_dp_aux_register(&mhdp->dp.aux);
+
+     return ret;
+}
+
+static int dp_aux_destroy(struct cdns_mhdp_device *mhdp) {
+     drm_dp_aux_unregister(&mhdp->dp.aux);
+     return 0;
+}
+
+static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp) {
+     u32 val;
+
+     /* reset pixel clk */
+     val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
+     cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
+     cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val); }
+
+static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp) {
+     int ret;

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+
+     cdns_mhdp_plat_call(mhdp, pclk_rate);
+
+     /* delay for DP FW stable after pixel clock relock */
+     msleep(50);
+
+     dp_pixel_clk_reset(mhdp);
+
+     /* Get DP Caps  */
+     ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV,

mhdp->dp.dpcd,

Quoted 4 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +4 -0
+                            DP_RECEIVER_CAP_SIZE);
+     if (ret < 0) {
+             DRM_ERROR("Failed to get caps %d\n", ret);
+             return;

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     }
+
+     mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd);
+     mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd);
+
+     /* check the max link rate */
+     if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE)
+             mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE;
+
+     /* Initialize link rate/num_lanes as panel max link

rate/max_num_lanes */

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +6 -0
+     cdns_mhdp_plat_call(mhdp, phy_set);
+
+     /* Video off */
+     ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+     if (ret) {
+             DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n",

ret);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 12 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +12 -0
+             return;
+     }
+
+     /* Line swaping */
+     mhdp->lane_mapping = mhdp->plat_data->lane_mapping;
+     cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 |
+ mhdp->lane_mapping);
+
+     /* Set DP host capability */
+     ret = cdns_mhdp_set_host_cap(mhdp);
+     if (ret) {
+             DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n",

ret);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +6 -0
+             return;
+     }
+
+     ret = cdns_mhdp_config_video(mhdp);
+     if (ret) {
+             DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n",

ret);

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +6 -0
+             return;
+     }
+
+     return;
+}
+

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+/*
+---------------------------------------------------------------------
+--------
+ * DP TX Setup
+ */
+static enum drm_connector_status
+cdns_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+     struct cdns_mhdp_device *mhdp = container_of(connector,
+                                     struct cdns_mhdp_device,

connector.base);

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     u8 hpd = 0xf;
+
+     hpd = cdns_mhdp_read_hpd(mhdp);
+     if (hpd == 1)
+             /* Cable Connected */
+             return connector_status_connected;
+     else if (hpd == 0)
+             /* Cable Disconnedted */
+             return connector_status_disconnected;
+     else {

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+             /* Cable status unknown */
+             DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+             return connector_status_unknown;
+     }
+}
+
+static int cdns_dp_connector_get_modes(struct drm_connector
+*connector) {
+     struct cdns_mhdp_device *mhdp = container_of(connector,
+                                     struct cdns_mhdp_device,

connector.base);

Quoted 17 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +17 -0
+     int num_modes = 0;
+     struct edid *edid;
+
+     edid = drm_do_get_edid(&mhdp->connector.base,
+                                cdns_mhdp_get_edid_block, mhdp);
+     if (edid) {
+             dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+                      edid->header[0], edid->header[1],
+                      edid->header[2], edid->header[3],
+                      edid->header[4], edid->header[5],
+                      edid->header[6], edid->header[7]);
+             drm_connector_update_edid_property(connector, edid);
+             num_modes = drm_add_edid_modes(connector, edid);
+             kfree(edid);
+     }
+
+     if (num_modes == 0)

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+             DRM_ERROR("Invalid edid\n");
+     return num_modes;
+}
+
+static const struct drm_connector_funcs cdns_dp_connector_funcs = {
+     .fill_modes = drm_helper_probe_single_connector_modes,
+     .detect = cdns_dp_connector_detect,
+     .destroy = drm_connector_cleanup,
+     .reset = drm_atomic_helper_connector_reset,
+     .atomic_duplicate_state =

drm_atomic_helper_connector_duplicate_state,

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 225

Quoted 5 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +5 -0
+     .atomic_destroy_state =
+drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs

cdns_dp_connector_helper_funcs = {

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 235

Quoted 7 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +7 -0
+     .get_modes = cdns_dp_connector_get_modes, };
+
+static int cdns_dp_bridge_attach(struct drm_bridge *bridge,
+                              enum drm_bridge_attach_flags flags) {
+     struct cdns_mhdp_device *mhdp = bridge->driver_private;
+     struct drm_encoder *encoder = bridge->encoder;
+     struct drm_connector *connector = &mhdp->connector.base;

New bridge drivers need to support operation without creating a connector

Quoted 9 lines

when the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is set in the flags argument. For an example of how this is done, please see
https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.ke
rnel.org%2Fdri-devel%2F20200526011505.31884-23-laurent.pinchart%2Bren esas%40ideasonboard.com%2F&amp;data=02%7C01%7Csandor.yu%40nxp.co m%7C3bcd86069c2f4203291408d8074da940%7C686ea1d3bc2b4c6fa92cd9 9c5c301635%7C0%7C0%7C637267377438245998&amp;sdata=BYg3bd0%2F KZYHqTTaHGHxkRMDpqwzNCjxFYpo3%2BTa2r4%3D&amp;reserved=0

I will followed the new bridge drivers later, thanks.

Quoted 689 lines

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 9 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +9 -0
+
+     connector->interlace_allowed = 1;
+
+     connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+     drm_connector_helper_add(connector,
+ &cdns_dp_connector_helper_funcs);
+
+     drm_connector_init(bridge->dev, connector,

&cdns_dp_connector_funcs,

Quoted 23 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +23 -0
+                        DRM_MODE_CONNECTOR_DisplayPort);
+
+     drm_connector_attach_encoder(connector, encoder);
+
+     return 0;
+}
+
+static enum drm_mode_status
+cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
+                       const struct drm_display_mode *mode) {
+     enum drm_mode_status mode_status = MODE_OK;
+
+     /* We don't support double-clocked modes */
+     if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+                     mode->flags & DRM_MODE_FLAG_INTERLACE)
+             return MODE_BAD;
+
+     /* MAX support pixel clock rate 594MHz */
+     if (mode->clock > 594000)
+             return MODE_CLOCK_HIGH;
+
+     /* 4096x2160 is not supported */
+     if (mode->hdisplay > 3840)

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+             return MODE_BAD_HVALUE;
+
+     if (mode->vdisplay > 2160)
+             return MODE_BAD_VVALUE;
+
+     return mode_status;
+}
+
+static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
+                                 const struct drm_display_mode

*orig_mode,

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 275

Quoted 1 line
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +1 -0
+                                 const struct drm_display_mode

*mode)

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 3 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +3 -0
+{
+     struct cdns_mhdp_device *mhdp = bridge->driver_private;
+     struct drm_display_info *display_info =

&mhdp->connector.base.display_info;

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +6 -0
+     struct video_info *video = &mhdp->video_info;
+
+     switch (display_info->bpc) {
+     case 10:
+             video->color_depth = 10;
+             break;

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     case 6:
+             video->color_depth = 6;
+             break;
+     default:
+             video->color_depth = 8;
+             break;
+     }
+
+     video->color_fmt = PXL_RGB;
+     video->v_sync_polarity = !!(mode->flags &

DRM_MODE_FLAG_NVSYNC);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 295

Quoted 1 line
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +1 -0
+     video->h_sync_polarity = !!(mode->flags &

DRM_MODE_FLAG_NHSYNC);

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 297

Quoted 2 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +2 -0
+
+     DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay,

mode->clock);

Quoted 11 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +11 -0
+     memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+
+     mutex_lock(&mhdp->lock);
+     cdns_dp_mode_set(mhdp);
+     mutex_unlock(&mhdp->lock);
+}
+
+static void cdn_dp_bridge_enable(struct drm_bridge *bridge) {
+     struct cdns_mhdp_device *mhdp = bridge->driver_private;
+     int ret;
+

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     /* Link trainning */
+     ret = cdns_mhdp_train_link(mhdp);
+     if (ret) {
+             DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
+             return;
+     }
+
+     ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
+     if (ret) {
+             DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n",

ret);

Quoted 9 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +9 -0
+             return;
+     }
+}
+
+static void cdn_dp_bridge_disable(struct drm_bridge *bridge) {
+     struct cdns_mhdp_device *mhdp = bridge->driver_private;
+
+     cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE); }
+

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
+     .attach = cdns_dp_bridge_attach,
+     .enable = cdn_dp_bridge_enable,
+     .disable = cdn_dp_bridge_disable,
+     .mode_set = cdns_dp_bridge_mode_set,
+     .mode_valid = cdns_dp_bridge_mode_valid, };
+
+static void hotplug_work_func(struct work_struct *work) {
+     struct cdns_mhdp_device *mhdp = container_of(work,
+                                        struct cdns_mhdp_device,

hotplug_work.work);

Quoted 63 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +63 -0
+     struct drm_connector *connector = &mhdp->connector.base;
+
+     drm_helper_hpd_irq_event(connector->dev);
+
+     if (connector->status == connector_status_connected) {
+             /* Cable connedted  */
+             DRM_INFO("HDMI/DP Cable Plug In\n");
+             enable_irq(mhdp->irq[IRQ_OUT]);
+     } else if (connector->status == connector_status_disconnected) {
+             /* Cable Disconnedted  */
+             DRM_INFO("HDMI/DP Cable Plug Out\n");
+             enable_irq(mhdp->irq[IRQ_IN]);
+     }
+}
+
+static irqreturn_t cdns_dp_irq_thread(int irq, void *data) {
+     struct cdns_mhdp_device *mhdp = data;
+
+     disable_irq_nosync(irq);
+
+     mod_delayed_work(system_wq, &mhdp->hotplug_work,
+                     msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+     return IRQ_HANDLED;
+}
+
+static int __cdns_dp_probe(struct platform_device *pdev,
+             struct cdns_mhdp_device *mhdp) {
+     struct device *dev = &pdev->dev;
+     struct resource *iores = NULL;
+     int ret;
+
+     mutex_init(&mhdp->lock);
+
+     INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+
+     iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+     if (iores) {
+             mhdp->regs_base = devm_ioremap(dev, iores->start,
+                                            resource_size(iores));
+             if (IS_ERR(mhdp->regs_base))
+                     return -ENOMEM;
+     }
+
+     mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+     if (mhdp->irq[IRQ_IN] < 0) {
+             dev_info(dev, "No plug_in irq number\n");
+     }
+
+     mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+     if (mhdp->irq[IRQ_OUT] < 0) {
+             dev_info(dev, "No plug_out irq number\n");
+     }
+
+     cdns_mhdp_plat_call(mhdp, power_on);
+
+     cdns_mhdp_plat_call(mhdp, firmware_init);
+
+     /* DP FW alive check */
+     ret = cdns_mhdp_check_alive(mhdp);
+     if (ret == false) {
+             DRM_ERROR("NO dp FW running\n");
+             return -ENXIO;

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     }
+
+     /* DP PHY init before AUX init */
+     cdns_mhdp_plat_call(mhdp, phy_set);
+
+     /* Enable Hotplug Detect IRQ thread */
+     irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+     ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+                                     NULL, cdns_dp_irq_thread,
+                                     IRQF_ONESHOT,

dev_name(dev),

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 12 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +12 -0
+                                     mhdp);
+
+     if (ret) {
+             dev_err(dev, "can't claim irq %d\n",
+                             mhdp->irq[IRQ_IN]);
+             return -EINVAL;
+     }
+
+     irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+     ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+                                     NULL, cdns_dp_irq_thread,
+                                     IRQF_ONESHOT,

dev_name(dev),

Quoted 55 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +55 -0
+                                     mhdp);
+
+     if (ret) {
+             dev_err(dev, "can't claim irq %d\n",
+                             mhdp->irq[IRQ_OUT]);
+             return -EINVAL;
+     }
+
+     if (cdns_mhdp_read_hpd(mhdp))
+             enable_irq(mhdp->irq[IRQ_OUT]);
+     else
+             enable_irq(mhdp->irq[IRQ_IN]);
+
+     mhdp->bridge.base.driver_private = mhdp;
+     mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs; #ifdef
+CONFIG_OF
+     mhdp->bridge.base.of_node = dev->of_node; #endif
+
+     dev_set_drvdata(dev, mhdp);
+
+     /* register audio driver */
+     cdns_mhdp_register_audio_driver(dev);
+
+     dp_aux_init(mhdp, dev);
+
+     return 0;
+}
+
+static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp) {
+     dp_aux_destroy(mhdp);
+     cdns_mhdp_unregister_audio_driver(mhdp->dev);
+}
+
+/*
+---------------------------------------------------------------------
+--------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int cdns_dp_probe(struct platform_device *pdev,
+               struct cdns_mhdp_device *mhdp) {
+     int ret;
+
+     ret = __cdns_dp_probe(pdev, mhdp);
+     if (ret)
+             return ret;
+
+     drm_bridge_add(&mhdp->bridge.base);
+
+     return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_probe);
+
+void cdns_dp_remove(struct platform_device *pdev) {
+     struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     drm_bridge_remove(&mhdp->bridge.base);
+
+     __cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_remove);
+
+/*
+---------------------------------------------------------------------
+--------
+ * Bind/unbind API, used from platforms based on the component

framework.

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 489

Quoted 2 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +2 -0
+ */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder

*encoder,

Quoted 14 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +14 -0
+             struct cdns_mhdp_device *mhdp) {
+     int ret;
+
+     ret = __cdns_dp_probe(pdev, mhdp);
+     if (ret < 0)
+             return ret;
+
+     ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0);
+     if (ret) {
+             cdns_dp_remove(pdev);
+             DRM_ERROR("Failed to initialize bridge with drm\n");
+             return ret;
+     }
+

drivers/gpu/drm/bridge/cadence/cdns-dp-core.c line 525

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +10 -0
+     return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_bind);
+
+void cdns_dp_unbind(struct device *dev) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+     __cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_unbind);

Do we really need to support the component framework, can't we just support the DRM bridge API ?

drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c int cdns_mhdp_audio_config(struct

Quoted 20 lines
drivers/gpu/drm/bridge/cadence/cdns-dp-core.c new file +4 -0
+
+MODULE_AUTHOR("Sandor Yu <[email protected]>");
+MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
+MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:cdns-dp");
drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c +3 -0
index 8f51de0672ab..fdd4bcd0d33c 100644
@@ -2,6 +2,9 @@
 /*
  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
  * Author: Chris Zhong <[email protected]>
+ *
+ * Cadence MHDP Audio driver
+ *
  */
 #include <linux/clk.h>
 #include <linux/reset.h>
@@ -196,3 +199,100 @@ int cdns_mhdp_audio_config(struct

cdns_mhdp_device *mhdp,

Quoted 113 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c +90 -0
      return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_audio_config);
+
+static int audio_hw_params(struct device *dev,  void *data,
+                               struct hdmi_codec_daifmt *daifmt,
+                               struct hdmi_codec_params *params) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+     struct audio_info audio = {
+             .sample_width = params->sample_width,
+             .sample_rate = params->sample_rate,
+             .channels = params->channels,
+             .connector_type = mhdp->connector.base.connector_type,
+     };
+     int ret;
+
+     switch (daifmt->fmt) {
+     case HDMI_I2S:
+             audio.format = AFMT_I2S;
+             break;
+     case HDMI_SPDIF:
+             audio.format = AFMT_SPDIF_EXT;
+             break;
+     default:
+             DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
+             ret = -EINVAL;
+             goto out;
+     }
+
+     ret = cdns_mhdp_audio_config(mhdp, &audio);
+     if (!ret)
+             mhdp->audio_info = audio;
+
+out:
+     return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+     int ret;
+
+     ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
+     if (!ret)
+             mhdp->audio_info.format = AFMT_UNUSED; }
+
+static int audio_digital_mute(struct device *dev, void *data,
+                                  bool enable) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+     int ret;
+
+     ret = cdns_mhdp_audio_mute(mhdp, enable);
+
+     return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+                             u8 *buf, size_t len) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+     memcpy(buf, mhdp->connector.base.eld,
+            min(sizeof(mhdp->connector.base.eld), len));
+
+     return 0;
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+     .hw_params = audio_hw_params,
+     .audio_shutdown = audio_shutdown,
+     .digital_mute = audio_digital_mute,
+     .get_eld = audio_get_eld,
+};
+
+int cdns_mhdp_register_audio_driver(struct device *dev) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+     struct hdmi_codec_pdata codec_data = {
+             .i2s = 1,
+             .spdif = 1,
+             .ops = &audio_codec_ops,
+             .max_i2s_channels = 8,
+     };
+
+     mhdp->audio_pdev = platform_device_register_data(
+                           dev, HDMI_CODEC_DRV_NAME, 1,
+                           &codec_data, sizeof(codec_data));
+
+     return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
+}
+
+void cdns_mhdp_unregister_audio_driver(struct device *dev) {
+     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+     platform_device_unregister(mhdp->audio_pdev);
+}
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +0 -11
index efb39cf5f48b..9fd4546c6914 100644
@@ -357,36 +357,6 @@ int cdns_mhdp_set_firmware_active(struct
 cdns_mhdp_device *mhdp, bool enable)  }
 EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
 
-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
-{
-     u8 msg[8];
-     int ret;
-
-     msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
-     msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
-     msg[2] = VOLTAGE_LEVEL_2;
-     msg[3] = PRE_EMPHASIS_LEVEL_3;
-     msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
-     msg[5] = FAST_LT_NOT_SUPPORT;

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c int cdns_mhdp_set_firmware_active(struct · line 380

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +0 -10
-     msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
-     msg[7] = ENHANCED;
-
-     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
-                                  DPTX_SET_HOST_CAPABILITIES,
-                                  sizeof(msg), msg);
-     if (ret)
-             goto err_set_host_cap;
-
-     ret = cdns_mhdp_reg_write(mhdp,

DP_AUX_SWAP_INVERSION_CONTROL,

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)

Quoted 5 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +0 -5
-                                     AUX_HOST_INVERT);
-
-err_set_host_cap:
-     if (ret)
-             DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n",

ret);

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c int cdns_mhdp_config_video(struct

Quoted 7 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +0 -4
-     return ret;
-}
-EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
-
 int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)  {
      u8 msg[5];
@@ -698,3 +668,15 @@ int cdns_mhdp_config_video(struct

cdns_mhdp_device *mhdp)

Quoted 18 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c +9 -0
      return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_config_video);
+
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32
+val) {
+     return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2),
+val); } EXPORT_SYMBOL(cdns_phy_reg_write);
+
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr) {
+     return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2)); }
+EXPORT_SYMBOL(cdns_phy_reg_read);
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h +0 -0
index 1f093a2deaa7..b122bf5f0bdf 100644

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h int cdns_mhdp_reg_write(struct cdns_mhdp_device · line 20

Quoted 1 line
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h +0 -0
@@ -20,4 +20,7 @@ int cdns_mhdp_reg_write(struct cdns_mhdp_device
 *mhdp, u32 addr, u32 val);  int cdns_mhdp_reg_write_bit(struct

cdns_mhdp_device *mhdp, u16 addr,

drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c static int cdns_mhdp_training_start(struct

Quoted 12 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h +3 -0
                                 u8 start_bit, u8 bits_no, u32 val);
 
+/* Audio */
+int cdns_mhdp_register_audio_driver(struct device *dev); void
+cdns_mhdp_unregister_audio_driver(struct device *dev);
 #endif
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +0 -0
index c8160f321aca..8fea072a5568 100644
@@ -108,7 +108,9 @@ static int cdns_mhdp_training_start(struct

cdns_mhdp_device *mhdp)

drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)

Quoted 6 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +2 -1
              if (ret)
                      goto err_training_start;
 
-             if (event[1] & EQ_PHASE_FINISHED)
+             if (event[1] & CLK_RECOVERY_FAILED)
+                     DRM_DEV_ERROR(mhdp->dev, "clock recovery

failed\n");

drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c int cdns_mhdp_train_link(struct

Quoted 5 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +1 -0
+             else if (event[1] & EQ_PHASE_FINISHED)
                      return 0;
      }
 
@@ -172,3 +174,33 @@ int cdns_mhdp_train_link(struct

cdns_mhdp_device *mhdp)

Quoted 14 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +11 -0
      return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_train_link);
+
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp) {
+     u8 msg[8];
+     int ret;
+
+     msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
+     msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
+     msg[2] = VOLTAGE_LEVEL_2;
+     msg[3] = PRE_EMPHASIS_LEVEL_3;
+     msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+     msg[5] = FAST_LT_NOT_SUPPORT;

drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)

Quoted 10 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +10 -0
+     msg[6] = mhdp->lane_mapping;
+     msg[7] = ENHANCED;
+
+     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+                                  DPTX_SET_HOST_CAPABILITIES,
+                                  sizeof(msg), msg);
+     if (ret)
+             goto err_set_host_cap;
+
+     ret = cdns_mhdp_reg_write(mhdp,

DP_AUX_SWAP_INVERSION_CONTROL,

drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)

Quoted 5 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +5 -0
+                                     AUX_HOST_INVERT);
+
+err_set_host_cap:
+     if (ret)
+             DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n",

ret);

drivers/gpu/drm/rockchip/cdn-dp-core.c static int cdn_dp_enable_phy(struct

Quoted 9 lines
drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c +3 -0
+     return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
drivers/gpu/drm/rockchip/cdn-dp-core.c +0 -0
index 06fd82b217b6..d94d22650899 100644
@@ -423,7 +423,12 @@ static int cdn_dp_enable_phy(struct

cdn_dp_device *dp, struct cdn_dp_port *port)

Quoted 39 lines
drivers/gpu/drm/rockchip/cdn-dp-core.c +6 -1
      }
 
      port->lanes = cdn_dp_get_port_lanes(port);
-     ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
+
+     if (property.intval)
+             dp->mhdp.lane_mapping = LANE_MAPPING_FLIPPED;
+     else
+             dp->mhdp.lane_mapping = LANE_MAPPING_NORMAL;
+     ret = cdns_mhdp_set_host_cap(&dp->mhdp);
      if (ret) {
              DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
                            ret);
(quoted diff) +0 -0

b/include/drm/bridge/cdns-mhdp.h index c8170e6048f7..6ffb97e17fae 100644

include/drm/bridge/cdns-mhdp.h +5 -0
@@ -14,6 +14,7 @@
 
 #define ADDR_IMEM            0x10000
 #define ADDR_DMEM            0x20000
+#define ADDR_PHY_AFE 0x80000
 
 /* APB CFG addr */
 #define APB_CTRL                     0
@@ -81,6 +82,10 @@
 #define SOURCE_PIF_SW_RESET          0x30834
 
 /* bellow registers need access by mailbox */
+
+/* source phy comp */
+#define LANES_CONFIG                 0x0814
+
 /* source car addr */
 #define SOURCE_HDTX_CAR                      0x0900
 #define SOURCE_DPTX_CAR                      0x0904
@@ -424,6 +429,16 @@
 /* Reference cycles when using lane clock as reference */

include/drm/bridge/cdns-mhdp.h line 439

Quoted 10 lines
include/drm/bridge/cdns-mhdp.h +8 -0
 #define LANE_REF_CYC                         0x8000
 
+#define HOTPLUG_DEBOUNCE_MS          200
+
+#define IRQ_IN    0
+#define IRQ_OUT   1
+#define IRQ_NUM   2
+
+#define cdns_mhdp_plat_call(mhdp, operation)                 \
+     (!(mhdp) ? -ENODEV : (((mhdp)->plat_data &&

(mhdp)->plat_data->operation) ? \

Quoted 47 lines
include/drm/bridge/cdns-mhdp.h +22 -0
+      (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD))
+
 enum voltage_swing_level {
      VOLTAGE_LEVEL_0,
      VOLTAGE_LEVEL_1,
@@ -504,9 +519,29 @@ struct cdns_mhdp_connector {
      struct cdns_mhdp_bridge *bridge;  };
 
+struct cdns_plat_data {
+     /* Vendor PHY support */
+     int (*bind)(struct platform_device *pdev,
+                     struct drm_encoder *encoder,
+                     struct cdns_mhdp_device *mhdp);
+     void (*unbind)(struct device *dev);
+
+     int (*phy_set)(struct cdns_mhdp_device *mhdp);
+     bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp);
+     int (*firmware_init)(struct cdns_mhdp_device *mhdp);
+     void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
+
+     int (*power_on)(struct cdns_mhdp_device *mhdp);
+     int (*power_off)(struct cdns_mhdp_device *mhdp);
+
+     char *plat_name;
+     int lane_mapping;
+};
+
 struct cdns_mhdp_device {
      struct device *dev;
      struct cdns_mhdp_connector connector;
+     struct cdns_mhdp_bridge bridge;
 
      void __iomem *regs_base;
      struct reset_control *spdif_rst; @@ -520,6 +555,11 @@ struct
 cdns_mhdp_device {
      unsigned int fw_version;
include/drm/bridge/cdns-mhdp.h +5 -0
+     struct delayed_work hotplug_work;
+     u32 lane_mapping;
+     bool power_up;
+     struct mutex lock;
+     int irq[IRQ_NUM];
      union {
              struct _dp_data {
                      u32 rate;

include/drm/bridge/cdns-mhdp.h struct cdns_mhdp_device { · line 575

Quoted 8 lines
include/drm/bridge/cdns-mhdp.h +2 -0
@@ -528,6 +568,8 @@ struct cdns_mhdp_device {
                      u8 dpcd[DP_RECEIVER_CAP_SIZE];
              } dp;
      };
+     const struct cdns_plat_data *plat_data;
+
 };
 
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp); @@

-535,7

Quoted 2 lines

+577,7 @@ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk); int cdns_mhdp_load_firmware(struct

cdns_mhdp_device *mhdp, const u32 *i_mem,

Quoted 8 lines
                          u32 i_size, const u32 *d_mem, u32 d_size);

int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable); -int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip);
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp);
int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp); u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp); int
cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp); @@ -547,10

+589,18

Quoted 8 lines

@@ int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid, int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp); int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active); int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp); +bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
struct audio_info *audio); int
cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);

int

include/drm/bridge/cdns-mhdp.h int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,

Quoted 9 lines

cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,

                         struct audio_info *audio);
include/drm/bridge/cdns-mhdp.h +6 -0
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32
+val);
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+
+/* DP  */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder

*encoder,

include/drm/bridge/cdns-mhdp.h

Quoted 3 lines
include/drm/bridge/cdns-mhdp.h +2 -0
+             struct cdns_mhdp_device *mhdp); void
+cdns_dp_unbind(struct device *dev);
 #endif /* CDNS_MHDP_H_ */

--
Regards,

Laurent Pinchart

#9 lore raw

PATCH 4/7 drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport

In reply to [email protected]

From: Sandor Yu <[email protected]>

Initial support for i.MX8MQ MHDP Displayport.
Add MHDP DP PHY configutation.
The features are same as MHDP DP bridge driver.

---
 drivers/gpu/drm/imx/Kconfig                 |   1 +
 drivers/gpu/drm/imx/Makefile                |   1 +
 drivers/gpu/drm/imx/mhdp/Kconfig            |   8 +
 drivers/gpu/drm/imx/mhdp/Makefile           |   4 +
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c | 390 ++++++++++++++++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c | 130 +++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h    | 146 ++++++++
 7 files changed, 680 insertions(+)
 create mode 100644 drivers/gpu/drm/imx/mhdp/Kconfig
 create mode 100644 drivers/gpu/drm/imx/mhdp/Makefile
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
drivers/gpu/drm/imx/Kconfig +1 -0
index 6231048aa5aa..4af2f575f04b 100644
@@ -41,3 +41,4 @@ config DRM_IMX_HDMI
 	  Choose this if you want to use HDMI on i.MX6.
 
 source "drivers/gpu/drm/imx/dcss/Kconfig"
+source "drivers/gpu/drm/imx/mhdp/Kconfig"
drivers/gpu/drm/imx/Makefile +1 -0
index b644deffe948..0b46c46b19a8 100644
@@ -10,3 +10,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
 
 obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
 obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += mhdp/
drivers/gpu/drm/imx/mhdp/Kconfig new file +8 -0
new file mode 100644
index 000000000000..c9e07a3bf3df
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRM_IMX_CDNS_MHDP
+	tristate "NXP i.MX MX8 DRM DP"
+	select DRM_CDNS_MHDP
+	select DRM_CDNS_DP
+	help
+	  Choose this if you want to use Displayport on i.MX8.
drivers/gpu/drm/imx/mhdp/Makefile new file +4 -0
new file mode 100644
index 000000000000..4383e689445a
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o
+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o
drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c new file +390 -0

390 lines not on this page · raw message

drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c new file +130 -0

130 lines not on this page · raw message

drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h new file +146 -0

146 lines not on this page · raw message

Signature · 1 line
2.17.1
#10 lore raw

PATCH 5/7 drm: bridge: cadence: Initial support for MHDP HDMI bridge driver

In reply to [email protected]

From: Sandor Yu <[email protected]>

This adds initial support for cadence MHDP HDMI bridge driver. Basic HDMI functions are supported, that include:
-Video mode set on-the-fly
-Cable hotplug detect
-MAX support resolution to 3096x2160@60fps
-HDMI audio
-AV infoframe
-EDID read
-SCDC read

---
 drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   3 +-
 .../gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 600 ++++++++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |  14 +
 .../gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   | 330 ++++++++++
 include/drm/bridge/cdns-mhdp.h                |  69 ++
 6 files changed, 1019 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
drivers/gpu/drm/bridge/cadence/Kconfig +4 -0
index b7b8d30b18b6..9bc098302837 100644
@@ -9,3 +9,7 @@ config DRM_CDNS_MHDP
 config DRM_CDNS_DP
 	tristate "Cadence DP DRM driver"
 	depends on DRM_CDNS_MHDP
+
+config DRM_CDNS_HDMI
+	tristate "Cadence HDMI DRM driver"
+	depends on DRM_CDNS_MHDP
drivers/gpu/drm/bridge/cadence/Makefile +2 -1
index cb3c88311a64..1d60166c2bf5 100644
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o cdns-mhdp-hdmi.o
 cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
 obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c new file +600 -0

600 lines not on this page · raw message

drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h +14 -0
index b122bf5f0bdf..fea648070611 100644
@@ -23,4 +23,18 @@ int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
 /* Audio */
 int cdns_mhdp_register_audio_driver(struct device *dev);
 void cdns_mhdp_unregister_audio_driver(struct device *dev);
+
+/* HDMI */
+int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value);
+void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
+					u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type);
+int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp,
+					int protocol, u32 char_rate);
+int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp);
+int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp);
+int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp,
+			struct drm_display_mode *mode, struct video_info *video_info);
+int cdns_hdmi_get_edid_block(void *data, u8 *edid,
+			  u32 block, size_t length);
+
 #endif
drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c new file +330 -0

330 lines not on this page · raw message

include/drm/bridge/cdns-mhdp.h +69 -0

115 lines not on this page · raw message

Signature · 1 line
2.17.1
#11 lore raw

PATCH 6/7 drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI

In reply to [email protected]

From: Sandor Yu <[email protected]>

Add initial support for i.MX8MQ MHDP HDMI.
Add MHDP HDMI PHY configuration.
The features are same as mhdp hdmi bridge driver.

---
 drivers/gpu/drm/imx/mhdp/Kconfig              |   5 +-
 drivers/gpu/drm/imx/mhdp/Makefile             |   2 +-
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 588 ++++++++++++++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c   |  12 +
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h      |   2 +
 5 files changed, 606 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
drivers/gpu/drm/imx/mhdp/Kconfig +3 -2
index c9e07a3bf3df..fc0cf708b900 100644
@@ -1,8 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 config DRM_IMX_CDNS_MHDP
-	tristate "NXP i.MX MX8 DRM DP"
+	tristate "NXP i.MX MX8 DRM DP/HDMI"
 	select DRM_CDNS_MHDP
 	select DRM_CDNS_DP
+	select DRM_CDNS_HDMI
 	help
-	  Choose this if you want to use Displayport on i.MX8.
+	  Choose this if you want to use Displayport/HDMI on i.MX8.
drivers/gpu/drm/imx/mhdp/Makefile +1 -1
index 4383e689445a..ca51a2a9641c 100644
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o
+cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o cdns-mhdp-hdmi-phy.o
 obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o
drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c new file +588 -0

588 lines not on this page · raw message

drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c +12 -0
index 2dec2e051be6..607d0b34b551 100644
@@ -23,6 +23,15 @@ static const struct drm_encoder_funcs cdns_mhdp_imx_encoder_funcs = {
 	.destroy = drm_encoder_cleanup,
 };
 
+static struct cdns_plat_data imx8mq_hdmi_drv_data = {
+	.plat_name = "imx8mq-hdmi",
+	.bind	= cdns_hdmi_bind,
+	.unbind	= cdns_hdmi_unbind,
+	.phy_set = cdns_hdmi_phy_set_imx8mq,
+	.phy_video_valid = cdns_hdmi_phy_mode_valid_imx8mq,
+	.lane_mapping = 0xe4,
+};
+
 static struct cdns_plat_data imx8mq_dp_drv_data = {
 	.plat_name = "imx8mq-dp",
 	.bind	= cdns_dp_bind,
@@ -32,6 +41,9 @@ static struct cdns_plat_data imx8mq_dp_drv_data = {
 };
 
 static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
+	{ .compatible = "nxp,imx8mq-cdns-hdmi",
+	  .data = &imx8mq_hdmi_drv_data
+	},
 	{ .compatible = "nxp,imx8mq-cdns-dp",
 	  .data = &imx8mq_dp_drv_data
 	},
drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h +2 -0
index 79b1907726db..3305a27bcec7 100644
@@ -143,4 +143,6 @@
 #define PHY_PMA_ISO_RX_DATA_HI          0xCC17
 
 int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp);
+bool cdns_hdmi_phy_mode_valid_imx8mq(struct cdns_mhdp_device *mhdp);
 #endif /* _CDNS_MHDP_PHY_H */
Signature · 1 line
2.17.1
#12 lore raw

PATCH 7/7 dt-bindings: display: Document Cadence MHDP HDMI/DP bindings

In reply to [email protected]

From: Sandor Yu <[email protected]>

Document the bindings used for the Cadence MHDP HDMI/DP bridge.

---
 .../bindings/display/bridge/cdns,mhdp.yaml    | 46 +++++++++++++++
 .../devicetree/bindings/display/imx/mhdp.yaml | 59 +++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/mhdp.yaml
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +46 -0
new file mode 100644
index 000000000000..aa23feba744a
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause))
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence MHDP TX Encoder
+
+maintainers:
+  - Sandor Yu <[email protected]>
+
+description: |
+  Cadence MHDP Controller supports one or more of the protocols,
+  such as HDMI and DisplayPort.
+  Each protocol requires a different FW binaries.
+
+  This document defines device tree properties for the Cadence MHDP Encoder
+  (CDNS MHDP TX). It doesn't constitue a device tree binding
+  specification by itself but is meant to be referenced by platform-specific
+  device tree bindings.
+
+  When referenced from platform device tree bindings the properties defined in
+  this document are defined as follows. The platform device tree bindings are
+  responsible for defining whether each property is required or optional.
+
+properties:
+  reg:
+    maxItems: 1
+    description: Memory mapped base address and length of the MHDP TX registers.
+
+  interrupts:
+    maxItems: 2
+
+  interrupt-names:
+    - const: plug_in
+      description: Hotplug detect interrupter for cable plugin event.
+    - const: plug_out
+      description: Hotplug detect interrupter for cable plugout event.
+
+  port:
+    type: object
+    description: |
+      The connectivity of the MHDP TX with the rest of the system is
+      expressed in using ports as specified in the device graph bindings defined
+      in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
+      is platform-specific.
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +59 -0

59 lines not on this page · raw message

Signature · 1 line
2.17.1
#13 lore raw

Re: [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings

Hi Sandor,

Thank you for the patch.

Quoted 8 lines · On Mon, Jun 01, 2020 at 02:17:37PM +0800, [email protected] wrote:

From: Sandor Yu <[email protected]>

Document the bindings used for the Cadence MHDP HDMI/DP bridge.

---
 .../bindings/display/bridge/cdns,mhdp.yaml    | 46 +++++++++++++++
 .../devicetree/bindings/display/imx/mhdp.yaml | 59 +++++++++++++++++++

Please split the patch in two.

Quoted 38 lines
 2 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/mhdp.yaml
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +28 -0
new file mode 100644
index 000000000000..aa23feba744a
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause))
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence MHDP TX Encoder
+
+maintainers:
+  - Sandor Yu <[email protected]>
+
+description: |
+  Cadence MHDP Controller supports one or more of the protocols,
+  such as HDMI and DisplayPort.
+  Each protocol requires a different FW binaries.
+
+  This document defines device tree properties for the Cadence MHDP Encoder
+  (CDNS MHDP TX). It doesn't constitue a device tree binding
+  specification by itself but is meant to be referenced by platform-specific
+  device tree bindings.
+
+  When referenced from platform device tree bindings the properties defined in
+  this document are defined as follows. The platform device tree bindings are
+  responsible for defining whether each property is required or optional.
+
+properties:
+  reg:
+    maxItems: 1

Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml line 38

Quoted 10 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +10 -0
+    description: Memory mapped base address and length of the MHDP TX registers.
+
+  interrupts:
+    maxItems: 2
+
+  interrupt-names:
+    - const: plug_in
+      description: Hotplug detect interrupter for cable plugin event.
+    - const: plug_out
+      description: Hotplug detect interrupter for cable plugout event.

Does the IP core really have two different interrupt lines, one for hot-plug and one for hot-unplug ? That's a very unusual design.

Quoted 22 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +8 -0
+
+  port:
+    type: object
+    description: |
+      The connectivity of the MHDP TX with the rest of the system is
+      expressed in using ports as specified in the device graph bindings defined
+      in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
+      is platform-specific.
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +8 -0
new file mode 100644
index 000000000000..17850cfd1cb1
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/mhdp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence MHDP Encoder
+

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 18

Quoted 10 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +10 -0
+maintainers:
+  - Sandor Yu <[email protected]>
+
+description: |
+  The MHDP transmitter is a Cadence HD Display TX controller IP
+  with a companion PHY IP.
+  The MHDP supports one or more of the protocols,
+  such as HDMI(1.4 & 2.0), DisplayPort(1.2).
+  switching between the two modes (HDMI and DisplayPort)
+  requires reloading the appropriate FW

Does the IP core integrated in the imx8mp SoCs (as that is what this binding targets) support both HDMI and DP ? If not this should be reworded to be more specific to the SoC.

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 24

Quoted 6 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +6 -0
+
+  These DT bindings follow the Cadence MHDP TX bindings defined in
+  Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml with the
+  following device-specific properties.
+
+Properties:

Have you tried validating this with make dt_binding_check ? See Documentation/devicetree/writing-schema.rst for more information.

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 30

Quoted 6 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +6 -0
+  compatible:
+    enum:
+      - nxp,imx8mq-cdns-hdmi
+      - nxp,imx8mq-cdns-dp
+
+  reg: See cdns,mhdp.yaml.

This isn't how bindings are referenced. You need to reference the parent binding with $ref, either globally, or on an individual property basis.

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 34

Quoted 4 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +4 -0
+
+  interrupts: See cdns,mhdp.yaml.
+
+  interrupt-names: See cdns,mhdp.yaml.

That's it ? No clocks, no power domains, no resets, no PHYs (especially given that you mention a PHY companion IP above) ?

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 36

Quoted 2 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +2 -0
+
+  ports: See cdns,mhdp.yaml.

This isn't correct. Please soo of-graph.txt. If can have either one port node, or one ports node that contains one of more port subnodes. In this case you need at least two ports, one for the input to the HDMI encoder, and one for the HDMI output. The latter should be connected to a DT node representing the HDMI connector. Yuo can search for "hdmi-connector" in the .dts files in the kernel for plenty of examples.

Quoted 23 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +23 -0
+
+Required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - ports
+
+Example:
+  - |
+    mhdp: mhdp@32c00000 {
+      compatible = "nxp,imx8mq-cdns-hdmi";
+      reg = <0x32c00000 0x100000>;
+      interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-names = "plug_in", "plug_out";
+
+      ports {
+        mhdp_in: endpoint {
+          remote-endpoint = <&dcss_out>;
+        };
+      };
+    };
Signature · 3 lines
Regards,

Laurent Pinchart
author
#14 lore raw

RE: [EXT] Re: [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings

Hi Laurent,

Thanks your review comments.

Quoted 23 lines

-----Original Message-----
From: Laurent Pinchart <[email protected]>
Sent: Wednesday, June 3, 2020 7:44 AM
To: Sandor Yu <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; dl-linux-imx <[email protected]>
Subject: [EXT] Re: [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings

Caution: EXT Email

Hi Sandor,

Thank you for the patch.

Quoted 4 lines · On Mon, Jun 01, 2020 at 02:17:37PM +0800, [email protected] wrote:

From: Sandor Yu <[email protected]>

Document the bindings used for the Cadence MHDP HDMI/DP bridge.

Quoted 7 lines
Quoted 5 lines
---
 .../bindings/display/bridge/cdns,mhdp.yaml    | 46 +++++++++++++++
 .../devicetree/bindings/display/imx/mhdp.yaml | 59

+++++++++++++++++++

Please split the patch in two.

OK, I will split it later.

Quoted 69 lines
Quoted 16 lines
 2 files changed, 105 insertions(+)
 create mode 100644
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
 create mode 100644

Documentation/devicetree/bindings/display/imx/mhdp.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file mode 100644
index 000000000000..aa23feba744a

Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml line 4

Quoted 4 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +4 -0
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)) %YAML 1.2
+---
+$id:
+https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi

+cetree.org%2Fschemas%2Fdisplay%2Fbridge%2Fcdns%2Cmhdp.yaml%23&a mp;dat

Quoted 1 line

+a=02%7C01%7Csandor.yu%40nxp.com%7C7862af2fa05b490b6fe908d8074eea 14%7C

Quoted 1 line

+686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637267382802978543& amp;sda

Quoted 1 line

+ta=1AoEDe9F2v7fy0RRWkn%2BgEXWgvt78E1D8DqmCf8AsnU%3D&amp;reser ved=0

Quoted 3 lines

+$schema:
+https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi

+cetree.org%2Fmeta-schemas%2Fcore.yaml%23&amp;data=02%7C01%7Csand or.yu

Quoted 1 line

+%40nxp.com%7C7862af2fa05b490b6fe908d8074eea14%7C686ea1d3bc2b4c6f a92cd

Quoted 1 line

+99c5c301635%7C0%7C0%7C637267382802988539&amp;sdata=X5HtTsR2roO %2FyqOI

Quoted 10 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +10 -0
+JbaLy3hEcxjmU5QL5b1UHXOdbLg%3D&amp;reserved=0
+
+title: Cadence MHDP TX Encoder
+
+maintainers:
+  - Sandor Yu <[email protected]>
+
+description: |
+  Cadence MHDP Controller supports one or more of the protocols,
+  such as HDMI and DisplayPort.

Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml

Quoted 10 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +10 -0
+  Each protocol requires a different FW binaries.
+
+  This document defines device tree properties for the Cadence MHDP
+ Encoder  (CDNS MHDP TX). It doesn't constitue a device tree binding
+ specification by itself but is meant to be referenced by
+ platform-specific  device tree bindings.
+
+  When referenced from platform device tree bindings the properties
+ defined in  this document are defined as follows. The platform
+ device tree bindings are  responsible for defining whether each property

is required or optional.

Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml

Quoted 5 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +5 -0
+
+properties:
+  reg:
+    maxItems: 1
+    description: Memory mapped base address and length of the MHDP TX

registers.

Quoted 13 lines

Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml line 38

Quoted 9 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +9 -0
+
+  interrupts:
+    maxItems: 2
+
+  interrupt-names:
+    - const: plug_in
+      description: Hotplug detect interrupter for cable plugin event.
+    - const: plug_out
+      description: Hotplug detect interrupter for cable plugout event.

Does the IP core really have two different interrupt lines, one for hot-plug and one for hot-unplug ? That's a very unusual design.

These two interrupter generated by SOC.
The IP Core haven't provide interrupt lines to SOC, it only provide HPD status in Firmware.

Quoted 52 lines

Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml

Quoted 6 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +6 -0
+
+  port:
+    type: object
+    description: |
+      The connectivity of the MHDP TX with the rest of the system is
+      expressed in using ports as specified in the device graph bindings

defined

Quoted 1 line

+ in Documentation/devicetree/bindings/graph.txt. The numbering of

the ports

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 4

Quoted 13 lines
Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml new file +1 -0
+      is platform-specific.
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +4 -0
new file mode 100644
index 000000000000..17850cfd1cb1
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2
+---
+$id:
+https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi

+cetree.org%2Fschemas%2Fdisplay%2Fbridge%2Fmhdp.yaml%23&amp;data=0 2%7C

Quoted 1 line

+01%7Csandor.yu%40nxp.com%7C7862af2fa05b490b6fe908d8074eea14%7C68 6ea1d

Quoted 1 line

+3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637267382802988539&amp;sdat a=88VM

Documentation/devicetree/bindings/display/imx/mhdp.yaml

Quoted 4 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +3 -0
+M6TP6Sd%2FwGnKsZ7REO1S5FNY5UJ6ll0H5pecNrY%3D&amp;reserved=0
+$schema:
+https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi

+cetree.org%2Fmeta-schemas%2Fcore.yaml%23&amp;data=02%7C01%7Csand or.yu

Quoted 1 line

+%40nxp.com%7C7862af2fa05b490b6fe908d8074eea14%7C686ea1d3bc2b4c6f a92cd

Quoted 1 line

+99c5c301635%7C0%7C0%7C637267382802988539&amp;sdata=X5HtTsR2roO %2FyqOI

Quoted 10 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +10 -0
+JbaLy3hEcxjmU5QL5b1UHXOdbLg%3D&amp;reserved=0
+
+title: Cadence MHDP Encoder
+
+maintainers:
+  - Sandor Yu <[email protected]>
+
+description: |
+  The MHDP transmitter is a Cadence HD Display TX controller IP
+  with a companion PHY IP.
Quoted 9 lines

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 18

Quoted 4 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +4 -0
+  The MHDP supports one or more of the protocols,
+  such as HDMI(1.4 & 2.0), DisplayPort(1.2).
+  switching between the two modes (HDMI and DisplayPort)
+  requires reloading the appropriate FW

Does the IP core integrated in the imx8mp SoCs (as that is what this binding targets) support both HDMI and DP ? If not this should be reworded to be more specific to the SoC.

Yes, the IP core have one MCU, it could run different firmware to support HDMI or DP.

Quoted 10 lines

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 24

Quoted 6 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +6 -0
+
+  These DT bindings follow the Cadence MHDP TX bindings defined in
+ Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml with
+ the  following device-specific properties.
+
+Properties:

Have you tried validating this with make dt_binding_check ? See Documentation/devicetree/writing-schema.rst for more information.

I have run the online yaml checker, I will check it with make dt_binding_check, thanks.

Quoted 9 lines

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 30

Quoted 6 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +6 -0
+  compatible:
+    enum:
+      - nxp,imx8mq-cdns-hdmi
+      - nxp,imx8mq-cdns-dp
+
+  reg: See cdns,mhdp.yaml.

This isn't how bindings are referenced. You need to reference the parent binding with $ref, either globally, or on an individual property basis.

OK

Quoted 9 lines

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 34

Quoted 5 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +4 -0
+
+  interrupts: See cdns,mhdp.yaml.
+
+  interrupt-names: See cdns,mhdp.yaml.

That's it ? No clocks, no power domains, no resets, no PHYs (especially given that you mention a PHY companion IP above) ?

Yes, iMX8MQ HDMI/DP firmware loaded by ROM code for security check,
IP core clock and power will management by ROM code, it will keep in ON status when device bootup. The PHY configurated in platform files, it will generate pixel clock for HDMI controller. So no clocks, power, reset and PHY.

Quoted 9 lines

Documentation/devicetree/bindings/display/imx/mhdp.yaml

Quoted 2 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +2 -0
+
+  ports: See cdns,mhdp.yaml.

This isn't correct. Please soo of-graph.txt. If can have either one port node, or one ports node that contains one of more port subnodes. In this case you need at least two ports, one for the input to the HDMI encoder, and one for the HDMI output. The latter should be connected to a DT node representing the HDMI connector. Yuo can search for "hdmi-connector" in the .dts files in the kernel for plenty of examples.

OK, I will add more information later.

Quoted 28 lines
Quoted 14 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +13 -0
+
+Required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - ports
+
+Example:
+  - |
+    mhdp: mhdp@32c00000 {
+      compatible = "nxp,imx8mq-cdns-hdmi";
+      reg = <0x32c00000 0x100000>;

Documentation/devicetree/bindings/display/imx/mhdp.yaml line 59

Quoted 10 lines
Documentation/devicetree/bindings/display/imx/mhdp.yaml new file +10 -0
+      interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-names = "plug_in", "plug_out";
+
+      ports {
+        mhdp_in: endpoint {
+          remote-endpoint = <&dcss_out>;
+        };
+      };
+    };

--
Regards,

Quoted 1 line

Laurent Pinchart

Regards,
Sandor