diff --git a/drivers/mfd/display-serdes/core.h b/drivers/mfd/display-serdes/core.h index b905cbdc79b8..909c12242b53 100644 --- a/drivers/mfd/display-serdes/core.h +++ b/drivers/mfd/display-serdes/core.h @@ -323,12 +323,12 @@ struct serdes_bridge { atomic_t triggered; struct drm_connector connector; struct drm_panel *panel; + struct drm_panel *split_panel; struct device *dev; struct serdes *parent; struct regmap *regmap; struct mipi_dsi_device *dsi; - struct device_node *remote_node; struct drm_display_mode mode; struct backlight_device *backlight; @@ -352,7 +352,6 @@ struct serdes_bridge_split { struct serdes *parent; struct regmap *regmap; struct mipi_dsi_device *dsi; - struct device_node *remote_node; struct drm_display_mode mode; struct backlight_device *backlight; diff --git a/drivers/mfd/display-serdes/serdes-bridge-split.c b/drivers/mfd/display-serdes/serdes-bridge-split.c index e44c51736157..9d049d2e2564 100644 --- a/drivers/mfd/display-serdes/serdes-bridge-split.c +++ b/drivers/mfd/display-serdes/serdes-bridge-split.c @@ -238,11 +238,22 @@ static const struct drm_bridge_funcs serdes_bridge_split_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, }; +static int serdes_bridge_split_parse_dt(struct serdes_bridge_split *serdes_bridge_split) +{ + struct device *dev = serdes_bridge_split->dev; + + serdes_bridge_split->sel_mipi = of_property_read_bool(dev->parent->of_node, "sel-mipi"); + + return 0; +} + static int serdes_bridge_split_probe(struct platform_device *pdev) { struct serdes *serdes = dev_get_drvdata(pdev->dev.parent); + struct device_node *remote_node; struct device *dev = &pdev->dev; struct serdes_bridge_split *serdes_bridge_split; + int ret = 0; if (!serdes->dev || !serdes->chip_data) return -1; @@ -259,22 +270,23 @@ static int serdes_bridge_split_probe(struct platform_device *pdev) if (!serdes_bridge_split->regmap) return dev_err_probe(dev, -ENODEV, "failed to get serdes regmap\n"); - serdes_bridge_split->sel_mipi = of_property_read_bool(dev->parent->of_node, "sel-mipi"); - SERDES_DBG_MFD("%s: sel_mipi=%d\n", __func__, serdes_bridge_split->sel_mipi); - serdes_bridge_split->base_bridge.of_node = dev->parent->of_node; - serdes_bridge_split->remote_node = of_graph_get_remote_node(dev->parent->of_node, 0, -1); - if (!serdes_bridge_split->remote_node) { + remote_node = of_graph_get_remote_node(dev->parent->of_node, 0, -1); + if (!remote_node) { serdes_bridge_split->base_bridge.of_node = dev->of_node; SERDES_DBG_MFD("warning: failed to get remote node for serdes on %s\n", dev_name(dev->parent)); - serdes_bridge_split->remote_node = of_graph_get_remote_node(dev->of_node, 0, -1); - if (!serdes_bridge_split->remote_node) { + remote_node = of_graph_get_remote_node(dev->of_node, 0, -1); + if (!remote_node) { return dev_err_probe(dev, -ENODEV, "failed to get remote node for serdes dsi\n"); } } + ret = serdes_bridge_split_parse_dt(serdes_bridge_split); + if (ret) + goto err_free_node; + serdes_bridge_split->base_bridge.funcs = &serdes_bridge_split_funcs; serdes_bridge_split->base_bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_MODES; @@ -287,7 +299,7 @@ static int serdes_bridge_split_probe(struct platform_device *pdev) SERDES_DBG_MFD("%s: type %d\n", __func__, serdes_bridge_split->base_bridge.type); } else { serdes_bridge_split->base_bridge.type = DRM_MODE_CONNECTOR_eDP; - SERDES_DBG_MFD("%s: type DRM_MODE_CONNECTOR_LVDS\n", __func__); + SERDES_DBG_MFD("%s: type DRM_MODE_CONNECTOR_eDP\n", __func__); } drm_bridge_add(&serdes_bridge_split->base_bridge); @@ -296,19 +308,25 @@ static int serdes_bridge_split_probe(struct platform_device *pdev) dev_info(serdes_bridge_split->dev->parent, "serdes sel_mipi %d\n", serdes_bridge_split->sel_mipi); /* Attach primary DSI */ - serdes_bridge_split->dsi = serdes_attach_dsi(serdes_bridge_split, - serdes_bridge_split->remote_node); + serdes_bridge_split->dsi = serdes_attach_dsi(serdes_bridge_split, remote_node); if (IS_ERR(serdes_bridge_split->dsi)) { drm_bridge_remove(&serdes_bridge_split->base_bridge); - return PTR_ERR(serdes_bridge_split->dsi); + ret = PTR_ERR(serdes_bridge_split->dsi); + goto err_free_node; } } + of_node_put(remote_node); + dev_info(dev, "serdes %s, %s successful mipi=%d, of_node=%s\n", serdes->chip_data->name, __func__, serdes_bridge_split->sel_mipi, serdes_bridge_split->base_bridge.of_node->name); return 0; + +err_free_node: + of_node_put(remote_node); + return ret; } static int serdes_bridge_split_remove(struct platform_device *pdev) diff --git a/drivers/mfd/display-serdes/serdes-bridge.c b/drivers/mfd/display-serdes/serdes-bridge.c index 381c4085938a..f8b051903a25 100644 --- a/drivers/mfd/display-serdes/serdes-bridge.c +++ b/drivers/mfd/display-serdes/serdes-bridge.c @@ -66,10 +66,21 @@ static int serdes_bridge_attach(struct drm_bridge *bridge, struct serdes *serdes = serdes_bridge->parent; int ret = 0; + if (serdes_bridge->split_mode) { + ret = drm_of_find_panel_or_bridge(bridge->of_node, 2, -1, + &serdes_bridge->split_panel, NULL); + if (ret) { + dev_err(serdes_bridge->dev->parent, + "failed to find serdes split bridge or panel, ret=%d\n", ret); + return ret; + } + } + ret = drm_of_find_panel_or_bridge(bridge->of_node, 1, -1, &serdes_bridge->panel, &serdes_bridge->next_bridge); if (ret) { - dev_err(serdes_bridge->dev->parent, "failed to find serdes bridge, ret=%d\n", ret); + dev_err(serdes_bridge->dev->parent, + "failed to find serdes bridge or panel, ret=%d\n", ret); return ret; } @@ -110,6 +121,9 @@ static void serdes_bridge_disable(struct drm_bridge *bridge) if (serdes_bridge->panel) drm_panel_disable(serdes_bridge->panel); + if (serdes_bridge->split_panel) + drm_panel_disable(serdes_bridge->split_panel); + if (serdes->chip_data->bridge_ops->disable) ret = serdes->chip_data->bridge_ops->disable(serdes); @@ -129,6 +143,9 @@ static void serdes_bridge_post_disable(struct drm_bridge *bridge) if (serdes_bridge->panel) ret = drm_panel_unprepare(serdes_bridge->panel); + if (serdes_bridge->split_panel) + ret = drm_panel_unprepare(serdes_bridge->split_panel); + if (serdes->chip_data->bridge_ops->post_disable) ret = serdes->chip_data->bridge_ops->post_disable(serdes); @@ -156,6 +173,9 @@ static void serdes_bridge_pre_enable(struct drm_bridge *bridge) if (serdes_bridge->panel) ret = drm_panel_prepare(serdes_bridge->panel); + if (serdes_bridge->split_panel) + ret = drm_panel_prepare(serdes_bridge->split_panel); + serdes_set_pinctrl_default(serdes); SERDES_DBG_MFD("%s: %s ret=%d\n", __func__, dev_name(serdes->dev), ret); @@ -170,6 +190,9 @@ static void serdes_bridge_enable(struct drm_bridge *bridge) if (serdes_bridge->panel) ret = drm_panel_enable(serdes_bridge->panel); + if (serdes_bridge->split_panel) + ret = drm_panel_enable(serdes_bridge->split_panel); + if (serdes->chip_data->bridge_ops->enable) ret = serdes->chip_data->bridge_ops->enable(serdes); @@ -239,11 +262,44 @@ static const struct drm_bridge_funcs serdes_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, }; +static int serdes_bridge_parse_dt(struct serdes_bridge *serdes_bridge) +{ + unsigned int nr = 0; + struct device_node *ports, *port; + struct device *dev = serdes_bridge->dev; + struct device_node *node = serdes_bridge->base_bridge.of_node; + + serdes_bridge->sel_mipi = of_property_read_bool(dev->parent->of_node, "sel-mipi"); + + ports = of_get_child_by_name(node, "ports"); + if (!ports) + return -EINVAL; + + for_each_available_child_of_node(ports, port) { + if (!of_find_property(port, "reg", NULL)) + continue; + + nr++; + } + + if (nr == 3) + serdes_bridge->split_mode = true; + + if (serdes_bridge->split_mode) + dev_info(dev->parent, "serdes bridge %s work split mode\n", node->name); + + of_node_put(ports); + + return 0; +} + static int serdes_bridge_probe(struct platform_device *pdev) { struct serdes *serdes = dev_get_drvdata(pdev->dev.parent); + struct device_node *remote_node; struct device *dev = &pdev->dev; struct serdes_bridge *serdes_bridge; + int ret = 0; if (!serdes->dev || !serdes->chip_data) return -1; @@ -260,22 +316,23 @@ static int serdes_bridge_probe(struct platform_device *pdev) if (!serdes_bridge->regmap) return dev_err_probe(dev, -ENODEV, "failed to get serdes regmap\n"); - serdes_bridge->sel_mipi = of_property_read_bool(dev->parent->of_node, "sel-mipi"); - SERDES_DBG_MFD("%s: sel_mipi=%d\n", __func__, serdes_bridge->sel_mipi); - serdes_bridge->base_bridge.of_node = dev->parent->of_node; - serdes_bridge->remote_node = of_graph_get_remote_node(dev->parent->of_node, 0, -1); - if (!serdes_bridge->remote_node) { + remote_node = of_graph_get_remote_node(dev->parent->of_node, 0, -1); + if (!remote_node) { serdes_bridge->base_bridge.of_node = dev->of_node; SERDES_DBG_MFD("warning: failed to get remote node for serdes on %s\n", dev_name(dev->parent)); - serdes_bridge->remote_node = of_graph_get_remote_node(dev->of_node, 0, -1); - if (!serdes_bridge->remote_node) { + remote_node = of_graph_get_remote_node(dev->of_node, 0, -1); + if (!remote_node) { return dev_err_probe(dev, -ENODEV, "failed to get remote node for serdes dsi\n"); } } + ret = serdes_bridge_parse_dt(serdes_bridge); + if (ret) + goto err_free_node; + serdes_bridge->base_bridge.funcs = &serdes_bridge_funcs; serdes_bridge->base_bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_MODES; @@ -287,7 +344,7 @@ static int serdes_bridge_probe(struct platform_device *pdev) SERDES_DBG_MFD("%s: type %d\n", __func__, serdes_bridge->base_bridge.type); } else { serdes_bridge->base_bridge.type = DRM_MODE_CONNECTOR_eDP; - SERDES_DBG_MFD("%s: type DRM_MODE_CONNECTOR_LVDS\n", __func__); + SERDES_DBG_MFD("%s: type DRM_MODE_CONNECTOR_eDP\n", __func__); } drm_bridge_add(&serdes_bridge->base_bridge); @@ -296,18 +353,25 @@ static int serdes_bridge_probe(struct platform_device *pdev) dev_info(serdes_bridge->dev->parent, "serdes sel_mipi %d\n", serdes_bridge->sel_mipi); /* Attach primary DSI */ - serdes_bridge->dsi = serdes_attach_dsi(serdes_bridge, serdes_bridge->remote_node); + serdes_bridge->dsi = serdes_attach_dsi(serdes_bridge, remote_node); if (IS_ERR(serdes_bridge->dsi)) { drm_bridge_remove(&serdes_bridge->base_bridge); - return PTR_ERR(serdes_bridge->dsi); + ret = PTR_ERR(serdes_bridge->dsi); + goto err_free_node; } } + of_node_put(remote_node); + dev_info(dev, "serdes %s, serdes_bridge_probe successful mipi=%d, of_node=%s\n", serdes->chip_data->name, serdes_bridge->sel_mipi, serdes_bridge->base_bridge.of_node->name); return 0; + +err_free_node: + of_node_put(remote_node); + return ret; } static int serdes_bridge_remove(struct platform_device *pdev)