mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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>
This commit is contained in:
@@ -260,6 +260,7 @@ struct dw_hdmi_phy_data {
|
||||
struct dw_hdmi {
|
||||
struct drm_connector connector;
|
||||
struct drm_bridge bridge;
|
||||
struct drm_bridge *next_bridge;
|
||||
struct platform_device *hdcp_dev;
|
||||
|
||||
unsigned int version;
|
||||
@@ -1749,14 +1750,16 @@ void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
|
||||
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
|
||||
HDMI_IH_PHY_STAT0);
|
||||
|
||||
/* Enable cable hot plug irq. */
|
||||
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
|
||||
if (!hdmi->next_bridge) {
|
||||
/* Enable cable hot plug irq. */
|
||||
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
|
||||
|
||||
/* Clear and unmute interrupts. */
|
||||
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
|
||||
HDMI_IH_PHY_STAT0);
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
/* Clear and unmute interrupts. */
|
||||
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
|
||||
HDMI_IH_PHY_STAT0);
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_hdmi_phy_setup_hpd);
|
||||
|
||||
@@ -2964,18 +2967,32 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
struct drm_encoder *encoder = bridge->encoder;
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
int ret;
|
||||
|
||||
connector->interlace_allowed = 1;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
if (!hdmi->next_bridge) {
|
||||
connector->interlace_allowed = 1;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
|
||||
drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
|
||||
|
||||
drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
dw_hdmi_attach_properties(hdmi);
|
||||
dw_hdmi_attach_properties(hdmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hdmi->next_bridge->encoder = bridge->encoder;
|
||||
ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge, bridge);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to attach bridge with dw-hdmi\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bridge->next = hdmi->next_bridge;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2988,6 +3005,9 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
struct drm_connector *connector = &hdmi->connector;
|
||||
enum drm_mode_status mode_status = MODE_OK;
|
||||
|
||||
if (hdmi->next_bridge)
|
||||
return MODE_OK;
|
||||
|
||||
if (hdmi->plat_data->mode_valid)
|
||||
mode_status = hdmi->plat_data->mode_valid(connector, mode);
|
||||
|
||||
@@ -3154,8 +3174,10 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
|
||||
check_hdmi_irq(hdmi, intr_stat, phy_int_pol);
|
||||
|
||||
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
if (!hdmi->next_bridge)
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
|
||||
HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
|
||||
hdcp_stat = hdmi_readb(hdmi, HDMI_A_APIINTSTAT);
|
||||
if (hdcp_stat) {
|
||||
@@ -3608,6 +3630,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *endpoint;
|
||||
struct platform_device_info pdevinfo;
|
||||
struct device_node *ddc_node;
|
||||
struct dw_hdmi_cec_data cec;
|
||||
@@ -3819,6 +3842,30 @@ __dw_hdmi_probe(struct platform_device *pdev,
|
||||
hdmi->bridge.of_node = pdev->dev.of_node;
|
||||
#endif
|
||||
|
||||
endpoint = of_graph_get_endpoint_by_regs(hdmi->dev->of_node, 1, -1);
|
||||
if (endpoint && of_device_is_available(endpoint)) {
|
||||
struct device_node *remote;
|
||||
|
||||
remote = of_graph_get_remote_port_parent(endpoint);
|
||||
of_node_put(endpoint);
|
||||
if (!remote || !of_device_is_available(remote)) {
|
||||
of_node_put(remote);
|
||||
ret = -ENODEV;
|
||||
goto err_iahb;
|
||||
}
|
||||
|
||||
hdmi->next_bridge = of_drm_find_bridge(remote);
|
||||
of_node_put(remote);
|
||||
if (!hdmi->next_bridge) {
|
||||
dev_err(hdmi->dev, "can't find next bridge\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_iahb;
|
||||
}
|
||||
|
||||
hdmi->sink_is_hdmi = true;
|
||||
hdmi->sink_has_audio = true;
|
||||
}
|
||||
|
||||
dw_hdmi_setup_i2c(hdmi);
|
||||
if (hdmi->phy.ops->setup_hpd)
|
||||
hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
|
||||
@@ -3960,9 +4007,13 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
|
||||
/* Disable all interrupts */
|
||||
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
|
||||
|
||||
dw_hdmi_destroy_properties(hdmi);
|
||||
hdmi->connector.funcs->destroy(&hdmi->connector);
|
||||
hdmi->bridge.encoder->funcs->destroy(hdmi->bridge.encoder);
|
||||
if (!hdmi->next_bridge) {
|
||||
dw_hdmi_destroy_properties(hdmi);
|
||||
hdmi->connector.funcs->destroy(&hdmi->connector);
|
||||
}
|
||||
|
||||
if (hdmi->bridge.encoder)
|
||||
hdmi->bridge.encoder->funcs->destroy(hdmi->bridge.encoder);
|
||||
|
||||
if (hdmi->cec_notifier)
|
||||
cec_notifier_put(hdmi->cec_notifier);
|
||||
@@ -4020,11 +4071,13 @@ struct dw_hdmi *dw_hdmi_bind(struct platform_device *pdev,
|
||||
|
||||
ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
|
||||
if (ret) {
|
||||
dw_hdmi_remove(hdmi);
|
||||
__dw_hdmi_remove(hdmi);
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
plat_data->connector = &hdmi->connector;
|
||||
|
||||
if (!hdmi->next_bridge)
|
||||
plat_data->connector = &hdmi->connector;
|
||||
|
||||
return hdmi;
|
||||
}
|
||||
@@ -4047,12 +4100,14 @@ static void dw_hdmi_reg_initial(struct dw_hdmi *hdmi)
|
||||
HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
|
||||
HDMI_PHY_I2CM_CTLINT_ADDR);
|
||||
|
||||
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
|
||||
HDMI_PHY_POL0);
|
||||
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
|
||||
HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
if (!hdmi->next_bridge) {
|
||||
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
|
||||
HDMI_PHY_POL0);
|
||||
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
|
||||
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
|
||||
HDMI_IH_PHY_STAT0_RX_SENSE),
|
||||
HDMI_IH_MUTE_PHY_STAT0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1534,9 +1534,11 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
|
||||
clk_disable_unprepare(hdmi->hclk_vop);
|
||||
}
|
||||
|
||||
hdmi->sub_dev.connector = plat_data->connector;
|
||||
hdmi->sub_dev.of_node = dev->of_node;
|
||||
rockchip_drm_register_sub_dev(&hdmi->sub_dev);
|
||||
if (plat_data->connector) {
|
||||
hdmi->sub_dev.connector = plat_data->connector;
|
||||
hdmi->sub_dev.of_node = dev->of_node;
|
||||
rockchip_drm_register_sub_dev(&hdmi->sub_dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1546,7 +1548,8 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
|
||||
{
|
||||
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
|
||||
|
||||
rockchip_drm_unregister_sub_dev(&hdmi->sub_dev);
|
||||
if (hdmi->sub_dev.connector)
|
||||
rockchip_drm_unregister_sub_dev(&hdmi->sub_dev);
|
||||
dw_hdmi_unbind(hdmi->hdmi);
|
||||
clk_disable_unprepare(hdmi->phyref_clk);
|
||||
clk_disable_unprepare(hdmi->hclk_vop);
|
||||
|
||||
Reference in New Issue
Block a user