Skip to content

Commit a27b6f2

Browse files
Algea Caorkhuangtao
authored andcommitted
drm/bridge: synopsys: dw-hdmi: Support dw-hdmi does not serve as a connector
If dw-hdmi is not used as the final output port, it is only used as a bridge but not a connector. Change-Id: Ie730f47d6075db74c0c54374849fd938c13f5ba8 Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
1 parent 4caa87b commit a27b6f2

1 file changed

Lines changed: 97 additions & 20 deletions

File tree

drivers/gpu/drm/bridge/synopsys/dw-hdmi.c

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ struct dw_hdmi {
216216
struct drm_connector connector;
217217
struct drm_encoder *encoder;
218218
struct drm_bridge bridge;
219+
struct drm_bridge *next_bridge;
219220
struct platform_device *hdcp_dev;
220221
enum dw_hdmi_devtype dev_type;
221222
unsigned int version;
@@ -2522,6 +2523,27 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
25222523
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
25232524
}
25242525

2526+
static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
2527+
{
2528+
struct dw_hdmi *hdmi = bridge->driver_private;
2529+
int ret;
2530+
2531+
if (!hdmi->next_bridge)
2532+
return 0;
2533+
2534+
hdmi->next_bridge->encoder = bridge->encoder;
2535+
2536+
ret = drm_bridge_attach(bridge->dev, hdmi->next_bridge);
2537+
if (ret) {
2538+
DRM_ERROR("Failed to attach bridge with dw-hdmi\n");
2539+
return -EINVAL;
2540+
}
2541+
2542+
bridge->next = hdmi->next_bridge;
2543+
2544+
return 0;
2545+
}
2546+
25252547
static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
25262548
struct drm_display_mode *orig_mode,
25272549
struct drm_display_mode *mode)
@@ -2884,6 +2906,7 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
28842906
};
28852907

28862908
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
2909+
.attach = dw_hdmi_bridge_attach,
28872910
.enable = dw_hdmi_bridge_enable,
28882911
.disable = dw_hdmi_bridge_disable,
28892912
.pre_enable = dw_hdmi_bridge_nop,
@@ -2997,8 +3020,10 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
29973020
check_hdmi_irq(hdmi, intr_stat, phy_int_pol);
29983021

29993022
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
3000-
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
3001-
HDMI_IH_MUTE_PHY_STAT0);
3023+
if (!hdmi->next_bridge)
3024+
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
3025+
HDMI_IH_PHY_STAT0_RX_SENSE),
3026+
HDMI_IH_MUTE_PHY_STAT0);
30023027

30033028
hdcp_stat = hdmi_readb(hdmi, HDMI_A_APIINTSTAT);
30043029
if (hdcp_stat) {
@@ -3204,19 +3229,59 @@ static void dw_hdmi_destroy_properties(struct dw_hdmi *hdmi)
32043229

32053230
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
32063231
{
3232+
struct device *dev = hdmi->dev;
32073233
struct drm_encoder *encoder = hdmi->encoder;
32083234
struct drm_bridge *bridge = &hdmi->bridge;
3235+
struct device_node *endpoint;
32093236
int ret;
32103237

32113238
bridge->driver_private = hdmi;
32123239
bridge->funcs = &dw_hdmi_bridge_funcs;
3240+
3241+
encoder->bridge = bridge;
3242+
3243+
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
3244+
if (endpoint && of_device_is_available(endpoint)) {
3245+
struct device_node *remote;
3246+
3247+
remote = of_graph_get_remote_port_parent(endpoint);
3248+
of_node_put(endpoint);
3249+
if (!remote || !of_device_is_available(remote)) {
3250+
of_node_put(remote);
3251+
return -ENODEV;
3252+
}
3253+
3254+
bridge->encoder = encoder;
3255+
ret = drm_bridge_add(bridge);
3256+
if (ret) {
3257+
dev_err(hdmi->dev, "failed to add bridge: %d\n", ret);
3258+
of_node_put(remote);
3259+
return ret;
3260+
}
3261+
3262+
hdmi->next_bridge = of_drm_find_bridge(remote);
3263+
of_node_put(remote);
3264+
if (!hdmi->next_bridge) {
3265+
dev_err(hdmi->dev, "can't find next bridge\n");
3266+
drm_bridge_remove(bridge);
3267+
return -EPROBE_DEFER;
3268+
}
3269+
3270+
ret = drm_bridge_attach(drm, bridge);
3271+
if (ret) {
3272+
dev_err(hdmi->dev, "can't attach bridge with drm\n");
3273+
return ret;
3274+
}
3275+
3276+
return 0;
3277+
}
3278+
32133279
ret = drm_bridge_attach(drm, bridge);
32143280
if (ret) {
32153281
DRM_ERROR("Failed to initialize bridge with drm\n");
32163282
return -EINVAL;
32173283
}
32183284

3219-
encoder->bridge = bridge;
32203285
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
32213286
hdmi->connector.port = hdmi->dev->of_node;
32223287

@@ -3597,7 +3662,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
35973662
hdmi->encoder = encoder;
35983663
hdmi->disabled = true;
35993664
hdmi->rxsense = true;
3600-
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
3665+
36013666
hdmi->irq = irq;
36023667
hdmi->mc_clkdis = 0x7f;
36033668

@@ -3768,9 +3833,6 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
37683833
/* Re-init HPD polarity */
37693834
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
37703835

3771-
/* Unmask HPD, clear transitory interrupts, then unmute */
3772-
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
3773-
37743836
if (hdmi->dev_type == RK3288_HDMI && hdmi->version == 0x200a)
37753837
hdmi->connector.ycbcr_420_allowed = false;
37763838
else
@@ -3780,13 +3842,24 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
37803842
if (ret)
37813843
goto err_iahb;
37823844

3845+
if (!hdmi->next_bridge) {
3846+
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
37833847
#ifdef CONFIG_SWITCH
3784-
hdmi->switchdev.name = "hdmi";
3785-
switch_dev_register(&hdmi->switchdev);
3848+
hdmi->switchdev.name = "hdmi";
3849+
switch_dev_register(&hdmi->switchdev);
3850+
37863851
#endif
3852+
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
3853+
HDMI_IH_PHY_STAT0_RX_SENSE),
3854+
HDMI_IH_MUTE_PHY_STAT0);
3855+
} else {
3856+
hdmi->sink_is_hdmi = true;
3857+
hdmi->sink_has_audio = true;
3858+
hdmi->phy_mask = 0xff;
3859+
}
37873860

3788-
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
3789-
HDMI_IH_MUTE_PHY_STAT0);
3861+
/* Unmask HPD, clear transitory interrupts, then unmute */
3862+
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
37903863

37913864
/* Unmute I2CM interrupts and reset HDMI DDC I2C master controller */
37923865
if (hdmi->i2c)
@@ -3911,11 +3984,13 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
39113984
if (hdmi->cec_notifier)
39123985
cec_notifier_put(hdmi->cec_notifier);
39133986

3987+
if (!hdmi->next_bridge) {
39143988
#ifdef CONFIG_SWITCH
3915-
switch_dev_unregister(&hdmi->switchdev);
3989+
switch_dev_unregister(&hdmi->switchdev);
39163990
#endif
3917-
dw_hdmi_destroy_properties(hdmi);
3918-
hdmi->connector.funcs->destroy(&hdmi->connector);
3991+
dw_hdmi_destroy_properties(hdmi);
3992+
hdmi->connector.funcs->destroy(&hdmi->connector);
3993+
}
39193994
hdmi->encoder->funcs->destroy(hdmi->encoder);
39203995

39213996
clk_disable_unprepare(hdmi->iahb_clk);
@@ -3941,12 +4016,14 @@ static void dw_hdmi_reg_initial(struct dw_hdmi *hdmi)
39414016
HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
39424017
HDMI_PHY_I2CM_CTLINT_ADDR);
39434018

3944-
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
3945-
HDMI_PHY_POL0);
3946-
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
3947-
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
3948-
HDMI_IH_PHY_STAT0_RX_SENSE),
3949-
HDMI_IH_MUTE_PHY_STAT0);
4019+
if (!hdmi->next_bridge) {
4020+
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
4021+
HDMI_PHY_POL0);
4022+
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
4023+
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
4024+
HDMI_IH_PHY_STAT0_RX_SENSE),
4025+
HDMI_IH_MUTE_PHY_STAT0);
4026+
}
39504027
}
39514028
}
39524029

0 commit comments

Comments
 (0)