mfd: display-serdes: Add serdes split mode support

Originally, there was no DRM framework to invoke the serdes enablement
process

Change-Id: I5ab31c2f712cf410c1537f5ef2dffbaa015d14ee
Signed-off-by: Zitong Cai <zitong.cai@rock-chips.com>
This commit is contained in:
Zitong Cai
2025-09-09 10:53:56 +08:00
committed by Tao Huang
parent e952ddd906
commit a50711af9b
3 changed files with 105 additions and 24 deletions

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)