diff mbox series

[v1,2/4] drm/panel: boe-tv101wum-nl6: Support for BOE nv110wum-l60 MIPI-DSI panel

Message ID 20240410071439.2152588-3-yangcong5@huaqin.corp-partner.google.com (mailing list archive)
State New, archived
Headers show
Series Support BOE nv110wum-l60 and IVO t109nw41 MIPI-DSI panel | expand

Commit Message

cong yang April 10, 2024, 7:14 a.m. UTC
The BOE nv110wum-l60 is a 11.0" WUXGA TFT LCD panel, which fits in nicely
with the existing panel-boe-tv101wum-nl6 driver. Hence, we add a new
compatible with panel specific config.

Signed-off-by: Cong Yang <yangcong5@huaqin.corp-partner.google.com>
---
 .../gpu/drm/panel/panel-boe-tv101wum-nl6.c    | 115 ++++++++++++++++++
 1 file changed, 115 insertions(+)

Comments

Doug Anderson April 11, 2024, 7:40 a.m. UTC | #1
Hi,

On Wed, Apr 10, 2024 at 12:15 AM Cong Yang
<yangcong5@huaqin.corp-partner.google.com> wrote:
>
> The BOE nv110wum-l60 is a 11.0" WUXGA TFT LCD panel, which fits in nicely
> with the existing panel-boe-tv101wum-nl6 driver. Hence, we add a new
> compatible with panel specific config.

I guess we have the same question we've had with this driver in the
past: do we add more tables here, or do we break this out into a
separate driver like we ended up doing with "ili9882t". I guess the
question is: what is the display controller used with this panel and
is it the same (or nearly the same) display controller as other panels
in this driver or is it a completely different display controller.
Maybe you could provide this information in the commit message to help
reviewers understand.


> Signed-off-by: Cong Yang <yangcong5@huaqin.corp-partner.google.com>
> ---
>  .../gpu/drm/panel/panel-boe-tv101wum-nl6.c    | 115 ++++++++++++++++++
>  1 file changed, 115 insertions(+)

Maybe add Linus W to your patches since he has had opinions on this
driver in the past. I've added him as CC here but you should make sure
to CC him on future versions unless he says not to. ;-)


> diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> index 0ffe8f8c01de..f91827e1548c 100644
> --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> @@ -1368,6 +1368,91 @@ static const struct panel_init_cmd starry_himax83102_j02_init_cmd[] = {
>         {},
>  };
>
> +static const struct panel_init_cmd boe_nv110wum_init_cmd[] = {
> +       _INIT_DELAY_CMD(60),
> +       _INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00),

Given that the first command of "(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00)"
seems to be the same as "starry_himax83102_j02" maybe those two are
the same controller? I'm just guessing, but if those are the same
controller as the two new ones you're adding in this series, maybe all
3 of them should be in their own driver? Maybe we can do something to
make more sense of some of these commands too? There certainly seem to
be a lot of commonalities in the init sequences of all 3 and if we can
define the init sequence more logically then we can share more of the
code between the different panels and we don't have a giant duplicated
blob.


> +       _INIT_DCS_CMD(0xB9, 0x00, 0x00, 0x00),
> +       _INIT_DELAY_CMD(50),
> +       _INIT_DCS_CMD(0x11),
> +       _INIT_DELAY_CMD(110),
> +       _INIT_DCS_CMD(0x29),
> +       _INIT_DELAY_CMD(25),
> +       {},
> +};
>  static inline struct boe_panel *to_boe_panel(struct drm_panel *panel)

nit: should have a blank line between the end of your struct and the
next function.


> +static const struct panel_desc boe_nv110wum_desc = {
> +       .modes = &boe_tv110wum_default_mode,
> +       .bpc = 8,
> +       .size = {
> +               .width_mm = 147,
> +               .height_mm = 235,
> +       },
> +       .lanes = 4,
> +       .format = MIPI_DSI_FMT_RGB888,
> +       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> +                     MIPI_DSI_MODE_LPM,
> +       .init_cmds = boe_nv110wum_init_cmd,
> +       .lp11_before_reset = true,
> +};
>  static int boe_panel_get_modes(struct drm_panel *panel,
>                                struct drm_connector *connector)

nit: should have a blank line between the end of your struct and the
next function.


> @@ -1973,6 +2085,9 @@ static const struct of_device_id boe_of_match[] = {
>         { .compatible = "starry,himax83102-j02",
>           .data = &starry_himax83102_j02_desc
>         },
> +       { .compatible = "boe,nv110wum-l60",
> +         .data = &boe_nv110wum_desc
> +       },

nit: the existing panels that are supported are sorted alphabetically.
Please sort things alphabetically throughout your patch series.

-Doug
cong yang April 11, 2024, 8:13 a.m. UTC | #2
Hi,

Doug Anderson <dianders@chromium.org> 于2024年4月11日周四 15:48写道:
>
> Hi,
>
> On Wed, Apr 10, 2024 at 12:15 AM Cong Yang
> <yangcong5@huaqin.corp-partner.google.com> wrote:
> >
> > The BOE nv110wum-l60 is a 11.0" WUXGA TFT LCD panel, which fits in nicely
> > with the existing panel-boe-tv101wum-nl6 driver. Hence, we add a new
> > compatible with panel specific config.
>
> I guess we have the same question we've had with this driver in the
> past: do we add more tables here, or do we break this out into a
> separate driver like we ended up doing with "ili9882t". I guess the
> question is: what is the display controller used with this panel and
> is it the same (or nearly the same) display controller as other panels
> in this driver or is it a completely different display controller.
> Maybe you could provide this information in the commit message to help
> reviewers understand.

okay, I will add detailed information in V2 patch.Thanks.
>
>
> > Signed-off-by: Cong Yang <yangcong5@huaqin.corp-partner.google.com>
> > ---
> >  .../gpu/drm/panel/panel-boe-tv101wum-nl6.c    | 115 ++++++++++++++++++
> >  1 file changed, 115 insertions(+)
>
> Maybe add Linus W to your patches since he has had opinions on this
> driver in the past. I've added him as CC here but you should make sure
> to CC him on future versions unless he says not to. ;-)

Got it,thanks.

>
>
> > diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> > index 0ffe8f8c01de..f91827e1548c 100644
> > --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> > +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> > @@ -1368,6 +1368,91 @@ static const struct panel_init_cmd starry_himax83102_j02_init_cmd[] = {
> >         {},
> >  };
> >
> > +static const struct panel_init_cmd boe_nv110wum_init_cmd[] = {
> > +       _INIT_DELAY_CMD(60),
> > +       _INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00),
>
> Given that the first command of "(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00)"
> seems to be the same as "starry_himax83102_j02" maybe those two are
> the same controller? I'm just guessing, but if those are the same
> controller as the two new ones you're adding in this series, maybe all
> 3 of them should be in their own driver? Maybe we can do something to
> make more sense of some of these commands too? There certainly seem to
> be a lot of commonalities in the init sequences of all 3 and if we can
> define the init sequence more logically then we can share more of the
> code between the different panels and we don't have a giant duplicated
> blob.

Yes, your guess is correct. boe_nv110wum and ivo_t109nw41 and
starry_himax83102_j02
are the same controller (himax83102). They are equipped with different
glass panels (BOE/IVO/starry),
so there will be some differences in initial code and porch.

>
>
> > +       _INIT_DCS_CMD(0xB9, 0x00, 0x00, 0x00),
> > +       _INIT_DELAY_CMD(50),
> > +       _INIT_DCS_CMD(0x11),
> > +       _INIT_DELAY_CMD(110),
> > +       _INIT_DCS_CMD(0x29),
> > +       _INIT_DELAY_CMD(25),
> > +       {},
> > +};
> >  static inline struct boe_panel *to_boe_panel(struct drm_panel *panel)
>
> nit: should have a blank line between the end of your struct and the
> next function.

Got it,thanks.

>
>
> > +static const struct panel_desc boe_nv110wum_desc = {
> > +       .modes = &boe_tv110wum_default_mode,
> > +       .bpc = 8,
> > +       .size = {
> > +               .width_mm = 147,
> > +               .height_mm = 235,
> > +       },
> > +       .lanes = 4,
> > +       .format = MIPI_DSI_FMT_RGB888,
> > +       .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
> > +                     MIPI_DSI_MODE_LPM,
> > +       .init_cmds = boe_nv110wum_init_cmd,
> > +       .lp11_before_reset = true,
> > +};
> >  static int boe_panel_get_modes(struct drm_panel *panel,
> >                                struct drm_connector *connector)
>
> nit: should have a blank line between the end of your struct and the
> next function.
>
>
> > @@ -1973,6 +2085,9 @@ static const struct of_device_id boe_of_match[] = {
> >         { .compatible = "starry,himax83102-j02",
> >           .data = &starry_himax83102_j02_desc
> >         },
> > +       { .compatible = "boe,nv110wum-l60",
> > +         .data = &boe_nv110wum_desc
> > +       },
>
> nit: the existing panels that are supported are sorted alphabetically.
> Please sort things alphabetically throughout your patch series.

Got it, fx net patch. Thanks.

>
> -Doug
Linus Walleij April 11, 2024, 8:25 a.m. UTC | #3
On Thu, Apr 11, 2024 at 9:40 AM Doug Anderson <dianders@chromium.org> wrote:
> On Wed, Apr 10, 2024 at 12:15 AM Cong Yang
> <yangcong5@huaqin.corp-partner.google.com> wrote:
> >
> > The BOE nv110wum-l60 is a 11.0" WUXGA TFT LCD panel, which fits in nicely
> > with the existing panel-boe-tv101wum-nl6 driver. Hence, we add a new
> > compatible with panel specific config.
>
> I guess we have the same question we've had with this driver in the
> past: do we add more tables here, or do we break this out into a
> separate driver like we ended up doing with "ili9882t". I guess the
> question is: what is the display controller used with this panel and
> is it the same (or nearly the same) display controller as other panels
> in this driver or is it a completely different display controller.
> Maybe you could provide this information in the commit message to help
> reviewers understand.

I think at a minimum we need to split out any identifiable display controllers
to their own drivers.

Then what developers see is that the code sequence is very similar
between two completely different display controllers so they have this
urge to shoehorn several displays into the same driver for this
reason.

The latter is not good code reuse, what we need to do here is to split
out a sequencing library, like if we had
drivers/gpu/drm/panel/cmd-seqence-lib.c|.h with a bool Kconfig and
some helpful symbols to do the same seqences in different drivers,
so the same order can be obtained in different display controller
drivers that would be great.

I'm thinking something along the line of

panel_seq_exit_sleep_mode(unsigned int delay_after_exit_sleep,
    u8 *cmd_seq_after_exit_sleep,
    unsigned int delay_after_cmd_seq,
    unsigned int delay_after_set_display_on);

That will call mipi_dsi_dcs_exit_sleep_mode(), delay, send
command sequence, delay, call mipi_dsi_dcs_set_display_on()
and delay where any delay can be 0.

This achieves the same goal without messing up the whole place,
but requires some tinkering with how to pass a sequence the right
way etc.

Are Google & partners interested in the job? ;)

Yours,
Linus Walleij
cong yang April 18, 2024, 12:42 p.m. UTC | #4
Hi,

Linus Walleij <linus.walleij@linaro.org> 于2024年4月11日周四 16:25写道:

>
> On Thu, Apr 11, 2024 at 9:40 AM Doug Anderson <dianders@chromium.org> wrote:
> > On Wed, Apr 10, 2024 at 12:15 AM Cong Yang
> > <yangcong5@huaqin.corp-partner.google.com> wrote:
> > >
> > > The BOE nv110wum-l60 is a 11.0" WUXGA TFT LCD panel, which fits in nicely
> > > with the existing panel-boe-tv101wum-nl6 driver. Hence, we add a new
> > > compatible with panel specific config.
> >
> > I guess we have the same question we've had with this driver in the
> > past: do we add more tables here, or do we break this out into a
> > separate driver like we ended up doing with "ili9882t". I guess the
> > question is: what is the display controller used with this panel and
> > is it the same (or nearly the same) display controller as other panels
> > in this driver or is it a completely different display controller.
> > Maybe you could provide this information in the commit message to help
> > reviewers understand.
>
> I think at a minimum we need to split out any identifiable display controllers
> to their own drivers.
>
> Then what developers see is that the code sequence is very similar
> between two completely different display controllers so they have this
> urge to shoehorn several displays into the same driver for this
> reason.
>
> The latter is not good code reuse, what we need to do here is to split
> out a sequencing library, like if we had
> drivers/gpu/drm/panel/cmd-seqence-lib.c|.h with a bool Kconfig and
> some helpful symbols to do the same seqences in different drivers,
> so the same order can be obtained in different display controller
> drivers that would be great.
>
> I'm thinking something along the line of
>
> panel_seq_exit_sleep_mode(unsigned int delay_after_exit_sleep,
>     u8 *cmd_seq_after_exit_sleep,
>     unsigned int delay_after_cmd_seq,
>     unsigned int delay_after_set_display_on);
>
> That will call mipi_dsi_dcs_exit_sleep_mode(), delay, send
> command sequence, delay, call mipi_dsi_dcs_set_display_on()
> and delay where any delay can be 0.
>
> This achieves the same goal without messing up the whole place,
> but requires some tinkering with how to pass a sequence the right
> way etc.
>
> Are Google & partners interested in the job? ;)
>
> Yours,
> Linus Walleij

I learned from himax that even if the same controller is used with
different glasses, the corresponding parameters are not fixed.

For example: _INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00),

even in the group initial code, the same register will be loaded with
parameters twice.

 example is the same“0xB4” , but the specific implementation functions
are also different.
_INIT_DCS_CMD(0xB4, 0x35, 0x35, 0x43, 0x43, 0x35, 0x35, 0x30, 0x7A,
0x30, 0x7A, 0x01, 0x9D),
. . .
. . .
_INIT_DCS_CMD(0xB4, 0x03, 0xFF, 0xF8),

So assuming that the registers of the two screens is the same now,
it cannot be set as a common parameter.
Otherwise, it may be a bit troublesome for the maintainers.

If necessary, I can break out starry_himax83102_j02, boe_nv110wum and
ivo_t109nw41
as separate driver. Then add some define to these registers.

#define HX83102_SETPOWER 0xb1
#define HX83102_SETDISP 0xb2
#define HX83102_SETCYC 0xb4
#define HX83102_SETEXTC 0xb9
#define HX83102_SETMIPI 0xba
#define HX83102_SETVDC 0xbc
#define HX83102_SETBANK 0xbd
#define HX83102_SETPTBA 0xbf
#define HX83102_SETSTBA 0xc0
#define HX83102_SETTCON 0xc7
#define HX83102_SETRAMDMY 0xc8
#define HX83102_SETPWM 0xc9
#define HX83102_SETCLOCK 0xcb
#define HX83102_SETPANEL 0xcc
#define HX83102_SETCASCADE 0xd0
#define HX83102_SETPCTRL 0xd1
#define HX83102_SETGIP0 0xd3
#define HX83102_SETGIP1 0xd5
#define HX83102_SETGIP3 0xd8
#define HX83102_SETTP1 0xe7
#define HX83102_SETSPCCMD 0xe9

Thanks!
Linus Walleij April 18, 2024, 2 p.m. UTC | #5
On Thu, Apr 18, 2024 at 2:42 PM cong yang
<yangcong5@huaqin.corp-partner.google.com> wrote:

> I learned from himax that even if the same controller is used with
> different glasses, the corresponding parameters are not fixed.
>
> For example: _INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00),
>
> even in the group initial code, the same register will be loaded with
> parameters twice.
(...)
> So assuming that the registers of the two screens is the same now,
> it cannot be set as a common parameter.
> Otherwise, it may be a bit troublesome for the maintainers.
>
> If necessary, I can break out starry_himax83102_j02, boe_nv110wum and
> ivo_t109nw41
> as separate driver. Then add some define to these registers.

Why would you do a separate driver per panel despite they have
the same display controller? I don't get it.

Use one driver, use different compatible strings for the different
panels and use the corresponding sequence for each panel
selected by compatible string.

For example, see drivers/gpu/drm/panel/panel-novatek-nt35510.c:

static const struct of_device_id nt35510_of_match[] = {
        {
                .compatible = "frida,frd400b25025",
                .data = &nt35510_frida_frd400b25025,
        },
        {
                .compatible = "hydis,hva40wv1",
                .data = &nt35510_hydis_hva40wv1,
        },
        { }
};


Take some inspiration from this driver and how we parameterize
the different data depending on compatible string.

Yours,
Linus Walleij
cong yang April 19, 2024, 12:48 a.m. UTC | #6
Hi,

Linus Walleij <linus.walleij@linaro.org> 于2024年4月18日周四 22:00写道:
>
> On Thu, Apr 18, 2024 at 2:42 PM cong yang
> <yangcong5@huaqin.corp-partner.google.com> wrote:
>
> > I learned from himax that even if the same controller is used with
> > different glasses, the corresponding parameters are not fixed.
> >
> > For example: _INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00),
> >
> > even in the group initial code, the same register will be loaded with
> > parameters twice.
> (...)
> > So assuming that the registers of the two screens is the same now,
> > it cannot be set as a common parameter.
> > Otherwise, it may be a bit troublesome for the maintainers.
> >
> > If necessary, I can break out starry_himax83102_j02, boe_nv110wum and
> > ivo_t109nw41
> > as separate driver. Then add some define to these registers.
>
> Why would you do a separate driver per panel despite they have
> the same display controller? I don't get it.
>
> Use one driver, use different compatible strings for the different
> panels and use the corresponding sequence for each panel
> selected by compatible string.

I mean add starry_himax83102_j02, boe_nv110wum and ivo_t109nw41
together to make a separate driver and break out boe-tv101wum-nl6 ,
because they belong to the same controller.

As Doug said :
“I'm just guessing, but if those are the same controller as
the two new ones you're adding in this series, maybe all
3 of them should be in their own driver? Maybe we can do something to
make more sense of some of these commands too? ”


Thanks.
>
> For example, see drivers/gpu/drm/panel/panel-novatek-nt35510.c:
>
> static const struct of_device_id nt35510_of_match[] = {
>         {
>                 .compatible = "frida,frd400b25025",
>                 .data = &nt35510_frida_frd400b25025,
>         },
>         {
>                 .compatible = "hydis,hva40wv1",
>                 .data = &nt35510_hydis_hva40wv1,
>         },
>         { }
> };
>
>
> Take some inspiration from this driver and how we parameterize
> the different data depending on compatible string.
>
> Yours,
> Linus Walleij
Linus Walleij April 19, 2024, 8:24 a.m. UTC | #7
On Fri, Apr 19, 2024 at 2:48 AM cong yang
<yangcong5@huaqin.corp-partner.google.com> wrote:

> > Use one driver, use different compatible strings for the different
> > panels and use the corresponding sequence for each panel
> > selected by compatible string.
>
> I mean add starry_himax83102_j02, boe_nv110wum and ivo_t109nw41
> together to make a separate driver and break out boe-tv101wum-nl6 ,
> because they belong to the same controller.

Aha OK sorry for my misunderstanding!

We are all in agreement.

Yours,
Linus Walleij
diff mbox series

Patch

diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
index 0ffe8f8c01de..f91827e1548c 100644
--- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
+++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
@@ -1368,6 +1368,91 @@  static const struct panel_init_cmd starry_himax83102_j02_init_cmd[] = {
 	{},
 };
 
+static const struct panel_init_cmd boe_nv110wum_init_cmd[] = {
+	_INIT_DELAY_CMD(60),
+	_INIT_DCS_CMD(0xB9, 0x83, 0x10, 0x21, 0x55, 0x00),
+	_INIT_DCS_CMD(0xB1, 0x2C, 0xAF, 0xAF, 0x2B, 0xEB, 0x42, 0xE1, 0x4D, 0x36, 0x36, 0x36, 0x36, 0x1A, 0x8B, 0x11, 0x65, 0x00, 0x88, 0xFA, 0xFF, 0xFF, 0x8F, 0xFF, 0x08, 0x9A, 0x33),
+	_INIT_DCS_CMD(0xB2, 0x00, 0x47, 0xB0, 0x80, 0x00, 0x12, 0x71, 0x3C, 0xA3, 0x11, 0x00, 0x00, 0x00, 0x88, 0xF5, 0x22, 0x8F),
+	_INIT_DCS_CMD(0xB4, 0x49, 0x49, 0x32, 0x32, 0x14, 0x32, 0x84, 0x6E, 0x84, 0x6E, 0x01, 0x9C),
+	_INIT_DCS_CMD(0xE9, 0xCD),
+	_INIT_DCS_CMD(0xBA, 0x84),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+
+	_INIT_DCS_CMD(0xBC, 0x1B, 0x04),
+	_INIT_DCS_CMD(0xBE, 0x20),
+	_INIT_DCS_CMD(0xBF, 0xFC, 0x84),
+
+	_INIT_DCS_CMD(0xC0, 0x36, 0x36, 0x22, 0x00, 0x00, 0xA0, 0x61, 0x08, 0xF5, 0x03),
+	_INIT_DCS_CMD(0xE9, 0xCC),
+	_INIT_DCS_CMD(0xC7, 0x80),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+	_INIT_DCS_CMD(0xE9, 0xC6),
+	_INIT_DCS_CMD(0xC8, 0x97),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+
+	_INIT_DCS_CMD(0xC9, 0x00, 0x1E, 0x30, 0xD4, 0x01),
+	_INIT_DCS_CMD(0xCB, 0x08, 0x13, 0x07, 0x00, 0x0F, 0x34),
+	_INIT_DCS_CMD(0xCC, 0x02, 0x03, 0x44),
+	_INIT_DCS_CMD(0xE9, 0xC4),
+	_INIT_DCS_CMD(0xD0, 0x03),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+	_INIT_DCS_CMD(0xD1, 0x37, 0x06, 0x00, 0x02, 0x04, 0x0C, 0xFF),
+	_INIT_DCS_CMD(0xD2, 0x1F, 0x11, 0x1F, 0x11),
+
+	_INIT_DCS_CMD(0xD3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x04, 0x08, 0x37, 0x37, 0x64, 0x4B, 0x11, 0x11, 0x03, 0x03, 0x32, 0x10, 0x0E, 0x00, 0x0E, 0x32, 0x10, 0x0A, 0x00, 0x0A, 0x32,
+			0x17, 0x98, 0x07, 0x98, 0x00, 0x00),
+	_INIT_DCS_CMD(0xD5, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x24, 0x24, 0x24, 0x24, 0x07, 0x06, 0x07, 0x06, 0x05, 0x04, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x21, 0x20, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18),
+	_INIT_DCS_CMD(0xD8, 0xAF, 0xAA, 0xAA, 0xAA, 0xAA, 0xA0, 0xAF, 0xAA, 0xAA, 0xAA, 0xAA, 0xA0),
+
+	_INIT_DCS_CMD(0xE0, 0x00, 0x05, 0x0D, 0x14, 0x1B, 0x2C, 0x44, 0x49, 0x51, 0x4C, 0x67, 0x6C, 0x71, 0x80, 0x7D, 0x84, 0x8D, 0xA0, 0xA0, 0x4F, 0x58, 0x64, 0x73, 0x00, 0x05, 0x0D, 0x14, 0x1B, 0x2C, 0x44, 0x49, 0x51, 0x4C, 0x67, 0x6C, 0x71, 0x80, 0x7D, 0x84, 0x8D, 0xA0, 0xA0, 0x4F, 0x58, 0x64, 0x73),
+	_INIT_DCS_CMD(0xE7, 0x07, 0x10, 0x10, 0x1A, 0x26, 0x9E, 0x00, 0x53, 0x9B, 0x14, 0x14),
+	_INIT_DCS_CMD(0xE1, 0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x07, 0x80, 0x02, 0x58, 0x00, 0x14, 0x02, 0x58, 0x02, 0x58, 0x02, 0x00, 0x02, 0x2C, 0x00, 0x20, 0x02, 0x02, 0x00, 0x08, 0x00, 0x0C,
+			0x05, 0x0E, 0x04, 0x94, 0x18, 0x00, 0x10, 0xF0, 0x03, 0x0C, 0x20, 0x00, 0x06, 0x0B, 0x0B, 0x33, 0x0E),
+	_INIT_DCS_CMD(0xBD, 0x01),
+	_INIT_DCS_CMD(0xD8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0xA0),
+	_INIT_DCS_CMD(0xB1, 0x01, 0xBF, 0x11),
+	_INIT_DCS_CMD(0xCB, 0x86),
+	_INIT_DCS_CMD(0xD2, 0x96),
+	_INIT_DCS_CMD(0xE9, 0xC9),
+	_INIT_DCS_CMD(0xD3, 0x84),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+	_INIT_DCS_CMD(0xE9, 0xD1),
+	_INIT_DCS_CMD(0xE1, 0xF6, 0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0x74),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+
+	_INIT_DCS_CMD(0xE7, 0x02, 0x00, 0x2B, 0x01, 0x7E, 0x0F, 0x7E, 0x10, 0xA0, 0x00, 0x00),
+	_INIT_DCS_CMD(0xBD, 0x02),
+	_INIT_DCS_CMD(0xB4, 0x02, 0x00, 0xBB, 0x11),
+	_INIT_DCS_CMD(0xD8, 0xFF, 0xAF, 0xFF, 0xFF, 0xFA, 0xA0, 0xFF, 0xAF, 0xFF, 0xFF, 0xFA, 0xA0),
+	_INIT_DCS_CMD(0xE7, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x81, 0x02, 0x40, 0x00, 0x20, 0x65, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00),
+
+	_INIT_DCS_CMD(0xBD, 0x03),
+	_INIT_DCS_CMD(0xD8, 0xAA, 0xAF, 0xAA, 0xAA, 0xA0, 0x00, 0xAA, 0xAF, 0xAA, 0xAA, 0xA0, 0x00, 0xAA, 0xAF, 0xAA, 0xAA, 0xA0, 0x00, 0xAA, 0xAF, 0xAA, 0xAA, 0xA0, 0x00),
+	_INIT_DCS_CMD(0xE9, 0xC6),
+	_INIT_DCS_CMD(0xB4, 0x03, 0xFF, 0xF8),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+	_INIT_DCS_CMD(0xE1, 0x00),
+
+	_INIT_DCS_CMD(0xBD, 0x00),
+	_INIT_DCS_CMD(0xE9, 0xC4),
+	_INIT_DCS_CMD(0xBA, 0x96),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+
+	_INIT_DCS_CMD(0xBD, 0x01),
+	_INIT_DCS_CMD(0xE9, 0xC5),
+	_INIT_DCS_CMD(0xBA, 0x4F),
+	_INIT_DCS_CMD(0xE9, 0x3F),
+
+	_INIT_DCS_CMD(0xBD, 0x00),
+
+	_INIT_DCS_CMD(0xB9, 0x00, 0x00, 0x00),
+	_INIT_DELAY_CMD(50),
+	_INIT_DCS_CMD(0x11),
+	_INIT_DELAY_CMD(110),
+	_INIT_DCS_CMD(0x29),
+	_INIT_DELAY_CMD(25),
+	{},
+};
 static inline struct boe_panel *to_boe_panel(struct drm_panel *panel)
 {
 	return container_of(panel, struct boe_panel, base);
@@ -1795,6 +1880,33 @@  static const struct panel_desc starry_himax83102_j02_desc = {
 	.lp11_before_reset = true,
 };
 
+static const struct drm_display_mode boe_tv110wum_default_mode = {
+	.clock = 166400,
+	.hdisplay = 1200,
+	.hsync_start = 1200 + 65,
+	.hsync_end = 1200 + 65 + 20,
+	.htotal = 1200 + 65 + 20 + 65,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 115,
+	.vsync_end = 1920 + 115 + 8,
+	.vtotal = 1920 + 115 + 8 + 12,
+	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct panel_desc boe_nv110wum_desc = {
+	.modes = &boe_tv110wum_default_mode,
+	.bpc = 8,
+	.size = {
+		.width_mm = 147,
+		.height_mm = 235,
+	},
+	.lanes = 4,
+	.format = MIPI_DSI_FMT_RGB888,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+		      MIPI_DSI_MODE_LPM,
+	.init_cmds = boe_nv110wum_init_cmd,
+	.lp11_before_reset = true,
+};
 static int boe_panel_get_modes(struct drm_panel *panel,
 			       struct drm_connector *connector)
 {
@@ -1973,6 +2085,9 @@  static const struct of_device_id boe_of_match[] = {
 	{ .compatible = "starry,himax83102-j02",
 	  .data = &starry_himax83102_j02_desc
 	},
+	{ .compatible = "boe,nv110wum-l60",
+	  .data = &boe_nv110wum_desc
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, boe_of_match);