Skip to content

Commit

Permalink
drm/bridge: parade-ps8640: Populate devices on aux-bus
Browse files Browse the repository at this point in the history
Conventionally, panel is listed under the root in the device tree.
When userland asks for display mode, ps8640 bridge is responsible
for returning EDID when ps8640_bridge_get_edid() is called.

Now enable a new option of listing the panel under "aux-bus" of ps8640
bridge node in the device tree. In this case, panel driver can retrieve
EDID by triggering AUX transactions, without ps8640_bridge_get_edid()
calls at all.

To prevent the "old" and "new" options from interfering with each
other's logic flow, disable DRM_BRIDGE_OP_EDID when the new option
is taken.

Signed-off-by: Philip Chen <philipchen@chromium.org>
  • Loading branch information
Philip Chen authored and intel-lab-lkp committed Oct 16, 2021
1 parent 7fd94f7 commit 3224ea8
Showing 1 changed file with 40 additions and 12 deletions.
52 changes: 40 additions & 12 deletions drivers/gpu/drm/bridge/parade-ps8640.c
Expand Up @@ -14,6 +14,7 @@
#include <linux/regulator/consumer.h>

#include <drm/drm_bridge.h>
#include <drm/drm_dp_aux_bus.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
Expand Down Expand Up @@ -149,6 +150,24 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
return container_of(aux, struct ps8640, aux);
}

static bool ps8640_of_panel_on_aux_bus(struct device *dev)
{
struct device_node *bus, *panel;

if (!dev->of_node)
return false;

bus = of_get_child_by_name(dev->of_node, "aux-bus");
if (!bus)
return false;

panel = of_get_child_by_name(bus, "panel");
if (!panel)
return false;

return true;
}

static void ps8640_ensure_hpd(struct ps8640 *ps_bridge)
{
struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
Expand Down Expand Up @@ -546,17 +565,6 @@ static int ps8640_probe(struct i2c_client *client)
if (!ps_bridge)
return -ENOMEM;

/* port@1 is ps8640 output port */
ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
if (ret < 0)
return ret;
if (!panel)
return -ENODEV;

ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
if (IS_ERR(ps_bridge->panel_bridge))
return PTR_ERR(ps_bridge->panel_bridge);

ps_bridge->supplies[0].supply = "vdd33";
ps_bridge->supplies[1].supply = "vdd12";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
Expand All @@ -579,9 +587,16 @@ static int ps8640_probe(struct i2c_client *client)

ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
ps_bridge->bridge.of_node = dev->of_node;
ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;
ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP;

/*
* In the device tree, if panel is listed under aux-bus of the bridge
* node, panel driver should be able to retrieve EDID by itself using
* aux-bus. So let's not set DRM_BRIDGE_OP_EDID here.
*/
if (!ps8640_of_panel_on_aux_bus(&client->dev))
ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID;

ps_bridge->page[PAGE0_DP_CNTL] = client;

ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config);
Expand Down Expand Up @@ -615,6 +630,19 @@ static int ps8640_probe(struct i2c_client *client)
if (ret)
return ret;

devm_of_dp_aux_populate_ep_devices(&ps_bridge->aux);

/* port@1 is ps8640 output port */
ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
if (ret < 0)
return ret;
if (!panel)
return -ENODEV;

ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
if (IS_ERR(ps_bridge->panel_bridge))
return PTR_ERR(ps_bridge->panel_bridge);

drm_bridge_add(&ps_bridge->bridge);

return 0;
Expand Down

0 comments on commit 3224ea8

Please sign in to comment.