Re: [PATCH] drm/panel-edp: Add ID for KD KD116N09-30NH-A016

2024-05-02 Thread Hsin-Yi Wang
On Thu, May 2, 2024 at 4:48 PM Douglas Anderson  wrote:
>
> As evidenced by in-field reports, this panel shipped on pompom but we
> never added the ID and thus we're stuck w/ conservative timings. The
> panel was part of early patches but somehow got left off in the
> end. :( Add it in now.
>
> For future reference, EDID from this panel is:
> 00002c821212
> 321e0104951a0e780ae511965e55932c
> 1950540001010101010101010101
> 010101010101a41f5686500084302820
> 55901018
> 
> 00fe
> 004b443131364e3039333041313600f6
>
> We use the ASCII string from decoding the EDID ("KD116N0930A16") as
> the panel name.
>
> Signed-off-by: Douglas Anderson 

Reviewed-by: Hsin-Yi Wang 

> ---
>
>  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 6db277efcbb7..9cfa05c7d193 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -2094,6 +2094,7 @@ static const struct edp_panel_entry edp_panels[] = {
> EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, 
> _kd116n21_30nv_a010.delay, "116N21-30NV-A010"),
> EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, _200_500_e50, 
> "KD116N29-30NK-A005"),
> EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, _200_500_e80_d50, 
> "116N29-30NK-C007"),
> +   EDP_PANEL_ENTRY('K', 'D', 'B', 0x1212, _200_500_e50, 
> "KD116N0930A16"),
>
> EDP_PANEL_ENTRY('K', 'D', 'C', 0x044f, _200_500_e50, 
> "KD116N9-30NH-F3"),
> EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, _200_500_e80_d50, 
> "KD116N5-30NV-G7"),
> --
> 2.45.0.rc1.225.g2a3ae87e7f-goog
>


Re: [PATCH v1 2/2] drm/panel: kd101ne3: add new panel driver

2024-04-24 Thread Hsin-Yi Wang
On Wed, Apr 24, 2024 at 2:49 PM Dmitry Baryshkov
 wrote:
>
> On Thu, 25 Apr 2024 at 00:04, Doug Anderson  wrote:
> >
> > Hi,
> >
> > On Tue, Apr 23, 2024 at 2:20 PM Dmitry Baryshkov
> >  wrote:
> > >
> > > On Tue, Apr 23, 2024 at 01:41:59PM -0700, Doug Anderson wrote:
> > > > Hi,
> > > >
> > > > On Tue, Apr 23, 2024 at 11:10 AM Hsin-Yi Wang  wrote:
> > > > >
> > > > > > > > > +#define _INIT_DCS_CMD(...) { \
> > > > > > > > > + .type = INIT_DCS_CMD, \
> > > > > > > > > + .len = sizeof((char[]){__VA_ARGS__}), \
> > > > > > > > > + .data = (char[]){__VA_ARGS__} }
> > > > > > > > > +
> > > > > > > > > +#define _INIT_DELAY_CMD(...) { \
> > > > > > > > > + .type = DELAY_CMD,\
> > > > > > > > > + .len = sizeof((char[]){__VA_ARGS__}), \
> > > > > > > > > + .data = (char[]){__VA_ARGS__} }
> > > > > > > >
> > > > > > > > This is the third panel driver using the same appoach. Can you 
> > > > > > > > use
> > > > > > > > mipi_dsi_generic_write_seq() instead of the huge table? Or if 
> > > > > > > > you prefer
> > > > > > > > the table, we should extract this framework to a common helper.
> > > > > > > > (my preference is shifted towards mipi_dsi_generic_write_seq()).
> > > > > > > >
> > > > > > > The drawback of mipi_dsi_generic_write_seq() is that it can cause 
> > > > > > > the
> > > > > > > kernel size grows a lot since every sequence will be expanded.
> > > > > > >
> > > > > > > Similar discussion in here:
> > > > > > > https://lore.kernel.org/dri-devel/CAD=FV=Wju3WS45=EpXMUg7FjYDh3-=mvm_js7tf1tsaazbb...@mail.gmail.com/
> > > > > > >
> > > > > > > This patch would increase the module size from 157K to 572K.
> > > > > > > scripts/bloat-o-meter shows chg +235.95%.
> > > > > > >
> > > > > > > So maybe the common helper is better regarding the kernel module 
> > > > > > > size?
> > > > > >
> > > > > > Yes, let's get a framework done in a useful way.
> > > > > > I'd say, drop the _INIT_DELAY_CMD. msleep() and usleep_range() 
> > > > > > should be
> > > > > > used instead (and it's up to the developer to select correct delay
> > > > > > function).
> > > > > >
> > > > > > >
> > > > > > > > > +
> > > > > > > > > +static const struct panel_init_cmd 
> > > > > > > > > kingdisplay_kd101ne3_init_cmd[] = {
> > > > > > > > > + _INIT_DELAY_CMD(50),
> > > > > > > > > + _INIT_DCS_CMD(0xE0, 0x00),
> > > > > >
> > > > > > [skipped the body of the table]
> > > > > >
> > > > > > > > > + _INIT_DCS_CMD(0x0E, 0x48),
> > > > > > > > > +
> > > > > > > > > + _INIT_DCS_CMD(0xE0, 0x00),
> > > > > >
> > > > > > > > > + _INIT_DCS_CMD(0X11),
> > > > > >
> > > > > > Also, at least this is mipi_dsi_dcs_exit_sleep_mode().
> > > > > >
> > > > > > > > > + /* T6: 120ms */
> > > > > > > > > + _INIT_DELAY_CMD(120),
> > > > > > > > > + _INIT_DCS_CMD(0X29),
> > > > > >
> > > > > > And this is mipi_dsi_dcs_set_display_on().
> > > > > >
> > > > > > Having a single table enourages people to put known commands into 
> > > > > > the
> > > > > > table, the practice that must be frowned upon and forbidden.
> > > > > >
> > > > > > We have functions for some of the standard DCS commands. So, maybe
> > > > > > instead of adding a single-table based approach we can improve
> > > > > > mipi_dsi_generic_write_seq() to reduce the bloat. E.g. by moving the
> > > > > > error handling to a common part of enable() / prepare() function.
> > > >

Re: [PATCH v1 2/2] drm/panel: kd101ne3: add new panel driver

2024-04-24 Thread Hsin-Yi Wang
On Wed, Apr 24, 2024 at 2:05 PM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Apr 23, 2024 at 2:20 PM Dmitry Baryshkov
>  wrote:
> >
> > On Tue, Apr 23, 2024 at 01:41:59PM -0700, Doug Anderson wrote:
> > > Hi,
> > >
> > > On Tue, Apr 23, 2024 at 11:10 AM Hsin-Yi Wang  wrote:
> > > >
> > > > > > > > +#define _INIT_DCS_CMD(...) { \
> > > > > > > > + .type = INIT_DCS_CMD, \
> > > > > > > > + .len = sizeof((char[]){__VA_ARGS__}), \
> > > > > > > > + .data = (char[]){__VA_ARGS__} }
> > > > > > > > +
> > > > > > > > +#define _INIT_DELAY_CMD(...) { \
> > > > > > > > + .type = DELAY_CMD,\
> > > > > > > > + .len = sizeof((char[]){__VA_ARGS__}), \
> > > > > > > > + .data = (char[]){__VA_ARGS__} }
> > > > > > >
> > > > > > > This is the third panel driver using the same appoach. Can you use
> > > > > > > mipi_dsi_generic_write_seq() instead of the huge table? Or if you 
> > > > > > > prefer
> > > > > > > the table, we should extract this framework to a common helper.
> > > > > > > (my preference is shifted towards mipi_dsi_generic_write_seq()).
> > > > > > >
> > > > > > The drawback of mipi_dsi_generic_write_seq() is that it can cause 
> > > > > > the
> > > > > > kernel size grows a lot since every sequence will be expanded.
> > > > > >
> > > > > > Similar discussion in here:
> > > > > > https://lore.kernel.org/dri-devel/CAD=FV=Wju3WS45=EpXMUg7FjYDh3-=mvm_js7tf1tsaazbb...@mail.gmail.com/
> > > > > >
> > > > > > This patch would increase the module size from 157K to 572K.
> > > > > > scripts/bloat-o-meter shows chg +235.95%.
> > > > > >
> > > > > > So maybe the common helper is better regarding the kernel module 
> > > > > > size?
> > > > >
> > > > > Yes, let's get a framework done in a useful way.
> > > > > I'd say, drop the _INIT_DELAY_CMD. msleep() and usleep_range() should 
> > > > > be
> > > > > used instead (and it's up to the developer to select correct delay
> > > > > function).
> > > > >
> > > > > >
> > > > > > > > +
> > > > > > > > +static const struct panel_init_cmd 
> > > > > > > > kingdisplay_kd101ne3_init_cmd[] = {
> > > > > > > > + _INIT_DELAY_CMD(50),
> > > > > > > > + _INIT_DCS_CMD(0xE0, 0x00),
> > > > >
> > > > > [skipped the body of the table]
> > > > >
> > > > > > > > + _INIT_DCS_CMD(0x0E, 0x48),
> > > > > > > > +
> > > > > > > > + _INIT_DCS_CMD(0xE0, 0x00),
> > > > >
> > > > > > > > + _INIT_DCS_CMD(0X11),
> > > > >
> > > > > Also, at least this is mipi_dsi_dcs_exit_sleep_mode().
> > > > >
> > > > > > > > + /* T6: 120ms */
> > > > > > > > + _INIT_DELAY_CMD(120),
> > > > > > > > + _INIT_DCS_CMD(0X29),
> > > > >
> > > > > And this is mipi_dsi_dcs_set_display_on().
> > > > >
> > > > > Having a single table enourages people to put known commands into the
> > > > > table, the practice that must be frowned upon and forbidden.
> > > > >
> > > > > We have functions for some of the standard DCS commands. So, maybe
> > > > > instead of adding a single-table based approach we can improve
> > > > > mipi_dsi_generic_write_seq() to reduce the bloat. E.g. by moving the
> > > > > error handling to a common part of enable() / prepare() function.
> > > > >
> > > >
> > > > For this panel, I think it can also refer to how
> > > > panel-kingdisplay-kd097d04.c does. Create the table for init cmd data,
> > > > not what operation to use, and use mipi_dsi_generic_write_seq() when
> > > > looping through the table.
> > >
> > > Even more similar discussion:
> > >
> > > https://lore.kernel.org/r/CAD=FV=ugdbnvamjzwsovxybgikqcvw9jsrtbxhvg8_97ype...@mail.gmail.com
> >
> > It seems I skipped that thread.
> >
> > I'd still suggest a code-based solution compared to table-based one, for
> > the reasons I've outlined before. Having a tables puts a pressure on the
> > developer to put commands there for which we already have a
> > command-specific function.
>
> The problem is that with these panels that need big init sequences the
> code based solution is _a lot_ bigger. If it were a few bytes or a
> 1-2KB then fine, but when Hsin-Yi measured Linus W's attempt to move
> from a table to code it was 100K difference in code [1]. I would also
> say that having these long init sequences done as separate commands
> encourages people to skip checking the return values of each of the
> transfer functions and I don't love that idea.
>
> It would be ideal if these panels didn't need these long init
> sequences, but I don't have any inside knowledge here saying that they
> could be removed. So assume we can't get rid of the init sequences it
> feels like we have to find some way to make the tables work for at
> least the large chunks of init code and encourage people to make the
> tables readable...
>
For the init sequence of the panel from this patch, using the table
approach, we can still use mipi_dsi_generic_write_seq() and not invent
new macro or make the code complicated.

>
> [1] 
> https://lore.kernel.org/r/CAD=FV=UFa_AoJQvUT3BTiRs19WCA2xLVeQOU=+nyu_hae0_...@mail.gmail.com


Re: [PATCH v1 2/2] drm/panel: kd101ne3: add new panel driver

2024-04-23 Thread Hsin-Yi Wang
On Thu, Apr 18, 2024 at 7:11 AM Dmitry Baryshkov
 wrote:
>
> On Thu, Apr 18, 2024 at 09:11:37PM +0800, Hsin-Yi Wang wrote:
> > On Thu, Apr 18, 2024 at 7:46 PM Dmitry Baryshkov
> >  wrote:
> > >
> > > On Thu, Apr 18, 2024 at 04:15:48PM +0800, lvzhaoxiong wrote:
> > > > The kingdisplay panel is based on JD9365DA controller.
> > > > Add a driver for it.
> > > >
> > > > Signed-off-by: lvzhaoxiong 
> > > > ---
> > > >  drivers/gpu/drm/panel/Kconfig |   9 +
> > > >  drivers/gpu/drm/panel/Makefile|   1 +
> > > >  .../drm/panel/panel-kingdisplay-kd101ne3.c| 607 ++
> > > >  3 files changed, 617 insertions(+)
> > > >  create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > > >
> > > > diff --git a/drivers/gpu/drm/panel/Kconfig 
> > > > b/drivers/gpu/drm/panel/Kconfig
> > > > index 154f5bf82980..2c73086cf102 100644
> > > > --- a/drivers/gpu/drm/panel/Kconfig
> > > > +++ b/drivers/gpu/drm/panel/Kconfig
> > > > @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> > > > 24 bit RGB per pixel. It provides a MIPI DSI interface to
> > > > the host and has a built-in LED backlight.
> > > >
> > > > +config DRM_PANEL_KINGDISPLAY_KD101NE3
> > > > + tristate "Kingdisplay kd101ne3 panel"
> > > > + depends on OF
> > > > + depends on DRM_MIPI_DSI
> > > > + depends on BACKLIGHT_CLASS_DEVICE
> > > > + help
> > > > +   Say Y if you want to enable support for panels based on the
> > > > +   Kingdisplay kd101ne3 controller.
> > > > +
> > > >  config DRM_PANEL_LEADTEK_LTK050H3146W
> > > >   tristate "Leadtek LTK050H3146W panel"
> > > >   depends on OF
> > > > diff --git a/drivers/gpu/drm/panel/Makefile 
> > > > b/drivers/gpu/drm/panel/Makefile
> > > > index 24a02655d726..cbd414b98bb0 100644
> > > > --- a/drivers/gpu/drm/panel/Makefile
> > > > +++ b/drivers/gpu/drm/panel/Makefile
> > > > @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += 
> > > > panel-jdi-lpm102a188a.o
> > > >  obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> > > >  obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> > > >  obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += 
> > > > panel-kingdisplay-kd097d04.o
> > > > +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += 
> > > > panel-kingdisplay-kd101ne3.o
> > > >  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += 
> > > > panel-leadtek-ltk050h3146w.o
> > > >  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += 
> > > > panel-leadtek-ltk500hd1829.o
> > > >  obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > > > diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c 
> > > > b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > > > new file mode 100644
> > > > index ..dbf0992f8b81
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > > > @@ -0,0 +1,607 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * Panels based on the JD9365DA display controller.
> > > > + * Author: Zhaoxiong Lv 
> > > > + */
> > > > +
> > > > +#include 
> > > > +#include 
> > > > +#include 
> > > > +#include 
> > > > +#include 
> > > > +#include 
> > > > +
> > > > +#include 
> > > > +#include 
> > > > +#include 
> > > > +#include 
> > > > +
> > > > +#include 
> > > > +
> > > > +struct panel_desc {
> > > > + const struct drm_display_mode *modes;
> > > > + unsigned int bpc;
> > > > +
> > > > + /**
> > > > +  * @width_mm: width of the panel's active display area
> > > > +  * @height_mm: height of the panel's active display area
> > > > +  */
> > > > + struct {
> > > > + unsigned int width_mm;
> > > > + unsigned int height_mm;
> > >
> > > Please move to the declared mode;
> > >
> > > > + } size;
> > > > +
> >

Re: [PATCH v1 2/2] drm/panel: kd101ne3: add new panel driver

2024-04-18 Thread Hsin-Yi Wang
On Thu, Apr 18, 2024 at 7:46 PM Dmitry Baryshkov
 wrote:
>
> On Thu, Apr 18, 2024 at 04:15:48PM +0800, lvzhaoxiong wrote:
> > The kingdisplay panel is based on JD9365DA controller.
> > Add a driver for it.
> >
> > Signed-off-by: lvzhaoxiong 
> > ---
> >  drivers/gpu/drm/panel/Kconfig |   9 +
> >  drivers/gpu/drm/panel/Makefile|   1 +
> >  .../drm/panel/panel-kingdisplay-kd101ne3.c| 607 ++
> >  3 files changed, 617 insertions(+)
> >  create mode 100644 drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> >
> > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > index 154f5bf82980..2c73086cf102 100644
> > --- a/drivers/gpu/drm/panel/Kconfig
> > +++ b/drivers/gpu/drm/panel/Kconfig
> > @@ -297,6 +297,15 @@ config DRM_PANEL_KINGDISPLAY_KD097D04
> > 24 bit RGB per pixel. It provides a MIPI DSI interface to
> > the host and has a built-in LED backlight.
> >
> > +config DRM_PANEL_KINGDISPLAY_KD101NE3
> > + tristate "Kingdisplay kd101ne3 panel"
> > + depends on OF
> > + depends on DRM_MIPI_DSI
> > + depends on BACKLIGHT_CLASS_DEVICE
> > + help
> > +   Say Y if you want to enable support for panels based on the
> > +   Kingdisplay kd101ne3 controller.
> > +
> >  config DRM_PANEL_LEADTEK_LTK050H3146W
> >   tristate "Leadtek LTK050H3146W panel"
> >   depends on OF
> > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > index 24a02655d726..cbd414b98bb0 100644
> > --- a/drivers/gpu/drm/panel/Makefile
> > +++ b/drivers/gpu/drm/panel/Makefile
> > @@ -30,6 +30,7 @@ obj-$(CONFIG_DRM_PANEL_JDI_LPM102A188A) += 
> > panel-jdi-lpm102a188a.o
> >  obj-$(CONFIG_DRM_PANEL_JDI_R63452) += panel-jdi-fhd-r63452.o
> >  obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
> >  obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += 
> > panel-kingdisplay-kd097d04.o
> > +obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD101NE3) += 
> > panel-kingdisplay-kd101ne3.o
> >  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += 
> > panel-leadtek-ltk050h3146w.o
> >  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += 
> > panel-leadtek-ltk500hd1829.o
> >  obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> > diff --git a/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c 
> > b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > new file mode 100644
> > index ..dbf0992f8b81
> > --- /dev/null
> > +++ b/drivers/gpu/drm/panel/panel-kingdisplay-kd101ne3.c
> > @@ -0,0 +1,607 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Panels based on the JD9365DA display controller.
> > + * Author: Zhaoxiong Lv 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#include 
> > +
> > +struct panel_desc {
> > + const struct drm_display_mode *modes;
> > + unsigned int bpc;
> > +
> > + /**
> > +  * @width_mm: width of the panel's active display area
> > +  * @height_mm: height of the panel's active display area
> > +  */
> > + struct {
> > + unsigned int width_mm;
> > + unsigned int height_mm;
>
> Please move to the declared mode;
>
> > + } size;
> > +
> > + unsigned long mode_flags;
> > + enum mipi_dsi_pixel_format format;
> > + const struct panel_init_cmd *init_cmds;
> > + unsigned int lanes;
> > + bool discharge_on_disable;
> > + bool lp11_before_reset;
> > +};
> > +
> > +struct kingdisplay_panel {
> > + struct drm_panel base;
> > + struct mipi_dsi_device *dsi;
> > +
> > + const struct panel_desc *desc;
> > +
> > + enum drm_panel_orientation orientation;
> > + struct regulator *pp3300;
> > + struct gpio_desc *enable_gpio;
> > +};
> > +
> > +enum dsi_cmd_type {
> > + INIT_DCS_CMD,
> > + DELAY_CMD,
> > +};
> > +
> > +struct panel_init_cmd {
> > + enum dsi_cmd_type type;
> > + size_t len;
> > + const char *data;
> > +};
> > +
> > +#define _INIT_DCS_CMD(...) { \
> > + .type = INIT_DCS_CMD, \
> > + .len = sizeof((char[]){__VA_ARGS__}), \
> > + .data = (char[]){__VA_ARGS__} }
> > +
> > +#define _INIT_DELAY_CMD(...) { \
> > + .type = DELAY_CMD,\
> > + .len = sizeof((char[]){__VA_ARGS__}), \
> > + .data = (char[]){__VA_ARGS__} }
>
> This is the third panel driver using the same appoach. Can you use
> mipi_dsi_generic_write_seq() instead of the huge table? Or if you prefer
> the table, we should extract this framework to a common helper.
> (my preference is shifted towards mipi_dsi_generic_write_seq()).
>
The drawback of mipi_dsi_generic_write_seq() is that it can cause the
kernel size grows a lot since every sequence will be expanded.

Similar discussion in here:
https://lore.kernel.org/dri-devel/CAD=FV=Wju3WS45=EpXMUg7FjYDh3-=mvm_js7tf1tsaazbb...@mail.gmail.com/

This patch would increase the module size from 157K to 572K.

Re: [PATCH 3/3] drm-panel: If drm_panel_dp_aux_backlight() fails, don't fail panel probe

2024-03-25 Thread Hsin-Yi Wang
On Mon, Mar 25, 2024 at 2:57 PM Douglas Anderson  wrote:
>
> If we're using the AUX channel for eDP backlight and it fails to probe
> for some reason, let's _not_ fail the panel probe.
>
> At least one case where we could fail to init the backlight is because
> of a dead or physically missing panel. As talked about in detail in
> the earlier patch in this series, ("drm/panel-edp: If we fail to
> powerup/get EDID, use conservative timings"), this can cause the
> entire system's display pipeline to fail to come up and that's
> non-ideal.
>
> If we fail to init the backlight for some transitory reason, we should
> dig in and see if there's a way to fix this (perhaps retries?). Even
> in that case, though, having a panel whose backlight is stuck at 100%
> (the default, at least in the panel Samsung ATNA33XC20 I tested) is
> better than having no panel at all.
>
> Signed-off-by: Douglas Anderson 

Reviewed-by: Hsin-Yi Wang 

> ---
> If needed, I could split this into two patches: one for each of the
> two panels that use drm_panel_dp_aux_backlight(). Since they both go
> through drm-misc, though, it doesn't feel worth it.
>
>  drivers/gpu/drm/panel/panel-edp.c| 8 +++-
>  drivers/gpu/drm/panel/panel-samsung-atna33xc20.c | 9 +++--
>  2 files changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> b/drivers/gpu/drm/panel/panel-edp.c
> index 607cdd6feda9..0bf66d9dd5b8 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -944,8 +944,14 @@ static int panel_edp_probe(struct device *dev, const 
> struct panel_desc *desc,
> err = drm_panel_dp_aux_backlight(>base, panel->aux);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> +
> +   /*
> +* Warn if we get an error, but don't consider it fatal. 
> Having
> +* a panel where we can't control the backlight is better than
> +* no panel.
> +*/
> if (err)
> -   goto err_finished_pm_runtime;
> +   dev_warn(dev, "failed to register dp aux backlight: 
> %d\n", err);
> }
>
> drm_panel_add(>base);
> diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c 
> b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
> index 9c336c71562b..6828a4f24d14 100644
> --- a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
> +++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
> @@ -328,9 +328,14 @@ static int atana33xc20_probe(struct dp_aux_ep_device 
> *aux_ep)
> ret = drm_panel_dp_aux_backlight(>base, aux_ep->aux);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> +
> +   /*
> +* Warn if we get an error, but don't consider it fatal. Having
> +* a panel where we can't control the backlight is better than
> +* no panel.
> +*/
> if (ret)
> -   return dev_err_probe(dev, ret,
> -"failed to register dp aux backlight\n");
> +   dev_warn(dev, "failed to register dp aux backlight: %d\n", 
> ret);
>
> drm_panel_add(>base);
>
> --
> 2.44.0.396.g6e790dbe36-goog
>


Re: [PATCH 2/3] drm/panel-edp: If we fail to powerup/get EDID, use conservative timings

2024-03-25 Thread Hsin-Yi Wang
On Mon, Mar 25, 2024 at 2:57 PM Douglas Anderson  wrote:
>
> If at boot we fail to power up the eDP panel (most often happens if
> the eDP panel never asserts HPD to us) or if we are unable to read the
> EDID at bootup to figure out the panel's ID then let's use the
> conservative eDP panel powerup/powerdown timings but _not_ fail the
> probe.
>
> It might seem strange to _not_ fail the probe in this case since we
> were unable to powerup the panel and confirm it's there. However,
> there is a reason to do this. Specifically, if we fail to probe the
> panel then it really throws the whole display pipeline for loop. Most
> DRM subsystems are written so that they wait until all components
> (including the panel) have probed before they set everything up. When
> the panel doesn't come up then this never happens. As a side effect of
> not setting everything up then other display adapters don't get
> initialized. As a practical example, I can see that if I open up a
> sc7180-trogdor based Chromebook that's using the generic "edp-panel"
> and unplug the eDP panel that it causes the _external_ DP monitor not
> to function. This is obviously bad because it means that a device with
> a dead eDP panel becomes e-waste when it could instead still be given
> useful life with an external display.
>
> NOTES:
> - When we fail to probe like this, boot is a bit slow because we try
>   several times to power the panel up. This doesn't feel horrible
>   because it'll eventually work and the retries are known to help
>   bring some panels up.
> - In the case where we hit the condition of failing to power up, the
>   display will likely _never_ have a chance to work again until
>   reboot. Once the panel-edp pm_runtime resume function fails it
>   doesn't ever seem to retry. This is probably for the best given that
>   we don't have any real timing/modes. eDP isn't expected to be
>   "hotplugged" so this makes some sense.
> - It turns out that this makes panel-edp behave more similarly for
>   users of the generic "edp-panel" compatible string and the old fixed
>   panel compatible string. With the old fixed panel compatible string
>   we don't talk to the panel during probe so we'd actually behave much
>   the same way that we'll now behave for the generic "edp-panel".
>
> Signed-off-by: Douglas Anderson 

Reviewed-by: Hsin-Yi Wang 

> ---
>
>  drivers/gpu/drm/panel/panel-edp.c | 12 +++-
>  1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> b/drivers/gpu/drm/panel/panel-edp.c
> index 8a19fea90ddf..607cdd6feda9 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -808,7 +808,10 @@ static int generic_edp_panel_probe(struct device *dev, 
> struct panel_edp *panel)
> /* Power the panel on so we can read the EDID */
> ret = pm_runtime_get_sync(dev);
> if (ret < 0) {
> -   dev_err(dev, "Couldn't power on panel to read EDID: %d\n", 
> ret);
> +   dev_err(dev,
> +   "Couldn't power on panel to ID it; using conservative 
> timings: %d\n",
> +   ret);
> +   panel_edp_set_conservative_timings(panel, desc);
> goto exit;
> }
>
> @@ -816,8 +819,8 @@ static int generic_edp_panel_probe(struct device *dev, 
> struct panel_edp *panel)
> if (base_block) {
> panel_id = drm_edid_get_panel_id(base_block);
> } else {
> -   dev_err(dev, "Couldn't identify panel via EDID\n");
> -   ret = -EIO;
> +   dev_err(dev, "Couldn't read EDID for ID; using conservative 
> timings\n");
> +   panel_edp_set_conservative_timings(panel, desc);
> goto exit;
> }
> drm_edid_decode_panel_id(panel_id, vend, _id);
> @@ -844,12 +847,11 @@ static int generic_edp_panel_probe(struct device *dev, 
> struct panel_edp *panel)
> desc->delay = *panel->detected_panel->delay;
> }
>
> -   ret = 0;
>  exit:
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
>
> -   return ret;
> +   return 0;
>  }
>
>  static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
> --
> 2.44.0.396.g6e790dbe36-goog
>


Re: [PATCH 1/3] drm/panel-edp: Abstract out function to set conservative timings

2024-03-25 Thread Hsin-Yi Wang
On Mon, Mar 25, 2024 at 2:56 PM Douglas Anderson  wrote:
>
> If we're using the generic "edp-panel" compatible string and we fail
> to detect an eDP panel then we fall back to conservative timings for
> powering up and powering down the panel. Abstract out the function for
> setting these timings so it can be used in future patches.
>
> No functional change expected--just code movement.
>
> Signed-off-by: Douglas Anderson 

Reviewed-by: Hsin-Yi Wang 

> ---
>
>  drivers/gpu/drm/panel/panel-edp.c | 40 +++
>  1 file changed, 20 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> b/drivers/gpu/drm/panel/panel-edp.c
> index c4f851200aa2..8a19fea90ddf 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -760,6 +760,25 @@ static void panel_edp_parse_panel_timing_node(struct 
> device *dev,
>
>  static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const 
> struct drm_edid *edid);
>
> +static void panel_edp_set_conservative_timings(struct panel_edp *panel, 
> struct panel_desc *desc)
> +{
> +   /*
> +* It's highly likely that the panel will work if we use very
> +* conservative timings, so let's do that.
> +*
> +* Nearly all panels have a "unprepare" delay of 500 ms though
> +* there are a few with 1000. Let's stick 2000 in just to be
> +* super conservative.
> +*
> +* An "enable" delay of 80 ms seems the most common, but we'll
> +* throw in 200 ms to be safe.
> +*/
> +   desc->delay.unprepare = 2000;
> +   desc->delay.enable = 200;
> +
> +   panel->detected_panel = ERR_PTR(-EINVAL);
> +}
> +
>  static int generic_edp_panel_probe(struct device *dev, struct panel_edp 
> *panel)
>  {
> struct panel_desc *desc;
> @@ -816,26 +835,7 @@ static int generic_edp_panel_probe(struct device *dev, 
> struct panel_edp *panel)
> dev_warn(dev,
>  "Unknown panel %s %#06x, using conservative 
> timings\n",
>  vend, product_id);
> -
> -   /*
> -* It's highly likely that the panel will work if we use very
> -* conservative timings, so let's do that. We already know 
> that
> -* the HPD-related delays must have worked since we got this
> -* far, so we really just need the "unprepare" / "enable"
> -* delays. We don't need "prepare_to_enable" since that
> -* overlaps the "enable" delay anyway.
> -*
> -* Nearly all panels have a "unprepare" delay of 500 ms though
> -* there are a few with 1000. Let's stick 2000 in just to be
> -* super conservative.
> -*
> -* An "enable" delay of 80 ms seems the most common, but we'll
> -* throw in 200 ms to be safe.
> -*/
> -   desc->delay.unprepare = 2000;
> -   desc->delay.enable = 200;
> -
> -   panel->detected_panel = ERR_PTR(-EINVAL);
> +   panel_edp_set_conservative_timings(panel, desc);
> } else {
> dev_info(dev, "Detected %s %s (%#06x)\n",
>  vend, panel->detected_panel->ident.name, product_id);
> --
> 2.44.0.396.g6e790dbe36-goog
>


Re: [PATCH v6 2/5] drm/edid: Add a function to match EDID with identity

2024-03-08 Thread Hsin-Yi Wang
On Fri, Mar 8, 2024 at 12:07 AM Jani Nikula  wrote:
>
> On Thu, 07 Mar 2024, Hsin-Yi Wang  wrote:
> > Create a type drm_edid_ident as the identity of an EDID. Currently it
> > contains panel id and monitor name.
> >
> > Create a function that can match a given EDID and an identity:
> > 1. Reject if the panel id doesn't match.
> > 2. If name is not null in identity, try to match it in the detailed timing
> >blocks. Note that some panel vendors put the monitor name after
> >    EDID_DETAIL_MONITOR_STRING.
> >
> > Signed-off-by: Hsin-Yi Wang 
>
> Reviewed-by: Jani Nikula 
>
> The series seems good to go. Thanks Hsin-Yi and Douglas for the
> constructive collaboration! I believe the end result is better now.
>

Thanks for everyone's suggestions to make it better.

> Thanks,
> Jani.
>
> --
> Jani Nikula, Intel


[PATCH v6 2/5] drm/edid: Add a function to match EDID with identity

2024-03-07 Thread Hsin-Yi Wang
Create a type drm_edid_ident as the identity of an EDID. Currently it
contains panel id and monitor name.

Create a function that can match a given EDID and an identity:
1. Reject if the panel id doesn't match.
2. If name is not null in identity, try to match it in the detailed timing
   blocks. Note that some panel vendors put the monitor name after
   EDID_DETAIL_MONITOR_STRING.

Signed-off-by: Hsin-Yi Wang 
---
v5->v6: finalize the trailing white space and/or NUL decision:
Allow only white space before \n.
---
 drivers/gpu/drm/drm_edid.c | 65 ++
 include/drm/drm_edid.h |  9 ++
 2 files changed, 74 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 284255a0315e..58fe35058181 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -100,6 +100,11 @@ struct detailed_mode_closure {
int modes;
 };
 
+struct drm_edid_match_closure {
+   const struct drm_edid_ident *ident;
+   bool matched;
+};
+
 #define LEVEL_DMT  0
 #define LEVEL_GTF  1
 #define LEVEL_GTF2 2
@@ -5408,6 +5413,66 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector 
*connector, const u8 *db)
connector->audio_latency[0], connector->audio_latency[1]);
 }
 
+static void
+match_identity(const struct detailed_timing *timing, void *data)
+{
+   struct drm_edid_match_closure *closure = data;
+   unsigned int i;
+   const char *name = closure->ident->name;
+   unsigned int name_len = strlen(name);
+   const char *desc = timing->data.other_data.data.str.str;
+   unsigned int desc_len = 
ARRAY_SIZE(timing->data.other_data.data.str.str);
+
+   if (name_len > desc_len ||
+   !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) ||
+ is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING)))
+   return;
+
+   if (strncmp(name, desc, name_len))
+   return;
+
+   for (i = name_len; i < desc_len; i++) {
+   if (desc[i] == '\n')
+   break;
+   /* Allow white space before EDID string terminator. */
+   if (!isspace(desc[i]))
+   return;
+   }
+
+   closure->matched = true;
+}
+
+/**
+ * drm_edid_match - match drm_edid with given identity
+ * @drm_edid: EDID
+ * @ident: the EDID identity to match with
+ *
+ * Check if the EDID matches with the given identity.
+ *
+ * Return: True if the given identity matched with EDID, false otherwise.
+ */
+bool drm_edid_match(const struct drm_edid *drm_edid,
+   const struct drm_edid_ident *ident)
+{
+   if (!drm_edid || drm_edid_get_panel_id(drm_edid) != ident->panel_id)
+   return false;
+
+   /* Match with name only if it's not NULL. */
+   if (ident->name) {
+   struct drm_edid_match_closure closure = {
+   .ident = ident,
+   .matched = false,
+   };
+
+   drm_for_each_detailed_block(drm_edid, match_identity, );
+
+   return closure.matched;
+   }
+
+   return true;
+}
+EXPORT_SYMBOL(drm_edid_match);
+
 static void
 monitor_name(const struct detailed_timing *timing, void *data)
 {
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 8b233865b085..5e3fc8c83a31 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -367,6 +367,13 @@ struct edid {
u8 checksum;
 } __attribute__((packed));
 
+/* EDID matching */
+struct drm_edid_ident {
+   /* ID encoded by drm_edid_encode_panel_id() */
+   u32 panel_id;
+   const char *name;
+};
+
 #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
 
 /* Short Audio Descriptor */
@@ -567,6 +574,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
 const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter);
 u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
+bool drm_edid_match(const struct drm_edid *drm_edid,
+   const struct drm_edid_ident *ident);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v6 4/5] drm/panel-edp: Match edp_panels with panel identity

2024-03-07 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. When matching generic edp
panels, we should first match with both panel identity, which contains both
panel id and panel name. If not found, match with panel id only.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v5->v6: add some comments.
---
 drivers/gpu/drm/panel/panel-edp.c | 50 +++
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index fe51680feb61..7f749b17df85 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -210,15 +210,12 @@ struct panel_desc {
  * struct edp_panel_entry - Maps panel ID to delay / panel name.
  */
 struct edp_panel_entry {
-   /** @panel_id: 32-bit ID for panel, encoded with 
drm_edid_encode_panel_id(). */
-   u32 panel_id;
+   /** @ident: edid identity used for panel matching. */
+   const struct drm_edid_ident ident;
 
/** @delay: The power sequencing delays needed for this panel. */
const struct panel_delay *delay;
 
-   /** @name: Name of this panel (for printing to logs). */
-   const char *name;
-
/** @override_edid_mode: Override the mode obtained by edid. */
const struct drm_display_mode *override_edid_mode;
 };
@@ -691,7 +688,7 @@ static int detected_panel_show(struct seq_file *s, void 
*data)
else if (!p->detected_panel)
seq_puts(s, "HARDCODED\n");
else
-   seq_printf(s, "%s\n", p->detected_panel->name);
+   seq_printf(s, "%s\n", p->detected_panel->ident.name);
 
return 0;
 }
@@ -761,7 +758,7 @@ static void panel_edp_parse_panel_timing_node(struct device 
*dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
 }
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const struct 
drm_edid *edid);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
@@ -799,7 +796,6 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
base_block = drm_edid_read_base_block(panel->ddc);
if (base_block) {
panel_id = drm_edid_get_panel_id(base_block);
-   drm_edid_free(base_block);
} else {
dev_err(dev, "Couldn't identify panel via EDID\n");
ret = -EIO;
@@ -807,7 +803,9 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
}
drm_edid_decode_panel_id(panel_id, vend, _id);
 
-   panel->detected_panel = find_edp_panel(panel_id);
+   panel->detected_panel = find_edp_panel(panel_id, base_block);
+
+   drm_edid_free(base_block);
 
/*
 * We're using non-optimized timings and want it really obvious that
@@ -840,7 +838,7 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
panel->detected_panel = ERR_PTR(-EINVAL);
} else {
dev_info(dev, "Detected %s %s (%#06x)\n",
-vend, panel->detected_panel->name, product_id);
+vend, panel->detected_panel->ident.name, product_id);
 
/* Update the delay; everything else comes from EDID */
desc->delay = *panel->detected_panel->delay;
@@ -1954,17 +1952,21 @@ static const struct panel_delay 
delay_200_500_e50_po2e200 = {
 
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
-   .name = _name, \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   }, \
.delay = _delay \
 }
 
 #define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
 { \
-   .name = _name, \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   }, \
.delay = _delay, \
.override_edid_mode = _mode \
 }
@@ -2111,15 +2113,25 @@ static const struct edp_panel_entry edp_panels[] = {
{ /* sentinal */ }
 };
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
+s

[PATCH v6 5/5] drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-03-07 Thread Hsin-Yi Wang
There are 2 different AUO panels using the same panel id. One of the
variants requires using overridden modes to resolve glitching issue as
described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
Other variants should use the modes parsed from EDID.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v5->v6: remove trailing white space.
---
 drivers/gpu/drm/panel/panel-edp.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 7f749b17df85..c7f81dd9023f 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1009,6 +1009,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAN04.0"),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, _200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v6 3/5] drm/edid: Match edid quirks with identity

2024-03-07 Thread Hsin-Yi Wang
Currently edid quirks are matched by panel id only.

Modify it to match with identity so it's easier to be extended
for more complex matching if required.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Jani Nikula 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/drm_edid.c | 13 -
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 58fe35058181..4abc50516cda 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -112,13 +112,15 @@ struct drm_edid_match_closure {
 
 #define EDID_QUIRK(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _quirks) \
 { \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, \
+vend_chr_2, product_id), \
+   }, \
.quirks = _quirks \
 }
 
 static const struct edid_quirk {
-   u32 panel_id;
+   const struct drm_edid_ident ident;
u32 quirks;
 } edid_quirk_list[] = {
/* Acer AL1706 */
@@ -2883,16 +2885,17 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  * @drm_edid: EDID to process
  *
  * This tells subsequent routines what fixes they need to apply.
+ *
+ * Return: A u32 represents the quirks to apply.
  */
 static u32 edid_get_quirks(const struct drm_edid *drm_edid)
 {
-   u32 panel_id = drm_edid_get_panel_id(drm_edid);
const struct edid_quirk *quirk;
int i;
 
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
quirk = _quirk_list[i];
-   if (quirk->panel_id == panel_id)
+   if (drm_edid_match(drm_edid, >ident))
return quirk->quirks;
}
 
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v6 1/5] drm_edid: Add a function to get EDID base block

2024-03-07 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. Besides panel id, now we need
more information from the EDID base block to distinguish these panel
variants.

Add drm_edid_read_base_block() to return the EDID base block, which is
wrapped in struct drm_edid.

Caller can further use it to get panel id or check if the block contains
certain strings, such as panel name.

Merge drm_edid_get_panel_id() and edid_extract_panel_id() into one
function.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
Reviewed-by: Jani Nikula 
---
v5->v6: 
1. squash v5 2/6 into this patch.
2. check edid size.
---
 drivers/gpu/drm/drm_edid.c| 71 ++-
 drivers/gpu/drm/panel/panel-edp.c |  8 +++-
 include/drm/drm_edid.h|  3 +-
 3 files changed, 50 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 1ad94473e400..284255a0315e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2743,8 +2743,27 @@ const struct drm_edid *drm_edid_read(struct 
drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_edid_read);
 
-static u32 edid_extract_panel_id(const struct edid *edid)
+/**
+ * drm_edid_get_panel_id - Get a panel's ID from EDID
+ * @drm_edid: EDID that contains panel ID.
+ *
+ * This function uses the first block of the EDID of a panel and (assuming
+ * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
+ * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
+ * supposed to be different for each different modem of panel.
+ *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID. Return 0 if the EDID size is less than a base block.
+ */
+u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid)
 {
+   const struct edid *edid = drm_edid->edid;
+
+   if (drm_edid->size < EDID_LENGTH)
+   return 0;
+
/*
 * We represent the ID as a 32-bit number so it can easily be compared
 * with "==".
@@ -2762,60 +2781,54 @@ static u32 edid_extract_panel_id(const struct edid 
*edid)
   (u32)edid->mfg_id[1] << 16   |
   (u32)EDID_PRODUCT_ID(edid);
 }
+EXPORT_SYMBOL(drm_edid_get_panel_id);
 
 /**
- * drm_edid_get_panel_id - Get a panel's ID through DDC
+ * drm_edid_read_base_block - Get a panel's EDID base block
  * @adapter: I2C adapter to use for DDC
  *
- * This function reads the first block of the EDID of a panel and (assuming
- * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
- * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
- * supposed to be different for each different modem of panel.
+ * This function returns the drm_edid containing the first block of the EDID of
+ * a panel.
  *
  * This function is intended to be used during early probing on devices where
  * more than one panel might be present. Because of its intended use it must
- * assume that the EDID of the panel is correct, at least as far as the ID
- * is concerned (in other words, we don't process any overrides here).
+ * assume that the EDID of the panel is correct, at least as far as the base
+ * block is concerned (in other words, we don't process any overrides here).
+ *
+ * Caller should call drm_edid_free() after use.
  *
  * NOTE: it's expected that this function and drm_do_get_edid() will both
  * be read the EDID, but there is no caching between them. Since we're only
  * reading the first block, hopefully this extra overhead won't be too big.
  *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
+ * WARNING: Only use this function when the connector is unknown. For example,
+ * during the early probe of panel. The EDID read from the function is 
temporary
+ * and should be replaced by the full EDID returned from other drm_edid_read.
+ *
+ * Return: Pointer to allocated EDID base block, or NULL on any failure.
  */
-
-u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
+const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter)
 {
enum edid_block_status status;
void *base_block;
-   u32 panel_id = 0;
-
-   /*
-* There are no manufacturer IDs of 0, so if there is a problem reading
-* the EDID then we'll just return 0.
-*/
 
base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
if (!base_block)
-   return 0;
+   return NULL;
 
status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter);
 
edid_block_

[PATCH v6 0/5] Match panel with identity

2024-03-07 Thread Hsin-Yi Wang
This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
product id. One of them requires an overridden mode, while the other should
use the mode directly from edid.

Match the panel for identity (id and name). If not found, fallback to match
id.

v1: https://lore.kernel.org/lkml/20240223223958.3887423-1-hsi...@chromium.org
v2: https://lore.kernel.org/lkml/20240228011133.1238439-1-hsi...@chromium.org
v3: https://lore.kernel.org/lkml/20240304195214.14563-1-hsi...@chromium.org
v4: https://lore.kernel.org/lkml/20240306004347.974304-1-hsi...@chromium.org/
v5: https://lore.kernel.org/lkml/20240306200353.1436198-1-hsi...@chromium.org/

Hsin-Yi Wang (5):
  drm_edid: Add a function to get EDID base block
  drm/edid: Add a function to match EDID with identity
  drm/edid: Match edid quirks with identity
  drm/panel-edp: Match edp_panels with panel identity
  drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

 drivers/gpu/drm/drm_edid.c| 147 +++---
 drivers/gpu/drm/panel/panel-edp.c |  73 ++-
 include/drm/drm_edid.h|  12 ++-
 3 files changed, 177 insertions(+), 55 deletions(-)

-- 
2.44.0.278.ge034bb2e1d-goog



Re: [PATCH v5 6/6] drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-03-07 Thread Hsin-Yi Wang
On Thu, Mar 7, 2024 at 5:28 AM Jani Nikula  wrote:
>
> On Wed, 06 Mar 2024, Doug Anderson  wrote:
> > Hi,
> >
> > On Wed, Mar 6, 2024 at 12:04 PM Hsin-Yi Wang  wrote:
> >>
> >> @@ -1009,6 +1009,19 @@ static const struct panel_desc auo_b101ean01 = {
> >> },
> >>  };
> >>
> >> +static const struct drm_display_mode auo_b116xa3_mode = {
> >> +   .clock = 70589,
> >> +   .hdisplay = 1366,
> >> +   .hsync_start = 1366 + 40,
> >> +   .hsync_end = 1366 + 40 + 40,
> >> +   .htotal = 1366 + 40 + 40 + 32,
> >> +   .vdisplay = 768,
> >> +   .vsync_start = 768 + 10,
> >> +   .vsync_end = 768 + 10 + 12,
> >> +   .vtotal = 768 + 10 + 12 + 6,
> >> +   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
> >> +};
> >> +
> >>  static const struct drm_display_mode auo_b116xak01_mode = {
> >> .clock = 69300,
> >> .hdisplay = 1366,
> >> @@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] = {
> >> EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
> >> "B116XAN06.1"),
> >> EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
> >> "B116XTN02.5"),
> >> EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
> >> "B140HAN04.0"),
> >> -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> >> "B116XAK01.0"),
> >> +   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> >> "B116XAN04.0"),
> >> +   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> >> "B116XAK01.0 ",
> >
> > Remove the trailing space from the string above now?
>
> Maybe it actually needs to be considered part of the name; see my other
> reply in the earlier patch.
>
I randomly checked 3 of the AUO panels that I had a datasheet with,
and all of them have a white space padding before \n.
The descriptor of that field is marked as "Reserved for definition",
unlike other characters, representing the name, which are marked with
"Manufacture P/N".

For this example, do we still want to consider the white space part of
the name? I know they didn't follow the spec exactly.

> >
> > Aside from that:
> >
> > Reviewed-by: Douglas Anderson 
>
> --
> Jani Nikula, Intel


Re: [PATCH v5 3/6] drm/edid: Add a function to match EDID with identity

2024-03-07 Thread Hsin-Yi Wang
On Thu, Mar 7, 2024 at 5:20 AM Jani Nikula  wrote:
>
> On Wed, 06 Mar 2024, Doug Anderson  wrote:
> > Hi,
> >
> > On Wed, Mar 6, 2024 at 4:20 PM Hsin-Yi Wang  wrote:
> >>
> >> On Wed, Mar 6, 2024 at 3:30 PM Doug Anderson  wrote:
> >> >
> >> > Hi,
> >> >
> >> > On Wed, Mar 6, 2024 at 12:04 PM Hsin-Yi Wang  wrote:
> >> > >
> >> > > +static void
> >> > > +match_identity(const struct detailed_timing *timing, void *data)
> >> > > +{
> >> > > +   struct drm_edid_match_closure *closure = data;
> >> > > +   unsigned int i;
> >> > > +   const char *name = closure->ident->name;
> >> > > +   unsigned int name_len = strlen(name);
> >> > > +   const char *desc = timing->data.other_data.data.str.str;
> >> > > +   unsigned int desc_len = 
> >> > > ARRAY_SIZE(timing->data.other_data.data.str.str);
> >> > > +
> >> > > +   if (name_len > desc_len ||
> >> > > +   !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) 
> >> > > ||
> >> > > + is_display_descriptor(timing, 
> >> > > EDID_DETAIL_MONITOR_STRING)))
> >> > > +   return;
> >> > > +
> >> > > +   if (strncmp(name, desc, name_len))
> >> > > +   return;
> >> > > +
> >> > > +   /* Allow trailing white spaces and \0. */
> >> > > +   for (i = name_len; i < desc_len; i++) {
> >> > > +   if (desc[i] == '\n')
> >> > > +   break;
> >> > > +   if (!isspace(desc[i]) && !desc[i])
> >> > > +   return;
> >> > > +   }
> >> >
> >> > If my code analysis is correct, I think you'll reject the case where:
> >> >
> >> > name = "foo"
> >> > desc[13] = "foo \0"
> >> >
> >> > ...but you'll accept these cases:
> >> >
> >> > desc[13] = "foo \n"
> >> > desc[13] = "foo \0\0\0\0\0\0\0\0\0"
> >> >
> >> > It somehow seems weird to me that a '\n' terminates the string but not a 
> >> > '\0'.
> >>
> >> I'm also not sure about \0... based on
> >> https://git.linuxtv.org/edid-decode.git/tree/parse-base-block.cpp#n493,
> >> they use \n as terminator. Maybe we should also reject \0 before\n?
> >> Since it's not printable.
> >
> > Ah, OK. I guess the EDID spec simply doesn't allow for '\0' in there.
> > I guess in that case I'd prefer simply removing the code to handle
> > '\0' instead of treating it like space until we see some actual need
> > for it. So just get rid of the "!desc[i]" case?
>
> The spec text, similar for both EDID_DETAIL_MONITOR_NAME and
> EDID_DETAIL_MONITOR_STRING:
>
> Up to 13 alphanumeric characters (using ASCII codes) may be used
> to define the model name of the display product. The data shall
> be sequenced such that the 1st byte (ASCII code) = the 1st
> character, the 2nd byte (ASCII code) = the 2nd character,
> etc. If there are less than 13 characters in the string, then
> terminate the display product name string with ASCII code ‘0Ah’
> (line feed) and pad the unused bytes in the field with ASCII
> code ‘20h’ (space).
>
> In theory, only checking for '\n' for termination should be enough, and
> this is what drm_edid_get_monitor_name() does. If there's a space
> *before* that, it should be considered part of the name, and not
> ignored. (So my suggestion in reply to the previous version is wrong.)
>
> However, since the match name uses NUL termination, maybe we should
> ignore NULs *before* '\n'? Like so:
>
> for (i = name_len; i < desc_len; i++) {
> if (desc[i] == '\n')
> break;
> if (!desc[i])
> return;
> }
>
Allow trailing white spaces so we don't need to add the trailing white
space in edp_panel_entry.

https://lore.kernel.org/lkml/caa8ejpr7lhvqegxhbfq8knn0lgduv19cw0i04qvuz51tjes...@mail.gmail.com/

>
> BR,
> Jani.
>
>
> >
> > -Doug
>
> --
> Jani Nikula, Intel


Re: [PATCH v5 3/6] drm/edid: Add a function to match EDID with identity

2024-03-06 Thread Hsin-Yi Wang
On Wed, Mar 6, 2024 at 3:30 PM Doug Anderson  wrote:
>
> Hi,
>
> On Wed, Mar 6, 2024 at 12:04 PM Hsin-Yi Wang  wrote:
> >
> > +static void
> > +match_identity(const struct detailed_timing *timing, void *data)
> > +{
> > +   struct drm_edid_match_closure *closure = data;
> > +   unsigned int i;
> > +   const char *name = closure->ident->name;
> > +   unsigned int name_len = strlen(name);
> > +   const char *desc = timing->data.other_data.data.str.str;
> > +   unsigned int desc_len = 
> > ARRAY_SIZE(timing->data.other_data.data.str.str);
> > +
> > +   if (name_len > desc_len ||
> > +   !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) ||
> > + is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING)))
> > +   return;
> > +
> > +   if (strncmp(name, desc, name_len))
> > +   return;
> > +
> > +   /* Allow trailing white spaces and \0. */
> > +   for (i = name_len; i < desc_len; i++) {
> > +   if (desc[i] == '\n')
> > +   break;
> > +   if (!isspace(desc[i]) && !desc[i])
> > +   return;
> > +   }
>
> If my code analysis is correct, I think you'll reject the case where:
>
> name = "foo"
> desc[13] = "foo \0"
>
> ...but you'll accept these cases:
>
> desc[13] = "foo \n"
> desc[13] = "foo \0\0\0\0\0\0\0\0\0"
>
> It somehow seems weird to me that a '\n' terminates the string but not a '\0'.

I'm also not sure about \0... based on
https://git.linuxtv.org/edid-decode.git/tree/parse-base-block.cpp#n493,
they use \n as terminator. Maybe we should also reject \0 before\n?
Since it's not printable.

>
> I would have done:
>
>   for (i = name_len; i < desc_len; i++) {
>   /* Consider \n or \0 to terminate the string */
>   if (desc[i] == '\n' || desc[i] == '\0')
>   break;
>   /* OK for spaces at the end, but non-space is a fail */
>   if (!isspace(desc[i]))
>   return;
>   }
>
>
> > @@ -367,6 +367,12 @@ struct edid {
> > u8 checksum;
> >  } __attribute__((packed));
> >
> > +/* EDID matching */
> > +struct drm_edid_ident {
> > +   u32 panel_id;
> > +   const char *name;
>
> Might not hurt to have a comment for panel_id saying that it's encoded
> by drm_edid_encode_panel_id() so it's obvious what this random u32 is.
>
>
> -Doug


[PATCH v5 5/6] drm/panel-edp: Match edp_panels with panel identity

2024-03-06 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. When matching generic edp
panels, we should first match with both panel identity, which contains both
panel id and panel name. If not found, match with panel id only.

Signed-off-by: Hsin-Yi Wang 
---
v5: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 45 ---
 1 file changed, 24 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index fe51680feb61..772bf6011d79 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -210,15 +210,12 @@ struct panel_desc {
  * struct edp_panel_entry - Maps panel ID to delay / panel name.
  */
 struct edp_panel_entry {
-   /** @panel_id: 32-bit ID for panel, encoded with 
drm_edid_encode_panel_id(). */
-   u32 panel_id;
+   /** @ident: edid identity used for panel matching. */
+   const struct drm_edid_ident ident;
 
/** @delay: The power sequencing delays needed for this panel. */
const struct panel_delay *delay;
 
-   /** @name: Name of this panel (for printing to logs). */
-   const char *name;
-
/** @override_edid_mode: Override the mode obtained by edid. */
const struct drm_display_mode *override_edid_mode;
 };
@@ -691,7 +688,7 @@ static int detected_panel_show(struct seq_file *s, void 
*data)
else if (!p->detected_panel)
seq_puts(s, "HARDCODED\n");
else
-   seq_printf(s, "%s\n", p->detected_panel->name);
+   seq_printf(s, "%s\n", p->detected_panel->ident.name);
 
return 0;
 }
@@ -761,7 +758,7 @@ static void panel_edp_parse_panel_timing_node(struct device 
*dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
 }
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const struct 
drm_edid *edid);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
@@ -799,7 +796,6 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
base_block = drm_edid_read_base_block(panel->ddc);
if (base_block) {
panel_id = drm_edid_get_panel_id(base_block);
-   drm_edid_free(base_block);
} else {
dev_err(dev, "Couldn't identify panel via EDID\n");
ret = -EIO;
@@ -807,7 +803,9 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
}
drm_edid_decode_panel_id(panel_id, vend, _id);
 
-   panel->detected_panel = find_edp_panel(panel_id);
+   panel->detected_panel = find_edp_panel(panel_id, base_block);
+
+   drm_edid_free(base_block);
 
/*
 * We're using non-optimized timings and want it really obvious that
@@ -840,7 +838,7 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
panel->detected_panel = ERR_PTR(-EINVAL);
} else {
dev_info(dev, "Detected %s %s (%#06x)\n",
-vend, panel->detected_panel->name, product_id);
+vend, panel->detected_panel->ident.name, product_id);
 
/* Update the delay; everything else comes from EDID */
desc->delay = *panel->detected_panel->delay;
@@ -1954,17 +1952,21 @@ static const struct panel_delay 
delay_200_500_e50_po2e200 = {
 
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
-   .name = _name, \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   }, \
.delay = _delay \
 }
 
 #define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
 { \
-   .name = _name, \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   }, \
.delay = _delay, \
.override_edid_mode = _mode \
 }
@@ -2111,15 +2113,16 @@ static const struct edp_panel_entry edp_panels[] = {
{ /* sentinal */ }
 };
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
+static const struct edp_panel_entr

[PATCH v5 4/6] drm/edid: Match edid quirks with identity

2024-03-06 Thread Hsin-Yi Wang
Currently edid quirks are matched by panel id only.

Modify it to match with identity so it's easier to be extended
for more complex matching if required.

Suggested-by: Jani Nikula 
Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Jani Nikula 
---
v5: no change
---
 drivers/gpu/drm/drm_edid.c | 13 -
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 29ef35ebee32..f9e4dacd7255 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -112,13 +112,15 @@ struct drm_edid_match_closure {
 
 #define EDID_QUIRK(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _quirks) \
 { \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, \
+vend_chr_2, product_id), \
+   }, \
.quirks = _quirks \
 }
 
 static const struct edid_quirk {
-   u32 panel_id;
+   const struct drm_edid_ident ident;
u32 quirks;
 } edid_quirk_list[] = {
/* Acer AL1706 */
@@ -2880,16 +2882,17 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  * @drm_edid: EDID to process
  *
  * This tells subsequent routines what fixes they need to apply.
+ *
+ * Return: A u32 represents the quirks to apply.
  */
 static u32 edid_get_quirks(const struct drm_edid *drm_edid)
 {
-   u32 panel_id = drm_edid_get_panel_id(drm_edid);
const struct edid_quirk *quirk;
int i;
 
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
quirk = _quirk_list[i];
-   if (quirk->panel_id == panel_id)
+   if (drm_edid_match(drm_edid, >ident))
return quirk->quirks;
}
 
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v5 6/6] drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-03-06 Thread Hsin-Yi Wang
There are 2 different AUO panels using the same panel id. One of the
variants requires using overridden modes to resolve glitching issue as
described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
Other variants should use the modes parsed from EDID.

Signed-off-by: Hsin-Yi Wang 
---
v5: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 772bf6011d79..e3de55314bda 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1009,6 +1009,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAN04.0"),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0 ",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, _200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v5 3/6] drm/edid: Add a function to match EDID with identity

2024-03-06 Thread Hsin-Yi Wang
Create a type drm_edid_ident as the identity of an EDID. Currently it
contains panel id and monitor name.

Create a function that can match a given EDID and an identity:
1. Reject if the panel id doesn't match.
2. If name is not null in identity, try to match it in the detailed timing
   blocks. Note that some panel vendors put the monitor name after
   EDID_DETAIL_MONITOR_STRING.

Signed-off-by: Hsin-Yi Wang 
---
v4->v5: use strncmp, change function/variable names.
---
 drivers/gpu/drm/drm_edid.c | 65 ++
 include/drm/drm_edid.h |  8 +
 2 files changed, 73 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index febe374fa969..29ef35ebee32 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -100,6 +100,11 @@ struct detailed_mode_closure {
int modes;
 };
 
+struct drm_edid_match_closure {
+   const struct drm_edid_ident *ident;
+   bool matched;
+};
+
 #define LEVEL_DMT  0
 #define LEVEL_GTF  1
 #define LEVEL_GTF2 2
@@ -5405,6 +5410,66 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector 
*connector, const u8 *db)
connector->audio_latency[0], connector->audio_latency[1]);
 }
 
+static void
+match_identity(const struct detailed_timing *timing, void *data)
+{
+   struct drm_edid_match_closure *closure = data;
+   unsigned int i;
+   const char *name = closure->ident->name;
+   unsigned int name_len = strlen(name);
+   const char *desc = timing->data.other_data.data.str.str;
+   unsigned int desc_len = 
ARRAY_SIZE(timing->data.other_data.data.str.str);
+
+   if (name_len > desc_len ||
+   !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) ||
+ is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING)))
+   return;
+
+   if (strncmp(name, desc, name_len))
+   return;
+
+   /* Allow trailing white spaces and \0. */
+   for (i = name_len; i < desc_len; i++) {
+   if (desc[i] == '\n')
+   break;
+   if (!isspace(desc[i]) && !desc[i])
+   return;
+   }
+
+   closure->matched = true;
+}
+
+/**
+ * drm_edid_match - match drm_edid with given identity
+ * @drm_edid: EDID
+ * @ident: the EDID identity to match with
+ *
+ * Check if the EDID matches with the given identity.
+ *
+ * Return: True if the given identity matched with EDID, false otherwise.
+ */
+bool drm_edid_match(const struct drm_edid *drm_edid,
+   const struct drm_edid_ident *ident)
+{
+   if (!drm_edid || drm_edid_get_panel_id(drm_edid) != ident->panel_id)
+   return false;
+
+   /* Match with name only if it's not NULL. */
+   if (ident->name) {
+   struct drm_edid_match_closure closure = {
+   .ident = ident,
+   .matched = false,
+   };
+
+   drm_for_each_detailed_block(drm_edid, match_identity, );
+
+   return closure.matched;
+   }
+
+   return true;
+}
+EXPORT_SYMBOL(drm_edid_match);
+
 static void
 monitor_name(const struct detailed_timing *timing, void *data)
 {
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 8b233865b085..28f05a7b2f7b 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -367,6 +367,12 @@ struct edid {
u8 checksum;
 } __attribute__((packed));
 
+/* EDID matching */
+struct drm_edid_ident {
+   u32 panel_id;
+   const char *name;
+};
+
 #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
 
 /* Short Audio Descriptor */
@@ -567,6 +573,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
 const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter);
 u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
+bool drm_edid_match(const struct drm_edid *drm_edid,
+   const struct drm_edid_ident *ident);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v5 2/6] drm/edid: Clean up drm_edid_get_panel_id()

2024-03-06 Thread Hsin-Yi Wang
drm_edid_get_panel_id() now just directly call edid_extract_panel_id().

Merge them into one function.

Signed-off-by: Hsin-Yi Wang 
---
v4->v5: new
---
 drivers/gpu/drm/drm_edid.c | 39 ++
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 8c7e871eff58..febe374fa969 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2743,8 +2743,24 @@ const struct drm_edid *drm_edid_read(struct 
drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_edid_read);
 
-static u32 edid_extract_panel_id(const struct edid *edid)
+/**
+ * drm_edid_get_panel_id - Get a panel's ID from EDID
+ * @drm_edid: EDID that contains panel ID.
+ *
+ * This function uses the first block of the EDID of a panel and (assuming
+ * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
+ * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
+ * supposed to be different for each different modem of panel.
+ *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID.
+ */
+u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid)
 {
+   const struct edid *edid = drm_edid->edid;
+
/*
 * We represent the ID as a 32-bit number so it can easily be compared
 * with "==".
@@ -2762,25 +2778,6 @@ static u32 edid_extract_panel_id(const struct edid *edid)
   (u32)edid->mfg_id[1] << 16   |
   (u32)EDID_PRODUCT_ID(edid);
 }
-
-/**
- * drm_edid_get_panel_id - Get a panel's ID from EDID
- * @drm_edid: EDID that contains panel ID.
- *
- * This function uses the first block of the EDID of a panel and (assuming
- * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
- * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
- * supposed to be different for each different modem of panel.
- *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
- */
-u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid)
-{
-   return edid_extract_panel_id(drm_edid->edid);
-}
 EXPORT_SYMBOL(drm_edid_get_panel_id);
 
 /**
@@ -2881,7 +2878,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  */
 static u32 edid_get_quirks(const struct drm_edid *drm_edid)
 {
-   u32 panel_id = edid_extract_panel_id(drm_edid->edid);
+   u32 panel_id = drm_edid_get_panel_id(drm_edid);
const struct edid_quirk *quirk;
int i;
 
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v5 1/6] drm_edid: Add a function to get EDID base block

2024-03-06 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. Besides panel id, now we need
more information from the EDID base block to distinguish these panel
variants.

Add drm_edid_read_base_block() to return the EDID base block, which is
wrapped in struct drm_edid.

Caller can further use it to get panel id or check if the block contains
certain strings, such as panel name.

Signed-off-by: Hsin-Yi Wang 
---
v4->v5: use _drm_edid_alloc
---
 drivers/gpu/drm/drm_edid.c| 63 +++
 drivers/gpu/drm/panel/panel-edp.c |  8 +++-
 include/drm/drm_edid.h|  3 +-
 3 files changed, 46 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 1ad94473e400..8c7e871eff58 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2764,58 +2764,71 @@ static u32 edid_extract_panel_id(const struct edid 
*edid)
 }
 
 /**
- * drm_edid_get_panel_id - Get a panel's ID through DDC
- * @adapter: I2C adapter to use for DDC
+ * drm_edid_get_panel_id - Get a panel's ID from EDID
+ * @drm_edid: EDID that contains panel ID.
  *
- * This function reads the first block of the EDID of a panel and (assuming
+ * This function uses the first block of the EDID of a panel and (assuming
  * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
  * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
  * supposed to be different for each different modem of panel.
  *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID.
+ */
+u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid)
+{
+   return edid_extract_panel_id(drm_edid->edid);
+}
+EXPORT_SYMBOL(drm_edid_get_panel_id);
+
+/**
+ * drm_edid_read_base_block - Get a panel's EDID base block
+ * @adapter: I2C adapter to use for DDC
+ *
+ * This function returns the drm_edid containing the first block of the EDID of
+ * a panel.
+ *
  * This function is intended to be used during early probing on devices where
  * more than one panel might be present. Because of its intended use it must
- * assume that the EDID of the panel is correct, at least as far as the ID
- * is concerned (in other words, we don't process any overrides here).
+ * assume that the EDID of the panel is correct, at least as far as the base
+ * block is concerned (in other words, we don't process any overrides here).
+ *
+ * Caller should call drm_edid_free() after use.
  *
  * NOTE: it's expected that this function and drm_do_get_edid() will both
  * be read the EDID, but there is no caching between them. Since we're only
  * reading the first block, hopefully this extra overhead won't be too big.
  *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
+ * WARNING: Only use this function when the connector is unknown. For example,
+ * during the early probe of panel. The EDID read from the function is 
temporary
+ * and should be replaced by the full EDID returned from other drm_edid_read.
+ *
+ * Return: Pointer to allocated EDID base block, or NULL on any failure.
  */
-
-u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
+const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter)
 {
enum edid_block_status status;
void *base_block;
-   u32 panel_id = 0;
-
-   /*
-* There are no manufacturer IDs of 0, so if there is a problem reading
-* the EDID then we'll just return 0.
-*/
 
base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
if (!base_block)
-   return 0;
+   return NULL;
 
status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter);
 
edid_block_status_print(status, base_block, 0);
 
-   if (edid_block_status_valid(status, edid_block_tag(base_block)))
-   panel_id = edid_extract_panel_id(base_block);
-   else
+   if (!edid_block_status_valid(status, edid_block_tag(base_block))) {
edid_block_dump(KERN_NOTICE, base_block, 0);
+   kfree(base_block);
+   return NULL;
+   }
 
-   kfree(base_block);
-
-   return panel_id;
+   return _drm_edid_alloc(base_block, EDID_LENGTH);
 }
-EXPORT_SYMBOL(drm_edid_get_panel_id);
+EXPORT_SYMBOL(drm_edid_read_base_block);
 
 /**
  * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 3fb5fcd326a4..fe51680feb61 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel

[PATCH v5 0/6] Match panel with identity

2024-03-06 Thread Hsin-Yi Wang
This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
product id. One of them requires an overridden mode, while the other should
use the mode directly from edid.

Match the panel for identity (id and name). If not found, fallback to match
id.

v1: https://lore.kernel.org/lkml/20240223223958.3887423-1-hsi...@chromium.org
v2: https://lore.kernel.org/lkml/20240228011133.1238439-1-hsi...@chromium.org
v3: https://lore.kernel.org/lkml/20240304195214.14563-1-hsi...@chromium.org
v4: https://lore.kernel.org/lkml/20240306004347.974304-1-hsi...@chromium.org/

Hsin-Yi Wang (6):
  drm_edid: Add a function to get EDID base block
  drm/edid: Clean up drm_edid_get_panel_id()
  drm/edid: Add a function to match EDID with identity
  drm/edid: Match edid quirks with identity
  drm/panel-edp: Match edp_panels with panel identity
  drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

 drivers/gpu/drm/drm_edid.c| 144 +++---
 drivers/gpu/drm/panel/panel-edp.c |  68 +-
 include/drm/drm_edid.h|  11 ++-
 3 files changed, 166 insertions(+), 57 deletions(-)

-- 
2.44.0.278.ge034bb2e1d-goog



Re: [PATCH v4 2/5] drm/edid: Add a function to match EDID with identity

2024-03-06 Thread Hsin-Yi Wang
On Wed, Mar 6, 2024 at 1:17 AM Jani Nikula  wrote:
>
> On Tue, 05 Mar 2024, Hsin-Yi Wang  wrote:
> > Create a type drm_edid_ident as the identity of an EDID. Currently it
> > contains panel id and monitor name.
> >
> > Create a function that can match a given EDID and an identity:
> > 1. Reject if the panel id doesn't match.
> > 2. If name is not null in identity, try to match it in the detailed timing
> >blocks. Note that some panel vendors put the monitor name after
> >    EDID_DETAIL_MONITOR_STRING.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v3->v4:
> > 1. add a type drm_edid_ident
> > 2. match name -> match identity. Modify function to use edid iterators.
> > ---
> >  drivers/gpu/drm/drm_edid.c | 76 ++
> >  include/drm/drm_edid.h |  8 
> >  2 files changed, 84 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> > index f9e09f327f81..5e7e69e0e345 100644
> > --- a/drivers/gpu/drm/drm_edid.c
> > +++ b/drivers/gpu/drm/drm_edid.c
> > @@ -102,6 +102,11 @@ struct detailed_mode_closure {
> >   int modes;
> >  };
> >
> > +struct drm_edid_ident_closure {
> > + const struct drm_edid_ident *ident;
> > + bool matched;
> > +};
>
> More like drm_edid_match_closure.
>
> > +
> >  #define LEVEL_DMT0
> >  #define LEVEL_GTF1
> >  #define LEVEL_GTF2   2
> > @@ -5455,6 +5460,77 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector 
> > *connector, const u8 *db)
> >   connector->audio_latency[0], connector->audio_latency[1]);
> >  }
> >
> > +static void
> > +match_identity(const struct detailed_timing *timing, void *data)
> > +{
> > + struct drm_edid_ident_closure *closure = data;
> > + unsigned int i, j;
> > + const char *str = closure->ident->name;
> > + unsigned int buflen = strlen(str);
> > + unsigned int size = ARRAY_SIZE(timing->data.other_data.data.str.str);
> > +
> > + if (buflen > size ||
> > + !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) ||
> > +   is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING)))
> > + return;
> > +
> > + for (i = 0; i < buflen; i++) {
> > + char c = timing->data.other_data.data.str.str[i];
> > +
> > + if (c != str[i] ||  c == '\n')
> > + break;
> > + }
> > +
> > + if (i == buflen) {
>
> This will never be true.

It should be

for (i = 0; i < buflen; i++) {
...
}

if (i==buflen) {
...
}

But okay we can use strcmp.

>
> > + /* Allow trailing white spaces. */
> > + for (j = i; j < size; j++) {
> > + char c = 
> > timing->data.other_data.data.str.str[j];
> > +
> > + if (c == '\n') {
> > + closure->matched = true;
> > + return;
> > + } else if (c != ' ') {
> > + break;
> > + }
> > + }
> > + if (j == size) {
> > + closure->matched = true;
> > + return;
> > + }
> > + }
>
> Please let's use strcmp and friends instead of reinventing our own:
>
> const char *name = closure->ident->name;
> int name_len = strlen(name);
> const char *desc = timing->data.other_data.data.str.str;
> int desc_len = ARRAY_SIZE(timing->data.other_data.data.str.str);
>
> if (name_len > desc_len)
> return;
>
> if (strncmp(name, desc, name_en))
> return;
>
> for (i = name_len; i < desc_len; i++) {
> if (!isspace(desc[i]) && !desc[i])
> return;
> }
>
> closure->matched = true;
>
>
> > +}
> > +
> > +/**
> > + * drm_edid_match_identity - match drm_edid with given identity
> > + * @drm_edid: EDID
> > + * @ident: the EDID identity to match with
> > + *
> > + * Check if the EDID matches with the given identity.
> > + *
> > + * Return: True if the given identity matched with EDID, false otherwise.
> > + */
> > +bool drm_edid_match_identity(const struct drm_edid *drm_edid,
> > +  const struct drm_edid_ide

Re: [PATCH v4 4/5] drm/panel-edp: Match edp_panels with panel identity

2024-03-06 Thread Hsin-Yi Wang
On Wed, Mar 6, 2024 at 1:23 AM Jani Nikula  wrote:
>
> On Tue, 05 Mar 2024, Hsin-Yi Wang  wrote:
> > It's found that some panels have variants that they share the same panel id
> > although their EDID and names are different. When matching generic edp
> > panels, we should first match with both panel identity, which contains both
> > panel id and panel name. If not found, match with panel id only.
>
> Do you want to start matching also with name, for all panels? That's
> totally up to you, but that's the big functional change here.
>

It might be difficult to find all the datasheets for all the panels to
verify the names. Also, some of the names in the panels are also
marked as "Unknown", so I think we still want to keep the matching
with id only.

Without really testing on the exact panel, I'm afraid that this might
break them.


> BR,
> Jani.
>
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v3->v4: combine name and id to identity.
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 45 ---
> >  1 file changed, 24 insertions(+), 21 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> > b/drivers/gpu/drm/panel/panel-edp.c
> > index d094cfc43da8..fb70e97a2e71 100644
> > --- a/drivers/gpu/drm/panel/panel-edp.c
> > +++ b/drivers/gpu/drm/panel/panel-edp.c
> > @@ -210,15 +210,12 @@ struct panel_desc {
> >   * struct edp_panel_entry - Maps panel ID to delay / panel name.
> >   */
> >  struct edp_panel_entry {
> > - /** @panel_id: 32-bit ID for panel, encoded with 
> > drm_edid_encode_panel_id(). */
> > - u32 panel_id;
> > + /** @ident: edid identity used for panel matching. */
> > + const struct drm_edid_ident ident;
> >
> >   /** @delay: The power sequencing delays needed for this panel. */
> >   const struct panel_delay *delay;
> >
> > - /** @name: Name of this panel (for printing to logs). */
> > - const char *name;
> > -
> >   /** @override_edid_mode: Override the mode obtained by edid. */
> >   const struct drm_display_mode *override_edid_mode;
> >  };
> > @@ -691,7 +688,7 @@ static int detected_panel_show(struct seq_file *s, void 
> > *data)
> >   else if (!p->detected_panel)
> >   seq_puts(s, "HARDCODED\n");
> >   else
> > - seq_printf(s, "%s\n", p->detected_panel->name);
> > + seq_printf(s, "%s\n", p->detected_panel->ident.name);
> >
> >   return 0;
> >  }
> > @@ -761,7 +758,7 @@ static void panel_edp_parse_panel_timing_node(struct 
> > device *dev,
> >   dev_err(dev, "Reject override mode: No display_timing 
> > found\n");
> >  }
> >
> > -static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
> > +static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const 
> > struct drm_edid *edid);
> >
> >  static int generic_edp_panel_probe(struct device *dev, struct panel_edp 
> > *panel)
> >  {
> > @@ -799,7 +796,6 @@ static int generic_edp_panel_probe(struct device *dev, 
> > struct panel_edp *panel)
> >   base_block = drm_edid_read_base_block(panel->ddc);
> >   if (base_block) {
> >   panel_id = drm_edid_get_panel_id(base_block);
> > - drm_edid_free(base_block);
> >   } else {
> >   dev_err(dev, "Couldn't identify panel via EDID\n");
> >   ret = -EIO;
> > @@ -807,7 +803,9 @@ static int generic_edp_panel_probe(struct device *dev, 
> > struct panel_edp *panel)
> >   }
> >   drm_edid_decode_panel_id(panel_id, vend, _id);
> >
> > - panel->detected_panel = find_edp_panel(panel_id);
> > + panel->detected_panel = find_edp_panel(panel_id, base_block);
> > +
> > + drm_edid_free(base_block);
> >
> >   /*
> >* We're using non-optimized timings and want it really obvious that
> > @@ -840,7 +838,7 @@ static int generic_edp_panel_probe(struct device *dev, 
> > struct panel_edp *panel)
> >   panel->detected_panel = ERR_PTR(-EINVAL);
> >   } else {
> >   dev_info(dev, "Detected %s %s (%#06x)\n",
> > -  vend, panel->detected_panel->name, product_id);
> > +  vend, panel->detected_panel->ident.name, product_id);
> >
> >   /* Update the delay; everything else comes from EDID */
> >   desc->delay = *

Re: [PATCH v3 2/4] drm/edid: Add a function to check monitor string

2024-03-05 Thread Hsin-Yi Wang
On Tue, Mar 5, 2024 at 11:25 AM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Mar 5, 2024 at 12:17 AM Jani Nikula  
> wrote:
> >
> > On Mon, 04 Mar 2024, Doug Anderson  wrote:
> > > Hi,
> > >
> > > On Mon, Mar 4, 2024 at 4:19 PM Hsin-Yi Wang  wrote:
> > >>
> > >> > > Probably change to u32 drm_edid_get_panel_id(const struct drm_edid
> > >> > > *);? Given that we still need to parse id from
> > >> > > drm_edid_read_base_block().
> > >> >
> > >> > No, we no longer need to parse the id outside of drm_edid.c. You'll 
> > >> > have
> > >> > the id's in panel code in the form of struct drm_edid_ident (or
> > >> > whatever), and use the match function to see if the opaque drm_edid
> > >> > matches.
> > >> >
> > >> drm_panel prints the panel_id info on whether the panel is detected or 
> > >> not.
> > >> https://elixir.bootlin.com/linux/v6.8-rc7/source/drivers/gpu/drm/panel/panel-edp.c#L792
> > >>
> > >> Is it okay to remove this information?
> > >
> > > Hmmm, I guess it also is exported via debugfs, actually. See
> > > detected_panel_show() in panel-edp.c. We probably don't want to remove
> > > that...
> >
> > You currently print the information via panel->detected_panel, which is
> > a struct edp_panel_entry *. That doesn't change. It'll be slightly
> > restructured to contain a struct drm_edid_ident, which will not be an
> > opaque type.
>
> Hmm. As Hsin-Yi pointed out to me offline. Somehow we'll need to get
> the actual panel ID out. Right now in panel-edp.c we have:
>
> dev_warn(dev,
>   "Unknown panel %s %#06x, using conservative timings\n",
>   vend, product_id);
>
> Where "vend" and "product_id" come from the panel ID of a panel that
> we didn't recognize. For instance:
>
>   Unknown panel BOE 0x0731, using conservative timings
>
> We need to still be able to print this message for unrecognized
> panels. Then when we see field reports including this message we know
> that somehow we ended up shipping an unrecognized panel.
>
> Any suggestions on what abstraction you'd like to see to enable us to
> print that message if everything is opaque?

Sent v4 here: 
https://lore.kernel.org/lkml/20240306004347.974304-1-hsi...@chromium.org/

Besides that it still keeps drm_edid_get_panel_id() to be used on the
kernel warning when no panel is matched, other parts I think are
following the comments.

Thanks.
>
> -Doug


[PATCH v4 5/5] drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-03-05 Thread Hsin-Yi Wang
There are 2 different AUO panels using the same panel id. One of the
variants requires using overridden modes to resolve glitching issue as
described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
Other variants should use the modes parsed from EDID.

Signed-off-by: Hsin-Yi Wang 
---
v4->v5: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index fb70e97a2e71..9db04457fb4d 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1007,6 +1007,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1966,7 +1979,9 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAN04.0"),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0 ",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, _200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v4 4/5] drm/panel-edp: Match edp_panels with panel identity

2024-03-05 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. When matching generic edp
panels, we should first match with both panel identity, which contains both
panel id and panel name. If not found, match with panel id only.

Signed-off-by: Hsin-Yi Wang 
---
v3->v4: combine name and id to identity.
---
 drivers/gpu/drm/panel/panel-edp.c | 45 ---
 1 file changed, 24 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index d094cfc43da8..fb70e97a2e71 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -210,15 +210,12 @@ struct panel_desc {
  * struct edp_panel_entry - Maps panel ID to delay / panel name.
  */
 struct edp_panel_entry {
-   /** @panel_id: 32-bit ID for panel, encoded with 
drm_edid_encode_panel_id(). */
-   u32 panel_id;
+   /** @ident: edid identity used for panel matching. */
+   const struct drm_edid_ident ident;
 
/** @delay: The power sequencing delays needed for this panel. */
const struct panel_delay *delay;
 
-   /** @name: Name of this panel (for printing to logs). */
-   const char *name;
-
/** @override_edid_mode: Override the mode obtained by edid. */
const struct drm_display_mode *override_edid_mode;
 };
@@ -691,7 +688,7 @@ static int detected_panel_show(struct seq_file *s, void 
*data)
else if (!p->detected_panel)
seq_puts(s, "HARDCODED\n");
else
-   seq_printf(s, "%s\n", p->detected_panel->name);
+   seq_printf(s, "%s\n", p->detected_panel->ident.name);
 
return 0;
 }
@@ -761,7 +758,7 @@ static void panel_edp_parse_panel_timing_node(struct device 
*dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
 }
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const struct 
drm_edid *edid);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
@@ -799,7 +796,6 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
base_block = drm_edid_read_base_block(panel->ddc);
if (base_block) {
panel_id = drm_edid_get_panel_id(base_block);
-   drm_edid_free(base_block);
} else {
dev_err(dev, "Couldn't identify panel via EDID\n");
ret = -EIO;
@@ -807,7 +803,9 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
}
drm_edid_decode_panel_id(panel_id, vend, _id);
 
-   panel->detected_panel = find_edp_panel(panel_id);
+   panel->detected_panel = find_edp_panel(panel_id, base_block);
+
+   drm_edid_free(base_block);
 
/*
 * We're using non-optimized timings and want it really obvious that
@@ -840,7 +838,7 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
panel->detected_panel = ERR_PTR(-EINVAL);
} else {
dev_info(dev, "Detected %s %s (%#06x)\n",
-vend, panel->detected_panel->name, product_id);
+vend, panel->detected_panel->ident.name, product_id);
 
/* Update the delay; everything else comes from EDID */
desc->delay = *panel->detected_panel->delay;
@@ -1930,17 +1928,21 @@ static const struct panel_delay 
delay_200_500_e50_po2e200 = {
 
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
-   .name = _name, \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   }, \
.delay = _delay \
 }
 
 #define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
 { \
-   .name = _name, \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   }, \
.delay = _delay, \
.override_edid_mode = _mode \
 }
@@ -2087,15 +2089,16 @@ static const struct edp_panel_entry edp_panels[] = {
{ /* sentinal */ }
 };
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
+static const struct edp_

[PATCH v4 3/5] drm/edid: Match edid quirks with identity

2024-03-05 Thread Hsin-Yi Wang
Currently edid quirks are matched by panel id only.

Modify it to match with identity so it's easier to be extended
for more complex matching if required.

Suggested-by: Jani Nikula 
Signed-off-by: Hsin-Yi Wang 
---
v4: new
Per discussion https://lore.kernel.org/lkml/87a5nd4tsg@intel.com/
---
 drivers/gpu/drm/drm_edid.c | 13 -
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 5e7e69e0e345..93a49b262dbe 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -114,13 +114,15 @@ struct drm_edid_ident_closure {
 
 #define EDID_QUIRK(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _quirks) \
 { \
-   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
-product_id), \
+   .ident = { \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, \
+vend_chr_2, product_id), \
+   }, \
.quirks = _quirks \
 }
 
 static const struct edid_quirk {
-   u32 panel_id;
+   const struct drm_edid_ident ident;
u32 quirks;
 } edid_quirk_list[] = {
/* Acer AL1706 */
@@ -2921,16 +2923,17 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  * @drm_edid: EDID to process
  *
  * This tells subsequent routines what fixes they need to apply.
+ *
+ * Return: A u32 represents the quirks to apply.
  */
 static u32 edid_get_quirks(const struct drm_edid *drm_edid)
 {
-   u32 panel_id = edid_extract_panel_id(drm_edid->edid);
const struct edid_quirk *quirk;
int i;
 
for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
quirk = _quirk_list[i];
-   if (quirk->panel_id == panel_id)
+   if (drm_edid_match_identity(drm_edid, >ident))
return quirk->quirks;
}
 
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v4 2/5] drm/edid: Add a function to match EDID with identity

2024-03-05 Thread Hsin-Yi Wang
Create a type drm_edid_ident as the identity of an EDID. Currently it
contains panel id and monitor name.

Create a function that can match a given EDID and an identity:
1. Reject if the panel id doesn't match.
2. If name is not null in identity, try to match it in the detailed timing
   blocks. Note that some panel vendors put the monitor name after
   EDID_DETAIL_MONITOR_STRING.

Signed-off-by: Hsin-Yi Wang 
---
v3->v4:
1. add a type drm_edid_ident
2. match name -> match identity. Modify function to use edid iterators.
---
 drivers/gpu/drm/drm_edid.c | 76 ++
 include/drm/drm_edid.h |  8 
 2 files changed, 84 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index f9e09f327f81..5e7e69e0e345 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -102,6 +102,11 @@ struct detailed_mode_closure {
int modes;
 };
 
+struct drm_edid_ident_closure {
+   const struct drm_edid_ident *ident;
+   bool matched;
+};
+
 #define LEVEL_DMT  0
 #define LEVEL_GTF  1
 #define LEVEL_GTF2 2
@@ -5455,6 +5460,77 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector 
*connector, const u8 *db)
connector->audio_latency[0], connector->audio_latency[1]);
 }
 
+static void
+match_identity(const struct detailed_timing *timing, void *data)
+{
+   struct drm_edid_ident_closure *closure = data;
+   unsigned int i, j;
+   const char *str = closure->ident->name;
+   unsigned int buflen = strlen(str);
+   unsigned int size = ARRAY_SIZE(timing->data.other_data.data.str.str);
+
+   if (buflen > size ||
+   !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) ||
+ is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING)))
+   return;
+
+   for (i = 0; i < buflen; i++) {
+   char c = timing->data.other_data.data.str.str[i];
+
+   if (c != str[i] ||  c == '\n')
+   break;
+   }
+
+   if (i == buflen) {
+   /* Allow trailing white spaces. */
+   for (j = i; j < size; j++) {
+   char c = 
timing->data.other_data.data.str.str[j];
+
+   if (c == '\n') {
+   closure->matched = true;
+   return;
+   } else if (c != ' ') {
+   break;
+   }
+   }
+   if (j == size) {
+   closure->matched = true;
+   return;
+   }
+   }
+}
+
+/**
+ * drm_edid_match_identity - match drm_edid with given identity
+ * @drm_edid: EDID
+ * @ident: the EDID identity to match with
+ *
+ * Check if the EDID matches with the given identity.
+ *
+ * Return: True if the given identity matched with EDID, false otherwise.
+ */
+bool drm_edid_match_identity(const struct drm_edid *drm_edid,
+const struct drm_edid_ident *ident)
+{
+   if (!drm_edid || edid_extract_panel_id(drm_edid->edid) != 
ident->panel_id)
+   return false;
+
+   /* Match with name only if it's not NULL. */
+   if (ident->name) {
+   struct drm_edid_ident_closure closure = {
+   .ident = ident,
+   .matched = false,
+   };
+
+   drm_for_each_detailed_block(drm_edid, match_identity, );
+
+   return closure.matched;
+   }
+
+   return true;
+}
+EXPORT_SYMBOL(drm_edid_match_identity);
+
 static void
 monitor_name(const struct detailed_timing *timing, void *data)
 {
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 9686a7cee6a6..01825a8954b6 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -312,6 +312,12 @@ struct edid {
u8 checksum;
 } __packed;
 
+/* EDID matching */
+struct drm_edid_ident {
+   u32 panel_id;
+   const char *name;
+};
+
 #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
 
 /* Short Audio Descriptor */
@@ -412,6 +418,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
 const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter);
 u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
+bool drm_edid_match_identity(const struct drm_edid *drm_edid,
+const struct drm_edid_ident *ident);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v4 0/5] Match panel with identity

2024-03-05 Thread Hsin-Yi Wang
This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
product id. One of them requires an overridden mode, while the other should
use the mode directly from edid.

Match the panel for identity (id and name). If not found, fallback to match
id.

v1: https://lore.kernel.org/lkml/20240223223958.3887423-1-hsi...@chromium.org
v2: https://lore.kernel.org/lkml/20240228011133.1238439-1-hsi...@chromium.org
v3: https://lore.kernel.org/lkml/20240304195214.14563-1-hsi...@chromium.org

Hsin-Yi Wang (5):
  drm_edid: Add a function to get EDID base block
  drm/edid: Add a function to match EDID with identity
  drm/edid: match edid quirks with identity
  drm/panel-edp: Match edp_panels with panel identity
  drm/panel-edp: Fix AUO 0x405c panel naming and add a variant

 drivers/gpu/drm/drm_edid.c| 152 --
 drivers/gpu/drm/panel/panel-edp.c |  68 -
 include/drm/drm_edid.h|  11 ++-
 3 files changed, 177 insertions(+), 54 deletions(-)

-- 
2.44.0.278.ge034bb2e1d-goog



[PATCH v4 1/5] drm_edid: Add a function to get EDID base block

2024-03-05 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. Besides panel id, now we need
more information from the EDID base block to distinguish these panel
variants.

Add drm_edid_read_base_block() to return the EDID base block, which is
wrapped in struct drm_edid.

Caller can further use it to get panel id or check if the block contains
certain strings, such as panel name.

Signed-off-by: Hsin-Yi Wang 
---
v3->v4: change drm_edid_read_base_block return type to drm_edid.
---
 drivers/gpu/drm/drm_edid.c| 63 +++
 drivers/gpu/drm/panel/panel-edp.c |  8 +++-
 include/drm/drm_edid.h|  3 +-
 3 files changed, 46 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..f9e09f327f81 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2770,58 +2770,71 @@ static u32 edid_extract_panel_id(const struct edid 
*edid)
 }
 
 /**
- * drm_edid_get_panel_id - Get a panel's ID through DDC
- * @adapter: I2C adapter to use for DDC
+ * drm_edid_get_panel_id - Get a panel's ID from EDID
+ * @drm_edid: EDID that contains panel ID.
  *
- * This function reads the first block of the EDID of a panel and (assuming
+ * This function uses the first block of the EDID of a panel and (assuming
  * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
  * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
  * supposed to be different for each different modem of panel.
  *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID.
+ */
+u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid)
+{
+   return edid_extract_panel_id(drm_edid->edid);
+}
+EXPORT_SYMBOL(drm_edid_get_panel_id);
+
+/**
+ * drm_edid_read_base_block - Get a panel's EDID base block
+ * @adapter: I2C adapter to use for DDC
+ *
+ * This function returns the drm_edid containing the first block of the EDID of
+ * a panel.
+ *
  * This function is intended to be used during early probing on devices where
  * more than one panel might be present. Because of its intended use it must
- * assume that the EDID of the panel is correct, at least as far as the ID
- * is concerned (in other words, we don't process any overrides here).
+ * assume that the EDID of the panel is correct, at least as far as the base
+ * block is concerned (in other words, we don't process any overrides here).
+ *
+ * Caller should call drm_edid_free() after use.
  *
  * NOTE: it's expected that this function and drm_do_get_edid() will both
  * be read the EDID, but there is no caching between them. Since we're only
  * reading the first block, hopefully this extra overhead won't be too big.
  *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
+ * WARNING: Only use this function when the connector is unknown. For example,
+ * during the early probe of panel. The EDID read from the function is 
temporary
+ * and should be replaced by the full EDID returned from other drm_edid_read.
+ *
+ * Return: Pointer to allocated EDID base block, or NULL on any failure.
  */
-
-u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
+const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter)
 {
enum edid_block_status status;
void *base_block;
-   u32 panel_id = 0;
-
-   /*
-* There are no manufacturer IDs of 0, so if there is a problem reading
-* the EDID then we'll just return 0.
-*/
 
base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
if (!base_block)
-   return 0;
+   return NULL;
 
status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter);
 
edid_block_status_print(status, base_block, 0);
 
-   if (edid_block_status_valid(status, edid_block_tag(base_block)))
-   panel_id = edid_extract_panel_id(base_block);
-   else
+   if (!edid_block_status_valid(status, edid_block_tag(base_block))) {
edid_block_dump(KERN_NOTICE, base_block, 0);
+   kfree(base_block);
+   return NULL;
+   }
 
-   kfree(base_block);
-
-   return panel_id;
+   return drm_edid_alloc(base_block, EDID_LENGTH);
 }
-EXPORT_SYMBOL(drm_edid_get_panel_id);
+EXPORT_SYMBOL(drm_edid_read_base_block);
 
 /**
  * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 745f3e48f02a..d094cfc43da8 100644
--- a/drivers/gpu/drm/panel/panel-edp.c

Re: [PATCH v3 2/4] drm/edid: Add a function to check monitor string

2024-03-04 Thread Hsin-Yi Wang
On Mon, Mar 4, 2024 at 4:09 PM Jani Nikula  wrote:
>
> On Mon, 04 Mar 2024, Hsin-Yi Wang  wrote:
> > On Mon, Mar 4, 2024 at 12:38 PM Jani Nikula  
> > wrote:
> >>
> >> On Mon, 04 Mar 2024, Hsin-Yi Wang  wrote:
> >> > Add a function to check if the EDID base block contains a given string.
> >> >
> >> > One of the use cases is fetching panel from a list of panel names, since
> >> > some panel vendors put the monitor name after EDID_DETAIL_MONITOR_STRING
> >> > instead of EDID_DETAIL_MONITOR_NAME.
> >> >
> >> > Signed-off-by: Hsin-Yi Wang 
> >> > ---
> >> > v2->v3: move string matching to drm_edid
> >> > ---
> >> >  drivers/gpu/drm/drm_edid.c | 49 ++
> >> >  include/drm/drm_edid.h |  1 +
> >> >  2 files changed, 50 insertions(+)
> >> >
> >> > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> >> > index 13454bc64ca2..fcdc2bd143dd 100644
> >> > --- a/drivers/gpu/drm/drm_edid.c
> >> > +++ b/drivers/gpu/drm/drm_edid.c
> >> > @@ -2789,6 +2789,55 @@ u32 drm_edid_get_panel_id(struct edid_base_block 
> >> > *base_block)
> >> >  }
> >> >  EXPORT_SYMBOL(drm_edid_get_panel_id);
> >> >
> >> > +/**
> >> > + * drm_edid_has_monitor_string - Check if a EDID base block has certain 
> >> > string.
> >> > + * @base_block: EDID base block to check.
> >> > + * @str: pointer to a character array to hold the string to be checked.
> >> > + *
> >> > + * Check if the detailed timings section of a EDID base block has the 
> >> > given
> >> > + * string.
> >> > + *
> >> > + * Return: True if the EDID base block contains the string, false 
> >> > otherwise.
> >> > + */
> >> > +bool drm_edid_has_monitor_string(struct edid_base_block *base_block, 
> >> > const char *str)
> >> > +{
> >> > + unsigned int i, j, k, buflen = strlen(str);
> >> > +
> >> > + for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
> >> > + struct detailed_timing *timing = 
> >> > _block->edid.detailed_timings[i];
> >> > + unsigned int size = 
> >> > ARRAY_SIZE(timing->data.other_data.data.str.str);
> >> > +
> >> > + if (buflen > size || timing->pixel_clock != 0 ||
> >> > + timing->data.other_data.pad1 != 0 ||
> >> > + (timing->data.other_data.type != 
> >> > EDID_DETAIL_MONITOR_NAME &&
> >> > +  timing->data.other_data.type != 
> >> > EDID_DETAIL_MONITOR_STRING))
> >> > + continue;
> >> > +
> >> > + for (j = 0; j < buflen; j++) {
> >> > + char c = timing->data.other_data.data.str.str[j];
> >> > +
> >> > + if (c != str[j] ||  c == '\n')
> >> > + break;
> >> > + }
> >> > +
> >> > + if (j == buflen) {
> >> > + /* Allow trailing white spaces. */
> >> > + for (k = j; k < size; k++) {
> >> > + char c = 
> >> > timing->data.other_data.data.str.str[k];
> >> > +
> >> > + if (c == '\n')
> >> > + return true;
> >> > + else if (c != ' ')
> >> > + break;
> >> > + }
> >> > + if (k == size)
> >> > + return true;
> >> > + }
> >> > + }
> >> > +
> >> > + return false;
> >> > +}
> >> > +
> >>
> >> So we've put a lot of effort into converting from struct edid to struct
> >> drm_edid, passing that around in drm_edid.c, with the allocation size it
> >> provides, and generally cleaning stuff up.
> >>
> >> I'm not at all happy to see *another* struct added just for the base
> >> block, and detailed timing iteration as well as monitor name parsing
> >> duplicated.
> >>
> >> With struct drm_edid you can actually return an 

Re: [PATCH v3 2/4] drm/edid: Add a function to check monitor string

2024-03-04 Thread Hsin-Yi Wang
On Mon, Mar 4, 2024 at 4:09 PM Jani Nikula  wrote:
>
> On Mon, 04 Mar 2024, Hsin-Yi Wang  wrote:
> > On Mon, Mar 4, 2024 at 12:38 PM Jani Nikula  
> > wrote:
> >>
> >> On Mon, 04 Mar 2024, Hsin-Yi Wang  wrote:
> >> > Add a function to check if the EDID base block contains a given string.
> >> >
> >> > One of the use cases is fetching panel from a list of panel names, since
> >> > some panel vendors put the monitor name after EDID_DETAIL_MONITOR_STRING
> >> > instead of EDID_DETAIL_MONITOR_NAME.
> >> >
> >> > Signed-off-by: Hsin-Yi Wang 
> >> > ---
> >> > v2->v3: move string matching to drm_edid
> >> > ---
> >> >  drivers/gpu/drm/drm_edid.c | 49 ++
> >> >  include/drm/drm_edid.h |  1 +
> >> >  2 files changed, 50 insertions(+)
> >> >
> >> > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> >> > index 13454bc64ca2..fcdc2bd143dd 100644
> >> > --- a/drivers/gpu/drm/drm_edid.c
> >> > +++ b/drivers/gpu/drm/drm_edid.c
> >> > @@ -2789,6 +2789,55 @@ u32 drm_edid_get_panel_id(struct edid_base_block 
> >> > *base_block)
> >> >  }
> >> >  EXPORT_SYMBOL(drm_edid_get_panel_id);
> >> >
> >> > +/**
> >> > + * drm_edid_has_monitor_string - Check if a EDID base block has certain 
> >> > string.
> >> > + * @base_block: EDID base block to check.
> >> > + * @str: pointer to a character array to hold the string to be checked.
> >> > + *
> >> > + * Check if the detailed timings section of a EDID base block has the 
> >> > given
> >> > + * string.
> >> > + *
> >> > + * Return: True if the EDID base block contains the string, false 
> >> > otherwise.
> >> > + */
> >> > +bool drm_edid_has_monitor_string(struct edid_base_block *base_block, 
> >> > const char *str)
> >> > +{
> >> > + unsigned int i, j, k, buflen = strlen(str);
> >> > +
> >> > + for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
> >> > + struct detailed_timing *timing = 
> >> > _block->edid.detailed_timings[i];
> >> > + unsigned int size = 
> >> > ARRAY_SIZE(timing->data.other_data.data.str.str);
> >> > +
> >> > + if (buflen > size || timing->pixel_clock != 0 ||
> >> > + timing->data.other_data.pad1 != 0 ||
> >> > + (timing->data.other_data.type != 
> >> > EDID_DETAIL_MONITOR_NAME &&
> >> > +  timing->data.other_data.type != 
> >> > EDID_DETAIL_MONITOR_STRING))
> >> > + continue;
> >> > +
> >> > + for (j = 0; j < buflen; j++) {
> >> > + char c = timing->data.other_data.data.str.str[j];
> >> > +
> >> > + if (c != str[j] ||  c == '\n')
> >> > + break;
> >> > + }
> >> > +
> >> > + if (j == buflen) {
> >> > + /* Allow trailing white spaces. */
> >> > + for (k = j; k < size; k++) {
> >> > + char c = 
> >> > timing->data.other_data.data.str.str[k];
> >> > +
> >> > + if (c == '\n')
> >> > + return true;
> >> > + else if (c != ' ')
> >> > + break;
> >> > + }
> >> > + if (k == size)
> >> > + return true;
> >> > + }
> >> > + }
> >> > +
> >> > + return false;
> >> > +}
> >> > +
> >>
> >> So we've put a lot of effort into converting from struct edid to struct
> >> drm_edid, passing that around in drm_edid.c, with the allocation size it
> >> provides, and generally cleaning stuff up.
> >>
> >> I'm not at all happy to see *another* struct added just for the base
> >> block, and detailed timing iteration as well as monitor name parsing
> >> duplicated.
> >>
> >> With struct drm_edid you can actually return an 

Re: [PATCH v3 2/4] drm/edid: Add a function to check monitor string

2024-03-04 Thread Hsin-Yi Wang
On Mon, Mar 4, 2024 at 12:38 PM Jani Nikula  wrote:
>
> On Mon, 04 Mar 2024, Hsin-Yi Wang  wrote:
> > Add a function to check if the EDID base block contains a given string.
> >
> > One of the use cases is fetching panel from a list of panel names, since
> > some panel vendors put the monitor name after EDID_DETAIL_MONITOR_STRING
> > instead of EDID_DETAIL_MONITOR_NAME.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v2->v3: move string matching to drm_edid
> > ---
> >  drivers/gpu/drm/drm_edid.c | 49 ++
> >  include/drm/drm_edid.h |  1 +
> >  2 files changed, 50 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> > index 13454bc64ca2..fcdc2bd143dd 100644
> > --- a/drivers/gpu/drm/drm_edid.c
> > +++ b/drivers/gpu/drm/drm_edid.c
> > @@ -2789,6 +2789,55 @@ u32 drm_edid_get_panel_id(struct edid_base_block 
> > *base_block)
> >  }
> >  EXPORT_SYMBOL(drm_edid_get_panel_id);
> >
> > +/**
> > + * drm_edid_has_monitor_string - Check if a EDID base block has certain 
> > string.
> > + * @base_block: EDID base block to check.
> > + * @str: pointer to a character array to hold the string to be checked.
> > + *
> > + * Check if the detailed timings section of a EDID base block has the given
> > + * string.
> > + *
> > + * Return: True if the EDID base block contains the string, false 
> > otherwise.
> > + */
> > +bool drm_edid_has_monitor_string(struct edid_base_block *base_block, const 
> > char *str)
> > +{
> > + unsigned int i, j, k, buflen = strlen(str);
> > +
> > + for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
> > + struct detailed_timing *timing = 
> > _block->edid.detailed_timings[i];
> > + unsigned int size = 
> > ARRAY_SIZE(timing->data.other_data.data.str.str);
> > +
> > + if (buflen > size || timing->pixel_clock != 0 ||
> > + timing->data.other_data.pad1 != 0 ||
> > + (timing->data.other_data.type != EDID_DETAIL_MONITOR_NAME 
> > &&
> > +  timing->data.other_data.type != 
> > EDID_DETAIL_MONITOR_STRING))
> > + continue;
> > +
> > + for (j = 0; j < buflen; j++) {
> > + char c = timing->data.other_data.data.str.str[j];
> > +
> > + if (c != str[j] ||  c == '\n')
> > + break;
> > + }
> > +
> > + if (j == buflen) {
> > + /* Allow trailing white spaces. */
> > + for (k = j; k < size; k++) {
> > + char c = 
> > timing->data.other_data.data.str.str[k];
> > +
> > + if (c == '\n')
> > + return true;
> > + else if (c != ' ')
> > + break;
> > + }
> > + if (k == size)
> > + return true;
> > + }
> > + }
> > +
> > + return false;
> > +}
> > +
>
> So we've put a lot of effort into converting from struct edid to struct
> drm_edid, passing that around in drm_edid.c, with the allocation size it
> provides, and generally cleaning stuff up.
>
> I'm not at all happy to see *another* struct added just for the base
> block, and detailed timing iteration as well as monitor name parsing
> duplicated.
>
> With struct drm_edid you can actually return an EDID that only has the
> base block and size 128, even if the EDID indicates more
> extensions. Because the whole thing is *designed* to handle that
> gracefully. The allocated size matters, not what the blob originating
> outside of the kernel tells you.
>
> What I'm thinking is:
>
> - Add some struct drm_edid_ident or similar. Add all the information
>   that's needed to identify a panel there. I guess initially that's
>   panel_id and name.
>
> struct drm_edid_ident {
> u32 panel_id;
> const char *name;
> };
>
> - Add function:
>
> bool drm_edid_match(const struct drm_edid *drm_edid, const struct 
> drm_edid_ident *ident);
>
>   Check if stuff in ident matches drm_edid. You can use and extend the
>   existing drm_edid based iteration etc. in
>   drm_edid.c. Straightforward. The fields in ident can trivially be
>   extended later, and the stuff can be useful

Re: [PATCH v2 3/3] drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-03-04 Thread Hsin-Yi Wang
On Wed, Feb 28, 2024 at 4:22 PM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Feb 27, 2024 at 5:11 PM Hsin-Yi Wang  wrote:
> >
> > There are 2 different AUO panels using the same panel id. One of the
> > variants requires using overridden modes to resolve glitching issue as
> > described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
> > Other variants should use the modes parsed from EDID.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v2: new
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 17 -
> >  1 file changed, 16 insertions(+), 1 deletion(-)
>
> The previous version of this patch that we reverted also had an
> override for AUO 0x615c. Is that one no longer needed?
>

I currently don't have the exact panel to verify at hand. If the
dependent code is agreed and accepted, I will send out a patch for
this panel later.


>
> > @@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] = {
> > EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
> > "B116XAN06.1"),
> > EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
> > "B116XTN02.5"),
> > EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
> > "B140HAN04.0"),
> > -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > "B116XAK01.0"),
> > +   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > "B116XAN04.0 "),
> > +   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > "B116XAK01.0 ",
> > +_b116xa3_mode),
>
> The name string now has a space at the end of it. I _guess_ that's OK.
> Hmmm, but I guess you should update the kernel doc for "struct
> edp_panel_entry". The name field is described as "Name of this panel
> (for printing to logs)". Now it should include that it's also used for
> matching EDIDs in some cases too.


Re: [PATCH 1/2] drm_edid: Add a function to get EDID base block

2024-03-04 Thread Hsin-Yi Wang
On Mon, Mar 4, 2024 at 8:17 AM Doug Anderson  wrote:
>
> Hi,
>
> On Sun, Mar 3, 2024 at 1:30 PM Dmitry Baryshkov
>  wrote:
> >
> > > The problem is that Dmitry didn't like the idea of using a hash and in
> > > v2 Hsin-Yi has moved to using the name of the display. ...except of
> > > course that eDP panels don't always properly specify
> > > "EDID_DETAIL_MONITOR_NAME". See the discussion [1]. If you want to see
> > > some of the EDIDs involved, you can see Hsin-Yi's post [2]. The panels
> > > included stuff like this:
> > >
> > > Alphanumeric Data String: 'AUO'
> > > Alphanumeric Data String: 'B116XAN04.0 '
> > >
> > > The fact that there is more than one string in there makes it hard to
> > > just "return" the display name in a generic way. The way Hsin-Yi's
> > > code was doing it was that it would consider it a match if the panel
> > > name was in any of the strings...
> > >
> > > How about this as a solution: we change drm_edid_get_panel_id() to
> > > return an opaque type (struct drm_edid_panel_id_blob) that's really
> > > just the first block of the EDID but we can all pretend that it isn't.
> > > Then we can add a function in drm_edid.c that takes this opaque blob,
> > > a 32-bit integer (as per drm_edid_encode_panel_id()), and a string
> > > name and it can tell us if the blob matches?
> >
> > Would it be easier to push drm_edid_match to drm_edid.c? It looks way
> > more simpler than the opaque blob.
>
> Yeah, that sounds reasonable / cleaner to me. Good idea! Maybe Hsin-Yi
> will be able to try this out and see if there's a reason it wouldn't
> work.

Thanks for all the suggestions. I sent out v3, which still has a blob
type since we need
1. get panel id
2. do the string matching.

And I felt that packing these 2 steps into one function may make that
function do multiple tasks?

But let me know if it's preferred in this way.

v3: https://lore.kernel.org/lkml/20240304195214.14563-1-hsi...@chromium.org/

>
> -Doug


[PATCH v3 4/4] drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-03-04 Thread Hsin-Yi Wang
There are 2 different AUO panels using the same panel id. One of the
variants requires using overridden modes to resolve glitching issue as
described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
Other variants should use the modes parsed from EDID.

Signed-off-by: Hsin-Yi Wang 
---
v2->v3: no change.
---
 drivers/gpu/drm/panel/panel-edp.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index e3044e34c5f8..d2e181efff98 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1011,6 +1011,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1966,7 +1979,9 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAN04.0"),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0 ",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, _200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
-- 
2.44.0.rc1.240.g4c46232300-goog



[PATCH v3 3/4] drm/panel: panel-edp: Match edp_panels with panel name

2024-03-04 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. When matching generic edp
panels, we should first match with both panel id and panel name by checking
if edid contains the name string. If not found, match with panel id only.

Signed-off-by: Hsin-Yi Wang 
---
v2->v3: move string matching to drm_edid
---
 drivers/gpu/drm/panel/panel-edp.c | 19 +--
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index fc2d648fd3ab..e3044e34c5f8 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -761,7 +761,8 @@ static void panel_edp_parse_panel_timing_node(struct device 
*dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
 }
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id,
+   struct edid_base_block 
*base_block);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
@@ -799,7 +800,6 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
base_block = drm_edid_get_base_block(panel->ddc);
if (base_block) {
panel_id = drm_edid_get_panel_id(base_block);
-   kfree(base_block);
} else {
dev_err(dev, "Couldn't identify panel via EDID\n");
ret = -EIO;
@@ -807,7 +807,9 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
}
drm_edid_decode_panel_id(panel_id, vend, _id);
 
-   panel->detected_panel = find_edp_panel(panel_id);
+   panel->detected_panel = find_edp_panel(panel_id, base_block);
+
+   kfree(base_block);
 
/*
 * We're using non-optimized timings and want it really obvious that
@@ -2087,13 +2089,18 @@ static const struct edp_panel_entry edp_panels[] = {
{ /* sentinal */ }
 };
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id,
+   struct edid_base_block 
*base_block)
 {
const struct edp_panel_entry *panel;
 
-   if (!panel_id)
-   return NULL;
+/* Match with both panel_id and name */
+   for (panel = edp_panels; panel->panel_id; panel++)
+   if (panel->panel_id == panel_id &&
+   drm_edid_has_monitor_string(base_block, panel->name))
+   return panel;
 
+   /* Match with only panel_id */
for (panel = edp_panels; panel->panel_id; panel++)
if (panel->panel_id == panel_id)
return panel;
-- 
2.44.0.rc1.240.g4c46232300-goog



[PATCH v3 1/4] drm_edid: Add a function to get EDID base block

2024-03-04 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. Besides panel id, now we need
more information from the EDID base block to distinguish these panel
variants.

Add drm_edid_get_base_block() to return the EDID base block, which is
introduced as a new type edid_base_block with the same layout as edid.

Caller can further use it to get panel id or check if the block contains
certain strings, such as panel name.

Signed-off-by: Hsin-Yi Wang 
---
v2->v3: change back to return only the first block.
---
 drivers/gpu/drm/drm_edid.c| 58 ++-
 drivers/gpu/drm/panel/panel-edp.c |  8 +++--
 include/drm/drm_edid.h|  7 +++-
 3 files changed, 45 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..13454bc64ca2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2770,58 +2770,66 @@ static u32 edid_extract_panel_id(const struct edid 
*edid)
 }
 
 /**
- * drm_edid_get_panel_id - Get a panel's ID through DDC
- * @adapter: I2C adapter to use for DDC
+ * drm_edid_get_panel_id - Get a panel's ID from EDID base block
+ * @base_block: EDID base block that contains panel ID.
  *
- * This function reads the first block of the EDID of a panel and (assuming
+ * This function uses the first block of the EDID of a panel and (assuming
  * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
  * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
  * supposed to be different for each different modem of panel.
  *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID.
+ */
+u32 drm_edid_get_panel_id(struct edid_base_block *base_block)
+{
+   return edid_extract_panel_id(_block->edid);
+}
+EXPORT_SYMBOL(drm_edid_get_panel_id);
+
+/**
+ * drm_edid_get_base_block - Get a panel's EDID base block
+ * @adapter: I2C adapter to use for DDC
+ *
+ * This function returns the first block of the EDID of a panel.
+ *
  * This function is intended to be used during early probing on devices where
  * more than one panel might be present. Because of its intended use it must
- * assume that the EDID of the panel is correct, at least as far as the ID
- * is concerned (in other words, we don't process any overrides here).
+ * assume that the EDID of the panel is correct, at least as far as the base
+ * block is concerned (in other words, we don't process any overrides here).
  *
  * NOTE: it's expected that this function and drm_do_get_edid() will both
  * be read the EDID, but there is no caching between them. Since we're only
  * reading the first block, hopefully this extra overhead won't be too big.
  *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
+ * Caller should free the base block after use.
+ *
+ * Return: Pointer to allocated EDID base block, or NULL if failed.
  */
-
-u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
+struct edid_base_block *drm_edid_get_base_block(struct i2c_adapter *adapter)
 {
enum edid_block_status status;
void *base_block;
-   u32 panel_id = 0;
-
-   /*
-* There are no manufacturer IDs of 0, so if there is a problem reading
-* the EDID then we'll just return 0.
-*/
 
base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
if (!base_block)
-   return 0;
+   return NULL;
 
status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter);
 
edid_block_status_print(status, base_block, 0);
 
-   if (edid_block_status_valid(status, edid_block_tag(base_block)))
-   panel_id = edid_extract_panel_id(base_block);
-   else
+   if (!edid_block_status_valid(status, edid_block_tag(base_block))) {
edid_block_dump(KERN_NOTICE, base_block, 0);
+   kfree(base_block);
+   return NULL;
+   }
 
-   kfree(base_block);
-
-   return panel_id;
+   return base_block;
 }
-EXPORT_SYMBOL(drm_edid_get_panel_id);
+EXPORT_SYMBOL(drm_edid_get_base_block);
 
 /**
  * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 745f3e48f02a..fc2d648fd3ab 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -766,6 +766,7 @@ static const struct edp_panel_entry *find_edp_panel(u32 
panel_id);
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
struct panel_desc *desc;
+   

[PATCH v3 2/4] drm/edid: Add a function to check monitor string

2024-03-04 Thread Hsin-Yi Wang
Add a function to check if the EDID base block contains a given string.

One of the use cases is fetching panel from a list of panel names, since
some panel vendors put the monitor name after EDID_DETAIL_MONITOR_STRING
instead of EDID_DETAIL_MONITOR_NAME.

Signed-off-by: Hsin-Yi Wang 
---
v2->v3: move string matching to drm_edid
---
 drivers/gpu/drm/drm_edid.c | 49 ++
 include/drm/drm_edid.h |  1 +
 2 files changed, 50 insertions(+)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 13454bc64ca2..fcdc2bd143dd 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2789,6 +2789,55 @@ u32 drm_edid_get_panel_id(struct edid_base_block 
*base_block)
 }
 EXPORT_SYMBOL(drm_edid_get_panel_id);
 
+/**
+ * drm_edid_has_monitor_string - Check if a EDID base block has certain string.
+ * @base_block: EDID base block to check.
+ * @str: pointer to a character array to hold the string to be checked.
+ *
+ * Check if the detailed timings section of a EDID base block has the given
+ * string.
+ *
+ * Return: True if the EDID base block contains the string, false otherwise.
+ */
+bool drm_edid_has_monitor_string(struct edid_base_block *base_block, const 
char *str)
+{
+   unsigned int i, j, k, buflen = strlen(str);
+
+   for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
+   struct detailed_timing *timing = 
_block->edid.detailed_timings[i];
+   unsigned int size = 
ARRAY_SIZE(timing->data.other_data.data.str.str);
+
+   if (buflen > size || timing->pixel_clock != 0 ||
+   timing->data.other_data.pad1 != 0 ||
+   (timing->data.other_data.type != EDID_DETAIL_MONITOR_NAME &&
+timing->data.other_data.type != 
EDID_DETAIL_MONITOR_STRING))
+   continue;
+
+   for (j = 0; j < buflen; j++) {
+   char c = timing->data.other_data.data.str.str[j];
+
+   if (c != str[j] ||  c == '\n')
+   break;
+   }
+
+   if (j == buflen) {
+   /* Allow trailing white spaces. */
+   for (k = j; k < size; k++) {
+   char c = 
timing->data.other_data.data.str.str[k];
+
+   if (c == '\n')
+   return true;
+   else if (c != ' ')
+   break;
+   }
+   if (k == size)
+   return true;
+   }
+   }
+
+   return false;
+}
+
 /**
  * drm_edid_get_base_block - Get a panel's EDID base block
  * @adapter: I2C adapter to use for DDC
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 2455d6ab2221..248ddb0a6b5d 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -416,6 +416,7 @@ struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
 struct edid_base_block *drm_edid_get_base_block(struct i2c_adapter *adapter);
 u32 drm_edid_get_panel_id(struct edid_base_block *base_block);
+bool drm_edid_has_monitor_string(struct edid_base_block *base_block, const 
char *str);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
-- 
2.44.0.rc1.240.g4c46232300-goog



[PATCH v3 0/4] Match panel with id and name

2024-03-04 Thread Hsin-Yi Wang
This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
product id. One of them requires an overridden mode, while the other should
use the mode directly from edid.

Match the panel for both name and id. If not found, fallback to match id.

v1: https://lore.kernel.org/lkml/20240223223958.3887423-1-hsi...@chromium.org
v2: https://lore.kernel.org/lkml/20240228011133.1238439-1-hsi...@chromium.org

Hsin-Yi Wang (4):
  drm_edid: Add a function to get EDID base block
  drm/edid: Add a function to check monitor string
  drm/panel: panel-edp: Match edp_panels with panel name
  drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

 drivers/gpu/drm/drm_edid.c| 107 +++---
 drivers/gpu/drm/panel/panel-edp.c |  42 +---
 include/drm/drm_edid.h|   8 ++-
 3 files changed, 123 insertions(+), 34 deletions(-)

-- 
2.44.0.rc1.240.g4c46232300-goog



Re: [PATCH v2 3/3] drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-02-28 Thread Hsin-Yi Wang
On Wed, Feb 28, 2024 at 5:13 PM Dmitry Baryshkov
 wrote:
>
> On Thu, 29 Feb 2024 at 03:05, Hsin-Yi Wang  wrote:
> >
> > On Wed, Feb 28, 2024 at 4:22 PM Doug Anderson  wrote:
> > >
> > > Hi,
> > >
> > > On Tue, Feb 27, 2024 at 5:11 PM Hsin-Yi Wang  wrote:
> > > >
> > > > There are 2 different AUO panels using the same panel id. One of the
> > > > variants requires using overridden modes to resolve glitching issue as
> > > > described in commit 70e0d5550f5c ("drm/panel-edp: Add 
> > > > auo_b116xa3_mode").
> > > > Other variants should use the modes parsed from EDID.
> > > >
> > > > Signed-off-by: Hsin-Yi Wang 
> > > > ---
> > > > v2: new
> > > > ---
> > > >  drivers/gpu/drm/panel/panel-edp.c | 17 -
> > > >  1 file changed, 16 insertions(+), 1 deletion(-)
> > >
> > > The previous version of this patch that we reverted also had an
> > > override for AUO 0x615c. Is that one no longer needed?
> > >
> > >
> > > > @@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] 
> > > > = {
> > > > EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
> > > > "B116XAN06.1"),
> > > > EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
> > > > "B116XTN02.5"),
> > > > EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
> > > > "B140HAN04.0"),
> > > > -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > > > "B116XAK01.0"),
> > > > +   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > > > "B116XAN04.0 "),
> > > > +   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > > > "B116XAK01.0 ",
> > > > +_b116xa3_mode),
> > >
> > > The name string now has a space at the end of it. I _guess_ that's OK.
> > > Hmmm, but I guess you should update the kernel doc for "struct
> > > edp_panel_entry". The name field is described as "Name of this panel
> > > (for printing to logs)". Now it should include that it's also used for
> > > matching EDIDs in some cases too.
> >
> > The space here is because in the EDID, there is space at the end,
> > before 0x0a (\n).
> > Okay I will update the kernel doc to mention that the same should be
> > exactly the same as the panel name.
>
> Maybe it would be better to strip all the whitespace on the right?
>

Sounds good too.

> --
> With best wishes
> Dmitry


Re: [PATCH v2 3/3] drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-02-28 Thread Hsin-Yi Wang
On Wed, Feb 28, 2024 at 4:22 PM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Feb 27, 2024 at 5:11 PM Hsin-Yi Wang  wrote:
> >
> > There are 2 different AUO panels using the same panel id. One of the
> > variants requires using overridden modes to resolve glitching issue as
> > described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
> > Other variants should use the modes parsed from EDID.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v2: new
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 17 -
> >  1 file changed, 16 insertions(+), 1 deletion(-)
>
> The previous version of this patch that we reverted also had an
> override for AUO 0x615c. Is that one no longer needed?
>
>
> > @@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] = {
> > EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
> > "B116XAN06.1"),
> > EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
> > "B116XTN02.5"),
> > EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
> > "B140HAN04.0"),
> > -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > "B116XAK01.0"),
> > +   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > "B116XAN04.0 "),
> > +   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> > "B116XAK01.0 ",
> > +_b116xa3_mode),
>
> The name string now has a space at the end of it. I _guess_ that's OK.
> Hmmm, but I guess you should update the kernel doc for "struct
> edp_panel_entry". The name field is described as "Name of this panel
> (for printing to logs)". Now it should include that it's also used for
> matching EDIDs in some cases too.

The space here is because in the EDID, there is space at the end,
before 0x0a (\n).
Okay I will update the kernel doc to mention that the same should be
exactly the same as the panel name.


Re: [PATCH v2 1/3] drm_edid: Support getting EDID through ddc without connector

2024-02-28 Thread Hsin-Yi Wang
On Wed, Feb 28, 2024 at 4:21 PM Doug Anderson  wrote:
>
> Hi,
>
> On Tue, Feb 27, 2024 at 5:11 PM Hsin-Yi Wang  wrote:
> >
> > Some panels are interested in the EDID during early probe when connector
> > is still unknown.
> >
> > Add a function drm_get_edid_no_connector() to get edid without connector.
> > No functional change for existing usage.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v1->v2:
> > add a function to return the entire edid without updating connector.
> > ---
> >  drivers/gpu/drm/drm_edid.c | 45 --
> >  include/drm/drm_edid.h |  1 +
> >  2 files changed, 34 insertions(+), 12 deletions(-)
>
> I'll respond in the discussion in v1 too, but overall I'm not a fan of
> reading the whole EDID twice at bootup. Personally I'd love to see us
> to back to just reading the base block like in v1, but I guess we can
> see what Jani and others say.
>
>
> > @@ -2385,18 +2385,20 @@ static struct edid *_drm_do_get_edid(struct 
> > drm_connector *connector,
> > if (status == EDID_BLOCK_READ_FAIL)
> > goto fail;
> >
> > -   /* FIXME: Clarify what a corrupt EDID actually means. */
> > -   if (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION)
> > -   connector->edid_corrupt = false;
> > -   else
> > -   connector->edid_corrupt = true;
> > +   if (connector) {
> > +   /* FIXME: Clarify what a corrupt EDID actually means. */
> > +   if (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION)
> > +   connector->edid_corrupt = false;
> > +   else
> > +   connector->edid_corrupt = true;
> >
> > -   if (!edid_block_status_valid(status, edid_block_tag(edid))) {
> > -   if (status == EDID_BLOCK_ZERO)
> > -   connector->null_edid_counter++;
> > +   if (!edid_block_status_valid(status, edid_block_tag(edid))) 
> > {
> > +   if (status == EDID_BLOCK_ZERO)
> > +   connector->null_edid_counter++;
> >
> > -   connector_bad_edid(connector, edid, 1);
> > -   goto fail;
> > +   connector_bad_edid(connector, edid, 1);
> > +   goto fail;
>
> This "goto fail" is now only run "if (connector)" which means that
> you're not properly checking if the EDID is valid when "connector ==
> NULL", right? That seems like a bug unless I missed something...

We can't check with connector_bad_edid() since there's no connector.
But we still check with edid_block_read() status, similar to what the
original drm_edid_get_panel_id() checks.


Re: [PATCH v2 1/3] drm_edid: Support getting EDID through ddc without connector

2024-02-27 Thread Hsin-Yi Wang
On Tue, Feb 27, 2024 at 5:11 PM Hsin-Yi Wang  wrote:
>
> Some panels are interested in the EDID during early probe when connector
> is still unknown.
>
> Add a function drm_get_edid_no_connector() to get edid without connector.
> No functional change for existing usage.
>
> Signed-off-by: Hsin-Yi Wang 
> ---
> v1->v2:
> add a function to return the entire edid without updating connector.
> ---
>  drivers/gpu/drm/drm_edid.c | 45 --
>  include/drm/drm_edid.h |  1 +
>  2 files changed, 34 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 1ad94473e400..15b97c8ed993 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -2364,7 +2364,7 @@ static struct edid *_drm_do_get_edid(struct 
> drm_connector *connector,
> struct edid *edid, *new;
> size_t alloc_size = EDID_LENGTH;
>
> -   override = drm_edid_override_get(connector);
> +   override = connector ? drm_edid_override_get(connector) : false;

typo: should be NULL here. I'll update in the next version with other comments.

> if (override) {
> alloc_size = override->size;
> edid = kmemdup(override->edid, alloc_size, GFP_KERNEL);
> @@ -2385,18 +2385,20 @@ static struct edid *_drm_do_get_edid(struct 
> drm_connector *connector,
> if (status == EDID_BLOCK_READ_FAIL)
> goto fail;
>
> -   /* FIXME: Clarify what a corrupt EDID actually means. */
> -   if (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION)
> -   connector->edid_corrupt = false;
> -   else
> -   connector->edid_corrupt = true;
> +   if (connector) {
> +   /* FIXME: Clarify what a corrupt EDID actually means. */
> +   if (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION)
> +   connector->edid_corrupt = false;
> +   else
> +   connector->edid_corrupt = true;
>
> -   if (!edid_block_status_valid(status, edid_block_tag(edid))) {
> -   if (status == EDID_BLOCK_ZERO)
> -   connector->null_edid_counter++;
> +   if (!edid_block_status_valid(status, edid_block_tag(edid))) {
> +   if (status == EDID_BLOCK_ZERO)
> +   connector->null_edid_counter++;
>
> -   connector_bad_edid(connector, edid, 1);
> -   goto fail;
> +   connector_bad_edid(connector, edid, 1);
> +   goto fail;
> +   }
> }
>
> if (!edid_extension_block_count(edid))
> @@ -2444,7 +2446,8 @@ static struct edid *_drm_do_get_edid(struct 
> drm_connector *connector,
> }
>
> if (invalid_blocks) {
> -   connector_bad_edid(connector, edid, num_blocks);
> +   if (connector)
> +   connector_bad_edid(connector, edid, num_blocks);
>
> edid = edid_filter_invalid_blocks(edid, _size);
> }
> @@ -2637,6 +2640,24 @@ struct edid *drm_get_edid(struct drm_connector 
> *connector,
>  }
>  EXPORT_SYMBOL(drm_get_edid);
>
> +/**
> + * drm_get_edid_no_connector - get EDID data without updating connector 
> status
> + * @adapter: I2C adapter to use for DDC
> + *
> + * Similar to drm_edid_read_ddc(), but not checking any connector status. Use
> + * this function to get EDID when connector is still unknown.
> + *
> + * Return: Pointer to valid EDID or NULL if we couldn't find any.
> + */
> +struct edid *drm_get_edid_no_connector(struct i2c_adapter *adapter)
> +{
> +   if (!drm_probe_ddc(adapter))
> +   return NULL;
> +
> +   return _drm_do_get_edid(NULL, drm_do_probe_ddc_edid, adapter, NULL);
> +}
> +EXPORT_SYMBOL(drm_get_edid_no_connector);
> +
>  /**
>   * drm_edid_read_custom - Read EDID data using given EDID block read function
>   * @connector: Connector to use
> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
> index 70ae6c290bdc..80c9e32ff80e 100644
> --- a/include/drm/drm_edid.h
> +++ b/include/drm/drm_edid.h
> @@ -565,6 +565,7 @@ struct edid *drm_do_get_edid(struct drm_connector 
> *connector,
> void *data);
>  struct edid *drm_get_edid(struct drm_connector *connector,
>   struct i2c_adapter *adapter);
> +struct edid *drm_get_edid_no_connector(struct i2c_adapter *adapter);
>  u32 drm_edid_get_panel_id(struct i2c_adapter *adapter);
>  struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
>  struct i2c_adapter *adapter);
> --
> 2.44.0.rc1.240.g4c46232300-goog
>


Re: [PATCH 1/2] drm_edid: Add a function to get EDID base block

2024-02-27 Thread Hsin-Yi Wang
On Tue, Feb 27, 2024 at 1:09 AM Jani Nikula  wrote:
>
> On Fri, 23 Feb 2024, Hsin-Yi Wang  wrote:
> > It's found that some panels have variants that they share the same panel id
> > although their EDID and names are different. Besides panel id, now we need
> > the hash of entire EDID base block to distinguish these panel variants.
> >
> > Add drm_edid_get_base_block to returns the EDID base block, so caller can
> > further use it to get panel id and/or the hash.
>
> Please reconsider the whole approach here.
>
> Please let's not add single-use special case functions to read an EDID
> base block.
>
> Please consider reading the whole EDID, using the regular EDID reading
> functions, and use that instead.
>
> Most likely you'll only have 1-2 blocks anyway. And you might consider
> caching the EDID in struct panel_edp if reading the entire EDID is too
> slow. (And if it is, this is probably sensible even if the EDID only
> consists of one block.)
>
> Anyway, please do *not* merge this as-is.
>

hi Jani,

I sent a v2 here implementing this method:
https://lore.kernel.org/lkml/20240228011133.1238439-2-hsi...@chromium.org/

We still have to read edid twice due to:
1. The first caller is in panel probe, at that time, connector is
still unknown, so we can't update connector status (eg. update
edid_corrupt).
2. It's possible that the connector can have some override
(drm_edid_override_get) to EDID, that is still unknown during the
first read.

> BR,
> Jani.
>
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> >  drivers/gpu/drm/drm_edid.c| 55 +--
> >  drivers/gpu/drm/panel/panel-edp.c |  8 +++--
> >  include/drm/drm_edid.h|  3 +-
> >  3 files changed, 38 insertions(+), 28 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> > index 923c4423151c..55598ca4a5d1 100644
> > --- a/drivers/gpu/drm/drm_edid.c
> > +++ b/drivers/gpu/drm/drm_edid.c
> > @@ -2770,58 +2770,63 @@ static u32 edid_extract_panel_id(const struct edid 
> > *edid)
> >  }
> >
> >  /**
> > - * drm_edid_get_panel_id - Get a panel's ID through DDC
> > - * @adapter: I2C adapter to use for DDC
> > + * drm_edid_get_panel_id - Get a panel's ID from EDID base block
> > + * @base_bock: EDID base block that contains panel ID.
> >   *
> > - * This function reads the first block of the EDID of a panel and (assuming
> > + * This function uses the first block of the EDID of a panel and (assuming
> >   * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit 
> > value
> >   * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
> >   * supposed to be different for each different modem of panel.
> >   *
> > + * Return: A 32-bit ID that should be different for each make/model of 
> > panel.
> > + * See the functions drm_edid_encode_panel_id() and
> > + * drm_edid_decode_panel_id() for some details on the structure of 
> > this
> > + * ID.
> > + */
> > +u32 drm_edid_get_panel_id(void *base_block)
> > +{
> > + return edid_extract_panel_id(base_block);
> > +}
> > +EXPORT_SYMBOL(drm_edid_get_panel_id);
> > +
> > +/**
> > + * drm_edid_get_base_block - Get a panel's EDID base block
> > + * @adapter: I2C adapter to use for DDC
> > + *
> > + * This function returns the first block of the EDID of a panel.
> > + *
> >   * This function is intended to be used during early probing on devices 
> > where
> >   * more than one panel might be present. Because of its intended use it 
> > must
> > - * assume that the EDID of the panel is correct, at least as far as the ID
> > - * is concerned (in other words, we don't process any overrides here).
> > + * assume that the EDID of the panel is correct, at least as far as the 
> > base
> > + * block is concerned (in other words, we don't process any overrides 
> > here).
> >   *
> >   * NOTE: it's expected that this function and drm_do_get_edid() will both
> >   * be read the EDID, but there is no caching between them. Since we're only
> >   * reading the first block, hopefully this extra overhead won't be too big.
> >   *
> > - * Return: A 32-bit ID that should be different for each make/model of 
> > panel.
> > - * See the functions drm_edid_encode_panel_id() and
> > - * drm_edid_decode_panel_id() for some details on the structure of 
> > this
> > - * ID.
> > + * Caller should free the base block after use.
> >   */
> > -
> > 

[PATCH v2 1/3] drm_edid: Support getting EDID through ddc without connector

2024-02-27 Thread Hsin-Yi Wang
Some panels are interested in the EDID during early probe when connector
is still unknown.

Add a function drm_get_edid_no_connector() to get edid without connector.
No functional change for existing usage.

Signed-off-by: Hsin-Yi Wang 
---
v1->v2:
add a function to return the entire edid without updating connector.
---
 drivers/gpu/drm/drm_edid.c | 45 --
 include/drm/drm_edid.h |  1 +
 2 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 1ad94473e400..15b97c8ed993 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2364,7 +2364,7 @@ static struct edid *_drm_do_get_edid(struct drm_connector 
*connector,
struct edid *edid, *new;
size_t alloc_size = EDID_LENGTH;
 
-   override = drm_edid_override_get(connector);
+   override = connector ? drm_edid_override_get(connector) : false;
if (override) {
alloc_size = override->size;
edid = kmemdup(override->edid, alloc_size, GFP_KERNEL);
@@ -2385,18 +2385,20 @@ static struct edid *_drm_do_get_edid(struct 
drm_connector *connector,
if (status == EDID_BLOCK_READ_FAIL)
goto fail;
 
-   /* FIXME: Clarify what a corrupt EDID actually means. */
-   if (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION)
-   connector->edid_corrupt = false;
-   else
-   connector->edid_corrupt = true;
+   if (connector) {
+   /* FIXME: Clarify what a corrupt EDID actually means. */
+   if (status == EDID_BLOCK_OK || status == EDID_BLOCK_VERSION)
+   connector->edid_corrupt = false;
+   else
+   connector->edid_corrupt = true;
 
-   if (!edid_block_status_valid(status, edid_block_tag(edid))) {
-   if (status == EDID_BLOCK_ZERO)
-   connector->null_edid_counter++;
+   if (!edid_block_status_valid(status, edid_block_tag(edid))) {
+   if (status == EDID_BLOCK_ZERO)
+   connector->null_edid_counter++;
 
-   connector_bad_edid(connector, edid, 1);
-   goto fail;
+   connector_bad_edid(connector, edid, 1);
+   goto fail;
+   }
}
 
if (!edid_extension_block_count(edid))
@@ -2444,7 +2446,8 @@ static struct edid *_drm_do_get_edid(struct drm_connector 
*connector,
}
 
if (invalid_blocks) {
-   connector_bad_edid(connector, edid, num_blocks);
+   if (connector)
+   connector_bad_edid(connector, edid, num_blocks);
 
edid = edid_filter_invalid_blocks(edid, _size);
}
@@ -2637,6 +2640,24 @@ struct edid *drm_get_edid(struct drm_connector 
*connector,
 }
 EXPORT_SYMBOL(drm_get_edid);
 
+/**
+ * drm_get_edid_no_connector - get EDID data without updating connector status
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Similar to drm_edid_read_ddc(), but not checking any connector status. Use
+ * this function to get EDID when connector is still unknown.
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+struct edid *drm_get_edid_no_connector(struct i2c_adapter *adapter)
+{
+   if (!drm_probe_ddc(adapter))
+   return NULL;
+
+   return _drm_do_get_edid(NULL, drm_do_probe_ddc_edid, adapter, NULL);
+}
+EXPORT_SYMBOL(drm_get_edid_no_connector);
+
 /**
  * drm_edid_read_custom - Read EDID data using given EDID block read function
  * @connector: Connector to use
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 70ae6c290bdc..80c9e32ff80e 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -565,6 +565,7 @@ struct edid *drm_do_get_edid(struct drm_connector 
*connector,
void *data);
 struct edid *drm_get_edid(struct drm_connector *connector,
  struct i2c_adapter *adapter);
+struct edid *drm_get_edid_no_connector(struct i2c_adapter *adapter);
 u32 drm_edid_get_panel_id(struct i2c_adapter *adapter);
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct i2c_adapter *adapter);
-- 
2.44.0.rc1.240.g4c46232300-goog



[PATCH v2 2/3] drm/panel: panel-edp: Match edp_panels with panel name

2024-02-27 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. When matching generic edp
panels, we should first match with both panel id and panel name by checking
if edid contains the name string. If not found, match with panel id only.

Signed-off-by: Hsin-Yi Wang 
---
v1->v2:
match with panel name instead of crc hash.
Note that we can't directly use drm_edid_get_monitor_name(), because some
panel store the name after EDID_DETAIL_MONITOR_STRING instead of
EDID_DETAIL_MONITOR_NAME.
---
 drivers/gpu/drm/drm_edid.c| 69 +++
 drivers/gpu/drm/panel/panel-edp.c | 44 +---
 include/drm/drm_edid.h|  2 +-
 3 files changed, 54 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 15b97c8ed993..c4126475ff0a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2764,7 +2764,19 @@ const struct drm_edid *drm_edid_read(struct 
drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_edid_read);
 
-static u32 edid_extract_panel_id(const struct edid *edid)
+/**
+ * edid_extract_panel_id - Extract a panel's ID from EDID
+ * @edid: EDID used to extract the panel's ID.
+ *
+ * Extract panel ID from EDID.
+ *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID.
+ */
+
+u32 edid_extract_panel_id(const struct edid *edid)
 {
/*
 * We represent the ID as a 32-bit number so it can easily be compared
@@ -2783,60 +2795,7 @@ static u32 edid_extract_panel_id(const struct edid *edid)
   (u32)edid->mfg_id[1] << 16   |
   (u32)EDID_PRODUCT_ID(edid);
 }
-
-/**
- * drm_edid_get_panel_id - Get a panel's ID through DDC
- * @adapter: I2C adapter to use for DDC
- *
- * This function reads the first block of the EDID of a panel and (assuming
- * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
- * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
- * supposed to be different for each different modem of panel.
- *
- * This function is intended to be used during early probing on devices where
- * more than one panel might be present. Because of its intended use it must
- * assume that the EDID of the panel is correct, at least as far as the ID
- * is concerned (in other words, we don't process any overrides here).
- *
- * NOTE: it's expected that this function and drm_do_get_edid() will both
- * be read the EDID, but there is no caching between them. Since we're only
- * reading the first block, hopefully this extra overhead won't be too big.
- *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
- */
-
-u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
-{
-   enum edid_block_status status;
-   void *base_block;
-   u32 panel_id = 0;
-
-   /*
-* There are no manufacturer IDs of 0, so if there is a problem reading
-* the EDID then we'll just return 0.
-*/
-
-   base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
-   if (!base_block)
-   return 0;
-
-   status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter);
-
-   edid_block_status_print(status, base_block, 0);
-
-   if (edid_block_status_valid(status, edid_block_tag(base_block)))
-   panel_id = edid_extract_panel_id(base_block);
-   else
-   edid_block_dump(KERN_NOTICE, base_block, 0);
-
-   kfree(base_block);
-
-   return panel_id;
-}
-EXPORT_SYMBOL(drm_edid_get_panel_id);
+EXPORT_SYMBOL(edid_extract_panel_id);
 
 /**
  * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 3fb5fcd326a4..72ad552bff24 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -761,11 +761,13 @@ static void panel_edp_parse_panel_timing_node(struct 
device *dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
 }
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
+static bool edid_has_name(struct edid *edid, const char *panel_name);
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id, struct edid 
*edid);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
struct panel_desc *desc;
+   struct edid *edid;
u32 panel_id;
char vend[4];
u16 product_id;
@@ -795,15 +797,19 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
   

[PATCH v2 0/3] Match panel with id and name

2024-02-27 Thread Hsin-Yi Wang
This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
product id. One of them requires an overridden mode, while the other should
use the mode directly from edid.

Match the panel for both name and id. If not found, fallback to match id.

v1: https://lore.kernel.org/lkml/20240223223958.3887423-1-hsi...@chromium.org/T/

Hsin-Yi Wang (3):
  drm_edid: Support getting EDID through ddc without connector
  drm/panel: panel-edp: Match edp_panels with panel name
  drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

 drivers/gpu/drm/drm_edid.c| 114 --
 drivers/gpu/drm/panel/panel-edp.c |  61 ++--
 include/drm/drm_edid.h|   3 +-
 3 files changed, 104 insertions(+), 74 deletions(-)

-- 
2.44.0.rc1.240.g4c46232300-goog



[PATCH v2 3/3] drm/panel: panel-edp: Fix AUO 0x405c panel naming and add a variant

2024-02-27 Thread Hsin-Yi Wang
There are 2 different AUO panels using the same panel id. One of the
variants requires using overridden modes to resolve glitching issue as
described in commit 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode").
Other variants should use the modes parsed from EDID.

Signed-off-by: Hsin-Yi Wang 
---
v2: new
---
 drivers/gpu/drm/panel/panel-edp.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 72ad552bff24..e39af92342e8 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1013,6 +1013,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1990,7 +2003,9 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAN04.0 "),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0 ",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, _200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
-- 
2.44.0.rc1.240.g4c46232300-goog



Re: [PATCH 0/2] Match panel hash for overridden mode

2024-02-26 Thread Hsin-Yi Wang
On Mon, Feb 26, 2024 at 4:37 PM Dmitry Baryshkov
 wrote:
>
> On Sat, 24 Feb 2024 at 00:40, Hsin-Yi Wang  wrote:
> >
> > This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
> > auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
> > product id. One of them requires an overridden mode, while the other should
> > use the mode directly from edid.
> >
> > Since product id match is no longer sufficient, EDP_PANEL_ENTRY2 is extended
> > to check the crc hash of the entire edid base block.
>
> Do you have these EDIDs posted somewhere? Can we use something less
> cryptic than hash for matching the panel, e.g. strings from Monitor
> Descriptors?
>

Panel 1:

00 ff ff ff ff ff ff 00 06 af 5c 40 00 00 00 00
00 1a 01 04 95 1a 0e 78 02 99 85 95 55 56 92 28
22 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 12 1b 56 5a 50 00 19 30 30 20
46 00 00 90 10 00 00 18 00 00 00 0f 00 00 00 00
00 00 00 00 00 00 00 00 00 20 00 00 00 fe 00 41
55 4f 0a 20 20 20 20 20 20 20 20 20 00 00 00 fe
00 42 31 31 36 58 41 4b 30 31 2e 30 20 0a 00 cc



Block 0, Base EDID:
  EDID Structure Version & Revision: 1.4
  Vendor & Product Identification:
Manufacturer: AUO
Model: 16476
Made in: 2016
  Basic Display Parameters & Features:
Digital display
Bits per primary color channel: 6
DisplayPort interface
Maximum image size: 26 cm x 14 cm
Gamma: 2.20
Supported color formats: RGB 4:4:4
First detailed timing includes the native pixel format and
preferred refresh rate
  Color Characteristics:
Red  : 0.5839, 0.3330
Green: 0.3378, 0.5712
Blue : 0.1582, 0.1328
White: 0.3134, 0.3291
  Established Timings I & II: none
  Standard Timings: none
  Detailed Timing Descriptors:
DTD 1:  1366x76860.020 Hz 683:384  47.596 kHz   69.300 MHz
(256 mm x 144 mm)
 Hfront   48 Hsync  32 Hback  10 Hpol N
 Vfront4 Vsync   6 Vback  15 Vpol N
Manufacturer-Specified Display Descriptor (0x0f): 00 0f 00 00 00
00 00 00 00 00 00 00 00 00 00 20 '... '
Alphanumeric Data String: 'AUO'
Alphanumeric Data String: 'B116XAK01.0 '
Checksum: 0xcc


Panel 2:

00 ff ff ff ff ff ff 00 06 af 5c 40 00 00 00 00
00 19 01 04 95 1a 0e 78 02 99 85 95 55 56 92 28
22 50 54 00 00 00 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 ce 1d 56 ea 50 00 1a 30 30 20
46 00 00 90 10 00 00 18 d4 17 56 ea 50 00 1a 30
30 20 46 00 00 90 10 00 00 18 00 00 00 fe 00 41
55 4f 0a 20 20 20 20 20 20 20 20 20 00 00 00 fe
00 42 31 31 36 58 41 4e 30 34 2e 30 20 0a 00 94



Block 0, Base EDID:
  EDID Structure Version & Revision: 1.4
  Vendor & Product Identification:
Manufacturer: AUO
Model: 16476
Made in: 2015
  Basic Display Parameters & Features:
Digital display
Bits per primary color channel: 6
DisplayPort interface
Maximum image size: 26 cm x 14 cm
Gamma: 2.20
Supported color formats: RGB 4:4:4
First detailed timing includes the native pixel format and
preferred refresh rate
  Color Characteristics:
Red  : 0.5839, 0.3330
Green: 0.3378, 0.5712
Blue : 0.1582, 0.1328
White: 0.3134, 0.3291
  Established Timings I & II: none
  Standard Timings: none
  Detailed Timing Descriptors:
DTD 1:  1366x76860.059824 Hz 683:384   47.688 kHz
76.30 MHz (256 mm x 144 mm)
 Hfront   48 Hsync  32 Hback  154 Hpol N
 Vfront4 Vsync   6 Vback   16 Vpol N
DTD 2:  1366x76848.016373 Hz 683:384   38.125 kHz
61.00 MHz (256 mm x 144 mm)
 Hfront   48 Hsync  32 Hback  154 Hpol N
 Vfront4 Vsync   6 Vback   16 Vpol N
Alphanumeric Data String: 'AUO'
Alphanumeric Data String: 'B116XAN04.0 '
Checksum: 0x94

In this example, Descriptors can also be used to distinguish. But it's
possible that the name field is also reused by mistake, for the same
reason as model id is reused.


> >
> > Hsin-Yi Wang (2):
> >   drm_edid: Add a function to get EDID base block
> >   drm/panel: panel-edp: Match with panel hash for overridden modes
> >
> >  drivers/gpu/drm/drm_edid.c| 55 +++-
> >  drivers/gpu/drm/panel/panel-edp.c | 60 ++-
> >  include/drm/drm_edid.h|  3 +-
> >  3 files changed, 84 insertions(+), 34 deletions(-)
> >
> > --
> > 2.44.0.rc0.258.g7320e95886-goog
> >
>
>
> --
> With best wishes
> Dmitry


Re: [PATCH 2/2] drm/panel: panel-edp: Match with panel hash for overridden modes

2024-02-26 Thread Hsin-Yi Wang
On Mon, Feb 26, 2024 at 2:29 PM Doug Anderson  wrote:
>
> Hi,
>
> On Fri, Feb 23, 2024 at 2:40 PM Hsin-Yi Wang  wrote:
> >
> > It's found that some panels have variants that they share the same panel id
> > although their EDID and names are different. One of the variants requires
> > using overridden modes to resolve glitching issue as described in commit
> > 70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode"). Other variants should
> > use the modes parsed from EDID.
> >
> > For example, AUO 0x405c B116XAK01.0, it has at least 2 different variants
> > that EDID and panel name are different, but using the same panel id. One of
> > the variants require using overridden mode. Same case for AUO 0x615c
> > B116XAN06.1.
> >
> > Add such entries and use the hash of the EDID to match the panel needs the
> > overridden modes.
>
> As pointed out in an offline discussion, it's possible that we might
> want to "ignore" some of these bytes for the purpose of the CRC.
> Specifically, we might want to ignore:
> * byte 16 - Week of manufacture
> * byte 17 - Year of manufacture
> * byte 127 - Checksum
>
> That way if a manufacturer actually is updating those numbers in
> production we can still have one hash that captures all the panels. I
> have no idea if manufacturers actually are, but IMO the hash of the
> rest of the base block should be sufficient to differentiate between
> different panels anyway. It would be easy to just zero out those 3
> bytes before computing the CRC.
>
> What do you think?

Agreed that we can zero out these fields.

>
>
> > @@ -758,13 +762,13 @@ static void panel_edp_parse_panel_timing_node(struct 
> > device *dev,
> > dev_err(dev, "Reject override mode: No display_timing 
> > found\n");
> >  }
> >
> > -static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
> > +static const struct edp_panel_entry *find_edp_panel(u32 panel_id, u32 
> > panel_hash);
> >
> >  static int generic_edp_panel_probe(struct device *dev, struct panel_edp 
> > *panel)
> >  {
> > struct panel_desc *desc;
> > void *base_block;
> > -   u32 panel_id;
> > +   u32 panel_id, panel_hash;
> > char vend[4];
> > u16 product_id;
> > u32 reliable_ms = 0;
> > @@ -796,15 +800,17 @@ static int generic_edp_panel_probe(struct device 
> > *dev, struct panel_edp *panel)
> > base_block = drm_edid_get_base_block(panel->ddc);
> > if (base_block) {
> > panel_id = drm_edid_get_panel_id(base_block);
> > +   panel_hash = crc32_le(~0, base_block, EDID_LENGTH) ^ 
> > 0x;
>
> Any reason you need to XOR with 0x?
>
To be consistent with the crc32[1] command. It's more convenient to be
able to verify it with userspace tools.

[1] https://www.commandlinux.com/man-page/man1/crc32.1.html

>
> > @@ -2077,13 +2098,32 @@ static const struct edp_panel_entry edp_panels[] = {
> > { /* sentinal */ }
> >  };
> >
> > -static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
> > +/*
> > + * Similar to edp_panels, this table lists panel variants that require 
> > using
> > + * overridden modes but have the same panel id as one of the entries in 
> > edp_panels.
> > + *
> > + * Sort first by vendor, then by product ID.
>
> Add ", then by hash" just in case we need it.
>
>
> > +static const struct edp_panel_entry *find_edp_panel(u32 panel_id, u32 
> > panel_hash)
> >  {
> > const struct edp_panel_entry *panel;
> >
> > -   if (!panel_id)
> > +   if (!panel_id || !panel_hash)
> > return NULL;
>
> IMO just remove the check above. Not sure why it was there in the
> first place. Maybe I had it from some older version of the code?
> Callers shouldn't be calling us with a panel ID / hash of 0 anyway,
> and if they do they'll go through the loop and return NULL anyway.
>

Sure.

>
>
> -Doug


[PATCH 2/2] drm/panel: panel-edp: Match with panel hash for overridden modes

2024-02-23 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. One of the variants requires
using overridden modes to resolve glitching issue as described in commit
70e0d5550f5c ("drm/panel-edp: Add auo_b116xa3_mode"). Other variants should
use the modes parsed from EDID.

For example, AUO 0x405c B116XAK01.0, it has at least 2 different variants
that EDID and panel name are different, but using the same panel id. One of
the variants require using overridden mode. Same case for AUO 0x615c
B116XAN06.1.

Add such entries and use the hash of the EDID to match the panel needs the
overridden modes.

Signed-off-by: Hsin-Yi Wang 
---
 drivers/gpu/drm/panel/panel-edp.c | 52 +++
 1 file changed, 46 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index f6ddbaa103b5..42c430036846 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -21,6 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -213,6 +214,9 @@ struct edp_panel_entry {
/** @panel_id: 32-bit ID for panel, encoded with 
drm_edid_encode_panel_id(). */
u32 panel_id;
 
+   /** @panel_hash: the CRC32 hash of the EDID base block. */
+   u32 panel_hash;
+
/** @delay: The power sequencing delays needed for this panel. */
const struct panel_delay *delay;
 
@@ -758,13 +762,13 @@ static void panel_edp_parse_panel_timing_node(struct 
device *dev,
dev_err(dev, "Reject override mode: No display_timing found\n");
 }
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id);
+static const struct edp_panel_entry *find_edp_panel(u32 panel_id, u32 
panel_hash);
 
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
struct panel_desc *desc;
void *base_block;
-   u32 panel_id;
+   u32 panel_id, panel_hash;
char vend[4];
u16 product_id;
u32 reliable_ms = 0;
@@ -796,15 +800,17 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
base_block = drm_edid_get_base_block(panel->ddc);
if (base_block) {
panel_id = drm_edid_get_panel_id(base_block);
+   panel_hash = crc32_le(~0, base_block, EDID_LENGTH) ^ 0x;
kfree(base_block);
} else {
dev_err(dev, "Couldn't identify panel via EDID\n");
ret = -EIO;
goto exit;
}
+
drm_edid_decode_panel_id(panel_id, vend, _id);
 
-   panel->detected_panel = find_edp_panel(panel_id);
+   panel->detected_panel = find_edp_panel(panel_id, panel_hash);
 
/*
 * We're using non-optimized timings and want it really obvious that
@@ -1006,6 +1012,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1926,11 +1945,13 @@ static const struct panel_delay 
delay_200_500_e50_po2e200 = {
.delay = _delay \
 }
 
-#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, \
+_hash, _delay, _name, _mode) \
 { \
.name = _name, \
.panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
 product_id), \
+   .panel_hash = _hash, \
.delay = _delay, \
.override_edid_mode = _mode \
 }
@@ -2077,13 +2098,32 @@ static const struct edp_panel_entry edp_panels[] = {
{ /* sentinal */ }
 };
 
-static const struct edp_panel_entry *find_edp_panel(u32 panel_id)
+/*
+ * Similar to edp_panels, this table lists panel variants that require using
+ * overridden modes but have the same panel id as one of the entries in 
edp_panels.
+ *
+ * Sort first by vendor, then by product ID.
+ */
+static const struct edp_panel_entry edp_panels_variants[] = {
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, 0xa9951478, 
_b116xak01.delay,
+"B116XAK01.0", _b116xa3_mode),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, 0x109b75b3, _200_500_e50,
+"B116XAN06.1", _b116xa3_mode),
+
+   { /* sentinal */ }
+};
+
+static const struct edp_panel_entry *find_edp_p

[PATCH 1/2] drm_edid: Add a function to get EDID base block

2024-02-23 Thread Hsin-Yi Wang
It's found that some panels have variants that they share the same panel id
although their EDID and names are different. Besides panel id, now we need
the hash of entire EDID base block to distinguish these panel variants.

Add drm_edid_get_base_block to returns the EDID base block, so caller can
further use it to get panel id and/or the hash.

Signed-off-by: Hsin-Yi Wang 
---
 drivers/gpu/drm/drm_edid.c| 55 +--
 drivers/gpu/drm/panel/panel-edp.c |  8 +++--
 include/drm/drm_edid.h|  3 +-
 3 files changed, 38 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 923c4423151c..55598ca4a5d1 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2770,58 +2770,63 @@ static u32 edid_extract_panel_id(const struct edid 
*edid)
 }
 
 /**
- * drm_edid_get_panel_id - Get a panel's ID through DDC
- * @adapter: I2C adapter to use for DDC
+ * drm_edid_get_panel_id - Get a panel's ID from EDID base block
+ * @base_bock: EDID base block that contains panel ID.
  *
- * This function reads the first block of the EDID of a panel and (assuming
+ * This function uses the first block of the EDID of a panel and (assuming
  * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value
  * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's
  * supposed to be different for each different modem of panel.
  *
+ * Return: A 32-bit ID that should be different for each make/model of panel.
+ * See the functions drm_edid_encode_panel_id() and
+ * drm_edid_decode_panel_id() for some details on the structure of this
+ * ID.
+ */
+u32 drm_edid_get_panel_id(void *base_block)
+{
+   return edid_extract_panel_id(base_block);
+}
+EXPORT_SYMBOL(drm_edid_get_panel_id);
+
+/**
+ * drm_edid_get_base_block - Get a panel's EDID base block
+ * @adapter: I2C adapter to use for DDC
+ *
+ * This function returns the first block of the EDID of a panel.
+ *
  * This function is intended to be used during early probing on devices where
  * more than one panel might be present. Because of its intended use it must
- * assume that the EDID of the panel is correct, at least as far as the ID
- * is concerned (in other words, we don't process any overrides here).
+ * assume that the EDID of the panel is correct, at least as far as the base
+ * block is concerned (in other words, we don't process any overrides here).
  *
  * NOTE: it's expected that this function and drm_do_get_edid() will both
  * be read the EDID, but there is no caching between them. Since we're only
  * reading the first block, hopefully this extra overhead won't be too big.
  *
- * Return: A 32-bit ID that should be different for each make/model of panel.
- * See the functions drm_edid_encode_panel_id() and
- * drm_edid_decode_panel_id() for some details on the structure of this
- * ID.
+ * Caller should free the base block after use.
  */
-
-u32 drm_edid_get_panel_id(struct i2c_adapter *adapter)
+void *drm_edid_get_base_block(struct i2c_adapter *adapter)
 {
enum edid_block_status status;
void *base_block;
-   u32 panel_id = 0;
-
-   /*
-* There are no manufacturer IDs of 0, so if there is a problem reading
-* the EDID then we'll just return 0.
-*/
 
base_block = kzalloc(EDID_LENGTH, GFP_KERNEL);
if (!base_block)
-   return 0;
+   return NULL;
 
status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter);
 
edid_block_status_print(status, base_block, 0);
 
-   if (edid_block_status_valid(status, edid_block_tag(base_block)))
-   panel_id = edid_extract_panel_id(base_block);
-   else
+   if (!edid_block_status_valid(status, edid_block_tag(base_block))) {
edid_block_dump(KERN_NOTICE, base_block, 0);
+   return NULL;
+   }
 
-   kfree(base_block);
-
-   return panel_id;
+   return base_block;
 }
-EXPORT_SYMBOL(drm_edid_get_panel_id);
+EXPORT_SYMBOL(drm_edid_get_base_block);
 
 /**
  * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index bd71d239272a..f6ddbaa103b5 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -763,6 +763,7 @@ static const struct edp_panel_entry *find_edp_panel(u32 
panel_id);
 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel)
 {
struct panel_desc *desc;
+   void *base_block;
u32 panel_id;
char vend[4];
u16 product_id;
@@ -792,8 +793,11 @@ static int generic_edp_panel_probe(struct device *dev, 
struct panel_edp *panel)
goto exit;
}
 
-   panel_id = drm_edid_get_panel_id(panel->ddc);
-   if (!panel_id) {
+   base_block = drm_edid_get_base_bl

[PATCH 0/2] Match panel hash for overridden mode

2024-02-23 Thread Hsin-Yi Wang
This series is a follow up for 1a5e81de180e ("Revert "drm/panel-edp: Add
auo_b116xa3_mode""). It's found that 2 different AUO panels use the same
product id. One of them requires an overridden mode, while the other should
use the mode directly from edid.

Since product id match is no longer sufficient, EDP_PANEL_ENTRY2 is extended
to check the crc hash of the entire edid base block.

Hsin-Yi Wang (2):
  drm_edid: Add a function to get EDID base block
  drm/panel: panel-edp: Match with panel hash for overridden modes

 drivers/gpu/drm/drm_edid.c| 55 +++-
 drivers/gpu/drm/panel/panel-edp.c | 60 ++-
 include/drm/drm_edid.h|  3 +-
 3 files changed, 84 insertions(+), 34 deletions(-)

-- 
2.44.0.rc0.258.g7320e95886-goog



[PATCH] drm/mediatek: Fix a null pointer crash in mtk_drm_crtc_finish_page_flip

2024-02-23 Thread Hsin-Yi Wang
It's possible that mtk_crtc->event is NULL in
mtk_drm_crtc_finish_page_flip().

pending_needs_vblank value is set by mtk_crtc->event, but in
mtk_drm_crtc_atomic_flush(), it's is not guarded by the same
lock in mtk_drm_finish_page_flip(), thus a race condition happens.

Consider the following case:

CPU1  CPU2
step 1:
mtk_drm_crtc_atomic_begin()
mtk_crtc->event is not null,
  step 1:
  mtk_drm_crtc_atomic_flush:
  mtk_drm_crtc_update_config(
  !!mtk_crtc->event)
step 2:
mtk_crtc_ddp_irq ->
mtk_drm_finish_page_flip:
lock
mtk_crtc->event set to null,
pending_needs_vblank set to false
unlock
  pending_needs_vblank set to true,

  step 2:
  mtk_crtc_ddp_irq ->
  mtk_drm_finish_page_flip called again,
  pending_needs_vblank is still true
  //null pointer

Instead of guarding the entire mtk_drm_crtc_atomic_flush(), it's more
efficient to just check if mtk_crtc->event is null before use.

Signed-off-by: Hsin-Yi Wang 
Fixes: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.")
---
 drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index db43f9dff912..d645b85f9721 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -95,11 +95,13 @@ static void mtk_drm_crtc_finish_page_flip(struct 
mtk_drm_crtc *mtk_crtc)
struct drm_crtc *crtc = _crtc->base;
unsigned long flags;
 
-   spin_lock_irqsave(>dev->event_lock, flags);
-   drm_crtc_send_vblank_event(crtc, mtk_crtc->event);
-   drm_crtc_vblank_put(crtc);
-   mtk_crtc->event = NULL;
-   spin_unlock_irqrestore(>dev->event_lock, flags);
+   if (mtk_crtc->event) {
+   spin_lock_irqsave(>dev->event_lock, flags);
+   drm_crtc_send_vblank_event(crtc, mtk_crtc->event);
+   drm_crtc_vblank_put(crtc);
+   mtk_crtc->event = NULL;
+   spin_unlock_irqrestore(>dev->event_lock, flags);
+   }
 }
 
 static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
-- 
2.44.0.rc0.258.g7320e95886-goog



[PATCH] Revert "drm/panel-edp: Add auo_b116xa3_mode"

2024-02-13 Thread Hsin-Yi Wang
This reverts commit 70e0d5550f5cec301ad116703b840a539fe985dc.

The overridden mode fixes the panel glitching issue on mt8186 chromebook.
However, it causes the internal display not working on mt8173 chromebook.
Revert the overridden mode for now to let mt8173 have a functional display.

Signed-off-by: Hsin-Yi Wang 
---
 drivers/gpu/drm/panel/panel-edp.c | 19 ++-
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 7d556b1bfa82..bd71d239272a 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1002,19 +1002,6 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
-static const struct drm_display_mode auo_b116xa3_mode = {
-   .clock = 70589,
-   .hdisplay = 1366,
-   .hsync_start = 1366 + 40,
-   .hsync_end = 1366 + 40 + 40,
-   .htotal = 1366 + 40 + 40 + 32,
-   .vdisplay = 768,
-   .vsync_start = 768 + 10,
-   .vsync_end = 768 + 10 + 12,
-   .vtotal = 768 + 10 + 12 + 6,
-   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
-};
-
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1963,12 +1950,10 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0",
-_b116xa3_mode),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, _200_500_e50, "Unknown"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
-   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1",
-_b116xa3_mode),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, _200_500_e50, 
"B140XTN07.2"),
-- 
2.43.0.687.g38aa6559b0-goog



Re: [PATCH] drm/dp: Don't attempt AUX transfers when eDP panels are not powered

2024-02-13 Thread Hsin-Yi Wang
On Wed, Feb 14, 2024 at 2:23 PM Douglas Anderson  wrote:
>
> If an eDP panel is not powered on then any attempts to talk to it over
> the DP AUX channel will timeout. Unfortunately these attempts may be
> quite slow. Userspace can initiate these attempts either via a
> /dev/drm_dp_auxN device or via the created i2c device.
>
> Making the DP AUX drivers timeout faster is a difficult proposition.
> In theory we could just poll the panel's HPD line in the AUX transfer
> function and immediately return an error there. However, this is
> easier said than done. For one thing, there's no hard requirement to
> hook the HPD line up for eDP panels and it's OK to just delay a fixed
> amount. For another thing, the HPD line may not be fast to probe. On
> parade-ps8640 we need to wait for the bridge chip's firmware to boot
> before we can get the HPD line and this is a slow process.
>
> The fact that the transfers are taking so long to timeout is causing
> real problems. The open source fwupd daemon sometimes scans DP busses
> looking for devices whose firmware need updating. If it happens to
> scan while a panel is turned off this scan can take a long time. The
> fwupd daemon could try to be smarter and only scan when eDP panels are
> turned on, but we can also improve the behavior in the kernel.
>
> Let's let eDP panels drivers specify that a panel is turned off and
> then modify the common AUX transfer code not to attempt a transfer in
> this case.
>
> Signed-off-by: Douglas Anderson 
> ---

Reviewed-by: Hsin-Yi Wang 

>
>  drivers/gpu/drm/display/drm_dp_helper.c   | 35 +++
>  drivers/gpu/drm/panel/panel-edp.c |  3 ++
>  .../gpu/drm/panel/panel-samsung-atna33xc20.c  |  2 ++
>  include/drm/display/drm_dp_helper.h   |  6 
>  4 files changed, 46 insertions(+)
>
> diff --git a/drivers/gpu/drm/display/drm_dp_helper.c 
> b/drivers/gpu/drm/display/drm_dp_helper.c
> index b1ca3a1100da..6fa705d82c8f 100644
> --- a/drivers/gpu/drm/display/drm_dp_helper.c
> +++ b/drivers/gpu/drm/display/drm_dp_helper.c
> @@ -532,6 +532,15 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 
> request,
>
> mutex_lock(>hw_mutex);
>
> +   /*
> +* If the device attached to the aux bus is powered down then there's
> +* no reason to attempt a transfer. Error out immediately.
> +*/
> +   if (aux->powered_down) {
> +   ret = -EBUSY;
> +   goto unlock;
> +   }
> +
> /*
>  * The specification doesn't give any recommendation on how often to
>  * retry native transactions. We used to retry 7 times like for
> @@ -599,6 +608,29 @@ int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned 
> int offset)
>  }
>  EXPORT_SYMBOL(drm_dp_dpcd_probe);
>
> +/**
> + * drm_dp_dpcd_set_powered() - Set whether the DP device is powered
> + * @aux: DisplayPort AUX channel; for convenience it's OK to pass NULL here
> + *   and the function will be a no-op.
> + * @powered: true if powered; false if not
> + *
> + * If the endpoint device on the DP AUX bus is known to be powered down
> + * then this function can be called to make future transfers fail immediately
> + * instead of needing to time out.
> + *
> + * If this function is never called then a device defaults to being powered.
> + */
> +void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered)
> +{
> +   if (!aux)
> +   return;
> +
> +   mutex_lock(>hw_mutex);
> +   aux->powered_down = !powered;
> +   mutex_unlock(>hw_mutex);
> +}
> +EXPORT_SYMBOL(drm_dp_dpcd_set_powered);
> +
>  /**
>   * drm_dp_dpcd_read() - read a series of bytes from the DPCD
>   * @aux: DisplayPort AUX channel (SST or MST)
> @@ -1858,6 +1890,9 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, 
> struct i2c_msg *msgs,
> struct drm_dp_aux_msg msg;
> int err = 0;
>
> +   if (aux->powered_down)
> +   return -EBUSY;
> +
> dp_aux_i2c_transfer_size = clamp(dp_aux_i2c_transfer_size, 1, 
> DP_AUX_MAX_PAYLOAD_BYTES);
>
> memset(, 0, sizeof(msg));
> diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> b/drivers/gpu/drm/panel/panel-edp.c
> index 7d556b1bfa82..d2a4e514d8fd 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -413,6 +413,7 @@ static int panel_edp_suspend(struct device *dev)
>  {
> struct panel_edp *p = dev_get_drvdata(dev);
>
> +   drm_dp_dpcd_set_powered(p->aux, false);
> gpiod_set_value_cansleep(p->enable_gpio, 0);
> regulator_disable(p->supply);
> p->unprepared_time = 

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

2024-01-17 Thread Hsin-Yi Wang
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(>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(>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(>aux_lock);
+   pm_runtime_put_sync_suspend(dev);
+   mutex_unlock(>aux_lock);
 }
 
 static enum drm_connector_status
@@ -2668,6 +2672,7 @@ static int anx7625_i2c_probe(struct i2c_client *client)
 
mutex_init(>lock);
mutex_init(>hdcp_wq_lock);
+   mutex_init(>aux_lock);
 
INIT_DELAYED_WORK(>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



Re: [PATCH] drm/bridge: parade-ps8640: Make sure we drop the AUX mutex in the error case

2024-01-17 Thread Hsin-Yi Wang
On Wed, Jan 17, 2024 at 10:35 AM Douglas Anderson  wrote:
>
> After commit 26db46bc9c67 ("drm/bridge: parade-ps8640: Ensure bridge
> is suspended in .post_disable()"), if we hit the error case in
> ps8640_aux_transfer() then we return without dropping the mutex. Fix
> this oversight.
>
> Fixes: 26db46bc9c67 ("drm/bridge: parade-ps8640: Ensure bridge is suspended 
> in .post_disable()")
> Signed-off-by: Douglas Anderson 
> ---
> Sorry for missing this in my review! :( Given that this is really
> simple and I'd rather the buggy commit not be there for long, if I can
> get a quick Reviewed-by tag on this patch I'll land it without the
> typical stewing period.
>

Reviewed-by: Hsin-Yi Wang 

>  drivers/gpu/drm/bridge/parade-ps8640.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
> b/drivers/gpu/drm/bridge/parade-ps8640.c
> index 166bfc725ef4..14d4dcf239da 100644
> --- a/drivers/gpu/drm/bridge/parade-ps8640.c
> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
> @@ -351,11 +351,13 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux 
> *aux,
> ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000);
> if (ret) {
> pm_runtime_put_sync_suspend(dev);
> -   return ret;
> +   goto exit;
> }
> ret = ps8640_aux_transfer_msg(aux, msg);
> pm_runtime_mark_last_busy(dev);
> pm_runtime_put_autosuspend(dev);
> +
> +exit:
> mutex_unlock(_bridge->aux_lock);
>
> return ret;
> --
> 2.43.0.381.gb435a96ce8-goog
>


[PATCH] drm/panel-edp: use put_sync in unprepare

2023-12-20 Thread Hsin-Yi Wang
Some edp panel requires T10 (Delay from end of valid video data transmitted
by the Source device to power-off) less than 500ms. Using autosuspend with
delay set as 1000 violates this requirement.

Use put_sync_suspend in unprepare to meet the spec. For other cases (such
as getting EDID), it still uses autosuspend.

Suggested-by: Douglas Anderson 
Fixes: 5f04e7ce392d ("drm/panel-edp: Split eDP panels out of panel-simple")
Signed-off-by: Hsin-Yi Wang 
---
 drivers/gpu/drm/panel/panel-edp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index cd05c76868e3..7d556b1bfa82 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -429,8 +429,7 @@ static int panel_edp_unprepare(struct drm_panel *panel)
if (!p->prepared)
return 0;
 
-   pm_runtime_mark_last_busy(panel->dev);
-   ret = pm_runtime_put_autosuspend(panel->dev);
+   ret = pm_runtime_put_sync_suspend(panel->dev);
if (ret < 0)
return ret;
p->prepared = false;
-- 
2.43.0.472.g3155946c3a-goog



Re: [PATCH v7 2/3] drm/panel-edp: Add auo_b116xa3_mode

2023-11-17 Thread Hsin-Yi Wang
On Fri, Nov 17, 2023 at 1:51 PM Hsin-Yi Wang  wrote:
>
> Add auo_b116xa3_mode to override the original modes parsed from edid
> of the panels 0x405c B116XAK01.0 and 0x615c B116XAN06.1 which result
> in glitches on panel.
>
> Signed-off-by: Hsin-Yi Wang 
> ---
> v6->v7: split usecase to another patch.

 -cc: stable

> ---
>  drivers/gpu/drm/panel/panel-edp.c | 19 +--
>  1 file changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> b/drivers/gpu/drm/panel/panel-edp.c
> index 33535f6de343..3e144145a6bd 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -983,6 +983,19 @@ static const struct panel_desc auo_b101ean01 = {
> },
>  };
>
> +static const struct drm_display_mode auo_b116xa3_mode = {
> +   .clock = 70589,
> +   .hdisplay = 1366,
> +   .hsync_start = 1366 + 40,
> +   .hsync_end = 1366 + 40 + 40,
> +   .htotal = 1366 + 40 + 40 + 32,
> +   .vdisplay = 768,
> +   .vsync_start = 768 + 10,
> +   .vsync_end = 768 + 10 + 12,
> +   .vtotal = 768 + 10 + 12 + 6,
> +   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
> +};
> +
>  static const struct drm_display_mode auo_b116xak01_mode = {
> .clock = 69300,
> .hdisplay = 1366,
> @@ -1908,9 +1921,11 @@ static const struct edp_panel_entry edp_panels[] = {
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
> "B116XAN06.1"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
> "B116XTN02.5"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
> "B140HAN04.0"),
> -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> "B116XAK01.0"),
> +   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> "B116XAK01.0",
> +_b116xa3_mode),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
> "B133UAN01.0"),
> -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
> "B116XAN06.1"),
> +   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, _200_500_e50, 
> "B116XAN06.1",
> +_b116xa3_mode),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
> "B116XAN06.3"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
> "B140HAK02.7"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
> "B133UAN01.0"),
> --
> 2.43.0.rc0.421.g78406f8d94-goog
>


Re: [PATCH v7 1/3] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-17 Thread Hsin-Yi Wang
On Fri, Nov 17, 2023 at 2:06 PM Greg KH  wrote:
>
> On Fri, Nov 17, 2023 at 01:46:32PM -0800, Hsin-Yi Wang wrote:
> > Generic edp gets mode from edid. However, some panels report incorrect
> > mode in this way, resulting in glitches on panel. Introduce a new quirk
> > additional_mode to the generic edid to pick a correct hardcoded mode.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > Reviewed-by: Douglas Anderson 
> > ---
> > v6->v7: split usecase to another patch.
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 48 +--
> >  1 file changed, 45 insertions(+), 3 deletions(-)
>
> 
>
> This is not the correct way to submit patches for inclusion in the
> stable kernel tree.  Please read:
> https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html
> for how to do this properly.
>
Forgot to -cc: stable, these patches don't need to be picked to stable.

> 


[PATCH v7 3/3] drm/panel-edp: Avoid adding multiple preferred modes

2023-11-17 Thread Hsin-Yi Wang
If a non generic edp-panel is under aux-bus, the mode read from edid would
still be selected as preferred and results in multiple preferred modes,
which is ambiguous.

If both hard-coded mode and edid exists, only add mode from hard-coded.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v6->v7: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 3e144145a6bd..825fa2a0d8a5 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -589,6 +589,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_hard_coded_modes = p->desc->num_timings || p->desc->num_modes;
bool has_override_edid_mode = p->detected_panel &&
  p->detected_panel != ERR_PTR(-EINVAL) &&
  p->detected_panel->override_edid_mode;
@@ -599,7 +600,11 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-   if (p->edid) {
+   /*
+* If both edid and hard-coded modes exists, skip edid modes to
+* avoid multiple preferred modes.
+*/
+   if (p->edid && !has_hard_coded_modes) {
if (has_override_edid_mode) {
/*
 * override_edid_mode is specified. Use
@@ -616,12 +621,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
pm_runtime_put_autosuspend(panel->dev);
}
 
-   /*
-* Add hard-coded panel modes. Don't call this if there are no timings
-* and no modes (the generic edp-panel case) because it will clobber
-* the display_info that was already set by drm_add_edid_modes().
-*/
-   if (p->desc->num_timings || p->desc->num_modes)
+   if (has_hard_coded_modes)
num += panel_edp_get_non_edid_modes(p, connector);
else if (!num)
dev_warn(p->base.dev, "No display modes\n");
-- 
2.43.0.rc0.421.g78406f8d94-goog



[PATCH v7 2/3] drm/panel-edp: Add auo_b116xa3_mode

2023-11-17 Thread Hsin-Yi Wang
Add auo_b116xa3_mode to override the original modes parsed from edid
of the panels 0x405c B116XAK01.0 and 0x615c B116XAN06.1 which result
in glitches on panel.

Signed-off-by: Hsin-Yi Wang 
---
v6->v7: split usecase to another patch.
---
 drivers/gpu/drm/panel/panel-edp.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 33535f6de343..3e144145a6bd 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -983,6 +983,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1908,9 +1921,11 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1",
+_b116xa3_mode),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
-- 
2.43.0.rc0.421.g78406f8d94-goog



[PATCH v7 1/3] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-17 Thread Hsin-Yi Wang
Generic edp gets mode from edid. However, some panels report incorrect
mode in this way, resulting in glitches on panel. Introduce a new quirk
additional_mode to the generic edid to pick a correct hardcoded mode.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v6->v7: split usecase to another patch.
---
 drivers/gpu/drm/panel/panel-edp.c | 48 +--
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index f22677373171..33535f6de343 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -203,6 +203,9 @@ struct edp_panel_entry {
 
/** @name: Name of this panel (for printing to logs). */
const char *name;
+
+   /** @override_edid_mode: Override the mode obtained by edid. */
+   const struct drm_display_mode *override_edid_mode;
 };
 
 struct panel_edp {
@@ -301,6 +304,24 @@ static unsigned int panel_edp_get_display_modes(struct 
panel_edp *panel,
return num;
 }
 
+static int panel_edp_override_edid_mode(struct panel_edp *panel,
+   struct drm_connector *connector,
+   const struct drm_display_mode 
*override_mode)
+{
+   struct drm_display_mode *mode;
+
+   mode = drm_mode_duplicate(connector->dev, override_mode);
+   if (!mode) {
+   dev_err(panel->base.dev, "failed to add additional mode\n");
+   return 0;
+   }
+
+   mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+   drm_mode_set_name(mode);
+   drm_mode_probed_add(connector, mode);
+   return 1;
+}
+
 static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
 {
@@ -568,6 +589,9 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_override_edid_mode = p->detected_panel &&
+ p->detected_panel != ERR_PTR(-EINVAL) &&
+ p->detected_panel->override_edid_mode;
 
/* probe EDID if a DDC bus is available */
if (p->ddc) {
@@ -575,9 +599,18 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-
-   if (p->edid)
-   num += drm_add_edid_modes(connector, p->edid);
+   if (p->edid) {
+   if (has_override_edid_mode) {
+   /*
+* override_edid_mode is specified. Use
+* override_edid_mode instead of from edid.
+*/
+   num += panel_edp_override_edid_mode(p, 
connector,
+   
p->detected_panel->override_edid_mode);
+   } else {
+   num += drm_add_edid_modes(connector, p->edid);
+   }
+   }
 
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
@@ -1849,6 +1882,15 @@ static const struct panel_delay delay_200_150_e200 = {
.delay = _delay \
 }
 
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+{ \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   .delay = _delay, \
+   .override_edid_mode = _mode \
+}
+
 /*
  * This table is used to figure out power sequencing delays for panels that
  * are detected by EDID. Entries here may point to entries in the
-- 
2.43.0.rc0.421.g78406f8d94-goog



[PATCH v7 0/3] Use correct mode for edp panel

2023-11-17 Thread Hsin-Yi Wang
This series contains 2 part to handle mode selection for edp panel:
1. (patch 1, 2) Add a quirk to override the edid mode for generic edp.
2. (patch 3) If a panel contains hardcoded mode, skip edid mode.

Previous versions:
v1: 
https://patchwork.kernel.org/project/dri-devel/cover/20231101212604.1636517-1-hsi...@chromium.org/
v2: 
https://patchwork.kernel.org/project/dri-devel/cover/20231102221309.1971910-1-hsi...@chromium.org/
v3: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106202718.2770821-1-hsi...@chromium.org/
v4: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106210337.2900034-1-hsi...@chromium.org/
v5: 
https://patchwork.kernel.org/project/dri-devel/cover/2023110723.2928195-1-hsi...@chromium.org/
v6: https://lore.kernel.org/lkml/20231107204611.3082200-2-hsi...@chromium.org/

Hsin-Yi Wang (3):
  drm/panel-edp: Add override_edid_mode quirk for generic edp
  drm/panel-edp: Add auo_b116xa3_mode
  drm/panel-edp: Avoid adding multiple preferred modes

 drivers/gpu/drm/panel/panel-edp.c | 79 ++-
 1 file changed, 68 insertions(+), 11 deletions(-)

-- 
2.43.0.rc0.421.g78406f8d94-goog



Re: [PATCH v6 3/5] drm/panel-edp: drm/panel-edp: Add several generic edp panels

2023-11-07 Thread Hsin-Yi Wang
On Tue, Nov 7, 2023 at 12:57 PM Greg KH  wrote:
>
> On Tue, Nov 07, 2023 at 12:41:53PM -0800, Hsin-Yi Wang wrote:
> > Add a few generic edp panels used by mt8186 chromebooks.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > Reviewed-by: Douglas Anderson 
> > ---
> > no change.
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 51 +++
> >  1 file changed, 51 insertions(+)
>
> 
>
> This is not the correct way to submit patches for inclusion in the
> stable kernel tree.  Please read:
> https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html
> for how to do this properly.
>
Sorry for confusion, only patch 1 & 2 need to be picked to stable. 3~5 don't.

> 


[PATCH v6 3/5] drm/panel-edp: drm/panel-edp: Add several generic edp panels

2023-11-07 Thread Hsin-Yi Wang
Add a few generic edp panels used by mt8186 chromebooks.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
no change.
---
 drivers/gpu/drm/panel/panel-edp.c | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index d41d205f7f5b..599a949d74d1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1832,6 +1832,12 @@ static const struct panel_delay delay_200_500_e50 = {
.enable = 50,
 };
 
+static const struct panel_delay delay_200_500_e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 80,
+};
+
 static const struct panel_delay delay_200_500_e80_d50 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1851,6 +1857,19 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d10 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 10,
+};
+
+static const struct panel_delay delay_200_150_e200 = {
+   .hpd_absent = 200,
+   .unprepare = 150,
+   .enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1871,37 +1890,69 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, _200_500_e50, 
"B140HTN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, _200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, _200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, _200_500_e80, 
"NT116WHM-N42"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, _200_500_e200, 
"NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, _200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, _nv133fhm_n61.delay, 
"NV133FHM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, _200_500_e200, 
"NT140FHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, _nv133fhm_n61.delay, 
"NV133FHM-N62"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, _200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, _200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, _200_500_e50, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, _200_500_e80, 
"NV116WHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, _200_500_e50, 
"NE135FBM-N41 v8.1"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, _200_500_e50, 
"NV116WHM-N49 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, _nv110wtm_n61.delay, 
"NV110WTM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, _200_500_e200, 
"NT140FHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, _200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, _200_500_e50, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, _200_500_e50, 
"NV116WHM-N4C"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, _200_500_e200, 
"NV140FHM-T09"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, _200_500_e80, 
"NT140FHM-N47"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, _200_500_e80, 
"NT140FHM-N47"),
 
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, _200_500_e80_d50, 
"N116BGE-EA2"),
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, _n116bca_ea1.delay, 
"N116BCA-EA1-RC4"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, _200_500_e80_d50, 
"N116BGE-EA2"),
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, _200_500_e8

[PATCH v6 5/5] drm/panel-edp: Avoid adding multiple preferred modes

2023-11-07 Thread Hsin-Yi Wang
If a non generic edp-panel is under aux-bus, the mode read from edid would
still be selected as preferred and results in multiple preferred modes,
which is ambiguous.

If both hard-coded mode and edid exists, only add mode from hard-coded.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
no change.
---
 drivers/gpu/drm/panel/panel-edp.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index c0c24d94c3a0..006939cc3fee 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -589,6 +589,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_hard_coded_modes = p->desc->num_timings || p->desc->num_modes;
bool has_override_edid_mode = p->detected_panel &&
  p->detected_panel != ERR_PTR(-EINVAL) &&
  p->detected_panel->override_edid_mode;
@@ -599,7 +600,11 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-   if (p->edid) {
+   /*
+* If both edid and hard-coded modes exists, skip edid modes to
+* avoid multiple preferred modes.
+*/
+   if (p->edid && !has_hard_coded_modes) {
if (has_override_edid_mode) {
/*
 * override_edid_mode is specified. Use
@@ -616,12 +621,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
pm_runtime_put_autosuspend(panel->dev);
}
 
-   /*
-* Add hard-coded panel modes. Don't call this if there are no timings
-* and no modes (the generic edp-panel case) because it will clobber
-* the display_info that was already set by drm_add_edid_modes().
-*/
-   if (p->desc->num_timings || p->desc->num_modes)
+   if (has_hard_coded_modes)
num += panel_edp_get_non_edid_modes(p, connector);
else if (!num)
dev_warn(p->base.dev, "No display modes\n");
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v6 4/5] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-07 Thread Hsin-Yi Wang
Generic edp gets mode from edid. However, some panels report incorrect
mode in this way, resulting in glitches on panel. Introduce a new quirk
additional_mode to the generic edid to pick a correct hardcoded mode.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
no change.
---
 drivers/gpu/drm/panel/panel-edp.c | 67 ---
 1 file changed, 62 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 599a949d74d1..c0c24d94c3a0 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -203,6 +203,9 @@ struct edp_panel_entry {
 
/** @name: Name of this panel (for printing to logs). */
const char *name;
+
+   /** @override_edid_mode: Override the mode obtained by edid. */
+   const struct drm_display_mode *override_edid_mode;
 };
 
 struct panel_edp {
@@ -301,6 +304,24 @@ static unsigned int panel_edp_get_display_modes(struct 
panel_edp *panel,
return num;
 }
 
+static int panel_edp_override_edid_mode(struct panel_edp *panel,
+   struct drm_connector *connector,
+   const struct drm_display_mode 
*override_mode)
+{
+   struct drm_display_mode *mode;
+
+   mode = drm_mode_duplicate(connector->dev, override_mode);
+   if (!mode) {
+   dev_err(panel->base.dev, "failed to add additional mode\n");
+   return 0;
+   }
+
+   mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+   drm_mode_set_name(mode);
+   drm_mode_probed_add(connector, mode);
+   return 1;
+}
+
 static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
 {
@@ -568,6 +589,9 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_override_edid_mode = p->detected_panel &&
+ p->detected_panel != ERR_PTR(-EINVAL) &&
+ p->detected_panel->override_edid_mode;
 
/* probe EDID if a DDC bus is available */
if (p->ddc) {
@@ -575,9 +599,18 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-
-   if (p->edid)
-   num += drm_add_edid_modes(connector, p->edid);
+   if (p->edid) {
+   if (has_override_edid_mode) {
+   /*
+* override_edid_mode is specified. Use
+* override_edid_mode instead of from edid.
+*/
+   num += panel_edp_override_edid_mode(p, 
connector,
+   
p->detected_panel->override_edid_mode);
+   } else {
+   num += drm_add_edid_modes(connector, p->edid);
+   }
+   }
 
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
@@ -950,6 +983,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1878,6 +1924,15 @@ static const struct panel_delay delay_200_150_e200 = {
.delay = _delay \
 }
 
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+{ \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   .delay = _delay, \
+   .override_edid_mode = _mode \
+}
+
 /*
  * This table is used to figure out power sequencing delays for panels that
  * are detected by EDID. Entries here may point to entries in the
@@ -1895,9 +1950,11 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _

[PATCH v6 1/5] drm/panel-edp: drm/panel-edp: Fix AUO B116XAK01 name and timing

2023-11-07 Thread Hsin-Yi Wang
Rename AUO 0x405c B116XAK01 to B116XAK01.0 and adjust the timing of
auo_b116xak01: T3=200, T12=500, T7_max = 50 according to decoding edid
and datasheet.

Fixes: da458286a5e2 ("drm/panel: Add support for AUO B116XAK01 panel")
Cc: sta...@vger.kernel.org
Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v5->v6: split to 2 patches.
---
 drivers/gpu/drm/panel/panel-edp.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 9dce4c702414..2fba7c1f49ce 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = {
},
.delay = {
.hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
},
 };
 
@@ -1870,7 +1872,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, "B116XTN02"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v6 2/5] drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02 name

2023-11-07 Thread Hsin-Yi Wang
Rename AUO 0x235c B116XTN02 to B116XTN02.3 according to decoding edid.

Fixes: 3db2420422a5 ("drm/panel-edp: Add AUO B116XTN02, BOE NT116WHM-N21,836X2, 
NV116WHM-N49 V8.0")
Cc: sta...@vger.kernel.org
Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v5->v6: split to 2 patches.
---
 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 2fba7c1f49ce..d41d205f7f5b 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1871,7 +1871,7 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, "B116XTN02"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v6 0/5] Add a few panels and use correct modes

2023-11-07 Thread Hsin-Yi Wang
This series contains following patches:
1-2. Fix 2 panel naming and timing.
3. Add a few new generic edp panels.
4. Support a new quirk to override the mode read from edid
5. Only add hard-coded mode if both edid and hard-coded modes presents.

v1: 
https://patchwork.kernel.org/project/dri-devel/cover/20231101212604.1636517-1-hsi...@chromium.org/
v2: 
https://patchwork.kernel.org/project/dri-devel/cover/20231102221309.1971910-1-hsi...@chromium.org/
v3: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106202718.2770821-1-hsi...@chromium.org/
v4: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106210337.2900034-1-hsi...@chromium.org/
v5: 
https://patchwork.kernel.org/project/dri-devel/cover/2023110723.2928195-1-hsi...@chromium.org/

Hsin-Yi Wang (5):
  drm/panel-edp: drm/panel-edp: Fix AUO B116XAK01 name and timing
  drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02 name
  drm/panel-edp: drm/panel-edp: Add several generic edp panels
  drm/panel-edp: Add override_edid_mode quirk for generic edp
  drm/panel-edp: Avoid adding multiple preferred modes

 drivers/gpu/drm/panel/panel-edp.c | 134 +++---
 1 file changed, 122 insertions(+), 12 deletions(-)

-- 
2.42.0.869.gea05f2083d-goog



Re: [PATCH v5 1/4] drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02, B116XAK01 name and timing

2023-11-06 Thread Hsin-Yi Wang
On Mon, Nov 6, 2023 at 4:00 PM Hsin-Yi Wang  wrote:
>
> According to decoding edid and datahseet:
> - Rename AUO 0x235c B116XTN02 to B116XTN02.3
> - Rename AUO 0x405c B116XAK01 to B116XAK01.0 and adjust the timing of
> auo_b116xak01: T3=200, T12=500, T7_max = 50.
>
> Fixes: 3db2420422a5 ("drm/panel-edp: Add AUO B116XTN02, BOE 
> NT116WHM-N21,836X2, NV116WHM-N49 V8.0")
> Fixes: da458286a5e2 ("drm/panel: Add support for AUO B116XAK01 panel")
> Signed-off-by: Hsin-Yi Wang 
> Reviewed-by: Douglas Anderson 
Cc: sta...@vger.kernel.org
> ---
> v4->v5: separate fixes patch.
> ---
>  drivers/gpu/drm/panel/panel-edp.c | 6 --
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> b/drivers/gpu/drm/panel/panel-edp.c
> index 9dce4c702414..d41d205f7f5b 100644
> --- a/drivers/gpu/drm/panel/panel-edp.c
> +++ b/drivers/gpu/drm/panel/panel-edp.c
> @@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = {
> },
> .delay = {
> .hpd_absent = 200,
> +   .unprepare = 500,
> +   .enable = 50,
> },
>  };
>
> @@ -1869,8 +1871,8 @@ static const struct edp_panel_entry edp_panels[] = {
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
> "B116XAB01.4"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
> "B133UAN02.1"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
> "B116XAK01.6"),
> -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
> "B116XTN02"),
> -   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> "B116XAK01"),
> +   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
> "B116XTN02.3"),
> +   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
> "B116XAK01.0"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
> "B133UAN01.0"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
> "B116XAN06.1"),
> EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
> "B133UAN01.0"),
> --
> 2.42.0.869.gea05f2083d-goog
>


[PATCH v5 4/4] drm/panel-edp: Avoid adding multiple preferred modes

2023-11-06 Thread Hsin-Yi Wang
If a non generic edp-panel is under aux-bus, the mode read from edid would
still be selected as preferred and results in multiple preferred modes,
which is ambiguous.

If both hard-coded mode and edid exists, only add mode from hard-coded.

Signed-off-by: Hsin-Yi Wang 
---
v4->v5: remove inapplicable comments.
---
 drivers/gpu/drm/panel/panel-edp.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index c0c24d94c3a0..006939cc3fee 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -589,6 +589,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_hard_coded_modes = p->desc->num_timings || p->desc->num_modes;
bool has_override_edid_mode = p->detected_panel &&
  p->detected_panel != ERR_PTR(-EINVAL) &&
  p->detected_panel->override_edid_mode;
@@ -599,7 +600,11 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-   if (p->edid) {
+   /*
+* If both edid and hard-coded modes exists, skip edid modes to
+* avoid multiple preferred modes.
+*/
+   if (p->edid && !has_hard_coded_modes) {
if (has_override_edid_mode) {
/*
 * override_edid_mode is specified. Use
@@ -616,12 +621,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
pm_runtime_put_autosuspend(panel->dev);
}
 
-   /*
-* Add hard-coded panel modes. Don't call this if there are no timings
-* and no modes (the generic edp-panel case) because it will clobber
-* the display_info that was already set by drm_add_edid_modes().
-*/
-   if (p->desc->num_timings || p->desc->num_modes)
+   if (has_hard_coded_modes)
num += panel_edp_get_non_edid_modes(p, connector);
else if (!num)
dev_warn(p->base.dev, "No display modes\n");
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v5 1/4] drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02, B116XAK01 name and timing

2023-11-06 Thread Hsin-Yi Wang
According to decoding edid and datahseet:
- Rename AUO 0x235c B116XTN02 to B116XTN02.3
- Rename AUO 0x405c B116XAK01 to B116XAK01.0 and adjust the timing of
auo_b116xak01: T3=200, T12=500, T7_max = 50.

Fixes: 3db2420422a5 ("drm/panel-edp: Add AUO B116XTN02, BOE NT116WHM-N21,836X2, 
NV116WHM-N49 V8.0")
Fixes: da458286a5e2 ("drm/panel: Add support for AUO B116XAK01 panel")
Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v4->v5: separate fixes patch.
---
 drivers/gpu/drm/panel/panel-edp.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 9dce4c702414..d41d205f7f5b 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = {
},
.delay = {
.hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
},
 };
 
@@ -1869,8 +1871,8 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, "B116XTN02"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v5 3/4] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-06 Thread Hsin-Yi Wang
Generic edp gets mode from edid. However, some panels report incorrect
mode in this way, resulting in glitches on panel. Introduce a new quirk
additional_mode to the generic edid to pick a correct hardcoded mode.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v4->v5: fix coding style comments from v4.
---
 drivers/gpu/drm/panel/panel-edp.c | 67 ---
 1 file changed, 62 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 599a949d74d1..c0c24d94c3a0 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -203,6 +203,9 @@ struct edp_panel_entry {
 
/** @name: Name of this panel (for printing to logs). */
const char *name;
+
+   /** @override_edid_mode: Override the mode obtained by edid. */
+   const struct drm_display_mode *override_edid_mode;
 };
 
 struct panel_edp {
@@ -301,6 +304,24 @@ static unsigned int panel_edp_get_display_modes(struct 
panel_edp *panel,
return num;
 }
 
+static int panel_edp_override_edid_mode(struct panel_edp *panel,
+   struct drm_connector *connector,
+   const struct drm_display_mode 
*override_mode)
+{
+   struct drm_display_mode *mode;
+
+   mode = drm_mode_duplicate(connector->dev, override_mode);
+   if (!mode) {
+   dev_err(panel->base.dev, "failed to add additional mode\n");
+   return 0;
+   }
+
+   mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+   drm_mode_set_name(mode);
+   drm_mode_probed_add(connector, mode);
+   return 1;
+}
+
 static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
 {
@@ -568,6 +589,9 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_override_edid_mode = p->detected_panel &&
+ p->detected_panel != ERR_PTR(-EINVAL) &&
+ p->detected_panel->override_edid_mode;
 
/* probe EDID if a DDC bus is available */
if (p->ddc) {
@@ -575,9 +599,18 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-
-   if (p->edid)
-   num += drm_add_edid_modes(connector, p->edid);
+   if (p->edid) {
+   if (has_override_edid_mode) {
+   /*
+* override_edid_mode is specified. Use
+* override_edid_mode instead of from edid.
+*/
+   num += panel_edp_override_edid_mode(p, 
connector,
+   
p->detected_panel->override_edid_mode);
+   } else {
+   num += drm_add_edid_modes(connector, p->edid);
+   }
+   }
 
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
@@ -950,6 +983,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1878,6 +1924,15 @@ static const struct panel_delay delay_200_150_e200 = {
.delay = _delay \
 }
 
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+{ \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   .delay = _delay, \
+   .override_edid_mode = _mode \
+}
+
 /*
  * This table is used to figure out power sequencing delays for panels that
  * are detected by EDID. Entries here may point to entries in the
@@ -1895,9 +1950,11 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', '

[PATCH v5 2/4] drm/panel-edp: drm/panel-edp: Add several generic edp panels

2023-11-06 Thread Hsin-Yi Wang
Add a few generic edp panels used by mt8186 chromebooks.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v4->v5: seperate fixes patch
---
 drivers/gpu/drm/panel/panel-edp.c | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index d41d205f7f5b..599a949d74d1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -1832,6 +1832,12 @@ static const struct panel_delay delay_200_500_e50 = {
.enable = 50,
 };
 
+static const struct panel_delay delay_200_500_e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 80,
+};
+
 static const struct panel_delay delay_200_500_e80_d50 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1851,6 +1857,19 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d10 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 10,
+};
+
+static const struct panel_delay delay_200_150_e200 = {
+   .hpd_absent = 200,
+   .unprepare = 150,
+   .enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1871,37 +1890,69 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, _200_500_e50, 
"B140HTN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, _200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, _200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, _200_500_e80, 
"NT116WHM-N42"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, _200_500_e200, 
"NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, _200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, _nv133fhm_n61.delay, 
"NV133FHM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, _200_500_e200, 
"NT140FHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, _nv133fhm_n61.delay, 
"NV133FHM-N62"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, _200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, _200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, _200_500_e50, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, _200_500_e80, 
"NV116WHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, _200_500_e50, 
"NE135FBM-N41 v8.1"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, _200_500_e50, 
"NV116WHM-N49 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, _nv110wtm_n61.delay, 
"NV110WTM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, _200_500_e200, 
"NT140FHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, _200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, _200_500_e50, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, _200_500_e50, 
"NV116WHM-N4C"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, _200_500_e200, 
"NV140FHM-T09"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, _200_500_e80, 
"NT140FHM-N47"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, _200_500_e80, 
"NT140FHM-N47"),
 
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, _200_500_e80_d50, 
"N116BGE-EA2"),
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, _n116bca_ea1.delay, 
"N116BCA-EA1-RC4"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, _200_500_e80_d50, 
"N116BGE-EA2"),
+   EDP_PANEL_ENTRY('C', 'M', 'N', 0x1

[PATCH v5 0/4] Add a few panels and use correct modes

2023-11-06 Thread Hsin-Yi Wang
This series contains 3 patches:
1. Add a few new generic edp panels.
2. Support a new quirk to override the mode read from edid
3. Only add hard-coded mode if both edid and hard-coded modes presents.

v1: 
https://patchwork.kernel.org/project/dri-devel/cover/20231101212604.1636517-1-hsi...@chromium.org/
v2: 
https://patchwork.kernel.org/project/dri-devel/cover/20231102221309.1971910-1-hsi...@chromium.org/
v3: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106202718.2770821-1-hsi...@chromium.org/
v4: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106210337.2900034-1-hsi...@chromium.org/

Hsin-Yi Wang (4):
  drm/panel-edp: drm/panel-edp: Fix AUO B116XTN02, B116XAK01 name and
timing
  drm/panel-edp: drm/panel-edp: Add several generic edp panels
  drm/panel-edp: Add override_edid_mode quirk for generic edp
  drm/panel-edp: Avoid adding multiple preferred modes

 drivers/gpu/drm/panel/panel-edp.c | 134 +++---
 1 file changed, 122 insertions(+), 12 deletions(-)

-- 
2.42.0.869.gea05f2083d-goog



[PATCH v4 3/3] drm/panel-edp: Avoid adding multiple preferred modes

2023-11-06 Thread Hsin-Yi Wang
If a non generic edp-panel is under aux-bus, the mode read from edid would
still be selected as preferred and results in multiple preferred modes,
which is ambiguous.

If both hard-coded mode and edid exists, only add mode from hard-coded.

Signed-off-by: Hsin-Yi Wang 
---
v3->v4: don't skip read edid. only skip add modes.
---
 drivers/gpu/drm/panel/panel-edp.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 0fb439b5efb1..c8bb4baf1d45 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -590,6 +590,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_hard_coded_modes = p->desc->num_timings || p->desc->num_modes;
bool has_override_edid_mode = p->detected_panel &&
  p->detected_panel != ERR_PTR(-EINVAL) &&
  p->detected_panel->override_edid_mode;
@@ -600,7 +601,11 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-   if (p->edid) {
+   /*
+* If both edid and hard-coded modes exists, skip edid modes to
+* avoid multiple preferred modes.
+*/
+   if (p->edid && !has_hard_coded_modes) {
if (has_override_edid_mode) {
/*
 * override_edid_mode is specified. Use
@@ -622,7 +627,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 * and no modes (the generic edp-panel case) because it will clobber
 * the display_info that was already set by drm_add_edid_modes().
 */
-   if (p->desc->num_timings || p->desc->num_modes)
+   if (has_hard_coded_modes)
num += panel_edp_get_non_edid_modes(p, connector);
else if (!num)
dev_warn(p->base.dev, "No display modes\n");
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v4 2/3] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-06 Thread Hsin-Yi Wang
Generic edp gets mode from edid. However, some panels report incorrect
mode in this way, resulting in glitches on panel. Introduce a new quirk
additional_mode to the generic edid to pick a correct hardcoded mode.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v3->v4: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 68 ---
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 599a949d74d1..0fb439b5efb1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -203,6 +203,9 @@ struct edp_panel_entry {
 
/** @name: Name of this panel (for printing to logs). */
const char *name;
+
+   /** @override_edid_mode: Override the mode obtained by edid. */
+   const struct drm_display_mode *override_edid_mode;
 };
 
 struct panel_edp {
@@ -301,6 +304,25 @@ static unsigned int panel_edp_get_display_modes(struct 
panel_edp *panel,
return num;
 }
 
+static int panel_edp_override_edid_mode(struct panel_edp *panel,
+   struct drm_connector *connector,
+   const struct drm_display_mode 
*override_mode)
+{
+   struct drm_display_mode *mode;
+
+   mode = drm_mode_duplicate(connector->dev, override_mode);
+   if (mode) {
+   mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+   drm_mode_set_name(mode);
+   drm_mode_probed_add(connector, mode);
+   return 1;
+   }
+
+   dev_err(panel->base.dev, "failed to add additional mode\n");
+
+   return 0;
+}
+
 static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
 {
@@ -568,6 +590,9 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_override_edid_mode = p->detected_panel &&
+ p->detected_panel != ERR_PTR(-EINVAL) &&
+ p->detected_panel->override_edid_mode;
 
/* probe EDID if a DDC bus is available */
if (p->ddc) {
@@ -575,9 +600,18 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-
-   if (p->edid)
-   num += drm_add_edid_modes(connector, p->edid);
+   if (p->edid) {
+   if (has_override_edid_mode) {
+   /*
+* override_edid_mode is specified. Use
+* override_edid_mode instead of from edid.
+*/
+   num += panel_edp_override_edid_mode(p, 
connector,
+   
p->detected_panel->override_edid_mode);
+   } else {
+   num += drm_add_edid_modes(connector, p->edid);
+   }
+   }
 
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
@@ -950,6 +984,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1878,6 +1925,15 @@ static const struct panel_delay delay_200_150_e200 = {
.delay = _delay \
 }
 
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+{ \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   .delay = _delay, \
+   .override_edid_mode = _mode \
+}
+
 /*
  * This table is used to figure out power sequencing delays for panels that
  * are detected by EDID. Entries here may point to entries in the
@@ -1895,9 +1951,11 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c

[PATCH v4 1/3] drm/panel-edp: drm/panel-edp: Add several generic edp panels

2023-11-06 Thread Hsin-Yi Wang
Add a few generic edp panels used by mt8186 chromebooks.
Besides, modify the following panel:
- AUO 0x235c B116XTN02 renamed to B116XTN02.3.
- AUO 0x405c B116XAK01 adjust the timing of auo_b116xak01. According
to the datasheet: T3=200, T12=500, T7_max = 50.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v3->v4: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 57 +--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 9dce4c702414..599a949d74d1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = {
},
.delay = {
.hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
},
 };
 
@@ -1830,6 +1832,12 @@ static const struct panel_delay delay_200_500_e50 = {
.enable = 50,
 };
 
+static const struct panel_delay delay_200_500_e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 80,
+};
+
 static const struct panel_delay delay_200_500_e80_d50 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1849,6 +1857,19 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d10 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 10,
+};
+
+static const struct panel_delay delay_200_150_e200 = {
+   .hpd_absent = 200,
+   .unprepare = 150,
+   .enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1869,37 +1890,69 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, "B116XTN02"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, _200_500_e50, 
"B140HTN02.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, _200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, _200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, _200_500_e80, 
"NT116WHM-N42"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, _200_500_e200, 
"NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, _200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, _nv133fhm_n61.delay, 
"NV133FHM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, _200_500_e200, 
"NT140FHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, _nv133fhm_n61.delay, 
"NV133FHM-N62"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, _200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, _200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, _200_500_e50, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, _200_500_e80, 
"NV116WHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, _200_500_e50, 
"NE135FBM-N41 v8.1"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, _200_500_e50, 
"NV116WHM-N49 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, _nv110wtm_n61.delay, 
"NV110WTM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, _200_500_e200, 
"NT140FHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, _200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, _200_500_e50, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, _200_500_e50, 
"NV116WHM-N4C"),

[PATCH v4 0/3] Add a few panels and use correct modes

2023-11-06 Thread Hsin-Yi Wang
This series contains 3 patches:
1. Add a few new generic edp panels.
2. Support a new quirk to override the mode read from edid
3. Only add hard-coded mode if both edid and hard-coded modes presents.

v1: 
https://patchwork.kernel.org/project/dri-devel/cover/20231101212604.1636517-1-hsi...@chromium.org/
v2: 
https://patchwork.kernel.org/project/dri-devel/cover/20231102221309.1971910-1-hsi...@chromium.org/
v3: 
https://patchwork.kernel.org/project/dri-devel/cover/20231106202718.2770821-1-hsi...@chromium.org/

Hsin-Yi Wang (3):
  drm/panel-edp: drm/panel-edp: Add several generic edp panels
  drm/panel-edp: Add override_edid_mode quirk for generic edp
  drm/panel-edp: Avoid adding multiple preferred modes

 drivers/gpu/drm/panel/panel-edp.c | 130 --
 1 file changed, 123 insertions(+), 7 deletions(-)

-- 
2.42.0.869.gea05f2083d-goog



Re: [PATCH v3 3/3] drm/panel-edp: Avoid adding multiple preferred modes

2023-11-06 Thread Hsin-Yi Wang
On Mon, Nov 6, 2023 at 12:33 PM Doug Anderson  wrote:
>
> Hi,
>
> On Mon, Nov 6, 2023 at 12:27 PM Hsin-Yi Wang  wrote:
> >
> > diff --git a/drivers/gpu/drm/panel/panel-edp.c 
> > b/drivers/gpu/drm/panel/panel-edp.c
> > index 0fb439b5efb1..54dbbdf62ec0 100644
> > --- a/drivers/gpu/drm/panel/panel-edp.c
> > +++ b/drivers/gpu/drm/panel/panel-edp.c
> > @@ -594,8 +594,20 @@ static int panel_edp_get_modes(struct drm_panel *panel,
> >   p->detected_panel != ERR_PTR(-EINVAL) 
> > &&
> >   p->detected_panel->override_edid_mode;
> >
> > -   /* probe EDID if a DDC bus is available */
> > -   if (p->ddc) {
> > +   /*
> > +* If both edid and hard-coded modes exists, only add hard-coded 
> > modes
> > +* to avoid multiple preferred modes.
> > +*/
> > +   if (p->desc->num_timings || p->desc->num_modes) {
> > +   /*
> > +* Add hard-coded panel modes. Don't call this if there are 
> > no
> > +* timings and no modes (the generic edp-panel case) 
> > because it
> > +* will clobber the display_info that was already set by
> > +* drm_add_edid_modes().
> > +*/
> > +   num += panel_edp_get_non_edid_modes(p, connector);
> > +   } else if (p->ddc) {
> > +   /* probe EDID if a DDC bus is available */
>
> As per discussion in v2, I think if you have the "ddc" you still want
> to fetch the EDID, you just don't want to add the modes from the EDID.
> This will mean that the EDID is present in sysfs if userspace wants to
> look at it for whatever reason.
>
Ack. Will update this.

> -Doug


[PATCH v3 3/3] drm/panel-edp: Avoid adding multiple preferred modes

2023-11-06 Thread Hsin-Yi Wang
If a non generic edp-panel is under aux-bus, the mode read from edid would
still be selected as preferred and results in multiple preferred modes,
which is ambiguous.

If both hard-coded mode and edid exists, only add mode from hard-coded.

Signed-off-by: Hsin-Yi Wang 
---
v2->v3: if hard-coded mode presents, don't add edid mode.
---
 drivers/gpu/drm/panel/panel-edp.c | 25 +++--
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 0fb439b5efb1..54dbbdf62ec0 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -594,8 +594,20 @@ static int panel_edp_get_modes(struct drm_panel *panel,
  p->detected_panel != ERR_PTR(-EINVAL) &&
  p->detected_panel->override_edid_mode;
 
-   /* probe EDID if a DDC bus is available */
-   if (p->ddc) {
+   /*
+* If both edid and hard-coded modes exists, only add hard-coded modes
+* to avoid multiple preferred modes.
+*/
+   if (p->desc->num_timings || p->desc->num_modes) {
+   /*
+* Add hard-coded panel modes. Don't call this if there are no
+* timings and no modes (the generic edp-panel case) because it
+* will clobber the display_info that was already set by
+* drm_add_edid_modes().
+*/
+   num += panel_edp_get_non_edid_modes(p, connector);
+   } else if (p->ddc) {
+   /* probe EDID if a DDC bus is available */
pm_runtime_get_sync(panel->dev);
 
if (!p->edid)
@@ -617,14 +629,7 @@ static int panel_edp_get_modes(struct drm_panel *panel,
pm_runtime_put_autosuspend(panel->dev);
}
 
-   /*
-* Add hard-coded panel modes. Don't call this if there are no timings
-* and no modes (the generic edp-panel case) because it will clobber
-* the display_info that was already set by drm_add_edid_modes().
-*/
-   if (p->desc->num_timings || p->desc->num_modes)
-   num += panel_edp_get_non_edid_modes(p, connector);
-   else if (!num)
+   if (!num)
dev_warn(p->base.dev, "No display modes\n");
 
/*
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v3 2/3] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-06 Thread Hsin-Yi Wang
Generic edp gets mode from edid. However, some panels report incorrect
mode in this way, resulting in glitches on panel. Introduce a new quirk
additional_mode to the generic edid to pick a correct hardcoded mode.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v2->v3: no change.
---
 drivers/gpu/drm/panel/panel-edp.c | 68 ---
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 599a949d74d1..0fb439b5efb1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -203,6 +203,9 @@ struct edp_panel_entry {
 
/** @name: Name of this panel (for printing to logs). */
const char *name;
+
+   /** @override_edid_mode: Override the mode obtained by edid. */
+   const struct drm_display_mode *override_edid_mode;
 };
 
 struct panel_edp {
@@ -301,6 +304,25 @@ static unsigned int panel_edp_get_display_modes(struct 
panel_edp *panel,
return num;
 }
 
+static int panel_edp_override_edid_mode(struct panel_edp *panel,
+   struct drm_connector *connector,
+   const struct drm_display_mode 
*override_mode)
+{
+   struct drm_display_mode *mode;
+
+   mode = drm_mode_duplicate(connector->dev, override_mode);
+   if (mode) {
+   mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+   drm_mode_set_name(mode);
+   drm_mode_probed_add(connector, mode);
+   return 1;
+   }
+
+   dev_err(panel->base.dev, "failed to add additional mode\n");
+
+   return 0;
+}
+
 static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
 {
@@ -568,6 +590,9 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_override_edid_mode = p->detected_panel &&
+ p->detected_panel != ERR_PTR(-EINVAL) &&
+ p->detected_panel->override_edid_mode;
 
/* probe EDID if a DDC bus is available */
if (p->ddc) {
@@ -575,9 +600,18 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-
-   if (p->edid)
-   num += drm_add_edid_modes(connector, p->edid);
+   if (p->edid) {
+   if (has_override_edid_mode) {
+   /*
+* override_edid_mode is specified. Use
+* override_edid_mode instead of from edid.
+*/
+   num += panel_edp_override_edid_mode(p, 
connector,
+   
p->detected_panel->override_edid_mode);
+   } else {
+   num += drm_add_edid_modes(connector, p->edid);
+   }
+   }
 
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
@@ -950,6 +984,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1878,6 +1925,15 @@ static const struct panel_delay delay_200_150_e200 = {
.delay = _delay \
 }
 
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+{ \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   .delay = _delay, \
+   .override_edid_mode = _mode \
+}
+
 /*
  * This table is used to figure out power sequencing delays for panels that
  * are detected by EDID. Entries here may point to entries in the
@@ -1895,9 +1951,11 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', '

[PATCH v3 1/3] drm/panel-edp: drm/panel-edp: Add several generic edp panels

2023-11-06 Thread Hsin-Yi Wang
Add a few generic edp panels used by mt8186 chromebooks.
Besides, modify the following panel:
- AUO 0x235c B116XTN02 renamed to B116XTN02.3.
- AUO 0x405c B116XAK01 adjust the timing of auo_b116xak01. According
to the datasheet: T3=200, T12=500, T7_max = 50.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v2->v3: fix title
---
 drivers/gpu/drm/panel/panel-edp.c | 57 +--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 9dce4c702414..599a949d74d1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = {
},
.delay = {
.hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
},
 };
 
@@ -1830,6 +1832,12 @@ static const struct panel_delay delay_200_500_e50 = {
.enable = 50,
 };
 
+static const struct panel_delay delay_200_500_e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 80,
+};
+
 static const struct panel_delay delay_200_500_e80_d50 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1849,6 +1857,19 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d10 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 10,
+};
+
+static const struct panel_delay delay_200_150_e200 = {
+   .hpd_absent = 200,
+   .unprepare = 150,
+   .enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1869,37 +1890,69 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, "B116XTN02"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, _200_500_e50, 
"B140HTN02.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, _200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, _200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, _200_500_e80, 
"NT116WHM-N42"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, _200_500_e200, 
"NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, _200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, _nv133fhm_n61.delay, 
"NV133FHM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, _200_500_e200, 
"NT140FHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, _nv133fhm_n61.delay, 
"NV133FHM-N62"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, _200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, _200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, _200_500_e50, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, _200_500_e80, 
"NV116WHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, _200_500_e50, 
"NE135FBM-N41 v8.1"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, _200_500_e50, 
"NV116WHM-N49 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, _nv110wtm_n61.delay, 
"NV110WTM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, _200_500_e200, 
"NT140FHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, _200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, _200_500_e50, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, _200_500_e50, 
"NV116WHM-N4C"),

[PATCH v3 0/3] Add a few panels and use correct modes

2023-11-06 Thread Hsin-Yi Wang
This series contains 3 patches:
1. Add a few new generic edp panels.
2. Support a new quirk to override the mode read from edid
3. Only add hard-coded mode if both edid and hard-coded modes presents.

v1: 
https://patchwork.kernel.org/project/dri-devel/cover/20231101212604.1636517-1-hsi...@chromium.org/
v2: 
https://patchwork.kernel.org/project/dri-devel/cover/20231102221309.1971910-1-hsi...@chromium.org/

Hsin-Yi Wang (3):
  drm/panel-edp: drm/panel-edp: Add several generic edp panels
  drm/panel-edp: Add override_edid_mode quirk for generic edp
  drm/panel-edp: Avoid adding multiple preferred modes

 drivers/gpu/drm/panel/panel-edp.c | 148 ++
 1 file changed, 132 insertions(+), 16 deletions(-)

-- 
2.42.0.869.gea05f2083d-goog



Re: [PATCH 3/3] drm/panel-edp: Choose correct preferred mode

2023-11-06 Thread Hsin-Yi Wang
On Mon, Nov 6, 2023 at 8:21 AM Doug Anderson  wrote:
>
> Hi,
>
> On Mon, Nov 6, 2023 at 12:06 AM Maxime Ripard  wrote:
> >
> > On Thu, Nov 02, 2023 at 07:33:48AM -0700, Doug Anderson wrote:
> > > Hi,
> > >
> > > On Wed, Nov 1, 2023 at 11:31 PM Dmitry Baryshkov
> > >  wrote:
> > > >
> > > > On Wed, 1 Nov 2023 at 23:26, Hsin-Yi Wang  wrote:
> > > > >
> > > > > If a non generic edp-panel is under aux-bus, the mode read from edid 
> > > > > would
> > > > > still be selected as preferred and results in multiple preferred 
> > > > > modes,
> > > > > which is ambiguous.
> > > > >
> > > > > If a hard-coded mode is present, unset the preferred bit of the modes 
> > > > > read
> > > > > from edid.
> > > >
> > > > Can we skip the EDID completely if the hardcoded override is present?
> > >
> > > Yeah, I wondered about that too. The blending of the hardcoded with
> > > the EDID predates my involvement with the driver. You can see even as
> > > of commit 280921de7241 ("drm/panel: Add simple panel support") that
> > > the driver would start with the EDID modes (if it had them) and then
> > > go onto add the hardcoded modes. At least for eDP panels, though,
> > > nobody (or almost nobody?) actually provided panel-simple a DDC bus at
> > > the same time it was given a hardcoded panel.
> > >
> > > I guess I could go either way, but I have a slight bias to adding the
> > > extra modes and just making it clear to userspace that none of them
> > > are "preferred". That seems like it would give userspace the most
> > > flexibility
> >
> > I disagree. "Flexibility" here just means "the way to shoot itself in
> > the foot without knowing it's aiming at its foot".
> >
> > If a mode is broken, we shouldn't expose it, just like we don't for all
> > modes that require a maximum frequency higher than what the controller
> > can provide on HDMI for example.
>
> In this particular case we aren't saying that modes are broken. There
> are two (somewhat separate) things in Hsin-Yi's series.
>
> The first thing is a quirk for panels with incorrect modes in their
> EDID when using the generic "edp-panel" compatible. In that case we
> now _replace_ the broken mode with a more correct one because, as you
> say, we shouldn't be telling userspace about a broken mode.
>
> The second thing in Hsin-Yi's series is for when we're _not_ using the
> generic "edp-panel". In that case we have a hardcoded mode from the
> "compatible" string but we also have modes from the EDID and that's
> what ${SUBJECT} patch is about. Here we don't truly know that the
> modes in the EDID are broken.
>
>
> > > and also is closer to what we've historically done (though,
> > > historically, we just allowed there to be more than one "preferred"
> > > mode).
> >
> > I have no idea what history you're referring to here
>
> History = historical behavior? As above, I pointed out that the kernel
> has been merging the hardcoded and EDID modes as far back as commit
> 280921de7241 ("drm/panel: Add simple panel support") in 2013.
>
> That being said, the historical behavior has more than one mode marked
> preferred which is bad, so we're changing the behavior anyway. I'm not
> against changing it to just have the hardcoded mode if that's what
> everyone else wants (and it sounds like it is).

I'll change the behavior to: if hard-coded mode presents, don't add
edid mode since it will result in multiple preferred modes.


Re: [PATCH v2 4/4] drm/panel-edp: Choose correct preferred mode

2023-11-03 Thread Hsin-Yi Wang
On Fri, Nov 3, 2023 at 9:03 AM Doug Anderson  wrote:
>
> Hi,
>
> On Thu, Nov 2, 2023 at 3:13 PM Hsin-Yi Wang  wrote:
> >
> > If a non generic edp-panel is under aux-bus, the mode read from edid would
> > still be selected as preferred and results in multiple preferred modes,
> > which is ambiguous.
> >
> > If a hard-coded mode is present, unset the preferred bit of the modes read
> > from edid.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v1->v2: split patches from drm_modes.
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 7 +--
> >  1 file changed, 5 insertions(+), 2 deletions(-)
>
> Reviewed-by: Douglas Anderson 
>
> Do you think this should have a "Fixes?" As per discussion on V1 [1],
> this has probably been a bit broken from the beginning, though I guess
> it only became a big deal after the AUX bus made it so that the panel
> driver commonly had the EDID...
>
If this patch needs to apply Fixes, then the previous patch might also have to?

Fixes: 280921de7241 ("drm/panel: Add simple panel support")


> [1] 
> https://lore.kernel.org/r/CAD=FV=WHzCdiYumsxUm_am+ALqq9SOOrjf=jyhqjuikfb+d...@mail.gmail.com


Re: [PATCH v2 1/4] drm/panel-edp: Add several AUO/BOE panels

2023-11-03 Thread Hsin-Yi Wang
On Fri, Nov 3, 2023 at 9:02 AM Doug Anderson  wrote:
>
> Hi,
>
> On Thu, Nov 2, 2023 at 3:13 PM Hsin-Yi Wang  wrote:
> >
> > Add a few generic edp panels used by mt8186 chromebooks.
> > Besides, modify the following panel:
> > - AUO 0x235c B116XTN02 renamed to B116XTN02.3.
> > - AUO 0x405c B116XAK01 adjust the timing of auo_b116xak01. According
> > to the datasheet: T3=200, T12=500, T7_max = 50.
> >
> > Signed-off-by: Hsin-Yi Wang 
> > ---
> > v1->v2: Address comments: update delay for auo_b116xak01, sort entries.
> > ---
> >  drivers/gpu/drm/panel/panel-edp.c | 57 +--
> >  1 file changed, 55 insertions(+), 2 deletions(-)
>
> This seems good to me now. I guess a tiny nit is that the ${SUBJECT}
> mentions AUO/BOE panels but a few other model panels are also added,
> but it's not a huge issue for me.
>
Yeah, it should be "drm/panel-edp: Add several generic edp panels",
the same as v1. If there are more comments that I need to send a v3,
I'll fix that in v3.


> Normally I apply patches to this table near-instantly, but since it's
> Friday and this touches a lot of panels, I'll probably wait until
> sometime next week.
>
> Reviewed-by: Douglas Anderson 


[PATCH v2 3/4] drm/modes: Add a function to clear preferred modes

2023-11-02 Thread Hsin-Yi Wang
Add a function to clear the preferred bit of a connector's existing modes.
This is useful for edp panel to unset the preferred modes read from edid
if the panel has hard-coded modes.

Signed-off-by: Hsin-Yi Wang 
---
v1->v2:
- fix doc string (reported by kernel test robot).
- split mode and panel patches.
---
 drivers/gpu/drm/drm_modes.c | 16 
 include/drm/drm_modes.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index ac9a406250c5..be3e9e931219 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1933,6 +1933,22 @@ void drm_connector_list_update(struct drm_connector 
*connector)
 }
 EXPORT_SYMBOL(drm_connector_list_update);
 
+/**
+ * drm_mode_unset_preferred_modes - clear the preferred bit on existing modes.
+ * @connector: the connector to update
+ *
+ * Walk the mode list for connector, clearing the preferred status on existing
+ * modes.
+ */
+void drm_mode_unset_preferred_modes(struct drm_connector *connector)
+{
+   struct drm_display_mode *cur_mode;
+
+   list_for_each_entry(cur_mode, >probed_modes, head)
+   cur_mode->type &= ~DRM_MODE_TYPE_PREFERRED;
+}
+EXPORT_SYMBOL_GPL(drm_mode_unset_preferred_modes);
+
 static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
  struct drm_cmdline_mode *mode)
 {
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index c613f0abe9dc..301817e00a15 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -560,6 +560,7 @@ void drm_mode_prune_invalid(struct drm_device *dev,
struct list_head *mode_list, bool verbose);
 void drm_mode_sort(struct list_head *mode_list);
 void drm_connector_list_update(struct drm_connector *connector);
+void drm_mode_unset_preferred_modes(struct drm_connector *connector);
 
 /* parsing cmdline modes */
 bool
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v2 4/4] drm/panel-edp: Choose correct preferred mode

2023-11-02 Thread Hsin-Yi Wang
If a non generic edp-panel is under aux-bus, the mode read from edid would
still be selected as preferred and results in multiple preferred modes,
which is ambiguous.

If a hard-coded mode is present, unset the preferred bit of the modes read
from edid.

Signed-off-by: Hsin-Yi Wang 
---
v1->v2: split patches from drm_modes.
---
 drivers/gpu/drm/panel/panel-edp.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 0fb439b5efb1..021322ff9f65 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -622,10 +622,13 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 * and no modes (the generic edp-panel case) because it will clobber
 * the display_info that was already set by drm_add_edid_modes().
 */
-   if (p->desc->num_timings || p->desc->num_modes)
+   if (p->desc->num_timings || p->desc->num_modes) {
+   /* hard-coded modes present, unset preferred modes from edid. */
+   drm_mode_unset_preferred_modes(connector);
num += panel_edp_get_non_edid_modes(p, connector);
-   else if (!num)
+   } else if (!num) {
dev_warn(p->base.dev, "No display modes\n");
+   }
 
/*
 * TODO: Remove once all drm drivers call
-- 
2.42.0.869.gea05f2083d-goog



[PATCH v2 2/4] drm/panel-edp: Add override_edid_mode quirk for generic edp

2023-11-02 Thread Hsin-Yi Wang
Generic edp gets mode from edid. However, some panels report incorrect
mode in this way, resulting in glitches on panel. Introduce a new quirk
additional_mode to the generic edid to pick a correct hardcoded mode.

Signed-off-by: Hsin-Yi Wang 
Reviewed-by: Douglas Anderson 
---
v1->v2: no change
---
 drivers/gpu/drm/panel/panel-edp.c | 68 ---
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 599a949d74d1..0fb439b5efb1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -203,6 +203,9 @@ struct edp_panel_entry {
 
/** @name: Name of this panel (for printing to logs). */
const char *name;
+
+   /** @override_edid_mode: Override the mode obtained by edid. */
+   const struct drm_display_mode *override_edid_mode;
 };
 
 struct panel_edp {
@@ -301,6 +304,25 @@ static unsigned int panel_edp_get_display_modes(struct 
panel_edp *panel,
return num;
 }
 
+static int panel_edp_override_edid_mode(struct panel_edp *panel,
+   struct drm_connector *connector,
+   const struct drm_display_mode 
*override_mode)
+{
+   struct drm_display_mode *mode;
+
+   mode = drm_mode_duplicate(connector->dev, override_mode);
+   if (mode) {
+   mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+   drm_mode_set_name(mode);
+   drm_mode_probed_add(connector, mode);
+   return 1;
+   }
+
+   dev_err(panel->base.dev, "failed to add additional mode\n");
+
+   return 0;
+}
+
 static int panel_edp_get_non_edid_modes(struct panel_edp *panel,
struct drm_connector *connector)
 {
@@ -568,6 +590,9 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 {
struct panel_edp *p = to_panel_edp(panel);
int num = 0;
+   bool has_override_edid_mode = p->detected_panel &&
+ p->detected_panel != ERR_PTR(-EINVAL) &&
+ p->detected_panel->override_edid_mode;
 
/* probe EDID if a DDC bus is available */
if (p->ddc) {
@@ -575,9 +600,18 @@ static int panel_edp_get_modes(struct drm_panel *panel,
 
if (!p->edid)
p->edid = drm_get_edid(connector, p->ddc);
-
-   if (p->edid)
-   num += drm_add_edid_modes(connector, p->edid);
+   if (p->edid) {
+   if (has_override_edid_mode) {
+   /*
+* override_edid_mode is specified. Use
+* override_edid_mode instead of from edid.
+*/
+   num += panel_edp_override_edid_mode(p, 
connector,
+   
p->detected_panel->override_edid_mode);
+   } else {
+   num += drm_add_edid_modes(connector, p->edid);
+   }
+   }
 
pm_runtime_mark_last_busy(panel->dev);
pm_runtime_put_autosuspend(panel->dev);
@@ -950,6 +984,19 @@ static const struct panel_desc auo_b101ean01 = {
},
 };
 
+static const struct drm_display_mode auo_b116xa3_mode = {
+   .clock = 70589,
+   .hdisplay = 1366,
+   .hsync_start = 1366 + 40,
+   .hsync_end = 1366 + 40 + 40,
+   .htotal = 1366 + 40 + 40 + 32,
+   .vdisplay = 768,
+   .vsync_start = 768 + 10,
+   .vsync_end = 768 + 10 + 12,
+   .vtotal = 768 + 10 + 12 + 6,
+   .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
 static const struct drm_display_mode auo_b116xak01_mode = {
.clock = 69300,
.hdisplay = 1366,
@@ -1878,6 +1925,15 @@ static const struct panel_delay delay_200_150_e200 = {
.delay = _delay \
 }
 
+#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name, _mode) \
+{ \
+   .name = _name, \
+   .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, 
vend_chr_2, \
+product_id), \
+   .delay = _delay, \
+   .override_edid_mode = _mode \
+}
+
 /*
  * This table is used to figure out power sequencing delays for panels that
  * are detected by EDID. Entries here may point to entries in the
@@ -1895,9 +1951,11 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c

[PATCH v2 1/4] drm/panel-edp: Add several AUO/BOE panels

2023-11-02 Thread Hsin-Yi Wang
Add a few generic edp panels used by mt8186 chromebooks.
Besides, modify the following panel:
- AUO 0x235c B116XTN02 renamed to B116XTN02.3.
- AUO 0x405c B116XAK01 adjust the timing of auo_b116xak01. According
to the datasheet: T3=200, T12=500, T7_max = 50.

Signed-off-by: Hsin-Yi Wang 
---
v1->v2: Address comments: update delay for auo_b116xak01, sort entries.
---
 drivers/gpu/drm/panel/panel-edp.c | 57 +--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/panel/panel-edp.c 
b/drivers/gpu/drm/panel/panel-edp.c
index 9dce4c702414..599a949d74d1 100644
--- a/drivers/gpu/drm/panel/panel-edp.c
+++ b/drivers/gpu/drm/panel/panel-edp.c
@@ -973,6 +973,8 @@ static const struct panel_desc auo_b116xak01 = {
},
.delay = {
.hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 50,
},
 };
 
@@ -1830,6 +1832,12 @@ static const struct panel_delay delay_200_500_e50 = {
.enable = 50,
 };
 
+static const struct panel_delay delay_200_500_e80 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 80,
+};
+
 static const struct panel_delay delay_200_500_e80_d50 = {
.hpd_absent = 200,
.unprepare = 500,
@@ -1849,6 +1857,19 @@ static const struct panel_delay delay_200_500_e200 = {
.enable = 200,
 };
 
+static const struct panel_delay delay_200_500_e200_d10 = {
+   .hpd_absent = 200,
+   .unprepare = 500,
+   .enable = 200,
+   .disable = 10,
+};
+
+static const struct panel_delay delay_200_150_e200 = {
+   .hpd_absent = 200,
+   .unprepare = 150,
+   .enable = 200,
+};
+
 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, 
_delay, _name) \
 { \
.name = _name, \
@@ -1869,37 +1890,69 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, _200_500_e50, 
"B116XAB01.4"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, _200_500_e50, 
"B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, _200_500_e50, 
"B116XAK01.6"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, "B116XTN02"),
-   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, _200_500_e50, 
"B140HTN02.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, _200_500_e50, 
"B116XTN02.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, _200_500_e50, 
"B116XTN02.5"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, _200_500_e50, 
"B140HAN04.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, _b116xak01.delay, 
"B116XAK01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, _200_500_e50, 
"B133UAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, _200_500_e50, 
"B116XAN06.1"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, _200_500_e50, 
"B116XAN06.3"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, _200_500_e50, 
"B140HAK02.7"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, _200_500_e50, 
"B133UAN01.0"),
+   EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, _200_500_e50, 
"B140XTN07.7"),
 
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, _200_150_e200, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, _200_500_e80, 
"NT116WHM-N42"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, _200_500_e200, 
"NT116WHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, _200_500_p2e80, 
"NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, _nv133fhm_n61.delay, 
"NV133FHM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, _200_500_e200, 
"NT140FHM-N44"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, _nv133fhm_n61.delay, 
"NV133FHM-N62"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, _200_500_e200, 
"NT140WHM-N49"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, _200_500_e50, 
"NT116WHM-N21,836X2"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, _200_500_e50, 
"NT116WHM-N21"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, _200_500_e80, 
"NV116WHM-N47"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, _200_500_e50, 
"NE135FBM-N41 v8.1"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, _200_500_e50, 
"NV116WHM-N49 V8.0"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, _nv110wtm_n61.delay, 
"NV110WTM-N61"),
+   EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, _200_500_e200, 
"NT140FHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, _200_500_e50, 
"NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, _200_500_e50, 
"NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, _200_50

[PATCH v2 0/4] Add a few panels and use correct modes

2023-11-02 Thread Hsin-Yi Wang
This series contains 4 patches:
1. Add a few new generic edp panels.
2. Support a new quirk to override the mode read from edid
3-4. Unset preferred mode from edid if hard-coded mode presents.

v1: 
https://patchwork.kernel.org/project/dri-devel/cover/20231101212604.1636517-1-hsi...@chromium.org/

Hsin-Yi Wang (4):
  drm/panel-edp: Add several AUO/BOE panels
  drm/panel-edp: Add override_edid_mode quirk for generic edp
  drm/modes: Add a function to clear preferred modes
  drm/panel-edp: Choose correct preferred mode

 drivers/gpu/drm/drm_modes.c   |  16 
 drivers/gpu/drm/panel/panel-edp.c | 130 --
 include/drm/drm_modes.h   |   1 +
 3 files changed, 139 insertions(+), 8 deletions(-)

-- 
2.42.0.869.gea05f2083d-goog



  1   2   3   4   5   6   >