linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems
@ 2021-05-03 21:58 Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node Douglas Anderson
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Douglas Anderson @ 2021-05-03 21:58 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg, Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Douglas Anderson, Andy Gross, Daniel Vetter, David Airlie,
	Maxime Ripard, Rob Herring, Robert Foss, Thomas Zimmermann,
	devicetree, linux-kernel

The primary goal of this series is to try to properly fix EDID reading
for eDP panels using the ti-sn65dsi86 bridge.

Previously we had a patch that added EDID reading but it turned out
not to work at bootup. This caused some extra churn at bootup as we
tried (and failed) to read the EDID several times and also ended up
forcing us to use the hardcoded mode at boot. With this patch series I
believe EDID reading is reliable at boot now and we never use the
hardcoded mode.

This series is the logical successor to the 3-part series containing
the patch ("drm/bridge: ti-sn65dsi86: Properly get the EDID, but only
if refclk") [1].

At v6 now, this patch series is smaller as I have landed most of the
cleanup patches. I've previously sent out a summary [2]. Now it just
has the i2c fix and some of the more controversial parts.

This patch was developed agains linuxnext (next-20210416) with
drm-misc-next (as of 20210503) merged in on a sc7180-trogdor-lazor
device. To get things booting for me, I had to use Stephen's patch [3]
to keep from crashing but otherwise all the patches I needed were
here.

Primary change between v2 and v3 is to stop doing the EDID caching in
the core. I also added Andrzej's review tags.

Between v3 and v4 this series grew a whole lot. I changed it so that
the EDID reading is actually driven by the panel driver now as was
suggested by Andrzej. While I still believe that the old approach
wasn't too bad I'm still switching. Why?

The main reason is that I think it's useful in general for the panel
code to have access to the DDC bus and to be able to read the
EDID. This may allow us to more easily have the panel code support
multiple sources of panels--it can read the EDID and possibly adjust
timings based on the model ID. It also allows the panel code (or
perhaps backlight code?) to send DDC commands if they are need for a
particular panel.

At the moment, once the panel is provided the DDC bus then existing
code will assume that it should be in charge of reading the
EDID. While it doesn't have to work that way, it seems sane to build
on what's already there.

In order to expose the DDC bus to the panel, I had to solve a bunch of
chicken-and-egg problems in terms of probe ordering between the bridge
and the panel. I've broken the bridge driver into several sub drivers
to make this happen. At the moment the sub-drivers are just there to
solve the probe problem, but conceivably someone could use them to
break the driver up in the future if need be.

Between v4 and v5, high-level view of changes.
- Some of the early patches landed, so dropped from series.
- New pm_runtime_disable() fix (fixed a patch that already landed).
- Added Bjorn's tags to most patches
- Fixed problems when building as a module.
- Reordered debugfs patch and fixed error handling there.
- Dropped last patch. I'm not convinced it's safe w/out more work.

Between v5 and v6 this patch added the patch ("drm/dp: Allow an early
call to register DDC i2c bus") and only includes the patches that
haven't already landed.

[1] https://lore.kernel.org/r/20210304155144.3.I60a7fb23ce4589006bc95c64ab8d15c74b876e68@changeid/
[2] https://lore.kernel.org/dri-devel/CAD=FV=Vzn0ih_RqR_ySJzFtq0B0x_4a-Uwjk56GeLyUZtTEXrQ@mail.gmail.com/
[3] https://lore.kernel.org/r/161706912161.3012082.17313817257247946143@swboyd.mtv.corp.google.com/

Changes in v6:
- ("drm/dp: Allow an early call to register DDC i2c bus") new for v6.
- Use new drm_dp_aux_register_ddc() calls.

Douglas Anderson (5):
  i2c: i2c-core-of: Fix corner case of finding adapter by node
  drm/dp: Allow an early call to register DDC i2c bus
  drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev
  drm/bridge: ti-sn65dsi86: Don't read EDID blob over DDC
  arm64: dts: qcom: Link the panel to the bridge's DDC bus

 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi |  1 +
 drivers/gpu/drm/bridge/ti-sn65dsi86.c        | 99 +++++++++++++-------
 drivers/gpu/drm/drm_dp_helper.c              | 67 ++++++++++---
 drivers/i2c/i2c-core-of.c                    | 17 ++--
 include/drm/drm_dp_helper.h                  |  2 +
 5 files changed, 134 insertions(+), 52 deletions(-)

-- 
2.31.1.527.g47e6f16901-goog


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node
  2021-05-03 21:58 [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems Douglas Anderson
@ 2021-05-03 21:58 ` Douglas Anderson
  2021-05-17 20:16   ` Doug Anderson
  2021-05-03 21:58 ` [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus Douglas Anderson
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Douglas Anderson @ 2021-05-03 21:58 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg, Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Douglas Anderson, linux-kernel

The of_find_i2c_adapter_by_node() could end up failing to find an
adapter in certain conditions. Specifically it's possible that
of_dev_or_parent_node_match() could end up finding an I2C client in
the list and cause bus_find_device() to stop early even though an I2C
adapter was present later in the list.

Let's move the i2c_verify_adapter() into the predicate function to
prevent this. Now we'll properly skip over the I2C client and be able
to find the I2C adapter.

This issue has always been a potential problem if a single device tree
node could represent both an I2C client and an adapter. I believe this
is a sane thing to do if, for instance, an I2C-connected DP bridge
chip is present. The bridge chip is an I2C client but it can also
provide an I2C adapter (DDC tunneled over AUX channel). We don't want
to have to create a sub-node just so a panel can link to it with the
"ddc-i2c-bus" property.

I believe that this problem got worse, however, with commit
e814e688413a ("i2c: of: Try to find an I2C adapter matching the
parent"). Starting at that commit it would be even easier to
accidentally miss finding the adapter.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Later patches in this series won't work right without this one, but
they won't crash. If we can't find the i2c bus we'll just fall back to
the hardcoded panel modes which, at least today, all panels have.

I'll also note that part of me wonders if we should actually fix this
further to run two passes through everything: first look to see if we
find an exact match and only look at the parent pointer if there is no
match. I don't currently have a need for that and it's a slightly
bigger change, but it seems conceivable that it could affect someone?

(no changes since v1)

 drivers/i2c/i2c-core-of.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c
index 3ed74aa4b44b..de0bf5fce3a2 100644
--- a/drivers/i2c/i2c-core-of.c
+++ b/drivers/i2c/i2c-core-of.c
@@ -124,6 +124,14 @@ static int of_dev_or_parent_node_match(struct device *dev, const void *data)
 	return 0;
 }
 
+static int of_i2c_adapter_match(struct device *dev, const void *data)
+{
+	if (!of_dev_or_parent_node_match(dev, data))
+		return 0;
+
+	return !!i2c_verify_adapter(dev);
+}
+
 /* must call put_device() when done with returned i2c_client device */
 struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 {
@@ -146,18 +154,13 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node);
 struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
 {
 	struct device *dev;
-	struct i2c_adapter *adapter;
 
 	dev = bus_find_device(&i2c_bus_type, NULL, node,
-			      of_dev_or_parent_node_match);
+			      of_i2c_adapter_match);
 	if (!dev)
 		return NULL;
 
-	adapter = i2c_verify_adapter(dev);
-	if (!adapter)
-		put_device(dev);
-
-	return adapter;
+	return to_i2c_adapter(dev);
 }
 EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
 
-- 
2.31.1.527.g47e6f16901-goog


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus
  2021-05-03 21:58 [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node Douglas Anderson
@ 2021-05-03 21:58 ` Douglas Anderson
  2021-05-07 21:18   ` Lyude Paul
  2021-05-03 21:58 ` [PATCH v6 3/5] drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev Douglas Anderson
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Douglas Anderson @ 2021-05-03 21:58 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg, Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Douglas Anderson, Daniel Vetter, David Airlie, Maxime Ripard,
	Thomas Zimmermann, linux-kernel

It can be helpful to fully register the AUX channel as an i2c bus even
before the bridge is created. Let's optionally allow bridges to do
that.

Specifically the case we're running into:
- The panel driver wants to get its DDC bus at probe time.
- The ti-sn65dsi86 MIPI-to-eDP bridge code, which provides the DDC
  bus, wants to get the panel at probe time.

The next patches ("drm/bridge: ti-sn65dsi86: Promote the AUX channel
to its own sub-dev") solves the chicken-and-egg problem by breaking
the ti-sn65dsi86 driver into sub-devices, but in order for it to
actually work we need the i2c bus to get registered at probe time and
not in bridge attach time.

Cc: Lyude Paul <lyude@redhat.com>
Cc: Thierry Reding <treding@nvidia.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---

Changes in v6:
- ("drm/dp: Allow an early call to register DDC i2c bus") new for v6.

 drivers/gpu/drm/drm_dp_helper.c | 67 +++++++++++++++++++++++++++------
 include/drm/drm_dp_helper.h     |  2 +
 2 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index cb56d74e9d38..830294f0b341 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -1757,6 +1757,49 @@ void drm_dp_aux_init(struct drm_dp_aux *aux)
 }
 EXPORT_SYMBOL(drm_dp_aux_init);
 
+/**
+ * drm_dp_aux_register_ddc() - register the DDC parts of the aux channel
+ * @aux: DisplayPort AUX channel
+ *
+ * This can be called after drm_dp_aux_init() to fully register the ddc bus
+ * as an i2c adapter with the rest of Linux.
+ *
+ * If you don't explicitly call this function it will be done implicitly as
+ * part of drm_dp_aux_register().
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_aux_register_ddc(struct drm_dp_aux *aux)
+{
+	WARN_ON_ONCE(!aux->dev);
+
+	aux->ddc.class = I2C_CLASS_DDC;
+	aux->ddc.owner = THIS_MODULE;
+	aux->ddc.dev.parent = aux->dev;
+
+	strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
+		sizeof(aux->ddc.name));
+
+	return i2c_add_adapter(&aux->ddc);
+}
+EXPORT_SYMBOL(drm_dp_aux_register_ddc);
+
+/**
+ * drm_dp_aux_unregister_ddc() - unregister the DDC parts of the aux channel
+ *
+ * This is useful if you called drm_dp_aux_register_ddc(). If you let
+ * drm_dp_aux_register() implicitly register the DDC for you then you don't
+ * need to worry about calling this yourself.
+ *
+ * @aux: DisplayPort AUX channel
+ */
+void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux)
+{
+	i2c_del_adapter(&aux->ddc);
+	aux->ddc.dev.parent = NULL;
+}
+EXPORT_SYMBOL(drm_dp_aux_unregister_ddc);
+
 /**
  * drm_dp_aux_register() - initialise and register aux channel
  * @aux: DisplayPort AUX channel
@@ -1793,20 +1836,19 @@ int drm_dp_aux_register(struct drm_dp_aux *aux)
 	if (!aux->ddc.algo)
 		drm_dp_aux_init(aux);
 
-	aux->ddc.class = I2C_CLASS_DDC;
-	aux->ddc.owner = THIS_MODULE;
-	aux->ddc.dev.parent = aux->dev;
-
-	strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
-		sizeof(aux->ddc.name));
+	/*
+	 * Implicitly register if drm_dp_aux_register_ddc() wasn't already
+	 * called (as evidenced by a NULL parent pointer).
+	 */
+	if (!aux->ddc.dev.parent) {
+		ret = drm_dp_aux_register_ddc(aux);
+		if (ret)
+			return ret;
+	}
 
 	ret = drm_dp_aux_register_devnode(aux);
-	if (ret)
-		return ret;
-
-	ret = i2c_add_adapter(&aux->ddc);
 	if (ret) {
-		drm_dp_aux_unregister_devnode(aux);
+		drm_dp_aux_unregister_ddc(aux);
 		return ret;
 	}
 
@@ -1821,7 +1863,8 @@ EXPORT_SYMBOL(drm_dp_aux_register);
 void drm_dp_aux_unregister(struct drm_dp_aux *aux)
 {
 	drm_dp_aux_unregister_devnode(aux);
-	i2c_del_adapter(&aux->ddc);
+	if (aux->ddc.dev.parent)
+		drm_dp_aux_unregister_ddc(aux);
 }
 EXPORT_SYMBOL(drm_dp_aux_unregister);
 
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index e932b2c40095..d4d2d5e25bb7 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -2021,6 +2021,8 @@ bool drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_
 
 void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
 void drm_dp_aux_init(struct drm_dp_aux *aux);
+int drm_dp_aux_register_ddc(struct drm_dp_aux *aux);
+void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux);
 int drm_dp_aux_register(struct drm_dp_aux *aux);
 void drm_dp_aux_unregister(struct drm_dp_aux *aux);
 
-- 
2.31.1.527.g47e6f16901-goog


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v6 3/5] drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev
  2021-05-03 21:58 [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus Douglas Anderson
@ 2021-05-03 21:58 ` Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 4/5] drm/bridge: ti-sn65dsi86: Don't read EDID blob over DDC Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 5/5] arm64: dts: qcom: Link the panel to the bridge's DDC bus Douglas Anderson
  4 siblings, 0 replies; 12+ messages in thread
From: Douglas Anderson @ 2021-05-03 21:58 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg, Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Douglas Anderson, Daniel Vetter, David Airlie, Robert Foss,
	linux-kernel

We'd like to be able to expose the DDC-over-AUX channel bus to our
panel. This gets into a chicken-and-egg problem because:
- The panel wants to get its DDC bus at probe time.
- The ti-sn65dsi86 MIPI-to-eDP bridge code, which provides the DDC
  bus, wants to get the panel at probe time.

By using a sub device we can fully create the AUX channel bits so that
the panel can get them. Then the panel can finish probing and the
bridge can probe.

To accomplish this, we use the new functions introduced in ("drm/dp:
Allow an early call to register DDC i2c bus") to register the i2c bus
early.

NOTE: there's a little bit of a trick here. Though the AUX channel can
run without the MIPI-to-eDP bits of the code, the MIPI-to-eDP bits
can't run without the AUX channel. We could come up a complicated
signaling scheme (have the MIPI-to-eDP bits return EPROBE_DEFER for a
while or wait on some sort of completion), but it seems simple enough
to just not even bother creating the bridge device until the AUX
channel probes. That's what we'll do.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
Commit 6cba3fe43341 ("drm/dp: Add backpointer to drm_device in
drm_dp_aux") made it very explicit that it's not OK to fully register
the aux device until we have the bridge, but hopefully just getting
the i2c bits early is OK?

Changes in v6:
- Use new drm_dp_aux_register_ddc() calls.

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 77 +++++++++++++++++++++++----
 1 file changed, 66 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index db027528febd..594aac57bdbc 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -116,6 +116,7 @@
  * struct ti_sn65dsi86 - Platform data for ti-sn65dsi86 driver.
  * @bridge_aux:   AUX-bus sub device for MIPI-to-eDP bridge functionality.
  * @gpio_aux:     AUX-bus sub device for GPIO controller functionality.
+ * @aux_aux:      AUX-bus sub device for eDP AUX channel functionality.
  *
  * @dev:          Pointer to the top level (i2c) device.
  * @regmap:       Regmap for accessing i2c.
@@ -148,6 +149,7 @@
 struct ti_sn65dsi86 {
 	struct auxiliary_device		bridge_aux;
 	struct auxiliary_device		gpio_aux;
+	struct auxiliary_device		aux_aux;
 
 	struct device			*dev;
 	struct regmap			*regmap;
@@ -1331,11 +1333,6 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev,
 	if (ret)
 		return ret;
 
-	pdata->aux.name = "ti-sn65dsi86-aux";
-	pdata->aux.dev = pdata->dev;
-	pdata->aux.transfer = ti_sn_aux_transfer;
-	drm_dp_aux_init(&pdata->aux);
-
 	pdata->bridge.funcs = &ti_sn_bridge_funcs;
 	pdata->bridge.of_node = np;
 
@@ -1430,6 +1427,50 @@ static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
 	return ret;
 }
 
+static void ti_sn65dsi86_unregister_dp_aux_ddc(void *data)
+{
+	drm_dp_aux_unregister_ddc(data);
+}
+
+static int ti_sn_aux_probe(struct auxiliary_device *adev,
+			   const struct auxiliary_device_id *id)
+{
+	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
+	int ret;
+
+	pdata->aux.name = "ti-sn65dsi86-aux";
+	pdata->aux.dev = pdata->dev;
+	pdata->aux.transfer = ti_sn_aux_transfer;
+	drm_dp_aux_init(&pdata->aux);
+
+	ret = drm_dp_aux_register_ddc(&pdata->aux);
+	if (ret < 0) {
+		drm_err(pdata, "Failed to register AUX DDC channel: %d\n", ret);
+		return ret;
+	}
+	ret = devm_add_action_or_reset(&adev->dev,
+				       ti_sn65dsi86_unregister_dp_aux_ddc, &pdata->aux);
+	if (ret)
+		return ret;
+
+	/*
+	 * The eDP to MIPI bridge parts don't work until the AUX channel is
+	 * setup so we don't add it in the main driver probe, we add it now.
+	 */
+	return ti_sn65dsi86_add_aux_device(pdata, &pdata->bridge_aux, "bridge");
+}
+
+static const struct auxiliary_device_id ti_sn_aux_id_table[] = {
+	{ .name = "ti_sn65dsi86.aux", },
+	{},
+};
+
+static struct auxiliary_driver ti_sn_aux_driver = {
+	.name = "aux",
+	.probe = ti_sn_aux_probe,
+	.id_table = ti_sn_aux_id_table,
+};
+
 static int ti_sn65dsi86_probe(struct i2c_client *client,
 			      const struct i2c_device_id *id)
 {
@@ -1488,10 +1529,11 @@ static int ti_sn65dsi86_probe(struct i2c_client *client,
 	 * motiviation here is to solve the chicken-and-egg problem of probe
 	 * ordering. The bridge wants the panel to be there when it probes.
 	 * The panel wants its HPD GPIO (provided by sn65dsi86 on some boards)
-	 * when it probes. There will soon be other devices (DDC I2C bus, PWM)
-	 * that have the same problem. Having sub-devices allows the some sub
-	 * devices to finish probing even if others return -EPROBE_DEFER and
-	 * gets us around the problems.
+	 * when it probes. The panel and maybe backlight might want the DDC
+	 * bus. Soon the PWM provided by the bridge chip will have the same
+	 * problem. Having sub-devices allows the some sub devices to finish
+	 * probing even if others return -EPROBE_DEFER and gets us around the
+	 * problems.
 	 */
 
 	if (IS_ENABLED(CONFIG_OF_GPIO)) {
@@ -1500,7 +1542,13 @@ static int ti_sn65dsi86_probe(struct i2c_client *client,
 			return ret;
 	}
 
-	return ti_sn65dsi86_add_aux_device(pdata, &pdata->bridge_aux, "bridge");
+	/*
+	 * NOTE: At the end of the AUX channel probe we'll add the aux device
+	 * for the bridge. This is because the bridge can't be used until the
+	 * AUX channel is there and this is a very simple solution to the
+	 * dependency problem.
+	 */
+	return ti_sn65dsi86_add_aux_device(pdata, &pdata->aux_aux, "aux");
 }
 
 static struct i2c_device_id ti_sn65dsi86_id[] = {
@@ -1537,12 +1585,18 @@ static int __init ti_sn65dsi86_init(void)
 	if (ret)
 		goto err_main_was_registered;
 
-	ret = auxiliary_driver_register(&ti_sn_bridge_driver);
+	ret = auxiliary_driver_register(&ti_sn_aux_driver);
 	if (ret)
 		goto err_gpio_was_registered;
 
+	ret = auxiliary_driver_register(&ti_sn_bridge_driver);
+	if (ret)
+		goto err_aux_was_registered;
+
 	return 0;
 
+err_aux_was_registered:
+	auxiliary_driver_unregister(&ti_sn_aux_driver);
 err_gpio_was_registered:
 	ti_sn_gpio_unregister();
 err_main_was_registered:
@@ -1555,6 +1609,7 @@ module_init(ti_sn65dsi86_init);
 static void __exit ti_sn65dsi86_exit(void)
 {
 	auxiliary_driver_unregister(&ti_sn_bridge_driver);
+	auxiliary_driver_unregister(&ti_sn_aux_driver);
 	ti_sn_gpio_unregister();
 	i2c_del_driver(&ti_sn65dsi86_driver);
 }
-- 
2.31.1.527.g47e6f16901-goog


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v6 4/5] drm/bridge: ti-sn65dsi86: Don't read EDID blob over DDC
  2021-05-03 21:58 [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems Douglas Anderson
                   ` (2 preceding siblings ...)
  2021-05-03 21:58 ` [PATCH v6 3/5] drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev Douglas Anderson
@ 2021-05-03 21:58 ` Douglas Anderson
  2021-05-03 21:58 ` [PATCH v6 5/5] arm64: dts: qcom: Link the panel to the bridge's DDC bus Douglas Anderson
  4 siblings, 0 replies; 12+ messages in thread
From: Douglas Anderson @ 2021-05-03 21:58 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg, Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Douglas Anderson, Daniel Vetter, David Airlie, Robert Foss,
	linux-kernel

This is really just a revert of commit 58074b08c04a ("drm/bridge:
ti-sn65dsi86: Read EDID blob over DDC"), resolving conflicts.

The old code failed to read the EDID properly in a very important
case: before the bridge's pre_enable() was called. The way things need
to work:
1. Read the EDID.
2. Based on the EDID, decide on video settings and pixel clock.
3. Enable the bridge w/ the desired settings.

The way things were working:
1. Try to read the EDID but fail; fall back to hardcoded values.
2. Based on hardcoded values, decide on video settings and pixel clock.
3. Enable the bridge w/ the desired settings.
4. Try again to read the EDID, it works now!
5. Realize that the hardcoded settings weren't quite right.
6. Disable / reenable the bridge w/ the right settings.

The reasons for the failures were twofold:
a) Since we never ran the bridge chip's pre-enable then we never set
   the bit to ignore HPD. This meant the bridge chip didn't even _try_
   to go out on the bus and communicate with the panel.
b) Even if we fixed things to ignore HPD, the EDID still wouldn't read
   if the panel wasn't on.

Instead of reverting the code, we could fix it to set the HPD bit and
also power on the panel. However, it also works nicely to just let the
panel code read the EDID. Now that we've split the driver up we can
expose the DDC AUX channel bus to the panel node. The panel can take
charge of reading the EDID.

NOTE: in order for things to work, anyone that needs to read the EDID
will need to add something that looks like this to their panel in the
dts:
  ddc-i2c-bus = <&sn65dsi86_bridge>;

Presumably it's OK to land this without waiting for users to add the
dts property since the EDID reading was a bit broken anyway, was
"recently" added, and we know we must have the fallback mode to use
(since the EDID reading was a bit broken).

Suggested-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---

(no changes since v1)

 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 22 ----------------------
 1 file changed, 22 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 594aac57bdbc..9f0f785f380d 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -125,7 +125,6 @@
  * @connector:    Our connector.
  * @host_node:    Remote DSI node.
  * @dsi:          Our MIPI DSI source.
- * @edid:         Detected EDID of eDP panel.
  * @refclk:       Our reference clock.
  * @panel:        Our panel.
  * @enable_gpio:  The GPIO we toggle to enable the bridge.
@@ -156,7 +155,6 @@ struct ti_sn65dsi86 {
 	struct drm_dp_aux		aux;
 	struct drm_bridge		bridge;
 	struct drm_connector		connector;
-	struct edid			*edid;
 	struct device_node		*host_node;
 	struct mipi_dsi_device		*dsi;
 	struct clk			*refclk;
@@ -405,24 +403,6 @@ connector_to_ti_sn65dsi86(struct drm_connector *connector)
 static int ti_sn_bridge_connector_get_modes(struct drm_connector *connector)
 {
 	struct ti_sn65dsi86 *pdata = connector_to_ti_sn65dsi86(connector);
-	struct edid *edid = pdata->edid;
-	int num, ret;
-
-	if (!edid) {
-		pm_runtime_get_sync(pdata->dev);
-		edid = pdata->edid = drm_get_edid(connector, &pdata->aux.ddc);
-		pm_runtime_put_autosuspend(pdata->dev);
-	}
-
-	if (edid && drm_edid_is_valid(edid)) {
-		ret = drm_connector_update_edid_property(connector, edid);
-		if (!ret) {
-			num = drm_add_edid_modes(connector, edid);
-			if (num)
-				return num;
-		}
-	}
-
 	return drm_panel_get_modes(pdata->panel, connector);
 }
 
@@ -1353,8 +1333,6 @@ static void ti_sn_bridge_remove(struct auxiliary_device *adev)
 		mipi_dsi_device_unregister(pdata->dsi);
 	}
 
-	kfree(pdata->edid);
-
 	drm_bridge_remove(&pdata->bridge);
 
 	of_node_put(pdata->host_node);
-- 
2.31.1.527.g47e6f16901-goog


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v6 5/5] arm64: dts: qcom: Link the panel to the bridge's DDC bus
  2021-05-03 21:58 [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems Douglas Anderson
                   ` (3 preceding siblings ...)
  2021-05-03 21:58 ` [PATCH v6 4/5] drm/bridge: ti-sn65dsi86: Don't read EDID blob over DDC Douglas Anderson
@ 2021-05-03 21:58 ` Douglas Anderson
  4 siblings, 0 replies; 12+ messages in thread
From: Douglas Anderson @ 2021-05-03 21:58 UTC (permalink / raw)
  To: Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg, Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Douglas Anderson, Andy Gross, Rob Herring, devicetree,
	linux-kernel

Adding this link allows the panel code to do things like read the
EDID.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---

(no changes since v1)

 arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
index 24d293ef56d7..96e530594509 100644
--- a/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
+++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor.dtsi
@@ -265,6 +265,7 @@ panel: panel {
 		power-supply = <&pp3300_dx_edp>;
 		backlight = <&backlight>;
 		hpd-gpios = <&sn65dsi86_bridge 2 GPIO_ACTIVE_HIGH>;
+		ddc-i2c-bus = <&sn65dsi86_bridge>;
 
 		ports {
 			port {
-- 
2.31.1.527.g47e6f16901-goog


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus
  2021-05-03 21:58 ` [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus Douglas Anderson
@ 2021-05-07 21:18   ` Lyude Paul
  2021-05-07 22:00     ` Bjorn Andersson
  0 siblings, 1 reply; 12+ messages in thread
From: Lyude Paul @ 2021-05-07 21:18 UTC (permalink / raw)
  To: Douglas Anderson, Andrzej Hajda, Neil Armstrong,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Sam Ravnborg,
	Wolfram Sang, Ville Syrjala
  Cc: Steev Klimaszewski, Stephen Boyd, Bjorn Andersson, linux-arm-msm,
	Stanislav Lisovskiy, Linus W, robdclark, Maarten Lankhorst,
	Thierry Reding, linux-i2c, dri-devel, Daniel Vetter,
	David Airlie, Maxime Ripard, Thomas Zimmermann, linux-kernel

Adding ville from Intel to also get their take on this.

In general we've been trying to move DRM to a design where we don't expose any
devices until everything is ready. That's pretty much the main reason that we
register things during bridge attach time. Note though that even before the
DDC bus is registered it should still be usable, just things like get_device()
won't work.

This isn't the first time we've run into a problem like the one you're trying
to solve though, Tegra currently has a similar issue. Something we discussed
as a possible long-term solution for this was splitting i2c_add_adapter() into
a minimal initialization function and a registration function. Linux's device
core already allows for this (device_initialize() and device_add(), which are
called together when device_register() is called). Would this be a solution
that might work for you (and even better, would you possibly be willing to
write the patches? :)

On Mon, 2021-05-03 at 14:58 -0700, Douglas Anderson wrote:
> It can be helpful to fully register the AUX channel as an i2c bus even
> before the bridge is created. Let's optionally allow bridges to do
> that.
> 
> Specifically the case we're running into:
> - The panel driver wants to get its DDC bus at probe time.
> - The ti-sn65dsi86 MIPI-to-eDP bridge code, which provides the DDC
>   bus, wants to get the panel at probe time.
> 
> The next patches ("drm/bridge: ti-sn65dsi86: Promote the AUX channel
> to its own sub-dev") solves the chicken-and-egg problem by breaking
> the ti-sn65dsi86 driver into sub-devices, but in order for it to
> actually work we need the i2c bus to get registered at probe time and
> not in bridge attach time.
> 
> Cc: Lyude Paul <lyude@redhat.com>
> Cc: Thierry Reding <treding@nvidia.com>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> ---
> 
> Changes in v6:
> - ("drm/dp: Allow an early call to register DDC i2c bus") new for v6.
> 
>  drivers/gpu/drm/drm_dp_helper.c | 67 +++++++++++++++++++++++++++------
>  include/drm/drm_dp_helper.h     |  2 +
>  2 files changed, 57 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_dp_helper.c
> b/drivers/gpu/drm/drm_dp_helper.c
> index cb56d74e9d38..830294f0b341 100644
> --- a/drivers/gpu/drm/drm_dp_helper.c
> +++ b/drivers/gpu/drm/drm_dp_helper.c
> @@ -1757,6 +1757,49 @@ void drm_dp_aux_init(struct drm_dp_aux *aux)
>  }
>  EXPORT_SYMBOL(drm_dp_aux_init);
>  
> +/**
> + * drm_dp_aux_register_ddc() - register the DDC parts of the aux channel
> + * @aux: DisplayPort AUX channel
> + *
> + * This can be called after drm_dp_aux_init() to fully register the ddc bus
> + * as an i2c adapter with the rest of Linux.
> + *
> + * If you don't explicitly call this function it will be done implicitly as
> + * part of drm_dp_aux_register().
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux)
> +{
> +       WARN_ON_ONCE(!aux->dev);
> +
> +       aux->ddc.class = I2C_CLASS_DDC;
> +       aux->ddc.owner = THIS_MODULE;
> +       aux->ddc.dev.parent = aux->dev;
> +
> +       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
> +               sizeof(aux->ddc.name));
> +
> +       return i2c_add_adapter(&aux->ddc);
> +}
> +EXPORT_SYMBOL(drm_dp_aux_register_ddc);
> +
> +/**
> + * drm_dp_aux_unregister_ddc() - unregister the DDC parts of the aux
> channel
> + *
> + * This is useful if you called drm_dp_aux_register_ddc(). If you let
> + * drm_dp_aux_register() implicitly register the DDC for you then you don't
> + * need to worry about calling this yourself.
> + *
> + * @aux: DisplayPort AUX channel
> + */
> +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux)
> +{
> +       i2c_del_adapter(&aux->ddc);
> +       aux->ddc.dev.parent = NULL;
> +}
> +EXPORT_SYMBOL(drm_dp_aux_unregister_ddc);
> +
>  /**
>   * drm_dp_aux_register() - initialise and register aux channel
>   * @aux: DisplayPort AUX channel
> @@ -1793,20 +1836,19 @@ int drm_dp_aux_register(struct drm_dp_aux *aux)
>         if (!aux->ddc.algo)
>                 drm_dp_aux_init(aux);
>  
> -       aux->ddc.class = I2C_CLASS_DDC;
> -       aux->ddc.owner = THIS_MODULE;
> -       aux->ddc.dev.parent = aux->dev;
> -
> -       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
> -               sizeof(aux->ddc.name));
> +       /*
> +        * Implicitly register if drm_dp_aux_register_ddc() wasn't already
> +        * called (as evidenced by a NULL parent pointer).
> +        */
> +       if (!aux->ddc.dev.parent) {
> +               ret = drm_dp_aux_register_ddc(aux);
> +               if (ret)
> +                       return ret;
> +       }
>  
>         ret = drm_dp_aux_register_devnode(aux);
> -       if (ret)
> -               return ret;
> -
> -       ret = i2c_add_adapter(&aux->ddc);
>         if (ret) {
> -               drm_dp_aux_unregister_devnode(aux);
> +               drm_dp_aux_unregister_ddc(aux);
>                 return ret;
>         }
>  
> @@ -1821,7 +1863,8 @@ EXPORT_SYMBOL(drm_dp_aux_register);
>  void drm_dp_aux_unregister(struct drm_dp_aux *aux)
>  {
>         drm_dp_aux_unregister_devnode(aux);
> -       i2c_del_adapter(&aux->ddc);
> +       if (aux->ddc.dev.parent)
> +               drm_dp_aux_unregister_ddc(aux);
>  }
>  EXPORT_SYMBOL(drm_dp_aux_unregister);
>  
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> index e932b2c40095..d4d2d5e25bb7 100644
> --- a/include/drm/drm_dp_helper.h
> +++ b/include/drm/drm_dp_helper.h
> @@ -2021,6 +2021,8 @@ bool drm_dp_lttpr_pre_emphasis_level_3_supported(const
> u8 caps[DP_LTTPR_PHY_CAP_
>  
>  void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
>  void drm_dp_aux_init(struct drm_dp_aux *aux);
> +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux);
> +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux);
>  int drm_dp_aux_register(struct drm_dp_aux *aux);
>  void drm_dp_aux_unregister(struct drm_dp_aux *aux);
>  

-- 
Cheers,
 Lyude Paul (she/her)
 Software Engineer at Red Hat


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus
  2021-05-07 21:18   ` Lyude Paul
@ 2021-05-07 22:00     ` Bjorn Andersson
  2021-05-07 22:09       ` Lyude Paul
  0 siblings, 1 reply; 12+ messages in thread
From: Bjorn Andersson @ 2021-05-07 22:00 UTC (permalink / raw)
  To: Lyude Paul
  Cc: Douglas Anderson, Andrzej Hajda, Neil Armstrong,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Sam Ravnborg,
	Wolfram Sang, Ville Syrjala, Steev Klimaszewski, Stephen Boyd,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Daniel Vetter, David Airlie, Maxime Ripard, Thomas Zimmermann,
	linux-kernel

On Fri 07 May 16:18 CDT 2021, Lyude Paul wrote:

> Adding ville from Intel to also get their take on this.
> 
> In general we've been trying to move DRM to a design where we don't expose any
> devices until everything is ready. That's pretty much the main reason that we
> register things during bridge attach time. Note though that even before the
> DDC bus is registered it should still be usable, just things like get_device()
> won't work.
> 
> This isn't the first time we've run into a problem like the one you're trying
> to solve though, Tegra currently has a similar issue. Something we discussed
> as a possible long-term solution for this was splitting i2c_add_adapter() into
> a minimal initialization function and a registration function. Linux's device
> core already allows for this (device_initialize() and device_add(), which are
> called together when device_register() is called). Would this be a solution
> that might work for you (and even better, would you possibly be willing to
> write the patches? :)
> 

It's not enough that the adapter is half-baked, because the bridge's
initialization depends on that the panel device is done probing, and the
panel driver will only complete its probe if it can find it's resources.

So we need a mechanism to fully create the resources exposed by the
bridge chip (i2c bus, gpio chip and (soon) a pwm chip), then allow the
panel to probe and after that initialize the bridge.

We did discuss possible ways to register these resources and then
"sleep for a while" before resolving the panel, but what we came up with
was definitely suboptimal - and ugly.

Regards,
Bjorn

> On Mon, 2021-05-03 at 14:58 -0700, Douglas Anderson wrote:
> > It can be helpful to fully register the AUX channel as an i2c bus even
> > before the bridge is created. Let's optionally allow bridges to do
> > that.
> > 
> > Specifically the case we're running into:
> > - The panel driver wants to get its DDC bus at probe time.
> > - The ti-sn65dsi86 MIPI-to-eDP bridge code, which provides the DDC
> >   bus, wants to get the panel at probe time.
> > 
> > The next patches ("drm/bridge: ti-sn65dsi86: Promote the AUX channel
> > to its own sub-dev") solves the chicken-and-egg problem by breaking
> > the ti-sn65dsi86 driver into sub-devices, but in order for it to
> > actually work we need the i2c bus to get registered at probe time and
> > not in bridge attach time.
> > 
> > Cc: Lyude Paul <lyude@redhat.com>
> > Cc: Thierry Reding <treding@nvidia.com>
> > Signed-off-by: Douglas Anderson <dianders@chromium.org>
> > ---
> > 
> > Changes in v6:
> > - ("drm/dp: Allow an early call to register DDC i2c bus") new for v6.
> > 
> >  drivers/gpu/drm/drm_dp_helper.c | 67 +++++++++++++++++++++++++++------
> >  include/drm/drm_dp_helper.h     |  2 +
> >  2 files changed, 57 insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_dp_helper.c
> > b/drivers/gpu/drm/drm_dp_helper.c
> > index cb56d74e9d38..830294f0b341 100644
> > --- a/drivers/gpu/drm/drm_dp_helper.c
> > +++ b/drivers/gpu/drm/drm_dp_helper.c
> > @@ -1757,6 +1757,49 @@ void drm_dp_aux_init(struct drm_dp_aux *aux)
> >  }
> >  EXPORT_SYMBOL(drm_dp_aux_init);
> >  
> > +/**
> > + * drm_dp_aux_register_ddc() - register the DDC parts of the aux channel
> > + * @aux: DisplayPort AUX channel
> > + *
> > + * This can be called after drm_dp_aux_init() to fully register the ddc bus
> > + * as an i2c adapter with the rest of Linux.
> > + *
> > + * If you don't explicitly call this function it will be done implicitly as
> > + * part of drm_dp_aux_register().
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux)
> > +{
> > +       WARN_ON_ONCE(!aux->dev);
> > +
> > +       aux->ddc.class = I2C_CLASS_DDC;
> > +       aux->ddc.owner = THIS_MODULE;
> > +       aux->ddc.dev.parent = aux->dev;
> > +
> > +       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
> > +               sizeof(aux->ddc.name));
> > +
> > +       return i2c_add_adapter(&aux->ddc);
> > +}
> > +EXPORT_SYMBOL(drm_dp_aux_register_ddc);
> > +
> > +/**
> > + * drm_dp_aux_unregister_ddc() - unregister the DDC parts of the aux
> > channel
> > + *
> > + * This is useful if you called drm_dp_aux_register_ddc(). If you let
> > + * drm_dp_aux_register() implicitly register the DDC for you then you don't
> > + * need to worry about calling this yourself.
> > + *
> > + * @aux: DisplayPort AUX channel
> > + */
> > +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux)
> > +{
> > +       i2c_del_adapter(&aux->ddc);
> > +       aux->ddc.dev.parent = NULL;
> > +}
> > +EXPORT_SYMBOL(drm_dp_aux_unregister_ddc);
> > +
> >  /**
> >   * drm_dp_aux_register() - initialise and register aux channel
> >   * @aux: DisplayPort AUX channel
> > @@ -1793,20 +1836,19 @@ int drm_dp_aux_register(struct drm_dp_aux *aux)
> >         if (!aux->ddc.algo)
> >                 drm_dp_aux_init(aux);
> >  
> > -       aux->ddc.class = I2C_CLASS_DDC;
> > -       aux->ddc.owner = THIS_MODULE;
> > -       aux->ddc.dev.parent = aux->dev;
> > -
> > -       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
> > -               sizeof(aux->ddc.name));
> > +       /*
> > +        * Implicitly register if drm_dp_aux_register_ddc() wasn't already
> > +        * called (as evidenced by a NULL parent pointer).
> > +        */
> > +       if (!aux->ddc.dev.parent) {
> > +               ret = drm_dp_aux_register_ddc(aux);
> > +               if (ret)
> > +                       return ret;
> > +       }
> >  
> >         ret = drm_dp_aux_register_devnode(aux);
> > -       if (ret)
> > -               return ret;
> > -
> > -       ret = i2c_add_adapter(&aux->ddc);
> >         if (ret) {
> > -               drm_dp_aux_unregister_devnode(aux);
> > +               drm_dp_aux_unregister_ddc(aux);
> >                 return ret;
> >         }
> >  
> > @@ -1821,7 +1863,8 @@ EXPORT_SYMBOL(drm_dp_aux_register);
> >  void drm_dp_aux_unregister(struct drm_dp_aux *aux)
> >  {
> >         drm_dp_aux_unregister_devnode(aux);
> > -       i2c_del_adapter(&aux->ddc);
> > +       if (aux->ddc.dev.parent)
> > +               drm_dp_aux_unregister_ddc(aux);
> >  }
> >  EXPORT_SYMBOL(drm_dp_aux_unregister);
> >  
> > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> > index e932b2c40095..d4d2d5e25bb7 100644
> > --- a/include/drm/drm_dp_helper.h
> > +++ b/include/drm/drm_dp_helper.h
> > @@ -2021,6 +2021,8 @@ bool drm_dp_lttpr_pre_emphasis_level_3_supported(const
> > u8 caps[DP_LTTPR_PHY_CAP_
> >  
> >  void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
> >  void drm_dp_aux_init(struct drm_dp_aux *aux);
> > +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux);
> > +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux);
> >  int drm_dp_aux_register(struct drm_dp_aux *aux);
> >  void drm_dp_aux_unregister(struct drm_dp_aux *aux);
> >  
> 
> -- 
> Cheers,
>  Lyude Paul (she/her)
>  Software Engineer at Red Hat
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus
  2021-05-07 22:00     ` Bjorn Andersson
@ 2021-05-07 22:09       ` Lyude Paul
  2021-05-14 11:16         ` Jani Nikula
  0 siblings, 1 reply; 12+ messages in thread
From: Lyude Paul @ 2021-05-07 22:09 UTC (permalink / raw)
  To: Bjorn Andersson, David Airlie, Jani Nikula, Ville Syrjala
  Cc: Douglas Anderson, Andrzej Hajda, Neil Armstrong,
	Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Sam Ravnborg,
	Wolfram Sang, Ville Syrjala, Steev Klimaszewski, Stephen Boyd,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, robdclark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel,
	Daniel Vetter, David Airlie, Maxime Ripard, Thomas Zimmermann,
	linux-kernel

On Fri, 2021-05-07 at 17:00 -0500, Bjorn Andersson wrote:
> On Fri 07 May 16:18 CDT 2021, Lyude Paul wrote:
> 
> > Adding ville from Intel to also get their take on this.
> > 
> > In general we've been trying to move DRM to a design where we don't expose
> > any
> > devices until everything is ready. That's pretty much the main reason that
> > we
> > register things during bridge attach time. Note though that even before
> > the
> > DDC bus is registered it should still be usable, just things like
> > get_device()
> > won't work.
> > 
> > This isn't the first time we've run into a problem like the one you're
> > trying
> > to solve though, Tegra currently has a similar issue. Something we
> > discussed
> > as a possible long-term solution for this was splitting i2c_add_adapter()
> > into
> > a minimal initialization function and a registration function. Linux's
> > device
> > core already allows for this (device_initialize() and device_add(), which
> > are
> > called together when device_register() is called). Would this be a
> > solution
> > that might work for you (and even better, would you possibly be willing to
> > write the patches? :)
> > 
> 
> It's not enough that the adapter is half-baked, because the bridge's
> initialization depends on that the panel device is done probing, and the
> panel driver will only complete its probe if it can find it's resources.
> 
> So we need a mechanism to fully create the resources exposed by the
> bridge chip (i2c bus, gpio chip and (soon) a pwm chip), then allow the
> panel to probe and after that initialize the bridge.
> 
> We did discuss possible ways to register these resources and then
> "sleep for a while" before resolving the panel, but what we came up with
> was definitely suboptimal - and ugly.

Sigh, I'm really starting to wonder if we should reconsider the rules on
exposing ddc adapters early...

Danvet, Jani, and/or airlied: can I get your take on this?

> 
> Regards,
> Bjorn
> 
> > On Mon, 2021-05-03 at 14:58 -0700, Douglas Anderson wrote:
> > > It can be helpful to fully register the AUX channel as an i2c bus even
> > > before the bridge is created. Let's optionally allow bridges to do
> > > that.
> > > 
> > > Specifically the case we're running into:
> > > - The panel driver wants to get its DDC bus at probe time.
> > > - The ti-sn65dsi86 MIPI-to-eDP bridge code, which provides the DDC
> > >   bus, wants to get the panel at probe time.
> > > 
> > > The next patches ("drm/bridge: ti-sn65dsi86: Promote the AUX channel
> > > to its own sub-dev") solves the chicken-and-egg problem by breaking
> > > the ti-sn65dsi86 driver into sub-devices, but in order for it to
> > > actually work we need the i2c bus to get registered at probe time and
> > > not in bridge attach time.
> > > 
> > > Cc: Lyude Paul <lyude@redhat.com>
> > > Cc: Thierry Reding <treding@nvidia.com>
> > > Signed-off-by: Douglas Anderson <dianders@chromium.org>
> > > ---
> > > 
> > > Changes in v6:
> > > - ("drm/dp: Allow an early call to register DDC i2c bus") new for v6.
> > > 
> > >  drivers/gpu/drm/drm_dp_helper.c | 67 +++++++++++++++++++++++++++------
> > >  include/drm/drm_dp_helper.h     |  2 +
> > >  2 files changed, 57 insertions(+), 12 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_dp_helper.c
> > > b/drivers/gpu/drm/drm_dp_helper.c
> > > index cb56d74e9d38..830294f0b341 100644
> > > --- a/drivers/gpu/drm/drm_dp_helper.c
> > > +++ b/drivers/gpu/drm/drm_dp_helper.c
> > > @@ -1757,6 +1757,49 @@ void drm_dp_aux_init(struct drm_dp_aux *aux)
> > >  }
> > >  EXPORT_SYMBOL(drm_dp_aux_init);
> > >  
> > > +/**
> > > + * drm_dp_aux_register_ddc() - register the DDC parts of the aux
> > > channel
> > > + * @aux: DisplayPort AUX channel
> > > + *
> > > + * This can be called after drm_dp_aux_init() to fully register the ddc
> > > bus
> > > + * as an i2c adapter with the rest of Linux.
> > > + *
> > > + * If you don't explicitly call this function it will be done
> > > implicitly as
> > > + * part of drm_dp_aux_register().
> > > + *
> > > + * Returns 0 on success or a negative error code on failure.
> > > + */
> > > +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux)
> > > +{
> > > +       WARN_ON_ONCE(!aux->dev);
> > > +
> > > +       aux->ddc.class = I2C_CLASS_DDC;
> > > +       aux->ddc.owner = THIS_MODULE;
> > > +       aux->ddc.dev.parent = aux->dev;
> > > +
> > > +       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux-
> > > >dev),
> > > +               sizeof(aux->ddc.name));
> > > +
> > > +       return i2c_add_adapter(&aux->ddc);
> > > +}
> > > +EXPORT_SYMBOL(drm_dp_aux_register_ddc);
> > > +
> > > +/**
> > > + * drm_dp_aux_unregister_ddc() - unregister the DDC parts of the aux
> > > channel
> > > + *
> > > + * This is useful if you called drm_dp_aux_register_ddc(). If you let
> > > + * drm_dp_aux_register() implicitly register the DDC for you then you
> > > don't
> > > + * need to worry about calling this yourself.
> > > + *
> > > + * @aux: DisplayPort AUX channel
> > > + */
> > > +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux)
> > > +{
> > > +       i2c_del_adapter(&aux->ddc);
> > > +       aux->ddc.dev.parent = NULL;
> > > +}
> > > +EXPORT_SYMBOL(drm_dp_aux_unregister_ddc);
> > > +
> > >  /**
> > >   * drm_dp_aux_register() - initialise and register aux channel
> > >   * @aux: DisplayPort AUX channel
> > > @@ -1793,20 +1836,19 @@ int drm_dp_aux_register(struct drm_dp_aux *aux)
> > >         if (!aux->ddc.algo)
> > >                 drm_dp_aux_init(aux);
> > >  
> > > -       aux->ddc.class = I2C_CLASS_DDC;
> > > -       aux->ddc.owner = THIS_MODULE;
> > > -       aux->ddc.dev.parent = aux->dev;
> > > -
> > > -       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux-
> > > >dev),
> > > -               sizeof(aux->ddc.name));
> > > +       /*
> > > +        * Implicitly register if drm_dp_aux_register_ddc() wasn't
> > > already
> > > +        * called (as evidenced by a NULL parent pointer).
> > > +        */
> > > +       if (!aux->ddc.dev.parent) {
> > > +               ret = drm_dp_aux_register_ddc(aux);
> > > +               if (ret)
> > > +                       return ret;
> > > +       }
> > >  
> > >         ret = drm_dp_aux_register_devnode(aux);
> > > -       if (ret)
> > > -               return ret;
> > > -
> > > -       ret = i2c_add_adapter(&aux->ddc);
> > >         if (ret) {
> > > -               drm_dp_aux_unregister_devnode(aux);
> > > +               drm_dp_aux_unregister_ddc(aux);
> > >                 return ret;
> > >         }
> > >  
> > > @@ -1821,7 +1863,8 @@ EXPORT_SYMBOL(drm_dp_aux_register);
> > >  void drm_dp_aux_unregister(struct drm_dp_aux *aux)
> > >  {
> > >         drm_dp_aux_unregister_devnode(aux);
> > > -       i2c_del_adapter(&aux->ddc);
> > > +       if (aux->ddc.dev.parent)
> > > +               drm_dp_aux_unregister_ddc(aux);
> > >  }
> > >  EXPORT_SYMBOL(drm_dp_aux_unregister);
> > >  
> > > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> > > index e932b2c40095..d4d2d5e25bb7 100644
> > > --- a/include/drm/drm_dp_helper.h
> > > +++ b/include/drm/drm_dp_helper.h
> > > @@ -2021,6 +2021,8 @@ bool
> > > drm_dp_lttpr_pre_emphasis_level_3_supported(const
> > > u8 caps[DP_LTTPR_PHY_CAP_
> > >  
> > >  void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
> > >  void drm_dp_aux_init(struct drm_dp_aux *aux);
> > > +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux);
> > > +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux);
> > >  int drm_dp_aux_register(struct drm_dp_aux *aux);
> > >  void drm_dp_aux_unregister(struct drm_dp_aux *aux);
> > >  
> > 
> > -- 
> > Cheers,
> >  Lyude Paul (she/her)
> >  Software Engineer at Red Hat
> > 
> 

-- 
Cheers,
 Lyude Paul (she/her)
 Software Engineer at Red Hat


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus
  2021-05-07 22:09       ` Lyude Paul
@ 2021-05-14 11:16         ` Jani Nikula
  2021-05-17 20:17           ` Doug Anderson
  0 siblings, 1 reply; 12+ messages in thread
From: Jani Nikula @ 2021-05-14 11:16 UTC (permalink / raw)
  To: Lyude Paul, Bjorn Andersson, David Airlie, Ville Syrjala
  Cc: Neil Armstrong, David Airlie, dri-devel, linux-kernel,
	Andrzej Hajda, Laurent Pinchart, Sam Ravnborg, robdclark,
	Ville Syrjala, Stanislav Lisovskiy, Thierry Reding,
	Thomas Zimmermann, Jonas Karlman, linux-arm-msm, Stephen Boyd,
	Steev Klimaszewski, Jernej Skrabec, Douglas Anderson,
	Wolfram Sang, linux-i2c

On Fri, 07 May 2021, Lyude Paul <lyude@redhat.com> wrote:
> On Fri, 2021-05-07 at 17:00 -0500, Bjorn Andersson wrote:
>> On Fri 07 May 16:18 CDT 2021, Lyude Paul wrote:
>> 
>> > Adding ville from Intel to also get their take on this.
>> > 
>> > In general we've been trying to move DRM to a design where we don't expose
>> > any
>> > devices until everything is ready. That's pretty much the main reason that
>> > we
>> > register things during bridge attach time. Note though that even before
>> > the
>> > DDC bus is registered it should still be usable, just things like
>> > get_device()
>> > won't work.
>> > 
>> > This isn't the first time we've run into a problem like the one you're
>> > trying
>> > to solve though, Tegra currently has a similar issue. Something we
>> > discussed
>> > as a possible long-term solution for this was splitting i2c_add_adapter()
>> > into
>> > a minimal initialization function and a registration function. Linux's
>> > device
>> > core already allows for this (device_initialize() and device_add(), which
>> > are
>> > called together when device_register() is called). Would this be a
>> > solution
>> > that might work for you (and even better, would you possibly be willing to
>> > write the patches? :)
>> > 
>> 
>> It's not enough that the adapter is half-baked, because the bridge's
>> initialization depends on that the panel device is done probing, and the
>> panel driver will only complete its probe if it can find it's resources.
>> 
>> So we need a mechanism to fully create the resources exposed by the
>> bridge chip (i2c bus, gpio chip and (soon) a pwm chip), then allow the
>> panel to probe and after that initialize the bridge.
>> 
>> We did discuss possible ways to register these resources and then
>> "sleep for a while" before resolving the panel, but what we came up with
>> was definitely suboptimal - and ugly.
>
> Sigh, I'm really starting to wonder if we should reconsider the rules on
> exposing ddc adapters early...
>
> Danvet, Jani, and/or airlied: can I get your take on this?

Granted, I did not study this in detail, but it sounds like we'd need to
be able to add and use an i2c adapter in kernel, before deciding to
register it with the userspace. But that does not seem to be as trivial
as making it possible to call the now-static i2c_register_adapter()
separately.


BR,
Jani.


>
>> 
>> Regards,
>> Bjorn
>> 
>> > On Mon, 2021-05-03 at 14:58 -0700, Douglas Anderson wrote:
>> > > It can be helpful to fully register the AUX channel as an i2c bus even
>> > > before the bridge is created. Let's optionally allow bridges to do
>> > > that.
>> > > 
>> > > Specifically the case we're running into:
>> > > - The panel driver wants to get its DDC bus at probe time.
>> > > - The ti-sn65dsi86 MIPI-to-eDP bridge code, which provides the DDC
>> > >   bus, wants to get the panel at probe time.
>> > > 
>> > > The next patches ("drm/bridge: ti-sn65dsi86: Promote the AUX channel
>> > > to its own sub-dev") solves the chicken-and-egg problem by breaking
>> > > the ti-sn65dsi86 driver into sub-devices, but in order for it to
>> > > actually work we need the i2c bus to get registered at probe time and
>> > > not in bridge attach time.
>> > > 
>> > > Cc: Lyude Paul <lyude@redhat.com>
>> > > Cc: Thierry Reding <treding@nvidia.com>
>> > > Signed-off-by: Douglas Anderson <dianders@chromium.org>
>> > > ---
>> > > 
>> > > Changes in v6:
>> > > - ("drm/dp: Allow an early call to register DDC i2c bus") new for v6.
>> > > 
>> > >  drivers/gpu/drm/drm_dp_helper.c | 67 +++++++++++++++++++++++++++------
>> > >  include/drm/drm_dp_helper.h     |  2 +
>> > >  2 files changed, 57 insertions(+), 12 deletions(-)
>> > > 
>> > > diff --git a/drivers/gpu/drm/drm_dp_helper.c
>> > > b/drivers/gpu/drm/drm_dp_helper.c
>> > > index cb56d74e9d38..830294f0b341 100644
>> > > --- a/drivers/gpu/drm/drm_dp_helper.c
>> > > +++ b/drivers/gpu/drm/drm_dp_helper.c
>> > > @@ -1757,6 +1757,49 @@ void drm_dp_aux_init(struct drm_dp_aux *aux)
>> > >  }
>> > >  EXPORT_SYMBOL(drm_dp_aux_init);
>> > >  
>> > > +/**
>> > > + * drm_dp_aux_register_ddc() - register the DDC parts of the aux
>> > > channel
>> > > + * @aux: DisplayPort AUX channel
>> > > + *
>> > > + * This can be called after drm_dp_aux_init() to fully register the ddc
>> > > bus
>> > > + * as an i2c adapter with the rest of Linux.
>> > > + *
>> > > + * If you don't explicitly call this function it will be done
>> > > implicitly as
>> > > + * part of drm_dp_aux_register().
>> > > + *
>> > > + * Returns 0 on success or a negative error code on failure.
>> > > + */
>> > > +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux)
>> > > +{
>> > > +       WARN_ON_ONCE(!aux->dev);
>> > > +
>> > > +       aux->ddc.class = I2C_CLASS_DDC;
>> > > +       aux->ddc.owner = THIS_MODULE;
>> > > +       aux->ddc.dev.parent = aux->dev;
>> > > +
>> > > +       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux-
>> > > >dev),
>> > > +               sizeof(aux->ddc.name));
>> > > +
>> > > +       return i2c_add_adapter(&aux->ddc);
>> > > +}
>> > > +EXPORT_SYMBOL(drm_dp_aux_register_ddc);
>> > > +
>> > > +/**
>> > > + * drm_dp_aux_unregister_ddc() - unregister the DDC parts of the aux
>> > > channel
>> > > + *
>> > > + * This is useful if you called drm_dp_aux_register_ddc(). If you let
>> > > + * drm_dp_aux_register() implicitly register the DDC for you then you
>> > > don't
>> > > + * need to worry about calling this yourself.
>> > > + *
>> > > + * @aux: DisplayPort AUX channel
>> > > + */
>> > > +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux)
>> > > +{
>> > > +       i2c_del_adapter(&aux->ddc);
>> > > +       aux->ddc.dev.parent = NULL;
>> > > +}
>> > > +EXPORT_SYMBOL(drm_dp_aux_unregister_ddc);
>> > > +
>> > >  /**
>> > >   * drm_dp_aux_register() - initialise and register aux channel
>> > >   * @aux: DisplayPort AUX channel
>> > > @@ -1793,20 +1836,19 @@ int drm_dp_aux_register(struct drm_dp_aux *aux)
>> > >         if (!aux->ddc.algo)
>> > >                 drm_dp_aux_init(aux);
>> > >  
>> > > -       aux->ddc.class = I2C_CLASS_DDC;
>> > > -       aux->ddc.owner = THIS_MODULE;
>> > > -       aux->ddc.dev.parent = aux->dev;
>> > > -
>> > > -       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux-
>> > > >dev),
>> > > -               sizeof(aux->ddc.name));
>> > > +       /*
>> > > +        * Implicitly register if drm_dp_aux_register_ddc() wasn't
>> > > already
>> > > +        * called (as evidenced by a NULL parent pointer).
>> > > +        */
>> > > +       if (!aux->ddc.dev.parent) {
>> > > +               ret = drm_dp_aux_register_ddc(aux);
>> > > +               if (ret)
>> > > +                       return ret;
>> > > +       }
>> > >  
>> > >         ret = drm_dp_aux_register_devnode(aux);
>> > > -       if (ret)
>> > > -               return ret;
>> > > -
>> > > -       ret = i2c_add_adapter(&aux->ddc);
>> > >         if (ret) {
>> > > -               drm_dp_aux_unregister_devnode(aux);
>> > > +               drm_dp_aux_unregister_ddc(aux);
>> > >                 return ret;
>> > >         }
>> > >  
>> > > @@ -1821,7 +1863,8 @@ EXPORT_SYMBOL(drm_dp_aux_register);
>> > >  void drm_dp_aux_unregister(struct drm_dp_aux *aux)
>> > >  {
>> > >         drm_dp_aux_unregister_devnode(aux);
>> > > -       i2c_del_adapter(&aux->ddc);
>> > > +       if (aux->ddc.dev.parent)
>> > > +               drm_dp_aux_unregister_ddc(aux);
>> > >  }
>> > >  EXPORT_SYMBOL(drm_dp_aux_unregister);
>> > >  
>> > > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
>> > > index e932b2c40095..d4d2d5e25bb7 100644
>> > > --- a/include/drm/drm_dp_helper.h
>> > > +++ b/include/drm/drm_dp_helper.h
>> > > @@ -2021,6 +2021,8 @@ bool
>> > > drm_dp_lttpr_pre_emphasis_level_3_supported(const
>> > > u8 caps[DP_LTTPR_PHY_CAP_
>> > >  
>> > >  void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
>> > >  void drm_dp_aux_init(struct drm_dp_aux *aux);
>> > > +int drm_dp_aux_register_ddc(struct drm_dp_aux *aux);
>> > > +void drm_dp_aux_unregister_ddc(struct drm_dp_aux *aux);
>> > >  int drm_dp_aux_register(struct drm_dp_aux *aux);
>> > >  void drm_dp_aux_unregister(struct drm_dp_aux *aux);
>> > >  
>> > 
>> > -- 
>> > Cheers,
>> >  Lyude Paul (she/her)
>> >  Software Engineer at Red Hat
>> > 
>> 

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node
  2021-05-03 21:58 ` [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node Douglas Anderson
@ 2021-05-17 20:16   ` Doug Anderson
  0 siblings, 0 replies; 12+ messages in thread
From: Doug Anderson @ 2021-05-17 20:16 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Lyude Paul, Steev Klimaszewski, Stephen Boyd, Bjorn Andersson,
	linux-arm-msm, Stanislav Lisovskiy, Linus W, Rob Clark,
	Maarten Lankhorst, Thierry Reding, linux-i2c, dri-devel, LKML,
	Andrzej Hajda, Neil Armstrong, Laurent Pinchart, Jonas Karlman,
	Jernej Skrabec, Sam Ravnborg

Hi,

On Mon, May 3, 2021 at 2:59 PM Douglas Anderson <dianders@chromium.org> wrote:
>
> The of_find_i2c_adapter_by_node() could end up failing to find an
> adapter in certain conditions. Specifically it's possible that
> of_dev_or_parent_node_match() could end up finding an I2C client in
> the list and cause bus_find_device() to stop early even though an I2C
> adapter was present later in the list.
>
> Let's move the i2c_verify_adapter() into the predicate function to
> prevent this. Now we'll properly skip over the I2C client and be able
> to find the I2C adapter.
>
> This issue has always been a potential problem if a single device tree
> node could represent both an I2C client and an adapter. I believe this
> is a sane thing to do if, for instance, an I2C-connected DP bridge
> chip is present. The bridge chip is an I2C client but it can also
> provide an I2C adapter (DDC tunneled over AUX channel). We don't want
> to have to create a sub-node just so a panel can link to it with the
> "ddc-i2c-bus" property.
>
> I believe that this problem got worse, however, with commit
> e814e688413a ("i2c: of: Try to find an I2C adapter matching the
> parent"). Starting at that commit it would be even easier to
> accidentally miss finding the adapter.
>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
> Later patches in this series won't work right without this one, but
> they won't crash. If we can't find the i2c bus we'll just fall back to
> the hardcoded panel modes which, at least today, all panels have.
>
> I'll also note that part of me wonders if we should actually fix this
> further to run two passes through everything: first look to see if we
> find an exact match and only look at the parent pointer if there is no
> match. I don't currently have a need for that and it's a slightly
> bigger change, but it seems conceivable that it could affect someone?
>
> (no changes since v1)
>
>  drivers/i2c/i2c-core-of.c | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)

FYI that I've just posted v7 of this series and I've dropped
${SUBJECT} patch from my series.

I think that ${SUBJECT} patch is still correct and could be useful to
land, but it's no longer needed by my series since I'm getting access
to the DDC bus in a different way. If this patch needs to be spun,
please let me know. ...or, feel free to land it! :-)

-Doug

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus
  2021-05-14 11:16         ` Jani Nikula
@ 2021-05-17 20:17           ` Doug Anderson
  0 siblings, 0 replies; 12+ messages in thread
From: Doug Anderson @ 2021-05-17 20:17 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Lyude Paul, Bjorn Andersson, David Airlie, Ville Syrjala,
	Rob Clark, Wolfram Sang, Jernej Skrabec, Neil Armstrong,
	David Airlie, linux-arm-msm, Jonas Karlman, LKML, dri-devel,
	Stephen Boyd, Stanislav Lisovskiy, Andrzej Hajda,
	Laurent Pinchart, Thomas Zimmermann, Thierry Reding,
	Sam Ravnborg, Steev Klimaszewski, linux-i2c

Hi,

On Fri, May 14, 2021 at 4:16 AM Jani Nikula <jani.nikula@intel.com> wrote:
>
> On Fri, 07 May 2021, Lyude Paul <lyude@redhat.com> wrote:
> > On Fri, 2021-05-07 at 17:00 -0500, Bjorn Andersson wrote:
> >> On Fri 07 May 16:18 CDT 2021, Lyude Paul wrote:
> >>
> >> > Adding ville from Intel to also get their take on this.
> >> >
> >> > In general we've been trying to move DRM to a design where we don't expose
> >> > any
> >> > devices until everything is ready. That's pretty much the main reason that
> >> > we
> >> > register things during bridge attach time. Note though that even before
> >> > the
> >> > DDC bus is registered it should still be usable, just things like
> >> > get_device()
> >> > won't work.
> >> >
> >> > This isn't the first time we've run into a problem like the one you're
> >> > trying
> >> > to solve though, Tegra currently has a similar issue. Something we
> >> > discussed
> >> > as a possible long-term solution for this was splitting i2c_add_adapter()
> >> > into
> >> > a minimal initialization function and a registration function. Linux's
> >> > device
> >> > core already allows for this (device_initialize() and device_add(), which
> >> > are
> >> > called together when device_register() is called). Would this be a
> >> > solution
> >> > that might work for you (and even better, would you possibly be willing to
> >> > write the patches? :)
> >> >
> >>
> >> It's not enough that the adapter is half-baked, because the bridge's
> >> initialization depends on that the panel device is done probing, and the
> >> panel driver will only complete its probe if it can find it's resources.
> >>
> >> So we need a mechanism to fully create the resources exposed by the
> >> bridge chip (i2c bus, gpio chip and (soon) a pwm chip), then allow the
> >> panel to probe and after that initialize the bridge.
> >>
> >> We did discuss possible ways to register these resources and then
> >> "sleep for a while" before resolving the panel, but what we came up with
> >> was definitely suboptimal - and ugly.
> >
> > Sigh, I'm really starting to wonder if we should reconsider the rules on
> > exposing ddc adapters early...
> >
> > Danvet, Jani, and/or airlied: can I get your take on this?
>
> Granted, I did not study this in detail, but it sounds like we'd need to
> be able to add and use an i2c adapter in kernel, before deciding to
> register it with the userspace. But that does not seem to be as trivial
> as making it possible to call the now-static i2c_register_adapter()
> separately.

To close the loop: I think the point is now moot in v7. Now crossing
my fingers that approach can gain momentum. If not, I might come back
here. ;-)

-Doug

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-05-17 20:26 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-03 21:58 [PATCH v6 0/5] drm: Fix EDID reading on ti-sn65dsi86; solve some chicken-and-egg problems Douglas Anderson
2021-05-03 21:58 ` [PATCH v6 1/5] i2c: i2c-core-of: Fix corner case of finding adapter by node Douglas Anderson
2021-05-17 20:16   ` Doug Anderson
2021-05-03 21:58 ` [PATCH v6 2/5] drm/dp: Allow an early call to register DDC i2c bus Douglas Anderson
2021-05-07 21:18   ` Lyude Paul
2021-05-07 22:00     ` Bjorn Andersson
2021-05-07 22:09       ` Lyude Paul
2021-05-14 11:16         ` Jani Nikula
2021-05-17 20:17           ` Doug Anderson
2021-05-03 21:58 ` [PATCH v6 3/5] drm/bridge: ti-sn65dsi86: Promote the AUX channel to its own sub-dev Douglas Anderson
2021-05-03 21:58 ` [PATCH v6 4/5] drm/bridge: ti-sn65dsi86: Don't read EDID blob over DDC Douglas Anderson
2021-05-03 21:58 ` [PATCH v6 5/5] arm64: dts: qcom: Link the panel to the bridge's DDC bus Douglas Anderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).