* [PATCH 5/7] drm/msm/hdmi: Convert to use GPIO descriptors
[not found] ` <20190629125933.679-1-linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
@ 2019-06-29 12:59 ` Linus Walleij
2019-06-29 12:59 ` [PATCH 6/7] RFT: drm/msm/hdmi: Bring up HDMI connector OFF Linus Walleij
` (3 subsequent siblings)
4 siblings, 0 replies; 13+ messages in thread
From: Linus Walleij @ 2019-06-29 12:59 UTC (permalink / raw)
To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Maarten Lankhorst,
Maxime Ripard, Sean Paul
Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
freedreno-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Rob Clark,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
This switches the MSM HDMI code to use GPIO descriptors.
Normally we would fetch the GPIOs from the device with the
flags GPIOD_IN or GPIOD_OUT_[LOW|HIGH] to set up the lines
immediately, but since the code seems eager to actively
drive the lines high/low when turning HDMI on and off, we
just fetch the GPIOs as-is and keep the code explicitly
driving them.
The old code would try legacy bindings (GPIOs without any
"-gpios" suffix) but this has been moved to the gpiolib
as a quirk by the previous patch.
Cc: Rob Clark <robdclark@gmail.com>
Cc: Sean Paul <sean@poorly.run>
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/gpu/drm/msm/hdmi/hdmi.c | 66 +++++++++++------------
drivers/gpu/drm/msm/hdmi/hdmi.h | 4 +-
drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 42 +++++----------
3 files changed, 45 insertions(+), 67 deletions(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index e247d6942a49..c8e8268c76e2 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -436,38 +436,6 @@ static const struct {
{ "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" },
};
-static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name)
-{
- int gpio;
-
- /* try with the gpio names as in the table (downstream bindings) */
- gpio = of_get_named_gpio(of_node, name, 0);
- if (gpio < 0) {
- char name2[32];
-
- /* try with the gpio names as in the upstream bindings */
- snprintf(name2, sizeof(name2), "%s-gpios", name);
- gpio = of_get_named_gpio(of_node, name2, 0);
- if (gpio < 0) {
- char name3[32];
-
- /*
- * try again after stripping out the "qcom,hdmi-tx"
- * prefix. This is mainly to match "hpd-gpios" used
- * in the upstream bindings
- */
- if (sscanf(name2, "qcom,hdmi-tx-%s", name3))
- gpio = of_get_named_gpio(of_node, name3, 0);
- }
-
- if (gpio < 0) {
- DBG("failed to get gpio: %s (%d)", name, gpio);
- gpio = -1;
- }
- }
- return gpio;
-}
-
/*
* HDMI audio codec callbacks
*/
@@ -593,11 +561,39 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
- hdmi_cfg->gpios[i].num = msm_hdmi_get_gpio(of_node,
- msm_hdmi_gpio_pdata[i].name);
+ const char *name = msm_hdmi_gpio_pdata[i].name;
+ struct gpio_desc *gpiod;
+
+ /*
+ * We are fetching the GPIO lines "as is" since the connector
+ * code is enabling and disabling the lines. Until that point
+ * the power-on default value will be kept.
+ */
+ gpiod = devm_gpiod_get_optional(dev, name, GPIOD_ASIS);
+ /* This will catch e.g. -PROBE_DEFER */
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
+ if (!gpiod) {
+ /* Try a second time, stripping down the name */
+ char name3[32];
+
+ /*
+ * Try again after stripping out the "qcom,hdmi-tx"
+ * prefix. This is mainly to match "hpd-gpios" used
+ * in the upstream bindings.
+ */
+ if (sscanf(name, "qcom,hdmi-tx-%s", name3))
+ gpiod = devm_gpiod_get_optional(dev, name3, GPIOD_ASIS);
+ if (IS_ERR(gpiod))
+ return PTR_ERR(gpiod);
+ if (!gpiod)
+ DBG("failed to get gpio: %s", name);
+ }
+ hdmi_cfg->gpios[i].gpiod = gpiod;
+ if (gpiod)
+ gpiod_set_consumer_name(gpiod, msm_hdmi_gpio_pdata[i].label);
hdmi_cfg->gpios[i].output = msm_hdmi_gpio_pdata[i].output;
hdmi_cfg->gpios[i].value = msm_hdmi_gpio_pdata[i].value;
- hdmi_cfg->gpios[i].label = msm_hdmi_gpio_pdata[i].label;
}
dev->platform_data = hdmi_cfg;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 5c5df6ab2a57..3ef956e8de71 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/hdmi.h>
#include "msm_drv.h"
@@ -33,10 +34,9 @@ struct hdmi_phy;
struct hdmi_platform_config;
struct hdmi_gpio_data {
- int num;
+ struct gpio_desc *gpiod;
bool output;
int value;
- const char *label;
};
struct hdmi_audio {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index a6eeab2c4dc3..c4e9f6d7960f 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -15,7 +15,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include "msm_kms.h"
@@ -79,30 +79,21 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi)
static int gpio_config(struct hdmi *hdmi, bool on)
{
- struct device *dev = &hdmi->pdev->dev;
const struct hdmi_platform_config *config = hdmi->config;
- int ret, i;
+ int i;
if (on) {
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i];
- if (gpio.num != -1) {
- ret = gpio_request(gpio.num, gpio.label);
- if (ret) {
- DRM_DEV_ERROR(dev,
- "'%s'(%d) gpio_request failed: %d\n",
- gpio.label, gpio.num, ret);
- goto err;
- }
-
+ if (gpio.gpiod) {
if (gpio.output) {
- gpio_direction_output(gpio.num,
- gpio.value);
+ gpiod_direction_output(gpio.gpiod,
+ gpio.value);
} else {
- gpio_direction_input(gpio.num);
- gpio_set_value_cansleep(gpio.num,
- gpio.value);
+ gpiod_direction_input(gpio.gpiod);
+ gpiod_set_value_cansleep(gpio.gpiod,
+ gpio.value);
}
}
}
@@ -112,29 +103,20 @@ static int gpio_config(struct hdmi *hdmi, bool on)
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i];
- if (gpio.num == -1)
+ if (!gpio.gpiod)
continue;
if (gpio.output) {
int value = gpio.value ? 0 : 1;
- gpio_set_value_cansleep(gpio.num, value);
+ gpiod_set_value_cansleep(gpio.gpiod, value);
}
-
- gpio_free(gpio.num);
};
DBG("gpio off");
}
return 0;
-err:
- while (i--) {
- if (config->gpios[i].num != -1)
- gpio_free(config->gpios[i].num);
- }
-
- return ret;
}
static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
@@ -322,7 +304,7 @@ static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
const struct hdmi_platform_config *config = hdmi->config;
struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
- return gpio_get_value(hpd_gpio.num) ?
+ return gpiod_get_value(hpd_gpio.gpiod) ?
connector_status_connected :
connector_status_disconnected;
}
@@ -341,7 +323,7 @@ static enum drm_connector_status hdmi_connector_detect(
* some platforms may not have hpd gpio. Rely only on the status
* provided by REG_HDMI_HPD_INT_STATUS in this case.
*/
- if (hpd_gpio.num == -1)
+ if (!hpd_gpio.gpiod)
return detect_reg(hdmi);
do {
--
2.20.1
_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 6/7] RFT: drm/msm/hdmi: Bring up HDMI connector OFF
[not found] ` <20190629125933.679-1-linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2019-06-29 12:59 ` [PATCH 5/7] drm/msm/hdmi: Convert to use GPIO descriptors Linus Walleij
@ 2019-06-29 12:59 ` Linus Walleij
2019-06-29 12:59 ` [PATCH 7/7] RFT: drm/msm/hdmi: Do not initialize HPD line value Linus Walleij
` (2 subsequent siblings)
4 siblings, 0 replies; 13+ messages in thread
From: Linus Walleij @ 2019-06-29 12:59 UTC (permalink / raw)
To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Maarten Lankhorst,
Maxime Ripard, Sean Paul
Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
freedreno-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Rob Clark,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
There is elaborate code in the HDMI connector handling to
leave the connector in the state it was at power-on and
only touch the GPIOs when the connector .enable() and
.disable() callbacks are called.
I don't think this is what we normally want, initialize
the connector as OFF (possibly saving power?) using the
appropriate GPIO descriptor flags. It will still be
switched on/off in the enable()/disable() connector
callback as before, but we can drop some strange surplus
code.
Cc: Rob Clark <robdclark@gmail.com>
Cc: Sean Paul <sean@poorly.run>
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/gpu/drm/msm/hdmi/hdmi.c | 19 ++++++++++++-----
drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 25 ++++++-----------------
2 files changed, 20 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c8e8268c76e2..7d87f8821d2f 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -563,13 +563,22 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
const char *name = msm_hdmi_gpio_pdata[i].name;
struct gpio_desc *gpiod;
+ enum gpiod_flags flags;
/*
- * We are fetching the GPIO lines "as is" since the connector
- * code is enabling and disabling the lines. Until that point
- * the power-on default value will be kept.
+ * Notice the inverse set up here: we initialize the connector
+ * to OFF state.
*/
- gpiod = devm_gpiod_get_optional(dev, name, GPIOD_ASIS);
+ if (msm_hdmi_gpio_pdata[i].output) {
+ if (msm_hdmi_gpio_pdata[i].value)
+ flags = GPIOD_OUT_LOW;
+ else
+ flags = GPIOD_OUT_HIGH;
+ } else {
+ flags = GPIOD_IN;
+ }
+
+ gpiod = devm_gpiod_get_optional(dev, name, flags);
/* This will catch e.g. -PROBE_DEFER */
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
@@ -583,7 +592,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
* in the upstream bindings.
*/
if (sscanf(name, "qcom,hdmi-tx-%s", name3))
- gpiod = devm_gpiod_get_optional(dev, name3, GPIOD_ASIS);
+ gpiod = devm_gpiod_get_optional(dev, name3, flags);
if (IS_ERR(gpiod))
return PTR_ERR(gpiod);
if (!gpiod)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index c4e9f6d7960f..89c64cc85027 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -86,16 +86,9 @@ static int gpio_config(struct hdmi *hdmi, bool on)
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i];
- if (gpio.gpiod) {
- if (gpio.output) {
- gpiod_direction_output(gpio.gpiod,
- gpio.value);
- } else {
- gpiod_direction_input(gpio.gpiod);
- gpiod_set_value_cansleep(gpio.gpiod,
- gpio.value);
- }
- }
+ /* The value indicates the value for turning things on */
+ if (gpio.gpiod)
+ gpiod_set_value_cansleep(gpio.gpiod, gpio.value);
}
DBG("gpio on");
@@ -103,16 +96,10 @@ static int gpio_config(struct hdmi *hdmi, bool on)
for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
struct hdmi_gpio_data gpio = config->gpios[i];
- if (!gpio.gpiod)
- continue;
-
- if (gpio.output) {
- int value = gpio.value ? 0 : 1;
-
- gpiod_set_value_cansleep(gpio.gpiod, value);
- }
+ /* The inverse value turns stuff off */
+ if (gpio.gpiod && gpio.output)
+ gpiod_set_value_cansleep(gpio.gpiod, !gpio.value);
};
-
DBG("gpio off");
}
--
2.20.1
_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 7/7] RFT: drm/msm/hdmi: Do not initialize HPD line value
[not found] ` <20190629125933.679-1-linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2019-06-29 12:59 ` [PATCH 5/7] drm/msm/hdmi: Convert to use GPIO descriptors Linus Walleij
2019-06-29 12:59 ` [PATCH 6/7] RFT: drm/msm/hdmi: Bring up HDMI connector OFF Linus Walleij
@ 2019-06-29 12:59 ` Linus Walleij
2019-07-28 10:02 ` [PATCH 1/7] drm/msm/mdp4: Drop unused GPIO include Linus Walleij
2019-08-13 0:22 ` Brian Masney
4 siblings, 0 replies; 13+ messages in thread
From: Linus Walleij @ 2019-06-29 12:59 UTC (permalink / raw)
To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Maarten Lankhorst,
Maxime Ripard, Sean Paul
Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
freedreno-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Rob Clark,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
After untangling the MSM HDMI GPIO code we see that the code
is deliberately setting the output value of the HPD (hot plug
detect) line to high, even though it is being used as input
which is of course the only viable use of a HPD pin.
This seems dubious: GPIO lines set up as input will have high
impedance (tristate) and the typical electronic construction
involves this line being used with a pull-down resistor around
10KOhm to keep it low (this is sometimes part of a levelshifter
component) and then an inserted connector will pull it up to
VDD and this asserts the HPD signal, as can be seen from the
code reading the HPD GPIO.
Stop try driving a value to the HPD input GPIO.
Cc: Rob Clark <robdclark@gmail.com>
Cc: Sean Paul <sean@poorly.run>
Cc: linux-arm-msm@vger.kernel.org
Cc: freedreno@lists.freedesktop.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index 89c64cc85027..ecbcd8638b66 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -87,7 +87,7 @@ static int gpio_config(struct hdmi *hdmi, bool on)
struct hdmi_gpio_data gpio = config->gpios[i];
/* The value indicates the value for turning things on */
- if (gpio.gpiod)
+ if (gpio.gpiod && gpio.output)
gpiod_set_value_cansleep(gpio.gpiod, gpio.value);
}
--
2.20.1
_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 1/7] drm/msm/mdp4: Drop unused GPIO include
[not found] ` <20190629125933.679-1-linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
` (2 preceding siblings ...)
2019-06-29 12:59 ` [PATCH 7/7] RFT: drm/msm/hdmi: Do not initialize HPD line value Linus Walleij
@ 2019-07-28 10:02 ` Linus Walleij
2019-08-05 9:01 ` Linus Walleij
2019-08-13 0:22 ` Brian Masney
4 siblings, 1 reply; 13+ messages in thread
From: Linus Walleij @ 2019-07-28 10:02 UTC (permalink / raw)
To: open list:DRM PANEL DRIVERS, Maarten Lankhorst, Maxime Ripard,
Sean Paul
Cc: MSM, Rob Clark, freedreno, Linux ARM
On Sat, Jun 29, 2019 at 3:01 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> This file is not using any symbols from <linux/gpio.h> so just
> drop this include.
>
> Cc: Rob Clark <robdclark@gmail.com>
> Cc: Sean Paul <sean@poorly.run>
> Cc: linux-arm-msm@vger.kernel.org
> Cc: freedreno@lists.freedesktop.org
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Rob & friends: can this be merged to wherever you merge
the MSM DRM patches? If it is in drm-misc I can apply it
but I need some ACKs.
Yours,
Linus Walleij
_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH 1/7] drm/msm/mdp4: Drop unused GPIO include
2019-07-28 10:02 ` [PATCH 1/7] drm/msm/mdp4: Drop unused GPIO include Linus Walleij
@ 2019-08-05 9:01 ` Linus Walleij
0 siblings, 0 replies; 13+ messages in thread
From: Linus Walleij @ 2019-08-05 9:01 UTC (permalink / raw)
To: open list:DRM PANEL DRIVERS, Maarten Lankhorst, Maxime Ripard,
Sean Paul
Cc: MSM, freedreno, Linux ARM
On Sun, Jul 28, 2019 at 12:02 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> On Sat, Jun 29, 2019 at 3:01 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> > This file is not using any symbols from <linux/gpio.h> so just
> > drop this include.
> >
> > Cc: Rob Clark <robdclark@gmail.com>
> > Cc: Sean Paul <sean@poorly.run>
> > Cc: linux-arm-msm@vger.kernel.org
> > Cc: freedreno@lists.freedesktop.org
> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>
> Rob & friends: can this be merged to wherever you merge
> the MSM DRM patches? If it is in drm-misc I can apply it
> but I need some ACKs.
Ping on this!
Yours,
Linus Walleij
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/7] drm/msm/mdp4: Drop unused GPIO include
[not found] ` <20190629125933.679-1-linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
` (3 preceding siblings ...)
2019-07-28 10:02 ` [PATCH 1/7] drm/msm/mdp4: Drop unused GPIO include Linus Walleij
@ 2019-08-13 0:22 ` Brian Masney
4 siblings, 0 replies; 13+ messages in thread
From: Brian Masney @ 2019-08-13 0:22 UTC (permalink / raw)
To: Linus Walleij
Cc: freedreno-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Maxime Ripard,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, Maarten Lankhorst,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Rob Clark, Sean Paul,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
On Sat, Jun 29, 2019 at 02:59:27PM +0200, Linus Walleij wrote:
> This file is not using any symbols from <linux/gpio.h> so just
> drop this include.
>
> Cc: Rob Clark <robdclark@gmail.com>
> Cc: Sean Paul <sean@poorly.run>
> Cc: linux-arm-msm@vger.kernel.org
> Cc: freedreno@lists.freedesktop.org
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
For the series:
Reviewed-by: Brian Masney <masneyb@onstation.org>
_______________________________________________
Freedreno mailing list
Freedreno@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/freedreno
^ permalink raw reply [flat|nested] 13+ messages in thread