drm/rockchip: cdn-dp: support get hpd by gpio

DPTX may use tcphy0 or tcphy1. If hardware design support
both tcphy0 and tcphy1, then each phy port need a hpd line.
For example, tcphy0 port use GPIO1B5 and tcphy1 port use
GPIO1B6, it should config dts as follow:
&cdn_dp {
	...
	pinctrl-names = "default";
	pinctrl-0 = <&cnd_dp_hpd>;
	hpd-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>,
		    <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
	phys = <&tcphy0_dp>, <&tcphy1_dp>;
	...
};

&pinctrl {
	...
	dp {
		cdn_dp_hpd: cdn-dp-hpd {
			rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>,
					<1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
		};
	};
	...
};

If only 1 phy port can be used for DPTX, For example, using
tcphy0 and GPIO1B5 as hpd pin. It should config dts as follow:
&cdn_dp {
	...
	pinctrl-names = "default";
	pinctrl-0 = <&cnd_dp_hpd>;
	hpd-gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
	phys = <&tcphy0_dp>;
	...
};

&pinctrl {
	...
	dp {
		cdn_dp_hpd: cdn-dp-hpd {
			rockchip,pins = <1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
		};
	};
	...
};

Change-Id: Id1acc428431bb13d7074e9daaab2fcca2ac2782e
Signed-off-by: Zhang Yubing <yubing.zhang@rock-chips.com>
This commit is contained in:
Zhang Yubing
2024-07-15 09:36:03 +08:00
parent a19d0c9b36
commit 14cf391f07
2 changed files with 66 additions and 0 deletions

View File

@@ -6,7 +6,9 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/gpio/consumer.h>
#include <linux/firmware.h>
#include <linux/irq.h>
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
@@ -150,6 +152,9 @@ static void cdn_dp_clk_disable(struct cdn_dp_device *dp)
static int cdn_dp_get_port_lanes(struct cdn_dp_port *port)
{
if (port->hpd_gpio && !gpiod_get_value_cansleep(port->hpd_gpio))
return 0;
return phy_get_bus_width(port->phy);
}
@@ -776,6 +781,15 @@ static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
static int cdn_dp_encoder_late_register(struct drm_encoder *encoder)
{
struct cdn_dp_device *dp = encoder_to_dp(encoder);
int i;
for (i = 0; i < dp->ports; i++) {
if (!dp->port[i])
continue;
if (dp->port[i]->hpd_gpio)
enable_irq(dp->port[i]->hpd_irq);
}
dp->registered = true;
schedule_delayed_work(&dp->event_work, 0);
@@ -786,6 +800,15 @@ static int cdn_dp_encoder_late_register(struct drm_encoder *encoder)
static void cdn_dp_encoder_early_unregister(struct drm_encoder *encoder)
{
struct cdn_dp_device *dp = encoder_to_dp(encoder);
int i;
for (i = 0; i < dp->ports; i++) {
if (!dp->port[i])
continue;
if (dp->port[i]->hpd_gpio)
disable_irq(dp->port[i]->hpd_irq);
}
dp->registered = false;
barrier();
@@ -1033,6 +1056,16 @@ out:
return ret;
}
static irqreturn_t cdn_dp_hpd_irq_handler(int irq, void *arg)
{
struct cdn_dp_port *port = arg;
struct cdn_dp_device *dp = port->dp;
schedule_delayed_work(&dp->event_work, 0);
return IRQ_HANDLED;
}
static void cdn_dp_pd_event_work(struct work_struct *work)
{
struct cdn_dp_device *dp = container_of(to_delayed_work(work), struct cdn_dp_device,
@@ -1309,6 +1342,36 @@ static int cdn_dp_probe(struct platform_device *pdev)
return -EINVAL;
}
for (i = 0; i < dp->ports; i++) {
if (!dp->port[i])
continue;
port = dp->port[i];
port->hpd_gpio = devm_gpiod_get_index_optional(dev, "hpd", i, GPIOD_IN);
if (IS_ERR(port->hpd_gpio)) {
DRM_DEV_ERROR(dev, "failed to get port%d hpd gpio\n", i);
return PTR_ERR(port->hpd_gpio);
}
if (port->hpd_gpio) {
port->hpd_irq = gpiod_to_irq(port->hpd_gpio);
if (port->hpd_irq < 0) {
DRM_DEV_ERROR(dev, "failed to get port%d hpd irq\n", i);
return port->hpd_irq;
}
ret = devm_request_irq(dev, port->hpd_irq, cdn_dp_hpd_irq_handler,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_NO_AUTOEN, "cdn-dp-hpd", port);
if (ret) {
DRM_DEV_ERROR(dev, "failed to request HPD interrupt\n");
return ret;
}
}
}
mutex_init(&dp->lock);
dev_set_drvdata(dev, dp);

View File

@@ -58,6 +58,9 @@ struct cdn_dp_port {
u8 lanes;
bool phy_enabled;
u8 id;
struct gpio_desc *hpd_gpio;
int hpd_irq;
};
struct cdn_dp_device {