2024-05-03 16:41:30

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 00/10] drm/bridge: Allow using fwnode API to get the next bridge

Currently, the various display bridge drivers rely on OF infrastructures
to works very well, yet there are platforms and/or devices absence of 'OF'
support. Such as virtual display drivers, USB display apapters and ACPI
based systems etc.

Add fwnode based helpers to fill the niche, this allows part of the display
bridge drivers to work across systems. As the fwnode API has wider coverage
than DT counterpart and the fwnode graphs are compatible with the OF graph,
so the provided helpers can be used on all systems in theory. Assumed that
the system has valid fwnode graphs established before drm bridge drivers
are probed, and there has fwnode assigned to involved drm bridge instance.

Tested on TI BeaglePlay board.

v1 -> v2:
* Modify it66121 to switch togather
* Drop the 'side-by-side' implement
* Add drm_bridge_find_next_bridge_by_fwnode() helper
* Add drm_bridge_set_node() helper

v2 -> v3:
* Read kernel-doc and improve function comments (Dmitry)
* Drop the 'port' argument of it66121_read_bus_width() (Dmitry)
* drm-bridge: sii902x get nuked

v3 -> v4:
* drm-bridge: tfp410 get nuked
* Add platform module alias
* Rebase and improve commit message and function comments

v4 -> v5:
* Modify sii9234, ch7033 and ANX7688
* Trivial fixes

Sui Jingfeng (10):
drm/bridge: Allow using fwnode APIs to get the next bridge
drm/bridge: Add a helper to setup both the of_node and fwnode of drm
bridge
drm/bridge: simple-bridge: Use fwnode APIs to acquire device
properties
drm/bridge: display-connector: Use fwnode APIs to acquire device
properties
drm/bridge: sii902x: Switch to use fwnode APIs to acquire device
properties
drm-bridge: it66121: Use fwnode APIs to acquire device properties
drm/bridge: tfp410: Use fwnode APIs to acquire device properties
drm/bridge: sii9234: Use fwnode APIs to abstract DT dependent API away
drm/bridge: ch7033: Switch to use fwnode based APIs
drm/bridge: anx7688: Switch to use drm_bridge_set_node() helper

drivers/gpu/drm/bridge/chrontel-ch7033.c | 14 ++--
drivers/gpu/drm/bridge/cros-ec-anx7688.c | 3 +-
drivers/gpu/drm/bridge/display-connector.c | 25 ++++----
drivers/gpu/drm/bridge/ite-it66121.c | 57 ++++++++++-------
drivers/gpu/drm/bridge/sii902x.c | 45 +++++--------
drivers/gpu/drm/bridge/sii9234.c | 8 ++-
drivers/gpu/drm/bridge/simple-bridge.c | 23 +++----
drivers/gpu/drm/bridge/ti-tfp410.c | 41 ++++++------
drivers/gpu/drm/drm_bridge.c | 74 ++++++++++++++++++++++
include/drm/drm_bridge.h | 18 +++++-
10 files changed, 201 insertions(+), 107 deletions(-)

--
2.34.1



2024-05-03 16:41:43

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 01/10] drm/bridge: Allow using fwnode APIs to get the next bridge

The various display bridge drivers rely on 'OF' infrastructures to
works very well, yet there are some platforms and/or devices lack of
'OF' support. Such as virtual display drivers, USB display apapters
and ACPI based systems etc.

Add fwnode based helpers to fill the niche, this allows part of display
bridge drivers to work across systems. As the fwnode APIs has wider
coverage than DT counterpart, and fwnode graphs are compatible with
OF graphs. So the newly created helpers can be used on all systems
in theory, assumed that there has valid OF/fwnode graphs established.

Note, the involved drm bridge instance should also has the fwnode
assigned, so that the user of it could find it via the fwnode handle.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/drm_bridge.c | 74 ++++++++++++++++++++++++++++++++++++
include/drm/drm_bridge.h | 8 ++++
2 files changed, 82 insertions(+)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 28abe9aa99ca..fc1a314140e7 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1368,6 +1368,80 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)
EXPORT_SYMBOL(of_drm_find_bridge);
#endif

+/**
+ * drm_bridge_find_by_fwnode - Find the bridge corresponding to the fwnode
+ *
+ * @fwnode: fwnode for which to find the matching drm_bridge
+ *
+ * This function looks up a drm_bridge in the global bridge list, based on
+ * its associated fwnode. Drivers who want to use this function should has
+ * fwnode handle assigned to the fwnode member of the struct drm_bridge
+ * instance.
+ *
+ * Returns:
+ * * A reference to the requested drm_bridge object on success, or
+ * * %NULL otherwise (object does not exist or the driver of requested
+ * bridge not probed yet).
+ */
+struct drm_bridge *drm_bridge_find_by_fwnode(struct fwnode_handle *fwnode)
+{
+ struct drm_bridge *ret = NULL;
+ struct drm_bridge *bridge;
+
+ if (!fwnode)
+ return NULL;
+
+ mutex_lock(&bridge_lock);
+
+ list_for_each_entry(bridge, &bridge_list, list) {
+ if (bridge->fwnode == fwnode) {
+ ret = bridge;
+ break;
+ }
+ }
+
+ mutex_unlock(&bridge_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(drm_bridge_find_by_fwnode);
+
+/**
+ * drm_bridge_find_next_bridge_by_fwnode - Find the next bridge by fwnode
+ * @fwnode: fwnode pointer to the current device.
+ * @port: identifier of the port node of the next bridge is connected.
+ *
+ * This function find the next bridge at the current node, it assumed that
+ * there has valid fwnode graph established.
+ *
+ * Returns:
+ * * A reference to the requested drm_bridge object on success, or
+ * * -%EINVAL or -%ENODEV if the fwnode graph or OF graph is not complete, or
+ * * %NULL if object does not exist or the next bridge is not probed yet.
+ */
+struct drm_bridge *
+drm_bridge_find_next_bridge_by_fwnode(struct fwnode_handle *fwnode, u32 port)
+{
+ struct drm_bridge *bridge;
+ struct fwnode_handle *ep;
+ struct fwnode_handle *remote;
+
+ ep = fwnode_graph_get_endpoint_by_id(fwnode, port, 0, 0);
+ if (!ep)
+ return ERR_PTR(-EINVAL);
+
+ remote = fwnode_graph_get_remote_port_parent(ep);
+ fwnode_handle_put(ep);
+ if (!remote)
+ return ERR_PTR(-ENODEV);
+
+ bridge = drm_bridge_find_by_fwnode(remote);
+ fwnode_handle_put(remote);
+
+ return bridge;
+}
+EXPORT_SYMBOL_GPL(drm_bridge_find_next_bridge_by_fwnode);
+
MODULE_AUTHOR("Ajay Kumar <[email protected]>");
MODULE_DESCRIPTION("DRM bridge infrastructure");
MODULE_LICENSE("GPL and additional rights");
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 4baca0d9107b..a1bb19425761 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -721,6 +721,8 @@ struct drm_bridge {
struct list_head chain_node;
/** @of_node: device node pointer to the bridge */
struct device_node *of_node;
+ /** @fwnode: fwnode pointer to the bridge */
+ struct fwnode_handle *fwnode;
/** @list: to keep track of all added bridges */
struct list_head list;
/**
@@ -797,6 +799,12 @@ static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np)
}
#endif

+struct drm_bridge *
+drm_bridge_find_by_fwnode(struct fwnode_handle *fwnode);
+
+struct drm_bridge *
+drm_bridge_find_next_bridge_by_fwnode(struct fwnode_handle *fwnode, u32 port);
+
/**
* drm_bridge_get_next_bridge() - Get the next bridge in the chain
* @bridge: bridge object
--
2.34.1


2024-05-03 16:42:08

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 02/10] drm/bridge: Add a helper to setup both the of_node and fwnode of drm bridge

The newly added helper is drm_bridge_set_node(), the reason behind of this
introduction is that the name 'of_node' itself has a smell of DT dependent,
when we are going to make drivers truly DT independent, we have to has a
way to hide it from its user referencing and/or dereferencing.

Please note that the introduction of drm_bridge_set_node() is actually
trying to follow the convention used by driver core, see device_set_node()
for reference.

While at it, include the of.h header as the drm_bridge struct always has
the of_node as its member. Therefore drop the forward declaration.

Signed-off-by: Sui Jingfeng <[email protected]>
---
include/drm/drm_bridge.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index a1bb19425761..b18e7c2f62c9 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -26,14 +26,13 @@
#include <linux/ctype.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/of.h>

#include <drm/drm_atomic.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_modes.h>

-struct device_node;
-
struct drm_bridge;
struct drm_bridge_timings;
struct drm_connector;
@@ -790,6 +789,13 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
struct drm_bridge *previous,
enum drm_bridge_attach_flags flags);

+static inline void
+drm_bridge_set_node(struct drm_bridge *bridge, struct fwnode_handle *fwnode)
+{
+ bridge->fwnode = fwnode;
+ bridge->of_node = to_of_node(fwnode);
+}
+
#ifdef CONFIG_OF
struct drm_bridge *of_drm_find_bridge(struct device_node *np);
#else
--
2.34.1


2024-05-03 16:42:16

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 03/10] drm/bridge: simple-bridge: Use fwnode APIs to acquire device properties

Make this driver less DT-dependent by calling the newly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
A side benifit is that boilerplates get reduced, no functional changes
for DT-based systems.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/simple-bridge.c | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index 5813a2c4fc5e..865ddd38f371 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -8,8 +8,6 @@

#include <linux/gpio/consumer.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>

@@ -169,33 +167,32 @@ static const struct drm_bridge_funcs simple_bridge_bridge_funcs = {

static int simple_bridge_probe(struct platform_device *pdev)
{
+ struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
struct simple_bridge *sbridge;
- struct device_node *remote;
+ int ret;

sbridge = devm_kzalloc(&pdev->dev, sizeof(*sbridge), GFP_KERNEL);
if (!sbridge)
return -ENOMEM;
platform_set_drvdata(pdev, sbridge);

- sbridge->info = of_device_get_match_data(&pdev->dev);
+ sbridge->info = device_get_match_data(&pdev->dev);

/* Get the next bridge in the pipeline. */
- remote = of_graph_get_remote_node(pdev->dev.of_node, 1, -1);
- if (!remote)
- return -EINVAL;
-
- sbridge->next_bridge = of_drm_find_bridge(remote);
- of_node_put(remote);
-
+ sbridge->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
if (!sbridge->next_bridge) {
dev_dbg(&pdev->dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
+ } else if (IS_ERR(sbridge->next_bridge)) {
+ ret = PTR_ERR(sbridge->next_bridge);
+ dev_err(&pdev->dev, "Error on finding the next bridge: %d\n", ret);
+ return ret;
}

/* Get the regulator and GPIO resources. */
sbridge->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
if (IS_ERR(sbridge->vdd)) {
- int ret = PTR_ERR(sbridge->vdd);
+ ret = PTR_ERR(sbridge->vdd);
if (ret == -EPROBE_DEFER)
return -EPROBE_DEFER;
sbridge->vdd = NULL;
@@ -209,8 +206,8 @@ static int simple_bridge_probe(struct platform_device *pdev)
"Unable to retrieve enable GPIO\n");

/* Register the bridge. */
+ drm_bridge_set_node(&sbridge->bridge, fwnode);
sbridge->bridge.funcs = &simple_bridge_bridge_funcs;
- sbridge->bridge.of_node = pdev->dev.of_node;
sbridge->bridge.timings = sbridge->info->timings;

drm_bridge_add(&sbridge->bridge);
--
2.34.1


2024-05-03 16:42:42

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 05/10] drm/bridge: sii902x: Switch to use fwnode APIs to acquire device properties

Make this driver less DT-dependent by calling the freshly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
One side benifit is that boilerplates get reduced, no functional changes
for DT-based systems.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/sii902x.c | 45 ++++++++++++--------------------
1 file changed, 16 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 8f84e98249c7..bc906b71c793 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -827,20 +827,17 @@ static int sii902x_audio_codec_init(struct sii902x *sii902x,
.spdif = 0,
.max_i2s_channels = 0,
};
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
u8 lanes[4];
int num_lanes, i;

- if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
+ if (!fwnode_property_present(fwnode, "#sound-dai-cells")) {
dev_dbg(dev, "%s: No \"#sound-dai-cells\", no audio\n",
__func__);
return 0;
}

- num_lanes = of_property_read_variable_u8_array(dev->of_node,
- "sil,i2s-data-lanes",
- lanes, 1,
- ARRAY_SIZE(lanes));
-
+ num_lanes = fwnode_property_count_u8(fwnode, "sil,i2s-data-lanes");
if (num_lanes == -EINVAL) {
dev_dbg(dev,
"%s: No \"sil,i2s-data-lanes\", use default <0>\n",
@@ -852,7 +849,11 @@ static int sii902x_audio_codec_init(struct sii902x *sii902x,
"%s: Error gettin \"sil,i2s-data-lanes\": %d\n",
__func__, num_lanes);
return num_lanes;
+ } else {
+ fwnode_property_read_u8_array(fwnode, "sil,i2s-data-lanes",
+ lanes, num_lanes);
}
+
codec_data.max_i2s_channels = 2 * num_lanes;

for (i = 0; i < num_lanes; i++)
@@ -1096,8 +1097,8 @@ static int sii902x_init(struct sii902x *sii902x)
if (ret)
goto err_unreg_audio;

+ drm_bridge_set_node(&sii902x->bridge, dev_fwnode(dev));
sii902x->bridge.funcs = &sii902x_bridge_funcs;
- sii902x->bridge.of_node = dev->of_node;
sii902x->bridge.timings = &default_sii902x_timings;
sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;

@@ -1118,7 +1119,6 @@ static int sii902x_init(struct sii902x *sii902x)
static int sii902x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
- struct device_node *endpoint;
struct sii902x *sii902x;
static const char * const supplies[] = {"iovcc", "cvcc12"};
int ret;
@@ -1147,27 +1147,14 @@ static int sii902x_probe(struct i2c_client *client)
return PTR_ERR(sii902x->reset_gpio);
}

- endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
- if (endpoint) {
- struct device_node *remote = of_graph_get_remote_port_parent(endpoint);
-
- of_node_put(endpoint);
- if (!remote) {
- dev_err(dev, "Endpoint in port@1 unconnected\n");
- return -ENODEV;
- }
-
- if (!of_device_is_available(remote)) {
- dev_err(dev, "port@1 remote device is disabled\n");
- of_node_put(remote);
- return -ENODEV;
- }
-
- sii902x->next_bridge = of_drm_find_bridge(remote);
- of_node_put(remote);
- if (!sii902x->next_bridge)
- return dev_err_probe(dev, -EPROBE_DEFER,
- "Failed to find remote bridge\n");
+ sii902x->next_bridge = drm_bridge_find_next_bridge_by_fwnode(dev_fwnode(dev), 1);
+ if (!sii902x->next_bridge) {
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "Failed to find the next bridge\n");
+ } else if (IS_ERR(sii902x->next_bridge)) {
+ ret = PTR_ERR(sii902x->next_bridge);
+ dev_err(dev, "Error on find the next bridge: %d\n", ret);
+ return ret;
}

mutex_init(&sii902x->mutex);
--
2.34.1


2024-05-03 16:42:57

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 06/10] drm-bridge: it66121: Use fwnode APIs to acquire device properties

Make this driver less DT-dependent by calling the newly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
A side benifit is that boilerplates get reduced, no functional changes
for DT-based systems.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/ite-it66121.c | 57 +++++++++++++++++-----------
1 file changed, 35 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 925e42f46cd8..688dc1830654 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -15,7 +15,6 @@
#include <linux/bitfield.h>
#include <linux/property.h>
#include <linux/regmap.h>
-#include <linux/of_graph.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
@@ -1480,7 +1479,7 @@ static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev)

dev_dbg(dev, "%s\n", __func__);

- if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
+ if (!fwnode_property_present(dev_fwnode(dev), "#sound-dai-cells")) {
dev_info(dev, "No \"#sound-dai-cells\", no audio\n");
return 0;
}
@@ -1503,13 +1502,36 @@ static const char * const it66121_supplies[] = {
"vcn33", "vcn18", "vrf12"
};

+static int it66121_read_bus_width(struct fwnode_handle *fwnode, u32 *bus_width)
+{
+ struct fwnode_handle *endpoint;
+ u32 val;
+ int ret;
+
+ endpoint = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
+ if (!endpoint)
+ return -EINVAL;
+
+ ret = fwnode_property_read_u32(endpoint, "bus-width", &val);
+ fwnode_handle_put(endpoint);
+ if (ret)
+ return ret;
+
+ if (val != 12 && val != 24)
+ return -EINVAL;
+
+ *bus_width = val;
+
+ return 0;
+}
+
static int it66121_probe(struct i2c_client *client)
{
u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 };
- struct device_node *ep;
int ret;
struct it66121_ctx *ctx;
struct device *dev = &client->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "I2C check functionality failed.\n");
@@ -1520,29 +1542,20 @@ static int it66121_probe(struct i2c_client *client)
if (!ctx)
return -ENOMEM;

- ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
- if (!ep)
- return -EINVAL;
-
ctx->dev = dev;
ctx->client = client;
ctx->info = i2c_get_match_data(client);

- of_property_read_u32(ep, "bus-width", &ctx->bus_width);
- of_node_put(ep);
-
- if (ctx->bus_width != 12 && ctx->bus_width != 24)
- return -EINVAL;
-
- ep = of_graph_get_remote_node(dev->of_node, 1, -1);
- if (!ep) {
- dev_err(ctx->dev, "The endpoint is unconnected\n");
- return -EINVAL;
- }
+ ret = it66121_read_bus_width(fwnode, &ctx->bus_width);
+ if (ret)
+ return ret;

- ctx->next_bridge = of_drm_find_bridge(ep);
- of_node_put(ep);
- if (!ctx->next_bridge) {
+ ctx->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
+ if (IS_ERR(ctx->next_bridge)) {
+ ret = PTR_ERR(ctx->next_bridge);
+ dev_err(dev, "Error in founding the next bridge: %d\n", ret);
+ return ret;
+ } else if (!ctx->next_bridge) {
dev_dbg(ctx->dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
}
@@ -1577,8 +1590,8 @@ static int it66121_probe(struct i2c_client *client)
return -ENODEV;
}

+ drm_bridge_set_node(&ctx->bridge, fwnode);
ctx->bridge.funcs = &it66121_bridge_funcs;
- ctx->bridge.of_node = dev->of_node;
ctx->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
if (client->irq > 0) {
--
2.34.1


2024-05-03 16:43:09

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 07/10] drm/bridge: tfp410: Use fwnode APIs to acquire device properties

Make this driver less DT-dependent by calling the newly created helpers,
also switch to use fwnode APIs to acquire additional device properties.
No functional changes for DT-based systems.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/ti-tfp410.c | 41 +++++++++++++++---------------
1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index c7bef5c23927..58dc7492844f 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -266,8 +266,9 @@ static const struct drm_bridge_timings tfp410_default_timings = {

static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
{
+ struct fwnode_handle *fwnode = dev_fwnode(dvi->dev);
struct drm_bridge_timings *timings = &dvi->timings;
- struct device_node *ep;
+ struct fwnode_handle *ep;
u32 pclk_sample = 0;
u32 bus_width = 24;
u32 deskew = 0;
@@ -288,14 +289,14 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
* and EDGE pins. They are specified in DT through endpoint properties
* and vendor-specific properties.
*/
- ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 0, 0);
+ ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
if (!ep)
return -EINVAL;

/* Get the sampling edge from the endpoint. */
- of_property_read_u32(ep, "pclk-sample", &pclk_sample);
- of_property_read_u32(ep, "bus-width", &bus_width);
- of_node_put(ep);
+ fwnode_property_read_u32(ep, "pclk-sample", &pclk_sample);
+ fwnode_property_read_u32(ep, "bus-width", &bus_width);
+ fwnode_handle_put(ep);

timings->input_bus_flags = DRM_BUS_FLAG_DE_HIGH;

@@ -324,7 +325,7 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
}

/* Get the setup and hold time from vendor-specific properties. */
- of_property_read_u32(dvi->dev->of_node, "ti,deskew", &deskew);
+ fwnode_property_read_u32(fwnode, "ti,deskew", &deskew);
if (deskew > 7)
return -EINVAL;

@@ -336,12 +337,12 @@ static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)

static int tfp410_init(struct device *dev, bool i2c)
{
- struct device_node *node;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct tfp410 *dvi;
int ret;

- if (!dev->of_node) {
- dev_err(dev, "device-tree data is missing\n");
+ if (!fwnode) {
+ dev_err(dev, "firmware data is missing\n");
return -ENXIO;
}

@@ -352,8 +353,8 @@ static int tfp410_init(struct device *dev, bool i2c)
dvi->dev = dev;
dev_set_drvdata(dev, dvi);

+ drm_bridge_set_node(&dvi->bridge, fwnode);
dvi->bridge.funcs = &tfp410_bridge_funcs;
- dvi->bridge.of_node = dev->of_node;
dvi->bridge.timings = &dvi->timings;
dvi->bridge.type = DRM_MODE_CONNECTOR_DVID;

@@ -362,15 +363,15 @@ static int tfp410_init(struct device *dev, bool i2c)
return ret;

/* Get the next bridge, connected to port@1. */
- node = of_graph_get_remote_node(dev->of_node, 1, -1);
- if (!node)
- return -ENODEV;
-
- dvi->next_bridge = of_drm_find_bridge(node);
- of_node_put(node);
-
- if (!dvi->next_bridge)
+ dvi->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
+ if (IS_ERR(dvi->next_bridge)) {
+ ret = PTR_ERR(dvi->next_bridge);
+ dev_err(dev, "Error in founding the next bridge: %d\n", ret);
+ return ret;
+ } else if (!dvi->next_bridge) {
+ dev_dbg(dev, "Next bridge not found, deferring probe\n");
return -EPROBE_DEFER;
+ }

/* Get the powerdown GPIO. */
dvi->powerdown = devm_gpiod_get_optional(dev, "powerdown",
@@ -422,10 +423,10 @@ static struct platform_driver tfp410_platform_driver = {
/* There is currently no i2c functionality. */
static int tfp410_i2c_probe(struct i2c_client *client)
{
+ struct fwnode_handle *fwnode = dev_fwnode(&client->dev);
int reg;

- if (!client->dev.of_node ||
- of_property_read_u32(client->dev.of_node, "reg", &reg)) {
+ if (!fwnode || fwnode_property_read_u32(fwnode, "reg", &reg)) {
dev_err(&client->dev,
"Can't get i2c reg property from device-tree\n");
return -ENXIO;
--
2.34.1


2024-05-03 16:43:36

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 08/10] drm/bridge: sii9234: Use fwnode APIs to abstract DT dependent API away

Switch to use the freshly created drm_bridge_set_node() helper, no
functional changes. The reason behind of this introduction is that
the name 'of_node' itself has a smell of DT dependent, and it is a
internal memeber, when there has helper function, we should use the
revelant helper and avoid directly referencing and/or dereferencing
it.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/sii9234.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sii9234.c b/drivers/gpu/drm/bridge/sii9234.c
index d8373d918324..19b09634a134 100644
--- a/drivers/gpu/drm/bridge/sii9234.c
+++ b/drivers/gpu/drm/bridge/sii9234.c
@@ -817,10 +817,11 @@ static int sii9234_init_resources(struct sii9234 *ctx,
struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
+ struct fwnode_handle *fwnode = dev_fwnode(ctx->dev);
int ret;

- if (!ctx->dev->of_node) {
- dev_err(ctx->dev, "not DT device\n");
+ if (!fwnode) {
+ dev_err(ctx->dev, "firmware data is missing\n");
return -ENODEV;
}

@@ -886,6 +887,7 @@ static int sii9234_probe(struct i2c_client *client)
struct i2c_adapter *adapter = client->adapter;
struct sii9234 *ctx;
struct device *dev = &client->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
int ret;

ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
@@ -922,7 +924,7 @@ static int sii9234_probe(struct i2c_client *client)
i2c_set_clientdata(client, ctx);

ctx->bridge.funcs = &sii9234_bridge_funcs;
- ctx->bridge.of_node = dev->of_node;
+ drm_bridge_set_node(&ctx->bridge, fwnode);
drm_bridge_add(&ctx->bridge);

sii9234_cable_in(ctx);
--
2.34.1


2024-05-03 16:45:23

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 04/10] drm/bridge: display-connector: Use fwnode APIs to acquire device properties

Switch to use the fwnode APIs, which is a fundamental step to make this
driver OF-independent possible. No functional changes for DT-based systems.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/display-connector.c | 25 +++++++++++-----------
1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c
index ab8e00baf3f1..ac680c6e9bd6 100644
--- a/drivers/gpu/drm/bridge/display-connector.c
+++ b/drivers/gpu/drm/bridge/display-connector.c
@@ -9,7 +9,6 @@
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>

@@ -204,6 +203,7 @@ static int display_connector_get_supply(struct platform_device *pdev,

static int display_connector_probe(struct platform_device *pdev)
{
+ struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
struct display_connector *conn;
unsigned int type;
const char *label = NULL;
@@ -215,15 +215,15 @@ static int display_connector_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, conn);

- type = (uintptr_t)of_device_get_match_data(&pdev->dev);
+ type = (uintptr_t)device_get_match_data(&pdev->dev);

/* Get the exact connector type. */
switch (type) {
case DRM_MODE_CONNECTOR_DVII: {
bool analog, digital;

- analog = of_property_read_bool(pdev->dev.of_node, "analog");
- digital = of_property_read_bool(pdev->dev.of_node, "digital");
+ analog = fwnode_property_present(fwnode, "analog");
+ digital = fwnode_property_present(fwnode, "digital");
if (analog && !digital) {
conn->bridge.type = DRM_MODE_CONNECTOR_DVIA;
} else if (!analog && digital) {
@@ -240,8 +240,7 @@ static int display_connector_probe(struct platform_device *pdev)
case DRM_MODE_CONNECTOR_HDMIA: {
const char *hdmi_type;

- ret = of_property_read_string(pdev->dev.of_node, "type",
- &hdmi_type);
+ ret = fwnode_property_read_string(fwnode, "type", &hdmi_type);
if (ret < 0) {
dev_err(&pdev->dev, "HDMI connector with no type\n");
return -EINVAL;
@@ -271,7 +270,7 @@ static int display_connector_probe(struct platform_device *pdev)
conn->bridge.interlace_allowed = true;

/* Get the optional connector label. */
- of_property_read_string(pdev->dev.of_node, "label", &label);
+ fwnode_property_read_string(fwnode, "label", &label);

/*
* Get the HPD GPIO for DVI, HDMI and DP connectors. If the GPIO can provide
@@ -309,12 +308,12 @@ static int display_connector_probe(struct platform_device *pdev)
if (type == DRM_MODE_CONNECTOR_DVII ||
type == DRM_MODE_CONNECTOR_HDMIA ||
type == DRM_MODE_CONNECTOR_VGA) {
- struct device_node *phandle;
+ struct fwnode_handle *phandle;

- phandle = of_parse_phandle(pdev->dev.of_node, "ddc-i2c-bus", 0);
- if (phandle) {
- conn->bridge.ddc = of_get_i2c_adapter_by_node(phandle);
- of_node_put(phandle);
+ phandle = fwnode_find_reference(fwnode, "ddc-i2c-bus", 0);
+ if (!IS_ERR(phandle)) {
+ conn->bridge.ddc = i2c_get_adapter_by_fwnode(phandle);
+ fwnode_handle_put(phandle);
if (!conn->bridge.ddc)
return -EPROBE_DEFER;
} else {
@@ -358,7 +357,7 @@ static int display_connector_probe(struct platform_device *pdev)
}

conn->bridge.funcs = &display_connector_bridge_funcs;
- conn->bridge.of_node = pdev->dev.of_node;
+ drm_bridge_set_node(&conn->bridge, fwnode);

if (conn->bridge.ddc)
conn->bridge.ops |= DRM_BRIDGE_OP_EDID
--
2.34.1


2024-05-03 16:47:31

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 09/10] drm/bridge: ch7033: Switch to use fwnode based APIs

Use the freshly created helper to replace the use of DT-dependent APIs,
also print error log if the fwnode graph is not complete which is benefit
to debug.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/chrontel-ch7033.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c
index c83486cf6b15..d856ad0987cc 100644
--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c
+++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c
@@ -531,6 +531,7 @@ static const struct regmap_config ch7033_regmap_config = {
static int ch7033_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct ch7033_priv *priv;
unsigned int val;
int ret;
@@ -541,10 +542,15 @@ static int ch7033_probe(struct i2c_client *client)

dev_set_drvdata(dev, priv);

- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
- &priv->next_bridge);
- if (ret)
+ priv->next_bridge = drm_bridge_find_next_bridge_by_fwnode(fwnode, 1);
+ if (IS_ERR(priv->next_bridge)) {
+ ret = PTR_ERR(priv->next_bridge);
+ dev_err(dev, "Error in founding the next bridge: %d\n", ret);
return ret;
+ } else if (!priv->next_bridge) {
+ dev_dbg(dev, "Next bridge not found, deferring probe\n");
+ return -EPROBE_DEFER;
+ }

priv->regmap = devm_regmap_init_i2c(client, &ch7033_regmap_config);
if (IS_ERR(priv->regmap)) {
@@ -575,7 +581,7 @@ static int ch7033_probe(struct i2c_client *client)

INIT_LIST_HEAD(&priv->bridge.list);
priv->bridge.funcs = &ch7033_bridge_funcs;
- priv->bridge.of_node = dev->of_node;
+ drm_bridge_set_node(&priv->bridge, fwnode);
drm_bridge_add(&priv->bridge);

dev_info(dev, "Chrontel CH7033 Video Encoder\n");
--
2.34.1


2024-05-03 16:47:58

by Sui Jingfeng

[permalink] [raw]
Subject: [PATCH v5 10/10] drm/bridge: anx7688: Switch to use drm_bridge_set_node() helper

Switch to use the freshly created drm_bridge_set_node() helper, because
fwnode APIs can be used to abstract DT dependent APIs away. As the fwnode
APIs has wider coverage than DT counterpart, driver don't have to bear
the burden of "OF dependent", let the core take the resposibility. No
functional changes.

Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/bridge/cros-ec-anx7688.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/cros-ec-anx7688.c b/drivers/gpu/drm/bridge/cros-ec-anx7688.c
index c8abd9920fee..30b27b808e02 100644
--- a/drivers/gpu/drm/bridge/cros-ec-anx7688.c
+++ b/drivers/gpu/drm/bridge/cros-ec-anx7688.c
@@ -98,6 +98,7 @@ static const struct drm_bridge_funcs cros_ec_anx7688_bridge_funcs = {
static int cros_ec_anx7688_bridge_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct cros_ec_anx7688 *anx7688;
u16 vendor, device, fw_version;
u8 buffer[4];
@@ -143,7 +144,7 @@ static int cros_ec_anx7688_bridge_probe(struct i2c_client *client)
fw_version = (u16)buffer[0] << 8 | buffer[1];
dev_info(dev, "ANX7688 firmware version 0x%04x\n", fw_version);

- anx7688->bridge.of_node = dev->of_node;
+ drm_bridge_set_node(&anx7688->bridge, fwnode);

/* FW version >= 0.85 supports bandwidth/lane count registers */
if (fw_version >= ANX7688_MINIMUM_FW_VERSION)
--
2.34.1