Linux ARM-MSM sub-architecture
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: Rob Clark <robdclark@gmail.com>
Cc: linux-arm-msm@vger.kernel.org,
	Bjorn Andersson <bjorn.andersson@sonymobile.com>,
	dri-devel@lists.freedesktop.org
Subject: Re: [PATCH] drm/panel: auo novatek 1080p video mode panel
Date: Fri, 7 Aug 2015 15:19:33 +0200	[thread overview]
Message-ID: <20150807131931.GA27639@ulmo> (raw)
In-Reply-To: <1437507362-20162-1-git-send-email-robdclark@gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 10268 bytes --]

On Tue, Jul 21, 2015 at 03:36:02PM -0400, Rob Clark wrote:
> This is one of several different panels that are used on the Sony Xperia
> Z3 phone.  It can operate in either command or video mode, although so
> far only video mode is implemented (since that is the mode that the
> downstream kernel version I happened to be looking at was using, and
> that is where I got the programming sequences for the panel).
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
> Couple Notes:
>  1) programming sequences and basically everything I know about the
>     panel came from downstream android kernel.  I've started a wiki
>     page to document how to translate from downstream kernel-msm way
>     of doing things to upstream panel framework, which may be useful
>     for others wanting to port downstream panel drivers for snapdragon
>     devices:
> 
>     https://github.com/freedreno/freedreno/wiki/DSI-Panel-Driver-Porting
> 
>  2) The Sony phones at least (not sure if this is common) use one of
>     several different panels, with runtime probing.  Depending on the
>     device they seem to either use a gpio (simple) or send some DSI
>     commands to read back the panel-id.  My rough thinking here about
>     how to handle this is to implement a "panel-meta" driver (or maybe
>     one each for the different probing methods), which would take a
>     list of phandles to the actual candidate panels, and fwd the panel
>     fxn calls to the chosen panel after probing.
> 
>  .../bindings/panel/auo,novatek-1080p.txt           |  25 ++
>  drivers/gpu/drm/panel/Kconfig                      |   9 +
>  drivers/gpu/drm/panel/Makefile                     |   1 +
>  drivers/gpu/drm/panel/panel-auo-novatek-1080p.c    | 470 +++++++++++++++++++++
>  4 files changed, 505 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/panel/auo,novatek-1080p.txt
>  create mode 100644 drivers/gpu/drm/panel/panel-auo-novatek-1080p.c
> 
> diff --git a/Documentation/devicetree/bindings/panel/auo,novatek-1080p.txt b/Documentation/devicetree/bindings/panel/auo,novatek-1080p.txt
> new file mode 100644
> index 0000000..8a53093
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/panel/auo,novatek-1080p.txt
> @@ -0,0 +1,25 @@
> +AU Optronics Corporation 1080x1920 DSI panel
> +
> +This panel supports both video and command mode (although currently only video
> +mode is implemented in the driver.
> +
> +Required properties:
> +- compatible: should be "auo,novatek-1080p-vid"

This looks a little generic for a compatible string. Can't we get at the
specific panel model number that's been used? What if AUO ever produced
some other Novatek panel with a 1080p resolution?

Also, what's the -vid suffix for?

> +Optional properties:
> +- power-supply: phandle of the regulator that provides the supply voltage
> +- reset-gpio: phandle of gpio for reset line
> +- backlight: phandle of the backlight device attached to the panel
> +
> +Example:
> +
> +	dsi@54300000 {
> +		panel: panel@0 {
> +			compatible = "auo,novatek-1080p-vid";
> +			reg = <0>;
> +
> +			power-supply = <...>;
> +			reset-gpio = <...>;
> +			backlight = <...>;
> +		};
> +	};
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index 6d64c7b..89f0e8c 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -43,4 +43,13 @@ config DRM_PANEL_SHARP_LQ101R1SX01
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called panel-sharp-lq101r1sx01.
>  
> +config DRM_PANEL_AUO_NOVATEK_1080P
> +	tristate "AUO Novatek 1080p video mode panel"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y here if you want to enable support for AUO 1080p DSI panel
> +	  as found in some Sony XPERIA Z3 devices
> +

Can we sort this alphabetically, please?

>  endmenu
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index 4b2a043..cbcfedf 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -2,3 +2,4 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
>  obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
>  obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
>  obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
> +obj-$(CONFIG_DRM_PANEL_AUO_NOVATEK_1080P) += panel-auo-novatek-1080p.o

This too.

Actually, nevermind. I have local patches to add vendor prefixes more
consistently so that we can actually sort properly. I can fix that up
in your patch when I apply.

> diff --git a/drivers/gpu/drm/panel/panel-auo-novatek-1080p.c b/drivers/gpu/drm/panel/panel-auo-novatek-1080p.c
> +static int auo_panel_init(struct auo_panel *auo)
> +{
> +	struct mipi_dsi_device *dsi = auo->dsi;
> +	int ret;
> +
> +	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
> +
> +	ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xb0, 0x04 }, 2);

I find this notation hard to read. Have you considered moving this into
some sort of table that you can loop through? Or perhaps add some
helpers, say, mipi_dsi_generic_writeb() and mipi_dsi_dcs_writeb() to
help make this more readable?

> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xff, (u8[]){ 0xe0 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xfb, (u8[]){ 0x01 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xb5, (u8[]){ 0x86 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xb6, (u8[]){ 0x77 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xb8, (u8[]){ 0xad }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xff, (u8[]){ 0x20 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xfb, (u8[]){ 0x01 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xff, (u8[]){ 0x24 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xfb, (u8[]){ 0x01 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xc6, (u8[]){ 0x00 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xc5, (u8[]){ 0x32 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0x92, (u8[]){ 0x92 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xff, (u8[]){ 0x10 }, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_SCANLINE,
> +			(u8[]){ 0x03, 0x00 }, 2);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0x3b, (u8[]){ 0x03, 0x30, 0x06 }, 3);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = mipi_dsi_dcs_write(dsi, 0xbb, (u8[]){ 0x10 }, 1);
> +	if (ret < 0)
> +		return ret;
> +	msleep(1);
> +
> +	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
> +	if (ret < 0)
> +		return ret;
> +	msleep(30);
> +
> +	return 0;
> +}
> +
> +static int auo_panel_on(struct auo_panel *auo)
> +{
> +	struct mipi_dsi_device *dsi = auo->dsi;
> +	int ret;
> +
> +	dsi->mode_flags |= MIPI_DSI_MODE_LPM;

This is weird.

> +	ret = mipi_dsi_dcs_set_display_on(dsi);
> +	if (ret < 0)
> +		return ret;
> +
> +	msleep(40);
> +
> +	return 0;
> +}
> +
> +static int auo_panel_off(struct auo_panel *auo)
> +{
> +	struct mipi_dsi_device *dsi = auo->dsi;
> +	int ret;
> +
> +	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;

And this even more. Doesn't the panel work when you simply send
everything in low-power mode?

> +static int auo_panel_prepare(struct drm_panel *panel)
> +{
> +	struct auo_panel *auo = to_auo_panel(panel);
> +	int ret;
> +
> +	if (auo->prepared)
> +		return 0;
> +
> +	DRM_DEBUG("prepare\n");
> +
> +	if (auo->reset_gpio) {
> +		gpiod_set_value(auo->reset_gpio, 0);
> +		msleep(5);
> +	}
> +
> +	ret = regulator_enable(auo->supply);
> +	if (ret < 0)
> +		return ret;
> +
> +	msleep(20);
> +
> +	if (auo->reset_gpio) {
> +		gpiod_set_value(auo->reset_gpio, 1);
> +		msleep(10);
> +	}
> +
> +	msleep(150);
> +
> +	ret = auo_panel_init(auo);
> +	if (ret) {
> +		dev_err(panel->dev, "failed to init panel: %d\n", ret);
> +		goto poweroff;
> +	}
> +
> +	ret = auo_panel_on(auo);
> +	if (ret) {
> +		dev_err(panel->dev, "failed to set panel on: %d\n", ret);
> +		goto poweroff;
> +	}
> +
> +	auo->prepared = true;
> +
> +	return 0;
> +
> +poweroff:
> +	regulator_disable(auo->supply);
> +	if (auo->reset_gpio)
> +		gpiod_set_value(auo->reset_gpio, 0);

You should be able to do without the check here, because
gpiod_set_value() will simply nop if the GPIO is NULL.

I assume you may not want to do it above because of the additional
delays that are only relevant if you have a reset GPIO.

> +	return ret;
> +}
> +
> +static int auo_panel_enable(struct drm_panel *panel)
> +{
> +	struct auo_panel *auo = to_auo_panel(panel);
> +
> +	if (auo->enabled)
> +		return 0;
> +
> +	DRM_DEBUG("enable\n");
> +
> +	if (auo->backlight) {
> +		auo->backlight->props.power = FB_BLANK_UNBLANK;
> +		backlight_update_status(auo->backlight);
> +	}
> +
> +	auo->enabled = true;
> +
> +	return 0;
> +}
> +
> +static int auo_panel_add(struct auo_panel *auo)
> +{
> +	struct device *dev= &auo->dsi->dev;
> +	struct device_node *np;
> +	int ret;
> +
> +	auo->mode = &default_mode;

This seems to be unused.

> +
> +	auo->supply = devm_regulator_get(dev, "power");
> +	if (IS_ERR(auo->supply))
> +		return PTR_ERR(auo->supply);
> +
> +	auo->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(auo->reset_gpio)) {
> +		dev_err(dev, "cannot get reset-gpios %ld\n",
> +			PTR_ERR(auo->reset_gpio));
> +		auo->reset_gpio = NULL;
> +	} else {
> +		gpiod_direction_output(auo->reset_gpio, 0);

Isn't that what GPIOD_OUT_LOW already does?


[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2015-08-07 13:19 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-21 19:36 [PATCH] drm/panel: auo novatek 1080p video mode panel Rob Clark
2015-08-07 13:19 ` Thierry Reding [this message]
2015-08-07 16:11   ` Rob Clark
2015-08-10 19:54     ` Bjorn Andersson
2015-08-10 21:45       ` Rob Clark
2015-08-17 11:38       ` Thierry Reding
2015-08-17 14:48         ` Rob Clark
2015-08-17 14:57           ` Thierry Reding
2015-08-17 12:07     ` Thierry Reding
2015-08-17 17:27 ` Bjorn Andersson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150807131931.GA27639@ulmo \
    --to=thierry.reding@gmail.com \
    --cc=bjorn.andersson@sonymobile.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=robdclark@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox