[PATCH v2 2/2] drm/bridge: it6505: Drop EDID cache on bridge power off

2024-09-26 Thread Pin-yen Lin
The bridge might miss the display change events when it's powered off.
This happens when a user changes the external monitor when the system
is suspended and the embedded controller doesn't not wake AP up.

It's also observed that one DP-to-HDMI bridge doesn't work correctly
when there is no EDID read after it is powered on.

Drop the cache to force an EDID read after system resume to fix this.

Fixes: 11feaef69d0c ("drm/bridge: it6505: Add caching for EDID")
Signed-off-by: Pin-yen Lin 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 

---

Changes in v2:
- Collect review tags

 drivers/gpu/drm/bridge/ite-it6505.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index 1e1c06fdf206..bb449efac2f4 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -3101,6 +3101,8 @@ static __maybe_unused int it6505_bridge_suspend(struct 
device *dev)
 {
struct it6505 *it6505 = dev_get_drvdata(dev);
 
+   it6505_remove_edid(it6505);
+
return it6505_poweroff(it6505);
 }
 
-- 
2.46.0.792.g87dc391469-goog



[PATCH v2 1/2] drm/bridge: anx7625: Drop EDID cache on bridge power off

2024-09-26 Thread Pin-yen Lin
The bridge might miss the display change events when it's powered off.
This happens when a user changes the external monitor when the system
is suspended and the embedded controller doesn't not wake AP up.

It's also observed that one DP-to-HDMI bridge doesn't work correctly
when there is no EDID read after it is powered on.

Drop the cache to force an EDID read after system resume to fix this.

Fixes: 8bdfc5dae4e3 ("drm/bridge: anx7625: Add anx7625 MIPI DSI/DPI to DP")
Signed-off-by: Pin-yen Lin 
Reviewed-by: Dmitry Baryshkov 

---

Changes in v2:
- Only drop the EDID cache for anx7625 when it's not in eDP mode
- Collect review tag

 drivers/gpu/drm/bridge/analogix/anx7625.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 88e4aa5830f3..5c6bd7be25c0 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -2561,6 +2561,8 @@ static int __maybe_unused 
anx7625_runtime_pm_suspend(struct device *dev)
mutex_lock(&ctx->lock);
 
anx7625_stop_dp_work(ctx);
+   if (!ctx->pdata.panel_bridge)
+   anx7625_remove_edid(ctx);
anx7625_power_standby(ctx);
 
mutex_unlock(&ctx->lock);
-- 
2.46.0.792.g87dc391469-goog



[PATCH v2 0/2] Drop EDID cache for it6505/anx7625 when the bridge is powered off

2024-09-26 Thread Pin-yen Lin
This mainly fixes the use case when the user changes the external monitor
when the system is suspended. Without this series, both of the bridges
will skip the EDID read and returned the cached one after resume.

Apart from that, we also observed a DP-to-HDMI bridge expects an EDID read
after it's powered on. This patch also works around the problem by always
triggering the EDID read after the system resume.

Changes in v2:
- Only drop the EDID cache for anx7625 when it's not in eDP mode
- Collect review tags

Pin-yen Lin (2):
  drm/bridge: anx7625: Drop EDID cache on bridge power off
  drm/bridge: it6505: Drop EDID cache on bridge power off

 drivers/gpu/drm/bridge/analogix/anx7625.c | 2 ++
 drivers/gpu/drm/bridge/ite-it6505.c   | 2 ++
 2 files changed, 4 insertions(+)

-- 
2.46.0.792.g87dc391469-goog



Re: [PATCH 2/2] drm/bridge: it6505: Drop EDID cache on bridge power off

2024-09-24 Thread Pin-yen Lin
Hi,

On Wed, Sep 25, 2024 at 1:48 AM Doug Anderson  wrote:
>
> Hi,
>
> On Mon, Sep 23, 2024 at 8:53 PM Pin-yen Lin  wrote:
> >
> > The bridge might miss the display change events when it's powered off.
> > This happens when a user changes the external monitor when the system
> > is suspended and the embedded controller doesn't not wake AP up.
> >
> > It's also observed that one DP-to-HDMI bridge doesn't work correctly
> > when there is no EDID read after it is powered on.
> >
> > Drop the cache to force an EDID read after system resume to fix this.
> >
> > Fixes: 11feaef69d0c ("drm/bridge: it6505: Add caching for EDID")
> > Signed-off-by: Pin-yen Lin 
>
> Ah, I guess this answers my question in the previous patch about
> whether caching was important even for external displays since this
> driver only supports external DP and the commit you mention in "Fixes"
> says that caching was important.
>
> So this looks reasonable. One thing I wonder is if you're totally
> guaranteed to get a PM Runtime suspend whenever you get an unplug /
> replug of a display. I tried to dig a little bit but I'm not super
> familiar with this bridge and it looks complicated enough that I guess
> I'll have to trust that it's fine. So...

it6505_remove_edid() is also called when the bridge reads HPD low in
the IRQ handler or the DPCD sink count changes to 0 after a HPD_IRQ
signal. The assumption here is that if the bridge is still powered on,
then it should be aware of the monitor change events and drop the EDID
cache when needed. This patch addresses the scenario where monitor
changes are not communicated to the bridge when it is powered off.
>
> Reviewed-by: Douglas Anderson 

Regards,
Pin-yen


Re: [PATCH 1/2] drm/bridge: anx7625: Drop EDID cache on bridge power off

2024-09-24 Thread Pin-yen Lin
Hi,

On Wed, Sep 25, 2024 at 12:43 AM Doug Anderson  wrote:
>
> Hi,
>
> On Mon, Sep 23, 2024 at 8:53 PM Pin-yen Lin  wrote:
> >
> > The bridge might miss the display change events when it's powered off.
> > This happens when a user changes the external monitor when the system
> > is suspended and the embedded controller doesn't not wake AP up.
> >
> > It's also observed that one DP-to-HDMI bridge doesn't work correctly
> > when there is no EDID read after it is powered on.
> >
> > Drop the cache to force an EDID read after system resume to fix this.
> >
> > Fixes: 8bdfc5dae4e3 ("drm/bridge: anx7625: Add anx7625 MIPI DSI/DPI to DP")
> > Signed-off-by: Pin-yen Lin 
> > ---
> >
> >  drivers/gpu/drm/bridge/analogix/anx7625.c | 1 +
> >  1 file changed, 1 insertion(+)
>
> I'm not totally sure if it matters, but I wonder if you should change
> this to only delete the EDID cache if you're in DP mode and not eDP
> mode? For eDP mode the panel is not allowed to change and re-reading
> it needlessly seems like it would slow down things like
> suspend/resume. I think this would only matter if someone were using
> eDP panels in the "old" way (not under the aux-bus) because we don't
> set the "DRM_BRIDGE_OP_EDID" when we see "aux-bus", so maybe we don't
> care that much but still...

I'll update this in v2.
>
> Other than that, I know that there have been discussions in the past
> about EDID caches but I can't quite remember all the details. I know
> that panel-edp.c still caches it, so we must have concluded that it's
> at least fine/reasonable for panels. I don't remember whether caching
> is encouraged / suggested for external displays, though. Do you happen
> to know if it even makes a difference there (in other words, do you
> actually see multiple calls to read the EDID when you plug in a DP
> display)?

At least on ChromeOS, Chrome triggers two EDID reads when I plug in an
external monitor. I'm not sure if this is common for other DRM masters
though.
>
> -Doug

Regards,
Pin-yen


[PATCH 2/2] drm/bridge: it6505: Drop EDID cache on bridge power off

2024-09-23 Thread Pin-yen Lin
The bridge might miss the display change events when it's powered off.
This happens when a user changes the external monitor when the system
is suspended and the embedded controller doesn't not wake AP up.

It's also observed that one DP-to-HDMI bridge doesn't work correctly
when there is no EDID read after it is powered on.

Drop the cache to force an EDID read after system resume to fix this.

Fixes: 11feaef69d0c ("drm/bridge: it6505: Add caching for EDID")
Signed-off-by: Pin-yen Lin 

---

 drivers/gpu/drm/bridge/ite-it6505.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index 1e1c06fdf206..bb449efac2f4 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -3101,6 +3101,8 @@ static __maybe_unused int it6505_bridge_suspend(struct 
device *dev)
 {
struct it6505 *it6505 = dev_get_drvdata(dev);
 
+   it6505_remove_edid(it6505);
+
return it6505_poweroff(it6505);
 }
 
-- 
2.46.0.792.g87dc391469-goog



[PATCH 1/2] drm/bridge: anx7625: Drop EDID cache on bridge power off

2024-09-23 Thread Pin-yen Lin
The bridge might miss the display change events when it's powered off.
This happens when a user changes the external monitor when the system
is suspended and the embedded controller doesn't not wake AP up.

It's also observed that one DP-to-HDMI bridge doesn't work correctly
when there is no EDID read after it is powered on.

Drop the cache to force an EDID read after system resume to fix this.

Fixes: 8bdfc5dae4e3 ("drm/bridge: anx7625: Add anx7625 MIPI DSI/DPI to DP")
Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/analogix/anx7625.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 88e4aa5830f3..b4c1f00f1c3d 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -2561,6 +2561,7 @@ static int __maybe_unused 
anx7625_runtime_pm_suspend(struct device *dev)
mutex_lock(&ctx->lock);
 
anx7625_stop_dp_work(ctx);
+   anx7625_remove_edid(ctx);
anx7625_power_standby(ctx);
 
mutex_unlock(&ctx->lock);
-- 
2.46.0.792.g87dc391469-goog



[PATCH 0/2] Drop EDID cache for it6505/anx7625 when the bridge is powered off

2024-09-23 Thread Pin-yen Lin
This mainly fixes the use case when the user changes the external monitor
when the system is suspended. Without this series, both of the bridges
will skip the EDID read and returned the cached one after resume.

Apart from that, we also observed a DP-to-HDMI bridge expects an EDID read
after it's powered on. This patch also works around the problem by always
triggering the EDID read after the system resume.


Pin-yen Lin (2):
  drm/bridge: anx7625: Drop EDID cache on bridge power off
  drm/bridge: it6505: Drop EDID cache on bridge power off

 drivers/gpu/drm/bridge/analogix/anx7625.c | 1 +
 drivers/gpu/drm/bridge/ite-it6505.c   | 2 ++
 2 files changed, 3 insertions(+)

-- 
2.46.0.792.g87dc391469-goog



Re: [PATCH v3 2/3] drm/bridge: it6505: HDCP CTS fail on repeater items

2024-09-23 Thread Pin-yen Lin
On Tue, Sep 24, 2024 at 10:57 AM  wrote:
>
> >On Mon, Sep 23, 2024 at 10:45:49AM GMT, hermes...@ite.com.tw wrote:
> >> >On Mon, Sep 23, 2024 at 05:48:28PM GMT, Hermes Wu wrote:
> >> >> From: Hermes Wu 
> >> >>
> >> >> Changes in v3:
> >> >>  -add detials about fail item and changes.
> >> >>
> >> >>
> >> >> Fix HDCP CTS fail items on UNIGRAF DRP-100
> >> >>
> >> >> DUT must Support 127 devices.
> >> >> DUT must check BSTATUS when receive CP_IRQ.
> >> >> DUT must enable encryption when R0' is ready.
> >> >> DUT must retry V' check 3 times.
> >> >> it6505 must read DRP-100 KSV FIFO by FIFO mode.
> >> >> it6505 should restart HDCP within 5s if KSV not ready.
> >> >
> >> >Still not readable.
> >> >
> >> >English text, please. Split the patch to fix one issue at a time.
> >> >Describe the _reason_ for the change. Annotate fixes with Fixes tags.
> >> >
> >>
> >> with fixes tag include drm/bridge like this ?  => "Fixes: drm/bridge: 
> >> it6505: HDCP CTS fail 1B-xx"
> >
> >No. Please read the document that I have been pointing you to. It describes 
> >all the tags and procedures.
> >
> >>
> >> About the reason about bug fixes.
> >>
> >> for example, the 1B-01 device count.
> >> will this readable?
> >>
> >> " When connect to HDCP repeater, it6505 must support 127 downstream 
> >> devices. "
> >>
> >> And this will be only one change in a patch?
> >
> >Let me repeat the phrase that you have quoted few lines above. "Split the 
> >patch to fix one issue at a time." So, no, this will not be the only change 
> >in the patch.
> >
>
> The HDCP CTS include serval items, I should split each failure item fixes 
> into different patch?

Yes, please. You can mention in the cover letter that those patches
are fixing HDCP CTS failures, but please fix one issue at a time and
explain what it fixes in the commit message.
>
>
> >>
> >> >>
> >> >> Signed-off-by: Hermes Wu 
> >> >> ---
> >> >>  drivers/gpu/drm/bridge/ite-it6505.c | 112
> >> >> ++--
> >> >>  1 file changed, 74 insertions(+), 38 deletions(-)
> >> >
> >> >--
> >> >With best wishes
> >> >Dmitry
> >>
> >> BR,
> >> Hermes
> >
> >--
> >With best wishes
> >Dmitry

Regards,
Pin-yen


Re: [PATCH v1] drm/bridge: it6505: HDCP CTS fail on repeater items

2024-09-23 Thread Pin-yen Lin
On Mon, Sep 23, 2024 at 3:25 PM  wrote:
>
> Hi
>
> BR,
> Hermes
>
>
> >-Original Message-
> >From: Dmitry Baryshkov 
> >Sent: Monday, September 23, 2024 2:16 PM
> >To: Hermes Wu (吳佳宏) 
> >Cc: treapk...@chromium.org; a.ha...@samsung.com; narmstr...@baylibre.com; 
> >robert.f...@linaro.org; laurent.pinch...@ideasonboard.com; jo...@kwiboo.se; 
> >jernej.>skra...@gmail.com; airl...@gmail.com; dan...@ffwll.ch; 
> >dri-devel@lists.freedesktop.org; linux-ker...@vger.kernel.org; Kenneth Hung 
> >(洪家倫) 
> >Subject: Re: [PATCH v1] drm/bridge: it6505: HDCP CTS fail on repeater items
> >
> >Hi,
> >
> >On Mon, Sep 23, 2024 at 05:21:41AM GMT, hermes...@ite.com.tw wrote:
> >> Hi
> >>
> >> Sorry for the confusion caused
> >
> >Please don't top post. Answers should come below the original quoted
> >text, not above it. Otherwise reading the email becomes really hard.
> >
> >>
> >> Last patches did not switch to drm-misc-nest. And I need re-create patches.
> >>
> >> The HDCP patches is now on tow threads.(This one and the one include MCCS 
> >> patches with cover letter)
> >
> >Just make sure that when you send the next iteration of the HDCP + MCSS
> >patches you provide the history of the changes in the changelog (either
> >in the cover letter or in the individual patches). Also please don't
> >send several patches using the same vN. I'd point out the 'b4' tool, it
> >can automate a lot of such topics for you.
> >
> I will check using of B4 tools
>
> >> Should I keep on this thread or restart a new thread?
> >
> >Please always send new revisions as a new thread. Otherwise your patches
> >can easily get lost.
> >
> >I suppose that [1] is the latest revision. Please review and implement
> >the feedback that was provided to all iterations of your pachset, then
> >send v3 as a separate new thread.
> >
> >[1] 
> >https://lore.kernel.org/dri-devel/vxs3eklfifsnaq5rn6kppegfv3plsviqaq5nvlzo3fgazwj6y7@od4atbvf5ep3/T/#u
> >
>
> A suggestion that a aux path need separate to different path, this change 
> will before HDCP
I assume you mean something needs to be a separate patch...? I don't
really get this sentence.
> Won't it become more complicate?
>
> it goes like this?
>
> Patch V1 aux
> Patch V3 HDCP
> Patch V3 MCCS
The whole series should share the same version number, so you can send
out a v3 series that contains these three patches. Just mark the new
aux patch as "new in v3" in your change log.

Regards,
Pin-yen
>
>
> >>
> >>
> >> BR,
> >> Hermes
> >> -Original Message-
> >> From: Dmitry Baryshkov 
> >> Sent: Friday, September 20, 2024 11:50 PM
> >> To: Pin-yen Lin 
> >> Cc: Hermes Wu (吳佳宏) ; Andrzej Hajda 
> >> ; Neil Armstrong ; Robert 
> >> Foss ; >Laurent Pinchart 
> >> ; Jonas Karlman ; 
> >> Jernej Skrabec ; David Airlie 
> >> ; >Daniel Vetter ; open list:DRM 
> >> DRIVERS ; open list 
> >> ; Kenneth Hung (洪家倫) 
> >> h...@ite.com.tw>
> >> Subject: Re: [PATCH v1] drm/bridge: it6505: HDCP CTS fail on repeater items
> >>
> >> On Fri, Sep 20, 2024 at 01:27:54PM GMT, Pin-yen Lin wrote:
> >> > On Thu, Sep 19, 2024 at 10:58 AM  wrote:
> >> > >
> >> > > From: Hermes Wu 
> >> > >
> >> > > Fix HDCP CTS items on UNIGRAF DPR-100.
> >> > >
> >> > > Signed-off-by: Hermes Wu 
> >> >
> >> > Reviewed-by: Pin-yen Lin 
> >>
> >> For the sake of somebody applying the patch because it was R-B'ed
> >>
> >> Nacked-by: Dmitry Baryshkov 
> >>
> >> The commit message doesn't describe what is being done and why, it
> >> doesn't have Fixes tags, etc.
> >>
> >> Hermes, I'm not sure what's happening on your side. I have seen several
> >> revisions of this patch with minimal modifications (and being a part of
> >> different series). Some of them were marked as v1 (although you've sent
> >> different patches as v1), other had v2 (but no changelog, etc). Please
> >> adhere to the described process of sending patches.
> >>
> >> --
> >> With best wishes
> >> Dmitry
>
> --
> With best wishes
> Dmitry
>
> BR,
> Hermes
>
>
> -Original Message-
> From: Dmitry Baryshkov 
> Sent: Monday, September 23, 2024 2:16 PM
&

Re: [PATCH v1 1/2] drm/bridge: it6505: HDCP CTS fail on repeater items

2024-09-20 Thread Pin-yen Lin
Hi Hermes,
On Thu, Sep 19, 2024 at 5:20 PM Hermes Wu  wrote:
>
> From: allen chen 
>
> Fix HDCP CTS items on UNIGRAF DPR-100.
>
> Change-Id: I03f0758779f73164c8ae2fdf61e41dc693e27605
>
> Change-Id: Ib7a8fabaeccd56d3bd7c8adc7384a363b0f7b88d
Remove the Change-Id's as mentioned in the other patch.
> Signed-off-by: Hermes Wu 
You'll want to add a Co-developed-by tag if you make modifications on
this patch.
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 152 ++--
>  1 file changed, 101 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index 7a4608844de3..cef02c8c363e 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -298,11 +298,11 @@
>  #define MAX_LANE_COUNT 4
>  #define MAX_LINK_RATE HBR
>  #define AUTO_TRAIN_RETRY 3
> -#define MAX_HDCP_DOWN_STREAM_COUNT 10
> +#define MAX_HDCP_DOWN_STREAM_COUNT 127
>  #define MAX_CR_LEVEL 0x03
>  #define MAX_EQ_LEVEL 0x03
>  #define AUX_WAIT_TIMEOUT_MS 15
> -#define AUX_FIFO_MAX_SIZE 32
> +#define AUX_FIFO_MAX_SIZE 16
>  #define PIXEL_CLK_DELAY 1
>  #define PIXEL_CLK_INVERSE 0
>  #define ADJUST_PHASE_THRESHOLD 8
> @@ -326,6 +326,9 @@ enum aux_cmd_type {
> CMD_AUX_NATIVE_READ = 0x0,
> CMD_AUX_NATIVE_WRITE = 0x5,
> CMD_AUX_I2C_EDID_READ = 0xB,
> +
> +   /*extend read ncommand */
> +   CMD_AUX_GET_KSV_LIST = 0x10,
>  };
>
>  enum aux_cmd_reply {
> @@ -973,7 +976,7 @@ static ssize_t it6505_aux_operation(struct it6505 *it6505,
> it6505_set_bits(it6505, REG_AUX_CTRL, AUX_USER_MODE, AUX_USER_MODE);
>
>  aux_op_start:
> -   if (cmd == CMD_AUX_I2C_EDID_READ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == CMD_AUX_GET_KSV_LIST) {
> /* AUX EDID FIFO has max length of AUX_FIFO_MAX_SIZE bytes. */
> size = min_t(size_t, size, AUX_FIFO_MAX_SIZE);
> /* Enable AUX FIFO read back and clear FIFO */
> @@ -1004,7 +1007,7 @@ static ssize_t it6505_aux_operation(struct it6505 
> *it6505,
>   size);
>
> /* Aux Fire */
> -   it6505_write(it6505, REG_AUX_CMD_REQ, cmd);
> +   it6505_write(it6505, REG_AUX_CMD_REQ, (cmd & 0x0F));
>
> ret = it6505_aux_wait(it6505);
> if (ret < 0)
> @@ -1038,7 +1041,7 @@ static ssize_t it6505_aux_operation(struct it6505 
> *it6505,
> goto aux_op_start;
> }
>
> -   if (cmd == CMD_AUX_I2C_EDID_READ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == CMD_AUX_GET_KSV_LIST) {
> for (i = 0; i < size; i++) {
> ret = it6505_read(it6505, REG_AUX_DATA_FIFO);
> if (ret < 0)
> @@ -1063,7 +1066,7 @@ static ssize_t it6505_aux_operation(struct it6505 
> *it6505,
> ret = i;
>
>  aux_op_err:
> -   if (cmd == CMD_AUX_I2C_EDID_READ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == CMD_AUX_GET_KSV_LIST) {
> /* clear AUX FIFO */
> it6505_set_bits(it6505, REG_AUX_CTRL,
> AUX_EN_FIFO_READ | CLR_EDID_FIFO,
> @@ -1084,18 +1087,25 @@ static ssize_t it6505_aux_do_transfer(struct it6505 
> *it6505,
>   size_t size, enum aux_cmd_reply *reply)
>  {
> int i, ret_size, ret = 0, request_size;
> +   struct device *dev = &it6505->client->dev;
This is unused and removed in the following patch. Please remove this.
>
> mutex_lock(&it6505->aux_lock);
> -   for (i = 0; i < size; i += 4) {
> -   request_size = min((int)size - i, 4);
> +   for (i = 0; i < size; ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == 
> CMD_AUX_GET_KSV_LIST)
> +   request_size = min((int)size - i, AUX_FIFO_MAX_SIZE);
> +   else
> +   request_size = min((int)size - i, 4);
> +
> ret_size = it6505_aux_operation(it6505, cmd, address + i,
> buffer + i, request_size,
> reply);
> +
Remove the blank line here.
> if (ret_size < 0) {
> ret = ret_size;
> goto aux_op_err;
> }
>
> +   i += request_size;
> ret += ret_size;
> }
>
> @@ -1186,6 +1196,35 @@ static int it6505_get_edid_block(void *data, u8 *buf, 
> unsigned int block,
> return 0;
>  }
>
> +static int it6505_get_ksvlist(struct it6505 *it6505, u8 *buf, size_t len)
> +{
> +   int i, request_size, ret;
> +   struct device *dev = &it6505->client->dev;
> +   enum aux_cmd_reply reply;
> +
> +   for (i = 0; i < len; ) {
> +   request_size = min((int)len - i, 15);
> +
> +   ret = it6505_aux_do_transfer(it6505, CMD_AUX_GET_KSV_LIST,
> +DP_AUX_HDCP_KSV_FIFO,
> +

Re: [PATCH v1 2/2] drm/bridge: it6505: Add MSSC suport

2024-09-20 Thread Pin-yen Lin
On Thu, Sep 19, 2024 at 5:20 PM Hermes Wu  wrote:
>
> From: "Hermes.Wu" 
>
> add AUX-I2C functionality to support MCCS.
>
> Change-Id: I63e1a0e5da67526f89f35605a82944be67dee8ac
Remove the Change-Id line. If you run scripts/checkpatch.pl, the
script should catch this for you.

> Signed-off-by: Hermes Wu 
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 209 ++--
>  1 file changed, 200 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index cef02c8c363e..1a272c67e82b 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -127,6 +127,9 @@
>  #define REG_AUX_ADR_16_19 0x26
>  #define REG_AUX_OUT_DATA0 0x27
>
> +#define REG_AUX_I2C_ADR 0x25
> +#define REG_AUX_I2C_OP 0x26
> +
>  #define REG_AUX_CMD_REQ 0x2B
>  #define AUX_BUSY BIT(5)
>
> @@ -268,6 +271,19 @@
>  #define REG_SSC_CTRL1 0x189
>  #define REG_SSC_CTRL2 0x18A
>
> +#define REG_AUX_USER_CTRL 0x190
> +#define EN_USER_AUX BIT(0)
> +#define USER_AUX_DONE BIT(1)
> +#define AUX_EVENT BIT(4)
> +
> +#define REG_AUX_USER_DATA_REC 0x191
> +#define M_AUX_IN_REC   0xF0
> +#define M_AUX_OUT_REC  0x0F
> +
> +#define REG_AUX_USER_TXB 0x190
> +#define REG_AUX_USER_REPLY 0x19A
> +#define REG_AUX_USER_RXB(n) (n + 0x19B)
> +
>  #define RBR DP_LINK_BW_1_62
>  #define HBR DP_LINK_BW_2_7
>  #define HBR2 DP_LINK_BW_5_4
> @@ -303,6 +319,8 @@
>  #define MAX_EQ_LEVEL 0x03
>  #define AUX_WAIT_TIMEOUT_MS 15
>  #define AUX_FIFO_MAX_SIZE 16
> +#define AUX_I2C_MAX_SIZE 4
> +#define AUX_I2C_DEFER_RETRY 4
>  #define PIXEL_CLK_DELAY 1
>  #define PIXEL_CLK_INVERSE 0
>  #define ADJUST_PHASE_THRESHOLD 8
> @@ -325,7 +343,12 @@
>  enum aux_cmd_type {
> CMD_AUX_NATIVE_READ = 0x0,
> CMD_AUX_NATIVE_WRITE = 0x5,
> +   CMD_AUX_GI2C_ADR = 0x08,
> +   CMD_AUX_GI2C_READ = 0x09,
> +   CMD_AUX_GI2C_WRITE = 0x0A,
> CMD_AUX_I2C_EDID_READ = 0xB,
> +   CMD_AUX_I2C_READ = 0x0D,
> +   CMD_AUX_I2C_WRITE = 0x0C,
>
> /*extend read ncommand */
> CMD_AUX_GET_KSV_LIST = 0x10,
> @@ -333,8 +356,11 @@ enum aux_cmd_type {
>
>  enum aux_cmd_reply {
> REPLY_ACK,
> -   REPLY_NACK,
> -   REPLY_DEFER,
> +   REPLY_NACK = 1,
> +   REPLY_DEFER = 2,
> +
> +   REPLY_I2C_NACK = 4,
> +   REPLY_I2C_DEFER = 8,
>  };
>
>  enum link_train_status {
> @@ -1087,7 +1113,6 @@ static ssize_t it6505_aux_do_transfer(struct it6505 
> *it6505,
>   size_t size, enum aux_cmd_reply *reply)
>  {
> int i, ret_size, ret = 0, request_size;
> -   struct device *dev = &it6505->client->dev;
The drm-misc/drm-misc-next doesn't have it6505->client node. It's
already removed at commit d65feac281ab ("drm/bridge: Remove redundant
i2c_client in anx7625/it6505").

Please rebase your patch.
>
> mutex_lock(&it6505->aux_lock);
> for (i = 0; i < size; ) {
> @@ -1114,6 +1139,168 @@ static ssize_t it6505_aux_do_transfer(struct it6505 
> *it6505,
> return ret;
>  }
>
> +
> +static int it6505_aux_i2c_wait(struct it6505 *it6505, u8 *reply)
> +{
> +   int err = 0;
> +   unsigned long timeout;
> +   struct device *dev = &it6505->client->dev;
> +
> +   timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
> +
> +   do {
> +   if (it6505_read(it6505, REG_AUX_USER_CTRL) & AUX_EVENT)
Do we need to assign err if it6505_read returns error?
> +   break;
> +   if (time_after(jiffies, timeout)) {
> +   dev_err(dev, "Timed out waiting AUX I2C, BUSY = %X\n",
> +   it6505_aux_op_finished(it6505));
> +   err = -ETIMEDOUT;
> +   goto end_aux_i2c_wait;
> +   }
> +   usleep_range(300, 800);
> +
> +   } while (!it6505_aux_op_finished(it6505));
Can this loop be changed to regmap_read_poll_timeout()?
> +
> +   if (reply == NULL)
> +   goto end_aux_i2c_wait;
If reply is NULL, then there will be a NULL pointer dereference at
it6505_aux_i2c_readb() anyway. From the usages in drm_dp_helper.c, I
doubt if this pointer is possible to be NULL. Even if it could, you
should have done this check earlier.
> +
> +   *reply = it6505_read(it6505, REG_AUX_USER_REPLY) >> 4;
> +
> +   if (*reply == 0)
> +   goto end_aux_i2c_wait;
> +
> +   if ((*reply == DP_AUX_NATIVE_REPLY_DEFER) ||
> +   (*reply == DP_AUX_I2C_REPLY_DEFER))
> +   err = -EBUSY;
> +   else if ((*reply == DP_AUX_NATIVE_REPLY_NACK) ||
> +   (*reply == DP_AUX_I2C_REPLY_NACK))
> +   err = -ENXIO;
> +
> +end_aux_i2c_wait:
> +   it6505_set_bits(it6505, REG_AUX_USER_CTRL, USER_AUX_DONE, 
> USER_AUX_DONE);
> +   return err;
> +}
> +
> +static int it6505_aux_i2c_readb(struct it6505 *it6505, u8 *buf, size_t size, 
> u8 *reply)
> +{
> + 

Re: [PATCH v1] drm/bridge: it6505: HDCP CTS fail on repeater items

2024-09-19 Thread Pin-yen Lin
On Thu, Sep 19, 2024 at 10:58 AM  wrote:
>
> From: Hermes Wu 
>
> Fix HDCP CTS items on UNIGRAF DPR-100.
>
> Signed-off-by: Hermes Wu 

Reviewed-by: Pin-yen Lin 
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 152 ++--
>  1 file changed, 101 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index 7a4608844de3..cef02c8c363e 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -298,11 +298,11 @@
>  #define MAX_LANE_COUNT 4
>  #define MAX_LINK_RATE HBR
>  #define AUTO_TRAIN_RETRY 3
> -#define MAX_HDCP_DOWN_STREAM_COUNT 10
> +#define MAX_HDCP_DOWN_STREAM_COUNT 127
>  #define MAX_CR_LEVEL 0x03
>  #define MAX_EQ_LEVEL 0x03
>  #define AUX_WAIT_TIMEOUT_MS 15
> -#define AUX_FIFO_MAX_SIZE 32
> +#define AUX_FIFO_MAX_SIZE 16
>  #define PIXEL_CLK_DELAY 1
>  #define PIXEL_CLK_INVERSE 0
>  #define ADJUST_PHASE_THRESHOLD 8
> @@ -326,6 +326,9 @@ enum aux_cmd_type {
> CMD_AUX_NATIVE_READ = 0x0,
> CMD_AUX_NATIVE_WRITE = 0x5,
> CMD_AUX_I2C_EDID_READ = 0xB,
> +
> +   /*extend read ncommand */
> +   CMD_AUX_GET_KSV_LIST = 0x10,
>  };
>
>  enum aux_cmd_reply {
> @@ -973,7 +976,7 @@ static ssize_t it6505_aux_operation(struct it6505 *it6505,
> it6505_set_bits(it6505, REG_AUX_CTRL, AUX_USER_MODE, AUX_USER_MODE);
>
>  aux_op_start:
> -   if (cmd == CMD_AUX_I2C_EDID_READ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == CMD_AUX_GET_KSV_LIST) {
> /* AUX EDID FIFO has max length of AUX_FIFO_MAX_SIZE bytes. */
> size = min_t(size_t, size, AUX_FIFO_MAX_SIZE);
> /* Enable AUX FIFO read back and clear FIFO */
> @@ -1004,7 +1007,7 @@ static ssize_t it6505_aux_operation(struct it6505 
> *it6505,
>   size);
>
> /* Aux Fire */
> -   it6505_write(it6505, REG_AUX_CMD_REQ, cmd);
> +   it6505_write(it6505, REG_AUX_CMD_REQ, (cmd & 0x0F));
>
> ret = it6505_aux_wait(it6505);
> if (ret < 0)
> @@ -1038,7 +1041,7 @@ static ssize_t it6505_aux_operation(struct it6505 
> *it6505,
> goto aux_op_start;
> }
>
> -   if (cmd == CMD_AUX_I2C_EDID_READ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == CMD_AUX_GET_KSV_LIST) {
> for (i = 0; i < size; i++) {
> ret = it6505_read(it6505, REG_AUX_DATA_FIFO);
> if (ret < 0)
> @@ -1063,7 +1066,7 @@ static ssize_t it6505_aux_operation(struct it6505 
> *it6505,
> ret = i;
>
>  aux_op_err:
> -   if (cmd == CMD_AUX_I2C_EDID_READ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == CMD_AUX_GET_KSV_LIST) {
> /* clear AUX FIFO */
> it6505_set_bits(it6505, REG_AUX_CTRL,
> AUX_EN_FIFO_READ | CLR_EDID_FIFO,
> @@ -1084,18 +1087,25 @@ static ssize_t it6505_aux_do_transfer(struct it6505 
> *it6505,
>   size_t size, enum aux_cmd_reply *reply)
>  {
> int i, ret_size, ret = 0, request_size;
> +   struct device *dev = &it6505->client->dev;
>
> mutex_lock(&it6505->aux_lock);
> -   for (i = 0; i < size; i += 4) {
> -   request_size = min((int)size - i, 4);
> +   for (i = 0; i < size; ) {
> +   if (cmd == CMD_AUX_I2C_EDID_READ || cmd == 
> CMD_AUX_GET_KSV_LIST)
> +   request_size = min((int)size - i, AUX_FIFO_MAX_SIZE);
> +   else
> +   request_size = min((int)size - i, 4);
> +
> ret_size = it6505_aux_operation(it6505, cmd, address + i,
> buffer + i, request_size,
> reply);
> +
> if (ret_size < 0) {
> ret = ret_size;
> goto aux_op_err;
> }
>
> +   i += request_size;
> ret += ret_size;
> }
>
> @@ -1186,6 +1196,35 @@ static int it6505_get_edid_block(void *data, u8 *buf, 
> unsigned int block,
> return 0;
>  }
>
> +static int it6505_get_ksvlist(struct it6505 *it6505, u8 *buf, size_t len)
> +{
> +   int i, request_size, ret;
> +   struct device *dev = &it6505->client->dev;
> +   enum aux_cmd_reply reply;
> +
> +   for (i = 0; i < len; ) {
> +   request_size = min((int)len - i, 15);
> +
> +   ret = it6505_aux_do_transfer(it6505, CMD_AUX_GE

[PATCH 2/2] arm64: dts: mt8183: Add port node to dpi node

2024-09-12 Thread Pin-yen Lin
Add the port node to fix the binding schema check.

Fixes: 009d855a26fd ("arm64: dts: mt8183: add dpi node to mt8183")
Signed-off-by: Pin-yen Lin 
Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202409110843.hm5w9upr-...@intel.com/

---

 arch/arm64/boot/dts/mediatek/mt8183.dtsi | 4 
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi 
b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
index 266441e999f2..0a6578aacf82 100644
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
@@ -1845,6 +1845,10 @@ dpi0: dpi@14015000 {
 <&mmsys CLK_MM_DPI_MM>,
 <&apmixedsys CLK_APMIXED_TVDPLL>;
clock-names = "pixel", "engine", "pll";
+
+   port {
+   dpi_out: endpoint { };
+   };
};
 
mutex: mutex@14016000 {
-- 
2.46.0.662.g92d0881bb0-goog



[PATCH 1/2] dt-bindings: display: mediatek: dpi: Add power-domains to the bindings

2024-09-12 Thread Pin-yen Lin
The power-domains property is used by most DT nodes using mediatek,dpi
bindings. Add this to the bindings to fix the schema check error.

Signed-off-by: Pin-yen Lin 
---

 .../bindings/display/mediatek/mediatek,dpi.yaml   | 8 
 1 file changed, 8 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml 
b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
index 5ca7679d5427..7e0bb88f5856 100644
--- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml
@@ -42,6 +42,12 @@ properties:
   interrupts:
 maxItems: 1
 
+  power-domains:
+description:
+  A phandle and PM domain specifier as defined by bindings
+  of the power controller specified by phandle. See
+  Documentation/devicetree/bindings/power/power-domain.yaml for details.
+
   clocks:
 items:
   - description: Pixel Clock
@@ -82,11 +88,13 @@ examples:
   - |
 #include 
 #include 
+#include 
 
 dpi0: dpi@1401d000 {
 compatible = "mediatek,mt8173-dpi";
 reg = <0x1401d000 0x1000>;
 interrupts = ;
+power-domains = <&spm MT8173_POWER_DOMAIN_MM>;
 clocks = <&mmsys CLK_MM_DPI_PIXEL>,
  <&mmsys CLK_MM_DPI_ENGINE>,
  <&apmixedsys CLK_APMIXED_TVDPLL>;
-- 
2.46.0.662.g92d0881bb0-goog



[PATCH 0/2] Fix dtcheck warnings for mediatek,dpi binding

2024-09-12 Thread Pin-yen Lin
This series fixes two binding schema errors in mediatek,dpi binding.
The first patch adds the power-domain property to the binding, and the
second patch adds the port node as it's required by the binding.


Pin-yen Lin (2):
  dt-bindings: display: mediatek: dpi: Add power-domains to the bindings
  arm64: dts: mt8183: Add port node to dpi node

 .../bindings/display/mediatek/mediatek,dpi.yaml   | 8 
 arch/arm64/boot/dts/mediatek/mt8183.dtsi  | 4 
 2 files changed, 12 insertions(+)

-- 
2.46.0.662.g92d0881bb0-goog



[PATCH] drm/bridge: it6505: Disable IRQ when powered off

2024-07-19 Thread Pin-yen Lin
When the bridge is powered off, disable the IRQ until the next power on
to workaround an interrupt storm on some badly-designed hardware.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/ite-it6505.c | 17 -
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index 1e1c06fdf206..87b8545fccc0 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -460,6 +460,8 @@ struct it6505 {
bool enable_drv_hold;
 
const struct drm_edid *cached_edid;
+
+   int irq;
 };
 
 struct it6505_step_train_para {
@@ -2624,6 +2626,8 @@ static int it6505_poweron(struct it6505 *it6505)
it6505_init(it6505);
it6505_lane_off(it6505);
 
+   enable_irq(it6505->irq);
+
return 0;
 }
 
@@ -2640,6 +2644,8 @@ static int it6505_poweroff(struct it6505 *it6505)
return 0;
}
 
+   disable_irq_nosync(it6505->irq);
+
if (pdata->gpiod_reset)
gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
 
@@ -3389,7 +3395,7 @@ static int it6505_i2c_probe(struct i2c_client *client)
struct it6505 *it6505;
struct device *dev = &client->dev;
struct extcon_dev *extcon;
-   int err, intp_irq;
+   int err;
 
it6505 = devm_kzalloc(&client->dev, sizeof(*it6505), GFP_KERNEL);
if (!it6505)
@@ -3430,17 +3436,18 @@ static int it6505_i2c_probe(struct i2c_client *client)
 
it6505_parse_dt(it6505);
 
-   intp_irq = client->irq;
+   it6505->irq = client->irq;
 
-   if (!intp_irq) {
+   if (!it6505->irq) {
dev_err(dev, "Failed to get INTP IRQ");
err = -ENODEV;
return err;
}
 
-   err = devm_request_threaded_irq(&client->dev, intp_irq, NULL,
+   err = devm_request_threaded_irq(&client->dev, it6505->irq, NULL,
it6505_int_threaded_handler,
-   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+   IRQF_TRIGGER_LOW | IRQF_ONESHOT |
+   IRQF_NO_AUTOEN,
"it6505-intp", it6505);
if (err) {
dev_err(dev, "Failed to request INTP threaded IRQ: %d", err);
-- 
2.45.2.1089.g2a221341d9-goog



[PATCH 2/2] drm/panel-edp: Add more panels with conservative timings

2024-05-27 Thread Pin-yen Lin
Same as commit 7c8690d8fc80 ("drm/panel-edp: Add some panels with
conservative timings"), the 3 panels added in this patch are used by
Mediatek MT8173 Chromebooks and they used to work with the downstream
v4.19 kernel without any specified delay.

These panel IDs were found from in-field reports, but their datahseets
are not available. For BOE 0x0623 and SHP 0x153a, their product names
are retrieved from the EDIDs. The EDID of AUO 0x1999 does not contain
such information, so list as "Unknown" in this patch.

Update these entries with less-conservative timings from other panels of
the same vendor.

Signed-off-by: Pin-yen Lin 

---

 drivers/gpu/drm/panel/panel-edp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 2688ff1eb14f..f5060c9f821d 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1983,6 +1983,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x1999, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, 
"B116XAK01.6"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x203d, &delay_200_500_e50, 
"B140HTN02.0"),
@@ -2007,6 +2008,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0609, &delay_200_500_e50_po2e200, 
"NT116WHM-N21 V4.1"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0623, &delay_200_500_e200, 
"NT116WHM-N21 V4.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"),
@@ -2118,6 +2120,7 @@ static const struct edp_panel_entry edp_panels[] = {
 
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, 
"LQ140M1JW48"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, 
"LQ140M1JW46"),
+   EDP_PANEL_ENTRY('S', 'H', 'P', 0x153a, &delay_200_500_e50, 
"LQ140T1JH01"),
EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, 
"LQ116M1JW10"),
 
EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, 
"2081116HHD028001-51D"),
-- 
2.45.1.288.g0e0cd299f1-goog



[PATCH 1/2] drm/panel-edp: Add support for several panels

2024-05-27 Thread Pin-yen Lin
Add support for the following models:
AUO B140HTN02.0
BOE NT116WHM-N21 V4.1
BOE NT116WHM-N21

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/panel/panel-edp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 01e26b5a2388..2688ff1eb14f 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1985,6 +1985,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, 
"B116XAK01.6"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x203d, &delay_200_500_e50, 
"B140HTN02.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, &delay_200_500_e50, 
"B140HTN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, 
"B116XTN02.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, 
"B116XAN06.1"),
@@ -2005,6 +2006,7 @@ static const struct edp_panel_entry edp_panels[] = {
 
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0609, &delay_200_500_e50_po2e200, 
"NT116WHM-N21 V4.1"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"),
@@ -2020,6 +2022,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x07a8, &delay_200_500_e50_po2e200, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, 
"NV133FHM-N61"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d3, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, 
"NT140FHM-N44"),
-- 
2.45.1.288.g0e0cd299f1-goog



[PATCH 0/2] Support more panels used by MT8173 Chromebooks in edp-panel

2024-05-27 Thread Pin-yen Lin
This series contains 2 patches.

The first patch adds more panel entries with the delays from the
datasheets.

The second patch adds 3 panel entries whose datasheets are not available.
For more backgrounds of the rationale behind these conservative timings,
please refer to the commit message of commit 7c8690d8fc80 ("drm/panel-edp:
Add some panels with conservative timings") and the related mailing list
discussion[1].

[1]: 
https://lore.kernel.org/all/CAD=FV=V=K9L=bjinvfj+k_dhutpxa4wtukxa+e_vw6uihe8...@mail.gmail.com/


Pin-yen Lin (2):
  drm/panel-edp: Add support for several panels
  drm/panel-edp: Add more panels with conservative timings

 drivers/gpu/drm/panel/panel-edp.c | 6 ++
 1 file changed, 6 insertions(+)

-- 
2.45.1.288.g0e0cd299f1-goog



[PATCH] drm/panel-edp: Add AUO B120XAN01.0

2024-03-25 Thread Pin-yen Lin
Add support for the AUO B120XAN01.0 panel.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/panel/panel-edp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index c4f851200aa2..1a4a1ffea2c1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1989,6 +1989,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, 
"B140XTN07.2"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, 
"B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
-- 
2.44.0.396.g6e790dbe36-goog



Re: [PATCH v4 1/1] drm/bridge: it6505: fix hibernate to resume no display issue

2024-03-08 Thread Pin-yen Lin
Hi Kuro,

On Fri, Mar 8, 2024 at 4:54 PM kuro  wrote:
>
> From: Kuro 
>
> ITE added a FIFO reset bit for input video. When system power resume,
> the TTL input of it6505 may get some noise before video signal stable
> and the hardware function reset is required.
> But the input FIFO reset will also trigger error interrupts of output module 
> rising.
> Thus, it6505 have to wait a period can clear those expected error interrupts
> caused by manual hardware reset in one interrupt handler calling to avoid 
> interrupt looping.
>
> Signed-off-by: Kuro Chung 
>
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 50 -
>  1 file changed, 35 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index b53da9bb65a16..eff888fe7c2e7 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -1318,6 +1318,8 @@ static void it6505_video_reset(struct it6505 *it6505)
> it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE);
> it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x02);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x00);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 
> RST_501_FIFO);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00);
> @@ -2475,31 +2477,49 @@ static void it6505_irq_link_train_fail(struct it6505 
> *it6505)
> schedule_work(&it6505->link_works);
>  }
>
> -static void it6505_irq_video_fifo_error(struct it6505 *it6505)
> +static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
>  {
> -   struct device *dev = &it6505->client->dev;
> +   return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
> +}
>
> -   DRM_DEV_DEBUG_DRIVER(dev, "video fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
> +static bool it6505_is_video_error_int(const int *int_status)
> +{
> +   if ((it6505_test_bit(BIT_INT_VID_FIFO_ERROR, (unsigned int 
> *)int_status)) || (it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW, (unsigned int 
> *)int_status)))
> +   return 1;
> +   return 0;
>  }
>
> -static void it6505_irq_io_latch_fifo_overflow(struct it6505 *it6505)
> +static void it6505_irq_video_error_handler(struct it6505 *it6505)
>  {
> struct device *dev = &it6505->client->dev;
> +   int int_status[3] = {0};
> +   int reg_0d;
> +   int i;
>
> -   DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt");
> it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> flush_work(&it6505->link_works);
> it6505_stop_hdcp(it6505);
> it6505_video_reset(it6505);
> -}
>
> -static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
> -{
> -   return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait video...");
> +

I still don't see any code comment around the following section.

> +   for (i = 0; i < 10; i++) {
> +   usleep_range(1, 11000);
> +   int_status[2] = it6505_read(it6505, INT_STATUS_03);
> +   reg_0d = it6505_read(it6505, REG_SYSTEM_STS);
> +   it6505_write(it6505, INT_STATUS_03, int_status[2]);
> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", int_status[2]);
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg0D = 0x%02x", reg_0d);
> +
> +   if ((reg_0d & VIDEO_STB) && (reg_0d >= 0))
> +   break;
> +
> +   if (it6505_is_video_error_int(int_status)) {
> +   it6505_video_reset(it6505);
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait 
> video (%d)", i);
> +   }
> +   }

Okay let me make the questions more specific:

1. What would happen if we remove the loop and only check the video
error interrupts once? If another video error interrupt comes out, we
handle it in the next interrupt handler. Will this lead to an infinite
loop?

2. Why do we run the loop for 10 times (100ms as you mentioned), but
not 5 times or 20 times? Does this "100ms" come from the hardware spec
or your experience on debugging this issue? I guess it's okay if it's
"I tried it a few times and 100ms seems to be just enough", but I
would prefer you to write that down in the code comments.

>  }
>
>  static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
> @@ -2519,8 +2539,6 @@ static irqreturn_t it6505_int_threaded_handler(int 
> unused, void *data)
> { BIT_INT_HDCP_KSV_

Re: [PATCH v3 1/1] UPSTREAM: drm/bridge: it6505: fix hibernate to resume no display issue

2024-03-06 Thread Pin-yen Lin
Hi Kuro,

Following up my comments from v2 [1]:

On Wed, Mar 6, 2024 at 10:09 AM kuro  wrote:
>
> From: kuro chung 
>
> ITE added a FIFO reset bit for input video. When system power resume,
> the TTL input of it6505 may get some noise before video signal stable
> and the hardware function reset is required.
> But the input FIFO reset will also trigger error interrupts of output module 
> rising.
> Thus, it6505 have to wait a period can clear those expected error interrupts
> caused by manual hardware reset in one interrupt handler calling to avoid 
> interrupt looping.
>
> Signed-off-by: Allen Chen 

IIUC you need to sign this off with your name as well. See [2] for more details.
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 54 -
>  1 file changed, 45 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index b53da9bb65a16..e592e14a48578 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -1318,6 +1318,8 @@ static void it6505_video_reset(struct it6505 *it6505)
> it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE);
> it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x02);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x00);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 
> RST_501_FIFO);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00);
> @@ -2480,10 +2482,6 @@ static void it6505_irq_video_fifo_error(struct it6505 
> *it6505)
> struct device *dev = &it6505->client->dev;
>
> DRM_DEV_DEBUG_DRIVER(dev, "video fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
>  }
>
>  static void it6505_irq_io_latch_fifo_overflow(struct it6505 *it6505)
> @@ -2491,10 +2489,6 @@ static void it6505_irq_io_latch_fifo_overflow(struct 
> it6505 *it6505)
> struct device *dev = &it6505->client->dev;
>
> DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
>  }

I don't really like functions that only print one line of debug log,
but I'm not sure what other reviewers think about this.
>
>  static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
> @@ -2502,6 +2496,46 @@ static bool it6505_test_bit(unsigned int bit, const 
> unsigned int *addr)
> return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
>  }
>
> +static bool it6505_is_video_error_int(const int *int_status)
> +{
> +   if ((it6505_test_bit(BIT_INT_VID_FIFO_ERROR, (unsigned int 
> *)int_status)) || (it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW, (unsigned int 
> *)int_status)))
> +   return 1;
> +   return 0;
> +}
> +
> +static void it6505_irq_video_error_handler(struct it6505 *it6505)
> +{
> +   struct device *dev = &it6505->client->dev;
> +   int int_status[3] = {0};
> +   int reg_0d;
> +   int i;
> +
> +   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> +   flush_work(&it6505->link_works);
> +   it6505_stop_hdcp(it6505);
> +   it6505_video_reset(it6505);
> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait video...");
> +
> +   for (i = 0; i < 10; i++) {
> +   usleep_range(1, 11000);
> +   int_status[2] = it6505_read(it6505, INT_STATUS_03);
> +   reg_0d = it6505_read(it6505, REG_SYSTEM_STS);
> +   it6505_write(it6505, INT_STATUS_03, int_status[2]);
> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", int_status[2]);
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg0D = 0x%02x", reg_0d);
> +
> +   if ((reg_0d & VIDEO_STB) && (reg_0d >= 0))
> +   break;
> +
> +   if (it6505_is_video_error_int(int_status)) {
> +   it6505_video_reset(it6505);
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait 
> video (%d)", i);
> +   }
> +   }

Again, I think we need some code comments for this section, and some
of your replies should be included there.

And can you elaborate more about how this speeds up the video
stabilization? What would happen if we only clear the interrupts once
instead of doing a loop?

> +}
> +
>  static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
>  {
> struct it6505 *it6505 = data;
> @@ -2522,7 +2556,7 @@ static irqreturn_t it6505_int_threaded_handler

Re: [PATCH v2 1/1] UPSTREAM: drm/bridge: it6505: fix hibernate to resume no display issue

2024-03-04 Thread Pin-yen Lin
Hi Kuro,

On Mon, Mar 4, 2024 at 11:08 AM kuro  wrote:
>
> From: kuro chung 
>
> ITE added a FIFO reset bit for input video. When system power resume,
> the TTL input of it6505 may get some noise before video signal stable
> and the hardware function reset is required.
> But the input FIFO reset will also trigger error interrupts of output module 
> rising.
> Thus, it6505 have to wait a period can clear those expected error interrupts
> caused by manual hardware reset in one interrupt handler calling to avoid 
> interrupt looping.
>
> Signed-off-by: Allen Chen 
> (cherry picked from commit Iaa3cd9da92a625496f579d87d0ab74ca9c4937c4)
>
> BUG=None
> TEST=None
>
> Change-Id: Iaa3cd9da92a625496f579d87d0ab74ca9c4937c4

Again, please remove the gerrit-specific lines like "BUG=",
"Change-Id", and the "cherry picked from commit ...".
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 54 -
>  1 file changed, 45 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index b53da9bb65a16..e592e14a48578 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -1318,6 +1318,8 @@ static void it6505_video_reset(struct it6505 *it6505)
> it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE);
> it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x02);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x00);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 
> RST_501_FIFO);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00);
> @@ -2480,10 +2482,6 @@ static void it6505_irq_video_fifo_error(struct it6505 
> *it6505)
> struct device *dev = &it6505->client->dev;
>
> DRM_DEV_DEBUG_DRIVER(dev, "video fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
>  }
>
>  static void it6505_irq_io_latch_fifo_overflow(struct it6505 *it6505)
> @@ -2491,10 +2489,6 @@ static void it6505_irq_io_latch_fifo_overflow(struct 
> it6505 *it6505)
> struct device *dev = &it6505->client->dev;
>
> DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
>  }
>
>  static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
> @@ -2502,6 +2496,46 @@ static bool it6505_test_bit(unsigned int bit, const 
> unsigned int *addr)
> return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
>  }
>
> +static bool it6505_is_video_error_int(const int *int_status)
> +{
> +   if ((it6505_test_bit(BIT_INT_VID_FIFO_ERROR, (unsigned int 
> *)int_status)) || (it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW, (unsigned int 
> *)int_status)))
> +   return 1;
> +   return 0;
> +}
> +
> +static void it6505_irq_video_error_handler(struct it6505 *it6505)
> +{
> +   struct device *dev = &it6505->client->dev;
> +   int int_status[3] = {0};
> +   int reg_0d;
> +   int i;
> +
> +   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> +   flush_work(&it6505->link_works);
> +   it6505_stop_hdcp(it6505);
> +   it6505_video_reset(it6505);
> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait video...");
> +
> +   for (i = 0; i < 10; i++) {
> +   usleep_range(1, 11000);
> +   int_status[2] = it6505_read(it6505, INT_STATUS_03);
> +   reg_0d = it6505_read(it6505, REG_SYSTEM_STS);
> +   it6505_write(it6505, INT_STATUS_03, int_status[2]);
> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", int_status[2]);
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg0D = 0x%02x", reg_0d);
> +
> +   if ((reg_0d & VIDEO_STB) && (reg_0d >= 0))
> +   break;
> +
> +   if (it6505_is_video_error_int(int_status)) {
> +   it6505_video_reset(it6505);
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait 
> video (%d)", i);
> +   }
> +   }
> +}
> +
>  static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
>  {
> struct it6505 *it6505 = data;
> @@ -2522,7 +2556,7 @@ static irqreturn_t it6505_int_threaded_handler(int 
> unused, void *data)
> { BIT_INT_VID_FIFO_ERROR, it6505_irq_video_fifo_error },
> { BIT_INT_IO_FIFO_OVERFLOW, it6505_irq_io_latch_fifo_overflow 
> },
> };
> -   int int_status[3], i;
> +   int i

Re: [PATCH] drm/bridge: it6505: fix hibernate to resume no display issue

2024-02-21 Thread Pin-yen Lin
Hi Kuro,

On Wed, Feb 21, 2024 at 3:53 PM kuro  wrote:
>
> From: kuro chung 
>
> ITE added a FIFO reset bit for input video. When system power resume,
> the TTL input of it6505 may get some noise before video signal stable
> and the hardware function reset is required.
> But the input FIFO reset will also trigger error interrupts of output module 
> rising.
> Thus, it6505 have to wait a period can clear those expected error interrupts
> caused by manual hardware reset in one interrupt handler calling to avoid 
> interrupt looping.
>
> Signed-off-by: Allen Chen 

IIUC you should also sign this off with your own account, and don't
include Allen if he is not involved in the patch development.corp
account here

>
> BUG=None
> TEST=None
Please remove these two lines for upstream review.
>
> ---
>  drivers/gpu/drm/bridge/ite-it6505.c | 53 -
>  1 file changed, 44 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
> b/drivers/gpu/drm/bridge/ite-it6505.c
> index b53da9bb65a16..86277968fab93 100644
> --- a/drivers/gpu/drm/bridge/ite-it6505.c
> +++ b/drivers/gpu/drm/bridge/ite-it6505.c
> @@ -1318,6 +1318,8 @@ static void it6505_video_reset(struct it6505 *it6505)
> it6505_set_bits(it6505, REG_DATA_MUTE_CTRL, EN_VID_MUTE, EN_VID_MUTE);
> it6505_set_bits(it6505, REG_INFOFRAME_CTRL, EN_VID_CTRL_PKT, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, VIDEO_RESET);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x02);
> +   it6505_set_bits(it6505, REG_VID_BUS_CTRL1, TX_FIFO_RESET, 0x00);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 
> RST_501_FIFO);
> it6505_set_bits(it6505, REG_501_FIFO_CTRL, RST_501_FIFO, 0x00);
> it6505_set_bits(it6505, REG_RESET_CTRL, VIDEO_RESET, 0x00);
> @@ -2480,10 +2482,6 @@ static void it6505_irq_video_fifo_error(struct it6505 
> *it6505)
> struct device *dev = &it6505->client->dev;
>
> DRM_DEV_DEBUG_DRIVER(dev, "video fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
>  }
>
>  static void it6505_irq_io_latch_fifo_overflow(struct it6505 *it6505)
> @@ -2491,10 +2489,6 @@ static void it6505_irq_io_latch_fifo_overflow(struct 
> it6505 *it6505)
> struct device *dev = &it6505->client->dev;
>
> DRM_DEV_DEBUG_DRIVER(dev, "IO latch fifo overflow interrupt");
> -   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> -   flush_work(&it6505->link_works);
> -   it6505_stop_hdcp(it6505);
> -   it6505_video_reset(it6505);
>  }

Do we need to keep these two functions if they do nothing other than logging?

>
>  static bool it6505_test_bit(unsigned int bit, const unsigned int *addr)
> @@ -2502,6 +2496,45 @@ static bool it6505_test_bit(unsigned int bit, const 
> unsigned int *addr)
> return 1 & (addr[bit / BITS_PER_BYTE] >> (bit % BITS_PER_BYTE));
>  }
>
> +static bool it6505_is_video_error_int(const int *int_status)
> +{
> +   if ((it6505_test_bit(BIT_INT_VID_FIFO_ERROR, (unsigned int 
> *)int_status)) || (it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW, (unsigned int 
> *)int_status)))
> +   return 1;
> +   return 0;
> +}

Maybe just:
return it6505_test_bit(BIT_INT_VID_FIFO_ERROR, (unsigned int
*)int_status) || it6505_test_bit(BIT_INT_IO_FIFO_OVERFLOW, (unsigned
int *)int_status)

> +
> +static void it6505_irq_video_error_handler(struct it6505 *it6505)
> +{
> +   struct device *dev = &it6505->client->dev;
> +   int int_status[3] = {0};
> +   int reg_0d;
> +
> +   it6505->auto_train_retry = AUTO_TRAIN_RETRY;
> +   flush_work(&it6505->link_works);
> +   it6505_stop_hdcp(it6505);
> +   it6505_video_reset(it6505);
> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait video...");
> +

Can you add some code comments here to explain why we need to clear
the interrupt bits here?

> +   for (i = 0; i < 10; i++) {
> +   usleep_range(1, 11000);
> +   int_status[2] = it6505_read(it6505, INT_STATUS_03);
> +   reg_0d = it6505_read(it6505, REG_SYSTEM_STS);
> +   it6505_write(it6505, INT_STATUS_03, int_status[2]);

If we clear all interrupts like this, won't we risk missing other
interrupts here? E.g., if an HPD interrupt is fired here, it will be
cleared without being handled.

> +
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", int_status[2]);
> +   DRM_DEV_DEBUG_DRIVER(dev, "reg0D = 0x%02x", reg_0d);
> +
> +   if ((reg_0d & VIDEO_STB) && (reg_0d >= 0))
> +   break;
> +
> +   if (it6505_is_video_error_int(int_status)) {
> +   it6505_video_reset(it6505);
> +   DRM_DEV_DEBUG_DRIVER(dev, "Video Error reset wait 
> video (%d)", i);
> +   }
> +   }
>

Re: [PATCH] drm/bridge: anx7625: Ensure bridge is suspended in disable()

2024-01-17 Thread Pin-yen Lin
Hi Hsin-Yi,

On Thu, Jan 18, 2024 at 9:59 AM Hsin-Yi Wang  wrote:
>
> Similar to commit 26db46bc9c67 ("drm/bridge: parade-ps8640: Ensure bridge
> is suspended in .post_disable()"). Add a mutex to ensure that aux transfer
> won't race with atomic_disable by holding the PM reference and prevent
> the bridge from suspend.
>
> Also we need to use pm_runtime_put_sync_suspend() to suspend the bridge
> instead of idle with pm_runtime_put_sync().
>
> Fixes: 3203e497eb76 ("drm/bridge: anx7625: Synchronously run runtime 
> suspend.")
> Fixes: adca62ec370c ("drm/bridge: anx7625: Support reading edid through aux 
> channel")
> Signed-off-by: Hsin-Yi Wang 
> Tested-by: Xuxin Xiong 
> ---
>  drivers/gpu/drm/bridge/analogix/anx7625.c | 7 ++-
>  drivers/gpu/drm/bridge/analogix/anx7625.h | 2 ++
>  2 files changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
> b/drivers/gpu/drm/bridge/analogix/anx7625.c
> index ef31033439bc..29d91493b101 100644
> --- a/drivers/gpu/drm/bridge/analogix/anx7625.c
> +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
> @@ -1762,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux 
> *aux,
> u8 request = msg->request & ~DP_AUX_I2C_MOT;
> int ret = 0;
>
> +   mutex_lock(&ctx->aux_lock);
> pm_runtime_get_sync(dev);
> msg->reply = 0;
> switch (request) {
> @@ -1778,6 +1779,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux 
> *aux,
> msg->size, msg->buffer);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> +   mutex_unlock(&ctx->aux_lock);
>
> return ret;
>  }
> @@ -2474,7 +2476,9 @@ static void anx7625_bridge_atomic_disable(struct 
> drm_bridge *bridge,
> ctx->connector = NULL;
> anx7625_dp_stop(ctx);
>
> -   pm_runtime_put_sync(dev);
> +   mutex_lock(&ctx->aux_lock);
> +   pm_runtime_put_sync_suspend(dev);
> +   mutex_unlock(&ctx->aux_lock);
>  }
>
>  static enum drm_connector_status
> @@ -2668,6 +2672,7 @@ static int anx7625_i2c_probe(struct i2c_client *client)
>
> mutex_init(&platform->lock);
> mutex_init(&platform->hdcp_wq_lock);
> +   mutex_init(&platform->aux_lock);
>
> INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func);
> platform->hdcp_workqueue = create_workqueue("hdcp workqueue");
> diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h 
> b/drivers/gpu/drm/bridge/analogix/anx7625.h
> index 66ebee7f3d83..39ed35d33836 100644
> --- a/drivers/gpu/drm/bridge/analogix/anx7625.h
> +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
> @@ -475,6 +475,8 @@ struct anx7625_data {
> struct workqueue_struct *hdcp_workqueue;
> /* Lock for hdcp work queue */
> struct mutex hdcp_wq_lock;
> +   /* Lock for aux transfer and disable */
> +   struct mutex aux_lock;
> char edid_block;
> struct display_timing dt;
> u8 display_timing_valid;
> --
> 2.43.0.381.gb435a96ce8-goog
>

Reviewed-by: Pin-yen Lin 


Re: [PATCH v2] drm/bridge: parade-ps8640: Ensure bridge is suspended in .post_disable()

2024-01-17 Thread Pin-yen Lin
Hi Doug,

On Thu, Jan 18, 2024 at 2:37 AM Doug Anderson  wrote:
>
> Hi,
>
> On Wed, Jan 17, 2024 at 9:34 AM Doug Anderson  wrote:
> >
> > Hi,
> >
> > On Tue, Jan 9, 2024 at 8:52 AM Doug Anderson  wrote:
> > >
> > > Hi,
> > >
> > > On Tue, Jan 9, 2024 at 4:05 AM Pin-yen Lin  wrote:
> > > >
> > > > The ps8640 bridge seems to expect everything to be power cycled at the
> > > > disable process, but sometimes ps8640_aux_transfer() holds the runtime
> > > > PM reference and prevents the bridge from suspend.
> > > >
> > > > Prevent that by introducing a mutex lock between ps8640_aux_transfer()
> > > > and .post_disable() to make sure the bridge is really powered off.
> > > >
> > > > Fixes: 826cff3f7ebb ("drm/bridge: parade-ps8640: Enable runtime power 
> > > > management")
> > > > Signed-off-by: Pin-yen Lin 
> > > > ---
> > > >
> > > > Changes in v2:
> > > > - Use mutex instead of the completion and autosuspend hack
> > > >
> > > >  drivers/gpu/drm/bridge/parade-ps8640.c | 16 
> > > >  1 file changed, 16 insertions(+)
> > >
> > > This looks OK to me now.
> > >
> > > Reviewed-by: Douglas Anderson 
> > >
> > > I'll let it stew on the mailing list for ~1 week and then land it in
> > > drm-misc-fixes unless there are additional comments.
> >
> > Pushed to drm-misc-fixes:
> >
> > 26db46bc9c67 drm/bridge: parade-ps8640: Ensure bridge is suspended in
> > .post_disable()
>
> Crud. I landed this and then almost immediately hit a bug with it. :(
> I've posted up the fix:
>
> https://lore.kernel.org/r/20240117103502.1.Ib726a0184913925efc7e99c4d4fc801982e1bc24@changeid
>
> -Doug

Sorry, I missed this because the patch was based on drm-misc-next, so
it did not include commit 024b32db43a3 ("drm/bridge: parade-ps8640:
Wait for HPD when doing an AUX transfer").

I also forgot to apply that commit when I did my testing.

Pin-yen


[PATCH v2] drm/bridge: parade-ps8640: Ensure bridge is suspended in .post_disable()

2024-01-09 Thread Pin-yen Lin
The ps8640 bridge seems to expect everything to be power cycled at the
disable process, but sometimes ps8640_aux_transfer() holds the runtime
PM reference and prevents the bridge from suspend.

Prevent that by introducing a mutex lock between ps8640_aux_transfer()
and .post_disable() to make sure the bridge is really powered off.

Fixes: 826cff3f7ebb ("drm/bridge: parade-ps8640: Enable runtime power 
management")
Signed-off-by: Pin-yen Lin 
---

Changes in v2:
- Use mutex instead of the completion and autosuspend hack

 drivers/gpu/drm/bridge/parade-ps8640.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index 8161b1a1a4b1..46c84ce66041 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -107,6 +107,7 @@ struct ps8640 {
struct device_link *link;
bool pre_enabled;
bool need_post_hpd_delay;
+   struct mutex aux_lock;
 };
 
 static const struct regmap_config ps8640_regmap_config[] = {
@@ -344,10 +345,12 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
int ret;
 
+   mutex_lock(&ps_bridge->aux_lock);
pm_runtime_get_sync(dev);
ret = ps8640_aux_transfer_msg(aux, msg);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
+   mutex_unlock(&ps_bridge->aux_lock);
 
return ret;
 }
@@ -469,7 +472,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge 
*bridge,
ps_bridge->pre_enabled = false;
 
ps8640_bridge_vdo_control(ps_bridge, DISABLE);
+
+   /*
+* The bridge seems to expect everything to be power cycled at the
+* disable process, so grab a lock here to make sure
+* ps8640_aux_transfer() is not holding a runtime PM reference and
+* preventing the bridge from suspend.
+*/
+   mutex_lock(&ps_bridge->aux_lock);
+
pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
+
+   mutex_unlock(&ps_bridge->aux_lock);
 }
 
 static int ps8640_bridge_attach(struct drm_bridge *bridge,
@@ -618,6 +632,8 @@ static int ps8640_probe(struct i2c_client *client)
if (!ps_bridge)
return -ENOMEM;
 
+   mutex_init(&ps_bridge->aux_lock);
+
ps_bridge->supplies[0].supply = "vdd12";
ps_bridge->supplies[1].supply = "vdd33";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
-- 
2.43.0.472.g3155946c3a-goog



Re: [PATCH] drm/bridge: parade-ps8640: Ensure bridge is suspended in .post_disable()

2024-01-09 Thread Pin-yen Lin
Hi Doug,

On Tue, Jan 9, 2024 at 6:46 AM Doug Anderson  wrote:
>
> Hi,
>
> On Wed, Dec 27, 2023 at 2:43 AM Pin-yen Lin  wrote:
> >
> > Disable the autosuspend of runtime PM and use completion to make sure
> > ps8640_suspend() is called in ps8640_atomic_post_disable().
> >
> > The ps8640 bridge seems to expect everything to be power cycled at the
> > disable process, but sometimes ps8640_aux_transfer() holds the runtime
> > PM reference and prevents the bridge from suspend.
> >
> > Instead of force powering off the bridge and taking the risk of breaking
> > the AUX communication, disable the autosuspend and wait for
> > ps8640_suspend() being called here, and re-enable the autosuspend
> > afterwards.  With this approach, the bridge should be suspended after
> > the current ps8640_aux_transfer() completes.
> >
> > Fixes: 826cff3f7ebb ("drm/bridge: parade-ps8640: Enable runtime power 
> > management")
> > Signed-off-by: Pin-yen Lin 
> > ---
> >
> >  drivers/gpu/drm/bridge/parade-ps8640.c | 33 +-
> >  1 file changed, 32 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
> > b/drivers/gpu/drm/bridge/parade-ps8640.c
> > index 8161b1a1a4b1..f8ea486a76fd 100644
> > --- a/drivers/gpu/drm/bridge/parade-ps8640.c
> > +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> > @@ -107,6 +107,7 @@ struct ps8640 {
> > struct device_link *link;
> > bool pre_enabled;
> > bool need_post_hpd_delay;
> > +   struct completion suspend_completion;
> >  };
> >
> >  static const struct regmap_config ps8640_regmap_config[] = {
> > @@ -417,6 +418,8 @@ static int __maybe_unused ps8640_suspend(struct device 
> > *dev)
> > if (ret < 0)
> > dev_err(dev, "cannot disable regulators %d\n", ret);
> >
> > +   complete_all(&ps_bridge->suspend_completion);
> > +
> > return ret;
> >  }
> >
> > @@ -465,11 +468,37 @@ static void ps8640_atomic_post_disable(struct 
> > drm_bridge *bridge,
> >struct drm_bridge_state 
> > *old_bridge_state)
> >  {
> > struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
> > +   struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
> >
> > ps_bridge->pre_enabled = false;
> >
> > ps8640_bridge_vdo_control(ps_bridge, DISABLE);
> > -   pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
> > +
> > +   /*
> > +* The ps8640 bridge seems to expect everything to be power cycled 
> > at
> > +* the disable process, but sometimes ps8640_aux_transfer() holds 
> > the
> > +* runtime PM reference and prevents the bridge from suspend.
> > +* Instead of force powering off the bridge and taking the risk of
> > +* breaking the AUX communication, disable the autosuspend and wait 
> > for
> > +* ps8640_suspend() being called here, and re-enable the autosuspend
> > +* afterwards.  With this approach, the bridge should be suspended 
> > after
> > +* the current ps8640_aux_transfer() completes.
> > +*/
> > +   reinit_completion(&ps_bridge->suspend_completion);
> > +   pm_runtime_dont_use_autosuspend(dev);
> > +   pm_runtime_put_sync_suspend(dev);
> > +
> > +   /*
> > +* Mostly the suspend completes under 10 ms, but sometimes it could
> > +* take 708 ms to complete.  Set the timeout to 2000 ms here to be
> > +* extra safe.
> > +*/
> > +   if (!wait_for_completion_timeout(&ps_bridge->suspend_completion,
> > +msecs_to_jiffies(2000))) {
> > +   dev_warn(dev, "Failed to wait for the suspend 
> > completion\n");
> > +   }
> > +
> > +   pm_runtime_use_autosuspend(dev);
>
> Thanks for tracking this down! I agree with your analysis and it seems
> like we've got to do something about it.
>
> I spent a little time trying to think about a cleaner way. What do you
> think about adding a "aux_transfer" mutex? You'd grab this mutex for
> the entire duration of ps8640_aux_transfer() and
> ps8640_atomic_post_disable(). That way you don't need the weird
> completion / timeout and don't need to hackily turn off/on
> autosuspend. You shouldn't need the mutex in
> ps8640_wait_hpd_asserted() because that will never be called at the
> same time as ps8640_atomic_post_disable().
>
> -Doug

Hi Doug,

Thanks for the suggestion! I tried that approach and it fixes the issue as well.

I'll send out another patch with that approach.

Regards,
Pin-yen


[PATCH] drm/bridge: parade-ps8640: Ensure bridge is suspended in .post_disable()

2023-12-27 Thread Pin-yen Lin
Disable the autosuspend of runtime PM and use completion to make sure
ps8640_suspend() is called in ps8640_atomic_post_disable().

The ps8640 bridge seems to expect everything to be power cycled at the
disable process, but sometimes ps8640_aux_transfer() holds the runtime
PM reference and prevents the bridge from suspend.

Instead of force powering off the bridge and taking the risk of breaking
the AUX communication, disable the autosuspend and wait for
ps8640_suspend() being called here, and re-enable the autosuspend
afterwards.  With this approach, the bridge should be suspended after
the current ps8640_aux_transfer() completes.

Fixes: 826cff3f7ebb ("drm/bridge: parade-ps8640: Enable runtime power 
management")
Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/parade-ps8640.c | 33 +-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index 8161b1a1a4b1..f8ea486a76fd 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -107,6 +107,7 @@ struct ps8640 {
struct device_link *link;
bool pre_enabled;
bool need_post_hpd_delay;
+   struct completion suspend_completion;
 };
 
 static const struct regmap_config ps8640_regmap_config[] = {
@@ -417,6 +418,8 @@ static int __maybe_unused ps8640_suspend(struct device *dev)
if (ret < 0)
dev_err(dev, "cannot disable regulators %d\n", ret);
 
+   complete_all(&ps_bridge->suspend_completion);
+
return ret;
 }
 
@@ -465,11 +468,37 @@ static void ps8640_atomic_post_disable(struct drm_bridge 
*bridge,
   struct drm_bridge_state 
*old_bridge_state)
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+   struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
 
ps_bridge->pre_enabled = false;
 
ps8640_bridge_vdo_control(ps_bridge, DISABLE);
-   pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev);
+
+   /*
+* The ps8640 bridge seems to expect everything to be power cycled at
+* the disable process, but sometimes ps8640_aux_transfer() holds the
+* runtime PM reference and prevents the bridge from suspend.
+* Instead of force powering off the bridge and taking the risk of
+* breaking the AUX communication, disable the autosuspend and wait for
+* ps8640_suspend() being called here, and re-enable the autosuspend
+* afterwards.  With this approach, the bridge should be suspended after
+* the current ps8640_aux_transfer() completes.
+*/
+   reinit_completion(&ps_bridge->suspend_completion);
+   pm_runtime_dont_use_autosuspend(dev);
+   pm_runtime_put_sync_suspend(dev);
+
+   /*
+* Mostly the suspend completes under 10 ms, but sometimes it could
+* take 708 ms to complete.  Set the timeout to 2000 ms here to be
+* extra safe.
+*/
+   if (!wait_for_completion_timeout(&ps_bridge->suspend_completion,
+msecs_to_jiffies(2000))) {
+   dev_warn(dev, "Failed to wait for the suspend completion\n");
+   }
+
+   pm_runtime_use_autosuspend(dev);
 }
 
 static int ps8640_bridge_attach(struct drm_bridge *bridge,
@@ -693,6 +722,8 @@ static int ps8640_probe(struct i2c_client *client)
if (ret)
return ret;
 
+   init_completion(&ps_bridge->suspend_completion);
+
ret = devm_of_dp_aux_populate_bus(&ps_bridge->aux, 
ps8640_bridge_link_panel);
 
/*
-- 
2.43.0.472.g3155946c3a-goog



Re: [PATCH] drm/bridge: parade-ps8640: Wait for HPD when doing an AUX transfer

2023-12-25 Thread Pin-yen Lin
Hi,

On Fri, Dec 22, 2023 at 11:34 PM Doug Anderson  wrote:
>
> Hi,
>
> On Fri, Dec 22, 2023 at 2:29 AM Pin-yen Lin  wrote:
> >
> > Hi Douglas,
> >
> > On Fri, Dec 22, 2023 at 5:56 AM Douglas Anderson  
> > wrote:
> > >
> > > Unlike what is claimed in commit f5aa7d46b0ee ("drm/bridge:
> > > parade-ps8640: Provide wait_hpd_asserted() in struct drm_dp_aux"), if
> > > someone manually tries to do an AUX transfer (like via `i2cdump ${bus}
> > > 0x50 i`) while the panel is off we don't just get a simple transfer
> > > error. Instead, the whole ps8640 gets thrown for a loop and goes into
> > > a bad state.
> > >
> > > Let's put the function to wait for the HPD (and the magical 50 ms
> > > after first reset) back in when we're doing an AUX transfer. This
> > > shouldn't actually make things much slower (assuming the panel is on)
> > > because we should immediately poll and see the HPD high. Mostly this
> > > is just an extra i2c transfer to the bridge.
> > >
> > > Fixes: f5aa7d46b0ee ("drm/bridge: parade-ps8640: Provide 
> > > wait_hpd_asserted() in struct drm_dp_aux")
> > > Signed-off-by: Douglas Anderson 
> > > ---
> > >
> > >  drivers/gpu/drm/bridge/parade-ps8640.c | 5 +
> > >  1 file changed, 5 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
> > > b/drivers/gpu/drm/bridge/parade-ps8640.c
> > > index 541e4f5afc4c..fb5e9ae9ad81 100644
> > > --- a/drivers/gpu/drm/bridge/parade-ps8640.c
> > > +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> > > @@ -346,6 +346,11 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux 
> > > *aux,
> > > int ret;
> > >
> > > pm_runtime_get_sync(dev);
> > > +   ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000);
> > > +   if (ret) {
> > > +   pm_runtime_put_sync_suspend(dev);
> > > +   return ret;
> > > +   }
> > > ret = ps8640_aux_transfer_msg(aux, msg);
> > > pm_runtime_mark_last_busy(dev);
> > > pm_runtime_put_autosuspend(dev);
> > > --
> > > 2.43.0.472.g3155946c3a-goog
> > >
> >
> > I think commit 9294914dd550 ("drm/bridge: parade-ps8640: Link device
> > to ensure suspend/resume order")  is trying to address the same
> > problem, but we see this issue here because the device link is missing
> > DL_FLAG_PM_RUNTIME. I prefer to add DL_FLAG_PM_RUNTIME here so we
> > don't need to add a _ps8640_wait_hpd_asserted() after every
> > pm_runtime_get_*() call.
>
> I disagree. We've had several discussions on the lists about this
> topic before, though since I'm technically on vacation right now I'm
> not going to go look them up. In general "pm_runtime" is not
> sufficient for powering up DRM components. While DRM components can
> use pm_runtime themselves (as we are doing here), powering up another
> DRM component by grabbing a pm_runtime reference isn't right. There is
> a reason for the complexity of the DRM prepare/enable and all the
> current debates about the right order to call components in prepare()
> just demonstrates further that a simple pm_runtime reference isn't
> enough.
>
> It can be noted that, with ${SUBJECT} patch we _aren't_ powering up
> the panel. I actually tested two cases on sc7180-lazor. In one case I
> just closed the lid, which powered off the panel, but the touchscreen
> kept the panel power rail on. In this case with my patch I could still
> read the panel EDID. I then hacked the touchscreen off. Now when I
> closed the lid I'd get a timeout. This is different than if we tried
> to get a pm_runtime reference to the panel.
>
Okay, thanks for the detailed explanation. Then, let's go with the
approach in this patch. So,

Tested-by: Pin-yen Lin 
Reviewed-by: Pin-yen Lin 

>
> > As a side note, I've verified both this patch and DL_FLAG_PM_RUNTIME
> > in our downstream v5.15 kernel and panel-edp driver. Both of them
> > successfully wait for HPD asserted when the timeout used to happen,
> > but the panel is black in that situation. That being said, this patch
> > still brings us to a better state. Originally, panel_edp_resume()
> > would return an error when the timeout occurs, so the panel-edp driver
> > is stuck at an unexpected state. With this patch or
> > DL_FLAG_PM_RUNTIME, the runtime PM callbacks won't fail and a system
> > suspend/resume brings the panel back.
>
> OK. I'm going to shut off email for real this time while I enjoy some
> time off. Hopefully the above convinces you. Otherwise I guess we can
> continue to debate in mid-January.
>
> -Doug

Happy holiday!

Pin-yen


Re: [PATCH] drm/bridge: parade-ps8640: Wait for HPD when doing an AUX transfer

2023-12-22 Thread Pin-yen Lin
Hi Douglas,

On Fri, Dec 22, 2023 at 5:56 AM Douglas Anderson  wrote:
>
> Unlike what is claimed in commit f5aa7d46b0ee ("drm/bridge:
> parade-ps8640: Provide wait_hpd_asserted() in struct drm_dp_aux"), if
> someone manually tries to do an AUX transfer (like via `i2cdump ${bus}
> 0x50 i`) while the panel is off we don't just get a simple transfer
> error. Instead, the whole ps8640 gets thrown for a loop and goes into
> a bad state.
>
> Let's put the function to wait for the HPD (and the magical 50 ms
> after first reset) back in when we're doing an AUX transfer. This
> shouldn't actually make things much slower (assuming the panel is on)
> because we should immediately poll and see the HPD high. Mostly this
> is just an extra i2c transfer to the bridge.
>
> Fixes: f5aa7d46b0ee ("drm/bridge: parade-ps8640: Provide wait_hpd_asserted() 
> in struct drm_dp_aux")
> Signed-off-by: Douglas Anderson 
> ---
>
>  drivers/gpu/drm/bridge/parade-ps8640.c | 5 +
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
> b/drivers/gpu/drm/bridge/parade-ps8640.c
> index 541e4f5afc4c..fb5e9ae9ad81 100644
> --- a/drivers/gpu/drm/bridge/parade-ps8640.c
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -346,6 +346,11 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux 
> *aux,
> int ret;
>
> pm_runtime_get_sync(dev);
> +   ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000);
> +   if (ret) {
> +   pm_runtime_put_sync_suspend(dev);
> +   return ret;
> +   }
> ret = ps8640_aux_transfer_msg(aux, msg);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> --
> 2.43.0.472.g3155946c3a-goog
>

I think commit 9294914dd550 ("drm/bridge: parade-ps8640: Link device
to ensure suspend/resume order")  is trying to address the same
problem, but we see this issue here because the device link is missing
DL_FLAG_PM_RUNTIME. I prefer to add DL_FLAG_PM_RUNTIME here so we
don't need to add a _ps8640_wait_hpd_asserted() after every
pm_runtime_get_*() call.

As a side note, I've verified both this patch and DL_FLAG_PM_RUNTIME
in our downstream v5.15 kernel and panel-edp driver. Both of them
successfully wait for HPD asserted when the timeout used to happen,
but the panel is black in that situation. That being said, this patch
still brings us to a better state. Originally, panel_edp_resume()
would return an error when the timeout occurs, so the panel-edp driver
is stuck at an unexpected state. With this patch or
DL_FLAG_PM_RUNTIME, the runtime PM callbacks won't fail and a system
suspend/resume brings the panel back.

Regards,
Pin-yen


[PATCH v3 3/3] drm/panel-edp: Add some panels with conservative timings

2023-12-14 Thread Pin-yen Lin
These panels are used by Mediatek MT8173 Chromebooks, and they used to
work with the downstream v4.19 kernel without any specified delay.
Back in the v4.19 kernel, they used the "little white lie" approach,
which is making the devicetree claim a specific panel's compatible
string for many different panels. That was a common solution before the
generic edp-panel driver.

After we uprevved the device to a newer kernel and used the edp-panel
driver, we saw multiple devices reporting warnings of using an unknown
panel and falling back to the conservative timings, which means that
they turn on/off much more slowly than they should. We tried to fill in
the timings for those panels, but we failed to find all the data sheets
for them.

Therefore, instead of having them use the default conservative timings,
update them with less-conservative timings from other panels of the same
vendor. The panels should still work under those timings, and we can
save some delays and suppress the warnings.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Douglas Anderson 

---

Changes in v3:
- Update the commit message.
- Collect review tag.

 drivers/gpu/drm/panel/panel-edp.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index b059f5895d3a..e23737284f31 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1955,6 +1955,7 @@ static const struct panel_delay delay_200_500_e50_po2e200 
= {
 static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, 
"B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, 
"B116XAK01.6"),
@@ -1965,6 +1966,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, 
"B140HAN04.0"),
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, 
"B116XAK01.0",
 &auo_b116xa3_mode),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, 
"B116XAN06.1",
 &auo_b116xa3_mode),
@@ -1974,18 +1976,34 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, 
"NV133FHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, 
"NT116WHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, 
"NT116WHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_2

[PATCH v3 2/3] drm/edp-panel: Add panels delay entries

2023-12-14 Thread Pin-yen Lin
Add panels used by Mediatek MT8173 Chromebooks.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Douglas Anderson 

---

Changes in v3:
- Collect review tag.

 drivers/gpu/drm/panel/panel-edp.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 44acf9cacaf7..b059f5895d3a 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1857,6 +1857,13 @@ static const struct panel_delay delay_200_500_p2e80 = {
.prepare_to_enable = 80,
 };
 
+static const struct panel_delay delay_200_500_e50_p2e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
+   .prepare_to_enable = 80,
+};
+
 static const struct panel_delay delay_200_500_p2e100 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1894,6 +1901,13 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d200 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 200,
+};
+
 static const struct panel_delay delay_200_500_e200_d10 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1907,6 +1921,13 @@ static const struct panel_delay delay_200_150_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e50_po2e200 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
+   .powered_on_to_enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1932,6 +1953,7 @@ static const struct panel_delay delay_200_150_e200 = {
  * Sort first by vendor, then by product ID.
  */
 static const struct edp_panel_entry edp_panels[] = {
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, 
"B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
@@ -1948,23 +1970,31 @@ static const struct edp_panel_entry edp_panels[] = {
 &auo_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, 
"B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, 
"B140HAK02.7"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, 
"B140XTN07.2"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, 
"NV133FHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, 
"NT116WHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, 
"NT116WHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, 
"NV133FHM-N61"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, 
"NT140FHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, 
"NT140WHM-N44 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, 
"NV133FHM-N62"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, 
"NT116WHM-N21"),

[PATCH v3 1/3] drm/panel-edp: Add powered_on_to_enable delay

2023-12-14 Thread Pin-yen Lin
Add the support of powered_on_to_enable delay as the minimum time that
needs to have passed between the panel powered on and enable may begin.

This delay is seen in BOE panels as the minimum delay of T3+T4+T5+T6+T8
in the eDP timing diagrams.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Douglas Anderson 

---

Changes in v3:
- Collect review tag.

 drivers/gpu/drm/panel/panel-edp.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index a0b6f69b916f..44acf9cacaf7 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -70,6 +70,21 @@ struct panel_delay {
 */
unsigned int hpd_absent;
 
+   /**
+* @powered_on_to_enable: Time between panel powered on and enable.
+*
+* The minimum time, in milliseconds, that needs to have passed
+* between when panel powered on and enable may begin.
+*
+* This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the
+* power supply enabled until we can turn the backlight on and see
+* valid data.
+*
+* This doesn't normally need to be set if timings are already met by
+* prepare_to_enable or enable.
+*/
+   unsigned int powered_on_to_enable;
+
/**
 * @prepare_to_enable: Time between prepare and enable.
 *
@@ -216,6 +231,7 @@ struct panel_edp {
bool prepared;
 
ktime_t prepared_time;
+   ktime_t powered_on_time;
ktime_t unprepared_time;
 
const struct panel_desc *desc;
@@ -455,6 +471,8 @@ static int panel_edp_prepare_once(struct panel_edp *p)
 
gpiod_set_value_cansleep(p->enable_gpio, 1);
 
+   p->powered_on_time = ktime_get_boottime();
+
delay = p->desc->delay.hpd_reliable;
if (p->no_hpd)
delay = max(delay, p->desc->delay.hpd_absent);
@@ -579,6 +597,8 @@ static int panel_edp_enable(struct drm_panel *panel)
 
panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
 
+   panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable);
+
p->enabled = true;
 
return 0;
-- 
2.43.0.472.g3155946c3a-goog



[PATCH v3 0/3] Support panels used by MT8173 Chromebooks in edp-panel

2023-12-14 Thread Pin-yen Lin
This series contains 4 patches:
1. Add a new panel delay to support some BOE panels
2. Add panel entries used by Mediatek MT8173 Chromebooks.
3. Add panels missing data sheets but used to work in older kernel version
   without any specified delays.

Changes in v3:
- Collect review tag.
- Update the commit message.

Changes in v2:
- Add a new patch to sort the list, and rebase the rest patches.

Pin-yen Lin (3):
  drm/panel-edp: Add powered_on_to_enable delay
  drm/edp-panel: Add panels delay entries
  drm/panel-edp: Add some panels with conservative timings

 drivers/gpu/drm/panel/panel-edp.c | 90 +++
 1 file changed, 90 insertions(+)

-- 
2.43.0.472.g3155946c3a-goog



Re: [PATCH v2 4/4] drm/panel-edp: Add some panels with conservative timings

2023-12-14 Thread Pin-yen Lin
On Thu, Dec 14, 2023 at 12:23 AM Doug Anderson  wrote:
>
> Hi,
>
> On Wed, Dec 13, 2023 at 7:34 AM Maxime Ripard  wrote:
> >
> > > > > Repeating my comments from v1 here too, since I expect this patch to
> > > > > sit on the lists for a little while:
> > > > >
> > > > >
> > > > > This is OK w/ me, but it will need time on the mailing lists before
> > > > > landing in case anyone else has opinions.
> > > >
> > > > Generally speaking, I'm not really a fan of big patches that dump
> > > > whatever ChromeOS is doing ...
> > > >
> > > > > Specifical thoughts:
> > > > >
> > > > > * I at least feel fairly confident that this is OK since these panels
> > > > > essentially booted without _any_ delays back on the old downstream
> > > > > v4.19 kernel. Presumably the panels just had fairly robust timing
> > > > > controllers and so worked OK, but it's better to get the timing more
> > > > > correct.
> > > >
> > > > ... especially since you have to rely on the recollection of engineers
> > > > involved at the time and you have no real way to test and make things
> > > > clearer anymore, and we have to take patches in that are handwavy "trust
> > > > us, it's doing the right thing".
> > > >
> > > > I'd really prefer to have these patches sent as they are found out.
> > >
> > > It's probably not clear enough from the commit message, but this isn't
> > > just a dump from downstream 4.19. What happened was:
> > >
> > > 1. Downstream chromeos-4.19 used the "little white lie" approach. They
> > > all claimed a specific panel's compatible string even though there
> > > were a whole pile of panels out there actually being used. Personally,
> > > this was not something I was ever a fan of (and I wasn't personally
> > > involved in this project), but it was the "state of the art" before
> > > the generic panel-edp. Getting out of the "little white lie" situation
> > > was why I spent so much time on the generic edp-panel solution
> > > upstream.
> > >
> > > 2. These devices have now been uprevved to a newer kernel and I
> > > believe that there were issues seen that necessitated a move to the
> > > proper generic panel-edp code.
> > >
> > > 3. We are now getting field reports from our warning collector about a
> > > whole pile of panels that are falling back to the "conservative"
> > > timings, which means that they turn on/off much more slowly than they
> > > should.
> > >
> > > Pin-yen made an attempt to search for panels data sheets that matched
> > > up with the IDs that came in from the field reports but there were
> > > some panels that he just couldn't find.
> > >
> > > So basically we're stuck. Options:
> > >
> > > 1. Leave customers who have these panels stuck with the hardware
> > > behaving worse than it used to. This is not acceptable to me.
> > >
> > > 2. Land Pin-yen's patch as a downstream-only patch in ChromeOS. This
> > > would solve the problem, but it would make me sad. If anyone ever
> > > wants to take these old laptops and run some other Linux distribution
> > > on them (and there are several that target old Chromebooks) then
> > > they'd be again stuck with old timings.
> > >
> > > 3. Land a patch like this one that at least gets us into not such a bad 
> > > shape.
> > >
> > > While I don't love this patch (and that's why I made it clear that it
> > > needs to spend time on the list), it seems better than the
> > > alternatives. Do you have a proposal for something else? If not, can
> > > you confirm you're OK with #3 given this explanation? ...and perhaps
> > > more details in the commit message?
> >
> > I don't have a specific comment, it was more of a comment about the
> > process itself, if you write down what's above in the commit message ...
>
> Pin-yen: can you take a whack at summarizing some of the above in the
> commit message and sending out a v3?

Sure I'll do that in v3. Sorry for not including enough details in the
original commit message.

Pin-yen


[PATCH v2 4/4] drm/panel-edp: Add some panels with conservative timings

2023-12-07 Thread Pin-yen Lin
These panels are used by Mediatek MT8173 Chromebooks but we can't find
the corresponding data sheets, and these panels used to work on v4.19
kernel without any specified delays.

Therefore, instead of having them use the default conservative timings,
update them with less-conservative timings from other panels of the same
vendor. The panels should still work under those timings, and we can
save some delays and suppress the warnings.

Signed-off-by: Pin-yen Lin 

---

(no changes since v1)

 drivers/gpu/drm/panel/panel-edp.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index b059f5895d3a..e23737284f31 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1955,6 +1955,7 @@ static const struct panel_delay delay_200_500_e50_po2e200 
= {
 static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, 
"B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, 
"B116XAK01.6"),
@@ -1965,6 +1966,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, 
"B140HAN04.0"),
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, 
"B116XAK01.0",
 &auo_b116xa3_mode),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, 
"B116XAN06.1",
 &auo_b116xa3_mode),
@@ -1974,18 +1976,34 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, 
"NV133FHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, 
"NT116WHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, 
"NT116WHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, 
"NV116WHM-N45"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, 
"NV116WHM-T01"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200

[PATCH v2 3/4] drm/edp-panel: Add panels delay entries

2023-12-07 Thread Pin-yen Lin
Add panels used by Mediatek MT8173 Chromebooks.

Signed-off-by: Pin-yen Lin 
---

(no changes since v1)

 drivers/gpu/drm/panel/panel-edp.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 44acf9cacaf7..b059f5895d3a 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1857,6 +1857,13 @@ static const struct panel_delay delay_200_500_p2e80 = {
.prepare_to_enable = 80,
 };
 
+static const struct panel_delay delay_200_500_e50_p2e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
+   .prepare_to_enable = 80,
+};
+
 static const struct panel_delay delay_200_500_p2e100 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1894,6 +1901,13 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d200 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 200,
+};
+
 static const struct panel_delay delay_200_500_e200_d10 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1907,6 +1921,13 @@ static const struct panel_delay delay_200_150_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e50_po2e200 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
+   .powered_on_to_enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1932,6 +1953,7 @@ static const struct panel_delay delay_200_150_e200 = {
  * Sort first by vendor, then by product ID.
  */
 static const struct edp_panel_entry edp_panels[] = {
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, 
"B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
@@ -1948,23 +1970,31 @@ static const struct edp_panel_entry edp_panels[] = {
 &auo_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, 
"B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, 
"B140HAK02.7"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, 
"B140XTN07.2"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, 
"NV133FHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, 
"NT116WHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, 
"NT116WHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, 
"NV133FHM-N61"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, 
"NT140FHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, 
"NT140WHM-N44 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, 
"NV133FHM-N62"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E&#x

[PATCH v2 2/4] drm/panel-edp: Add powered_on_to_enable delay

2023-12-07 Thread Pin-yen Lin
Add the support of powered_on_to_enable delay as the minimum time that
needs to have passed between the panel powered on and enable may begin.

This delay is seen in BOE panels as the minimum delay of T3+T4+T5+T6+T8
in the eDP timing diagrams.

Signed-off-by: Pin-yen Lin 
---

(no changes since v1)

 drivers/gpu/drm/panel/panel-edp.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index a0b6f69b916f..44acf9cacaf7 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -70,6 +70,21 @@ struct panel_delay {
 */
unsigned int hpd_absent;
 
+   /**
+* @powered_on_to_enable: Time between panel powered on and enable.
+*
+* The minimum time, in milliseconds, that needs to have passed
+* between when panel powered on and enable may begin.
+*
+* This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the
+* power supply enabled until we can turn the backlight on and see
+* valid data.
+*
+* This doesn't normally need to be set if timings are already met by
+* prepare_to_enable or enable.
+*/
+   unsigned int powered_on_to_enable;
+
/**
 * @prepare_to_enable: Time between prepare and enable.
 *
@@ -216,6 +231,7 @@ struct panel_edp {
bool prepared;
 
ktime_t prepared_time;
+   ktime_t powered_on_time;
ktime_t unprepared_time;
 
const struct panel_desc *desc;
@@ -455,6 +471,8 @@ static int panel_edp_prepare_once(struct panel_edp *p)
 
gpiod_set_value_cansleep(p->enable_gpio, 1);
 
+   p->powered_on_time = ktime_get_boottime();
+
delay = p->desc->delay.hpd_reliable;
if (p->no_hpd)
delay = max(delay, p->desc->delay.hpd_absent);
@@ -579,6 +597,8 @@ static int panel_edp_enable(struct drm_panel *panel)
 
panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
 
+   panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable);
+
p->enabled = true;
 
return 0;
-- 
2.43.0.472.g3155946c3a-goog



[PATCH v2 1/4] drm/edp-panel: Move the KDC panel to a separate group

2023-12-07 Thread Pin-yen Lin
Move the KDC panel entry to make the list sorted by the vendor string.

Signed-off-by: Pin-yen Lin 
---

(no changes since v1)

 drivers/gpu/drm/panel/panel-edp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index c76f186c4baa..a0b6f69b916f 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1980,9 +1980,10 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM 
R1"),
 
EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, 
&kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
-   EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, 
"KD116N2930A15"),
EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, 
"116N29-30NK-C007"),
 
+   EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, 
"KD116N2930A15"),
+
EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, 
"ATNA45AF01"),
 
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, 
"LQ140M1JW48"),
-- 
2.43.0.472.g3155946c3a-goog



[PATCH v2 0/4] Support panels used by MT8173 Chromebooks in edp-panel

2023-12-07 Thread Pin-yen Lin
This series contains 4 patches:
1. Sort the panel entries as a clean up. This one has no dependency with
   other patches in this series and can be merged separately.
2. Add a new panel delay to support some BOE panels
3. Add panel entries used by Mediatek MT8173 Chromebooks.
4. Add panels missing data sheets but used to work in older kernel version
   without any specified delays.

Changes in v2:
- Add a new patch to sort the list, and rebase the rest patches.

Pin-yen Lin (4):
  drm/edp-panel: Move the KDC panel to a separate group
  drm/panel-edp: Add powered_on_to_enable delay
  drm/edp-panel: Add panels delay entries
  drm/panel-edp: Add some panels with conservative timings

 drivers/gpu/drm/panel/panel-edp.c | 93 ++-
 1 file changed, 92 insertions(+), 1 deletion(-)

-- 
2.43.0.472.g3155946c3a-goog



[PATCH 4/4] drm/panel-edp: Add some panels with conservative timings

2023-12-05 Thread Pin-yen Lin
These panels are used by Mediatek MT8173 Chromebooks but we can't find
the corresponding data sheets, and these panels used to work on v4.19
kernel without any specified delays.

Therefore, instead of having them use the default conservative timings,
update them with less-conservative timings from other panels of the same
vendor. The panels should still work under those timings, and we can
save some delays and suppress the warnings.

Signed-off-by: Pin-yen Lin 

---

 drivers/gpu/drm/panel/panel-edp.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 475257fe1ddc..55e747715178 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1955,6 +1955,7 @@ static const struct panel_delay delay_200_500_e50_po2e200 
= {
 static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, 
"B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, 
"B116XAK01.6"),
@@ -1965,6 +1966,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, 
"B140HAN04.0"),
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, 
"B116XAK01.0",
 &auo_b116xa3_mode),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, 
"B116XAN06.1",
 &auo_b116xa3_mode),
@@ -1974,18 +1976,34 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, 
"NV133FHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, 
"NT116WHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, 
"NT116WHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, 
"NV116WHM-N45"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, 
"NV116WHM-T01"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"

[PATCH 3/4] drm/edp-panel: Add panels delay entries

2023-12-05 Thread Pin-yen Lin
Add panels used by Mediatek MT8173 Chromebooks.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/panel/panel-edp.c | 39 +++
 1 file changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index e0a18e17d3a2..475257fe1ddc 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1857,6 +1857,13 @@ static const struct panel_delay delay_200_500_p2e80 = {
.prepare_to_enable = 80,
 };
 
+static const struct panel_delay delay_200_500_e50_p2e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
+   .prepare_to_enable = 80,
+};
+
 static const struct panel_delay delay_200_500_p2e100 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1894,6 +1901,13 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d200 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 200,
+};
+
 static const struct panel_delay delay_200_500_e200_d10 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1907,6 +1921,13 @@ static const struct panel_delay delay_200_150_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e50_po2e200 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
+   .powered_on_to_enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1932,6 +1953,7 @@ static const struct panel_delay delay_200_150_e200 = {
  * Sort first by vendor, then by product ID.
  */
 static const struct edp_panel_entry edp_panels[] = {
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, 
"B116XTN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, 
"B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, 
"B133UAN02.1"),
@@ -1948,23 +1970,31 @@ static const struct edp_panel_entry edp_panels[] = {
 &auo_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, 
"B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, 
"B140HAK02.7"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, 
"B140XTN07.2"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, 
"NT116WHM-N11"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, 
"NV133FHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, 
"NT116WHM-N42"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, 
"NT116WHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, 
"NV133FHM-N61"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, 
"NT140FHM-N44"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, 
"NT140WHM-N44 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, 
"NV133FHM-N62"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09

[PATCH 2/4] drm/edp-panel: Sort the panel entries

2023-12-05 Thread Pin-yen Lin
Move the order of CMN 0x14e5 to make the list sorted.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/panel/panel-edp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 819fe8115c08..e0a18e17d3a2 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1987,9 +1987,9 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, 
"N140HCA-EAC"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, 
"N140HGA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, 
"N140HGA-EA1"),
-   EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, 
"N140HGA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, 
"N140HCA-EAC"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, 
"N140BGA-EA4"),
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, 
"N140HGA-EA1"),
 
EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, 
"MB116AN01-2"),
 
-- 
2.43.0.rc2.451.g8631bc7472-goog



[PATCH 1/4] drm/panel-edp: Add powered_on_to_enable delay

2023-12-05 Thread Pin-yen Lin
Add the support of powered_on_to_enable delay as the minimum time that
needs to have passed between the panel powered on and enable may begin.

This delay is seen in BOE panels as the minimum delay of T3+T4+T5+T6+T8
in the eDP timing diagrams.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/panel/panel-edp.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 825fa2a0d8a5..819fe8115c08 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -70,6 +70,21 @@ struct panel_delay {
 */
unsigned int hpd_absent;
 
+   /**
+* @powered_on_to_enable: Time between panel powered on and enable.
+*
+* The minimum time, in milliseconds, that needs to have passed
+* between when panel powered on and enable may begin.
+*
+* This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the
+* power supply enabled until we can turn the backlight on and see
+* valid data.
+*
+* This doesn't normally need to be set if timings are already met by
+* prepare_to_enable or enable.
+*/
+   unsigned int powered_on_to_enable;
+
/**
 * @prepare_to_enable: Time between prepare and enable.
 *
@@ -216,6 +231,7 @@ struct panel_edp {
bool prepared;
 
ktime_t prepared_time;
+   ktime_t powered_on_time;
ktime_t unprepared_time;
 
const struct panel_desc *desc;
@@ -455,6 +471,8 @@ static int panel_edp_prepare_once(struct panel_edp *p)
 
gpiod_set_value_cansleep(p->enable_gpio, 1);
 
+   p->powered_on_time = ktime_get_boottime();
+
delay = p->desc->delay.hpd_reliable;
if (p->no_hpd)
delay = max(delay, p->desc->delay.hpd_absent);
@@ -579,6 +597,8 @@ static int panel_edp_enable(struct drm_panel *panel)
 
panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable);
 
+   panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable);
+
p->enabled = true;
 
return 0;
-- 
2.43.0.rc2.451.g8631bc7472-goog



[PATCH 0/4] Support panels used by MT8173 Chromebooks in edp-panel

2023-12-05 Thread Pin-yen Lin
This series contains 4 patches:
1. Add a new panel delay to support some BOE panels
2. Sort the panel entries as a clean up. This one does not depend on other
   patches in this series and can be merged separately.
3. Add panel entries used by Mediatek MT8173 Chromebooks.
4. Add panels missing data sheets but used to work in older kernel version
   without any specified delays.


Pin-yen Lin (4):
  drm/panel-edp: Add powered_on_to_enable delay
  drm/edp-panel: Sort the panel entries
  drm/edp-panel: Add panels delay entries
  drm/panel-edp: Add some panels with conservative timings

 drivers/gpu/drm/panel/panel-edp.c | 92 ++-
 1 file changed, 91 insertions(+), 1 deletion(-)

-- 
2.43.0.rc2.451.g8631bc7472-goog



[PATCH] drm/bridge: it6505: Check power state with it6505->powered in IRQ handler

2023-07-27 Thread Pin-yen Lin
On system resume, the driver might call it6505_poweron directly if the
runtime PM hasn't been enabled. In such case, pm_runtime_get_if_in_use
will always return 0 because dev->power.runtime_status stays at
RPM_SUSPENDED, and the IRQ will never be handled.

Use it6505->powered from the driver struct fixes this because it always
gets updated when it6505_poweron is called.

Fixes: 5eb9a4314053 ("drm/bridge: it6505: Guard bridge power in IRQ handler")
Signed-off-by: Pin-yen Lin 

---

 drivers/gpu/drm/bridge/ite-it6505.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index 6c2fcd8b8780..2f300f5ca051 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -2517,9 +2517,11 @@ static irqreturn_t it6505_int_threaded_handler(int 
unused, void *data)
};
int int_status[3], i;
 
-   if (it6505->enable_drv_hold || pm_runtime_get_if_in_use(dev) <= 0)
+   if (it6505->enable_drv_hold || !it6505->powered)
return IRQ_HANDLED;
 
+   pm_runtime_get_sync(dev);
+
int_status[0] = it6505_read(it6505, INT_STATUS_01);
int_status[1] = it6505_read(it6505, INT_STATUS_02);
int_status[2] = it6505_read(it6505, INT_STATUS_03);
-- 
2.41.0.487.g6d72f3e995-goog



Re: [PATCH] drm/bridge: ps8640: Drop the ability of ps8640 to fetch the EDID

2023-06-15 Thread Pin-yen Lin
Hi Doug,

On Thu, Jun 15, 2023 at 5:31 AM Doug Anderson  wrote:
>
> Hi,
>
> On Wed, Jun 14, 2023 at 1:22 AM AngeloGioacchino Del Regno
>  wrote:
> >
> > Il 13/06/23 01:32, Douglas Anderson ha scritto:
> > > In order to read the EDID from an eDP panel, you not only need to
> > > power on the bridge chip itself but also the panel. In the ps8640
> > > driver, this was made to work by having the bridge chip manually power
> > > the panel on by calling pre_enable() on everything connectorward on
> > > the bridge chain. This worked OK, but...
> > >
> > > ...when trying to do the same thing on ti-sn65dsi86, feedback was that
> > > this wasn't a great idea. As a result, we designed the "DP AUX"
> > > bus. With the design we ended up with the panel driver itself was in
> > > charge of reading the EDID. The panel driver could power itself on and
> > > the bridge chip was able to power itself on because it implemented the
> > > DP AUX bus.
> > >
> > > Despite the fact that we came up with a new scheme, implemented in on
> > > ti-sn65dsi86, and even implemented it on parade-ps8640, we still kept
> > > the old code around. This was because the new scheme required a DT
> > > change. Previously the panel was a simple "platform_device" and in DT
> > > at the top level. With the new design the panel needs to be listed in
> > > DT under the DP controller node. The old code allowed us to properly
> > > fetch EDIDs with ps8640 with the old DTs.
> > >
> > > Unfortunately, the old code stopped working as of commit 102e80d1fa2c
> > > ("drm/bridge: ps8640: Use atomic variants of drm_bridge_funcs"). There
> > > are cases at bootup where connector->state->state is NULL and the
> > > kernel crashed at:
> > > * drm_atomic_bridge_chain_pre_enable
> > > * drm_atomic_get_old_bridge_state
> > > * drm_atomic_get_old_private_obj_state
> > >
> > > A bit of digging was done to see if there was an easy fix but there
> > > was nothing obvious. Instead, the only device using ps8640 the "old"
> > > way had its DT updated so that the panel was no longer a simple
> > > "platform_deice". See commit c2d94f72140a ("arm64: dts: mediatek:
> > > mt8173-elm: Move display to ps8640 auxiliary bus") and commit
> > > 113b5cc06f44 ("arm64: dts: mediatek: mt8173-elm: remove panel model
> > > number in DT").
> > >
> > > Let's delete the old, crashing code so nobody gets tempted to copy it
> > > or figure out how it works (since it doesn't).
> > >
> > > NOTE: from a device tree "purist" point of view, we're supposed to
> > > keep old device trees working and this patch is technically "against
> > > policy". Reasons I'm still proposing it anyway:
> > > 1. Officially, old mt8173-elm device trees worked via the "little
> > > white lie" approach. The DT would list an arbitrary/representative
> > > panel that would be used for power sequencing. The mode information
> > > in the panel driver would then be ignored / overridden by the EDID
> > > reading code in ps8640. I don't feel too terrible breaking DTs that
> > > contained the wrong "compatible" string to begin with. NOTE that
> > > any old device trees that _didn't_ lie about their compatible will
> > > still work because the mode information will come from the
> > > hardcoded panels in panel-edp.
> > > 2. The only users of the old code were Chromebooks and Chromebooks
> > > don't bake their DTs into the BIOS (they are bundled with the
> > > kernel). Thus we don't need to worry about breaking someone using
> > > an old DT with a new kernel.
> > > 3. The old code was crashing anyway. If someone wants to fix the old
> > > code instead of deleting it then they have my blessing, but without
> > > a proper fix the old code isn't useful.
> > >
> > > I'll list this as "Fixing" the code that made the old code start
> > > failing. There's not lots of reason to bring this back any further
> > > than that.
> >
> > Hoping to see removal of non-aux EDID reading code from all drivers that can
> > support aux-bus is exactly why I moved Elm to the proper... aux-bus.. so...
> >
> > Yes! Let's go!
> >
> > >
> > > Fixes: 102e80d1fa2c ("drm/bridge: ps8640: Use atomic variants of 
> > > drm_bridge_funcs")
> >
> > ...but this Fixes tag will cause this commit to be backported to kernel 
> > versions
> > before my commit moving Elm to aux-bus, and break display on those.
> >
> > I would suggest to either find a different Fixes tag, or don't add any, 
> > since
> > technically this is a deprecation commit. We could imply that the old 
> > technique
> > is deprecated since kernel version X.Y and get away with it.
> >
> > Otherwise, if you want it backported *anyway*, the safest way would be to 
> > Cc it
> > to stable and explicitly say which versions should it be backported to.
>
> The problem is that, as I understand it, as of commit 102e80d1fa2c
> ("drm/bridge: ps8640: Use atomic variants of drm_bridge_funcs"),
> things are broken anyway and you'll get a crash at bootup. However, if
> 

Re: [PATCH v15 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-05-29 Thread Pin-yen Lin
On Fri, May 12, 2023 at 1:30 AM Stephen Boyd  wrote:
>
> Quoting Pin-yen Lin (2023-05-09 20:41:54)
> > On Sat, Apr 29, 2023 at 12:47 PM Stephen Boyd  wrote:
> > >
> > > Good point. I'm suggesting to make the drm bridge chain into a tree. We
> > > need to teach drm_bridge core about a mux, and have some logic to
> > > navigate atomically switching from one output to another. I was talking
> > > with dianders@ and he was suggesting to use bridge attach/detach for
> > > this. I'm not sure that will work though because that hook is only
> > > called when the encoder is attached to the bridge.
> > >
> > > It may also turn out that this helps with DP multi-stream transport
> > > (MST). As far as I can recall DP MST doesn't mesh well with drm_bridge
> > > designs because it wants to operate on a drm_connector and
> > > drm_bridge_connector_init() wants to make only one drm_connector for a
> > > chain of bridges. If you squint, the anx7625 could be an MST "branch"
> > > that only supports one drm_connector being enabled at a time. Maybe that
> > > is what we should do here, make drm_bridge support creating more than
> > > one drm_connector and when there is a mux in the tree it walks both
> > > sides and runs a callback similar to struct
> > > drm_dp_mst_topology_cbs::add_connector() to tell the encoder that
> > > there's another possible drm_connector here.
> >
> > I have been surveying the approaches to change the bridge chain in
> > runtime, and I found this thread[1]. Quoting from Daniel:
>
> I find the lore links easier to read.
>
> > "... exchanging the bridge chain isn't supported, there's no locking
> > for that since it's assumed to be invariant over the lifetime of the
> > drm_device instance. The simplest way to make that happen right now is to
> > have 2 drm_encoder instances, one with the lvds bridge chain, the other
> > with the hdmi bridge chain, and select the right encoder/bridge chain
> > depending upon which output userspace picks.
> > ...
> > I wouldn't try to make bridge chains exchangeable instead, that's
> > headaches - e.g. with dp mst we've also opted for a bunch of fake
> > drm_encoders to model that kind of switching."
> >
> > I'm not sure how we register two encoders properly, though. Do we make
> > the encoder driver check all the downstream bridges and register two
> > drm_encoder when a bridge is acting as a mux?
>
> I honestly don't know because I'm not a DRM expert. Maybe Jagan or DRM
> bridge maintainers can add to the thread here.
>
> I kept reading the thread[2] and I think they settled on 2 drm_encoders
> because they're different display formats (LVDS vs. HDMI) and 2
> drm_connector structures. But then I watched the youtube video from this
> thread[3] and it seems like 1 drm_encoder is actually what should be
> done because there is really only DSI at the root. There's at least
> three people working on this topic of muxing displays though. Good news?
>
> The analogy between their gpio controlled mux and this anx part with a
> crosspoint switch is that the gpio is like the crosspoint switch, but
> the gpio is like a virtual mux? If the gpio is asserted for them, one
> display bridge is enabled (HDMI) and the other one is not (LVDS).
>
> In this case, the type-c cables may be connected to both
> usb-c-connectors and HPD may be asserted on both, but only one
> drm_connector will be able to attach to the 1 drm_encoder at a time. If
> we had 2 drm_encoders it would be possible to attach both encoders to
> both drm_connectors at the same time, which is impossible because it's a
> mux. Indicating that each connector is connected is OK when HPD is high
> on both usb-c-connectors. Userspace will have to attach an encoder to
> the drm_connector it wants to use, and the drm_connector will indicate
> which drm_encoders are possible for it, so all the information will be
> provided to userspace in this design.
>
> I think it really comes down to implementing the tree walking logic in
> the drm bridge APIs. The problem is things like
> drm_bridge_get_next_bridge(), drm_bridge_get_prev_bridge(), and
> drm_for_each_bridge_in_chain() which will have to operate on a tree
> instead of a list. There's also drm_bridge_chain_get_first_bridge() and
> drm_bridge_attach(). The good news is most of these APIs are used
> sparingly.
>
> Maybe the simplest way to handle this is to maintain a tree of bridges
> and generate bridge chains when an encoder is attached to a connector in
> the tree. Pr

Re: [PATCH v15 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-05-09 Thread Pin-yen Lin
+Jagan who worked on a similar design and initiated the thread.

Hi Stephen,

On Sat, Apr 29, 2023 at 12:47 PM Stephen Boyd  wrote:
>
> Quoting Pin-yen Lin (2023-04-20 02:10:46)
> > On Thu, Apr 20, 2023 at 2:10 PM Stephen Boyd  wrote:
> > >
> > > Quoting Stephen Boyd (2023-04-13 17:22:46)
> > > > Quoting Pin-yen Lin (2023-04-13 02:50:44)
> > > > >
> > > > > Actually the `mode-switch` property here is mainly because
> > > > > `fwnode_typec_mux_get`[1] and `typec_mux_match`[2] only return matches
> > > > > when the property is present. I am not sure what side effects would be
> > > > > if I remove the ID-matching condition in `typec_mux_match`, so I added
> > > > > the property here.
> > > > >
> > > > > Is it feasible to remove the `mode-switch` property here given the
> > > > > existing implementation of the Type-C framework?
> > > >
> > > > Omitting the mode-switch property would require changes to the type-c
> > > > framework.
> > > >
> > > > I'm wondering if we can have this anx driver register mode switches for
> > > > however many endpoints exist in the output port all the time when the
> > > > aux-bus node doesn't exist. Then the type-c framework can walk from the
> > > > usb-c-connector to each connected node looking for a device that is both
> > > > a drm_bridge and a mode-switch. When it finds that combination, it knows
> > > > that the mode-switch has been found. This hinges on the idea that a
> > > > device that would have the mode-switch property is a drm_bridge and
> > > > would register a mode-switch with the type-c framework.
> > > >
> > > > It may be a little complicated though, because we would only register
> > > > one drm_bridge for the input to this anx device. The type-c walking code
> > > > would need to look at the graph endpoint, and find the parent device to
> > > > see if it is a drm_bridge.
> > >
> > > I've been thinking more about this. I think we should only have the
> > > 'mode-switch' property possible when the USB input pins (port@2) are
> > > connected and the DPI input pins are connected (port@0). Probably you
> > > don't have that case though?
> >
> > No we don't have the use case that uses the USB input pins on anx7625.
> > >
> > > In your case, this device should register either one or two drm_bridges
> > > that connect to whatever downstream is actually muxing the 2 DP lanes
> > > with the USB SS lanes onto the usb-c-connector.
> >
> > What do you mean by "muxing the 2 DP lanes with the USB SS lanes''? In
> > our use case, the USB data lanes from both ports are connected to a
> > USB hub, but the DP lanes are muxed by the crosspoint switch on
> > anx7625. HPD and AUX for the external display are muxed by the EC. You
> > can find the diagram at
> > https://lore.kernel.org/linux-usb/yxgzk6dnat0ac...@chromium.org/
>
> I mean that you must have some sort of orientation switch hardware that
> takes the 2 DP lanes and the 2 USB SuperSpeed "lanes" or "pairs" and
> puts them all onto a usb-c-connector. The usb-c-connector node can't be
> connected directly to the anx7625 in your diagram because there must be
> some sort of "flipper" that does the orientation control. Otherwise the
> usb-c-connector wouldn't work if the user flipped the cable. Probably
> this is some TCPC or redriver controlled by the EC.
>
> >
> > > If that is the EC for
> > > ChromeOS, then the EC should have a binding that accepts some number of
> > > input ports for DP. The EC would act as a drm_bridge, or in this case
> > > probably two bridges, and also as two type-c switches for each
> > > drm_bridge corresponding to the usb-c-connector nodes. When DP is on the
> > > cable, the type-c switch/mux would signal to the drm_bridge that the
> > > display is 'connected' via DRM_BRIDGE_OP_DETECT and struct
> > > drm_bridge_funcs::detect(). Then the drm_bridge in this anx part would
> > > implement struct drm_bridge_funcs::atomic_enable() and configure the
> > > crosspoint switch the right way depending on the reg property of the
> > > output node in port@1.
> >
> > So there will be two drm bridges that act as the downstreams for
> > anx7625, and we find the downstream with connector_status_connected to
> > configure the crosspoint switch? How do we suppor

Re: [PATCH v15 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-04-27 Thread Pin-yen Lin
On Thu, Apr 20, 2023 at 5:10 PM Pin-yen Lin  wrote:
>
> On Thu, Apr 20, 2023 at 2:10 PM Stephen Boyd  wrote:
> >
> > Quoting Stephen Boyd (2023-04-13 17:22:46)
> > > Quoting Pin-yen Lin (2023-04-13 02:50:44)
> > > >
> > > > Actually the `mode-switch` property here is mainly because
> > > > `fwnode_typec_mux_get`[1] and `typec_mux_match`[2] only return matches
> > > > when the property is present. I am not sure what side effects would be
> > > > if I remove the ID-matching condition in `typec_mux_match`, so I added
> > > > the property here.
> > > >
> > > > Is it feasible to remove the `mode-switch` property here given the
> > > > existing implementation of the Type-C framework?
> > >
> > > Omitting the mode-switch property would require changes to the type-c
> > > framework.
> > >
> > > I'm wondering if we can have this anx driver register mode switches for
> > > however many endpoints exist in the output port all the time when the
> > > aux-bus node doesn't exist. Then the type-c framework can walk from the
> > > usb-c-connector to each connected node looking for a device that is both
> > > a drm_bridge and a mode-switch. When it finds that combination, it knows
> > > that the mode-switch has been found. This hinges on the idea that a
> > > device that would have the mode-switch property is a drm_bridge and
> > > would register a mode-switch with the type-c framework.

I spent some time working on this approach on the Type-C side. The
issue I met is that the driver doesn't know whether a node is a
drm_bridge before the anx7625 driver probes. When there is a
"mode-switch" property in the node, the Type-C framework knows that
"here is a mode switch, but the corresponding driver hasn't registered
the typec_mux". So it returns -EPROBE_DEFER and retries later.
However, if we remove the property, the Type-C framework won't know
whether a node will be registered as a drm_bridge and register a
typec_mux.

Do you have other suggestions on this if we want to choose this approach?

Best regards,
Pin-yen
> > >
> > > It may be a little complicated though, because we would only register
> > > one drm_bridge for the input to this anx device. The type-c walking code
> > > would need to look at the graph endpoint, and find the parent device to
> > > see if it is a drm_bridge.
> >
> > I've been thinking more about this. I think we should only have the
> > 'mode-switch' property possible when the USB input pins (port@2) are
> > connected and the DPI input pins are connected (port@0). Probably you
> > don't have that case though?
>
> No we don't have the use case that uses the USB input pins on anx7625.
> >
> > In your case, this device should register either one or two drm_bridges
> > that connect to whatever downstream is actually muxing the 2 DP lanes
> > with the USB SS lanes onto the usb-c-connector.
>
> What do you mean by "muxing the 2 DP lanes with the USB SS lanes''? In
> our use case, the USB data lanes from both ports are connected to a
> USB hub, but the DP lanes are muxed by the crosspoint switch on
> anx7625. HPD and AUX for the external display are muxed by the EC. You
> can find the diagram at
> https://lore.kernel.org/linux-usb/yxgzk6dnat0ac...@chromium.org/
>
> > If that is the EC for
> > ChromeOS, then the EC should have a binding that accepts some number of
> > input ports for DP. The EC would act as a drm_bridge, or in this case
> > probably two bridges, and also as two type-c switches for each
> > drm_bridge corresponding to the usb-c-connector nodes. When DP is on the
> > cable, the type-c switch/mux would signal to the drm_bridge that the
> > display is 'connected' via DRM_BRIDGE_OP_DETECT and struct
> > drm_bridge_funcs::detect(). Then the drm_bridge in this anx part would
> > implement struct drm_bridge_funcs::atomic_enable() and configure the
> > crosspoint switch the right way depending on the reg property of the
> > output node in port@1.
>
> So there will be two drm bridges that act as the downstreams for
> anx7625, and we find the downstream with connector_status_connected to
> configure the crosspoint switch? How do we support that kind of
> topology given that the drm bridge chain is currently a list? Are you
> suggesting making the bridge topology to a tree, or maintaining the
> two downstreams inside the anx7625 driver and not attaching them to
> the bridge chain?
>
> Also, if we still register mode switches on the two downstream
> bridges, why do you prefer that over the original approach that
> register switches in the anx7625 driver?
>
> >
> > Because you don't have the part that implements the orientation-switch,
> > you don't need to implement the code for it. I think simply adding
> > support in the binding for mode-switch and orientation-switch if this is
> > directly wired to a usb-c-connector should be sufficient. Those
> > properties would be at the top-level and not part of the graph binding.


Re: [PATCH v15 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-04-20 Thread Pin-yen Lin
On Thu, Apr 20, 2023 at 2:10 PM Stephen Boyd  wrote:
>
> Quoting Stephen Boyd (2023-04-13 17:22:46)
> > Quoting Pin-yen Lin (2023-04-13 02:50:44)
> > >
> > > Actually the `mode-switch` property here is mainly because
> > > `fwnode_typec_mux_get`[1] and `typec_mux_match`[2] only return matches
> > > when the property is present. I am not sure what side effects would be
> > > if I remove the ID-matching condition in `typec_mux_match`, so I added
> > > the property here.
> > >
> > > Is it feasible to remove the `mode-switch` property here given the
> > > existing implementation of the Type-C framework?
> >
> > Omitting the mode-switch property would require changes to the type-c
> > framework.
> >
> > I'm wondering if we can have this anx driver register mode switches for
> > however many endpoints exist in the output port all the time when the
> > aux-bus node doesn't exist. Then the type-c framework can walk from the
> > usb-c-connector to each connected node looking for a device that is both
> > a drm_bridge and a mode-switch. When it finds that combination, it knows
> > that the mode-switch has been found. This hinges on the idea that a
> > device that would have the mode-switch property is a drm_bridge and
> > would register a mode-switch with the type-c framework.
> >
> > It may be a little complicated though, because we would only register
> > one drm_bridge for the input to this anx device. The type-c walking code
> > would need to look at the graph endpoint, and find the parent device to
> > see if it is a drm_bridge.
>
> I've been thinking more about this. I think we should only have the
> 'mode-switch' property possible when the USB input pins (port@2) are
> connected and the DPI input pins are connected (port@0). Probably you
> don't have that case though?

No we don't have the use case that uses the USB input pins on anx7625.
>
> In your case, this device should register either one or two drm_bridges
> that connect to whatever downstream is actually muxing the 2 DP lanes
> with the USB SS lanes onto the usb-c-connector.

What do you mean by "muxing the 2 DP lanes with the USB SS lanes''? In
our use case, the USB data lanes from both ports are connected to a
USB hub, but the DP lanes are muxed by the crosspoint switch on
anx7625. HPD and AUX for the external display are muxed by the EC. You
can find the diagram at
https://lore.kernel.org/linux-usb/yxgzk6dnat0ac...@chromium.org/

> If that is the EC for
> ChromeOS, then the EC should have a binding that accepts some number of
> input ports for DP. The EC would act as a drm_bridge, or in this case
> probably two bridges, and also as two type-c switches for each
> drm_bridge corresponding to the usb-c-connector nodes. When DP is on the
> cable, the type-c switch/mux would signal to the drm_bridge that the
> display is 'connected' via DRM_BRIDGE_OP_DETECT and struct
> drm_bridge_funcs::detect(). Then the drm_bridge in this anx part would
> implement struct drm_bridge_funcs::atomic_enable() and configure the
> crosspoint switch the right way depending on the reg property of the
> output node in port@1.

So there will be two drm bridges that act as the downstreams for
anx7625, and we find the downstream with connector_status_connected to
configure the crosspoint switch? How do we support that kind of
topology given that the drm bridge chain is currently a list? Are you
suggesting making the bridge topology to a tree, or maintaining the
two downstreams inside the anx7625 driver and not attaching them to
the bridge chain?

Also, if we still register mode switches on the two downstream
bridges, why do you prefer that over the original approach that
register switches in the anx7625 driver?

>
> Because you don't have the part that implements the orientation-switch,
> you don't need to implement the code for it. I think simply adding
> support in the binding for mode-switch and orientation-switch if this is
> directly wired to a usb-c-connector should be sufficient. Those
> properties would be at the top-level and not part of the graph binding.


Re: [PATCH v15 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-04-13 Thread Pin-yen Lin
Hi Stephen,

On Wed, Apr 12, 2023 at 10:38 AM Stephen Boyd  wrote:
>
> Quoting Pin-yen Lin (2023-03-31 02:11:39)
> > diff --git 
> > a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml 
> > b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
> > index b42553ac505c..604c7391d74f 100644
> > --- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
> > +++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
> > @@ -12,7 +12,8 @@ maintainers:
> >
> >  description: |
> >The ANX7625 is an ultra-low power 4K Mobile HD Transmitter
> > -  designed for portable devices.
> > +  designed for portable devices. Product brief is available at
> > +  
> > https://www.analogix.com/en/system/files/AA-002291-PB-6-ANX7625_ProductBrief.pdf
> >
> >  properties:
> >compatible:
> > @@ -112,9 +113,40 @@ properties:
> >data-lanes: true
> >
> >port@1:
> > -$ref: /schemas/graph.yaml#/properties/port
> > +$ref: /schemas/graph.yaml#/$defs/port-base
> >  description:
> > -  Video port for panel or connector.
> > +  Video port for panel or connector. Each endpoint connects to a 
> > video
> > +  output downstream, and the "data-lanes" property is used to 
> > describe
> > +  the pin connections. 0, 1, 2, 3 in "data-lanes" maps to SSRX1, 
> > SSTX1,
> > +  SSRX2, SSTX2, respectively.
> > +
> > +patternProperties:
> > +  "^endpoint@[01]$":
> > +$ref: /schemas/media/video-interfaces.yaml#
> > +properties:
> > +  reg: true
> > +
> > +  remote-endpoint: true
> > +
> > +  data-lanes:
> > +oneOf:
> > +  - items:
> > +  - enum: [0, 1, 2, 3]
> > +
> > +  - items:
> > +  - const: 0
> > +  - const: 1
> > +
> > +  - items:
> > +  - const: 2
> > +  - const: 3
> > +
> > +  mode-switch:
>
> Is it possible to not have this property? Can we have the driver for
> this anx device look at the remote-endpoint and if it sees that it is
> not a drm_bridge or panel on the other end, or a DP connector, that it
> should register a typec mode switch (or two depending on the number of
> endpoints in port@1)? Is there any case where that doesn't hold true?
>
> I see these possible scenarios:
>
> 1. DPI to DP bridge steering DP to one of two usb-c-connectors
>
> In this case, endpoint@0 is connected to one usb-c-connector and
> endpoint@1 is connected to another usb-c-connector. The input endpoint
> is only connected to DPI. The USB endpoint is not present (although I
> don't see this described in the binding either, so we would need a
> port@2, entirely optional to describe USB3 input). The driver will
> register two mode switches.
>
> 2. DPI to DP bridge with USB3 to one usb-c-connector
>
> In this case, endpoint@1 doesn't exist. The SSTX1/2 and SSRX1/2 pins are
> all connected to a usb-c-connector node. The input ports (0 and 2) are
> connected to both DPI and USB. The device acts as both a mode-switch and
> an orientation-switch. It registers both switches. I wonder if there is
> any benefit to describing SBU connections or CC connections? Maybe we
> don't register the orientation-switch if the SBU or CC connection isn't
> described?
>
> 3. DPI to DP bridge connected to eDP panel
>
> In this case, endpoint@1 doesn't exist. The USB endpoint is not present
> (port@2). Depending on how the crosspoint should be configured, we'll
> need to use data-lanes in the port@1 endpoint to describe which SSTRX
> pair to use (1 or 2). Or we'll have to use the endpoint's reg property
> to describe which pair to drive DP on. Presumably the default
> configuration is SSRX2/SSTX2 providing 2 lanes of DP to an eDP panel.
> The endpoint@0 in port@1 will be connected to a drm_panel, and the
> driver will be able to detect this properly by checking for the
> existence of an aux-bus node or the return value of
> of_dp_aux_populate_bus().

Can we assume that the eDP panel always stays behind an `aux-bus`
node? Can't the panel be connected to the bridge directly in the
graph? Though this might not matter if we only register mode switches
when there are usb-c-connectors connected.
>
> 4. DPI to DP bridge connected to DP connector
>
&g

Re: [PATCH v15 08/10] dt-bindings: display: bridge: it6505: Add mode-switch support

2023-04-06 Thread Pin-yen Lin
Hi Rob,

Thanks for the review.

On Fri, Apr 7, 2023 at 12:15 AM Rob Herring  wrote:
>
> On Fri, Mar 31, 2023 at 05:11:43PM +0800, Pin-yen Lin wrote:
> > ITE IT6505 can be used in systems to switch the DP traffic between
> > two downstreams, which can be USB Type-C DisplayPort alternate mode
> > lane or regular DisplayPort output ports.
> >
> > Update the binding to accommodate this usage by introducing a
> > data-lanes and a mode-switch property on endpoints.
> >
> > Signed-off-by: Pin-yen Lin 
> >
> > ---
> >
> > (no changes since v12)
> >
> > Changes in v12:
> > - Fixed the schema of "data-lanes" property for it6505
> > - Reworded the description of the mode-switch property
> >
> > Changes in v11:
> > - Updated the description of the endpoints in the bindings
> > - Referenced video-interfaces.yaml instead for the endpoints binding
> > - Removed duplicated definitions from inherited schema
> >
> > Changes in v9:
> > - Fixed subject prefix again
> > - Changed the naming of the example node for it6505
> >
> > Changes in v8:
> > - Updated bindings for data-lanes property
> > - Fixed subject prefix
> >
> > Changes in v7:
> > - Fixed issues reported by dt_binding_check.
> > - Updated the schema and the example dts for data-lanes.
> > - Changed to generic naming for the example dts node.
> >
> > Changes in v6:
> > - Remove switches node and use endpoints and data-lanes property to
> >   describe the connections.
> >
> >  .../bindings/display/bridge/ite,it6505.yaml   | 101 +++---
> >  1 file changed, 88 insertions(+), 13 deletions(-)
> >
> > diff --git 
> > a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml 
> > b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
> > index c9a882ee6d98..348b02f26041 100644
> > --- a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
> > +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
> > @@ -75,22 +75,49 @@ properties:
> >port@1:
> >  $ref: /schemas/graph.yaml#/$defs/port-base
> >  unevaluatedProperties: false
> > -description: Video port for DP output
> > +description:
> > +  Video port for DP output. Each endpoint connects to a video 
> > output
> > +  downstream, and the "data-lanes" property is used to describe 
> > the pin
> > +  connections. 0, 1, 2, 3 in "data-lanes" maps to TX0, TX1, TX2, 
> > TX3,
> > +  respectively.
> >
> > -properties:
> > -  endpoint:
> > -$ref: /schemas/graph.yaml#/$defs/endpoint-base
> > +
> > +patternProperties:
> > +  "^endpoint@[01]$":
> > +$ref: /schemas/media/video-interfaces.yaml#
> >  unevaluatedProperties: false
> >
> >  properties:
> > +  reg: true
> > +
> > +  remote-endpoint: true
>
> You don't need to list these 2.
>
> > +
> >data-lanes:
> > -minItems: 1
> > -uniqueItems: true
> > -items:
> > -  - enum: [ 0, 1 ]
> > -  - const: 1
> > -  - const: 2
> > -  - const: 3
> > +oneOf:
> > +  - items:
> > +  - enum: [0, 3]
>
> Only lane 1 wasn't valid? If so, mention that in the commit message.

Tha IT6505 bridge only supports "lane swapping" that reverses the
output pins, so only lane 1 or lane 2 is not valid. I'll update this
in the commit message as well.
>
> > +
> > +  - items:
> > +  - const: 0
> > +  - const: 1
> > +
> > +  - items:
> > +  - const: 3
> > +  - const: 2
> > +
> > +  - items:
> > +  - const: 0
> > +  - const: 1
> > +  - const: 2
> > +  - const: 3
>
> Isn't this the default if 'data-lanes' is omitted.

I don't think we have a "default" in the IT6505 driver because it
currently doesn't have any use case that has all 4 pins described in
an output node. The old use case uses an extcon node to describe the
output, and a 4-pin co

[PATCH v15 10/10] drm/bridge: it6505: Register Type C mode switches

2023-03-31 Thread Pin-yen Lin
Register USB Type-C mode switches when the "mode-switch" property and
relevant port are available in Device Tree. Configure the "lane_swap"
state based on the entered alternate mode for a specific Type-C
connector, which ends up updating the lane swap registers of the it6505
chip.

Signed-off-by: Pin-yen Lin 

---

Changes in v15:
- Add comments about the completion
- Fix style issues
- Abort the mux_set callback when the switch is unregistered

Changes in v14:
- Fix style issues

Changes in v13:
- Fix style issues

Changes in v12:
- Fixes style issues in it6505 driver
- Replaced &it6505->client->dev with it6505->dev
- Updated the error logs when parsing data-lanes property

Changes in v11:
- Added back "data-lanes" parsing logics
- Removed Kconfig dependency
- Updated the usage of the private data

Changes in v7:
- Fixed style issues in it6505 driver
- Removed the redundant sleep in it6505 driver
- Removed DT property validation in it6505 driver
- Rebased to drm-misc-next
- Extracted common codes to another commit

Changes in v6:
- Changed it6505_typec_mux_set callback function to accommodate with
  the latest drm-misc patches
- Changed the driver implementation to accommodate with the new binding
- Squashed to a single patch

 drivers/gpu/drm/bridge/ite-it6505.c | 198 +++-
 1 file changed, 191 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index 39edcbad586f..12fea5727c92 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -17,6 +17,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
@@ -27,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -401,6 +404,11 @@ struct debugfs_entries {
const struct file_operations *fops;
 };
 
+struct it6505_typec_port_data {
+   bool dp_connected;
+   bool lane_swap;
+};
+
 struct it6505 {
struct drm_dp_aux aux;
struct drm_bridge bridge;
@@ -454,6 +462,9 @@ struct it6505 {
struct delayed_work delayed_audio;
struct it6505_audio_data audio;
struct dentry *debugfs;
+   struct completion mux_register;
+   struct drm_dp_typec_switch_desc switch_desc;
+   struct it6505_typec_port_data *port_data;
 
/* it6505 driver hold option */
bool enable_drv_hold;
@@ -3357,12 +3368,172 @@ static void it6505_shutdown(struct i2c_client *client)
it6505_lane_off(it6505);
 }
 
+static void it6505_typec_ports_update(struct it6505 *it6505)
+{
+   unsigned int i;
+
+   /* Check if both ports available and do nothing to retain the current 
one */
+   if (it6505->port_data[0].dp_connected && 
it6505->port_data[1].dp_connected)
+   return;
+
+   for (i = 0; i < 2; i++) {
+   if (it6505->port_data[i].dp_connected)
+   it6505->lane_swap = it6505->port_data[i].lane_swap;
+   }
+}
+
+static int it6505_typec_mux_set(struct typec_mux_dev *mux,
+   struct typec_mux_state *state)
+{
+   struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
+   struct it6505 *it6505 = port->data;
+   struct device *dev = it6505->dev;
+   struct drm_dp_typec_switch_desc switch_desc = it6505->switch_desc;
+   bool old_dp_connected, new_dp_connected;
+   int ret = 0;
+
+   if (switch_desc.num_typec_switches == 1)
+   return 0;
+
+   mutex_lock(&it6505->extcon_lock);
+   /*
+* The completion is called in it6505_register_typec_switches even on
+* errors, so it's safe to wait for completion without timeout.
+*/
+   wait_for_completion(&it6505->mux_register);
+
+   /* Abort when the switches are unregistered. */
+   if (!it6505->port_data) {
+   ret = -EINVAL;
+   goto unlock;
+   }
+
+   old_dp_connected = it6505->port_data[0].dp_connected ||
+  it6505->port_data[1].dp_connected;
+
+   it6505->port_data[port->port_num].dp_connected =
+   state->alt &&
+   state->alt->svid == USB_TYPEC_DP_SID &&
+   state->alt->mode == USB_TYPEC_DP_MODE;
+
+   dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
+   it6505->port_data[0].dp_connected, 
it6505->port_data[1].dp_connected);
+
+   new_dp_connected = it6505->port_data[0].dp_connected ||
+  it6505->port_data[1].dp_connected;
+
+   if (it6505->enable_drv_hold) {
+   dev_dbg(dev, "enable driver hold\n");
+   goto unlock;
+   }
+
+   it6505_typec_ports_update(it6505);
+
+   if (!old_dp_connected && new_dp_connected) {
+   /*
+

[PATCH v15 08/10] dt-bindings: display: bridge: it6505: Add mode-switch support

2023-03-31 Thread Pin-yen Lin
ITE IT6505 can be used in systems to switch the DP traffic between
two downstreams, which can be USB Type-C DisplayPort alternate mode
lane or regular DisplayPort output ports.

Update the binding to accommodate this usage by introducing a
data-lanes and a mode-switch property on endpoints.

Signed-off-by: Pin-yen Lin 

---

(no changes since v12)

Changes in v12:
- Fixed the schema of "data-lanes" property for it6505
- Reworded the description of the mode-switch property

Changes in v11:
- Updated the description of the endpoints in the bindings
- Referenced video-interfaces.yaml instead for the endpoints binding
- Removed duplicated definitions from inherited schema

Changes in v9:
- Fixed subject prefix again
- Changed the naming of the example node for it6505

Changes in v8:
- Updated bindings for data-lanes property
- Fixed subject prefix

Changes in v7:
- Fixed issues reported by dt_binding_check.
- Updated the schema and the example dts for data-lanes.
- Changed to generic naming for the example dts node.

Changes in v6:
- Remove switches node and use endpoints and data-lanes property to
  describe the connections.

 .../bindings/display/bridge/ite,it6505.yaml   | 101 +++---
 1 file changed, 88 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml 
b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
index c9a882ee6d98..348b02f26041 100644
--- a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
@@ -75,22 +75,49 @@ properties:
   port@1:
 $ref: /schemas/graph.yaml#/$defs/port-base
 unevaluatedProperties: false
-description: Video port for DP output
+description:
+  Video port for DP output. Each endpoint connects to a video output
+  downstream, and the "data-lanes" property is used to describe the pin
+  connections. 0, 1, 2, 3 in "data-lanes" maps to TX0, TX1, TX2, TX3,
+  respectively.
 
-properties:
-  endpoint:
-$ref: /schemas/graph.yaml#/$defs/endpoint-base
+
+patternProperties:
+  "^endpoint@[01]$":
+$ref: /schemas/media/video-interfaces.yaml#
 unevaluatedProperties: false
 
 properties:
+  reg: true
+
+  remote-endpoint: true
+
   data-lanes:
-minItems: 1
-uniqueItems: true
-items:
-  - enum: [ 0, 1 ]
-  - const: 1
-  - const: 2
-  - const: 3
+oneOf:
+  - items:
+  - enum: [0, 3]
+
+  - items:
+  - const: 0
+  - const: 1
+
+  - items:
+  - const: 3
+  - const: 2
+
+  - items:
+  - const: 0
+  - const: 1
+  - const: 2
+  - const: 3
+
+  mode-switch:
+type: boolean
+description: Serves as Type-C mode switch if present.
+
+required:
+  - reg
+  - remote-endpoint
 
 required:
   - port@0
@@ -102,7 +129,6 @@ required:
   - pwr18-supply
   - interrupts
   - reset-gpios
-  - extcon
   - ports
 
 additionalProperties: false
@@ -139,8 +165,11 @@ examples:
 };
 
 port@1 {
+#address-cells = <1>;
+#size-cells = <0>;
 reg = <1>;
-it6505_out: endpoint {
+it6505_out: endpoint@0 {
+reg = <0>;
 remote-endpoint = <&dp_in>;
 data-lanes = <0 1>;
 };
@@ -148,3 +177,49 @@ examples:
 };
 };
 };
+  - |
+#include 
+
+i2c {
+#address-cells = <1>;
+#size-cells = <0>;
+
+dp-bridge@5c {
+compatible = "ite,it6505";
+interrupts = <8 IRQ_TYPE_LEVEL_LOW 8 0>;
+reg = <0x5c>;
+pinctrl-names = "default";
+pinctrl-0 = <&it6505_pins>;
+ovdd-supply = <&mt6366_vsim2_reg>;
+pwr18-supply = <&pp1800_dpbrdg_dx>;
+reset-gpios = <&pio 177 0>;
+
+ports {
+#address-cells = <1>;
+#size-cells = <0>;
+port@0 {
+reg = <0>;
+it6505_dpi_in: endpoint {
+remote-endpoint = <&dpi_out>;
+};
+};
+port@1 {
+ 

[PATCH v15 09/10] drm/bridge: it6505: Fix Kconfig indentation

2023-03-31 Thread Pin-yen Lin
Replace the spaces with tab characters in the Kconfig file.

Signed-off-by: Pin-yen Lin 
Reviewed-by: AngeloGioacchino Del Regno 


---

(no changes since v10)

Changes in v10:
- Collected Reviewed-by tag

Changes in v7:
- New in v7

 drivers/gpu/drm/bridge/Kconfig | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index f076a09afac0..8f81311710e5 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -74,19 +74,19 @@ config DRM_FSL_LDB
  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
 
 config DRM_ITE_IT6505
-tristate "ITE IT6505 DisplayPort bridge"
-depends on OF
+   tristate "ITE IT6505 DisplayPort bridge"
+   depends on OF
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDCP_HELPER
select DRM_DISPLAY_HELPER
-select DRM_DP_AUX_BUS
-select DRM_KMS_HELPER
-select DRM_DP_HELPER
-select EXTCON
-select CRYPTO
-select CRYPTO_HASH
-help
-  ITE IT6505 DisplayPort bridge chip driver.
+   select DRM_DP_AUX_BUS
+   select DRM_KMS_HELPER
+   select DRM_DP_HELPER
+   select EXTCON
+   select CRYPTO
+   select CRYPTO_HASH
+   help
+ ITE IT6505 DisplayPort bridge chip driver.
 
 config DRM_LONTIUM_LT8912B
tristate "Lontium LT8912B DSI/HDMI bridge"
-- 
2.40.0.348.gf938b09366-goog



[PATCH v15 07/10] drm/bridge: anx7625: Register Type C mode switches

2023-03-31 Thread Pin-yen Lin
Register USB Type-C mode switches when the "mode-switch" property and
relevant ports are available in Device Tree. Configure the crosspoint
switch based on the entered alternate mode for a specific Type-C
connector.

Crosspoint switch can also be used for switching the output signal for
different orientations of a single USB Type-C connector, but the
orientation switch is not implemented yet. A TODO is added for this.

Signed-off-by: Pin-yen Lin 

---

Changes in v15:
- Swap the definitions in anx7625_typec_port_data
- Add comments about the completion
- Abort the mux_set callback when the switch is unregistered
- Fix style issues

Changes in v14:
- Fix style issues

Changes in v12:
- Fixed style issues in anx7625 driver
- Fixed the inverted orientation setting in anx7625 driver
- Changed "&ctx->client->dev" to "ctx->dev"
- Fix style issues
- Updated the error logs when parsing data-lanes property

Changes in v11:
- Added back "data-lanes" parsing logics
- Removed Kconfig dependency
- Updated the usage of the private data
- Dropped Tested-by tag because of the new changes

Changes in v10:
- Added a TODO for implementing orientation switch for anx7625
- Updated the commit message for the absence of orientation switch
- Fixed typo in the commit message
- Collected Tested-by tag

Changes in v7:
- Fixed style issues in anx7625 driver
- Removed DT property validation in anx7625 driver.
- Extracted common codes to another commit.

Changes in v6:
- Squashed to a single patch

 drivers/gpu/drm/bridge/analogix/anx7625.c | 157 ++
 drivers/gpu/drm/bridge/analogix/anx7625.h |  20 +++
 2 files changed, 177 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 76d46db3f8dc..7ed5797e134c 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -15,6 +15,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
@@ -2570,6 +2572,154 @@ static void anx7625_runtime_disable(void *data)
pm_runtime_disable(data);
 }
 
+static void anx7625_set_crosspoint_switch(struct anx7625_data *ctx,
+ enum typec_orientation orientation)
+{
+   if (orientation == TYPEC_ORIENTATION_NORMAL) {
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_0,
+ SW_SEL1_SSRX_RX1 | SW_SEL1_DPTX0_RX2);
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_1,
+ SW_SEL2_SSTX_TX1 | SW_SEL2_DPTX1_TX2);
+   } else if (orientation == TYPEC_ORIENTATION_REVERSE) {
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_0,
+ SW_SEL1_SSRX_RX2 | SW_SEL1_DPTX0_RX1);
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_1,
+ SW_SEL2_SSTX_TX2 | SW_SEL2_DPTX1_TX1);
+   }
+}
+
+static void anx7625_typec_two_ports_update(struct anx7625_data *ctx)
+{
+   unsigned int i;
+
+   /* Check if both ports available and do nothing to retain the current 
one */
+   if (ctx->port_data[0].dp_connected && ctx->port_data[1].dp_connected)
+   return;
+
+   for (i = 0; i < 2; i++) {
+   if (ctx->port_data[i].dp_connected)
+   anx7625_set_crosspoint_switch(ctx,
+ 
ctx->port_data[i].orientation);
+   }
+}
+
+static int anx7625_typec_mux_set(struct typec_mux_dev *mux,
+struct typec_mux_state *state)
+{
+   struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
+   struct anx7625_data *ctx = port->data;
+   struct device *dev = ctx->dev;
+   struct drm_dp_typec_switch_desc switch_desc = ctx->switch_desc;
+   bool new_dp_connected, old_dp_connected;
+
+   if (switch_desc.num_typec_switches == 1)
+   return 0;
+
+   /*
+* The completion is called in anx7625_register_typec_switches
+* even on errors, so it's safe to wait for completion without timeout.
+*/
+   wait_for_completion(&ctx->mux_register);
+
+   /* Abort when the switches are unregistered. */
+   if (!ctx->port_data)
+   return -EINVAL;
+
+   old_dp_connected = ctx->port_data[0].dp_connected ||
+  ctx->port_data[1].dp_connected;
+
+   ctx->port_data[port->port_num].dp_connected =
+   state->alt &&
+   state->alt->svid == USB_TYPEC_DP_SID &&
+   state->alt->mode == USB_TYPEC_DP_MODE;
+
+   dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
+   ctx->port_data[0].dp_connected, ctx->port_data[1].dp_connected);
+
+   new_dp_c

[PATCH v15 06/10] drm/bridge: Remove redundant i2c_client in anx7625/it6505

2023-03-31 Thread Pin-yen Lin
These two drivers embed a i2c_client in their private driver data, but
only strict device is actually needed. Replace the i2c_client reference
with a struct device one.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 
Reviewed-by: AngeloGioacchino Del Regno 


---

Changes in v15:
- Collect review tag

Changes in v13:
- Update a typo in the commit message
- Collect Reviewed-by tag

Changes in v12:
- New in v12

 drivers/gpu/drm/bridge/analogix/anx7625.c |  96 
 drivers/gpu/drm/bridge/analogix/anx7625.h |   2 +-
 drivers/gpu/drm/bridge/ite-it6505.c   | 128 +++---
 3 files changed, 113 insertions(+), 113 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 3f6bf7674d32..76d46db3f8dc 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -207,7 +207,7 @@ static int anx7625_read_ctrl_status_p0(struct anx7625_data 
*ctx)
 
 static int wait_aux_op_finish(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int val;
int ret;
 
@@ -234,7 +234,7 @@ static int wait_aux_op_finish(struct anx7625_data *ctx)
 static int anx7625_aux_trans(struct anx7625_data *ctx, u8 op, u32 address,
 u8 len, u8 *buf)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
u8 addrh, addrm, addrl;
u8 cmd;
@@ -427,7 +427,7 @@ static int anx7625_odfc_config(struct anx7625_data *ctx,
   u8 post_divider)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Config input reference clock frequency 27MHz/19.2MHz */
ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, MIPI_DIGITAL_PLL_16,
@@ -477,7 +477,7 @@ static int anx7625_set_k_value(struct anx7625_data *ctx)
 
 static int anx7625_dsi_video_timing_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
unsigned long m, n;
u16 htotal;
int ret;
@@ -575,7 +575,7 @@ static int anx7625_dsi_video_timing_config(struct 
anx7625_data *ctx)
 static int anx7625_swap_dsi_lane3(struct anx7625_data *ctx)
 {
int val;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Swap MIPI-DSI data lane 3 P and N */
val = anx7625_reg_read(ctx, ctx->i2c.rx_p1_client, MIPI_SWAP);
@@ -592,7 +592,7 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx)
 
 {
int val, ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Swap MIPI-DSI data lane 3 P and N */
ret = anx7625_swap_dsi_lane3(ctx);
@@ -657,7 +657,7 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx)
 
 static int anx7625_dsi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
 
DRM_DEV_DEBUG_DRIVER(dev, "config dsi.\n");
@@ -689,7 +689,7 @@ static int anx7625_dsi_config(struct anx7625_data *ctx)
 
 static int anx7625_api_dpi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
u16 freq = ctx->dt.pixelclock.min / 1000;
int ret;
 
@@ -720,7 +720,7 @@ static int anx7625_api_dpi_config(struct anx7625_data *ctx)
 
 static int anx7625_dpi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
 
DRM_DEV_DEBUG_DRIVER(dev, "config dpi\n");
@@ -765,7 +765,7 @@ static int anx7625_read_flash_status(struct anx7625_data 
*ctx)
 static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
 {
int ret, val;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
u8 ident[FLASH_BUF_LEN];
 
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -815,7 +815,7 @@ static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
 static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Select HDCP 1.4 KEY */
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -843,7 +843,7 @@ static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
 static int anx7625_hdcp_disable(struct anx7625_data *ctx)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
dev_dbg(dev, "disable HDCP 1.4\n");
 
@@ -864,7 +86

[PATCH v15 05/10] drm/bridge: anx7625: Check for Type-C during panel registration

2023-03-31 Thread Pin-yen Lin
The output port endpoints can be connected to USB-C connectors.
Running drm_of_find_panel_or_bridge() with such endpoints leads to
a continuous return value of -EPROBE_DEFER, even though there is
no panel present.

To avoid this, check for the existence of a "mode-switch" property in
the port endpoint, and skip panel registration completely if so.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 
Reviewed-by: AngeloGioacchino Del Regno 


---

Changes in v15:
- Collect review tag

Changes in v14:
- Collect review tag

Changes in v13:
- Use the new typec_mode_switch_node_count helper

Changes in v12:
- Updated to use fwnode_for_each_typec_mode_switch macro
- Dropped collected tags

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v6:
- New in v6

 drivers/gpu/drm/bridge/analogix/anx7625.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 6846199a2ee1..3f6bf7674d32 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -1648,7 +1648,8 @@ static int anx7625_get_swing_setting(struct device *dev,
 static int anx7625_parse_dt(struct device *dev,
struct anx7625_platform_data *pdata)
 {
-   struct device_node *np = dev->of_node, *ep0;
+   struct device_node *np = dev->of_node, *ep0, *port_node;
+   unsigned int count;
int bus_type, mipi_lanes;
 
anx7625_get_swing_setting(dev, pdata);
@@ -1687,6 +1688,15 @@ static int anx7625_parse_dt(struct device *dev,
if (of_property_read_bool(np, "analogix,audio-enable"))
pdata->audio_en = 1;
 
+   /*
+* Don't bother finding a panel if a Type-C `mode-switch` property is
+* present in one of the endpoints in the output port.
+*/
+   port_node = of_graph_get_port_by_id(np, 1);
+   count = typec_mode_switch_node_count(&port_node->fwnode);
+   if (count)
+   return 0;
+
pdata->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
if (IS_ERR(pdata->panel_bridge)) {
if (PTR_ERR(pdata->panel_bridge) == -ENODEV) {
-- 
2.40.0.348.gf938b09366-goog



[PATCH v15 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-03-31 Thread Pin-yen Lin
Analogix 7625 can be used in systems to switch the DP traffic between
two downstreams, which can be USB Type-C DisplayPort alternate mode
lane or regular DisplayPort output ports.

Update the binding to accommodate this usage by introducing a
data-lanes and a mode-switch property on endpoints.

Also include the link to the product brief in the bindings.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Krzysztof Kozlowski 
Reviewed-by: Chen-Yu Tsai 
Tested-by: Chen-Yu Tsai 
Reviewed-by: AngeloGioacchino Del Regno 


---

(no changes since v12)

Changes in v12:
- Removed the 4-lane binding in analogix,anx7625.yaml
- Reworded the description for the mode-switch property

Changes in v11:
- Updated the description of the endpoints
- Referenced video-interfaces.yaml instead for the endpoints

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v9:
- Collected Reviewed-by tag

Changes in v8:
- Updated anx7625 bindings for data-lane property
- Fixed the subject prefix

Changes in v7:
- Fixed issues reported by dt_binding_check
- Updated the schema and the example dts for data-lanes.
- Changed to generic naming for the example dts node.

Changes in v6:
- Remove switches node and use endpoints and data-lanes property to
  describe the connections.

 .../display/bridge/analogix,anx7625.yaml  | 88 ++-
 1 file changed, 85 insertions(+), 3 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml 
b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
index b42553ac505c..604c7391d74f 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
@@ -12,7 +12,8 @@ maintainers:
 
 description: |
   The ANX7625 is an ultra-low power 4K Mobile HD Transmitter
-  designed for portable devices.
+  designed for portable devices. Product brief is available at
+  
https://www.analogix.com/en/system/files/AA-002291-PB-6-ANX7625_ProductBrief.pdf
 
 properties:
   compatible:
@@ -112,9 +113,40 @@ properties:
   data-lanes: true
 
   port@1:
-$ref: /schemas/graph.yaml#/properties/port
+$ref: /schemas/graph.yaml#/$defs/port-base
 description:
-  Video port for panel or connector.
+  Video port for panel or connector. Each endpoint connects to a video
+  output downstream, and the "data-lanes" property is used to describe
+  the pin connections. 0, 1, 2, 3 in "data-lanes" maps to SSRX1, SSTX1,
+  SSRX2, SSTX2, respectively.
+
+patternProperties:
+  "^endpoint@[01]$":
+$ref: /schemas/media/video-interfaces.yaml#
+properties:
+  reg: true
+
+  remote-endpoint: true
+
+  data-lanes:
+oneOf:
+  - items:
+  - enum: [0, 1, 2, 3]
+
+  - items:
+  - const: 0
+  - const: 1
+
+  - items:
+  - const: 2
+  - const: 3
+
+  mode-switch:
+type: boolean
+description: Serves as Type-C mode switch if present.
+
+required:
+  - remote-endpoint
 
 required:
   - port@0
@@ -186,3 +218,53 @@ examples:
 };
 };
 };
+  - |
+i2c3 {
+#address-cells = <1>;
+#size-cells = <0>;
+
+encoder@58 {
+compatible = "analogix,anx7625";
+reg = <0x58>;
+pinctrl-names = "default";
+pinctrl-0 = <&anx7625_dp_pins>;
+enable-gpios = <&pio 176 GPIO_ACTIVE_HIGH>;
+reset-gpios = <&pio 177 GPIO_ACTIVE_HIGH>;
+vdd10-supply = <&pp1100_dpbrdg>;
+vdd18-supply = <&pp1800_dpbrdg_dx>;
+vdd33-supply = <&pp3300_dpbrdg_dx>;
+analogix,audio-enable;
+
+ports {
+#address-cells = <1>;
+#size-cells = <0>;
+
+port@0 {
+reg = <0>;
+anx7625_dp_in: endpoint {
+bus-type = <7>;
+remote-endpoint = <&dpi_out>;
+};
+};
+
+port@1 {
+#address-cells = <1>;
+#size-cells = <0>;
+
+reg = <1>;
+anx_typec0: endpoint@0 {
+reg = <0>;
+mode-switch;
+data-lanes = <0 1>;
+remote-endpoint = <&typec_port0>;
+};
+  

[PATCH v15 03/10] drm/display: Add Type-C switch helpers

2023-03-31 Thread Pin-yen Lin
Add helpers to register and unregister Type-C "switches" for bridges
capable of switching their output between two downstream devices.

The helper registers USB Type-C mode switches when the "mode-switch"
and the "reg" properties are available in Device Tree.

Signed-off-by: Pin-yen Lin 

---

Changes in v15:
- Change the struct definition order for the Type-C switch helpers
- Fix style issues
- Updated the docs for the return value
- Updated the description in Kconfig
- Use dev_name as the typec_mux name

Changes in v14:
- Introduce a new Kconfig because it didn't build when CONFIG_TYPEC=m
- Add comments about devm_* usage
- Fix style issues

Changes in v13:
- Add typec_mode_switch_node_count helper
- Fix style issues

Changes in v12:
- Add fwnode_for_each_typec_mode_switch macro
- Remove a duplicated dmesg in the helper
- Used IS_REACHABLE instead to guard the function signatures

Changes in v11:
- Use fwnode helpers instead of DT
- Moved the helpers to a new file
- Use "reg" instead of "data-lanes" to determine the port number
- Dropped collected tags due to new changes

Changes in v10:
- Collected Reviewed-by and Tested-by tags
- Replaced "void *" with "typec_mux_set_fn_t" for mux_set callbacks
- Print out the node name when errors on parsing DT
- Use dev_dbg instead of dev_warn when no Type-C switch nodes available
- Made the return path of drm_dp_register_mode_switch clearer

Changes in v8:
- Fixed the build issue when CONFIG_TYPEC=m
- Fixed some style issues

Changes in v7:
- Extracted the common codes to a helper function
- New in v7

 drivers/gpu/drm/display/Kconfig   |   8 ++
 drivers/gpu/drm/display/Makefile  |   2 +
 drivers/gpu/drm/display/drm_dp_typec_helper.c | 107 ++
 include/drm/display/drm_dp_helper.h   |  46 
 4 files changed, 163 insertions(+)
 create mode 100644 drivers/gpu/drm/display/drm_dp_typec_helper.c

diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index 09712b88a5b8..4eaf00380a1f 100644
--- a/drivers/gpu/drm/display/Kconfig
+++ b/drivers/gpu/drm/display/Kconfig
@@ -29,6 +29,14 @@ config DRM_DISPLAY_HDMI_HELPER
help
  DRM display helpers for HDMI.
 
+config DRM_DISPLAY_DP_TYPEC_HELPER
+   def_bool y
+   depends on DRM_DISPLAY_HELPER
+   depends on DRM_DISPLAY_HELPER=TYPEC || TYPEC=y
+   help
+ Choose this option to enable helpers for registering USB Type-C
+ switches when USB Type-C DisplayPort Alternate mode is used.
+
 config DRM_DP_AUX_CHARDEV
bool "DRM DP AUX Interface"
depends on DRM && DRM_DISPLAY_HELPER
diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile
index 17ac4a1006a8..2202a6aea38e 100644
--- a/drivers/gpu/drm/display/Makefile
+++ b/drivers/gpu/drm/display/Makefile
@@ -8,6 +8,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \
drm_dp_helper.o \
drm_dp_mst_topology.o \
drm_dsc_helper.o
+drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER) += \
+   drm_dp_typec_helper.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
drm_hdmi_helper.o \
diff --git a/drivers/gpu/drm/display/drm_dp_typec_helper.c 
b/drivers/gpu/drm/display/drm_dp_typec_helper.c
new file mode 100644
index ..48c1bbf57b2d
--- /dev/null
+++ b/drivers/gpu/drm/display/drm_dp_typec_helper.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+
+static int drm_dp_register_mode_switch(struct device *dev,
+  struct fwnode_handle *fwnode,
+  struct drm_dp_typec_switch_desc 
*switch_desc,
+  void *data, typec_mux_set_fn_t mux_set)
+{
+   struct drm_dp_typec_port_data *port_data;
+   struct typec_mux_desc mux_desc = {};
+   char name[32];
+   u32 port_num;
+   int ret;
+
+   ret = fwnode_property_read_u32(fwnode, "reg", &port_num);
+   if (ret) {
+   dev_err(dev, "Failed to read reg property: %d\n", ret);
+   return ret;
+   }
+
+   port_data = &switch_desc->typec_ports[port_num];
+   port_data->data = data;
+   port_data->port_num = port_num;
+   port_data->fwnode = fwnode;
+   mux_desc.fwnode = fwnode;
+   mux_desc.drvdata = port_data;
+   snprintf(name, sizeof(name), "%s-%u", dev_name(dev), port_num);
+   mux_desc.name = name;
+   mux_desc.set = mux_set;
+
+   port_data->typec_mux = typec_mux_register(dev, &mux_desc);
+   ret = PTR_ERR_OR_ZERO(port_data->typec_mux);
+   if (ret)
+   dev_err(dev, "Mode switch register for port %d failed: %d\n",
+   port_num, ret);
+
+

[PATCH v15 02/10] platform/chrome: cros_ec_typec: Purge blocking switch devlinks

2023-03-31 Thread Pin-yen Lin
From: Prashant Malani 

When using OF graph, the fw_devlink code will create links between the
individual port driver (cros-ec-typec here) and the parent device for
a Type-C switch (like mode-switch). Since the mode-switch will in turn
have the usb-c-connector (i.e the child of the port driver) as a
supplier, fw_devlink will not be able to resolve the cyclic dependency
correctly.

As a result, the mode-switch driver probe() never runs, so mode-switches
are never registered. Because of that, the port driver probe constantly
fails with -EPROBE_DEFER, because the Type-C connector class requires all
switch devices to be registered prior to port registration.

To break this deadlock and allow the mode-switch registration to occur,
purge all the usb-c-connector nodes' absent suppliers. This eliminates
the connector as a supplier for a switch and allows it to be probed.

Signed-off-by: Prashant Malani 
Signed-off-by: Pin-yen Lin 
Reviewed-by: Chen-Yu Tsai 
Reviewed-by: AngeloGioacchino Del Regno 

Tested-by: Chen-Yu Tsai 
Acked-by: Heikki Krogerus 

---

Changes in v15:
- Collected Reviewed-by tags

Changes in v11:
- Collected Acked-by tag

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v7:
- Fix the long comment lines

Changes in v6:
- New in v6

 drivers/platform/chrome/cros_ec_typec.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/platform/chrome/cros_ec_typec.c 
b/drivers/platform/chrome/cros_ec_typec.c
index a673c3342470..5911cd9640cb 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -325,6 +325,16 @@ static int cros_typec_init_ports(struct cros_typec_data 
*typec)
return -EINVAL;
}
 
+   /*
+* OF graph may have set up some device links with switches,
+* since connectors have their own compatible. Purge these
+* to avoid a deadlock in switch probe (the switch mistakenly
+* assumes the connector is a supplier).
+*/
+   if (dev_of_node(dev))
+   device_for_each_child_node(dev, fwnode)
+   fw_devlink_purge_absent_suppliers(fwnode);
+
/* DT uses "reg" to specify port number. */
port_prop = dev->of_node ? "reg" : "port-number";
device_for_each_child_node(dev, fwnode) {
-- 
2.40.0.348.gf938b09366-goog



[PATCH v15 01/10] device property: Add remote endpoint to devcon matcher

2023-03-31 Thread Pin-yen Lin
From: Prashant Malani 

When searching the device graph for device matches, check the
remote-endpoint itself for a match.

Some drivers register devices for individual endpoints. This allows
the matcher code to evaluate those for a match too, instead
of only looking at the remote parent devices. This is required when a
device supports two mode switches in its endpoints, so we can't simply
register the mode switch with the parent node.

Signed-off-by: Prashant Malani 
Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 
Reviewed-by: Sakari Ailus 
Reviewed-by: Heikki Krogerus 

---

(no changes since v14)

Changes in v14:
- Collect review tags

Changes in v13:
- Update the kernel doc of fwnode_connection_find_match

Changes in v12:
- Check the availability of the device node in fwnode_graph_devcon_matches
- Ensured valid access to "matches" in fwnode_graph_devcon_matches
- Updated the documentation in fwnode_connection_find_match(es)
- Dropped collected tags due to the new changes

Changes in v11:
- Added missing fwnode_handle_put in drivers/base/property.c

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v6:
- New in v6

 drivers/base/property.c | 31 ++-
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/base/property.c b/drivers/base/property.c
index 083a95791d3b..4426ac2b16ca 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1243,6 +1243,23 @@ static unsigned int fwnode_graph_devcon_matches(const 
struct fwnode_handle *fwno
continue;
}
 
+   ret = match(node, con_id, data);
+   fwnode_handle_put(node);
+   if (ret) {
+   if (matches)
+   matches[count] = ret;
+   count++;
+
+   if (matches && count >= matches_len)
+   break;
+   }
+
+   /*
+* Some drivers may register devices for endpoints. Check
+* the remote-endpoints for matches in addition to the remote
+* port parent.
+*/
+   node = fwnode_graph_get_remote_endpoint(ep);
ret = match(node, con_id, data);
fwnode_handle_put(node);
if (ret) {
@@ -1293,8 +1310,11 @@ static unsigned int fwnode_devcon_matches(const struct 
fwnode_handle *fwnode,
  * @match: Function to check and convert the connection description
  *
  * Find a connection with unique identifier @con_id between @fwnode and another
- * device node. @match will be used to convert the connection description to
- * data the caller is expecting to be returned.
+ * device node. For fwnode graph connections, the graph endpoints are also
+ * checked. @match will be used to convert the connection description to data
+ * the caller is expecting to be returned.
+ *
+ * Return: The pointer to the matched node, or NULL on error.
  */
 void *fwnode_connection_find_match(const struct fwnode_handle *fwnode,
   const char *con_id, void *data,
@@ -1325,9 +1345,10 @@ EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
  * @matches_len: Length of @matches
  *
  * Find up to @matches_len connections with unique identifier @con_id between
- * @fwnode and other device nodes. @match will be used to convert the
- * connection description to data the caller is expecting to be returned
- * through the @matches array.
+ * @fwnode and other device nodes. For fwnode graph connections, the graph
+ * endpoints are also checked. @match will be used to convert the connection
+ * description to data the caller is expecting to be returned through the
+ * @matches array.
  * If @matches is NULL @matches_len is ignored and the total number of resolved
  * matches is returned.
  *
-- 
2.40.0.348.gf938b09366-goog



[PATCH v15 00/10] Register Type-C mode-switch in DP bridge endpoints

2023-03-31 Thread Pin-yen Lin
6505 driver
- Removed DT property validation in it6505 driver
- Rebased to drm-misc-next
- Fixed indentations in bindings patches
- Added a new patch to fix indentations in Kconfig

Changes in v6:
- Changed it6505_typec_mux_set callback function to accommodate with
  the latest drm-misc patches
- Changed the driver implementation to accommodate with the new binding
- Dropped typec-switch binding and use endpoints and data-lanes properties
  to describe the pin connections
- Added new patches (patch 1,2,4) to fix probing issues
- Changed the bindings of it6505/anx7625 and modified the drivers
  accordingly
- Merged it6505/anx7625 driver changes into a single patch

Pin-yen Lin (8):
  drm/display: Add Type-C switch helpers
  dt-bindings: display: bridge: anx7625: Add mode-switch support
  drm/bridge: anx7625: Check for Type-C during panel registration
  drm/bridge: Remove redundant i2c_client in anx7625/it6505
  drm/bridge: anx7625: Register Type C mode switches
  dt-bindings: display: bridge: it6505: Add mode-switch support
  drm/bridge: it6505: Fix Kconfig indentation
  drm/bridge: it6505: Register Type C mode switches

Prashant Malani (2):
  device property: Add remote endpoint to devcon matcher
  platform/chrome: cros_ec_typec: Purge blocking switch devlinks

 .../display/bridge/analogix,anx7625.yaml  |  88 -
 .../bindings/display/bridge/ite,it6505.yaml   | 101 +-
 drivers/base/property.c   |  31 +-
 drivers/gpu/drm/bridge/Kconfig|  20 +-
 drivers/gpu/drm/bridge/analogix/anx7625.c | 265 +++---
 drivers/gpu/drm/bridge/analogix/anx7625.h |  22 +-
 drivers/gpu/drm/bridge/ite-it6505.c   | 326 ++
 drivers/gpu/drm/display/Kconfig   |   8 +
 drivers/gpu/drm/display/Makefile  |   2 +
 drivers/gpu/drm/display/drm_dp_typec_helper.c | 107 ++
 drivers/platform/chrome/cros_ec_typec.c   |  10 +
 include/drm/display/drm_dp_helper.h   |  46 +++
 12 files changed, 874 insertions(+), 152 deletions(-)
 create mode 100644 drivers/gpu/drm/display/drm_dp_typec_helper.c

-- 
2.40.0.348.gf938b09366-goog



Re: [PATCH v14 07/10] drm/bridge: anx7625: Register Type C mode switches

2023-03-31 Thread Pin-yen Lin
Hi Andy,

Thanks for the review.

On Wed, Mar 22, 2023 at 8:16 PM Andy Shevchenko
 wrote:
>
> On Wed, Mar 22, 2023 at 06:46:36PM +0800, Pin-yen Lin wrote:
> > Register USB Type-C mode switches when the "mode-switch" property and
> > relevant ports are available in Device Tree. Configure the crosspoint
> > switch based on the entered alternate mode for a specific Type-C
> > connector.
> >
> > Crosspoint switch can also be used for switching the output signal for
> > different orientations of a single USB Type-C connector, but the
> > orientation switch is not implemented yet. A TODO is added for this.
>
> ...
>
> > +static int anx7625_typec_mux_set(struct typec_mux_dev *mux,
> > +  struct typec_mux_state *state)
> > +{
> > + struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
> > + struct anx7625_data *ctx = port->data;
> > + struct device *dev = ctx->dev;
> > + struct drm_dp_typec_switch_desc switch_desc = ctx->switch_desc;
> > + bool new_dp_connected, old_dp_connected;
> > +
> > + if (switch_desc.num_typec_switches == 1)
> > + return 0;
>
> > + wait_for_completion(&ctx->mux_register);
>
> How do we guarantee this won't become an infinite waiting?
> Perhaps a comment explaining that?
>
> > + old_dp_connected = ctx->port_data[0].dp_connected ||
> > +ctx->port_data[1].dp_connected;
> > +
> > + ctx->port_data[port->port_num].dp_connected =
> > + state->alt &&
> > + state->alt->svid == USB_TYPEC_DP_SID &&
> > + state->alt->mode == USB_TYPEC_DP_MODE;
> > +
> > + dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
> > + ctx->port_data[0].dp_connected, 
> > ctx->port_data[1].dp_connected);
> > +
> > + new_dp_connected = ctx->port_data[0].dp_connected ||
> > +ctx->port_data[1].dp_connected;
> > +
> > + /* DP on, power on first */
> > + if (!old_dp_connected && new_dp_connected)
> > + pm_runtime_get_sync(dev);
> > +
> > + anx7625_typec_two_ports_update(ctx);
> > +
> > + /* DP off, power off last */
> > + if (old_dp_connected && !new_dp_connected)
> > + pm_runtime_put_sync(dev);
> > +
> > + return 0;
> > +}
>
> ...
>
> > + struct device_node *port_node = of_graph_get_port_by_id(dev->of_node, 
> > 1);
>
> You use fwnode below, so why not fwnode_graph_...(dev_fwnode(dev), ...) ?

There is no existing helper like `fwnode_graph_get_port_by_id`, so
using of_graph variant is easier here. Should I add a
`fwnode_graph_get_port_by_id` helper for this?
>
> > + struct drm_dp_typec_switch_desc *switch_desc = &ctx->switch_desc;
> > + int ret;
> > + u32 dp_lanes[4];
> > + unsigned int i, num_lanes;
> > +
> > + /*
> > +  * Currently, only mode switch is implemented.
> > +  * TODO: Implement Type-C orientation switch for anx7625.
> > +  */
> > + ret = drm_dp_register_typec_switches(dev, &port_node->fwnode,
> > +  &ctx->switch_desc, ctx,
> > +  anx7625_typec_mux_set);
> > + if (ret)
> > + return ret;
> > +
> > + ctx->port_data = devm_kcalloc(dev, switch_desc->num_typec_switches,
> > +   sizeof(struct anx7625_typec_port_data),
>
>   sizeof(*ctx->port_data),
>
> ?
>
> > +   GFP_KERNEL);
> > + if (!ctx->port_data) {
> > + ret = -ENOMEM;
> > + goto unregister_mux;
> > + }
>
> ...
>
> > +struct anx7625_typec_port_data {
> > + bool dp_connected;
> > + enum typec_orientation orientation;
>
> Most likely enum will be 32-bit and bool 8-bit. Which means that the data type
> size become 8 bytes for no reason. Can you swap the lines and perhaps check 
> this
> with `pahole` tool?
>
> > +};
>
> --
> With Best Regards,
> Andy Shevchenko
>
>

Best regards,
Pin-yen


Re: [PATCH v14 03/10] drm/display: Add Type-C switch helpers

2023-03-30 Thread Pin-yen Lin
On Fri, Mar 31, 2023 at 11:36 AM Pin-yen Lin  wrote:
>
> Hi Andy,
>
> Thanks for the review.
>
> On Wed, Mar 22, 2023 at 8:01 PM Andy Shevchenko
>  wrote:
> >
> > On Wed, Mar 22, 2023 at 06:46:32PM +0800, Pin-yen Lin wrote:
> > > Add helpers to register and unregister Type-C "switches" for bridges
> > > capable of switching their output between two downstream devices.
> > >
> > > The helper registers USB Type-C mode switches when the "mode-switch"
> > > and the "reg" properties are available in Device Tree.
> >
> > ...
> >
> > > +config DRM_DISPLAY_DP_TYPEC_HELPER
> >
> > > + bool
> > > + default y
> >
> > def_bool y
> >
> > > + depends on DRM_DISPLAY_HELPER
> > > + depends on DRM_DISPLAY_HELPER=TYPEC || TYPEC=y
> > > + help
> > > +   DRM display helpers for USB Type-C Displayport Alternate mode.
> >
> > Hmm... Dunno if this help is enough.
>
> Okay I'll add more detail in the next version.
> >
> > ...
> >
> > > + snprintf(name, sizeof(name), "%pfwP-%u", fwnode, port_num);
> >
> > Would it be possible to have a dup in name and would it be a problem if so?
> >
> The port_num is included in the name, so the names should be unique.
> Also, the fwnode name actually contains the reg property, so this name
> looks like "endpoint@0-1" now... I'll change the name from fwnode name

This should be "endpoint@0-0", or "endpoint@1-1@. The `port_num` value
has the same number as the `reg` property

> to dev_name() per Dmitry's comment.
> > ...
> >
> > > +/**
> > > + * drm_dp_register_typec_switches() - register Type-C switches
> > > + * @dev: Device that registers Type-C switches
> > > + * @port: Device node for the switch
> > > + * @switch_desc: A Type-C switch descriptor
> > > + * @data: Private data for the switches
> > > + * @mux_set: Callback function for typec_mux_set
> > > + *
> > > + * This function registers USB Type-C switches for DP bridges that can 
> > > switch
> > > + * the output signal between their output pins. This function uses 
> > > devm_kcalloc
> > > + * to allocate memory, so it is expected to only call this in the driver 
> > > probe
> > > + * functions.
> > > + *
> > > + * Currently only mode switches are implemented, and the function 
> > > assumes the
> > > + * given @port device node has endpoints with "mode-switch" property.
> > > + * The port number is determined by the "reg" property of the endpoint.
> >
> > `kernel-doc -v ...` should complain on absence of "Return" section.
> >
> > > + */
> >
> > ...
> >
> > > + switch_desc->typec_ports = devm_kcalloc(dev, 
> > > switch_desc->num_typec_switches,
> > > + sizeof(struct 
> > > drm_dp_typec_port_data),
> >
> > 
> > sizeof(*switch_desc_typec_ports),
> >
> > ?
> >
> > > + GFP_KERNEL);
> > > + if (!switch_desc->typec_ports)
> > > + return -ENOMEM;
> >
> > ...
> >
> > > +#ifdef CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER
> >
> > Ah, maybe this should use IS_REACHABLE() ?
>
> CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER is a boolean. Is there any
> difference between IS_REACHABLE and ifdef when the given config is a
> boolean?
> >
> > > +void drm_dp_unregister_typec_switches(struct drm_dp_typec_switch_desc 
> > > *switch_desc);
> > > +int drm_dp_register_typec_switches(struct device *dev, struct 
> > > fwnode_handle *port,
> > > +struct drm_dp_typec_switch_desc 
> > > *switch_desc,
> > > +void *data, typec_mux_set_fn_t mux_set);
> > > +#else
> > > +static inline void drm_dp_unregister_typec_switches(struct 
> > > drm_dp_typec_switch_desc *switch_desc)
> > > +{
> > > +}
> > > +static inline int drm_dp_register_typec_switches(
> > > + struct device *dev, struct fwnode_handle *port,
> > > + struct drm_dp_typec_switch_desc *switch_desc, void *data,
> > > + typec_mux_set_fn_t mux_set)
> > > +{
> > > + return -EOPNOTSUPP;
> > > +}
> > > +#endif
> >
> > --
> > With Best Regards,
> > Andy Shevchenko
> >
>
> Best regards,
> Pin-yen
> >


[PATCH] drm/bridge: ps8640: Use constant sleep time for polling hpd

2023-03-30 Thread Pin-yen Lin
The default hpd_wait_us in panel_edp.c is 2 seconds. This makes the
sleep time in the polling of _ps8640_wait_hpd_asserted become 200ms.
Change it to a constant 20ms to speed up the function.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/parade-ps8640.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index b823e55650b1..c3eb45179405 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -184,7 +184,7 @@ static int _ps8640_wait_hpd_asserted(struct ps8640 
*ps_bridge, unsigned long wai
 * actually connected to GPIO9).
 */
ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status,
-  status & PS_GPIO9, wait_us / 10, 
wait_us);
+  status & PS_GPIO9, 2, wait_us);
 
/*
 * The first time we see HPD go high after a reset we delay an extra
-- 
2.40.0.348.gf938b09366-goog



Re: [PATCH v14 03/10] drm/display: Add Type-C switch helpers

2023-03-30 Thread Pin-yen Lin
Hi Dmitry,

Thanks for the review.

On Thu, Mar 23, 2023 at 7:39 AM Dmitry Baryshkov
 wrote:
>
> On Wed, 22 Mar 2023 at 12:47, Pin-yen Lin  wrote:
> >
> > Add helpers to register and unregister Type-C "switches" for bridges
> > capable of switching their output between two downstream devices.
> >
> > The helper registers USB Type-C mode switches when the "mode-switch"
> > and the "reg" properties are available in Device Tree.
> >
> > Signed-off-by: Pin-yen Lin 
> >
> > ---
> >
> > Changes in v14:
> > - Introduce a new Kconfig becuase it didn't build when CONFIG_TYPEC=m
> > - Add comments about devm_* usage
> > - Fix style issues
> >
> > Changes in v13:
> > - Add typec_mode_switch_node_count helper
> > - Fix style issues
> >
> > Changes in v12:
> > - Add fwnode_for_each_typec_mode_switch macro
> > - Remove a duplicated dmesg in the helper
> > - Used IS_REACHABLE instead to guard the function signatures
> >
> > Changes in v11:
> > - Use fwnode helpers instead of DT
> > - Moved the helpers to a new file
> > - Use "reg" instead of "data-lanes" to determine the port number
> > - Dropped collected tags due to new changes
> >
> > Changes in v10:
> > - Collected Reviewed-by and Tested-by tags
> > - Replaced "void *" with "typec_mux_set_fn_t" for mux_set callbacks
> > - Print out the node name when errors on parsing DT
> > - Use dev_dbg instead of dev_warn when no Type-C switch nodes available
> > - Made the return path of drm_dp_register_mode_switch clearer
> >
> > Changes in v8:
> > - Fixed the build issue when CONFIG_TYPEC=m
> > - Fixed some style issues
> >
> > Changes in v7:
> > - Extracted the common codes to a helper function
> > - New in v7
> >
> >  drivers/gpu/drm/display/Kconfig   |   8 ++
> >  drivers/gpu/drm/display/Makefile  |   2 +
> >  drivers/gpu/drm/display/drm_dp_typec_helper.c | 105 ++
> >  include/drm/display/drm_dp_helper.h   |  46 
> >  4 files changed, 161 insertions(+)
> >  create mode 100644 drivers/gpu/drm/display/drm_dp_typec_helper.c
> >
> > diff --git a/drivers/gpu/drm/display/Kconfig 
> > b/drivers/gpu/drm/display/Kconfig
> > index 09712b88a5b8..d61076947a1c 100644
> > --- a/drivers/gpu/drm/display/Kconfig
> > +++ b/drivers/gpu/drm/display/Kconfig
> > @@ -29,6 +29,14 @@ config DRM_DISPLAY_HDMI_HELPER
> > help
> >   DRM display helpers for HDMI.
> >
> > +config DRM_DISPLAY_DP_TYPEC_HELPER
> > +   bool
> > +   default y
> > +   depends on DRM_DISPLAY_HELPER
> > +   depends on DRM_DISPLAY_HELPER=TYPEC || TYPEC=y
>
> If it is a select'able option, it doesn't make sense to use "depends"
> here. Select will override depends.
>
I'm not very familiar with the practices of Kconfigs, but I'll keep
this in the next version per Andy's comment.

> > +   help
> > + DRM display helpers for USB Type-C Displayport Alternate mode.
> > +
> >  config DRM_DP_AUX_CHARDEV
> > bool "DRM DP AUX Interface"
> > depends on DRM && DRM_DISPLAY_HELPER
> > diff --git a/drivers/gpu/drm/display/Makefile 
> > b/drivers/gpu/drm/display/Makefile
> > index 17ac4a1006a8..2202a6aea38e 100644
> > --- a/drivers/gpu/drm/display/Makefile
> > +++ b/drivers/gpu/drm/display/Makefile
> > @@ -8,6 +8,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \
> > drm_dp_helper.o \
> > drm_dp_mst_topology.o \
> > drm_dsc_helper.o
> > +drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER) += \
> > +   drm_dp_typec_helper.o
> >  drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
> >  drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
> > drm_hdmi_helper.o \
> > diff --git a/drivers/gpu/drm/display/drm_dp_typec_helper.c 
> > b/drivers/gpu/drm/display/drm_dp_typec_helper.c
> > new file mode 100644
> > index ..1562a9ccdaf2
> > --- /dev/null
> > +++ b/drivers/gpu/drm/display/drm_dp_typec_helper.c
> > @@ -0,0 +1,105 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +#include 
> > +#include 
> > +
> > +static int drm_dp_register_mode_switch(struct device *dev,
> > +  struct fwnode_handle *fwnode,
> > +  

Re: [PATCH v14 03/10] drm/display: Add Type-C switch helpers

2023-03-30 Thread Pin-yen Lin
Hi Andy,

Thanks for the review.

On Wed, Mar 22, 2023 at 8:01 PM Andy Shevchenko
 wrote:
>
> On Wed, Mar 22, 2023 at 06:46:32PM +0800, Pin-yen Lin wrote:
> > Add helpers to register and unregister Type-C "switches" for bridges
> > capable of switching their output between two downstream devices.
> >
> > The helper registers USB Type-C mode switches when the "mode-switch"
> > and the "reg" properties are available in Device Tree.
>
> ...
>
> > +config DRM_DISPLAY_DP_TYPEC_HELPER
>
> > + bool
> > + default y
>
> def_bool y
>
> > + depends on DRM_DISPLAY_HELPER
> > + depends on DRM_DISPLAY_HELPER=TYPEC || TYPEC=y
> > + help
> > +   DRM display helpers for USB Type-C Displayport Alternate mode.
>
> Hmm... Dunno if this help is enough.

Okay I'll add more detail in the next version.
>
> ...
>
> > + snprintf(name, sizeof(name), "%pfwP-%u", fwnode, port_num);
>
> Would it be possible to have a dup in name and would it be a problem if so?
>
The port_num is included in the name, so the names should be unique.
Also, the fwnode name actually contains the reg property, so this name
looks like "endpoint@0-1" now... I'll change the name from fwnode name
to dev_name() per Dmitry's comment.
> ...
>
> > +/**
> > + * drm_dp_register_typec_switches() - register Type-C switches
> > + * @dev: Device that registers Type-C switches
> > + * @port: Device node for the switch
> > + * @switch_desc: A Type-C switch descriptor
> > + * @data: Private data for the switches
> > + * @mux_set: Callback function for typec_mux_set
> > + *
> > + * This function registers USB Type-C switches for DP bridges that can 
> > switch
> > + * the output signal between their output pins. This function uses 
> > devm_kcalloc
> > + * to allocate memory, so it is expected to only call this in the driver 
> > probe
> > + * functions.
> > + *
> > + * Currently only mode switches are implemented, and the function assumes 
> > the
> > + * given @port device node has endpoints with "mode-switch" property.
> > + * The port number is determined by the "reg" property of the endpoint.
>
> `kernel-doc -v ...` should complain on absence of "Return" section.
>
> > + */
>
> ...
>
> > + switch_desc->typec_ports = devm_kcalloc(dev, 
> > switch_desc->num_typec_switches,
> > + sizeof(struct 
> > drm_dp_typec_port_data),
>
> 
> sizeof(*switch_desc_typec_ports),
>
> ?
>
> > + GFP_KERNEL);
> > + if (!switch_desc->typec_ports)
> > + return -ENOMEM;
>
> ...
>
> > +#ifdef CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER
>
> Ah, maybe this should use IS_REACHABLE() ?

CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER is a boolean. Is there any
difference between IS_REACHABLE and ifdef when the given config is a
boolean?
>
> > +void drm_dp_unregister_typec_switches(struct drm_dp_typec_switch_desc 
> > *switch_desc);
> > +int drm_dp_register_typec_switches(struct device *dev, struct 
> > fwnode_handle *port,
> > +struct drm_dp_typec_switch_desc 
> > *switch_desc,
> > +void *data, typec_mux_set_fn_t mux_set);
> > +#else
> > +static inline void drm_dp_unregister_typec_switches(struct 
> > drm_dp_typec_switch_desc *switch_desc)
> > +{
> > +}
> > +static inline int drm_dp_register_typec_switches(
> > + struct device *dev, struct fwnode_handle *port,
> > + struct drm_dp_typec_switch_desc *switch_desc, void *data,
> > + typec_mux_set_fn_t mux_set)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +#endif
>
> --
> With Best Regards,
> Andy Shevchenko
>

Best regards,
Pin-yen
>


[PATCH] drm/bridge: ps8640: Return NULL immediately when EDID read fail

2023-03-23 Thread Pin-yen Lin
drm_edid_read returns NULL on error, so feeding it directly into
drm_edid_duplicate may lead to NULL pointer dereference. Add a check to
guard this.

Fixes: 6a17b4d1b52f ("drm/bridge: ps8640: Add a cache for EDID")
Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/parade-ps8640.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index cddbfe91f75e..b823e55650b1 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -543,6 +543,7 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
   struct drm_connector *connector)
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
+   struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev;
bool poweroff = !ps_bridge->pre_enabled;
 
if (!ps_bridge->edid) {
@@ -574,6 +575,11 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 
connector->state->state);
}
 
+   if (!ps_bridge->edid) {
+   dev_err(dev, "Failed to get EDID\n");
+   return NULL;
+   }
+
return drm_edid_duplicate(ps_bridge->edid);
 }
 
-- 
2.40.0.348.gf938b09366-goog



[PATCH v14 10/10] drm/bridge: it6505: Register Type C mode switches

2023-03-22 Thread Pin-yen Lin
Register USB Type-C mode switches when the "mode-switch" property and
relevant port are available in Device Tree. Configure the "lane_swap"
state based on the entered alternate mode for a specific Type-C
connector, which ends up updating the lane swap registers of the it6505
chip.

Signed-off-by: Pin-yen Lin 

---

Changes in v14:
- Fix style issues

Changes in v13:
- Fix style issues

Changes in v12:
- Fixes style issues in it6505 driver
- Replaced &it6505->client->dev with it6505->dev
- Updated the error logs when parsing data-lanes property

Changes in v11:
- Added back "data-lanes" parsing logics
- Removed Kconfig dependency
- Updated the usage of the private data

Changes in v7:
- Fixed style issues in it6505 driver
- Removed the redundant sleep in it6505 driver
- Removed DT property validation in it6505 driver
- Rebased to drm-misc-next
- Extracted common codes to another commit

Changes in v6:
- Changed it6505_typec_mux_set callback function to accommodate with
  the latest drm-misc patches
- Changed the driver implementation to accommodate with the new binding
- Squashed to a single patch

 drivers/gpu/drm/bridge/ite-it6505.c | 190 +++-
 1 file changed, 183 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index d4bc388b68ac..28d07fd7486b 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -17,6 +17,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
@@ -27,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -401,6 +404,11 @@ struct debugfs_entries {
const struct file_operations *fops;
 };
 
+struct it6505_typec_port_data {
+   bool dp_connected;
+   bool lane_swap;
+};
+
 struct it6505 {
struct drm_dp_aux aux;
struct drm_bridge bridge;
@@ -454,6 +462,9 @@ struct it6505 {
struct delayed_work delayed_audio;
struct it6505_audio_data audio;
struct dentry *debugfs;
+   struct completion mux_register;
+   struct drm_dp_typec_switch_desc switch_desc;
+   struct it6505_typec_port_data *port_data;
 
/* it6505 driver hold option */
bool enable_drv_hold;
@@ -3345,12 +3356,162 @@ static void it6505_shutdown(struct i2c_client *client)
it6505_lane_off(it6505);
 }
 
+static void it6505_typec_ports_update(struct it6505 *it6505)
+{
+   unsigned int i;
+
+   /* Check if both ports available and do nothing to retain the current 
one */
+   if (it6505->port_data[0].dp_connected && 
it6505->port_data[1].dp_connected)
+   return;
+
+   for (i = 0; i < 2; i++) {
+   if (it6505->port_data[i].dp_connected)
+   it6505->lane_swap = it6505->port_data[i].lane_swap;
+   }
+}
+
+static int it6505_typec_mux_set(struct typec_mux_dev *mux,
+   struct typec_mux_state *state)
+{
+   struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
+   struct it6505 *it6505 = port->data;
+   struct device *dev = it6505->dev;
+   struct drm_dp_typec_switch_desc switch_desc = it6505->switch_desc;
+   bool old_dp_connected, new_dp_connected;
+
+   if (switch_desc.num_typec_switches == 1)
+   return 0;
+
+   mutex_lock(&it6505->extcon_lock);
+   wait_for_completion(&it6505->mux_register);
+
+   old_dp_connected = it6505->port_data[0].dp_connected ||
+  it6505->port_data[1].dp_connected;
+
+   it6505->port_data[port->port_num].dp_connected =
+   state->alt &&
+   state->alt->svid == USB_TYPEC_DP_SID &&
+   state->alt->mode == USB_TYPEC_DP_MODE;
+
+   dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
+   it6505->port_data[0].dp_connected, 
it6505->port_data[1].dp_connected);
+
+   new_dp_connected = it6505->port_data[0].dp_connected ||
+  it6505->port_data[1].dp_connected;
+
+   if (it6505->enable_drv_hold) {
+   dev_dbg(dev, "enable driver hold\n");
+   goto unlock;
+   }
+
+   it6505_typec_ports_update(it6505);
+
+   if (!old_dp_connected && new_dp_connected) {
+   int ret = pm_runtime_get_sync(dev);
+
+   /*
+* pm_runtime_force_suspend() disables runtime PM when the
+* system enters suspend state. But on system resume, mux_set
+* can be triggered before pm_runtime_force_resume() re-enables
+* runtime PM. This makes the bridge stay powered off if the
+* downstream display is connected when the system is suspended.
+* Handling the e

[PATCH v14 09/10] drm/bridge: it6505: Fix Kconfig indentation

2023-03-22 Thread Pin-yen Lin
Replace the spaces with tab characters in the Kconfig file.

Signed-off-by: Pin-yen Lin 
Reviewed-by: AngeloGioacchino Del Regno 


---

(no changes since v10)

Changes in v10:
- Collected Reviewed-by tag

Changes in v7:
- New in v7

 drivers/gpu/drm/bridge/Kconfig | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 12e8f30c65f7..28dc7711bf5f 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -74,19 +74,19 @@ config DRM_FSL_LDB
  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
 
 config DRM_ITE_IT6505
-tristate "ITE IT6505 DisplayPort bridge"
-depends on OF
+   tristate "ITE IT6505 DisplayPort bridge"
+   depends on OF
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDCP_HELPER
select DRM_DISPLAY_HELPER
-select DRM_DP_AUX_BUS
-select DRM_KMS_HELPER
-select DRM_DP_HELPER
-select EXTCON
-select CRYPTO
-select CRYPTO_HASH
-help
-  ITE IT6505 DisplayPort bridge chip driver.
+   select DRM_DP_AUX_BUS
+   select DRM_KMS_HELPER
+   select DRM_DP_HELPER
+   select EXTCON
+   select CRYPTO
+   select CRYPTO_HASH
+   help
+ ITE IT6505 DisplayPort bridge chip driver.
 
 config DRM_LONTIUM_LT8912B
tristate "Lontium LT8912B DSI/HDMI bridge"
-- 
2.40.0.rc1.284.g88254d51c5-goog



[PATCH v14 07/10] drm/bridge: anx7625: Register Type C mode switches

2023-03-22 Thread Pin-yen Lin
Register USB Type-C mode switches when the "mode-switch" property and
relevant ports are available in Device Tree. Configure the crosspoint
switch based on the entered alternate mode for a specific Type-C
connector.

Crosspoint switch can also be used for switching the output signal for
different orientations of a single USB Type-C connector, but the
orientation switch is not implemented yet. A TODO is added for this.

Signed-off-by: Pin-yen Lin 

---

Changes in v14:
- Fix style issues

Changes in v12:
- Fixed style issues in anx7625 driver
- Fixed the inverted orientation setting in anx7625 driver
- Changed "&ctx->client->dev" to "ctx->dev"
- Fix style issues
- Updated the error logs when parsing data-lanes property

Changes in v11:
- Added back "data-lanes" parsing logics
- Removed Kconfig dependency
- Updated the usage of the private data
- Dropped Tested-by tag because of the new changes

Changes in v10:
- Added a TODO for implementing orientation switch for anx7625
- Updated the commit message for the absence of orientation switch
- Fixed typo in the commit message
- Collected Tested-by tag

Changes in v7:
- Fixed style issues in anx7625 driver
- Removed DT property validation in anx7625 driver.
- Extracted common codes to another commit.

Changes in v6:
- Squashed to a single patch

 drivers/gpu/drm/bridge/analogix/anx7625.c | 148 ++
 drivers/gpu/drm/bridge/analogix/anx7625.h |  20 +++
 2 files changed, 168 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 76d46db3f8dc..9b259c07743f 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -15,6 +15,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
@@ -2570,6 +2572,145 @@ static void anx7625_runtime_disable(void *data)
pm_runtime_disable(data);
 }
 
+static void anx7625_set_crosspoint_switch(struct anx7625_data *ctx,
+ enum typec_orientation orientation)
+{
+   if (orientation == TYPEC_ORIENTATION_NORMAL) {
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_0,
+ SW_SEL1_SSRX_RX1 | SW_SEL1_DPTX0_RX2);
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_1,
+ SW_SEL2_SSTX_TX1 | SW_SEL2_DPTX1_TX2);
+   } else if (orientation == TYPEC_ORIENTATION_REVERSE) {
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_0,
+ SW_SEL1_SSRX_RX2 | SW_SEL1_DPTX0_RX1);
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_1,
+ SW_SEL2_SSTX_TX2 | SW_SEL2_DPTX1_TX1);
+   }
+}
+
+static void anx7625_typec_two_ports_update(struct anx7625_data *ctx)
+{
+   unsigned int i;
+
+   /* Check if both ports available and do nothing to retain the current 
one */
+   if (ctx->port_data[0].dp_connected && ctx->port_data[1].dp_connected)
+   return;
+
+   for (i = 0; i < 2; i++) {
+   if (ctx->port_data[i].dp_connected)
+   anx7625_set_crosspoint_switch(ctx,
+ 
ctx->port_data[i].orientation);
+   }
+}
+
+static int anx7625_typec_mux_set(struct typec_mux_dev *mux,
+struct typec_mux_state *state)
+{
+   struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
+   struct anx7625_data *ctx = port->data;
+   struct device *dev = ctx->dev;
+   struct drm_dp_typec_switch_desc switch_desc = ctx->switch_desc;
+   bool new_dp_connected, old_dp_connected;
+
+   if (switch_desc.num_typec_switches == 1)
+   return 0;
+
+   wait_for_completion(&ctx->mux_register);
+
+   old_dp_connected = ctx->port_data[0].dp_connected ||
+  ctx->port_data[1].dp_connected;
+
+   ctx->port_data[port->port_num].dp_connected =
+   state->alt &&
+   state->alt->svid == USB_TYPEC_DP_SID &&
+   state->alt->mode == USB_TYPEC_DP_MODE;
+
+   dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
+   ctx->port_data[0].dp_connected, ctx->port_data[1].dp_connected);
+
+   new_dp_connected = ctx->port_data[0].dp_connected ||
+  ctx->port_data[1].dp_connected;
+
+   /* DP on, power on first */
+   if (!old_dp_connected && new_dp_connected)
+   pm_runtime_get_sync(dev);
+
+   anx7625_typec_two_ports_update(ctx);
+
+   /* DP off, power off last */
+   if (old_dp_connected && !new_dp_connected)
+   pm_runtime_put_sync(dev);
+
+   return 0;
+}
+
+static void anx762

[PATCH v14 08/10] dt-bindings: display: bridge: it6505: Add mode-switch support

2023-03-22 Thread Pin-yen Lin
ITE IT6505 can be used in systems to switch the DP traffic between
two downstreams, which can be USB Type-C DisplayPort alternate mode
lane or regular DisplayPort output ports.

Update the binding to accommodate this usage by introducing a
data-lanes and a mode-switch property on endpoints.

Signed-off-by: Pin-yen Lin 

---

(no changes since v12)

Changes in v12:
- Fixed the schema of "data-lanes" property for it6505
- Reworded the description of the mode-switch property

Changes in v11:
- Updated the description of the endpoints in the bindings
- Referenced video-interfaces.yaml instead for the endpoints binding
- Removed duplicated definitions from inherited schema

Changes in v9:
- Fixed subject prefix again
- Changed the naming of the example node for it6505

Changes in v8:
- Updated bindings for data-lanes property
- Fixed subject prefix

Changes in v7:
- Fixed issues reported by dt_binding_check.
- Updated the schema and the example dts for data-lanes.
- Changed to generic naming for the example dts node.

Changes in v6:
- Remove switches node and use endpoints and data-lanes property to
  describe the connections.

 .../bindings/display/bridge/ite,it6505.yaml   | 101 +++---
 1 file changed, 88 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml 
b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
index c9a882ee6d98..348b02f26041 100644
--- a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
@@ -75,22 +75,49 @@ properties:
   port@1:
 $ref: /schemas/graph.yaml#/$defs/port-base
 unevaluatedProperties: false
-description: Video port for DP output
+description:
+  Video port for DP output. Each endpoint connects to a video output
+  downstream, and the "data-lanes" property is used to describe the pin
+  connections. 0, 1, 2, 3 in "data-lanes" maps to TX0, TX1, TX2, TX3,
+  respectively.
 
-properties:
-  endpoint:
-$ref: /schemas/graph.yaml#/$defs/endpoint-base
+
+patternProperties:
+  "^endpoint@[01]$":
+$ref: /schemas/media/video-interfaces.yaml#
 unevaluatedProperties: false
 
 properties:
+  reg: true
+
+  remote-endpoint: true
+
   data-lanes:
-minItems: 1
-uniqueItems: true
-items:
-  - enum: [ 0, 1 ]
-  - const: 1
-  - const: 2
-  - const: 3
+oneOf:
+  - items:
+  - enum: [0, 3]
+
+  - items:
+  - const: 0
+  - const: 1
+
+  - items:
+  - const: 3
+  - const: 2
+
+  - items:
+  - const: 0
+  - const: 1
+  - const: 2
+  - const: 3
+
+  mode-switch:
+type: boolean
+description: Serves as Type-C mode switch if present.
+
+required:
+  - reg
+  - remote-endpoint
 
 required:
   - port@0
@@ -102,7 +129,6 @@ required:
   - pwr18-supply
   - interrupts
   - reset-gpios
-  - extcon
   - ports
 
 additionalProperties: false
@@ -139,8 +165,11 @@ examples:
 };
 
 port@1 {
+#address-cells = <1>;
+#size-cells = <0>;
 reg = <1>;
-it6505_out: endpoint {
+it6505_out: endpoint@0 {
+reg = <0>;
 remote-endpoint = <&dp_in>;
 data-lanes = <0 1>;
 };
@@ -148,3 +177,49 @@ examples:
 };
 };
 };
+  - |
+#include 
+
+i2c {
+#address-cells = <1>;
+#size-cells = <0>;
+
+dp-bridge@5c {
+compatible = "ite,it6505";
+interrupts = <8 IRQ_TYPE_LEVEL_LOW 8 0>;
+reg = <0x5c>;
+pinctrl-names = "default";
+pinctrl-0 = <&it6505_pins>;
+ovdd-supply = <&mt6366_vsim2_reg>;
+pwr18-supply = <&pp1800_dpbrdg_dx>;
+reset-gpios = <&pio 177 0>;
+
+ports {
+#address-cells = <1>;
+#size-cells = <0>;
+port@0 {
+reg = <0>;
+it6505_dpi_in: endpoint {
+remote-endpoint = <&dpi_out>;
+};
+};
+port@1 {
+ 

[PATCH v14 06/10] drm/bridge: Remove redundant i2c_client in anx7625/it6505

2023-03-22 Thread Pin-yen Lin
These two drivers embed a i2c_client in their private driver data, but
only strict device is actually needed. Replace the i2c_client reference
with a struct device one.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 
---

(no changes since v13)

Changes in v13:
- Update a typo in the commit message
- Collect Reviewed-by tag

Changes in v12:
- New in v12

 drivers/gpu/drm/bridge/analogix/anx7625.c |  96 
 drivers/gpu/drm/bridge/analogix/anx7625.h |   2 +-
 drivers/gpu/drm/bridge/ite-it6505.c   | 128 +++---
 3 files changed, 113 insertions(+), 113 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 3f6bf7674d32..76d46db3f8dc 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -207,7 +207,7 @@ static int anx7625_read_ctrl_status_p0(struct anx7625_data 
*ctx)
 
 static int wait_aux_op_finish(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int val;
int ret;
 
@@ -234,7 +234,7 @@ static int wait_aux_op_finish(struct anx7625_data *ctx)
 static int anx7625_aux_trans(struct anx7625_data *ctx, u8 op, u32 address,
 u8 len, u8 *buf)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
u8 addrh, addrm, addrl;
u8 cmd;
@@ -427,7 +427,7 @@ static int anx7625_odfc_config(struct anx7625_data *ctx,
   u8 post_divider)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Config input reference clock frequency 27MHz/19.2MHz */
ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, MIPI_DIGITAL_PLL_16,
@@ -477,7 +477,7 @@ static int anx7625_set_k_value(struct anx7625_data *ctx)
 
 static int anx7625_dsi_video_timing_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
unsigned long m, n;
u16 htotal;
int ret;
@@ -575,7 +575,7 @@ static int anx7625_dsi_video_timing_config(struct 
anx7625_data *ctx)
 static int anx7625_swap_dsi_lane3(struct anx7625_data *ctx)
 {
int val;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Swap MIPI-DSI data lane 3 P and N */
val = anx7625_reg_read(ctx, ctx->i2c.rx_p1_client, MIPI_SWAP);
@@ -592,7 +592,7 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx)
 
 {
int val, ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Swap MIPI-DSI data lane 3 P and N */
ret = anx7625_swap_dsi_lane3(ctx);
@@ -657,7 +657,7 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx)
 
 static int anx7625_dsi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
 
DRM_DEV_DEBUG_DRIVER(dev, "config dsi.\n");
@@ -689,7 +689,7 @@ static int anx7625_dsi_config(struct anx7625_data *ctx)
 
 static int anx7625_api_dpi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
u16 freq = ctx->dt.pixelclock.min / 1000;
int ret;
 
@@ -720,7 +720,7 @@ static int anx7625_api_dpi_config(struct anx7625_data *ctx)
 
 static int anx7625_dpi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
 
DRM_DEV_DEBUG_DRIVER(dev, "config dpi\n");
@@ -765,7 +765,7 @@ static int anx7625_read_flash_status(struct anx7625_data 
*ctx)
 static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
 {
int ret, val;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
u8 ident[FLASH_BUF_LEN];
 
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -815,7 +815,7 @@ static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
 static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Select HDCP 1.4 KEY */
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -843,7 +843,7 @@ static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
 static int anx7625_hdcp_disable(struct anx7625_data *ctx)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
dev_dbg(dev, "disable HDCP 1.4\n");
 
@@ -864,7 +864,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx)
 {

[PATCH v14 05/10] drm/bridge: anx7625: Check for Type-C during panel registration

2023-03-22 Thread Pin-yen Lin
The output port endpoints can be connected to USB-C connectors.
Running drm_of_find_panel_or_bridge() with such endpoints leads to
a continuous return value of -EPROBE_DEFER, even though there is
no panel present.

To avoid this, check for the existence of a "mode-switch" property in
the port endpoint, and skip panel registration completely if so.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 

---

Changes in v14:
- Collect review tag

Changes in v13:
- Use the new typec_mode_switch_node_count helper

Changes in v12:
- Updated to use fwnode_for_each_typec_mode_switch macro
- Dropped collected tags

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v6:
- New in v6

 drivers/gpu/drm/bridge/analogix/anx7625.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 6846199a2ee1..3f6bf7674d32 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -1648,7 +1648,8 @@ static int anx7625_get_swing_setting(struct device *dev,
 static int anx7625_parse_dt(struct device *dev,
struct anx7625_platform_data *pdata)
 {
-   struct device_node *np = dev->of_node, *ep0;
+   struct device_node *np = dev->of_node, *ep0, *port_node;
+   unsigned int count;
int bus_type, mipi_lanes;
 
anx7625_get_swing_setting(dev, pdata);
@@ -1687,6 +1688,15 @@ static int anx7625_parse_dt(struct device *dev,
if (of_property_read_bool(np, "analogix,audio-enable"))
pdata->audio_en = 1;
 
+   /*
+* Don't bother finding a panel if a Type-C `mode-switch` property is
+* present in one of the endpoints in the output port.
+*/
+   port_node = of_graph_get_port_by_id(np, 1);
+   count = typec_mode_switch_node_count(&port_node->fwnode);
+   if (count)
+   return 0;
+
pdata->panel_bridge = devm_drm_of_get_bridge(dev, np, 1, 0);
if (IS_ERR(pdata->panel_bridge)) {
if (PTR_ERR(pdata->panel_bridge) == -ENODEV) {
-- 
2.40.0.rc1.284.g88254d51c5-goog



[PATCH v14 04/10] dt-bindings: display: bridge: anx7625: Add mode-switch support

2023-03-22 Thread Pin-yen Lin
Analogix 7625 can be used in systems to switch the DP traffic between
two downstreams, which can be USB Type-C DisplayPort alternate mode
lane or regular DisplayPort output ports.

Update the binding to accommodate this usage by introducing a
data-lanes and a mode-switch property on endpoints.

Also include the link to the product brief in the bindings.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Krzysztof Kozlowski 
Reviewed-by: Chen-Yu Tsai 
Tested-by: Chen-Yu Tsai 
Reviewed-by: AngeloGioacchino Del Regno 


---

(no changes since v12)

Changes in v12:
- Removed the 4-lane binding in analogix,anx7625.yaml
- Reworded the description for the mode-switch property

Changes in v11:
- Updated the description of the endpoints
- Referenced video-interfaces.yaml instead for the endpoints

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v9:
- Collected Reviewed-by tag

Changes in v8:
- Updated anx7625 bindings for data-lane property
- Fixed the subject prefix

Changes in v7:
- Fixed issues reported by dt_binding_check
- Updated the schema and the example dts for data-lanes.
- Changed to generic naming for the example dts node.

Changes in v6:
- Remove switches node and use endpoints and data-lanes property to
  describe the connections.

 .../display/bridge/analogix,anx7625.yaml  | 88 ++-
 1 file changed, 85 insertions(+), 3 deletions(-)

diff --git 
a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml 
b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
index 4590186c4a0b..a50de536cffd 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
@@ -12,7 +12,8 @@ maintainers:
 
 description: |
   The ANX7625 is an ultra-low power 4K Mobile HD Transmitter
-  designed for portable devices.
+  designed for portable devices. Product brief is available at
+  
https://www.analogix.com/en/system/files/AA-002291-PB-6-ANX7625_ProductBrief.pdf
 
 properties:
   compatible:
@@ -112,9 +113,40 @@ properties:
   data-lanes: true
 
   port@1:
-$ref: /schemas/graph.yaml#/properties/port
+$ref: /schemas/graph.yaml#/$defs/port-base
 description:
-  Video port for panel or connector.
+  Video port for panel or connector. Each endpoint connects to a video
+  output downstream, and the "data-lanes" property is used to describe
+  the pin connections. 0, 1, 2, 3 in "data-lanes" maps to SSRX1, SSTX1,
+  SSRX2, SSTX2, respectively.
+
+patternProperties:
+  "^endpoint@[01]$":
+$ref: /schemas/media/video-interfaces.yaml#
+properties:
+  reg: true
+
+  remote-endpoint: true
+
+  data-lanes:
+oneOf:
+  - items:
+  - enum: [0, 1, 2, 3]
+
+  - items:
+  - const: 0
+  - const: 1
+
+  - items:
+  - const: 2
+  - const: 3
+
+  mode-switch:
+type: boolean
+description: Serves as Type-C mode switch if present.
+
+required:
+  - remote-endpoint
 
 required:
   - port@0
@@ -186,3 +218,53 @@ examples:
 };
 };
 };
+  - |
+i2c3 {
+#address-cells = <1>;
+#size-cells = <0>;
+
+encoder@58 {
+compatible = "analogix,anx7625";
+reg = <0x58>;
+pinctrl-names = "default";
+pinctrl-0 = <&anx7625_dp_pins>;
+enable-gpios = <&pio 176 GPIO_ACTIVE_HIGH>;
+reset-gpios = <&pio 177 GPIO_ACTIVE_HIGH>;
+vdd10-supply = <&pp1100_dpbrdg>;
+vdd18-supply = <&pp1800_dpbrdg_dx>;
+vdd33-supply = <&pp3300_dpbrdg_dx>;
+analogix,audio-enable;
+
+ports {
+#address-cells = <1>;
+#size-cells = <0>;
+
+port@0 {
+reg = <0>;
+anx7625_dp_in: endpoint {
+bus-type = <7>;
+remote-endpoint = <&dpi_out>;
+};
+};
+
+port@1 {
+#address-cells = <1>;
+#size-cells = <0>;
+
+reg = <1>;
+anx_typec0: endpoint@0 {
+reg = <0>;
+mode-switch;
+data-lanes = <0 1>;
+remote-endpoint = <&typec_port0>;
+};
+  

[PATCH v14 03/10] drm/display: Add Type-C switch helpers

2023-03-22 Thread Pin-yen Lin
Add helpers to register and unregister Type-C "switches" for bridges
capable of switching their output between two downstream devices.

The helper registers USB Type-C mode switches when the "mode-switch"
and the "reg" properties are available in Device Tree.

Signed-off-by: Pin-yen Lin 

---

Changes in v14:
- Introduce a new Kconfig becuase it didn't build when CONFIG_TYPEC=m
- Add comments about devm_* usage
- Fix style issues

Changes in v13:
- Add typec_mode_switch_node_count helper
- Fix style issues

Changes in v12:
- Add fwnode_for_each_typec_mode_switch macro
- Remove a duplicated dmesg in the helper
- Used IS_REACHABLE instead to guard the function signatures

Changes in v11:
- Use fwnode helpers instead of DT
- Moved the helpers to a new file
- Use "reg" instead of "data-lanes" to determine the port number
- Dropped collected tags due to new changes

Changes in v10:
- Collected Reviewed-by and Tested-by tags
- Replaced "void *" with "typec_mux_set_fn_t" for mux_set callbacks
- Print out the node name when errors on parsing DT
- Use dev_dbg instead of dev_warn when no Type-C switch nodes available
- Made the return path of drm_dp_register_mode_switch clearer

Changes in v8:
- Fixed the build issue when CONFIG_TYPEC=m
- Fixed some style issues

Changes in v7:
- Extracted the common codes to a helper function
- New in v7

 drivers/gpu/drm/display/Kconfig   |   8 ++
 drivers/gpu/drm/display/Makefile  |   2 +
 drivers/gpu/drm/display/drm_dp_typec_helper.c | 105 ++
 include/drm/display/drm_dp_helper.h   |  46 
 4 files changed, 161 insertions(+)
 create mode 100644 drivers/gpu/drm/display/drm_dp_typec_helper.c

diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig
index 09712b88a5b8..d61076947a1c 100644
--- a/drivers/gpu/drm/display/Kconfig
+++ b/drivers/gpu/drm/display/Kconfig
@@ -29,6 +29,14 @@ config DRM_DISPLAY_HDMI_HELPER
help
  DRM display helpers for HDMI.
 
+config DRM_DISPLAY_DP_TYPEC_HELPER
+   bool
+   default y
+   depends on DRM_DISPLAY_HELPER
+   depends on DRM_DISPLAY_HELPER=TYPEC || TYPEC=y
+   help
+ DRM display helpers for USB Type-C Displayport Alternate mode.
+
 config DRM_DP_AUX_CHARDEV
bool "DRM DP AUX Interface"
depends on DRM && DRM_DISPLAY_HELPER
diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile
index 17ac4a1006a8..2202a6aea38e 100644
--- a/drivers/gpu/drm/display/Makefile
+++ b/drivers/gpu/drm/display/Makefile
@@ -8,6 +8,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \
drm_dp_helper.o \
drm_dp_mst_topology.o \
drm_dsc_helper.o
+drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TYPEC_HELPER) += \
+   drm_dp_typec_helper.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o
 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \
drm_hdmi_helper.o \
diff --git a/drivers/gpu/drm/display/drm_dp_typec_helper.c 
b/drivers/gpu/drm/display/drm_dp_typec_helper.c
new file mode 100644
index ..1562a9ccdaf2
--- /dev/null
+++ b/drivers/gpu/drm/display/drm_dp_typec_helper.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include 
+#include 
+
+static int drm_dp_register_mode_switch(struct device *dev,
+  struct fwnode_handle *fwnode,
+  struct drm_dp_typec_switch_desc 
*switch_desc,
+  void *data, typec_mux_set_fn_t mux_set)
+{
+   struct drm_dp_typec_port_data *port_data;
+   struct typec_mux_desc mux_desc = {};
+   char name[32];
+   u32 port_num;
+   int ret;
+
+   ret = fwnode_property_read_u32(fwnode, "reg", &port_num);
+   if (ret) {
+   dev_err(dev, "Failed to read reg property: %d\n", ret);
+   return ret;
+   }
+
+   port_data = &switch_desc->typec_ports[port_num];
+   port_data->data = data;
+   port_data->port_num = port_num;
+   port_data->fwnode = fwnode;
+   mux_desc.fwnode = fwnode;
+   mux_desc.drvdata = port_data;
+   snprintf(name, sizeof(name), "%pfwP-%u", fwnode, port_num);
+   mux_desc.name = name;
+   mux_desc.set = mux_set;
+
+   port_data->typec_mux = typec_mux_register(dev, &mux_desc);
+   ret = PTR_ERR_OR_ZERO(port_data->typec_mux);
+   if (ret)
+   dev_err(dev, "Mode switch register for port %d failed: %d\n",
+   port_num, ret);
+
+   return ret;
+}
+
+/**
+ * drm_dp_register_typec_switches() - register Type-C switches
+ * @dev: Device that registers Type-C switches
+ * @port: Device node for the switch
+ * @switch_desc: A Type-C switch descriptor
+ * @data: Private data for the switches
+ * @mux_set

[PATCH v14 02/10] platform/chrome: cros_ec_typec: Purge blocking switch devlinks

2023-03-22 Thread Pin-yen Lin
From: Prashant Malani 

When using OF graph, the fw_devlink code will create links between the
individual port driver (cros-ec-typec here) and the parent device for
a Type-C switch (like mode-switch). Since the mode-switch will in turn
have the usb-c-connector (i.e the child of the port driver) as a
supplier, fw_devlink will not be able to resolve the cyclic dependency
correctly.

As a result, the mode-switch driver probe() never runs, so mode-switches
are never registered. Because of that, the port driver probe constantly
fails with -EPROBE_DEFER, because the Type-C connector class requires all
switch devices to be registered prior to port registration.

To break this deadlock and allow the mode-switch registration to occur,
purge all the usb-c-connector nodes' absent suppliers. This eliminates
the connector as a supplier for a switch and allows it to be probed.

Signed-off-by: Prashant Malani 
Signed-off-by: Pin-yen Lin 
Reviewed-by: Chen-Yu Tsai 
Tested-by: Chen-Yu Tsai 
Acked-by: Heikki Krogerus 

---

(no changes since v11)

Changes in v11:
- Collected Acked-by tag

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v7:
- Fix the long comment lines

Changes in v6:
- New in v6

 drivers/platform/chrome/cros_ec_typec.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/platform/chrome/cros_ec_typec.c 
b/drivers/platform/chrome/cros_ec_typec.c
index a673c3342470..5911cd9640cb 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -325,6 +325,16 @@ static int cros_typec_init_ports(struct cros_typec_data 
*typec)
return -EINVAL;
}
 
+   /*
+* OF graph may have set up some device links with switches,
+* since connectors have their own compatible. Purge these
+* to avoid a deadlock in switch probe (the switch mistakenly
+* assumes the connector is a supplier).
+*/
+   if (dev_of_node(dev))
+   device_for_each_child_node(dev, fwnode)
+   fw_devlink_purge_absent_suppliers(fwnode);
+
/* DT uses "reg" to specify port number. */
port_prop = dev->of_node ? "reg" : "port-number";
device_for_each_child_node(dev, fwnode) {
-- 
2.40.0.rc1.284.g88254d51c5-goog



[PATCH v14 01/10] device property: Add remote endpoint to devcon matcher

2023-03-22 Thread Pin-yen Lin
From: Prashant Malani 

When searching the device graph for device matches, check the
remote-endpoint itself for a match.

Some drivers register devices for individual endpoints. This allows
the matcher code to evaluate those for a match too, instead
of only looking at the remote parent devices. This is required when a
device supports two mode switches in its endpoints, so we can't simply
register the mode switch with the parent node.

Signed-off-by: Prashant Malani 
Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 
Reviewed-by: Sakari Ailus 
Reviewed-by: Heikki Krogerus 

---

Changes in v14:
- Collect review tags

Changes in v13:
- Update the kernel doc of fwnode_connection_find_match

Changes in v12:
- Check the availability of the device node in fwnode_graph_devcon_matches
- Ensured valid access to "matches" in fwnode_graph_devcon_matches
- Updated the documentation in fwnode_connection_find_match(es)
- Dropped collected tags due to the new changes

Changes in v11:
- Added missing fwnode_handle_put in drivers/base/property.c

Changes in v10:
- Collected Reviewed-by and Tested-by tags

Changes in v6:
- New in v6

 drivers/base/property.c | 31 ++-
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/base/property.c b/drivers/base/property.c
index 083a95791d3b..4426ac2b16ca 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1243,6 +1243,23 @@ static unsigned int fwnode_graph_devcon_matches(const 
struct fwnode_handle *fwno
continue;
}
 
+   ret = match(node, con_id, data);
+   fwnode_handle_put(node);
+   if (ret) {
+   if (matches)
+   matches[count] = ret;
+   count++;
+
+   if (matches && count >= matches_len)
+   break;
+   }
+
+   /*
+* Some drivers may register devices for endpoints. Check
+* the remote-endpoints for matches in addition to the remote
+* port parent.
+*/
+   node = fwnode_graph_get_remote_endpoint(ep);
ret = match(node, con_id, data);
fwnode_handle_put(node);
if (ret) {
@@ -1293,8 +1310,11 @@ static unsigned int fwnode_devcon_matches(const struct 
fwnode_handle *fwnode,
  * @match: Function to check and convert the connection description
  *
  * Find a connection with unique identifier @con_id between @fwnode and another
- * device node. @match will be used to convert the connection description to
- * data the caller is expecting to be returned.
+ * device node. For fwnode graph connections, the graph endpoints are also
+ * checked. @match will be used to convert the connection description to data
+ * the caller is expecting to be returned.
+ *
+ * Return: The pointer to the matched node, or NULL on error.
  */
 void *fwnode_connection_find_match(const struct fwnode_handle *fwnode,
   const char *con_id, void *data,
@@ -1325,9 +1345,10 @@ EXPORT_SYMBOL_GPL(fwnode_connection_find_match);
  * @matches_len: Length of @matches
  *
  * Find up to @matches_len connections with unique identifier @con_id between
- * @fwnode and other device nodes. @match will be used to convert the
- * connection description to data the caller is expecting to be returned
- * through the @matches array.
+ * @fwnode and other device nodes. For fwnode graph connections, the graph
+ * endpoints are also checked. @match will be used to convert the connection
+ * description to data the caller is expecting to be returned through the
+ * @matches array.
  * If @matches is NULL @matches_len is ignored and the total number of resolved
  * matches is returned.
  *
-- 
2.40.0.rc1.284.g88254d51c5-goog



[PATCH v14 00/10] Register Type-C mode-switch in DP bridge endpoints

2023-03-22 Thread Pin-yen Lin
- Added new patches (patch 1,2,4) to fix probing issues
- Changed the bindings of it6505/anx7625 and modified the drivers
  accordingly
- Merged it6505/anx7625 driver changes into a single patch

Pin-yen Lin (8):
  drm/display: Add Type-C switch helpers
  dt-bindings: display: bridge: anx7625: Add mode-switch support
  drm/bridge: anx7625: Check for Type-C during panel registration
  drm/bridge: Remove redundant i2c_client in anx7625/it6505
  drm/bridge: anx7625: Register Type C mode switches
  dt-bindings: display: bridge: it6505: Add mode-switch support
  drm/bridge: it6505: Fix Kconfig indentation
  drm/bridge: it6505: Register Type C mode switches

Prashant Malani (2):
  device property: Add remote endpoint to devcon matcher
  platform/chrome: cros_ec_typec: Purge blocking switch devlinks

 .../display/bridge/analogix,anx7625.yaml  |  88 -
 .../bindings/display/bridge/ite,it6505.yaml   | 101 +-
 drivers/base/property.c   |  31 +-
 drivers/gpu/drm/bridge/Kconfig|  20 +-
 drivers/gpu/drm/bridge/analogix/anx7625.c | 256 +++---
 drivers/gpu/drm/bridge/analogix/anx7625.h |  22 +-
 drivers/gpu/drm/bridge/ite-it6505.c   | 318 ++
 drivers/gpu/drm/display/Kconfig   |   8 +
 drivers/gpu/drm/display/Makefile  |   2 +
 drivers/gpu/drm/display/drm_dp_typec_helper.c | 105 ++
 drivers/platform/chrome/cros_ec_typec.c   |  10 +
 include/drm/display/drm_dp_helper.h   |  46 +++
 12 files changed, 855 insertions(+), 152 deletions(-)
 create mode 100644 drivers/gpu/drm/display/drm_dp_typec_helper.c

-- 
2.40.0.rc1.284.g88254d51c5-goog



Re: [PATCH 1/2] drm/bridge: ps8640: Skip redundant bridge enable

2023-03-16 Thread Pin-yen Lin
Hi,

On Thu, Mar 16, 2023 at 5:34 AM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Mar 14, 2023 at 8:28 PM Pin-yen Lin  wrote:
> >
> > Hi Doug,
> >
> > On Wed, Mar 15, 2023 at 5:31 AM Doug Anderson  wrote:
> > >
> > > Hi,
> > >
> > > On Tue, Mar 14, 2023 at 4:00 AM Pin-yen Lin  
> > > wrote:
> > > >
> > > > Skip the drm_bridge_chain_pre_enable call when the bridge is already
> > > > pre_enabled. This make pre_enable and post_disable (thus
> > > > pm_runtime_get/put) symmetric.
> > > >
> > > > Fixes: 46f206304db0 ("drm/bridge: ps8640: Rework power state handling")
> > > > Signed-off-by: Pin-yen Lin 
> > > > ---
> > > >
> > > >  drivers/gpu/drm/bridge/parade-ps8640.c | 3 ++-
> > > >  1 file changed, 2 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
> > > > b/drivers/gpu/drm/bridge/parade-ps8640.c
> > > > index 4b361d7d5e44..08de501c436e 100644
> > > > --- a/drivers/gpu/drm/bridge/parade-ps8640.c
> > > > +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> > > > @@ -557,7 +557,8 @@ static struct edid *ps8640_bridge_get_edid(struct 
> > > > drm_bridge *bridge,
> > > >  * EDID, for this chip, we need to do a full poweron, otherwise 
> > > > it will
> > > >  * fail.
> > > >  */
> > > > -   drm_atomic_bridge_chain_pre_enable(bridge, 
> > > > connector->state->state);
> > > > +   if (poweroff)
> > > > +   drm_atomic_bridge_chain_pre_enable(bridge, 
> > > > connector->state->state);
> > >
> > > It always seemed weird to me that this function was asymmetric, so I
> > > like this change, thanks!
> > >
> > > I also remember wondering before how this function was safe, though.
> > > The callpath for getting here from the ioctl is documented in the
> > > function and when I look at it I wonder if anything is preventing the
> > > bridge from being enabled / disabled through normal means at the same
> > > time your function is running. That could cause all sorts of badness
> > > if it is indeed possible. Does anyone reading this know if that's
> > > indeed a problem?
> >
> > If the "normal mean" is disabling the bridge, then we are probably
> > disabling the whole display pipeline. If so, is the EDID still
> > relevant in this case?
>
> In general when we do a "modeset" I believe that the display pipeline
> is disabled and re-enabled. On a Chromebook test image you can see
> this disable / re-enable happen when you switch between "VT2" and the
> main login screen.
>
> If the display pipeline is disabled / re-enabled then it should still
> be fine to keep the EDID cached, so that's not what I'm worried about.
> I'm more worried that someone could be querying the EDID at the same
> time that someone else was turning the screen off. In that case it
> would be possible for "poweroff" to be true (because the screen was on

You mean "poweroff" to be "false", right? That is,
"ps_bridge->pre_enabled" is true. So the .get_edid function assumes
that the pipeline is enabled, but another thread is turning off the
screen.

> when we started reading the EDID) and then partway through the screen
> could get turned off.

Thanks for the detailed explanation. In that case, we probably get an
error and return a NULL EDID. But do we need the EDID when the screen
is turned off? And the EDID should be re-read if the screen is turned
back on.

However, in a reversed setting, if the .get_edid is reading EDID when
the pipeline is disabled (poweroff=true), but someone enables the
pipeline in between. In that case, .get_edid might disable the bridge
and panel after the pipeline is enabled.

Anyway, the function is not safe, but it's no more unsafe than before.
Patch 2/2 should lower the chance for anything bad to happen by adding
a cache by only read EDID once.
>
> -Doug

Thanks and regards,
Pin-yen


[PATCH v2 2/2] drm/bridge: ps8640: Add a cache for EDID

2023-03-14 Thread Pin-yen Lin
When there are multiple EDID reads, the bridge will be repeatedly
enabled and disabled. Add a cache for EDID to speed this up.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Robert Foss 
Reviewed-by: Douglas Anderson 
---

Changes in v2:
- Remove the NULL assignment in ps8640_remove

 drivers/gpu/drm/bridge/parade-ps8640.c | 60 +++---
 1 file changed, 36 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index 08de501c436e..cddbfe91f75e 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -105,6 +105,7 @@ struct ps8640 {
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_powerdown;
struct device_link *link;
+   struct edid *edid;
bool pre_enabled;
bool need_post_hpd_delay;
 };
@@ -543,34 +544,37 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
bool poweroff = !ps_bridge->pre_enabled;
-   struct edid *edid;
 
-   /*
-* When we end calling get_edid() triggered by an ioctl, i.e
-*
-*   drm_mode_getconnector (ioctl)
-* -> drm_helper_probe_single_connector_modes
-*-> drm_bridge_connector_get_modes
-*   -> ps8640_bridge_get_edid
-*
-* We need to make sure that what we need is enabled before reading
-* EDID, for this chip, we need to do a full poweron, otherwise it will
-* fail.
-*/
-   if (poweroff)
-   drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
+   if (!ps_bridge->edid) {
+   /*
+* When we end calling get_edid() triggered by an ioctl, i.e
+*
+*   drm_mode_getconnector (ioctl)
+* -> drm_helper_probe_single_connector_modes
+*-> drm_bridge_connector_get_modes
+*   -> ps8640_bridge_get_edid
+*
+* We need to make sure that what we need is enabled before
+* reading EDID, for this chip, we need to do a full poweron,
+* otherwise it will fail.
+*/
+   if (poweroff)
+   drm_atomic_bridge_chain_pre_enable(bridge,
+  
connector->state->state);
 
-   edid = drm_get_edid(connector,
-   ps_bridge->page[PAGE0_DP_CNTL]->adapter);
+   ps_bridge->edid = drm_get_edid(connector,
+  
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
 
-   /*
-* If we call the get_edid() function without having enabled the chip
-* before, return the chip to its original power state.
-*/
-   if (poweroff)
-   drm_atomic_bridge_chain_post_disable(bridge, 
connector->state->state);
+   /*
+* If we call the get_edid() function without having enabled the
+* chip before, return the chip to its original power state.
+*/
+   if (poweroff)
+   drm_atomic_bridge_chain_post_disable(bridge,
+
connector->state->state);
+   }
 
-   return edid;
+   return drm_edid_duplicate(ps_bridge->edid);
 }
 
 static void ps8640_runtime_disable(void *data)
@@ -767,6 +771,13 @@ static int ps8640_probe(struct i2c_client *client)
return ret;
 }
 
+static void ps8640_remove(struct i2c_client *client)
+{
+   struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+   kfree(ps_bridge->edid);
+}
+
 static const struct of_device_id ps8640_match[] = {
{ .compatible = "parade,ps8640" },
{ }
@@ -775,6 +786,7 @@ MODULE_DEVICE_TABLE(of, ps8640_match);
 
 static struct i2c_driver ps8640_driver = {
.probe_new = ps8640_probe,
+   .remove = ps8640_remove,
.driver = {
.name = "ps8640",
.of_match_table = ps8640_match,
-- 
2.40.0.rc1.284.g88254d51c5-goog



[PATCH v2 1/2] drm/bridge: ps8640: Skip redundant bridge enable

2023-03-14 Thread Pin-yen Lin
Skip the drm_bridge_chain_pre_enable call when the bridge is already
pre_enabled. This make pre_enable and post_disable (thus
pm_runtime_get/put) symmetric.

Fixes: 46f206304db0 ("drm/bridge: ps8640: Rework power state handling")
Signed-off-by: Pin-yen Lin 
Reviewed-by: Robert Foss 
Reviewed-by: Douglas Anderson 
---

(no changes since v1)

 drivers/gpu/drm/bridge/parade-ps8640.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index 4b361d7d5e44..08de501c436e 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -557,7 +557,8 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 * EDID, for this chip, we need to do a full poweron, otherwise it will
 * fail.
 */
-   drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
+   if (poweroff)
+   drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
 
edid = drm_get_edid(connector,
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
-- 
2.40.0.rc1.284.g88254d51c5-goog



Re: [PATCH 1/2] drm/bridge: ps8640: Skip redundant bridge enable

2023-03-14 Thread Pin-yen Lin
Hi Doug,

On Wed, Mar 15, 2023 at 5:31 AM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Mar 14, 2023 at 4:00 AM Pin-yen Lin  wrote:
> >
> > Skip the drm_bridge_chain_pre_enable call when the bridge is already
> > pre_enabled. This make pre_enable and post_disable (thus
> > pm_runtime_get/put) symmetric.
> >
> > Fixes: 46f206304db0 ("drm/bridge: ps8640: Rework power state handling")
> > Signed-off-by: Pin-yen Lin 
> > ---
> >
> >  drivers/gpu/drm/bridge/parade-ps8640.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
> > b/drivers/gpu/drm/bridge/parade-ps8640.c
> > index 4b361d7d5e44..08de501c436e 100644
> > --- a/drivers/gpu/drm/bridge/parade-ps8640.c
> > +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> > @@ -557,7 +557,8 @@ static struct edid *ps8640_bridge_get_edid(struct 
> > drm_bridge *bridge,
> >  * EDID, for this chip, we need to do a full poweron, otherwise it 
> > will
> >  * fail.
> >  */
> > -   drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
> > +   if (poweroff)
> > +   drm_atomic_bridge_chain_pre_enable(bridge, 
> > connector->state->state);
>
> It always seemed weird to me that this function was asymmetric, so I
> like this change, thanks!
>
> I also remember wondering before how this function was safe, though.
> The callpath for getting here from the ioctl is documented in the
> function and when I look at it I wonder if anything is preventing the
> bridge from being enabled / disabled through normal means at the same
> time your function is running. That could cause all sorts of badness
> if it is indeed possible. Does anyone reading this know if that's
> indeed a problem?

If the "normal mean" is disabling the bridge, then we are probably
disabling the whole display pipeline. If so, is the EDID still
relevant in this case?

drm_get_edid returns NULL whenever error happens, and the helpers seem
to handle this case properly.
>
> I suppose that, if this is unsafe, it's no more unsafe now than it was
> before your patch, so I guess:
>
> Reviewed-by: Douglas Anderson 
>
> If there are no issues, I'll plan to land this patch and the next one
> to drm-misc-next sometime late-ish next week.

Thanks for the review. I'll submit a v2 to collect the review tags and
fix up the nit in patch 2/2.

Best regards,
Pin-yen


[PATCH 2/2] drm/bridge: ps8640: Add a cache for EDID

2023-03-14 Thread Pin-yen Lin
When there are multiple EDID reads, the bridge will be repeatedly
enabled and disabled. Add a cache for EDID to speed this up.

Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/parade-ps8640.c | 61 --
 1 file changed, 37 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index 08de501c436e..4d594be8b89c 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -105,6 +105,7 @@ struct ps8640 {
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_powerdown;
struct device_link *link;
+   struct edid *edid;
bool pre_enabled;
bool need_post_hpd_delay;
 };
@@ -543,34 +544,37 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
bool poweroff = !ps_bridge->pre_enabled;
-   struct edid *edid;
 
-   /*
-* When we end calling get_edid() triggered by an ioctl, i.e
-*
-*   drm_mode_getconnector (ioctl)
-* -> drm_helper_probe_single_connector_modes
-*-> drm_bridge_connector_get_modes
-*   -> ps8640_bridge_get_edid
-*
-* We need to make sure that what we need is enabled before reading
-* EDID, for this chip, we need to do a full poweron, otherwise it will
-* fail.
-*/
-   if (poweroff)
-   drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
+   if (!ps_bridge->edid) {
+   /*
+* When we end calling get_edid() triggered by an ioctl, i.e
+*
+*   drm_mode_getconnector (ioctl)
+* -> drm_helper_probe_single_connector_modes
+*-> drm_bridge_connector_get_modes
+*   -> ps8640_bridge_get_edid
+*
+* We need to make sure that what we need is enabled before
+* reading EDID, for this chip, we need to do a full poweron,
+* otherwise it will fail.
+*/
+   if (poweroff)
+   drm_atomic_bridge_chain_pre_enable(bridge,
+  
connector->state->state);
 
-   edid = drm_get_edid(connector,
-   ps_bridge->page[PAGE0_DP_CNTL]->adapter);
+   ps_bridge->edid = drm_get_edid(connector,
+  
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
 
-   /*
-* If we call the get_edid() function without having enabled the chip
-* before, return the chip to its original power state.
-*/
-   if (poweroff)
-   drm_atomic_bridge_chain_post_disable(bridge, 
connector->state->state);
+   /*
+* If we call the get_edid() function without having enabled the
+* chip before, return the chip to its original power state.
+*/
+   if (poweroff)
+   drm_atomic_bridge_chain_post_disable(bridge,
+
connector->state->state);
+   }
 
-   return edid;
+   return drm_edid_duplicate(ps_bridge->edid);
 }
 
 static void ps8640_runtime_disable(void *data)
@@ -767,6 +771,14 @@ static int ps8640_probe(struct i2c_client *client)
return ret;
 }
 
+static void ps8640_remove(struct i2c_client *client)
+{
+   struct ps8640 *ps_bridge = i2c_get_clientdata(client);
+
+   kfree(ps_bridge->edid);
+   ps_bridge->edid = NULL;
+}
+
 static const struct of_device_id ps8640_match[] = {
{ .compatible = "parade,ps8640" },
{ }
@@ -775,6 +787,7 @@ MODULE_DEVICE_TABLE(of, ps8640_match);
 
 static struct i2c_driver ps8640_driver = {
.probe_new = ps8640_probe,
+   .remove = ps8640_remove,
.driver = {
.name = "ps8640",
.of_match_table = ps8640_match,
-- 
2.40.0.rc1.284.g88254d51c5-goog



[PATCH 1/2] drm/bridge: ps8640: Skip redundant bridge enable

2023-03-14 Thread Pin-yen Lin
Skip the drm_bridge_chain_pre_enable call when the bridge is already
pre_enabled. This make pre_enable and post_disable (thus
pm_runtime_get/put) symmetric.

Fixes: 46f206304db0 ("drm/bridge: ps8640: Rework power state handling")
Signed-off-by: Pin-yen Lin 
---

 drivers/gpu/drm/bridge/parade-ps8640.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index 4b361d7d5e44..08de501c436e 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -557,7 +557,8 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 * EDID, for this chip, we need to do a full poweron, otherwise it will
 * fail.
 */
-   drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
+   if (poweroff)
+   drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
 
edid = drm_get_edid(connector,
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
-- 
2.40.0.rc1.284.g88254d51c5-goog



Re: [PATCH v13 10/10] drm/bridge: it6505: Register Type C mode switches

2023-03-09 Thread Pin-yen Lin
Hi Andy,

On Wed, Mar 8, 2023 at 11:31 PM Andy Shevchenko
 wrote:
>
> On Wed, Mar 08, 2023 at 09:51:19PM +0800, Pin-yen Lin wrote:
> > On Mon, Mar 6, 2023 at 8:03 PM Andy Shevchenko
> >  wrote:
> > > On Fri, Mar 03, 2023 at 10:33:50PM +0800, Pin-yen Lin wrote:
>
> ...
>
> > > > + it6505->port_data[i].lane_swap = (dp_lanes[0] / 2 == 1);
> > >
> > > ' % 2 == 0' ?
> > >
> > Per another patch, I'll update this into `< 2`
>
> But here it should be >= 2 then, no?
>
Yes it should be >= 2 here. I wasn't really using my brain when I
replied to the mail
> --
> With Best Regards,
> Andy Shevchenko
>
>
Best regards,
Pin-yen


Re: [PATCH v13 03/10] drm/display: Add Type-C switch helpers

2023-03-09 Thread Pin-yen Lin
Hi Andy,

On Wed, Mar 8, 2023 at 11:29 PM Andy Shevchenko
 wrote:
>
> On Wed, Mar 08, 2023 at 06:20:14PM +0800, Pin-yen Lin wrote:
> > On Mon, Mar 6, 2023 at 7:49 PM Andy Shevchenko
> > > On Fri, Mar 03, 2023 at 10:33:43PM +0800, Pin-yen Lin wrote:
>
> ...
>
> > > > + switch_desc->typec_ports = devm_kcalloc(dev, 
> > > > switch_desc->num_typec_switches,
> > > > + sizeof(struct 
> > > > drm_dp_typec_port_data),
> > > > + GFP_KERNEL);
> > > > + if (!switch_desc->typec_ports)
> > > > + return -ENOMEM;
> > >
> > > How often this function _can_ be called during the runtime?
> > > If it's _possible_ to call it infinite times, consider *not* using devm.
> >
> > I would expect this function to be only called during driver probing,
> > and this is the case for the current users in this series. So I think
> > this is only called once if EPROBDE_DEFER doesn't count.
>
> No, deferred probe is not counted.
>
> Can you add a word somewhere in the comment(?) to make this clear?

Sure. I'll add some note in the comments about this.
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Thanks and regards,
Pin-yen


Re: [PATCH v13 10/10] drm/bridge: it6505: Register Type C mode switches

2023-03-08 Thread Pin-yen Lin
Hi Andy,

Thanks for the review.

On Mon, Mar 6, 2023 at 8:03 PM Andy Shevchenko
 wrote:
>
> On Fri, Mar 03, 2023 at 10:33:50PM +0800, Pin-yen Lin wrote:
> > Register USB Type-C mode switches when the "mode-switch" property and
> > relevant port are available in Device Tree. Configure the "lane_swap"
> > state based on the entered alternate mode for a specific Type-C
> > connector, which ends up updating the lane swap registers of the it6505
> > chip.
>
> ...
>
> > + it6505->port_data = devm_kcalloc(dev, switch_desc->num_typec_switches,
> > +  sizeof(struct 
> > it6505_typec_port_data),
> > +  GFP_KERNEL);
>
> > +
>
> Same, no need for a blank line here.
>
I'll fix this in the next version.
> > + if (!it6505->port_data) {
> > + ret = -ENOMEM;
> > + goto unregister_mux;
> > + }
>
> ...
>
> > + it6505->port_data[i].lane_swap = (dp_lanes[0] / 2 == 1);
>
> ' % 2 == 0' ?
>
Per another patch, I'll update this into `< 2`
> ...
>
> Wouldn't be better to have
>
> ret = PTR_ERR_OR_ZERO(extcon);
>
> here and amend the following accordingly?
>
> >   if (PTR_ERR(extcon) == -EPROBE_DEFER)
> >   return -EPROBE_DEFER;
> >   if (IS_ERR(extcon)) {
> > - dev_err(dev, "can not get extcon device!");
> > - return PTR_ERR(extcon);
> > + if (PTR_ERR(extcon) != -ENODEV)
> > + dev_warn(dev, "Cannot get extcon device: %ld\n",
> > +  PTR_ERR(extcon));
> > + it6505->extcon = NULL;
> > + } else {
> > + it6505->extcon = extcon;
> >   }
> >
> > - it6505->extcon = extcon;
> > + init_completion(&it6505->mux_register);
> > + ret = it6505_register_typec_switches(dev, it6505);
> > + if (ret) {
> > + if (ret != -ENODEV)
> > + dev_warn(dev, "Didn't register Type-C switches, err: 
> > %d\n",
> > +  ret);
> > + if (!it6505->extcon) {
> > + dev_err(dev, "Both extcon and typec-switch are not 
> > registered.\n");
> > + return -EINVAL;
> > + }
> > + }
>
>
> Perhaps
>
> if (ret != -ENODEV)
> dev_warn(dev, "Didn't register Type-C switches, err: %d\n", 
> ret);
>
> if (ret && !it6505->extcon) {
> dev_err(dev, "Both extcon and typec-switch are not 
> registered.\n");
> return ret;
> }
>
> ?


Thanks for the suggestion! I'll update this in v14.
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Best regards,
Pin-yen


Re: [PATCH v13 07/10] drm/bridge: anx7625: Register Type C mode switches

2023-03-08 Thread Pin-yen Lin
Hi Andy,

Thanks for the review.

On Mon, Mar 6, 2023 at 7:55 PM Andy Shevchenko
 wrote:
>
> On Fri, Mar 03, 2023 at 10:33:47PM +0800, Pin-yen Lin wrote:
> > Register USB Type-C mode switches when the "mode-switch" property and
> > relevant ports are available in Device Tree. Configure the crosspoint
> > switch based on the entered alternate mode for a specific Type-C
> > connector.
> >
> > Crosspoint switch can also be used for switching the output signal for
> > different orientations of a single USB Type-C connector, but the
> > orientation switch is not implemented yet. A TODO is added for this.
>
> ...
>
> > + ctx->port_data = devm_kcalloc(
> > + dev, switch_desc->num_typec_switches,
> > + sizeof(struct anx7625_typec_port_data), GFP_KERNEL);
>
> I believe I have commented on this (indentation)...
>
> > +
>
> ...and this (blank line).

Sorry for missing this one. I'll fix this in v14.
>
> > + if (!ctx->port_data) {
> > + ret = -ENOMEM;
> > + goto unregister_mux;
> > + }
>
> ...
>
> > + ctx->port_data[i].orientation = (dp_lanes[0] / 2 == 0) ?
> > + TYPEC_ORIENTATION_REVERSE : TYPEC_ORIENTATION_NORMAL;
>
> I believe that this is an error prone check, you should rather do the 
> opposite,
> i.e.  ' % 2  == 0'.
>
The orientation should be TYPEC_ORIENTATION_REVERSE when the
data-lanes value is 0/1, so ` / 2` is what I meant here.

Though, after second thought, I think it would be clearer if I use
`dp_lanes[0] < 2`. I'll update this in v14 as well.
> --
> With Best Regards,
> Andy Shevchenko
>
>
Best regards,
Pin-yen


Re: [PATCH v13 05/10] drm/bridge: anx7625: Check for Type-C during panel registration

2023-03-08 Thread Pin-yen Lin
HI Andy,

On Mon, Mar 6, 2023 at 7:52 PM Andy Shevchenko
 wrote:
>
> On Fri, Mar 03, 2023 at 10:33:45PM +0800, Pin-yen Lin wrote:
> > The output port endpoints can be connected to USB-C connectors.
> > Running drm_of_find_panel_or_bridge() with such endpoints leads to
> > a continuous return value of -EPROBE_DEFER, even though there is
> > no panel present.
> >
> > To avoid this, check for the existence of a "mode-switch" property in
> > the port endpoint, and skip panel registration completely if so.
>
> ...
>
> > + port_node = of_graph_get_port_by_id(np, 1);
> > + count = typec_mode_switch_node_count(&port_node->fwnode);
>
> Do you need to drop reference count here?
> (I don't know myself, so, please check this)
>
> If no, patch LGTM.

The helper completes the for-loop of fwnode_for_each_child_node, which
drops the reference count whenever the next node is get. So we don't
need drop the reference count here.
>
> > + if (count)
> > + return 0;
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Best regards,
Pin-yen


Re: [PATCH v13 03/10] drm/display: Add Type-C switch helpers

2023-03-08 Thread Pin-yen Lin
Hi Andy,

Thanks for the review.

On Mon, Mar 6, 2023 at 7:49 PM Andy Shevchenko
 wrote:
>
> On Fri, Mar 03, 2023 at 10:33:43PM +0800, Pin-yen Lin wrote:
> > Add helpers to register and unregister Type-C "switches" for bridges
> > capable of switching their output between two downstream devices.
> >
> > The helper registers USB Type-C mode switches when the "mode-switch"
> > and the "reg" properties are available in Device Tree.
>
> ...
>
> > + port_data->typec_mux = typec_mux_register(dev, &mux_desc);
> > + if (IS_ERR(port_data->typec_mux)) {
> > + ret = PTR_ERR(port_data->typec_mux);
> > + dev_err(dev, "Mode switch register for port %d failed: %d\n",
> > + port_num, ret);
>
> > + return ret;
> > + }
> > +
> > + return 0;
>
> Can be simply
>
> port_data->typec_mux = typec_mux_register(dev, &mux_desc);
> ret = PTR_ERR_OR_ZERO(port_data->typec_mux);
> if (ret)
> dev_err(dev, "Mode switch register for port %d failed: %d\n",
> port_num, ret);
>
> return ret;
>
This was suggested by Angelo in [1], but you are not the first
reviewer that finds this weird... I'll update this in the next
version.

[1]: 
https://lore.kernel.org/all/023519eb-0adb-3b08-71b9-afb92a6cc...@collabora.com/

> ...
>
> > + switch_desc->typec_ports = devm_kcalloc(dev, 
> > switch_desc->num_typec_switches,
> > + sizeof(struct 
> > drm_dp_typec_port_data),
> > + GFP_KERNEL);
> > + if (!switch_desc->typec_ports)
> > + return -ENOMEM;
>
> How often this function _can_ be called during the runtime?
> If it's _possible_ to call it infinite times, consider *not* using devm.

I would expect this function to be only called during driver probing,
and this is the case for the current users in this series. So I think
this is only called once if EPROBDE_DEFER doesn't count.
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Best regards,
Pin-yen


[PATCH v13 10/10] drm/bridge: it6505: Register Type C mode switches

2023-03-03 Thread Pin-yen Lin
Register USB Type-C mode switches when the "mode-switch" property and
relevant port are available in Device Tree. Configure the "lane_swap"
state based on the entered alternate mode for a specific Type-C
connector, which ends up updating the lane swap registers of the it6505
chip.

Signed-off-by: Pin-yen Lin 

---

Changes in v13:
- Fix style issues

Changes in v12:
- Fixes style issues in it6505 driver
- Replaced &it6505->client->dev with it6505->dev
- Updated the error logs when parsing data-lanes property

Changes in v11:
- Added back "data-lanes" parsing logics
- Removed Kconfig dependency
- Updated the usage of the private data

Changes in v7:
- Fixed style issues in it6505 driver
- Removed the redundant sleep in it6505 driver
- Removed DT property validation in it6505 driver
- Rebased to drm-misc-next
- Extracted common codes to another commit

Changes in v6:
- Changed it6505_typec_mux_set callback function to accommodate with
  the latest drm-misc patches
- Changed the driver implementation to accommodate with the new binding
- Squashed to a single patch

 drivers/gpu/drm/bridge/ite-it6505.c | 185 +++-
 1 file changed, 181 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index d4bc388b68ac..988fe28619ab 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -17,6 +17,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
@@ -27,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -401,6 +404,11 @@ struct debugfs_entries {
const struct file_operations *fops;
 };
 
+struct it6505_typec_port_data {
+   bool dp_connected;
+   bool lane_swap;
+};
+
 struct it6505 {
struct drm_dp_aux aux;
struct drm_bridge bridge;
@@ -454,6 +462,9 @@ struct it6505 {
struct delayed_work delayed_audio;
struct it6505_audio_data audio;
struct dentry *debugfs;
+   struct completion mux_register;
+   struct drm_dp_typec_switch_desc switch_desc;
+   struct it6505_typec_port_data *port_data;
 
/* it6505 driver hold option */
bool enable_drv_hold;
@@ -3345,12 +3356,163 @@ static void it6505_shutdown(struct i2c_client *client)
it6505_lane_off(it6505);
 }
 
+static void it6505_typec_ports_update(struct it6505 *it6505)
+{
+   unsigned int i;
+
+   /* Check if both ports available and do nothing to retain the current 
one */
+   if (it6505->port_data[0].dp_connected && 
it6505->port_data[1].dp_connected)
+   return;
+
+   for (i = 0; i < 2; i++) {
+   if (it6505->port_data[i].dp_connected)
+   it6505->lane_swap = it6505->port_data[i].lane_swap;
+   }
+}
+
+static int it6505_typec_mux_set(struct typec_mux_dev *mux,
+   struct typec_mux_state *state)
+{
+   struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
+   struct it6505 *it6505 = port->data;
+   struct device *dev = it6505->dev;
+   struct drm_dp_typec_switch_desc switch_desc = it6505->switch_desc;
+   bool old_dp_connected, new_dp_connected;
+
+   if (switch_desc.num_typec_switches == 1)
+   return 0;
+
+   mutex_lock(&it6505->extcon_lock);
+   wait_for_completion(&it6505->mux_register);
+
+   old_dp_connected = it6505->port_data[0].dp_connected ||
+  it6505->port_data[1].dp_connected;
+
+   it6505->port_data[port->port_num].dp_connected =
+   state->alt &&
+   state->alt->svid == USB_TYPEC_DP_SID &&
+   state->alt->mode == USB_TYPEC_DP_MODE;
+
+   dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
+   it6505->port_data[0].dp_connected, 
it6505->port_data[1].dp_connected);
+
+   new_dp_connected = it6505->port_data[0].dp_connected ||
+  it6505->port_data[1].dp_connected;
+
+   if (it6505->enable_drv_hold) {
+   dev_dbg(dev, "enable driver hold\n");
+   goto unlock;
+   }
+
+   it6505_typec_ports_update(it6505);
+
+   if (!old_dp_connected && new_dp_connected) {
+   int ret = pm_runtime_get_sync(dev);
+
+   /*
+* pm_runtime_force_suspend() disables runtime PM when the
+* system enters suspend state. But on system resume, mux_set
+* can be triggered before pm_runtime_force_resume() re-enables
+* runtime PM. This makes the bridge stay powered off if the
+* downstream display is connected when the system is suspended.
+* Handling the error here to make sure the bridge is powered
+   

[PATCH v13 09/10] drm/bridge: it6505: Fix Kconfig indentation

2023-03-03 Thread Pin-yen Lin
Replace the spaces with tab characters in the Kconfig file.

Signed-off-by: Pin-yen Lin 
Reviewed-by: AngeloGioacchino Del Regno 


---

(no changes since v10)

Changes in v10:
- Collected Reviewed-by tag

Changes in v7:
- New in v7

 drivers/gpu/drm/bridge/Kconfig | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 12e8f30c65f7..28dc7711bf5f 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -74,19 +74,19 @@ config DRM_FSL_LDB
  Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
 
 config DRM_ITE_IT6505
-tristate "ITE IT6505 DisplayPort bridge"
-depends on OF
+   tristate "ITE IT6505 DisplayPort bridge"
+   depends on OF
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDCP_HELPER
select DRM_DISPLAY_HELPER
-select DRM_DP_AUX_BUS
-select DRM_KMS_HELPER
-select DRM_DP_HELPER
-select EXTCON
-select CRYPTO
-select CRYPTO_HASH
-help
-  ITE IT6505 DisplayPort bridge chip driver.
+   select DRM_DP_AUX_BUS
+   select DRM_KMS_HELPER
+   select DRM_DP_HELPER
+   select EXTCON
+   select CRYPTO
+   select CRYPTO_HASH
+   help
+ ITE IT6505 DisplayPort bridge chip driver.
 
 config DRM_LONTIUM_LT8912B
tristate "Lontium LT8912B DSI/HDMI bridge"
-- 
2.40.0.rc0.216.gc4246ad0f0-goog



[PATCH v13 08/10] dt-bindings: display: bridge: it6505: Add mode-switch support

2023-03-03 Thread Pin-yen Lin
ITE IT6505 can be used in systems to switch the DP traffic between
two downstreams, which can be USB Type-C DisplayPort alternate mode
lane or regular DisplayPort output ports.

Update the binding to accommodate this usage by introducing a
data-lanes and a mode-switch property on endpoints.

Signed-off-by: Pin-yen Lin 

---

(no changes since v12)

Changes in v12:
- Fixed the schema of "data-lanes" property for it6505
- Reworded the description of the mode-switch property

Changes in v11:
- Updated the description of the endpoints in the bindings
- Referenced video-interfaces.yaml instead for the endpoints binding
- Removed duplicated definitions from inherited schema

Changes in v9:
- Fixed subject prefix again
- Changed the naming of the example node for it6505

Changes in v8:
- Updated bindings for data-lanes property
- Fixed subject prefix

Changes in v7:
- Fixed issues reported by dt_binding_check.
- Updated the schema and the example dts for data-lanes.
- Changed to generic naming for the example dts node.

Changes in v6:
- Remove switches node and use endpoints and data-lanes property to
  describe the connections.

 .../bindings/display/bridge/ite,it6505.yaml   | 101 +++---
 1 file changed, 88 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml 
b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
index c9a882ee6d98..348b02f26041 100644
--- a/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.yaml
@@ -75,22 +75,49 @@ properties:
   port@1:
 $ref: /schemas/graph.yaml#/$defs/port-base
 unevaluatedProperties: false
-description: Video port for DP output
+description:
+  Video port for DP output. Each endpoint connects to a video output
+  downstream, and the "data-lanes" property is used to describe the pin
+  connections. 0, 1, 2, 3 in "data-lanes" maps to TX0, TX1, TX2, TX3,
+  respectively.
 
-properties:
-  endpoint:
-$ref: /schemas/graph.yaml#/$defs/endpoint-base
+
+patternProperties:
+  "^endpoint@[01]$":
+$ref: /schemas/media/video-interfaces.yaml#
 unevaluatedProperties: false
 
 properties:
+  reg: true
+
+  remote-endpoint: true
+
   data-lanes:
-minItems: 1
-uniqueItems: true
-items:
-  - enum: [ 0, 1 ]
-  - const: 1
-  - const: 2
-  - const: 3
+oneOf:
+  - items:
+  - enum: [0, 3]
+
+  - items:
+  - const: 0
+  - const: 1
+
+  - items:
+  - const: 3
+  - const: 2
+
+  - items:
+  - const: 0
+  - const: 1
+  - const: 2
+  - const: 3
+
+  mode-switch:
+type: boolean
+description: Serves as Type-C mode switch if present.
+
+required:
+  - reg
+  - remote-endpoint
 
 required:
   - port@0
@@ -102,7 +129,6 @@ required:
   - pwr18-supply
   - interrupts
   - reset-gpios
-  - extcon
   - ports
 
 additionalProperties: false
@@ -139,8 +165,11 @@ examples:
 };
 
 port@1 {
+#address-cells = <1>;
+#size-cells = <0>;
 reg = <1>;
-it6505_out: endpoint {
+it6505_out: endpoint@0 {
+reg = <0>;
 remote-endpoint = <&dp_in>;
 data-lanes = <0 1>;
 };
@@ -148,3 +177,49 @@ examples:
 };
 };
 };
+  - |
+#include 
+
+i2c {
+#address-cells = <1>;
+#size-cells = <0>;
+
+dp-bridge@5c {
+compatible = "ite,it6505";
+interrupts = <8 IRQ_TYPE_LEVEL_LOW 8 0>;
+reg = <0x5c>;
+pinctrl-names = "default";
+pinctrl-0 = <&it6505_pins>;
+ovdd-supply = <&mt6366_vsim2_reg>;
+pwr18-supply = <&pp1800_dpbrdg_dx>;
+reset-gpios = <&pio 177 0>;
+
+ports {
+#address-cells = <1>;
+#size-cells = <0>;
+port@0 {
+reg = <0>;
+it6505_dpi_in: endpoint {
+remote-endpoint = <&dpi_out>;
+};
+};
+port@1 {
+ 

[PATCH v13 07/10] drm/bridge: anx7625: Register Type C mode switches

2023-03-03 Thread Pin-yen Lin
Register USB Type-C mode switches when the "mode-switch" property and
relevant ports are available in Device Tree. Configure the crosspoint
switch based on the entered alternate mode for a specific Type-C
connector.

Crosspoint switch can also be used for switching the output signal for
different orientations of a single USB Type-C connector, but the
orientation switch is not implemented yet. A TODO is added for this.

Signed-off-by: Pin-yen Lin 

---

(no changes since v12)

Changes in v12:
- Fixed style issues in anx7625 driver
- Fixed the inverted orientation setting in anx7625 driver
- Changed "&ctx->client->dev" to "ctx->dev"
- Fix style issues
- Updated the error logs when parsing data-lanes property

Changes in v11:
- Added back "data-lanes" parsing logics
- Removed Kconfig dependency
- Updated the usage of the private data
- Dropped Tested-by tag because of the new changes

Changes in v10:
- Added a TODO for implementing orientation switch for anx7625
- Updated the commit message for the absence of orientation switch
- Fixed typo in the commit message
- Collected Tested-by tag

Changes in v7:
- Fixed style issues in anx7625 driver
- Removed DT property validation in anx7625 driver.
- Extracted common codes to another commit.

Changes in v6:
- Squashed to a single patch

 drivers/gpu/drm/bridge/analogix/anx7625.c | 149 ++
 drivers/gpu/drm/bridge/analogix/anx7625.h |  20 +++
 2 files changed, 169 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 76d46db3f8dc..4361a1b52a67 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -15,6 +15,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 
 #include 
@@ -2570,6 +2572,146 @@ static void anx7625_runtime_disable(void *data)
pm_runtime_disable(data);
 }
 
+static void anx7625_set_crosspoint_switch(struct anx7625_data *ctx,
+ enum typec_orientation orientation)
+{
+   if (orientation == TYPEC_ORIENTATION_NORMAL) {
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_0,
+ SW_SEL1_SSRX_RX1 | SW_SEL1_DPTX0_RX2);
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_1,
+ SW_SEL2_SSTX_TX1 | SW_SEL2_DPTX1_TX2);
+   } else if (orientation == TYPEC_ORIENTATION_REVERSE) {
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_0,
+ SW_SEL1_SSRX_RX2 | SW_SEL1_DPTX0_RX1);
+   anx7625_reg_write(ctx, ctx->i2c.tcpc_client, TCPC_SWITCH_1,
+ SW_SEL2_SSTX_TX2 | SW_SEL2_DPTX1_TX1);
+   }
+}
+
+static void anx7625_typec_two_ports_update(struct anx7625_data *ctx)
+{
+   unsigned int i;
+
+   /* Check if both ports available and do nothing to retain the current 
one */
+   if (ctx->port_data[0].dp_connected && ctx->port_data[1].dp_connected)
+   return;
+
+   for (i = 0; i < 2; i++) {
+   if (ctx->port_data[i].dp_connected)
+   anx7625_set_crosspoint_switch(ctx,
+ 
ctx->port_data[i].orientation);
+   }
+}
+
+static int anx7625_typec_mux_set(struct typec_mux_dev *mux,
+struct typec_mux_state *state)
+{
+   struct drm_dp_typec_port_data *port = typec_mux_get_drvdata(mux);
+   struct anx7625_data *ctx = port->data;
+   struct device *dev = ctx->dev;
+   struct drm_dp_typec_switch_desc switch_desc = ctx->switch_desc;
+   bool new_dp_connected, old_dp_connected;
+
+   if (switch_desc.num_typec_switches == 1)
+   return 0;
+
+   wait_for_completion(&ctx->mux_register);
+
+   old_dp_connected = ctx->port_data[0].dp_connected ||
+  ctx->port_data[1].dp_connected;
+
+   ctx->port_data[port->port_num].dp_connected =
+   state->alt &&
+   state->alt->svid == USB_TYPEC_DP_SID &&
+   state->alt->mode == USB_TYPEC_DP_MODE;
+
+   dev_dbg(dev, "mux_set dp_connected: c0=%d, c1=%d\n",
+   ctx->port_data[0].dp_connected, ctx->port_data[1].dp_connected);
+
+   new_dp_connected = ctx->port_data[0].dp_connected ||
+  ctx->port_data[1].dp_connected;
+
+   /* DP on, power on first */
+   if (!old_dp_connected && new_dp_connected)
+   pm_runtime_get_sync(dev);
+
+   anx7625_typec_two_ports_update(ctx);
+
+   /* DP off, power off last */
+   if (old_dp_connected && !new_dp_connected)
+   pm_runtime_put_sync(dev);
+
+   return 0;
+}
+
+static void anx7625_unregi

[PATCH v13 06/10] drm/bridge: Remove redundant i2c_client in anx7625/it6505

2023-03-03 Thread Pin-yen Lin
These two drivers embed a i2c_client in their private driver data, but
only strict device is actually needed. Replace the i2c_client reference
with a struct device one.

Signed-off-by: Pin-yen Lin 
Reviewed-by: Andy Shevchenko 
---

Changes in v13:
- Update a typo in the commit message
- Collect Reviewed-by tag

Changes in v12:
- New in v12

 drivers/gpu/drm/bridge/analogix/anx7625.c |  96 
 drivers/gpu/drm/bridge/analogix/anx7625.h |   2 +-
 drivers/gpu/drm/bridge/ite-it6505.c   | 128 +++---
 3 files changed, 113 insertions(+), 113 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c 
b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 3f6bf7674d32..76d46db3f8dc 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -207,7 +207,7 @@ static int anx7625_read_ctrl_status_p0(struct anx7625_data 
*ctx)
 
 static int wait_aux_op_finish(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int val;
int ret;
 
@@ -234,7 +234,7 @@ static int wait_aux_op_finish(struct anx7625_data *ctx)
 static int anx7625_aux_trans(struct anx7625_data *ctx, u8 op, u32 address,
 u8 len, u8 *buf)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
u8 addrh, addrm, addrl;
u8 cmd;
@@ -427,7 +427,7 @@ static int anx7625_odfc_config(struct anx7625_data *ctx,
   u8 post_divider)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Config input reference clock frequency 27MHz/19.2MHz */
ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, MIPI_DIGITAL_PLL_16,
@@ -477,7 +477,7 @@ static int anx7625_set_k_value(struct anx7625_data *ctx)
 
 static int anx7625_dsi_video_timing_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
unsigned long m, n;
u16 htotal;
int ret;
@@ -575,7 +575,7 @@ static int anx7625_dsi_video_timing_config(struct 
anx7625_data *ctx)
 static int anx7625_swap_dsi_lane3(struct anx7625_data *ctx)
 {
int val;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Swap MIPI-DSI data lane 3 P and N */
val = anx7625_reg_read(ctx, ctx->i2c.rx_p1_client, MIPI_SWAP);
@@ -592,7 +592,7 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx)
 
 {
int val, ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Swap MIPI-DSI data lane 3 P and N */
ret = anx7625_swap_dsi_lane3(ctx);
@@ -657,7 +657,7 @@ static int anx7625_api_dsi_config(struct anx7625_data *ctx)
 
 static int anx7625_dsi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
 
DRM_DEV_DEBUG_DRIVER(dev, "config dsi.\n");
@@ -689,7 +689,7 @@ static int anx7625_dsi_config(struct anx7625_data *ctx)
 
 static int anx7625_api_dpi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
u16 freq = ctx->dt.pixelclock.min / 1000;
int ret;
 
@@ -720,7 +720,7 @@ static int anx7625_api_dpi_config(struct anx7625_data *ctx)
 
 static int anx7625_dpi_config(struct anx7625_data *ctx)
 {
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
int ret;
 
DRM_DEV_DEBUG_DRIVER(dev, "config dpi\n");
@@ -765,7 +765,7 @@ static int anx7625_read_flash_status(struct anx7625_data 
*ctx)
 static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
 {
int ret, val;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
u8 ident[FLASH_BUF_LEN];
 
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -815,7 +815,7 @@ static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
 static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
/* Select HDCP 1.4 KEY */
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
@@ -843,7 +843,7 @@ static int anx7625_hdcp_key_load(struct anx7625_data *ctx)
 static int anx7625_hdcp_disable(struct anx7625_data *ctx)
 {
int ret;
-   struct device *dev = &ctx->client->dev;
+   struct device *dev = ctx->dev;
 
dev_dbg(dev, "disable HDCP 1.4\n");
 
@@ -864,7 +864,7 @@ static int anx7625_hdcp_enable(struct anx7625_data *ctx)
 {
u8 bca

  1   2   3   >