Re: [PATCH v4 1/3] virtio: add dma-buf support for exported objects

2020-06-07 Thread Michael S. Tsirkin
On Mon, Jun 08, 2020 at 10:33:09AM +0900, David Stevens wrote:
> On Sun, Jun 7, 2020 at 5:04 AM Michael S. Tsirkin  wrote:
> >
> > On Fri, Jun 05, 2020 at 10:28:42AM +0900, David Stevens wrote:
> > > On Fri, Jun 5, 2020 at 4:05 AM Michael S. Tsirkin  wrote:
> > > >
> > > > On Tue, May 26, 2020 at 07:58:09PM +0900, David Stevens wrote:
> > > > > This change adds a new flavor of dma-bufs that can be used by virtio
> > > > > drivers to share exported objects. A virtio dma-buf can be queried by
> > > > > virtio drivers to obtain the UUID which identifies the underlying
> > > > > exported object.
> > > > >
> > > > > Signed-off-by: David Stevens 
> > > >
> > > > Is this just for graphics? If yes I'd rather we put it in the graphics
> > > > driver. We can always move it later ...
> > >
> > > As stated in the cover letter, this will be used by virtio-video.
> > >
> > > The proposed virtio-video patches: 
> > > https://markmail.org/thread/p5d3k566srtdtute
> > > The patch which imports these dma-bufs (slightly out of data, uses v3
> > > of this patch set): https://markmail.org/thread/j4xlqaaim266qpks
> > >
> > > > > ---
> > > > >  drivers/virtio/Makefile |  2 +-
> > > > >  drivers/virtio/virtio.c |  6 +++
> > > > >  drivers/virtio/virtio_dma_buf.c | 89 
> > > > > +
> > > > >  include/linux/virtio.h  |  1 +
> > > > >  include/linux/virtio_dma_buf.h  | 58 +
> > > > >  5 files changed, 155 insertions(+), 1 deletion(-)
> > > > >  create mode 100644 drivers/virtio/virtio_dma_buf.c
> > > > >  create mode 100644 include/linux/virtio_dma_buf.h
> > > > >
> > > > > diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
> > > > > index 29a1386ecc03..ecdae5b596de 100644
> > > > > --- a/drivers/virtio/Makefile
> > > > > +++ b/drivers/virtio/Makefile
> > > > > @@ -1,5 +1,5 @@
> > > > >  # SPDX-License-Identifier: GPL-2.0
> > > > > -obj-$(CONFIG_VIRTIO) += virtio.o virtio_ring.o
> > > > > +obj-$(CONFIG_VIRTIO) += virtio.o virtio_ring.o virtio_dma_buf.o
> > > > >  obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
> > > > >  obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
> > > > >  virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
> > > > > diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
> > > > > index a977e32a88f2..5d46f0ded92d 100644
> > > > > --- a/drivers/virtio/virtio.c
> > > > > +++ b/drivers/virtio/virtio.c
> > > > > @@ -357,6 +357,12 @@ int register_virtio_device(struct virtio_device 
> > > > > *dev)
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(register_virtio_device);
> > > > >
> > > > > +bool is_virtio_device(struct device *dev)
> > > > > +{
> > > > > + return dev->bus == &virtio_bus;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(is_virtio_device);
> > > > > +
> > > > >  void unregister_virtio_device(struct virtio_device *dev)
> > > > >  {
> > > > >   int index = dev->index; /* save for after device release */
> > > > > diff --git a/drivers/virtio/virtio_dma_buf.c 
> > > > > b/drivers/virtio/virtio_dma_buf.c
> > > > > new file mode 100644
> > > > > index ..23e3399b11ed
> > > > > --- /dev/null
> > > > > +++ b/drivers/virtio/virtio_dma_buf.c
> > > > > @@ -0,0 +1,89 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > > > +/*
> > > > > + * dma-bufs for virtio exported objects
> > > > > + *
> > > > > + * Copyright (C) 2020 Google, Inc.
> > > > > + */
> > > > > +
> > > > > +#include 
> > > > > +
> > > > > +/**
> > > > > + * virtio_dma_buf_export - Creates a new dma-buf for a virtio 
> > > > > exported object
> > > > > + *
> > > > > + * This wraps dma_buf_export() to allow virtio drivers to create a 
> > > > > dma-buf
> > > > > + * for an virtio exported object that can be queried by other virtio 
> > > > > drivers
> > > > > + * for the object's UUID.
> > > > > + */
> > > > > +struct dma_buf *virtio_dma_buf_export(
> > > > > + const struct virtio_dma_buf_export_info 
> > > > > *virtio_exp_info)
> > > > > +{
> > > > > + struct dma_buf_export_info exp_info;
> > > > > +
> > > > > + if (!virtio_exp_info->ops
> > > > > + || virtio_exp_info->ops->ops.attach != 
> > > > > &virtio_dma_buf_attach
> > > > > + || !virtio_exp_info->ops->get_uuid) {
> > > > > + return ERR_PTR(-EINVAL);
> > > > > + }
> > > > > +
> > > > > + exp_info.exp_name = virtio_exp_info->exp_name;
> > > > > + exp_info.owner = virtio_exp_info->owner;
> > > > > + exp_info.ops = &virtio_exp_info->ops->ops;
> > > > > + exp_info.size = virtio_exp_info->size;
> > > > > + exp_info.flags = virtio_exp_info->flags;
> > > > > + exp_info.resv = virtio_exp_info->resv;
> > > > > + exp_info.priv = virtio_exp_info->priv;
> > > > > + BUILD_BUG_ON(sizeof(struct virtio_dma_buf_export_info)
> > > > > +  != sizeof(struct dma_buf_export_info));
> > > >
> > > > This is the only part that gives me pause. Why do we need this hack?
> > > > What's wrong with just using dma_b

[git pull] drm msm next for 5.8-rc1

2020-06-07 Thread Dave Airlie
Hi Linus,

This should be the final feature pull for drm for rc1. This tree has
been in next for a couple of weeks, but Rob missed an arm32 build
issue, so I was awaiting the tree with a patch reverted. The tree was
also based on an 5.7-rc5 tree so I didn't want to futz around with
backmerging just for this, so I'm sending it from a topic branch based
on v5.7.

Dave.

drm-next-msm-5.8-2020-06-08:
drm msm next for 5.8-rc1

* new gpu support: a405, a640, a650
* dpu: color processing support
* mdp5: support for msm8x36 (the thing with a405)
* some prep work for per-context pagetables (ie the part that
  does not depend on in-flight iommu patches)
* last but not least, UABI update for submit ioctl to support
  syncobj (from Bas)
The following changes since commit 3d77e6a8804abcc0504c904bd6e5cdf3a5cf8162:

  Linux 5.7 (2020-05-31 16:49:15 -0700)

are available in the Git repository at:

  git://anongit.freedesktop.org/drm/drm tags/drm-next-msm-5.8-2020-06-08

for you to fetch changes up to efe792f39ddbc6396b9142afff97855ee357b492:

  Merge https://gitlab.freedesktop.org/drm/msm into drm-next-msm-5.8
(2020-06-08 13:22:57 +1000)


drm msm next for 5.8-rc1

* new gpu support: a405, a640, a650
* dpu: color processing support
* mdp5: support for msm8x36 (the thing with a405)
* some prep work for per-context pagetables (ie the part that
  does not depend on in-flight iommu patches)
* last but not least, UABI update for submit ioctl to support
  syncobj (from Bas)


Bas Nieuwenhuizen (1):
  drm/msm: Add syncobj support.

Bjorn Andersson (1):
  drm/msm: Fix undefined "rd_full" link error

Christophe JAILLET (2):
  drm/msm/a6xx: Fix a typo in an error message
  drm/msm: Fix typo

Dave Airlie (1):
  Merge https://gitlab.freedesktop.org/drm/msm into drm-next-msm-5.8

Hongbo Yao (1):
  drm/msm/dpu: Fix compile warnings

Jonathan Marek (10):
  drm/msm: add msm_gem_get_and_pin_iova_range
  drm/msm: add internal MSM_BO_MAP_PRIV flag
  drm/msm/a6xx: use msm_gem for GMU memory objects
  drm/msm/a6xx: add A640/A650 to gpulist
  drm/msm/a6xx: HFI v2 for A640 and A650
  drm/msm/a6xx: A640/A650 GMU firmware path
  drm/msm/a6xx: update pdc/rscc GMU registers for A640/A650
  drm/msm/a6xx: enable GMU log
  drm/msm/a6xx: update a6xx_hw_init for A640 and A650
  drm/msm/a6xx: skip HFI set freq if GMU is powered down

Jordan Crouse (4):
  drm/msm: Check for powered down HW in the devfreq callbacks
  drm/msm: Attach the IOMMU device during initialization
  drm/msm: Refactor address space initialization
  drm/msm: Update the MMU helper function APIs

Kalyan Thota (3):
  drm/msm/dpu: add support for color processing blocks in dpu driver
  drm/msm/dpu: add support for pcc color block in dpu driver
  drm/msm/dpu: add support for clk and bw scaling for display

Konrad Dybcio (1):
  drm/msm/mdp5: Add MDP5 configuration for MSM8x36.

Krishna Manikandan (1):
  drm/msm/dpu: update bandwidth threshold check

Rob Clark (1):
  Revert "drm/msm/dpu: add support for clk and bw scaling for display"

Roy Spliet (1):
  drm/msm/mdp5: Fix mdp5_init error path for failed mdp5_kms allocation

Shawn Guo (2):
  drm/msm/a4xx: add adreno a405 support
  drm/msm/a4xx: add a405_registers for a405 device

kbuild test robot (2):
  drm/msm/a6xx: a6xx_hfi_send_start() can be static
  drm/msm/dpu: dpu_setup_dspp_pcc() can be static

 drivers/gpu/drm/msm/Makefile   |   1 +
 drivers/gpu/drm/msm/adreno/a2xx_gpu.c  |  16 +
 drivers/gpu/drm/msm/adreno/a3xx_gpu.c  |   1 +
 drivers/gpu/drm/msm/adreno/a4xx_gpu.c  |  83 -
 drivers/gpu/drm/msm/adreno/a5xx_gpu.c  |   7 +
 drivers/gpu/drm/msm/adreno/a6xx.xml.h  |  14 +
 drivers/gpu/drm/msm/adreno/a6xx_gmu.c  | 418 +++--
 drivers/gpu/drm/msm/adreno/a6xx_gmu.h  |  37 ++-
 drivers/gpu/drm/msm/adreno/a6xx_gmu.xml.h  |  48 +--
 drivers/gpu/drm/msm/adreno/a6xx_gpu.c  |  70 -
 drivers/gpu/drm/msm/adreno/a6xx_hfi.c  | 123 +++-
 drivers/gpu/drm/msm/adreno/a6xx_hfi.h  |  50 ++-
 drivers/gpu/drm/msm/adreno/adreno_device.c |  35 +++
 drivers/gpu/drm/msm/adreno/adreno_gpu.c|  27 +-
 drivers/gpu/drm/msm/adreno/adreno_gpu.h|  23 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c  |  23 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  95 --
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h   |   2 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  48 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  39 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c |  26 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h |   3 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c| 129 
 drivers

Re: [PATCH v2] drm/rcar-du: DRM_RCAR_WRITEBACK depends on DRM

2020-06-07 Thread Laurent Pinchart
Hi Qian,

I forgot to mention, I think the subject line should be

drm/rcar-du: Make DRM_RCAR_WRITEBACK depend on DRM_RCAR_DU

Could you please let me know if you're OK with these two small changes ?

On Mon, Jun 08, 2020 at 06:14:43AM +0300, Laurent Pinchart wrote:
> On Sun, Jun 07, 2020 at 10:53:40PM -0400, Qian Cai wrote:
> > There is no need to select DRM_RCAR_WRITEBACK if DRM=n which just make
> 
> s/DRM=n/DRM_RCAR_DU=n/ here.
> 
> > the generated .config a bit ugly.
> > 
> >  # ARM devices
> >  #
> >  # end of ARM devices
> > 
> >  CONFIG_DRM_RCAR_WRITEBACK=y
> > 
> >  #
> >  # Frame buffer Devices
> > 
> > Let DRM_RCAR_WRITEBACK depend on DRM_RCAR_DU instead.
> > 
> > Signed-off-by: Qian Cai 
> 
> Reviewed-by: Laurent Pinchart 
> 
> No need to submit a v3 if you agree with the above change, I'll fix it
> in my tree.
> 
> > ---
> >  drivers/gpu/drm/rcar-du/Kconfig | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/drivers/gpu/drm/rcar-du/Kconfig 
> > b/drivers/gpu/drm/rcar-du/Kconfig
> > index 0919f1f159a4..3304b41f5611 100644
> > --- a/drivers/gpu/drm/rcar-du/Kconfig
> > +++ b/drivers/gpu/drm/rcar-du/Kconfig
> > @@ -48,3 +48,4 @@ config DRM_RCAR_VSP
> >  config DRM_RCAR_WRITEBACK
> > bool
> > default y if ARM64
> > +   depends on DRM_RCAR_DU

-- 
Regards,

Laurent Pinchart
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[git pull] drm next fixes for 5.7-rc1

2020-06-07 Thread Dave Airlie
Hey Linus,

This are the fixes from last week for the stuff merged in the merge
window. It got a bunch of nouveau fixes for HDA audio on some new
GPUs, some i915 and some amdpgu fixes.

I've got another pull request with Rob's msm next stuff in it I'll
send along after this, it was in -next all along, but it needed a
revert before I merged it, and it also was on a different base, so
I'll sent a separate pull from my fixes branch to avoid me having to
backmerge anything here yet.

Dave.

drm-next-2020-06-08:
drm fixes for 5.7-rc1

i915:
- gvt: Fix one clang warning on debug only function
   Use ARRAY_SIZE for coccicheck warn
- Use after free fix for display global state.
- Whitelisting context-local timestamp on Gen9
  and two scheduler fixes with deps (Cc: stable)
- Removal of write flag from sysfs files where
  ineffective

nouveau:
- HDMI/DP audio HDA fixes
- display hang fix for Volta/Turing
- GK20A regression fix.

amdgpu:
- Prevent hwmon accesses while GPU is in reset
- CTF interrupt fix
- Backlight fix for renoir
- Fix for display sync groups
- Display bandwidth validation workaround
The following changes since commit 9ca1f474cea0edc14a1d7ec933e5472c0ff115d3:

  Merge tag 'amd-drm-next-5.8-2020-05-27' of
git://people.freedesktop.org/~agd5f/linux into drm-next (2020-05-28
16:10:17 +1000)

are available in the Git repository at:

  git://anongit.freedesktop.org/drm/drm tags/drm-next-2020-06-08

for you to fetch changes up to 8d286e2ff4400d313955b4203fc640ca6fd9228b:

  Merge tag 'drm-intel-next-fixes-2020-06-04' of
git://anongit.freedesktop.org/drm/drm-intel into drm-next (2020-06-08
11:59:57 +1000)


drm fixes for 5.7-rc1

i915:
- gvt: Fix one clang warning on debug only function
   Use ARRAY_SIZE for coccicheck warn
- Use after free fix for display global state.
- Whitelisting context-local timestamp on Gen9
  and two scheduler fixes with deps (Cc: stable)
- Removal of write flag from sysfs files where
  ineffective

nouveau:
- HDMI/DP audio HDA fixes
- display hang fix for Volta/Turing
- GK20A regression fix.

amdgpu:
- Prevent hwmon accesses while GPU is in reset
- CTF interrupt fix
- Backlight fix for renoir
- Fix for display sync groups
- Display bandwidth validation workaround


Aishwarya Ramakrishnan (1):
  drm/i915/gvt: Use ARRAY_SIZE for vgpu_types

Alex Deucher (2):
  drm/amdgpu/pm: return an error during GPU reset or suspend (v2)
  drm/amdgpu/display: use blanked rather than plane state for sync groups

Ben Skeggs (8):
  drm/nouveau/disp/gm200-: fix NV_PDISP_SOR_HDMI2_CTRL(n) selection
  drm/nouveau/kms/gt215-: fix race with audio driver runpm
  drm/nouveau/disp: provide hint to OR allocation about HDA requirements
  drm/nouveau/disp: split part of OR allocation logic into a function
  drm/nouveau/disp: modify OR allocation policy to account for HDA
requirements
  drm/nouveau/disp/gp100: split SOR implementation from gm200
  drm/nouveau/disp/gm200-: detect and potentially disable HDA
support on some SORs
  drm/nouveau/kms/nv50-: clear SW state of disabled windows harder

Chris Wilson (9):
  drm/i915: Don't set queue-priority hint when supressing the reschedule
  drm/i915/gt: Remove errant assertion in __intel_context_do_pin
  drm/i915: Disable semaphore inter-engine sync without timeslicing
  drm/i915: Avoid using rq->engine after free during i915_fence_release
  drm/i915/gem: Avoid iterating an empty list
  drm/i915: Reorder await_execution before await_request
  drm/i915/gt: Do not schedule normal requests immediately along virtual
  drm/i915: Check for awaits on still currently executing requests
  drm/i915: Whitelist context-local timestamp in the gen9 cmdparser

Dave Airlie (3):
  Merge branch 'linux-5.8' of git://github.com/skeggsb/linux into drm-next
  Merge tag 'amd-drm-fixes-5.8-2020-06-04' of
git://people.freedesktop.org/~agd5f/linux into drm-next
  Merge tag 'drm-intel-next-fixes-2020-06-04' of
git://anongit.freedesktop.org/drm/drm-intel into drm-next

Evan Quan (1):
  drm/amd/powerplay: ack the SMUToHost interrupt on receive V2

Harry Wentland (1):
  Revert "drm/amd/display: disable dcn20 abm feature for bring up"

Jani Nikula (2):
  drm/i915/params: don't expose inject_probe_failure in debugfs
  drm/i915/params: fix i915.fake_lmem_start module param sysfs permissions

Joonas Lahtinen (1):
  Merge tag 'gvt-next-fixes-2020-05-28' of
https://github.com/intel/gvt-linux into drm-intel-next-fixes

Nathan Chancellor (1):
  drm/i915: Mark check_shadow_context_ppgtt as maybe unused

Nicholas Kazlauskas (1):
  drm/amd/display: Revalidate bandwidth before commiting DC updates

Thierry Reding (1):
  drm/nouveau: gr/gk20a: Use firmware version 0

Ville Syrjälä (1):
  drm/i915: Fix global state use-after-frees with a refcount

 driv

Re: [PATCH v2] drm/rcar-du: DRM_RCAR_WRITEBACK depends on DRM

2020-06-07 Thread Laurent Pinchart
Hi Qian,

Thank you for the patch.

On Sun, Jun 07, 2020 at 10:53:40PM -0400, Qian Cai wrote:
> There is no need to select DRM_RCAR_WRITEBACK if DRM=n which just make

s/DRM=n/DRM_RCAR_DU=n/ here.

> the generated .config a bit ugly.
> 
>  # ARM devices
>  #
>  # end of ARM devices
> 
>  CONFIG_DRM_RCAR_WRITEBACK=y
> 
>  #
>  # Frame buffer Devices
> 
> Let DRM_RCAR_WRITEBACK depend on DRM_RCAR_DU instead.
> 
> Signed-off-by: Qian Cai 

Reviewed-by: Laurent Pinchart 

No need to submit a v3 if you agree with the above change, I'll fix it
in my tree.

> ---
>  drivers/gpu/drm/rcar-du/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
> index 0919f1f159a4..3304b41f5611 100644
> --- a/drivers/gpu/drm/rcar-du/Kconfig
> +++ b/drivers/gpu/drm/rcar-du/Kconfig
> @@ -48,3 +48,4 @@ config DRM_RCAR_VSP
>  config DRM_RCAR_WRITEBACK
>   bool
>   default y if ARM64
> + depends on DRM_RCAR_DU

-- 
Regards,

Laurent Pinchart
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH] drm/rcar-du: DRM_RCAR_WRITEBACK depends on DRM

2020-06-07 Thread Laurent Pinchart
Hi Qian,

Thank you for the patch.

On Sun, Jun 07, 2020 at 09:48:18PM -0400, Qian Cai wrote:
> There is no need to select DRM_RCAR_WRITEBACK if DRM=n which just make
> the generated .config a bit ugly.
> 
>  # ARM devices
>  #
>  # end of ARM devices
> 
>  CONFIG_DRM_RCAR_WRITEBACK=y
> 
>  #
>  # Frame buffer Devices
> 
> Signed-off-by: Qian Cai 
> ---
>  drivers/gpu/drm/rcar-du/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
> index 0919f1f159a4..d80696455d3e 100644
> --- a/drivers/gpu/drm/rcar-du/Kconfig
> +++ b/drivers/gpu/drm/rcar-du/Kconfig
> @@ -48,3 +48,4 @@ config DRM_RCAR_VSP
>  config DRM_RCAR_WRITEBACK
>   bool
>   default y if ARM64
> + depends on DRM

How about depending on DRM_RCAR_DU instead, as DRM_RCAR_WRITEBACK is
used to select compilation of rcar_du_writeback.c that is part of the
rcar-du driver ?

-- 
Regards,

Laurent Pinchart
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v4 00/12] PCI: brcmstb: enable PCIe for STB chips

2020-06-07 Thread Jim Quinlan


v4:
  Commit "device core: Introduce multiple dma pfn offsets"
  -- of_dma_get_range() does not take a dev param but instead
 takes two "out" params: map and map_size.  We do this so
 that the code that parses dma-ranges is separate from
 the code that modifies 'dev'.   (Nicolas)
  -- the separate case of having a single pfn offset has
 been removed and is now processed by going through the
 map array. (Nicolas)
  -- move attach_uniform_dma_pfn_offset() from of/address.c to
 dma/mapping.c so that it does not depend on CONFIG_OF. (Nicolas)
  -- devm_kcalloc => devm_kzalloc (DanC)
  -- add/fix assignment to dev->dma_pfn_offset_map for func
 attach_uniform_dma_pfn_offset() (DanC, Nicolas)
  -- s/struct dma_pfn_offset_region/struct bus_dma_region/ (Nicolas)
  -- s/attach_uniform_dma_pfn_offset/dma_attach_uniform_pfn_offset/
  -- s/attach_dma_pfn_offset_map/dma_attach_pfn_offset_map/
  -- More use of PFN_{PHYS,DOWN,UP}. (AndyS)
  Commit "of: Include a dev param in of_dma_get_range()"
  -- this commit was sqaushed with "device core: Introduce ..."

v3:
  Commit "device core: Introduce multiple dma pfn offsets"
  Commit "arm: dma-mapping: Invoke dma offset func if needed"
  -- The above two commits have been squashed.  More importantly,
 the code has been modified so that the functionality for
 multiple pfn offsets subsumes the use of dev->dma_pfn_offset.
 In fact, dma_pfn_offset is removed and supplanted by
 dma_pfn_offset_map, which is a pointer to an array.  The
 more common case of a uniform offset is now handled as
 a map with a single entry, while cases requiring multiple
 pfn offsets use a map with multiple entries.  Code paths
 that used to do this:

 dev->dma_pfn_offset = mydrivers_pfn_offset;

 have been changed to do this:

 attach_uniform_dma_pfn_offset(dev, pfn_offset);

  Commit "dt-bindings: PCI: Add bindings for more Brcmstb chips"
  -- Add if/then clause for required props: resets, reset-names (RobH)
  -- Change compatible list from const to enum (RobH)
  -- Change list of u32-tuples to u64 (RobH)

  Commit "of: Include a dev param in of_dma_get_range()"
  -- modify of/unittests.c to add NULL param in of_dma_get_range() call.

  Commit "device core: Add ability to handle multiple dma offsets"
  -- align comment in device.h (AndyS).
  -- s/cpu_beg/cpu_start/ and s/dma_beg/dma_start/ in struct
 dma_pfn_offset_region (AndyS).

v2:
Commit: "device core: Add ability to handle multiple dma offsets"
  o Added helper func attach_dma_pfn_offset_map() in address.c (Chistoph)
  o Helpers funcs added to __phys_to_dma() & __dma_to_phys() (Christoph)
  o Added warning when multiple offsets are needed and !DMA_PFN_OFFSET_MAP
  o dev->dma_pfn_map => dev->dma_pfn_offset_map
  o s/frm/from/ for dma_pfn_offset_frm_{phys,dma}_addr() (Christoph)
  o In device.h: s/const void */const struct dma_pfn_offset_region */
  o removed 'unlikely' from unlikely(dev->dma_pfn_offset_map) since
guarded by CONFIG_DMA_PFN_OFFSET_MAP (Christoph)
  o Since dev->dma_pfn_offset is copied in usb/core/{usb,message}.c, now
dev->dma_pfn_offset_map is copied as well.
  o Merged two of the DMA commits into one (Christoph).

Commit "arm: dma-mapping: Invoke dma offset func if needed":
  o Use helper functions instead of #if CONFIG_DMA_PFN_OFFSET

Other commits' changes:
  o Removed need for carrying of_id var in priv (Nicolas)
  o Commit message rewordings (Bjorn)
  o Commit log messages filled to 75 chars (Bjorn)
  o devm_reset_control_get_shared())
=> devm_reset_control_get_optional_shared (Philipp)
  o Add call to reset_control_assert() in PCIe remove routines (Philipp)

v1:
This patchset expands the usefulness of the Broadcom Settop Box PCIe
controller by building upon the PCIe driver used currently by the
Raspbery Pi.  Other forms of this patchset were submitted by me years
ago and not accepted; the major sticking point was the code required
for the DMA remapping needed for the PCIe driver to work [1].

There have been many changes to the DMA and OF subsystems since that
time, making a cleaner and less intrusive patchset possible.  This
patchset implements a generalization of "dev->dma_pfn_offset", except
that instead of a single scalar offset it provides for multiple
offsets via a function which depends upon the "dma-ranges" property of
the PCIe host controller.  This is required for proper functionality
of the BrcmSTB PCIe controller and possibly some other devices.

[1] 
https://lore.kernel.org/linux-arm-kernel/1516058925-46522-5-git-send-email-jim2101...@gmail.com/

Jim Quinlan (12):
  PCI: brcmstb: PCIE_BRCMSTB depends on ARCH_BRCMSTB
  ata: ahci_brcm: Fix use of BCM7216 reset controller
  dt-bindings: PCI: Add bindings for more Brcmstb chips
  PCI: brcmstb: Add bcm7278 register info
  PCI: brcmstb: Add suspend and resume pm_ops
  PCI: brcmstb: Add bcm7278 PERST support
  PCI: brcmstb: Add control of rescal reset
  device core: Introduce

[PATCH v4 08/12] device core: Introduce multiple dma pfn offsets

2020-06-07 Thread Jim Quinlan
The new field in struct device 'dma_pfn_offset_map' is used to facilitate
the use of single or multiple pfn offsets between cpu addrs and dma addrs.
It subsumes the role of dev->dma_pfn_offset -- a uniform offset.

The function of_dma_get_range() has been modified to take two additional
arguments: the "map", which is an array that holds the information
regarding the pfn offset regions, and map_size, which is the size in bytes
of the map array.

of_dma_configure() is the typical manner to set pfn offsets but there are a
number of ad hoc assignments to dev->dma_pfn_offset in the kernel driver
code.  These cases now invoke the function
dma_attach_uniform_pfn_offset(dev, pfn_offset).

Signed-off-by: Jim Quinlan 
---
 arch/arm/include/asm/dma-mapping.h|  9 +--
 arch/arm/mach-keystone/keystone.c |  9 ++-
 arch/sh/drivers/pci/pcie-sh7786.c |  3 +-
 arch/sh/kernel/dma-coherent.c | 14 ++--
 arch/x86/pci/sta2x11-fixup.c  |  7 +-
 drivers/acpi/arm64/iort.c |  5 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c |  5 +-
 drivers/iommu/io-pgtable-arm.c|  2 +-
 .../platform/sunxi/sun4i-csi/sun4i_csi.c  |  5 +-
 .../platform/sunxi/sun6i-csi/sun6i_csi.c  |  4 +-
 drivers/of/address.c  | 72 ---
 drivers/of/device.c   | 19 +++--
 drivers/of/of_private.h   | 11 +--
 drivers/of/unittest.c |  8 ++-
 drivers/remoteproc/remoteproc_core.c  |  2 +-
 .../staging/media/sunxi/cedrus/cedrus_hw.c|  7 +-
 drivers/usb/core/message.c|  4 +-
 drivers/usb/core/usb.c|  2 +-
 include/linux/device.h|  4 +-
 include/linux/dma-direct.h| 16 -
 include/linux/dma-mapping.h   | 38 ++
 kernel/dma/coherent.c | 11 +--
 kernel/dma/mapping.c  | 38 ++
 23 files changed, 235 insertions(+), 60 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h 
b/arch/arm/include/asm/dma-mapping.h
index bdd80ddbca34..f1e72f99468b 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -35,8 +35,9 @@ static inline const struct dma_map_ops 
*get_arch_dma_ops(struct bus_type *bus)
 #ifndef __arch_pfn_to_dma
 static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
 {
-   if (dev)
-   pfn -= dev->dma_pfn_offset;
+   if (dev && dev->dma_pfn_offset_map)
+   pfn -= dma_pfn_offset_from_phys_addr(dev, PFN_PHYS(pfn));
+
return (dma_addr_t)__pfn_to_bus(pfn);
 }
 
@@ -44,8 +45,8 @@ static inline unsigned long dma_to_pfn(struct device *dev, 
dma_addr_t addr)
 {
unsigned long pfn = __bus_to_pfn(addr);
 
-   if (dev)
-   pfn += dev->dma_pfn_offset;
+   if (dev && dev->dma_pfn_offset_map)
+   pfn += dma_pfn_offset_from_dma_addr(dev, addr);
 
return pfn;
 }
diff --git a/arch/arm/mach-keystone/keystone.c 
b/arch/arm/mach-keystone/keystone.c
index 638808c4e122..dfb095b31534 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -8,6 +8,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -38,9 +39,11 @@ static int keystone_platform_notifier(struct notifier_block 
*nb,
return NOTIFY_BAD;
 
if (!dev->of_node) {
-   dev->dma_pfn_offset = keystone_dma_pfn_offset;
-   dev_err(dev, "set dma_pfn_offset%08lx\n",
-   dev->dma_pfn_offset);
+   int ret = dma_attach_uniform_pfn_offset
+   (dev, keystone_dma_pfn_offset);
+
+   dev_err(dev, "set dma_pfn_offset%08lx%s\n",
+   dev->dma_pfn_offset, ret ? " failed" : "");
}
return NOTIFY_OK;
 }
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c 
b/arch/sh/drivers/pci/pcie-sh7786.c
index e0b568aaa701..3e63c6b6e070 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -487,7 +488,7 @@ int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 
slot, u8 pin)
 
 void pcibios_bus_add_device(struct pci_dev *pdev)
 {
-   pdev->dev.dma_pfn_offset = dma_pfn_offset;
+   dma_attach_uniform_pfn_offset(&pdev->dev, dma_pfn_offset);
 }
 
 static int __init sh7786_pcie_core_init(void)
diff --git a/arch/sh/kernel/dma-coherent.c b/arch/sh/kernel/dma-coherent.c
index d4811691b93c..f4a092e74910 100644
--- a/arch/sh/kernel/dma-coherent.c
+++ b/arch/sh/kernel/dma-coherent.c
@@ -14,6 +14,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, 
dma_addr_t *dma_handle,
 {
void *ret, *ret_nocache;
int order = get_order(size);
+   phys_addr_t phys;
 
gfp |= __GFP_Z

Re: [PATCH v3 09/13] device core: Introduce multiple dma pfn offsets

2020-06-07 Thread Jim Quinlan
On Fri, Jun 5, 2020 at 1:27 PM Nicolas Saenz Julienne
 wrote:
>
> Hi Christoph,
> a question arouse, is there a real value to dealing with PFNs (as opposed to
> real addresses) in the core DMA code/structures? I see that in some cases it
> eases interacting with mm, but the overwhelming usage of say,
> dev->dma_pfn_offset, involves shifting it.
>
> Hi Jim,
> On Thu, 2020-06-04 at 14:01 -0400, Jim Quinlan wrote:
> > Hi Nicolas,
>
> [...]
>
> > > I understand the need for dev to be around, devm_*() is key. But also it's
> > > important to keep the functions on purpose. And if of_dma_get_range() 
> > > starts
> > > setting ranges it calls, for the very least, for a function rename. 
> > > Although
> > > I'd rather split the parsing and setting of ranges as mentioned earlier.
> > > That
> > > said, I get that's a more drastic move.
> >
> > I agree with you.  I could do this from device.c:
> >
> > of_dma_get_num_ranges(..., &num_ranges); /* new function */
> > r = devm_kcalloc(dev, num_ranges + 1, sizeof(*r), GFP_KERNEL);
> > of_dma_get_range(np, &dma_addr, &paddr, &size, r, num_ranges);
> >
> > The problem here is that there could be four ranges, all with
> > offset=0.  My current code would optimize this case out but the above
> > would have us holding useless memory and looping through the four
> > ranges on every dma <=> phys conversion only to add 0.
>
> Point taken. Ultimately it's setting the device's dma ranges in
> of_dma_get_range() that was really bothering me, so if we have to pass the
> device pointer for allocations, be it.
>
> > > Talking about drastic moves. How about getting rid of the concept of
> > > dma_pfn_offset for drivers altogether. Let them provide
> > > dma_pfn_offset_regions
> > > (even when there is only one). I feel it's conceptually nicer, as you'd be
> > > dealing only in one currency, so to speak, and you'd centralize the bus 
> > > DMA
> > > ranges setter function which is always easier to maintain.
> > Do you agree that we have to somehow hang this info on the struct
> > device structure?  Because in the dma2phys() and phys2dma() all you
> > have is the dev parameter.  I don't see how this  can be done w/o
> > involving dev.
>
> Sorry I didn't make myself clear here. What bothers me is having two functions
> setting the same device parameter trough different means, I'd be happy to get
> rid of attach_uniform_dma_pfn_offset(), and always use the same function to 
> set
> a device's bus dma regions. Something the likes of this comes to mind:
>
> dma_attach_pfn_offset_region(struct device *dev, struct 
> dma_pfn_offset_regions *r)
>
> We could maybe use some helper macros for the linear case. But that's the gist
> of it.
>
> Also, it goes hand in hand with the comment below. Why having a special case
> for non sparse DMA offsets in struct dma_pfn_offset_regions? The way I see it,
> in this case, code simplicity is more interesting than a small optimization.
I've removed the special case and also need for 'dev' in
of_dma_get_range().  v4 is comming...
>
> > > I'd go as far as not creating a special case for uniform offsets. Let just
> > > set
> > > cpu_end and dma_end to -1 so we always get a match. It's slightly more
> > > compute
> > > heavy, but I don't think it's worth the optimization.
> > Well, there are two subcases here.  One where we do know the bounds
> > and one where we do not.  I suppose for the latter I could have the
> > drivers calling it with begin=0 and end=~(dma_addr_t)0.  Let me give
> > this some thought...
> >
> > > Just my two cents :)
> >
> > Worth much more than $0.02 IMO :-)
>
> BTW, would you consider renaming the DMA offset struct to something simpler
> like, struct bus_dma_region? It complements 'dev->bus_dma_limit' better IMO.
Will do

Thanks,
Jim
>
> > BTW, I tried putting the "if (dev->dma_pfn_offset_map)" clause inside
> > the inline functions but the problem is that it slows the fastpath;
> > consider the following code from dma-direct.h
> >
> > if (dev->dma_pfn_offset_map) {
> > unsigned long dma_pfn_offset =
> dma_pfn_offset_from_phys_addr(dev, paddr);
> >
> > dev_addr -= ((dma_addr_t)dma_pfn_offset << PAGE_SHIFT);
> > }
> > return dev_addr;
> >
> > becomes
> >
> > unsigned long dma_pfn_offset = dma_pfn_offset_from_phys_addr(dev,
> paddr);
> >
> > dev_addr -= ((dma_addr_t)dma_pfn_offset << PAGE_SHIFT);
> > return dev_addr;
> >
> > So those configurations that  have no dma_pfn_offsets are doing an
> > unnecessary shift and add.
>
> Fair enough. Still not a huge difference, but I see the value being the most
> common case.
>
> Regards,
> Nicolas
>
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 3/3] drm/dp_mst: Fix flushing the delayed port/mstb destroy work

2020-06-07 Thread Imre Deak
Atm, a pending delayed destroy work during module removal will be
canceled, leaving behind MST ports, mstbs. Fix this by using a dedicated
workqueue which will be drained of requeued items as well when
destroying it.

Signed-off-by: Imre Deak 
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 17 ++---
 include/drm/drm_dp_mst_helper.h   |  8 
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c 
b/drivers/gpu/drm/drm_dp_mst_topology.c
index 083255c33ee0..075fb5ac9264 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1630,7 +1630,7 @@ static void drm_dp_destroy_mst_branch_device(struct kref 
*kref)
mutex_lock(&mgr->delayed_destroy_lock);
list_add(&mstb->destroy_next, &mgr->destroy_branch_device_list);
mutex_unlock(&mgr->delayed_destroy_lock);
-   schedule_work(&mgr->delayed_destroy_work);
+   queue_work(mgr->delayed_destroy_wq, &mgr->delayed_destroy_work);
 }
 
 /**
@@ -1747,7 +1747,7 @@ static void drm_dp_destroy_port(struct kref *kref)
mutex_lock(&mgr->delayed_destroy_lock);
list_add(&port->next, &mgr->destroy_port_list);
mutex_unlock(&mgr->delayed_destroy_lock);
-   schedule_work(&mgr->delayed_destroy_work);
+   queue_work(mgr->delayed_destroy_wq, &mgr->delayed_destroy_work);
 }
 
 /**
@@ -5208,6 +5208,15 @@ int drm_dp_mst_topology_mgr_init(struct 
drm_dp_mst_topology_mgr *mgr,
INIT_LIST_HEAD(&mgr->destroy_port_list);
INIT_LIST_HEAD(&mgr->destroy_branch_device_list);
INIT_LIST_HEAD(&mgr->up_req_list);
+
+   /*
+* delayed_destroy_work will be queued on a dedicated WQ, so that any
+* requeuing will be also flushed when deiniting the topology manager.
+*/
+   mgr->delayed_destroy_wq = alloc_ordered_workqueue("drm_dp_mst_wq", 0);
+   if (mgr->delayed_destroy_wq == NULL)
+   return -ENOMEM;
+
INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work);
INIT_WORK(&mgr->tx_work, drm_dp_tx_work);
INIT_WORK(&mgr->delayed_destroy_work, drm_dp_delayed_destroy_work);
@@ -5252,7 +5261,9 @@ void drm_dp_mst_topology_mgr_destroy(struct 
drm_dp_mst_topology_mgr *mgr)
 {
drm_dp_mst_topology_mgr_set_mst(mgr, false);
flush_work(&mgr->work);
-   cancel_work_sync(&mgr->delayed_destroy_work);
+   /* The following will also drain any requeued work on the WQ. */
+   destroy_workqueue(mgr->delayed_destroy_wq);
+   mgr->delayed_destroy_wq = NULL;
mutex_lock(&mgr->payload_lock);
kfree(mgr->payloads);
mgr->payloads = NULL;
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index b230ff6f7081..8b9eb4db3381 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -681,6 +681,14 @@ struct drm_dp_mst_topology_mgr {
 * @destroy_branch_device_list.
 */
struct mutex delayed_destroy_lock;
+
+   /**
+* @delayed_destroy_wq: Workqueue used for delayed_destroy_work items.
+* A dedicated WQ makes it possible to drain any requeued work items
+* on it.
+*/
+   struct workqueue_struct *delayed_destroy_wq;
+
/**
 * @delayed_destroy_work: Work item to destroy MST port and branch
 * devices, needed to avoid locking inversion.
-- 
2.23.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 1/3] drm/dp_mst: Fix the DDC I2C device unregistration of an MST port

2020-06-07 Thread Imre Deak
The WARN below triggers during the removal of an MST port. The problem
is that the parent device's (the connector's kdev) sysfs directory is
removed recursively when the connector is unregistered (even though the
I2C device holds a reference on the parent device). To fix this set
first the Peer Device Type to none which will remove the I2C device.

Note that atm, inconsistently, the parent of the I2C device is initially set to
the DRM kdev and after a Connection Status Notification the parent may be reset
to be the connector's kdev. This problem is addressed by the next patch.

[ 4462.989299] [ cut here ]
[ 4463.014940] sysfs group 'power' not found for kobject 'i2c-24'
[ 4463.034664] WARNING: CPU: 0 PID: 970 at fs/sysfs/group.c:281 
sysfs_remove_group+0x71/0x80
[ 4463.044357] Modules linked in: snd_hda_intel i915 drm_kms_helper(O) drm 
netconsole snd_hda_codec_hdmi mei_hdcp x86_pkg_temp_thermal coretemp 
crct10dif_pclmul snd_intel_dspcf
g crc32_pclmul snd_hda_codec snd_hwdep ghash_clmulni_intel snd_hda_core asix 
usbnet kvm_intel mii i2c_algo_bit snd_pcm syscopyarea sysfillrect e1000e 
sysimgblt fb_sys_fops prim
e_numbers ptp pps_core i2c_i801 r8169 mei_me realtek mei [last unloaded: drm]
[ 4463.044399] CPU: 0 PID: 970 Comm: kworker/0:2 Tainted: G   O  
5.7.0+ #172
[ 4463.044402] Hardware name: Intel Corporation Tiger Lake Client 
Platform/TigerLake U DDR4 SODIMM RVP
[ 4463.044423] Workqueue: events drm_dp_delayed_destroy_work [drm_kms_helper]
[ 4463.044428] RIP: 0010:sysfs_remove_group+0x71/0x80
[ 4463.044431] Code: 48 89 df 5b 5d 41 5c e9 cd b6 ff ff 48 89 df e8 95 b4 ff 
ff eb cb 49 8b 14 24 48 8b 75 00 48 c7 c7 20 0f 3f 82 e8 9f c5 d7 ff <0f> 0b 5b 
5d 41 5c c3 0f 1f
84 00 00 00 00 00 48 85 f6 74 31 41 54
[ 4463.044433] RSP: 0018:c900018bfbf0 EFLAGS: 00010282
[ 4463.044436] RAX:  RBX:  RCX: 0001
[ 4463.044439] RDX: 8001 RSI: 88849e828f38 RDI: 
[ 4463.052970] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:100:plane 
2B] c2160caa state to d172564a
[ 4463.070533] RBP: 820cea20 R08: 88847f4b8958 R09: 
[ 4463.070535] R10:  R11:  R12: 88848a725018
[ 4463.070537] R13:  R14: 827090e0 R15: 0002
[ 4463.070539] FS:  () GS:88849e80() 
knlGS:
[ 4463.070541] CS:  0010 DS:  ES:  CR0: 80050033
[ 4463.070543] CR2: 7fdf8a756538 CR3: 000489684001 CR4: 00760ef0
[ 4463.070545] DR0:  DR1:  DR2: 
[ 4463.070547] DR3:  DR6: fffe0ff0 DR7: 0400
[ 4463.070549] PKRU: 5554
[ 4463.070551] Call Trace:
[ 4463.070560]  device_del+0x84/0x400
[ 4463.070571]  cdev_device_del+0x10/0x30
[ 4463.070578]  put_i2c_dev+0x69/0x80
[ 4463.070584]  i2cdev_detach_adapter+0x2e/0x60
[ 4463.070591]  notifier_call_chain+0x34/0x90
[ 4463.070599]  blocking_notifier_call_chain+0x3f/0x60
[ 4463.070606]  device_del+0x7c/0x400
[ 4463.087817]  ? lockdep_init_map_waits+0x57/0x210
[ 4463.087825]  device_unregister+0x11/0x60
[ 4463.087829]  i2c_del_adapter+0x249/0x310
[ 4463.087846]  drm_dp_port_set_pdt+0x6b/0x2c0 [drm_kms_helper]
[ 4463.087862]  drm_dp_delayed_destroy_work+0x2af/0x350 [drm_kms_helper]
[ 4463.087876]  process_one_work+0x268/0x600
[ 4463.105438]  ? __schedule+0x30c/0x920
[ 4463.105451]  worker_thread+0x37/0x380
[ 4463.105457]  ? process_one_work+0x600/0x600
[ 4463.105462]  kthread+0x140/0x160
[ 4463.105466]  ? kthread_park+0x80/0x80
[ 4463.105474]  ret_from_fork+0x24/0x50

Cc: 
Signed-off-by: Imre Deak 
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c 
b/drivers/gpu/drm/drm_dp_mst_topology.c
index 2a309fb2c4cc..02c800b8199f 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -4669,12 +4669,13 @@ static void drm_dp_tx_work(struct work_struct *work)
 static inline void
 drm_dp_delayed_destroy_port(struct drm_dp_mst_port *port)
 {
+   drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
+
if (port->connector) {
drm_connector_unregister(port->connector);
drm_connector_put(port->connector);
}
 
-   drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
drm_dp_mst_put_port_malloc(port);
 }
 
-- 
2.23.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/3] drm/dp_mst: Fix the DDC I2C device registration of an MST port

2020-06-07 Thread Imre Deak
During the initial MST probing an MST port's I2C device will be
registered using the kdev of the DRM device as a parent. Later after MST
Connection Status Notifications this I2C device will be re-registered
with the kdev of the port's connector. This will also move
inconsistently the I2C device's sysfs entry from the DRM device's sysfs
dir to the connector's dir.

Fix the above by keeping the DRM kdev as the parent of the I2C device.

Ideally the connector's kdev would be used as a parent, similarly to
non-MST connectors, however that needs some more refactoring to ensure
the connector's kdev is already available early enough. So keep the
existing (initial) behavior for now.

Cc: 
Signed-off-by: Imre Deak 
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 28 +++
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c 
b/drivers/gpu/drm/drm_dp_mst_topology.c
index 02c800b8199f..083255c33ee0 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -88,8 +88,8 @@ static int drm_dp_send_enum_path_resources(struct 
drm_dp_mst_topology_mgr *mgr,
 static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
 u8 *guid);
 
-static int drm_dp_mst_register_i2c_bus(struct drm_dp_aux *aux);
-static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux);
+static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port);
+static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port);
 static void drm_dp_mst_kick_tx(struct drm_dp_mst_topology_mgr *mgr);
 
 #define DBG_PREFIX "[dp_mst]"
@@ -1993,7 +1993,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 
new_pdt,
}
 
/* remove i2c over sideband */
-   drm_dp_mst_unregister_i2c_bus(&port->aux);
+   drm_dp_mst_unregister_i2c_bus(port);
} else {
mutex_lock(&mgr->lock);
drm_dp_mst_topology_put_mstb(port->mstb);
@@ -2008,7 +2008,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 
new_pdt,
if (port->pdt != DP_PEER_DEVICE_NONE) {
if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
/* add i2c over sideband */
-   ret = drm_dp_mst_register_i2c_bus(&port->aux);
+   ret = drm_dp_mst_register_i2c_bus(port);
} else {
lct = drm_dp_calculate_rad(port, rad);
mstb = drm_dp_add_mst_branch_device(lct, rad);
@@ -5375,22 +5375,26 @@ static const struct i2c_algorithm drm_dp_mst_i2c_algo = 
{
 
 /**
  * drm_dp_mst_register_i2c_bus() - register an I2C adapter for I2C-over-AUX
- * @aux: DisplayPort AUX channel
+ * @port: The port to add the I2C bus on
  *
  * Returns 0 on success or a negative error code on failure.
  */
-static int drm_dp_mst_register_i2c_bus(struct drm_dp_aux *aux)
+static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port)
 {
+   struct drm_dp_aux *aux = &port->aux;
+   struct device *parent_dev = port->mgr->dev->dev;
+
aux->ddc.algo = &drm_dp_mst_i2c_algo;
aux->ddc.algo_data = aux;
aux->ddc.retries = 3;
 
aux->ddc.class = I2C_CLASS_DDC;
aux->ddc.owner = THIS_MODULE;
-   aux->ddc.dev.parent = aux->dev;
-   aux->ddc.dev.of_node = aux->dev->of_node;
+   /* FIXME: set the kdev of the port's connector as parent */
+   aux->ddc.dev.parent = parent_dev;
+   aux->ddc.dev.of_node = parent_dev->of_node;
 
-   strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
+   strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(parent_dev),
sizeof(aux->ddc.name));
 
return i2c_add_adapter(&aux->ddc);
@@ -5398,11 +5402,11 @@ static int drm_dp_mst_register_i2c_bus(struct 
drm_dp_aux *aux)
 
 /**
  * drm_dp_mst_unregister_i2c_bus() - unregister an I2C-over-AUX adapter
- * @aux: DisplayPort AUX channel
+ * @port: The port to remove the I2C bus from
  */
-static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux)
+static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port)
 {
-   i2c_del_adapter(&aux->ddc);
+   i2c_del_adapter(&port->aux.ddc);
 }
 
 /**
-- 
2.23.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 0/2] drm: rockchip: add NV15 and NV20 support

2020-06-07 Thread Jonas Karlman
Hi,

This series adds support for displaying 10-bit 4:2:0 and 4:2:2 formats produced
by the Rockchip Video Decoder on RK322X, RK3288, RK3328, RK3368 and RK3399.

First patch adds a new fourcc 10-bit YUV format with 4:2:2 sub-sampling.
Second patch adds support for using the the two new fourcc formats.
Both depend on "drm: drm_fourcc: add NV15, Q410, Q401 YUV formats" at [1].

This series can also be found at [2], and can be tested on RK3399 using an
upcoming rkvdec series at [3] together with ffmpeg at [4] and kodi-gbm or mpv.

[1] https://patchwork.freedesktop.org/series/76326/
[2] https://github.com/Kwiboo/linux-rockchip/commits/next-20200605-fmt_10
[3] https://github.com/Kwiboo/linux-rockchip/commits/next-20200605-rkvdec
[4] https://github.com/Kwiboo/FFmpeg/commits/v4l2-request-hwaccel-4.2.2-rkvdec

Regards,
Jonas

Jonas Karlman (2):
  drm: drm_fourcc: add NV20 YUV format
  drm: rockchip: add NV15 and NV20 support

 drivers/gpu/drm/drm_fourcc.c|  4 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 27 --
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  1 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 31 +
 include/uapi/drm/drm_fourcc.h   |  1 +
 5 files changed, 56 insertions(+), 8 deletions(-)

-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH 2/2] drm: rockchip: add NV15 and NV20 support

2020-06-07 Thread Jonas Karlman
Add support for displaying 10-bit 4:2:0 and 4:2:2 formats produced by the
Rockchip Video Decoder on RK322X, RK3288, RK3328, RK3368 and RK3399.

Signed-off-by: Jonas Karlman 
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 27 --
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  1 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 31 +
 3 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 33463b79a37b..13a0682d438b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -261,6 +261,17 @@ static bool has_rb_swapped(uint32_t format)
}
 }
 
+static bool is_fmt_10(uint32_t format)
+{
+   switch (format) {
+   case DRM_FORMAT_NV15:
+   case DRM_FORMAT_NV20:
+   return true;
+   default:
+   return false;
+   }
+}
+
 static enum vop_data_format vop_convert_format(uint32_t format)
 {
switch (format) {
@@ -276,8 +287,10 @@ static enum vop_data_format vop_convert_format(uint32_t 
format)
case DRM_FORMAT_BGR565:
return VOP_FMT_RGB565;
case DRM_FORMAT_NV12:
+   case DRM_FORMAT_NV15:
return VOP_FMT_YUV420SP;
case DRM_FORMAT_NV16:
+   case DRM_FORMAT_NV20:
return VOP_FMT_YUV422SP;
case DRM_FORMAT_NV24:
return VOP_FMT_YUV444SP;
@@ -922,7 +935,12 @@ static void vop_plane_atomic_update(struct drm_plane 
*plane,
dsp_sty = dest->y1 + crtc->mode.vtotal - crtc->mode.vsync_start;
dsp_st = dsp_sty << 16 | (dsp_stx & 0x);
 
-   offset = (src->x1 >> 16) * fb->format->cpp[0];
+   if (fb->format->block_w[0])
+   offset = (src->x1 >> 16) * fb->format->char_per_block[0] /
+fb->format->block_w[0];
+   else
+   offset = (src->x1 >> 16) * fb->format->cpp[0];
+
offset += (src->y1 >> 16) * fb->pitches[0];
dma_addr = rk_obj->dma_addr + offset + fb->offsets[0];
 
@@ -948,6 +966,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
}
 
VOP_WIN_SET(vop, win, format, format);
+   VOP_WIN_SET(vop, win, fmt_10, is_fmt_10(fb->format->format));
VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv);
@@ -964,7 +983,11 @@ static void vop_plane_atomic_update(struct drm_plane 
*plane,
uv_obj = fb->obj[1];
rk_uv_obj = to_rockchip_obj(uv_obj);
 
-   offset = (src->x1 >> 16) * bpp / hsub;
+   if (fb->format->block_w[1])
+   offset = (src->x1 >> 16) * bpp /
+fb->format->block_w[1] / hsub;
+   else
+   offset = (src->x1 >> 16) * bpp / hsub;
offset += (src->y1 >> 16) * fb->pitches[1] / vsub;
 
dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index d03bdb531ef2..db1138da2bd4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -154,6 +154,7 @@ struct vop_win_phy {
struct vop_reg enable;
struct vop_reg gate;
struct vop_reg format;
+   struct vop_reg fmt_10;
struct vop_reg rb_swap;
struct vop_reg act_info;
struct vop_reg dsp_info;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c 
b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 2413deded22c..503736c8b6c4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -50,6 +50,22 @@ static const uint32_t formats_win_full[] = {
DRM_FORMAT_NV24,
 };
 
+static const uint32_t formats_win_full_10[] = {
+   DRM_FORMAT_XRGB,
+   DRM_FORMAT_ARGB,
+   DRM_FORMAT_XBGR,
+   DRM_FORMAT_ABGR,
+   DRM_FORMAT_RGB888,
+   DRM_FORMAT_BGR888,
+   DRM_FORMAT_RGB565,
+   DRM_FORMAT_BGR565,
+   DRM_FORMAT_NV12,
+   DRM_FORMAT_NV16,
+   DRM_FORMAT_NV24,
+   DRM_FORMAT_NV15,
+   DRM_FORMAT_NV20,
+};
+
 static const uint64_t format_modifiers_win_full[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID,
@@ -570,11 +586,12 @@ static const struct vop_scl_regs rk3288_win_full_scl = {
 
 static const struct vop_win_phy rk3288_win01_data = {
.scl = &rk3288_win_full_scl,
-   .data_formats = formats_win_full,
-   .nformats = ARRAY_SIZE(formats_win_full),
+   .data_formats = formats_win_full_10,
+   .nformats = ARRAY_SIZE(formats_win_full_10),
.format_modifiers = format_modifiers_win_full,
.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
.format = VOP_REG(RK3

[PATCH 1/2] drm: drm_fourcc: add NV20 YUV format

2020-06-07 Thread Jonas Karlman
DRM_FORMAT_NV20 is a 2 plane format suitable for linear memory layout.
The format is similar to P210 with 4:2:2 sub-sampling but has no padding
between components. Instead, luminance and chrominance samples are grouped
into 4s so that each group is packed into an integer number of bytes:

 = UVUV = 4 * 10 bits = 40 bits = 5 bytes

The '20' suffix refers to the optimum effective bits per pixel which is
achieved when the total number of luminance samples is a multiple of 4.

Signed-off-by: Jonas Karlman 
---
 drivers/gpu/drm/drm_fourcc.c  | 4 
 include/uapi/drm/drm_fourcc.h | 1 +
 2 files changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 722c7ebe4e88..2a9c8ae719ed 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -278,6 +278,10 @@ const struct drm_format_info *__drm_format_info(u32 format)
  .num_planes = 2, .char_per_block = { 5, 5, 0 },
  .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
  .vsub = 2, .is_yuv = true },
+   { .format = DRM_FORMAT_NV20,.depth = 0,
+ .num_planes = 2, .char_per_block = { 5, 5, 0 },
+ .block_w = { 4, 2, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2,
+ .vsub = 1, .is_yuv = true },
{ .format = DRM_FORMAT_Q410,.depth = 0,
  .num_planes = 3, .char_per_block = { 2, 2, 2 },
  .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index b5bf1c0e630e..244d32433a67 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -242,6 +242,7 @@ extern "C" {
  * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian
  */
 #define DRM_FORMAT_NV15fourcc_code('N', 'V', '1', '5') /* 2x2 
subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV20fourcc_code('N', 'V', '2', '0') /* 2x1 
subsampled Cr:Cb plane */
 
 /*
  * 2 plane YCbCr MSB aligned
-- 
2.17.1

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 27/39] interconnect: Relax requirement in of_icc_get_from_provider()

2020-06-07 Thread Dmitry Osipenko
From: Artur Świgoń 

This patch relaxes the condition in of_icc_get_from_provider() so that it
is no longer required to set #interconnect-cells = <1> in the DT. In case
of the devfreq driver for exynos-bus, #interconnect-cells is always zero.

Signed-off-by: Artur Świgoń 
[dig...@gmail.com: added cells_num checking for of_icc_xlate_onecell()]
Signed-off-by: Dmitry Osipenko 
---
 drivers/interconnect/core.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index e5f998744501..cb143421ca67 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -339,7 +339,7 @@ static struct icc_node *of_icc_get_from_provider(struct 
of_phandle_args *spec)
struct icc_node *node = ERR_PTR(-EPROBE_DEFER);
struct icc_provider *provider;
 
-   if (!spec || spec->args_count != 1)
+   if (!spec)
return ERR_PTR(-EINVAL);
 
mutex_lock(&icc_lock);
@@ -967,6 +967,15 @@ EXPORT_SYMBOL_GPL(icc_nodes_remove);
  */
 int icc_provider_add(struct icc_provider *provider)
 {
+   struct device_node *np = provider->dev->of_node;
+   u32 cells_num;
+   int err;
+
+   err = of_property_read_u32(np, "#interconnect-cells", &cells_num);
+   if (WARN_ON(err))
+   return err;
+   if (WARN_ON(provider->xlate == of_icc_xlate_onecell && cells_num != 1))
+   return -EINVAL;
if (WARN_ON(!provider->set))
return -EINVAL;
if (WARN_ON(!provider->xlate))
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH] drm/panfrost: Use kvfree() to free bo->sgts in panfrost_mmu_map_fault_addr()

2020-06-07 Thread Denis Efremov
Use kvfree() to free bo->sgts, because the memory is allocated with
kvmalloc_array().

Fixes: 187d2929206e ("drm/panfrost: Add support for GPU heap allocations")
Cc: sta...@vger.kernel.org
Signed-off-by: Denis Efremov 
---
 drivers/gpu/drm/panfrost/panfrost_mmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c 
b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index ed28aeba6d59..3c8ae7411c80 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -486,7 +486,7 @@ static int panfrost_mmu_map_fault_addr(struct 
panfrost_device *pfdev, int as,
pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
   sizeof(struct page *), GFP_KERNEL | 
__GFP_ZERO);
if (!pages) {
-   kfree(bo->sgts);
+   kvfree(bo->sgts);
bo->sgts = NULL;
mutex_unlock(&bo->base.pages_lock);
ret = -ENOMEM;
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 10/39] PM / devfreq: tegra20: Silence deferred probe error

2020-06-07 Thread Dmitry Osipenko
Tegra EMC driver was turned into a regular kernel driver, it also could
be compiled as a loadable kernel module now. Hence EMC clock isn't
guaranteed to be available and clk_get("emc") may return -EPROBE_DEFER and
there is no good reason to spam KMSG with a error about missing EMC clock
in this case, so let's silence the deferred probe error.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra20-devfreq.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/devfreq/tegra20-devfreq.c 
b/drivers/devfreq/tegra20-devfreq.c
index ff82bac9ee4e..6469dc69c5e0 100644
--- a/drivers/devfreq/tegra20-devfreq.c
+++ b/drivers/devfreq/tegra20-devfreq.c
@@ -141,9 +141,11 @@ static int tegra_devfreq_probe(struct platform_device 
*pdev)
 
/* EMC is a system-critical clock that is always enabled */
tegra->emc_clock = devm_clk_get(&pdev->dev, "emc");
-   if (IS_ERR(tegra->emc_clock)) {
-   err = PTR_ERR(tegra->emc_clock);
-   dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
+   err = PTR_ERR_OR_ZERO(tegra->emc_clock);
+   if (err) {
+   if (err != -EPROBE_DEFER)
+   dev_err(&pdev->dev, "failed to get emc clock: %d\n",
+   err);
return err;
}
 
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 26/39] ARM: tegra: Add interconnect properties to Tegra30 device-tree

2020-06-07 Thread Dmitry Osipenko
Add interconnect properties to the memory controller, external memory
controller and the display controller nodes in order to describe hardware
interconnection.

Signed-off-by: Dmitry Osipenko 
---
 arch/arm/boot/dts/tegra30.dtsi | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index d2d05f1da274..2b183025629f 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -208,6 +208,15 @@ dc@5420 {
 
nvidia,head = <0>;
 
+   interconnects = <&mc TEGRA30_MC_DISPLAY0A &emc>,
+   <&mc TEGRA30_MC_DISPLAY0B &emc>,
+   <&mc TEGRA30_MC_DISPLAY0C &emc>,
+   <&mc TEGRA30_MC_DISPLAY1B &emc>;
+   interconnect-names = "display0a",
+"display0b",
+"display0c",
+"display1b";
+
rgb {
status = "disabled";
};
@@ -227,6 +236,15 @@ dc@5424 {
 
nvidia,head = <1>;
 
+   interconnects = <&mc TEGRA30_MC_DISPLAY0AB &emc>,
+   <&mc TEGRA30_MC_DISPLAY0BB &emc>,
+   <&mc TEGRA30_MC_DISPLAY0CB &emc>,
+   <&mc TEGRA30_MC_DISPLAY1BB &emc>;
+   interconnect-names = "display0a",
+"display0b",
+"display0c",
+"display1b";
+
rgb {
status = "disabled";
};
@@ -733,15 +751,18 @@ mc: memory-controller@7000f000 {
 
#iommu-cells = <1>;
#reset-cells = <1>;
+   #interconnect-cells = <1>;
};
 
-   memory-controller@7000f400 {
+   emc: memory-controller@7000f400 {
compatible = "nvidia,tegra30-emc";
reg = <0x7000f400 0x400>;
interrupts = ;
clocks = <&tegra_car TEGRA30_CLK_EMC>;
 
nvidia,memory-controller = <&mc>;
+
+   #interconnect-cells = <0>;
};
 
fuse@7000f800 {
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 04/39] memory: tegra20-emc: Make driver modular

2020-06-07 Thread Dmitry Osipenko
This patch adds modularization support to the Tegra20 EMC driver. Driver
now can be compiled as a loadable kernel module.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/Kconfig   |  2 +-
 drivers/memory/tegra/tegra20-emc.c | 16 +++-
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig
index 9f0a96bf9ccc..7e0e1ef87763 100644
--- a/drivers/memory/tegra/Kconfig
+++ b/drivers/memory/tegra/Kconfig
@@ -8,7 +8,7 @@ config TEGRA_MC
  NVIDIA Tegra SoCs.
 
 config TEGRA20_EMC
-   bool "NVIDIA Tegra20 External Memory Controller driver"
+   tristate "NVIDIA Tegra20 External Memory Controller driver"
default y
depends on ARCH_TEGRA_2x_SOC
help
diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index 027f46287dbf..035d9251e28a 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -724,6 +724,13 @@ static int tegra_emc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, emc);
tegra_emc_debugfs_init(emc);
 
+   /*
+* Don't allow the kernel module to be unloaded. Unloading adds some
+* extra complexity which doesn't really worth the effort in a case of
+* this driver.
+*/
+   try_module_get(THIS_MODULE);
+
return 0;
 
 unset_cb:
@@ -736,6 +743,7 @@ static const struct of_device_id tegra_emc_of_match[] = {
{ .compatible = "nvidia,tegra20-emc", },
{},
 };
+MODULE_DEVICE_TABLE(of, tegra_emc_of_match);
 
 static struct platform_driver tegra_emc_driver = {
.probe = tegra_emc_probe,
@@ -745,9 +753,7 @@ static struct platform_driver tegra_emc_driver = {
.suppress_bind_attrs = true,
},
 };
+module_platform_driver(tegra_emc_driver);
 
-static int __init tegra_emc_init(void)
-{
-   return platform_driver_register(&tegra_emc_driver);
-}
-subsys_initcall(tegra_emc_init);
+MODULE_DESCRIPTION("NVIDIA Tegra20 EMC driver");
+MODULE_LICENSE("GPL v2");
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 24/39] dt-bindings: memory: tegra30: Add memory client IDs

2020-06-07 Thread Dmitry Osipenko
Each memory client have a unique hardware ID, this patch adds these IDs.

Signed-off-by: Dmitry Osipenko 
---
 include/dt-bindings/memory/tegra30-mc.h | 67 +
 1 file changed, 67 insertions(+)

diff --git a/include/dt-bindings/memory/tegra30-mc.h 
b/include/dt-bindings/memory/tegra30-mc.h
index 169f005fbc78..930f708aca17 100644
--- a/include/dt-bindings/memory/tegra30-mc.h
+++ b/include/dt-bindings/memory/tegra30-mc.h
@@ -41,4 +41,71 @@
 #define TEGRA30_MC_RESET_VDE   16
 #define TEGRA30_MC_RESET_VI17
 
+#define TEGRA30_MC_PTCR0
+#define TEGRA30_MC_DISPLAY0A   1
+#define TEGRA30_MC_DISPLAY0AB  2
+#define TEGRA30_MC_DISPLAY0B   3
+#define TEGRA30_MC_DISPLAY0BB  4
+#define TEGRA30_MC_DISPLAY0C   5
+#define TEGRA30_MC_DISPLAY0CB  6
+#define TEGRA30_MC_DISPLAY1B   7
+#define TEGRA30_MC_DISPLAY1BB  8
+#define TEGRA30_MC_EPPUP   9
+#define TEGRA30_MC_G2PR10
+#define TEGRA30_MC_G2SR11
+#define TEGRA30_MC_MPEUNIFBR   12
+#define TEGRA30_MC_VIRUV   13
+#define TEGRA30_MC_AFIR14
+#define TEGRA30_MC_AVPCARM7R   15
+#define TEGRA30_MC_DISPLAYHC   16
+#define TEGRA30_MC_DISPLAYHCB  17
+#define TEGRA30_MC_FDCDRD  18
+#define TEGRA30_MC_FDCDRD2 19
+#define TEGRA30_MC_G2DR20
+#define TEGRA30_MC_HDAR21
+#define TEGRA30_MC_HOST1XDMAR  22
+#define TEGRA30_MC_HOST1XR 23
+#define TEGRA30_MC_IDXSRD  24
+#define TEGRA30_MC_IDXSRD2 25
+#define TEGRA30_MC_MPE_IPRED   26
+#define TEGRA30_MC_MPEAMEMRD   27
+#define TEGRA30_MC_MPECSRD 28
+#define TEGRA30_MC_PPCSAHBDMAR 29
+#define TEGRA30_MC_PPCSAHBSLVR 30
+#define TEGRA30_MC_SATAR   31
+#define TEGRA30_MC_TEXSRD  32
+#define TEGRA30_MC_TEXSRD2 33
+#define TEGRA30_MC_VDEBSEVR34
+#define TEGRA30_MC_VDEMBER 35
+#define TEGRA30_MC_VDEMCER 36
+#define TEGRA30_MC_VDETPER 37
+#define TEGRA30_MC_MPCORELPR   38
+#define TEGRA30_MC_MPCORER 39
+#define TEGRA30_MC_EPPU40
+#define TEGRA30_MC_EPPV41
+#define TEGRA30_MC_EPPY42
+#define TEGRA30_MC_MPEUNIFBW   43
+#define TEGRA30_MC_VIWSB   44
+#define TEGRA30_MC_VIWU45
+#define TEGRA30_MC_VIWV46
+#define TEGRA30_MC_VIWY47
+#define TEGRA30_MC_G2DW48
+#define TEGRA30_MC_AFIW49
+#define TEGRA30_MC_AVPCARM7W   50
+#define TEGRA30_MC_FDCDWR  51
+#define TEGRA30_MC_FDCDWR2 52
+#define TEGRA30_MC_HDAW53
+#define TEGRA30_MC_HOST1XW 54
+#define TEGRA30_MC_ISPW55
+#define TEGRA30_MC_MPCORELPW   56
+#define TEGRA30_MC_MPCOREW 57
+#define TEGRA30_MC_MPECSWR 58
+#define TEGRA30_MC_PPCSAHBDMAW 59
+#define TEGRA30_MC_PPCSAHBSLVW 60
+#define TEGRA30_MC_SATAW   61
+#define TEGRA30_MC_VDEBSEVW62
+#define TEGRA30_MC_VDEDBGW 63
+#define TEGRA30_MC_VDEMBEW 64
+#define TEGRA30_MC_VDETPMW 65
+
 #endif
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 12/39] PM / devfreq: tegra20: Use MC timings for building OPP table

2020-06-07 Thread Dmitry Osipenko
The clk_round_rate() won't be usable for building OPP table once
interconnect support will be added to the EMC driver because that CLK API
function limits the rounded rate based on the clk rate that is imposed by
active clk-users, and thus, the rounding won't work as expected if
interconnect will set the minimum EMC clock rate before devfreq driver is
loaded. The struct tegra_mc contains memory timings which could be used by
the devfreq driver for building up OPP table instead of rounding clock
rate, this patch implements this idea.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra20-devfreq.c | 18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/devfreq/tegra20-devfreq.c 
b/drivers/devfreq/tegra20-devfreq.c
index 6469dc69c5e0..bf504ca4dea2 100644
--- a/drivers/devfreq/tegra20-devfreq.c
+++ b/drivers/devfreq/tegra20-devfreq.c
@@ -123,8 +123,7 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
 {
struct tegra_devfreq *tegra;
struct tegra_mc *mc;
-   unsigned long max_rate;
-   unsigned long rate;
+   unsigned int i;
int err;
 
mc = tegra_get_memory_controller();
@@ -151,12 +150,17 @@ static int tegra_devfreq_probe(struct platform_device 
*pdev)
 
tegra->regs = mc->regs;
 
-   max_rate = clk_round_rate(tegra->emc_clock, ULONG_MAX);
-
-   for (rate = 0; rate <= max_rate; rate++) {
-   rate = clk_round_rate(tegra->emc_clock, rate);
+   if (!mc->num_timings) {
+   err = dev_pm_opp_add(&pdev->dev,
+clk_get_rate(tegra->emc_clock), 0);
+   if (err) {
+   dev_err(&pdev->dev, "failed to add OPP: %d\n", err);
+   return err;
+   }
+   }
 
-   err = dev_pm_opp_add(&pdev->dev, rate, 0);
+   for (i = 0; i < mc->num_timings; i++) {
+   err = dev_pm_opp_add(&pdev->dev, mc->timings[i].rate, 0);
if (err) {
dev_err(&pdev->dev, "failed to add opp: %d\n", err);
goto remove_opps;
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v3 004/105] clk: bcm: Add BCM2711 DVP driver

2020-06-07 Thread Nicolas Saenz Julienne
On Fri, 2020-06-05 at 19:43 +0200, Maxime Ripard wrote:
> Hi Nicolas,
> 
> On Thu, Jun 04, 2020 at 07:26:07PM +0200, Nicolas Saenz Julienne wrote:
> > On Wed, 2020-05-27 at 17:47 +0200, Maxime Ripard wrote:
> > > The HDMI block has a block that controls clocks and reset signals to the
> > > HDMI0 and HDMI1 controllers.
> > 
> > Why not having two separate drivers?
> 
> They share the same address space, so it wouldn't really make sense to
> split it into two drivers and an MFD, especially when the clock/reset
> association is fairly common.

Fair enough.

> 
> > > Let's expose that through a clock driver implementing a clock and reset
> > > provider.
> > > 
> > > Cc: Michael Turquette 
> > > Cc: Stephen Boyd 
> > > Cc: Rob Herring 
> > > Cc: linux-...@vger.kernel.org
> > > Cc: devicet...@vger.kernel.org
> > > Reviewed-by: Stephen Boyd 
> > > Signed-off-by: Maxime Ripard 
> > > ---
> > >  drivers/clk/bcm/Kconfig   |  11 +++-
> > >  drivers/clk/bcm/Makefile  |   1 +-
> > >  drivers/clk/bcm/clk-bcm2711-dvp.c | 127 +++-
> > >  3 files changed, 139 insertions(+)
> > >  create mode 100644 drivers/clk/bcm/clk-bcm2711-dvp.c
> > > 
> > > diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
> > > index 8c83977a7dc4..784f12c72365 100644
> > > --- a/drivers/clk/bcm/Kconfig
> > > +++ b/drivers/clk/bcm/Kconfig
> > > @@ -1,4 +1,15 @@
> > >  # SPDX-License-Identifier: GPL-2.0-only
> > > +
> > > +config CLK_BCM2711_DVP
> > > + tristate "Broadcom BCM2711 DVP support"
> > > + depends on ARCH_BCM2835 ||COMPILE_TEST
> > > + depends on COMMON_CLK
> > > + default ARCH_BCM2835
> > > + select RESET_SIMPLE
> > > + help
> > > +   Enable common clock framework support for the Broadcom BCM2711
> > > +   DVP Controller.
> > > +
> > >  config CLK_BCM2835
> > >   bool "Broadcom BCM2835 clock support"
> > >   depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
> > > diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
> > > index 0070ddf6cdd2..2c1349062147 100644
> > > --- a/drivers/clk/bcm/Makefile
> > > +++ b/drivers/clk/bcm/Makefile
> > > @@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA)+= clk-kona-setup.o
> > >  obj-$(CONFIG_CLK_BCM_KONA)   += clk-bcm281xx.o
> > >  obj-$(CONFIG_CLK_BCM_KONA)   += clk-bcm21664.o
> > >  obj-$(CONFIG_COMMON_CLK_IPROC)   += clk-iproc-armpll.o clk-iproc-pll.o
> > > clk-iproc-asiu.o
> > > +obj-$(CONFIG_CLK_BCM2835)+= clk-bcm2711-dvp.o
> > >  obj-$(CONFIG_CLK_BCM2835)+= clk-bcm2835.o
> > >  obj-$(CONFIG_CLK_BCM2835)+= clk-bcm2835-aux.o
> > >  obj-$(CONFIG_CLK_RASPBERRYPI)+= clk-raspberrypi.o
> > > diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c b/drivers/clk/bcm/clk-
> > > bcm2711-
> > > dvp.c
> > > new file mode 100644
> > > index ..c1c4b5857d32
> > > --- /dev/null
> > > +++ b/drivers/clk/bcm/clk-bcm2711-dvp.c
> > > @@ -0,0 +1,127 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +// Copyright 2020 Cerno
> > > +
> > > +#include 
> > > +#include 
> > > +#include 
> > > +#include 
> > > +#include 
> > > +
> > > +#define DVP_HT_RPI_SW_INIT   0x04
> > > +#define DVP_HT_RPI_MISC_CONFIG   0x08
> > > +
> > > +#define NR_CLOCKS2
> > > +#define NR_RESETS6
> > > +
> > > +struct clk_dvp {
> > > + struct clk_hw_onecell_data  *data;
> > > + struct reset_simple_datareset;
> > > +};
> > > +
> > > +static const struct clk_parent_data clk_dvp_parent = {
> > > + .index  = 0,
> > > +};
> > > +
> > > +static int clk_dvp_probe(struct platform_device *pdev)
> > > +{
> > > + struct clk_hw_onecell_data *data;
> > > + struct resource *res;
> > > + struct clk_dvp *dvp;
> > > + void __iomem *base;
> > > + int ret;
> > > +
> > > + dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
> > > + if (!dvp)
> > > + return -ENOMEM;
> > > + platform_set_drvdata(pdev, dvp);
> > > +
> > > + dvp->data = devm_kzalloc(&pdev->dev,
> > > +  struct_size(dvp->data, hws, NR_CLOCKS),
> > > +  GFP_KERNEL);
> > > + if (!dvp->data)
> > > + return -ENOMEM;
> > > + data = dvp->data;
> > > +
> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > + base = devm_ioremap_resource(&pdev->dev, res);
> > 
> > I think the cool function to use these days is
> > devm_platform_get_and_ioremap_resource().
> 
> i'll change it, thanks!

Reviewed-by: Nicolas Saenz Julienne 

Regards,
Nicolas



signature.asc
Description: This is a digitally signed message part
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 03/39] clk: tegra: Export Tegra20 EMC kernel symbols

2020-06-07 Thread Dmitry Osipenko
We're going to modularize Tegra EMC drivers and some of the EMC clk driver
symbols need to be exported, let's export them.

Signed-off-by: Dmitry Osipenko 
---
 drivers/clk/tegra/clk-tegra20-emc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/clk/tegra/clk-tegra20-emc.c 
b/drivers/clk/tegra/clk-tegra20-emc.c
index 03bf0009a33c..dd74b8543bf1 100644
--- a/drivers/clk/tegra/clk-tegra20-emc.c
+++ b/drivers/clk/tegra/clk-tegra20-emc.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -235,6 +236,7 @@ void 
tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
emc->cb_arg = cb_arg;
}
 }
+EXPORT_SYMBOL_GPL(tegra20_clk_set_emc_round_callback);
 
 bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw)
 {
@@ -291,3 +293,4 @@ int tegra20_clk_prepare_emc_mc_same_freq(struct clk 
*emc_clk, bool same)
 
return 0;
 }
+EXPORT_SYMBOL_GPL(tegra20_clk_prepare_emc_mc_same_freq);
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 33/39] memory: tegra30-emc: Continue probing if timings are missing in device-tree

2020-06-07 Thread Dmitry Osipenko
EMC driver will become mandatory after turning it into interconnect
provider because interconnect users, like display controller driver, will
fail to probe using newer device-trees that have interconnect properties.
Thus make EMC driver to probe even if timings are missing in device-tree.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra30-emc.c | 29 +++--
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/memory/tegra/tegra30-emc.c 
b/drivers/memory/tegra/tegra30-emc.c
index 205d8053fa75..76586edb34ee 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -988,6 +988,11 @@ static struct device_node 
*emc_find_node_by_ram_code(struct device *dev)
u32 value, ram_code;
int err;
 
+   if (of_get_child_count(dev->of_node) == 0) {
+   dev_info(dev, "device-tree doesn't have memory timings\n");
+   return NULL;
+   }
+
ram_code = tegra_read_ram_code();
 
for_each_child_of_node(dev->of_node, np) {
@@ -1057,6 +1062,9 @@ static long emc_round_rate(unsigned long rate,
struct tegra_emc *emc = arg;
unsigned int i;
 
+   if (!emc->num_timings)
+   return clk_get_rate(emc->clk);
+
min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
 
for (i = 0; i < emc->num_timings; i++) {
@@ -1263,12 +1271,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
struct tegra_emc *emc;
int err;
 
-   if (of_get_child_count(pdev->dev.of_node) == 0) {
-   dev_info(&pdev->dev,
-"device-tree node doesn't have memory timings\n");
-   return -ENODEV;
-   }
-
np = of_parse_phandle(pdev->dev.of_node, "nvidia,memory-controller", 0);
if (!np) {
dev_err(&pdev->dev, "could not get memory controller node\n");
@@ -1280,10 +1282,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (!mc)
return -ENOENT;
 
-   np = emc_find_node_by_ram_code(&pdev->dev);
-   if (!np)
-   return -EINVAL;
-
emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
if (!emc) {
of_node_put(np);
@@ -1297,10 +1295,13 @@ static int tegra_emc_probe(struct platform_device *pdev)
emc->clk_nb.notifier_call = emc_clk_change_notify;
emc->dev = &pdev->dev;
 
-   err = emc_load_timings_from_dt(emc, np);
-   of_node_put(np);
-   if (err)
-   return err;
+   np = emc_find_node_by_ram_code(&pdev->dev);
+   if (np) {
+   err = emc_load_timings_from_dt(emc, np);
+   of_node_put(np);
+   if (err)
+   return err;
+   }
 
emc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(emc->regs))
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 39/39] ARM: multi_v7_defconfig: Enable interconnect API

2020-06-07 Thread Dmitry Osipenko
NVIDIA Tegra now has interconnect providers that are used for memory
bandwidth allocation.

Signed-off-by: Dmitry Osipenko 
---
 arch/arm/configs/multi_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/multi_v7_defconfig 
b/arch/arm/configs/multi_v7_defconfig
index 95543914d3c7..d3b554045dbe 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -1086,6 +1086,7 @@ CONFIG_FSI_MASTER_ASPEED=m
 CONFIG_FSI_SCOM=m
 CONFIG_FSI_SBEFIFO=m
 CONFIG_FSI_OCC=m
+CONFIG_INTERCONNECT=y
 CONFIG_EXT4_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_MSDOS_FS=y
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 0/4] DSI/DBI and TinyDRM driver

2020-06-07 Thread Paul Cercueil
Hi,

Here's a follow-up on the previous discussion about the current state of
DSI/DBI panel drivers, TinyDRM, and the need of a cleanup.

This patchset introduces the following:
* It slightly tweaks the MIPI DSI code so that it supports MIPI DBI over
  various buses. This patch has been tested with a non-upstream DRM
  panel driver for a ILI9331 DBI/8080 panel, written with the DSI
  framework (and doesn't include ), and non-upstream
  DSI/DBI host driver for the Ingenic SoCs.

* A SPI DBI host driver, using the current MIPI DSI framework. It allows
  MIPI DSI/DBI drivers to be written with the DSI framework, even if
  they are connected over SPI, instead of registering as SPI device
  drivers. Since most of these panels can be connected over various
  buses, it permits to reuse the same driver independently of the bus
  used.

* A TinyDRM driver for DSI/DBI panels, once again independent of the bus
  used; the only dependency (currently) being that the panel must
  understand DCS commands.

* A DRM panel driver to test the stack. This driver controls Ilitek
  ILI9341 based DBI panels, like the Adafruit YX240QV29-T 320x240 2.4"
  TFT LCD panel. This panel was converted from
  drivers/gpu/drm/tiny/ili9341.c.

I would like to emphasize that while it has been compile-tested, I did
not test it with real hardware since I do not have any DBI panel
connected over SPI. I did runtime-test the code, just without any panel
connected.

Another thing to note, is that it does not break Device Tree ABI. The
display node stays the same:

display@0 {
compatible = "adafruit,yx240qv29", "ilitek,ili9341";
reg = <0>;
spi-max-frequency = <3200>;
dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
rotation = <270>;
backlight = <&backlight>;
};

The reason it works, is that the "adafruit,yx240qv29" device is probed
on the SPI bus, so it will match with the SPI/DBI host driver. This will
in turn register the very same node with the DSI bus, and the ILI9341
DRM panel driver will probe. The driver will detect that no controller
is linked to the panel, and eventually register the DBI/DSI TinyDRM
driver.

I can't stress it enough that this is a RFC, so it still has very rough
edges.

Cheers,
-Paul

Paul Cercueil (4):
  gpu/drm: dsi: Let host and device specify supported bus
  gpu/drm: Add SPI DBI host driver
  gpu/drm: Add TinyDRM for DSI/DBI panels
  gpu/drm: Add Ilitek ILI9341 DBI panel driver

 drivers/gpu/drm/bridge/Kconfig   |   8 +
 drivers/gpu/drm/bridge/Makefile  |   1 +
 drivers/gpu/drm/bridge/dbi-spi.c | 159 +
 drivers/gpu/drm/drm_mipi_dsi.c   |   9 +
 drivers/gpu/drm/panel/Kconfig|   9 +
 drivers/gpu/drm/panel/Makefile   |   1 +
 drivers/gpu/drm/panel/panel-ilitek-ili9341.c | 347 +++
 drivers/gpu/drm/tiny/Kconfig |   8 +
 drivers/gpu/drm/tiny/Makefile|   1 +
 drivers/gpu/drm/tiny/tiny-dsi.c  | 262 ++
 include/drm/drm_mipi_dsi.h   |  31 ++
 11 files changed, 836 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/dbi-spi.c
 create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c
 create mode 100644 drivers/gpu/drm/tiny/tiny-dsi.c

-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 25/39] ARM: tegra: Add interconnect properties to Tegra20 device-tree

2020-06-07 Thread Dmitry Osipenko
Add interconnect properties to the memory controller, external memory
controller and the display controller nodes in order to describe hardware
interconnection.

Signed-off-by: Dmitry Osipenko 
---
 arch/arm/boot/dts/tegra20.dtsi | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index c3b8ad53b967..974048e83541 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -109,6 +109,15 @@ dc@5420 {
 
nvidia,head = <0>;
 
+   interconnects = <&mc TEGRA20_MC_DISPLAY0A &emc>,
+   <&mc TEGRA20_MC_DISPLAY0B &emc>,
+   <&mc TEGRA20_MC_DISPLAY0C &emc>,
+   <&mc TEGRA20_MC_DISPLAY1B &emc>;
+   interconnect-names = "display0a",
+"display0b",
+"display0c",
+"display1b";
+
rgb {
status = "disabled";
};
@@ -126,6 +135,15 @@ dc@5424 {
 
nvidia,head = <1>;
 
+   interconnects = <&mc TEGRA20_MC_DISPLAY0AB &emc>,
+   <&mc TEGRA20_MC_DISPLAY0BB &emc>,
+   <&mc TEGRA20_MC_DISPLAY0CB &emc>,
+   <&mc TEGRA20_MC_DISPLAY1BB &emc>;
+   interconnect-names = "display0a",
+"display0b",
+"display0c",
+"display1b";
+
rgb {
status = "disabled";
};
@@ -626,15 +644,17 @@ mc: memory-controller@7000f000 {
interrupts = ;
#reset-cells = <1>;
#iommu-cells = <0>;
+   #interconnect-cells = <1>;
};
 
-   memory-controller@7000f400 {
+   emc: memory-controller@7000f400 {
compatible = "nvidia,tegra20-emc";
reg = <0x7000f400 0x200>;
interrupts = ;
clocks = <&tegra_car TEGRA20_CLK_EMC>;
#address-cells = <1>;
#size-cells = <0>;
+   #interconnect-cells = <0>;
};
 
fuse@7000f800 {
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 06/39] memory: tegra124-emc: Make driver modular

2020-06-07 Thread Dmitry Osipenko
This patch adds modularization support to the Tegra124 EMC driver. Driver
now can be compiled as a loadable kernel module.

Signed-off-by: Dmitry Osipenko 
---
 drivers/clk/tegra/clk-tegra124-emc.c | 63 +---
 drivers/clk/tegra/clk-tegra124.c |  3 +-
 drivers/clk/tegra/clk.h  | 12 --
 drivers/memory/tegra/Kconfig |  2 +-
 drivers/memory/tegra/tegra124-emc.c  | 31 +-
 include/linux/clk/tegra.h| 11 +
 include/soc/tegra/emc.h  | 16 ---
 7 files changed, 72 insertions(+), 66 deletions(-)
 delete mode 100644 include/soc/tegra/emc.h

diff --git a/drivers/clk/tegra/clk-tegra124-emc.c 
b/drivers/clk/tegra/clk-tegra124-emc.c
index 745f9faa98d8..4d8b8f1ba7cd 100644
--- a/drivers/clk/tegra/clk-tegra124-emc.c
+++ b/drivers/clk/tegra/clk-tegra124-emc.c
@@ -11,7 +11,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -21,10 +23,10 @@
 #include 
 
 #include 
-#include 
 
 #include "clk.h"
 
+#define CLK_BASE 0x60006000
 #define CLK_SOURCE_EMC 0x19c
 
 #define CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_SHIFT 0
@@ -79,7 +81,9 @@ struct tegra_clk_emc {
 
int num_timings;
struct emc_timing *timings;
-   spinlock_t *lock;
+
+   tegra124_emc_prepare_timing_change_cb *prepare_timing_change;
+   tegra124_emc_complete_timing_change_cb *complete_timing_change;
 };
 
 /* Common clock framework callback implementations */
@@ -98,7 +102,7 @@ static unsigned long emc_recalc_rate(struct clk_hw *hw,
 */
parent_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
 
-   val = readl(tegra->clk_regs + CLK_SOURCE_EMC);
+   val = readl(tegra->clk_regs);
div = val & CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR_MASK;
 
return parent_rate / (div + 2) * 2;
@@ -163,7 +167,7 @@ static u8 emc_get_parent(struct clk_hw *hw)
 
tegra = container_of(hw, struct tegra_clk_emc, hw);
 
-   val = readl(tegra->clk_regs + CLK_SOURCE_EMC);
+   val = readl(tegra->clk_regs);
 
return (val >> CLK_SOURCE_EMC_EMC_2X_CLK_SRC_SHIFT)
& CLK_SOURCE_EMC_EMC_2X_CLK_SRC_MASK;
@@ -204,7 +208,6 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
int err;
u8 div;
u32 car_value;
-   unsigned long flags = 0;
struct tegra_emc *emc = emc_ensure_emc_driver(tegra);
 
if (!emc)
@@ -241,13 +244,11 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
 
div = timing->parent_rate / (timing->rate / 2) - 2;
 
-   err = tegra_emc_prepare_timing_change(emc, timing->rate);
+   err = tegra->prepare_timing_change(emc, timing->rate);
if (err)
return err;
 
-   spin_lock_irqsave(tegra->lock, flags);
-
-   car_value = readl(tegra->clk_regs + CLK_SOURCE_EMC);
+   car_value = readl(tegra->clk_regs);
 
car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_SRC(~0);
car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_SRC(timing->parent_index);
@@ -255,11 +256,9 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
car_value &= ~CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(~0);
car_value |= CLK_SOURCE_EMC_EMC_2X_CLK_DIVISOR(div);
 
-   writel(car_value, tegra->clk_regs + CLK_SOURCE_EMC);
-
-   spin_unlock_irqrestore(tegra->lock, flags);
+   writel(car_value, tegra->clk_regs);
 
-   tegra_emc_complete_timing_change(emc, timing->rate);
+   tegra->complete_timing_change(emc, timing->rate);
 
clk_hw_reparent(&tegra->hw, __clk_get_hw(timing->parent));
clk_disable_unprepare(tegra->prev_parent);
@@ -473,12 +472,15 @@ static const struct clk_ops tegra_clk_emc_ops = {
.get_parent = emc_get_parent,
 };
 
-struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
-  spinlock_t *lock)
+struct clk *
+tegra124_clk_register_emc(struct device_node *emc_np,
+ tegra124_emc_prepare_timing_change_cb *prep_cb,
+ tegra124_emc_complete_timing_change_cb *complete_cb)
 {
struct tegra_clk_emc *tegra;
struct clk_init_data init;
struct device_node *node;
+   struct resource res;
u32 node_ram_code;
struct clk *clk;
int err;
@@ -487,12 +489,21 @@ struct clk *tegra_clk_register_emc(void __iomem *base, 
struct device_node *np,
if (!tegra)
return ERR_PTR(-ENOMEM);
 
-   tegra->clk_regs = base;
-   tegra->lock = lock;
+   res.start = CLK_BASE + CLK_SOURCE_EMC;
+   res.end = res.start + 3;
+   res.flags = IORESOURCE_MEM;
 
-   tegra->num_timings = 0;
+   tegra->clk_regs = ioremap(res.start, resource_size(&res));
+   if (!tegra->clk_regs) {
+   pr_err("failed to map CLK_SOURCE_EMC\n");
+   return ERR_PTR(-EINVAL);
+   }
+
+   tegra->emc_node = emc_np;
+   tegra->prepare_timing_change = prep_cb;
+   tegra->complete_timing_

Re: [PATCH] drm/i915/gvt: print actionable error message when gm runs out

2020-06-07 Thread Julian Stecklina
On Fri, 2020-06-05 at 12:54 +0800, Zhenyu Wang wrote:
> On 2020.06.03 14:33:21 +0200, Julian Stecklina wrote:
> > +   gvt_err("vgpu%d: failed to allocate %s gm space from host\n",
> > +   vgpu->id, high_gm ? "high" : "low");
> > +   gvt_err("vgpu%d: destroying vGPUs, decreasing vGPU memory size
> > or increasing GPU aperture size may resolve this\n",
> > +   vgpu->id);
> 
> Currently we can't decrease vGPU mem size as defined by mdev type,
> so actually you may try different vGPU type.

Yes, that's what I meant.

>  And aperture size is
> also handled for supported vGPU mdev types, so assume user should
> already be awared of that too. I just don't want us to be too chatty. :)

Our users typically hit this particular error message when they haven't
configured the GPU aperture size in the system BIOS correctly. Many laptops we
see have the aperture set to 256MB and this is simply not enough.

I don't cling to the specific wording of the error message, but any hint in the
error message that this is not an obscure, internal error or bug, but something
that the user can actually fix, would be helpful.

Julian

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 37/39] drm/tegra: dc: Extend debug stats with total number of events

2020-06-07 Thread Dmitry Osipenko
It's useful to know the total number of underflow events and currently
the debug stats are getting reset each time CRTC is being disabled. Let's
account the overall number of events that doesn't get reset.

Signed-off-by: Dmitry Osipenko 
---
 drivers/gpu/drm/tegra/dc.c | 10 ++
 drivers/gpu/drm/tegra/dc.h |  5 +
 2 files changed, 15 insertions(+)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 48dad375b470..6a5a017e37d5 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1616,6 +1616,11 @@ static int tegra_dc_show_stats(struct seq_file *s, void 
*data)
seq_printf(s, "underflow: %lu\n", dc->stats.underflow);
seq_printf(s, "overflow: %lu\n", dc->stats.overflow);
 
+   seq_printf(s, "frames total: %lu\n", dc->stats.frames_total);
+   seq_printf(s, "vblank total: %lu\n", dc->stats.vblank_total);
+   seq_printf(s, "underflow total: %lu\n", dc->stats.underflow_total);
+   seq_printf(s, "overflow total: %lu\n", dc->stats.overflow_total);
+
return 0;
 }
 
@@ -2178,6 +2183,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
/*
dev_dbg(dc->dev, "%s(): frame end\n", __func__);
*/
+   dc->stats.frames_total++;
dc->stats.frames++;
}
 
@@ -2186,6 +2192,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
*/
drm_crtc_handle_vblank(&dc->base);
+   dc->stats.vblank_total++;
dc->stats.vblank++;
}
 
@@ -2193,6 +2200,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
/*
dev_dbg(dc->dev, "%s(): underflow\n", __func__);
*/
+   dc->stats.underflow_total++;
dc->stats.underflow++;
}
 
@@ -2200,11 +2208,13 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
/*
dev_dbg(dc->dev, "%s(): overflow\n", __func__);
*/
+   dc->stats.overflow_total++;
dc->stats.overflow++;
}
 
if (status & HEAD_UF_INT) {
dev_dbg_ratelimited(dc->dev, "%s(): head underflow\n", 
__func__);
+   dc->stats.underflow_total++;
dc->stats.underflow++;
}
 
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 3a0ff57c5169..3eb4eddc2288 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -41,6 +41,11 @@ struct tegra_dc_stats {
unsigned long vblank;
unsigned long underflow;
unsigned long overflow;
+
+   unsigned long frames_total;
+   unsigned long vblank_total;
+   unsigned long underflow_total;
+   unsigned long overflow_total;
 };
 
 struct tegra_windowgroup_soc {
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 36/39] drm/tegra: dc: Tune up high priority request controls for Tegra20

2020-06-07 Thread Dmitry Osipenko
Tegra20 has a high-priority-request control that allows to configure
when display's memory client should perform read requests with a higher
priority (Tegra30+ uses other means like Latency Allowance).

This patch changes the controls configuration in order to get a more
aggressive memory prefetching, which allows to reliably avoid FIFO
underflow when running on a lower memory frequency. This allow us
safely drop the memory bandwidth requirement by about two times in a
most popular use-cases (only one display active, video overlay inactive,
no scaling is done).

Signed-off-by: Dmitry Osipenko 
---
 drivers/gpu/drm/tegra/dc.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 12b318bb8475..48dad375b470 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1971,12 +1971,12 @@ static void tegra_crtc_atomic_enable(struct drm_crtc 
*crtc,
tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
 
/* initialize timer */
-   value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
-   WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
+   value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x70) |
+   WINDOW_B_THRESHOLD(0x30) | WINDOW_C_THRESHOLD(0x70);
tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
 
-   value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
-   WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
+   value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0) |
+   WINDOW_B_THRESHOLD(0) | WINDOW_C_THRESHOLD(0);
tegra_dc_writel(dc, value, 
DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
 
value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT 
|
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 20/39] dt-bindings: memory: tegra30: mc: Document new interconnect property

2020-06-07 Thread Dmitry Osipenko
Memory controller is interconnected with memory clients and with the
external memory controller. Document new interconnect property which
turns memory controller into interconnect provider.

Acked-by: Rob Herring 
Signed-off-by: Dmitry Osipenko 
---
 .../bindings/memory-controllers/nvidia,tegra30-mc.yaml   | 5 +
 1 file changed, 5 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml
index 84fd57bcf0dc..5436e6d420bc 100644
--- 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml
+++ 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-mc.yaml
@@ -57,6 +57,9 @@ properties:
   "#iommu-cells":
 const: 1
 
+  "#interconnect-cells":
+const: 1
+
 patternProperties:
   "^emc-timings-[0-9]+$":
 type: object
@@ -120,6 +123,7 @@ required:
   - clock-names
   - "#reset-cells"
   - "#iommu-cells"
+  - "#interconnect-cells"
 
 additionalProperties: false
 
@@ -135,6 +139,7 @@ examples:
 
 #iommu-cells = <1>;
 #reset-cells = <1>;
+#interconnect-cells = <1>;
 
 emc-timings-1 {
 nvidia,ram-code = <1>;
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 13/39] PM / devfreq: tegra30: Use MC timings for building OPP table

2020-06-07 Thread Dmitry Osipenko
The clk_round_rate() won't be usable for building OPP table once
interconnect support will be added to the EMC driver because that CLK API
function limits the rounded rate based on the clk rate that is imposed by
active clk-users, and thus, the rounding won't work as expected if
interconnect will set the minimum EMC clock rate before devfreq driver is
loaded. The struct tegra_mc contains memory timings which could be used by
the devfreq driver for building up OPP table instead of rounding clock
rate, this patch implements this idea.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra30-devfreq.c | 98 ++-
 1 file changed, 70 insertions(+), 28 deletions(-)

diff --git a/drivers/devfreq/tegra30-devfreq.c 
b/drivers/devfreq/tegra30-devfreq.c
index 423dd35c95b3..13f93c6038ab 100644
--- a/drivers/devfreq/tegra30-devfreq.c
+++ b/drivers/devfreq/tegra30-devfreq.c
@@ -19,6 +19,8 @@
 #include 
 #include 
 
+#include 
+
 #include "governor.h"
 
 #define ACTMON_GLB_STATUS  0x0
@@ -153,6 +155,18 @@ struct tegra_devfreq_device {
unsigned long target_freq;
 };
 
+struct tegra_devfreq_soc_data {
+   const char *mc_compatible;
+};
+
+static const struct tegra_devfreq_soc_data tegra30_soc = {
+   .mc_compatible = "nvidia,tegra30-mc",
+};
+
+static const struct tegra_devfreq_soc_data tegra124_soc = {
+   .mc_compatible = "nvidia,tegra124-mc",
+};
+
 struct tegra_devfreq {
struct devfreq  *devfreq;
 
@@ -771,15 +785,44 @@ static struct devfreq_governor tegra_devfreq_governor = {
.interrupt_driven = true,
 };
 
+static struct tegra_mc *tegra_get_memory_controller(const char *compatible)
+{
+   struct platform_device *pdev;
+   struct device_node *np;
+   struct tegra_mc *mc;
+
+   np = of_find_compatible_node(NULL, NULL, compatible);
+   if (!np)
+   return ERR_PTR(-ENOENT);
+
+   pdev = of_find_device_by_node(np);
+   of_node_put(np);
+   if (!pdev)
+   return ERR_PTR(-ENODEV);
+
+   mc = platform_get_drvdata(pdev);
+   if (!mc)
+   return ERR_PTR(-EPROBE_DEFER);
+
+   return mc;
+}
+
 static int tegra_devfreq_probe(struct platform_device *pdev)
 {
+   const struct tegra_devfreq_soc_data *soc_data;
struct tegra_devfreq_device *dev;
struct tegra_devfreq *tegra;
struct devfreq *devfreq;
+   struct tegra_mc *mc;
unsigned int i;
-   long rate;
int err;
 
+   soc_data = of_device_get_match_data(&pdev->dev);
+
+   mc = tegra_get_memory_controller(soc_data->mc_compatible);
+   if (IS_ERR(mc))
+   return PTR_ERR(mc);
+
tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
if (!tegra)
return -ENOMEM;
@@ -825,6 +868,30 @@ static int tegra_devfreq_probe(struct platform_device 
*pdev)
return err;
}
 
+   if (!mc->num_timings) {
+   tegra->max_freq = clk_get_rate(tegra->clock) / KHZ;
+
+   err = dev_pm_opp_add(&pdev->dev, tegra->max_freq, 0);
+   if (err) {
+   dev_err(&pdev->dev, "Failed to add OPP: %d\n", err);
+   return err;
+   }
+   }
+
+   for (i = 0; i < mc->num_timings; i++) {
+   /*
+* Memory Controller timings are sorted in ascending clock
+* rate order, so the last timing will be the max freq.
+*/
+   tegra->max_freq = mc->timings[i].rate / KHZ;
+
+   err = dev_pm_opp_add(&pdev->dev, tegra->max_freq, 0);
+   if (err) {
+   dev_err(&pdev->dev, "Failed to add OPP: %d\n", err);
+   goto remove_opps;
+   }
+   }
+
reset_control_assert(tegra->reset);
 
err = clk_prepare_enable(tegra->clock);
@@ -836,37 +903,12 @@ static int tegra_devfreq_probe(struct platform_device 
*pdev)
 
reset_control_deassert(tegra->reset);
 
-   rate = clk_round_rate(tegra->emc_clock, ULONG_MAX);
-   if (rate < 0) {
-   dev_err(&pdev->dev, "Failed to round clock rate: %ld\n", rate);
-   return rate;
-   }
-
-   tegra->max_freq = rate / KHZ;
-
for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) {
dev = tegra->devices + i;
dev->config = actmon_device_configs + i;
dev->regs = tegra->regs + dev->config->offset;
}
 
-   for (rate = 0; rate <= tegra->max_freq * KHZ; rate++) {
-   rate = clk_round_rate(tegra->emc_clock, rate);
-
-   if (rate < 0) {
-   dev_err(&pdev->dev,
-   "Failed to round clock rate: %ld\n", rate);
-   err = rate;
-   goto remove_opps;
-   }
-
-   err = dev_pm_opp_add(&pdev->dev, rate / KHZ, 0);
-

[PATCH v3 08/39] soc/tegra: fuse: Export tegra_read_ram_code()

2020-06-07 Thread Dmitry Osipenko
The tegra_read_ram_code() is used by EMC drivers and we're going to make
these driver modular, hence this function needs to be exported.

Signed-off-by: Dmitry Osipenko 
---
 drivers/soc/tegra/fuse/tegra-apbmisc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c 
b/drivers/soc/tegra/fuse/tegra-apbmisc.c
index 3cdd69d1bd4d..b3c930b805c5 100644
--- a/drivers/soc/tegra/fuse/tegra-apbmisc.c
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -65,6 +66,7 @@ u32 tegra_read_ram_code(void)
 
return straps >> PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT;
 }
+EXPORT_SYMBOL_GPL(tegra_read_ram_code);
 
 static const struct of_device_id apbmisc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-apbmisc", },
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 14/39] PM / devfreq: tegra20: Add error messages to tegra_devfreq_target()

2020-06-07 Thread Dmitry Osipenko
It's useful to now when something goes wrong instead of failing silently,
so let's add error messages to tegra_devfreq_target() to prevent situation
where it fails silently.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra20-devfreq.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/devfreq/tegra20-devfreq.c 
b/drivers/devfreq/tegra20-devfreq.c
index bf504ca4dea2..249d0dc44f6c 100644
--- a/drivers/devfreq/tegra20-devfreq.c
+++ b/drivers/devfreq/tegra20-devfreq.c
@@ -44,19 +44,25 @@ static int tegra_devfreq_target(struct device *dev, 
unsigned long *freq,
int err;
 
opp = devfreq_recommended_opp(dev, freq, flags);
-   if (IS_ERR(opp))
+   if (IS_ERR(opp)) {
+   dev_err(dev, "failed to find opp for %lu Hz\n", *freq);
return PTR_ERR(opp);
+   }
 
rate = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
 
err = clk_set_min_rate(tegra->emc_clock, rate);
-   if (err)
+   if (err) {
+   dev_err(dev, "failed to set min rate: %d\n", err);
return err;
+   }
 
err = clk_set_rate(tegra->emc_clock, 0);
-   if (err)
+   if (err) {
+   dev_err(dev, "failed to set rate: %d\n", err);
goto restore_min_rate;
+   }
 
return 0;
 
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 29/39] memory: tegra20-emc: Use devm_platform_ioremap_resource

2020-06-07 Thread Dmitry Osipenko
Utilize that relatively new helper which makes code a bit cleaner.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra20-emc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index a95522020a25..79fdae042b57 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -689,7 +689,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
 {
struct device_node *np;
struct tegra_emc *emc;
-   struct resource *res;
int irq, err;
 
/* driver has nothing to do in a case of memory timing absence */
@@ -724,8 +723,7 @@ static int tegra_emc_probe(struct platform_device *pdev)
if (err)
return err;
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   emc->regs = devm_ioremap_resource(&pdev->dev, res);
+   emc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(emc->regs))
return PTR_ERR(emc->regs);
 
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 19/39] dt-bindings: memory: tegra20: emc: Document new interconnect property

2020-06-07 Thread Dmitry Osipenko
External memory controller is interconnected with memory controller and
with external memory. Document new interconnect property which turns
external memory controller into interconnect provider.

Acked-by: Rob Herring 
Signed-off-by: Dmitry Osipenko 
---
 .../bindings/memory-controllers/nvidia,tegra20-emc.txt  | 2 ++
 1 file changed, 2 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt
index add95367640b..f51da7662de4 100644
--- 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt
+++ 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.txt
@@ -12,6 +12,7 @@ Properties:
   irrespective of ram-code configuration.
 - interrupts : Should contain EMC General interrupt.
 - clocks : Should contain EMC clock.
+- #interconnect-cells : Should be 0.
 
 Child device nodes describe the memory settings for different configurations 
and clock rates.
 
@@ -20,6 +21,7 @@ Example:
memory-controller@7000f400 {
#address-cells = < 1 >;
#size-cells = < 0 >;
+   #interconnect-cells = < 0 >;
compatible = "nvidia,tegra20-emc";
reg = <0x7000f4000 0x200>;
interrupts = <0 78 0x04>;
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 18/39] dt-bindings: memory: tegra20: mc: Document new interconnect property

2020-06-07 Thread Dmitry Osipenko
Memory controller is interconnected with memory clients and with the
external memory controller. Document new interconnect property which
turns memory controller into interconnect provider.

Acked-by: Rob Herring 
Signed-off-by: Dmitry Osipenko 
---
 .../bindings/memory-controllers/nvidia,tegra20-mc.txt  | 3 +++
 1 file changed, 3 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt
index e55328237df4..739b7c6f2e26 100644
--- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-mc.txt
@@ -16,6 +16,8 @@ Required properties:
   IOMMU specifier needed to encode an address. GART supports only a single
   address space that is shared by all devices, therefore no additional
   information needed for the address encoding.
+- #interconnect-cells : Should be 1. This cell represents memory client.
+  The assignments may be found in header file 
.
 
 Example:
mc: memory-controller@7000f000 {
@@ -27,6 +29,7 @@ Example:
interrupts = ;
#reset-cells = <1>;
#iommu-cells = <0>;
+   #interconnect-cells = <1>;
};
 
video-codec@6001a000 {
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 07/39] memory: tegra124-emc: Use devm_platform_ioremap_resource

2020-06-07 Thread Dmitry Osipenko
Utilize that relatively new helper which makes code a bit cleaner.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra124-emc.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/memory/tegra/tegra124-emc.c 
b/drivers/memory/tegra/tegra124-emc.c
index 95afb0fa4a06..46089ef023a8 100644
--- a/drivers/memory/tegra/tegra124-emc.c
+++ b/drivers/memory/tegra/tegra124-emc.c
@@ -1193,7 +1193,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
struct platform_device *mc;
struct device_node *np;
struct tegra_emc *emc;
-   struct resource *res;
u32 ram_code;
int err;
 
@@ -1203,8 +1202,7 @@ static int tegra_emc_probe(struct platform_device *pdev)
 
emc->dev = &pdev->dev;
 
-   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   emc->regs = devm_ioremap_resource(&pdev->dev, res);
+   emc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(emc->regs))
return PTR_ERR(emc->regs);
 
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 34/39] memory: tegra30-emc: Register as interconnect provider

2020-06-07 Thread Dmitry Osipenko
Now external memory controller is a memory interconnection provider.
This allows us to use interconnect API to change memory configuration.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra30-emc.c | 115 +
 1 file changed, 115 insertions(+)

diff --git a/drivers/memory/tegra/tegra30-emc.c 
b/drivers/memory/tegra/tegra30-emc.c
index 76586edb34ee..096ec5265084 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -14,6 +14,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -327,6 +328,7 @@ struct tegra_emc {
struct device *dev;
struct tegra_mc *mc;
struct notifier_block clk_nb;
+   struct icc_provider provider;
struct clk *clk;
void __iomem *regs;
unsigned int irq;
@@ -1264,6 +1266,112 @@ static void tegra_emc_debugfs_init(struct tegra_emc 
*emc)
emc, &tegra_emc_debug_max_rate_fops);
 }
 
+static inline struct tegra_emc *
+to_tegra_emc_provider(struct icc_provider *provider)
+{
+   return container_of(provider, struct tegra_emc, provider);
+}
+
+static struct icc_node *
+emc_of_icc_xlate(struct of_phandle_args *spec, void *data)
+{
+   struct icc_provider *provider = data;
+   struct icc_node *node;
+
+   /* External Memory is the only possible ICC route */
+   list_for_each_entry(node, &provider->nodes, node_list) {
+   if (node->id == TEGRA_ICC_EMEM)
+   return node;
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+   struct tegra_emc *emc = to_tegra_emc_provider(dst->provider);
+   unsigned long long rate = icc_units_to_bps(dst->avg_bw);
+   unsigned int dram_data_bus_width_bytes = 4;
+   unsigned int ddr = 2;
+   int err;
+
+   do_div(rate, ddr * dram_data_bus_width_bytes);
+   rate = min_t(u64, rate, U32_MAX);
+
+   err = clk_set_min_rate(emc->clk, rate);
+   if (err)
+   return err;
+
+   err = clk_set_rate(emc->clk, rate);
+   if (err)
+   return err;
+
+   return 0;
+}
+
+static int emc_icc_aggregate(struct icc_node *node,
+u32 tag, u32 avg_bw, u32 peak_bw,
+u32 *agg_avg, u32 *agg_peak)
+{
+   *agg_avg = min((u64)avg_bw + (*agg_avg), (u64)U32_MAX);
+   *agg_peak = max(*agg_peak, peak_bw);
+
+   return 0;
+}
+
+static int tegra_emc_interconnect_init(struct tegra_emc *emc)
+{
+   struct icc_node *node;
+   int err;
+
+   /* older device-trees don't have interconnect properties */
+   if (!of_find_property(emc->dev->of_node, "#interconnect-cells", NULL))
+   return 0;
+
+   emc->provider.dev = emc->dev;
+   emc->provider.set = emc_icc_set;
+   emc->provider.data = &emc->provider;
+   emc->provider.xlate = emc_of_icc_xlate;
+   emc->provider.aggregate = emc_icc_aggregate;
+
+   err = icc_provider_add(&emc->provider);
+   if (err)
+   return err;
+
+   /* create External Memory Controller node */
+   node = icc_node_create(TEGRA_ICC_EMC);
+   err = PTR_ERR_OR_ZERO(node);
+   if (err)
+   goto del_provider;
+
+   node->name = "External Memory Controller";
+   icc_node_add(node, &emc->provider);
+
+   /* link External Memory Controller to External Memory (DRAM) */
+   err = icc_link_create(node, TEGRA_ICC_EMEM);
+   if (err)
+   goto remove_nodes;
+
+   /* create External Memory node */
+   node = icc_node_create(TEGRA_ICC_EMEM);
+   err = PTR_ERR_OR_ZERO(node);
+   if (err)
+   goto remove_nodes;
+
+   node->name = "External Memory (DRAM)";
+   icc_node_add(node, &emc->provider);
+
+   return 0;
+
+remove_nodes:
+   icc_nodes_remove(&emc->provider);
+
+del_provider:
+   icc_provider_del(&emc->provider);
+
+   return err;
+}
+
 static int tegra_emc_probe(struct platform_device *pdev)
 {
struct platform_device *mc;
@@ -1344,6 +1452,13 @@ static int tegra_emc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, emc);
tegra_emc_debugfs_init(emc);
 
+   if (IS_ENABLED(CONFIG_INTERCONNECT)) {
+   err = tegra_emc_interconnect_init(emc);
+   if (err)
+   dev_err(&pdev->dev, "failed to initialize ICC: %d\n",
+   err);
+   }
+
/*
 * Don't allow the kernel module to be unloaded. Unloading adds some
 * extra complexity which doesn't really worth the effort in a case of
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 3/3] drm/mipi: use dcs write for mipi_dsi_dcs_set_tear_scanline

2020-06-07 Thread Vinay Simha B N
hi emil,

On Wed, May 13, 2020 at 3:17 PM Emil Velikov  wrote:
>
> Hi Vinay,
>
> On Thu, 7 May 2020 at 17:18, Emil Velikov  wrote:
> >
> > On Thu, 7 May 2020 at 13:29, Vinay Simha B N  wrote:
> > >
> > > Emil,
> > >
> > > Reply inline
> > >
> > > On Tue, 5 May 2020 at 9:35 PM, Emil Velikov  
> > > wrote:
> > >>
> > >> From: Emil Velikov 
> > >>
> > >> The helper uses the MIPI_DCS_SET_TEAR_SCANLINE, although it's currently
> > >> using the generic write. This does not look right.
> > >>
> > >> Perhaps some platforms don't distinguish between the two writers?
> > >>
> > >> Cc: Robert Chiras 
> > >> Cc: Vinay Simha BN 
> > >> Cc: Jani Nikula 
> > >> Cc: Thierry Reding 
> > >> Fixes: e83950816367 ("drm/dsi: Implement set tear scanline")
> > >> Signed-off-by: Emil Velikov 
> > >> ---
> > >> Robert, can you please test this against the only user - the Raydium
> > >> RM67191 panel driver that you introduced.
> > >>
> > >> Thanks
> > >>
> > >> Vinay, can you confirm if this is a genuine typo or there's something
> > >> really subtle happening.
> > >
> > > this has been tested on nexus 7 with jdi panel.
> > The jdi panel (JDI LT070ME05000 I believe) does not use the function, hmm.
> >
> > Looking through the ML archive - the call in the first 4 revisions of the 
> > patch.
> > Then with v5 it has magically disappeared alongside 
> > mipi_dsi_dcs_set_tear_on().
> >
> > No comment explaining why though - does the driver work w/o both of those?
> >
> Any ideas, does the driver work in today's state?
Initially I had used cmd mode, later modified to video mode panel,
since to control the panel in cmd mode is not available for mdp4.
so mipi_dsi_dcs_set_tear_on was not used.


>
> > > I did not understand what is the typo here?
> > > We need to use DC’s write instead of generic write?
> >
> > I believe the clue is in the command name - MIPI_DSI_DCS. I was going
> > to double-check with the spec although it's members only :-\
> > Based on the usage in DRM, all DCS commands are issued via
> > mipi_dsi_dcs_{read,write}
> >
> Do you agree with the rationale? Alternatively, do you have a
> reference to the Android tree where the generic write is used.
>
default android nexus 7 kernel
https://github.com/vinaysimhabn/msm/commits/nexus7-msm-flo-3.4-lollipop-release
> Thanks
> Emil



--
regards,
vinaysimha
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-07 Thread Andy Shevchenko
On Sat, Jun 06, 2020 at 10:25:47PM +0200, Hans de Goede wrote:
> The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
> controller gets turned off from the _PS3 method of the graphics-card dev:
> 
> Method (_PS3, 0, Serialized)  // _PS3: Power State 3
> {
> ...
> PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
> PSAT |= 0x03
> Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
> ...
> }
> 
> Where PSAT is the power-status register of the PWM controller.
> 
> Since the i915 driver will do a pwm_get on the pwm device as it uses it to
> control the LCD panel backlight, there is a device-link marking the i915
> device as a consumer of the pwm device. So that the PWM controller will
> always be suspended after the i915 driver suspends (which is the right
> thing to do). This causes the above GFX0 PS3 AML code to run before
> acpi_lpss.c calls acpi_lpss_save_ctx().
> 
> So on these devices the PWM controller will already be off when
> acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
> as ctx register values.
> 
> When these bogus values get restored on resume the PWM controller actually
> keeps working, since most bits are reserved, but this does set bit 3 of
> the LPSS General purpose register, which for the PWM controller has the
> following function: "This bit is re-used to support 32kHz slow mode.
> Default is 19.2MHz as PWM source clock".
> 
> This causes the clock of the PWM controller to switch from 19.2MHz to
> 32KHz, which is a slow-down of a factor 600. Suprisingly enough so far
> there have been few bug reports about this. This is likely because the
> i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
> by 600 would result in a PWM frequency of aprox. 78 Hz, which mostly
> still works fine. There are some bug reports about the LCD backlight
> flickering after suspend/resume which are likely caused by this issue.
> 
> But with the upcoming patch-series to finally switch the i915 drivers
> code for external PWM controllers to use the atomic API and to honor
> the PWM frequency specified in the video BIOS (VBT), this becomes a much
> bigger problem. On most cases the VBT specifies either 200 Hz or 20
> KHz as PWM frequency, which with the mentioned issue ends up being either
> 1/3 Hz, where the backlight actually visible blinks on and off every 3s,
> or in 33 Hz and horrible flickering of the backlight.
> 
> There are a number of possible solutions to this problem:
> 
> 1. Make acpi_lpss_save_ctx() run before GFX0._PS3
>  Pro: Clean solution from pov of not medling with save/restore ctx code
>  Con: As mentioned the current ordering is the right thing to do
>  Con: Requires assymmetry in at what suspend/resume phase we do the save vs
>   restore, requiring more suspend/resume ordering hacks in already
>   convoluted acpi_lpss.c suspend/resume code.
> 2. Do some sort of save once mode for the LPSS ctx
>  Pro: Reasonably clean
>  Con: Needs a new LPSS flag + code changes to handle the flag
> 3. Detect we have failed to save the ctx registers and do not restore them
>  Pro: Not PWM specific, might help with issues on other LPSS devices too
>  Con: If we can get away with not restoring the ctx why bother with it at
>   all?
> 4. Do not save the ctx for CHT PWM controllers
>  Pro: Clean, as simple as dropping a flag?
>  Con: Not so simple as dropping a flag, needs a new flag to ensure that
>   we still do lpss_deassert_reset() on device activation.
> 5. Make the pwm-lpss code fixup the LPSS-context registers
>  Pro: Keeps acpi_lpss.c code clean
>  Con: Moves knowledge of LPSS-context into the pwm-lpss.c code
> 
> 1 and 5 both do not seem to be a desirable way forward.
> 
> 3 and 4 seem ok, but they both assume that restoring the LPSS-context
> registers is not necessary. I have done a couple of test and those do
> show that restoring the LPSS-context indeed does not seem to be necessary
> on devices using s2idle suspend (and successfully reaching S0i3). But I
> have no hardware to test deep / S3 suspend. So I'm not sure that not
> restoring the context is safe.
> 
> That leaves solution 2, which is about as simple / clean as 3 and 4,
> so this commit fixes the described problem by implementing a new
> LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.
> 
> Signed-off-by: Hans de Goede 
> ---
>  drivers/acpi/acpi_lpss.c | 19 ---
>  1 file changed, 16 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
> index 67892fc0b822..26933e6b7b8c 100644
> --- a/drivers/acpi/acpi_lpss.c
> +++ b/drivers/acpi/acpi_lpss.c
> @@ -68,6 +68,14 @@ ACPI_MODULE_NAME("acpi_lpss");
>  #define LPSS_LTR BIT(3)
>  #define LPSS_SAVE_CTXBIT(4)
>  #define LPSS_NO_D3_DELAY BIT(5)
> +/*
> + * F

[PATCH v3 05/39] memory: tegra30-emc: Make driver modular

2020-06-07 Thread Dmitry Osipenko
This patch adds modularization support to the Tegra30 EMC driver. Driver
now can be compiled as a loadable kernel module.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/Kconfig   |  2 +-
 drivers/memory/tegra/mc.c  |  3 +++
 drivers/memory/tegra/tegra30-emc.c | 16 +++-
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig
index 7e0e1ef87763..bd453de9d446 100644
--- a/drivers/memory/tegra/Kconfig
+++ b/drivers/memory/tegra/Kconfig
@@ -18,7 +18,7 @@ config TEGRA20_EMC
  external memory.
 
 config TEGRA30_EMC
-   bool "NVIDIA Tegra30 External Memory Controller driver"
+   tristate "NVIDIA Tegra30 External Memory Controller driver"
default y
depends on TEGRA_MC && ARCH_TEGRA_3x_SOC
help
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index ec8403557ed4..772aa021b5f6 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -6,6 +6,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -298,6 +299,7 @@ int tegra_mc_write_emem_configuration(struct tegra_mc *mc, 
unsigned long rate)
 
return 0;
 }
+EXPORT_SYMBOL_GPL(tegra_mc_write_emem_configuration);
 
 unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc)
 {
@@ -309,6 +311,7 @@ unsigned int tegra_mc_get_emem_device_count(struct tegra_mc 
*mc)
 
return dram_count;
 }
+EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count);
 
 static int load_one_timing(struct tegra_mc *mc,
   struct tegra_mc_timing *timing,
diff --git a/drivers/memory/tegra/tegra30-emc.c 
b/drivers/memory/tegra/tegra30-emc.c
index 055af0e08a2e..205d8053fa75 100644
--- a/drivers/memory/tegra/tegra30-emc.c
+++ b/drivers/memory/tegra/tegra30-emc.c
@@ -1343,6 +1343,13 @@ static int tegra_emc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, emc);
tegra_emc_debugfs_init(emc);
 
+   /*
+* Don't allow the kernel module to be unloaded. Unloading adds some
+* extra complexity which doesn't really worth the effort in a case of
+* this driver.
+*/
+   try_module_get(THIS_MODULE);
+
return 0;
 
 unset_cb:
@@ -1393,6 +1400,7 @@ static const struct of_device_id tegra_emc_of_match[] = {
{ .compatible = "nvidia,tegra30-emc", },
{},
 };
+MODULE_DEVICE_TABLE(of, tegra_emc_of_match);
 
 static struct platform_driver tegra_emc_driver = {
.probe = tegra_emc_probe,
@@ -1403,9 +1411,7 @@ static struct platform_driver tegra_emc_driver = {
.suppress_bind_attrs = true,
},
 };
+module_platform_driver(tegra_emc_driver);
 
-static int __init tegra_emc_init(void)
-{
-   return platform_driver_register(&tegra_emc_driver);
-}
-subsys_initcall(tegra_emc_init);
+MODULE_DESCRIPTION("NVIDIA Tegra30 EMC driver");
+MODULE_LICENSE("GPL v2");
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 09/39] memory: tegra20-emc: Initialize MC timings

2020-06-07 Thread Dmitry Osipenko
We're going to add interconnect support to the EMC driver. Once this
support will be added, the Tegra20 devfreq driver will no longer be
able to use clk_round_rate(emc) for building up OPP table. It's quite
handy that struct tegra_mc contains memory timings which could be used
by the devfreq drivers instead of the clk rate-rounding. The tegra_mc
timings are populated by the MC driver only for Tegra30+ SoCs, hence
the Tegra20 EMC could populate timings by itself.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra20-emc.c | 47 ++
 1 file changed, 47 insertions(+)

diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index 035d9251e28a..a95522020a25 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -15,12 +15,15 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 
 #include 
 
+#include "mc.h"
+
 #define EMC_INTSTATUS  0x000
 #define EMC_INTMASK0x004
 #define EMC_DBG0x008
@@ -650,6 +653,38 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
emc, &tegra_emc_debug_max_rate_fops);
 }
 
+static int tegra_emc_init_mc_timings(struct tegra_emc *emc)
+{
+   struct tegra_mc_timing *timing;
+   struct platform_device *pdev;
+   struct device_node *np;
+   struct tegra_mc *mc;
+   unsigned int i;
+
+   np = of_find_compatible_node(NULL, NULL, "nvidia,tegra20-mc-gart");
+   if (!np)
+   return -ENOENT;
+
+   pdev = of_find_device_by_node(np);
+   of_node_put(np);
+   if (!pdev)
+   return -ENOENT;
+
+   mc = platform_get_drvdata(pdev);
+   if (!mc)
+   return -EPROBE_DEFER;
+
+   mc->timings = devm_kcalloc(mc->dev, emc->num_timings, sizeof(*timing),
+  GFP_KERNEL);
+   if (!mc->timings)
+   return -ENOMEM;
+
+   for (i = 0; i < emc->num_timings; i++)
+   mc->timings[mc->num_timings++].rate = emc->timings[i].rate;
+
+   return 0;
+}
+
 static int tegra_emc_probe(struct platform_device *pdev)
 {
struct device_node *np;
@@ -705,6 +740,18 @@ static int tegra_emc_probe(struct platform_device *pdev)
return err;
}
 
+   /*
+* Only Tegra30+ SoCs are having Memory Controller timings initialized
+* by the MC driver. For Tegra20 we need to populate the MC timings
+* from here. The MC timings will be used by the Tegra20 devfreq driver.
+*/
+   err = tegra_emc_init_mc_timings(emc);
+   if (err) {
+   dev_err(&pdev->dev, "failed to initialize mc timings: %d\n",
+   err);
+   return err;
+   }
+
tegra20_clk_set_emc_round_callback(emc_round_rate, emc);
 
emc->clk = devm_clk_get(&pdev->dev, "emc");
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 23/39] dt-bindings: memory: tegra20: Add memory client IDs

2020-06-07 Thread Dmitry Osipenko
Each memory client have a unique hardware ID, this patch adds these IDs.

Signed-off-by: Dmitry Osipenko 
---
 include/dt-bindings/memory/tegra20-mc.h | 53 +
 1 file changed, 53 insertions(+)

diff --git a/include/dt-bindings/memory/tegra20-mc.h 
b/include/dt-bindings/memory/tegra20-mc.h
index 35e131eee198..6f8829508ad0 100644
--- a/include/dt-bindings/memory/tegra20-mc.h
+++ b/include/dt-bindings/memory/tegra20-mc.h
@@ -18,4 +18,57 @@
 #define TEGRA20_MC_RESET_VDE   13
 #define TEGRA20_MC_RESET_VI14
 
+#define TEGRA20_MC_DISPLAY0A   0
+#define TEGRA20_MC_DISPLAY0AB  1
+#define TEGRA20_MC_DISPLAY0B   2
+#define TEGRA20_MC_DISPLAY0BB  3
+#define TEGRA20_MC_DISPLAY0C   4
+#define TEGRA20_MC_DISPLAY0CB  5
+#define TEGRA20_MC_DISPLAY1B   6
+#define TEGRA20_MC_DISPLAY1BB  7
+#define TEGRA20_MC_EPPUP   8
+#define TEGRA20_MC_G2PR9
+#define TEGRA20_MC_G2SR10
+#define TEGRA20_MC_MPEUNIFBR   11
+#define TEGRA20_MC_VIRUV   12
+#define TEGRA20_MC_AVPCARM7R   13
+#define TEGRA20_MC_DISPLAYHC   14
+#define TEGRA20_MC_DISPLAYHCB  15
+#define TEGRA20_MC_FDCDRD  16
+#define TEGRA20_MC_G2DR17
+#define TEGRA20_MC_HOST1XDMAR  18
+#define TEGRA20_MC_HOST1XR 19
+#define TEGRA20_MC_IDXSRD  20
+#define TEGRA20_MC_MPCORER 21
+#define TEGRA20_MC_MPE_IPRED   22
+#define TEGRA20_MC_MPEAMEMRD   23
+#define TEGRA20_MC_MPECSRD 24
+#define TEGRA20_MC_PPCSAHBDMAR 25
+#define TEGRA20_MC_PPCSAHBSLVR 26
+#define TEGRA20_MC_TEXSRD  27
+#define TEGRA20_MC_VDEBSEVR28
+#define TEGRA20_MC_VDEMBER 29
+#define TEGRA20_MC_VDEMCER 30
+#define TEGRA20_MC_VDETPER 31
+#define TEGRA20_MC_EPPU32
+#define TEGRA20_MC_EPPV33
+#define TEGRA20_MC_EPPY34
+#define TEGRA20_MC_MPEUNIFBW   35
+#define TEGRA20_MC_VIWSB   36
+#define TEGRA20_MC_VIWU37
+#define TEGRA20_MC_VIWV38
+#define TEGRA20_MC_VIWY39
+#define TEGRA20_MC_G2DW40
+#define TEGRA20_MC_AVPCARM7W   41
+#define TEGRA20_MC_FDCDWR  42
+#define TEGRA20_MC_HOST1XW 43
+#define TEGRA20_MC_ISPW44
+#define TEGRA20_MC_MPCOREW 45
+#define TEGRA20_MC_MPECSWR 46
+#define TEGRA20_MC_PPCSAHBDMAW 47
+#define TEGRA20_MC_PPCSAHBSLVW 48
+#define TEGRA20_MC_VDEBSEVW49
+#define TEGRA20_MC_VDEMBEW 50
+#define TEGRA20_MC_VDETPMW 51
+
 #endif
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v3 004/105] clk: bcm: Add BCM2711 DVP driver

2020-06-07 Thread Maxime Ripard
Hi Nicolas,

On Thu, Jun 04, 2020 at 07:26:07PM +0200, Nicolas Saenz Julienne wrote:
> On Wed, 2020-05-27 at 17:47 +0200, Maxime Ripard wrote:
> > The HDMI block has a block that controls clocks and reset signals to the
> > HDMI0 and HDMI1 controllers.
> 
> Why not having two separate drivers?

They share the same address space, so it wouldn't really make sense to
split it into two drivers and an MFD, especially when the clock/reset
association is fairly common.

> > Let's expose that through a clock driver implementing a clock and reset
> > provider.
> > 
> > Cc: Michael Turquette 
> > Cc: Stephen Boyd 
> > Cc: Rob Herring 
> > Cc: linux-...@vger.kernel.org
> > Cc: devicet...@vger.kernel.org
> > Reviewed-by: Stephen Boyd 
> > Signed-off-by: Maxime Ripard 
> > ---
> >  drivers/clk/bcm/Kconfig   |  11 +++-
> >  drivers/clk/bcm/Makefile  |   1 +-
> >  drivers/clk/bcm/clk-bcm2711-dvp.c | 127 +++-
> >  3 files changed, 139 insertions(+)
> >  create mode 100644 drivers/clk/bcm/clk-bcm2711-dvp.c
> > 
> > diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig
> > index 8c83977a7dc4..784f12c72365 100644
> > --- a/drivers/clk/bcm/Kconfig
> > +++ b/drivers/clk/bcm/Kconfig
> > @@ -1,4 +1,15 @@
> >  # SPDX-License-Identifier: GPL-2.0-only
> > +
> > +config CLK_BCM2711_DVP
> > +   tristate "Broadcom BCM2711 DVP support"
> > +   depends on ARCH_BCM2835 ||COMPILE_TEST
> > +   depends on COMMON_CLK
> > +   default ARCH_BCM2835
> > +   select RESET_SIMPLE
> > +   help
> > + Enable common clock framework support for the Broadcom BCM2711
> > + DVP Controller.
> > +
> >  config CLK_BCM2835
> > bool "Broadcom BCM2835 clock support"
> > depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
> > diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile
> > index 0070ddf6cdd2..2c1349062147 100644
> > --- a/drivers/clk/bcm/Makefile
> > +++ b/drivers/clk/bcm/Makefile
> > @@ -6,6 +6,7 @@ obj-$(CONFIG_CLK_BCM_KONA)  += clk-kona-setup.o
> >  obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
> >  obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
> >  obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o
> > clk-iproc-asiu.o
> > +obj-$(CONFIG_CLK_BCM2835)  += clk-bcm2711-dvp.o
> >  obj-$(CONFIG_CLK_BCM2835)  += clk-bcm2835.o
> >  obj-$(CONFIG_CLK_BCM2835)  += clk-bcm2835-aux.o
> >  obj-$(CONFIG_CLK_RASPBERRYPI)  += clk-raspberrypi.o
> > diff --git a/drivers/clk/bcm/clk-bcm2711-dvp.c 
> > b/drivers/clk/bcm/clk-bcm2711-
> > dvp.c
> > new file mode 100644
> > index ..c1c4b5857d32
> > --- /dev/null
> > +++ b/drivers/clk/bcm/clk-bcm2711-dvp.c
> > @@ -0,0 +1,127 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +// Copyright 2020 Cerno
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define DVP_HT_RPI_SW_INIT 0x04
> > +#define DVP_HT_RPI_MISC_CONFIG 0x08
> > +
> > +#define NR_CLOCKS  2
> > +#define NR_RESETS  6
> > +
> > +struct clk_dvp {
> > +   struct clk_hw_onecell_data  *data;
> > +   struct reset_simple_datareset;
> > +};
> > +
> > +static const struct clk_parent_data clk_dvp_parent = {
> > +   .index  = 0,
> > +};
> > +
> > +static int clk_dvp_probe(struct platform_device *pdev)
> > +{
> > +   struct clk_hw_onecell_data *data;
> > +   struct resource *res;
> > +   struct clk_dvp *dvp;
> > +   void __iomem *base;
> > +   int ret;
> > +
> > +   dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
> > +   if (!dvp)
> > +   return -ENOMEM;
> > +   platform_set_drvdata(pdev, dvp);
> > +
> > +   dvp->data = devm_kzalloc(&pdev->dev,
> > +struct_size(dvp->data, hws, NR_CLOCKS),
> > +GFP_KERNEL);
> > +   if (!dvp->data)
> > +   return -ENOMEM;
> > +   data = dvp->data;
> > +
> > +   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +   base = devm_ioremap_resource(&pdev->dev, res);
> 
> I think the cool function to use these days is
> devm_platform_get_and_ioremap_resource().

i'll change it, thanks!
Maxime


signature.asc
Description: PGP signature
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 32/39] memory: tegra20-emc: Create tegra20-devfreq device

2020-06-07 Thread Dmitry Osipenko
The tegra20-devfreq driver provides memory frequency scaling functionality
and it uses EMC clock for the scaling. Since tegra20-devfreq is a software
driver, the device for the driver needs to be created manually. Let's do
it from EMC driver since it provides the clk rate-change functionality.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra20-emc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index 2281bf9b784b..6dfd9807e042 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -882,6 +882,9 @@ static int tegra_emc_probe(struct platform_device *pdev)
err);
}
 
+   if (IS_ENABLED(CONFIG_ARM_TEGRA20_DEVFREQ))
+   platform_device_register_simple("tegra20-devfreq", -1, NULL, 0);
+
/*
 * Don't allow the kernel module to be unloaded. Unloading adds some
 * extra complexity which doesn't really worth the effort in a case of
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v5 0/8] drm: rcar-du: Add Color Management Module (CMM)

2020-06-07 Thread Eugeniu Rosca
Hi Jacopo,

On Fri, Jun 05, 2020 at 03:29:00PM +0200, Jacopo Mondi wrote:
> On Wed, May 27, 2020 at 09:15:55AM +0200, Eugeniu Rosca wrote:
> > Could you kindly share the cross compilation steps for your kmsxx fork?
> 
> I usually build it on the target :)

Interesting approach. With ARM getting more and more potent, why not? :)

> 
> > Just out of curiosity, have you ever tried to pull the display's HDMI
> > cable while reading from CM2_LUT_TBL?
> 
> Ahem, not really :) Did I get you right, you mean disconnecting the
> HDMI cable from the board ?

Right.

> >
> > At least with the out-of-tree CMM implementation [*], this sends the
> > R-Car3 reference targets into an unrecoverable freeze, with no lockup
> > reported by the kernel (i.e. looks like an serious HW issue).
> >
> > >
> > > CMM functionalities are retained between suspend/resume cycles (tested 
> > > with
> > > suspend-to-idle) without requiring a re-programming of the LUT tables.
> >
> > Hmm. Is this backed up by any statement in the HW User's manual?
> > This comes in contrast with the original Renesas CMM implementation [**]
> > which does make use of suspend (where the freeze actually happens).
> >
> > Can we infer, based on your statement, that we could also get rid of
> > the suspend callback in [**]?
> 
> As Geert (thanks) explained what I've tested with is suspend-to-idle,
> which retains the state of the LUT tables (and I assume other
> not-yet-implemented CMM features, like CLU). I recall the out-of-tree
> driver has suspend/resume routines but I never really tested that.

I see. JFYI, there is a flaw in the suspend handling in the out-of-tree
CMM patch [*], which renders the SoC unresponsive on HDMI hotplug. The
fix is currently under review. Hopefully it will make its way to [*]
in the nearest future. Just to keep in mind for the moment when CMM
s2ram will become a mainline feature.

> >
> > [*] https://github.com/renesas-rcar/du_cmm
> > [**] 
> > https://github.com/renesas-rcar/du_cmm/blob/c393ed49834bdbc/meta-rcar-gen3/recipes-kernel/linux/linux-renesas/0001-drm-rcar-du-Add-DU-CMM-support.patch#L1912

-- 
Best regards,
Eugeniu Rosca
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 2/4] gpu/drm: Add SPI DBI host driver

2020-06-07 Thread Paul Cercueil
This driver will register a DBI host driver for panels connected over
SPI.

For now, only DBI type c3 is supported, which is a SPI protocol with 8
bits per word, with the data/command information carried by a separate
GPIO.

Signed-off-by: Paul Cercueil 
---
 drivers/gpu/drm/bridge/Kconfig   |   8 ++
 drivers/gpu/drm/bridge/Makefile  |   1 +
 drivers/gpu/drm/bridge/dbi-spi.c | 159 +++
 3 files changed, 168 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/dbi-spi.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index aaed2347ace9..61587bc4d6e6 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -180,6 +180,14 @@ config DRM_TI_TPD12S015
  Texas Instruments TPD12S015 HDMI level shifter and ESD protection
  driver.
 
+config DRM_MIPI_DBI_SPI
+   tristate "SPI host support for MIPI DBI"
+   depends on OF && SPI
+   select DRM_MIPI_DSI
+   select DRM_MIPI_DBI
+   help
+ Driver to support DBI over SPI.
+
 source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
 source "drivers/gpu/drm/bridge/adv7511/Kconfig"
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 6fb062b5b0f0..17fdf7de498d 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
 obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
 obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
 obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o
+obj-$(CONFIG_DRM_MIPI_DBI_SPI) += dbi-spi.o
 
 obj-y += analogix/
 obj-y += synopsys/
diff --git a/drivers/gpu/drm/bridge/dbi-spi.c b/drivers/gpu/drm/bridge/dbi-spi.c
new file mode 100644
index ..c790514b7372
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dbi-spi.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MIPI Display Bus Interface (DBI) SPI support
+ *
+ * Copyright 2016 Noralf Trønnes
+ * Copyright 2020 Paul Cercueil 
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+struct dbi_spi {
+   struct mipi_dsi_host host;
+   struct mipi_dsi_host_ops host_ops;
+
+   struct spi_device *spi;
+   struct gpio_desc *dc;
+   struct mutex cmdlock;
+};
+
+static inline struct dbi_spi *host_to_dbi_spi(struct mipi_dsi_host *host)
+{
+   return container_of(host, struct dbi_spi, host);
+}
+
+static ssize_t dbi_spi_transfer(struct mipi_dsi_host *host,
+   const struct mipi_dsi_msg *msg)
+{
+   struct dbi_spi *dbi = host_to_dbi_spi(host);
+   struct spi_device *spi = dbi->spi;
+   const u8 *buf = msg->tx_buf;
+   unsigned int bpw = 8;
+   u32 speed_hz;
+   ssize_t ret;
+
+   /* for now we only support sending messages, not receiving */
+   if (msg->rx_len)
+   return -ENOTSUPP;
+
+   gpiod_set_value_cansleep(dbi->dc, 0);
+
+   speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
+   ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, buf, 1);
+   if (ret || msg->tx_len == 1)
+   return ret;
+
+   if (buf[0] == MIPI_DCS_WRITE_MEMORY_START)
+   bpw = 16;
+
+   gpiod_set_value_cansleep(dbi->dc, 1);
+   speed_hz = mipi_dbi_spi_cmd_max_speed(spi, msg->tx_len - 1);
+
+   ret = mipi_dbi_spi_transfer(spi, speed_hz, bpw,
+   &buf[1], msg->tx_len - 1);
+   if (ret)
+   return ret;
+
+   return msg->tx_len;
+}
+
+static int dbi_spi_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *dsi)
+{
+   return 0; /* Nothing to do */
+}
+
+static int dbi_spi_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *dsi)
+{
+   return 0; /* Nothing to do */
+}
+
+static void dbi_spi_host_unregister(void *d)
+{
+   mipi_dsi_host_unregister(d);
+}
+
+static int dbi_spi_probe(struct spi_device *spi)
+{
+   struct device *dev = &spi->dev;
+   struct mipi_dsi_device_info info = { };
+   struct mipi_dsi_device *dsi;
+   struct dbi_spi *dbi;
+   int ret;
+
+   dbi = devm_kzalloc(dev, sizeof(*dbi), GFP_KERNEL);
+   if (!dbi)
+   return -ENOMEM;
+
+   /* Only DBI Type C3 supported for now */
+   dbi->host.bus_types = MIPI_DEVICE_TYPE_DBI_SPI_MODE3;
+
+   dbi->host.dev = dev;
+   dbi->host.ops = &dbi->host_ops;
+   dbi->spi = spi;
+   spi_set_drvdata(spi, dbi);
+
+   dbi->dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+   if (IS_ERR(dbi->dc)) {
+   dev_err(dev, "Failed to get gpio 'dc'\n");
+   return PTR_ERR(dbi->dc);
+   }
+
+   dbi->host_ops.transfer = dbi_spi_transfer;
+   dbi->host_ops.attach = dbi_spi_attach;
+   dbi->host_ops.detach = dbi_spi_detach;
+
+   mutex_init(&dbi->cmdlock);
+
+   ret = mipi_dsi_host_register(&dbi->host);
+   if (ret) {
+   dev_err(dev, "Un

[PATCH v3 17/39] PM / devfreq: tegra20: Relax Kconfig dependency

2020-06-07 Thread Dmitry Osipenko
The Tegra EMC driver now could be compiled as a loadable kernel module.
Currently devfreq driver depends on the EMC/MC drivers in Kconfig, and
thus, devfreq is forced to be a kernel module if EMC is compiled as a
module. This build dependency could be relaxed since devfreq driver
checks MC/EMC presence on probe, allowing kernel configuration where
devfreq is a built-in driver and EMC driver is a loadable module.
This change puts Tegra20 devfreq Kconfig entry on a par with the Tegra30
devfreq entry.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 37dc40d1fcfb..0ee36ae2fa79 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -123,7 +123,7 @@ config ARM_TEGRA_DEVFREQ
 
 config ARM_TEGRA20_DEVFREQ
tristate "NVIDIA Tegra20 DEVFREQ Driver"
-   depends on (TEGRA_MC && TEGRA20_EMC) || COMPILE_TEST
+   depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST
depends on COMMON_CLK
select DEVFREQ_GOV_SIMPLE_ONDEMAND
help
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 02/39] clk: tegra: Remove Memory Controller lock

2020-06-07 Thread Dmitry Osipenko
The shared Memory Controller lock isn't needed since the time when
Memory Clock was made read-only. The lock could be removed safely now.
Hence let's remove it, this will help a tad to make further patches
cleaner.

Signed-off-by: Dmitry Osipenko 
---
 drivers/clk/tegra/clk-divider.c  | 4 ++--
 drivers/clk/tegra/clk-tegra114.c | 6 ++
 drivers/clk/tegra/clk-tegra124.c | 7 ++-
 drivers/clk/tegra/clk-tegra20.c  | 3 +--
 drivers/clk/tegra/clk-tegra30.c  | 3 +--
 drivers/clk/tegra/clk.h  | 2 +-
 6 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 38daf483ddf1..56adb01638cc 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -177,10 +177,10 @@ static const struct clk_div_table mc_div_table[] = {
 };
 
 struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
- void __iomem *reg, spinlock_t *lock)
+ void __iomem *reg)
 {
return clk_register_divider_table(NULL, name, parent_name,
  CLK_IS_CRITICAL,
  reg, 16, 1, CLK_DIVIDER_READ_ONLY,
- mc_div_table, lock);
+ mc_div_table, NULL);
 }
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index bc9e47a4cb60..ca8d9737d301 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -134,7 +134,6 @@ static DEFINE_SPINLOCK(pll_d_lock);
 static DEFINE_SPINLOCK(pll_d2_lock);
 static DEFINE_SPINLOCK(pll_u_lock);
 static DEFINE_SPINLOCK(pll_re_lock);
-static DEFINE_SPINLOCK(emc_lock);
 
 static struct div_nmp pllxc_nmp = {
.divm_shift = 0,
@@ -1050,10 +1049,9 @@ static __init void tegra114_periph_clk_init(void __iomem 
*clk_base,
   ARRAY_SIZE(mux_pllmcp_clkm),
   CLK_SET_RATE_NO_REPARENT,
   clk_base + CLK_SOURCE_EMC,
-  29, 3, 0, &emc_lock);
+  29, 3, 0, NULL);
 
-   clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
-   &emc_lock);
+   clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC);
clks[TEGRA114_CLK_MC] = clk;
 
clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base,
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index e931319dcc9d..0c956e14b9ca 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -126,7 +126,6 @@ static DEFINE_SPINLOCK(pll_d_lock);
 static DEFINE_SPINLOCK(pll_e_lock);
 static DEFINE_SPINLOCK(pll_re_lock);
 static DEFINE_SPINLOCK(pll_u_lock);
-static DEFINE_SPINLOCK(emc_lock);
 static DEFINE_SPINLOCK(sor0_lock);
 
 /* possible OSC frequencies in Hz */
@@ -1050,8 +1049,7 @@ static __init void tegra124_periph_clk_init(void __iomem 
*clk_base,
 periph_clk_enb_refcnt);
clks[TEGRA124_CLK_DSIB] = clk;
 
-   clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
-   &emc_lock);
+   clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC);
clks[TEGRA124_CLK_MC] = clk;
 
/* cml0 */
@@ -1518,8 +1516,7 @@ static void __init tegra124_132_clock_init_post(struct 
device_node *np)
  tegra124_reset_deassert);
tegra_add_of_provider(np, of_clk_src_onecell_get);
 
-   clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np,
-   &emc_lock);
+   clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np, NULL);
 
tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
 
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 3efc651b42e3..2f8b6de4198f 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -802,8 +802,7 @@ static void __init tegra20_periph_clk_init(void)
 
clks[TEGRA20_CLK_EMC] = clk;
 
-   clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
-   NULL);
+   clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC);
clks[TEGRA20_CLK_MC] = clk;
 
/* dsi */
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 37244a7e68c2..88e8c485f8ae 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -1042,8 +1042,7 @@ static void __init tegra30_periph_clk_init(void)
 
clks[TEGRA30_CLK_EMC] = clk;
 
-   clk = tegra_clk_register_mc("mc", "emc", clk_base + CLK_SOURCE_EMC,
-   NULL);
+   clk = tegra_clk_register_mc("mc",

[PATCH v3 01/39] clk: Export clk_hw_reparent()

2020-06-07 Thread Dmitry Osipenko
We're going to turn Tegra124 Memory Controller driver into a loadable
kernel module. The driver uses clk_hw_reparent(), which isn't an exported
kernel symbol. Let's export that function in order to allow modularization
of the Tegra driver.

Signed-off-by: Dmitry Osipenko 
---
 drivers/clk/clk.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 3f588ed06ce3..2fa6394d9a1b 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2439,6 +2439,7 @@ void clk_hw_reparent(struct clk_hw *hw, struct clk_hw 
*new_parent)
 
clk_core_reparent(hw->core, !new_parent ? NULL : new_parent->core);
 }
+EXPORT_SYMBOL_GPL(clk_hw_reparent);
 
 /**
  * clk_has_parent - check if a clock is a possible parent for another
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 15/39] PM / devfreq: tegra30: Add error messages to tegra_devfreq_target()

2020-06-07 Thread Dmitry Osipenko
It's useful to now when something goes wrong instead of failing silently,
so let's add error messages to tegra_devfreq_target() to prevent situation
where it fails silently.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra30-devfreq.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/devfreq/tegra30-devfreq.c 
b/drivers/devfreq/tegra30-devfreq.c
index 13f93c6038ab..a03fb16c5c4c 100644
--- a/drivers/devfreq/tegra30-devfreq.c
+++ b/drivers/devfreq/tegra30-devfreq.c
@@ -641,12 +641,16 @@ static int tegra_devfreq_target(struct device *dev, 
unsigned long *freq,
dev_pm_opp_put(opp);
 
err = clk_set_min_rate(tegra->emc_clock, rate * KHZ);
-   if (err)
+   if (err) {
+   dev_err(dev, "Failed to set min rate: %d\n", err);
return err;
+   }
 
err = clk_set_rate(tegra->emc_clock, 0);
-   if (err)
+   if (err) {
+   dev_err(dev, "Failed to set rate: %d\n", err);
goto restore_min_rate;
+   }
 
return 0;
 
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 28/39] memory: tegra: Register as interconnect provider

2020-06-07 Thread Dmitry Osipenko
Now memory controller is a memory interconnection provider. This allows us
to use interconnect API in order to change memory configuration.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/mc.c | 118 ++
 drivers/memory/tegra/mc.h |   8 +++
 include/soc/tegra/mc.h|   3 +
 3 files changed, 129 insertions(+)

diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index 772aa021b5f6..645b5fd1e14b 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -594,6 +594,117 @@ static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, 
void *data)
return IRQ_HANDLED;
 }
 
+static int tegra_mc_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+   return 0;
+}
+
+static int tegra_mc_icc_aggregate(struct icc_node *node,
+ u32 tag, u32 avg_bw, u32 peak_bw,
+ u32 *agg_avg, u32 *agg_peak)
+{
+   *agg_avg = min((u64)avg_bw + (*agg_avg), (u64)U32_MAX);
+   *agg_peak = max(*agg_peak, peak_bw);
+
+   return 0;
+}
+
+/*
+ * Memory Controller (MC) has few Memory Clients that are issuing memory
+ * bandwidth allocation requests to the MC interconnect provider. The MC
+ * provider aggregates the requests and then sends the aggregated request
+ * up to the External Memory Controller (EMC) interconnect provider which
+ * re-configures hardware interface to External Memory (EMEM) in accordance
+ * to the required bandwidth. Each MC interconnect node represents an
+ * individual Memory Client.
+ *
+ * Memory interconnect topology:
+ *
+ *   ++
+ * ++||
+ * | TEXSRD +--->+|
+ * ++||
+ *   ||+-++--+
+ *...| MC +--->+ EMC +--->+ EMEM |
+ *   ||+-++--+
+ * ++||
+ * | DISP.. +--->+|
+ * ++||
+ *   ++
+ */
+static int tegra_mc_interconnect_setup(struct tegra_mc *mc)
+{
+   struct icc_onecell_data *data;
+   struct icc_node *node;
+   unsigned int num_nodes;
+   unsigned int i;
+   int err;
+
+   /* older device-trees don't have interconnect properties */
+   if (!of_find_property(mc->dev->of_node, "#interconnect-cells", NULL))
+   return 0;
+
+   num_nodes = mc->soc->num_clients;
+
+   data = devm_kzalloc(mc->dev, struct_size(data, nodes, num_nodes),
+   GFP_KERNEL);
+   if (!data)
+   return -ENOMEM;
+
+   mc->provider.dev = mc->dev;
+   mc->provider.set = tegra_mc_icc_set;
+   mc->provider.data = data;
+   mc->provider.xlate = of_icc_xlate_onecell;
+   mc->provider.aggregate = tegra_mc_icc_aggregate;
+
+   err = icc_provider_add(&mc->provider);
+   if (err)
+   return err;
+
+   /* create Memory Controller node */
+   node = icc_node_create(TEGRA_ICC_MC);
+   err = PTR_ERR_OR_ZERO(node);
+   if (err)
+   goto del_provider;
+
+   node->name = "Memory Controller";
+   icc_node_add(node, &mc->provider);
+
+   /* link Memory Controller to External Memory Controller */
+   err = icc_link_create(node, TEGRA_ICC_EMC);
+   if (err)
+   goto remove_nodes;
+
+   for (i = 0; i < num_nodes; i++) {
+   /* create MC client node */
+   node = icc_node_create(mc->soc->clients[i].id);
+   err = PTR_ERR_OR_ZERO(node);
+   if (err)
+   goto remove_nodes;
+
+   node->name = mc->soc->clients[i].name;
+   icc_node_add(node, &mc->provider);
+
+   /* link Memory Client to Memory Controller */
+   err = icc_link_create(node, TEGRA_ICC_MC);
+   if (err)
+   goto remove_nodes;
+
+   data->nodes[i] = node;
+   }
+   data->num_nodes = num_nodes;
+
+   return 0;
+
+remove_nodes:
+   icc_nodes_remove(&mc->provider);
+
+del_provider:
+   icc_provider_del(&mc->provider);
+
+   return err;
+}
+
 static int tegra_mc_probe(struct platform_device *pdev)
 {
struct resource *res;
@@ -702,6 +813,13 @@ static int tegra_mc_probe(struct platform_device *pdev)
}
}
 
+   if (IS_ENABLED(CONFIG_INTERCONNECT)) {
+   err = tegra_mc_interconnect_setup(mc);
+   if (err)
+   dev_err(&pdev->dev, "failed to initialize ICC: %d\n",
+   err);
+   }
+
return 0;
 }
 
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index afa3ba45c9e6..abeb6a2cc36a 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -115,4 +115,12 @@ extern const struct tegra_mc_soc tegra132_mc_soc;
 extern const struct tegra_mc_soc tegra210_mc_soc;
 #endif
 
+/*
+ * These IDs are for internal use of Tegra's ICC, the values are chosen
+ * such that they don't 

[RFC PATCH 1/4] gpu/drm: dsi: Let host and device specify supported bus

2020-06-07 Thread Paul Cercueil
The current MIPI DSI framework can very well be used to support MIPI DBI
panels. In order to add support for the various bus types supported by
DBI, the DRM panel drivers should specify the bus type they will use,
and the DSI host drivers should specify the bus types they are
compatible with.

The DSI host driver can then use the information provided by the DBI/DSI
device driver, such as the bus type and the number of lanes, to
configure its hardware properly.

Signed-off-by: Paul Cercueil 
---
 drivers/gpu/drm/drm_mipi_dsi.c |  9 +
 include/drm/drm_mipi_dsi.h | 12 
 2 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 55531895dde6..fe0d874d1594 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -282,6 +282,9 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host)
 {
struct device_node *node;
 
+   if (WARN_ON_ONCE(!host->bus_types))
+   host->bus_types = MIPI_DEVICE_TYPE_DSI;
+
for_each_available_child_of_node(host->dev->of_node, node) {
/* skip nodes without reg property */
if (!of_find_property(node, "reg", NULL))
@@ -324,6 +327,12 @@ int mipi_dsi_attach(struct mipi_dsi_device *dsi)
 {
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
 
+   if (WARN_ON_ONCE(!dsi->bus_type))
+   dsi->bus_type = MIPI_DEVICE_TYPE_DSI;
+
+   if (!(dsi->bus_type & dsi->host->bus_types))
+   return -ENOTSUPP;
+
if (!ops || !ops->attach)
return -ENOSYS;
 
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 360e6377e84b..65d2961fc054 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -63,6 +63,14 @@ struct mipi_dsi_packet {
 int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
   const struct mipi_dsi_msg *msg);
 
+/* MIPI bus types */
+#define MIPI_DEVICE_TYPE_DSI   BIT(0)
+#define MIPI_DEVICE_TYPE_DBI_SPI_MODE1 BIT(1)
+#define MIPI_DEVICE_TYPE_DBI_SPI_MODE2 BIT(2)
+#define MIPI_DEVICE_TYPE_DBI_SPI_MODE3 BIT(3)
+#define MIPI_DEVICE_TYPE_DBI_M6800 BIT(4)
+#define MIPI_DEVICE_TYPE_DBI_I8080 BIT(5)
+
 /**
  * struct mipi_dsi_host_ops - DSI bus operations
  * @attach: attach DSI device to DSI host
@@ -94,11 +102,13 @@ struct mipi_dsi_host_ops {
  * struct mipi_dsi_host - DSI host device
  * @dev: driver model device node for this DSI host
  * @ops: DSI host operations
+ * @bus_types: Bitmask of supported MIPI bus types
  * @list: list management
  */
 struct mipi_dsi_host {
struct device *dev;
const struct mipi_dsi_host_ops *ops;
+   unsigned int bus_types;
struct list_head list;
 };
 
@@ -162,6 +172,7 @@ struct mipi_dsi_device_info {
  * @host: DSI host for this peripheral
  * @dev: driver model device node for this peripheral
  * @name: DSI peripheral chip type
+ * @bus_type: MIPI bus type (MIPI_DEVICE_TYPE_DSI/...)
  * @channel: virtual channel assigned to the peripheral
  * @format: pixel format for video mode
  * @lanes: number of active data lanes
@@ -178,6 +189,7 @@ struct mipi_dsi_device {
struct device dev;
 
char name[DSI_DEV_NAME_SIZE];
+   unsigned int bus_type;
unsigned int channel;
unsigned int lanes;
enum mipi_dsi_pixel_format format;
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH v3 09/13] device core: Introduce multiple dma pfn offsets

2020-06-07 Thread Nicolas Saenz Julienne
Hi Christoph,
a question arouse, is there a real value to dealing with PFNs (as opposed to
real addresses) in the core DMA code/structures? I see that in some cases it
eases interacting with mm, but the overwhelming usage of say,
dev->dma_pfn_offset, involves shifting it.

Hi Jim,
On Thu, 2020-06-04 at 14:01 -0400, Jim Quinlan wrote:
> Hi Nicolas,

[...]

> > I understand the need for dev to be around, devm_*() is key. But also it's
> > important to keep the functions on purpose. And if of_dma_get_range() starts
> > setting ranges it calls, for the very least, for a function rename. Although
> > I'd rather split the parsing and setting of ranges as mentioned earlier.
> > That
> > said, I get that's a more drastic move.
> 
> I agree with you.  I could do this from device.c:
> 
> of_dma_get_num_ranges(..., &num_ranges); /* new function */
> r = devm_kcalloc(dev, num_ranges + 1, sizeof(*r), GFP_KERNEL);
> of_dma_get_range(np, &dma_addr, &paddr, &size, r, num_ranges);
> 
> The problem here is that there could be four ranges, all with
> offset=0.  My current code would optimize this case out but the above
> would have us holding useless memory and looping through the four
> ranges on every dma <=> phys conversion only to add 0.

Point taken. Ultimately it's setting the device's dma ranges in
of_dma_get_range() that was really bothering me, so if we have to pass the
device pointer for allocations, be it.

> > Talking about drastic moves. How about getting rid of the concept of
> > dma_pfn_offset for drivers altogether. Let them provide
> > dma_pfn_offset_regions
> > (even when there is only one). I feel it's conceptually nicer, as you'd be
> > dealing only in one currency, so to speak, and you'd centralize the bus DMA
> > ranges setter function which is always easier to maintain.
> Do you agree that we have to somehow hang this info on the struct
> device structure?  Because in the dma2phys() and phys2dma() all you
> have is the dev parameter.  I don't see how this  can be done w/o
> involving dev.

Sorry I didn't make myself clear here. What bothers me is having two functions
setting the same device parameter trough different means, I'd be happy to get
rid of attach_uniform_dma_pfn_offset(), and always use the same function to set
a device's bus dma regions. Something the likes of this comes to mind:

dma_attach_pfn_offset_region(struct device *dev, struct dma_pfn_offset_regions 
*r)

We could maybe use some helper macros for the linear case. But that's the gist
of it.

Also, it goes hand in hand with the comment below. Why having a special case
for non sparse DMA offsets in struct dma_pfn_offset_regions? The way I see it,
in this case, code simplicity is more interesting than a small optimization.

> > I'd go as far as not creating a special case for uniform offsets. Let just
> > set
> > cpu_end and dma_end to -1 so we always get a match. It's slightly more
> > compute
> > heavy, but I don't think it's worth the optimization.
> Well, there are two subcases here.  One where we do know the bounds
> and one where we do not.  I suppose for the latter I could have the
> drivers calling it with begin=0 and end=~(dma_addr_t)0.  Let me give
> this some thought...
> 
> > Just my two cents :)
> 
> Worth much more than $0.02 IMO :-)

BTW, would you consider renaming the DMA offset struct to something simpler
like, struct bus_dma_region? It complements 'dev->bus_dma_limit' better IMO.

> BTW, I tried putting the "if (dev->dma_pfn_offset_map)" clause inside
> the inline functions but the problem is that it slows the fastpath;
> consider the following code from dma-direct.h
> 
> if (dev->dma_pfn_offset_map) {
> unsigned long dma_pfn_offset =
dma_pfn_offset_from_phys_addr(dev, paddr);
> 
> dev_addr -= ((dma_addr_t)dma_pfn_offset << PAGE_SHIFT);
> }
> return dev_addr;
> 
> becomes
> 
> unsigned long dma_pfn_offset = dma_pfn_offset_from_phys_addr(dev,
paddr);
> 
> dev_addr -= ((dma_addr_t)dma_pfn_offset << PAGE_SHIFT);
> return dev_addr;
> 
> So those configurations that  have no dma_pfn_offsets are doing an
> unnecessary shift and add.

Fair enough. Still not a huge difference, but I see the value being the most
common case.

Regards,
Nicolas



signature.asc
Description: This is a digitally signed message part
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 22/39] dt-bindings: host1x: Document new interconnect properties

2020-06-07 Thread Dmitry Osipenko
Most of Host1x devices have at least one memory client. These clients
are directly connected to the memory controller. The new interconnect
properties represent the memory client's connection to the memory
controller.

Signed-off-by: Dmitry Osipenko 
---
 .../display/tegra/nvidia,tegra20-host1x.txt   | 68 +++
 1 file changed, 68 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt 
b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
index 47319214b5f6..ab4fbee7bccf 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
@@ -20,6 +20,10 @@ Required properties:
 - reset-names: Must include the following entries:
   - host1x
 
+Each host1x client module having to perform DMA through the Memory Controller
+should have the interconnect endpoints set to the Memory Client and External
+Memory respectively.
+
 The host1x top-level node defines a number of children, each representing one
 of the following host1x client modules:
 
@@ -36,6 +40,12 @@ of the following host1x client modules:
   - reset-names: Must include the following entries:
 - mpe
 
+  Optional properties:
+  - interconnects: Must contain entry for the MPE memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
+
 - vi: video input
 
   Required properties:
@@ -65,6 +75,12 @@ of the following host1x client modules:
   - power-domains: Must include sor powergate node as csicil is in
 SOR partition.
 
+  Optional properties:
+  - interconnects: Must contain entry for the VI memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
+
 - epp: encoder pre-processor
 
   Required properties:
@@ -78,6 +94,12 @@ of the following host1x client modules:
   - reset-names: Must include the following entries:
 - epp
 
+  Optional properties:
+  - interconnects: Must contain entry for the EPP memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
+
 - isp: image signal processor
 
   Required properties:
@@ -91,6 +113,12 @@ of the following host1x client modules:
   - reset-names: Must include the following entries:
 - isp
 
+  Optional properties:
+  - interconnects: Must contain entry for the ISP memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
+
 - gr2d: 2D graphics engine
 
   Required properties:
@@ -104,6 +132,12 @@ of the following host1x client modules:
   - reset-names: Must include the following entries:
 - 2d
 
+  Optional properties:
+  - interconnects: Must contain entry for the GR2D memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
+
 - gr3d: 3D graphics engine
 
   Required properties:
@@ -122,6 +156,12 @@ of the following host1x client modules:
 - 3d
 - 3d2 (Only required on SoCs with two 3D clocks)
 
+  Optional properties:
+  - interconnects: Must contain entry for the GR3D memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
+
 - dc: display controller
 
   Required properties:
@@ -149,6 +189,10 @@ of the following host1x client modules:
   - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
   - nvidia,edid: supplies a binary EDID blob
   - nvidia,panel: phandle of a display panel
+  - interconnects: Must contain entry for the DC memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+available memory clients, see MEMORY CONTROLLER section.
 
 - hdmi: High Definition Multimedia Interface
 
@@ -297,6 +341,12 @@ of the following host1x client modules:
   - reset-names: Must include the following entries:
 - vic
 
+  Optional properties:
+  - interconnects: Must contain entry for the VIC memory clients.
+  - interconnect-names: Must include name of the interconnect path for each
+interconnect entry. Consult TRM documentation for information about
+ava

Re: [PATCH v4 08/12] device core: Introduce multiple dma pfn offsets

2020-06-07 Thread Andy Shevchenko
On Fri, Jun 05, 2020 at 05:26:48PM -0400, Jim Quinlan wrote:
> The new field in struct device 'dma_pfn_offset_map' is used to facilitate
> the use of single or multiple pfn offsets between cpu addrs and dma addrs.
> It subsumes the role of dev->dma_pfn_offset -- a uniform offset.
> 
> The function of_dma_get_range() has been modified to take two additional
> arguments: the "map", which is an array that holds the information
> regarding the pfn offset regions, and map_size, which is the size in bytes
> of the map array.
> 
> of_dma_configure() is the typical manner to set pfn offsets but there are a
> number of ad hoc assignments to dev->dma_pfn_offset in the kernel driver
> code.  These cases now invoke the function
> dma_attach_uniform_pfn_offset(dev, pfn_offset).

...

> + int ret = dma_attach_uniform_pfn_offset
> + (dev, keystone_dma_pfn_offset);

It's strange indentation. Have you configured your editor correctly?
Seems to me as fit on one line.

> + dev_err(dev, "set dma_pfn_offset%08lx%s\n",
> + dev->dma_pfn_offset, ret ? " failed" : "");

...

> + *map_size = (num_ranges + 1) * sizeof(**map);
> + r = kzalloc(*map_size, GFP_KERNEL);

kcalloc()

> + if (!r)
> + return -ENOMEM;

...

> + r->pfn_offset = PFN_DOWN(range.cpu_addr)
> + - PFN_DOWN(range.bus_addr);

Ditto (indentation).

...


> + unsigned long dma_pfn_offset
> + = dma_pfn_offset_from_phys_addr(dev, paddr);

Ditto.

...

> + unsigned long dma_pfn_offset
> + = dma_pfn_offset_from_dma_addr(dev, dev_addr);

Ditto.

Check entire your series for a such, please!

-- 
With Best Regards,
Andy Shevchenko


___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 31/39] memory: tegra20-emc: Register as interconnect provider

2020-06-07 Thread Dmitry Osipenko
Now memory controller is a memory interconnection provider. This allows us
to use interconnect API in order to change memory configuration.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra20-emc.c | 115 +
 1 file changed, 115 insertions(+)

diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index 8d1967f4b4aa..2281bf9b784b 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -148,6 +149,7 @@ struct emc_timing {
 struct tegra_emc {
struct device *dev;
struct notifier_block clk_nb;
+   struct icc_provider provider;
struct clk *clk;
void __iomem *regs;
 
@@ -661,6 +663,112 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc)
emc, &tegra_emc_debug_max_rate_fops);
 }
 
+static inline struct tegra_emc *
+to_tegra_emc_provider(struct icc_provider *provider)
+{
+   return container_of(provider, struct tegra_emc, provider);
+}
+
+static struct icc_node *
+emc_of_icc_xlate(struct of_phandle_args *spec, void *data)
+{
+   struct icc_provider *provider = data;
+   struct icc_node *node;
+
+   /* External Memory is the only possible ICC route */
+   list_for_each_entry(node, &provider->nodes, node_list) {
+   if (node->id == TEGRA_ICC_EMEM)
+   return node;
+   }
+
+   return ERR_PTR(-EINVAL);
+}
+
+static int emc_icc_set(struct icc_node *src, struct icc_node *dst)
+{
+   struct tegra_emc *emc = to_tegra_emc_provider(dst->provider);
+   unsigned long long rate = icc_units_to_bps(dst->avg_bw);
+   unsigned int dram_data_bus_width_bytes = 4;
+   unsigned int ddr = 2;
+   int err;
+
+   do_div(rate, ddr * dram_data_bus_width_bytes);
+   rate = min_t(u64, rate, U32_MAX);
+
+   err = clk_set_min_rate(emc->clk, rate);
+   if (err)
+   return err;
+
+   err = clk_set_rate(emc->clk, rate);
+   if (err)
+   return err;
+
+   return 0;
+}
+
+static int emc_icc_aggregate(struct icc_node *node,
+u32 tag, u32 avg_bw, u32 peak_bw,
+u32 *agg_avg, u32 *agg_peak)
+{
+   *agg_avg = min((u64)avg_bw + (*agg_avg), (u64)U32_MAX);
+   *agg_peak = max(*agg_peak, peak_bw);
+
+   return 0;
+}
+
+static int tegra_emc_interconnect_init(struct tegra_emc *emc)
+{
+   struct icc_node *node;
+   int err;
+
+   /* older device-trees don't have interconnect properties */
+   if (!of_find_property(emc->dev->of_node, "#interconnect-cells", NULL))
+   return 0;
+
+   emc->provider.dev = emc->dev;
+   emc->provider.set = emc_icc_set;
+   emc->provider.data = &emc->provider;
+   emc->provider.xlate = emc_of_icc_xlate;
+   emc->provider.aggregate = emc_icc_aggregate;
+
+   err = icc_provider_add(&emc->provider);
+   if (err)
+   return err;
+
+   /* create External Memory Controller node */
+   node = icc_node_create(TEGRA_ICC_EMC);
+   err = PTR_ERR_OR_ZERO(node);
+   if (err)
+   goto del_provider;
+
+   node->name = "External Memory Controller";
+   icc_node_add(node, &emc->provider);
+
+   /* link External Memory Controller to External Memory (DRAM) */
+   err = icc_link_create(node, TEGRA_ICC_EMEM);
+   if (err)
+   goto remove_nodes;
+
+   /* create External Memory node */
+   node = icc_node_create(TEGRA_ICC_EMEM);
+   err = PTR_ERR_OR_ZERO(node);
+   if (err)
+   goto remove_nodes;
+
+   node->name = "External Memory (DRAM)";
+   icc_node_add(node, &emc->provider);
+
+   return 0;
+
+remove_nodes:
+   icc_nodes_remove(&emc->provider);
+
+del_provider:
+   icc_provider_del(&emc->provider);
+
+   return err;
+}
+
 static int tegra_emc_init_mc_timings(struct tegra_emc *emc)
 {
struct tegra_mc_timing *timing;
@@ -767,6 +875,13 @@ static int tegra_emc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, emc);
tegra_emc_debugfs_init(emc);
 
+   if (IS_ENABLED(CONFIG_INTERCONNECT)) {
+   err = tegra_emc_interconnect_init(emc);
+   if (err)
+   dev_err(&pdev->dev, "failed to initialize ICC: %d\n",
+   err);
+   }
+
/*
 * Don't allow the kernel module to be unloaded. Unloading adds some
 * extra complexity which doesn't really worth the effort in a case of
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 16/39] PM / devfreq: tegra20: Adjust clocks conversion ratio and polling interval

2020-06-07 Thread Dmitry Osipenko
The current conversion ratio results in a higher frequency than needed,
that is not very actual now since the Display Controller driver got
support for memory bandwidth management and hence memory frequency can
go lower now without bad consequences. Since memory freq now goes to a
lower rates, the responsiveness of interactive applications become worse
due to a quite high polling interval value that is currently set to 500ms.
Changing polling interval to 30ms results in a good responsiveness of the
system.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra20-devfreq.c | 14 +-
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/devfreq/tegra20-devfreq.c 
b/drivers/devfreq/tegra20-devfreq.c
index 249d0dc44f6c..7cdea4ba38f7 100644
--- a/drivers/devfreq/tegra20-devfreq.c
+++ b/drivers/devfreq/tegra20-devfreq.c
@@ -79,16 +79,12 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
 
/*
 * EMC_COUNT returns number of memory events, that number is lower
-* than the number of clocks. Conversion ratio of 1/8 results in a
-* bit higher bandwidth than actually needed, it is good enough for
-* the time being because drivers don't support requesting minimum
-* needed memory bandwidth yet.
-*
-* TODO: adjust the ratio value once relevant drivers will support
-* memory bandwidth management.
+* than the number of total EMC clocks over the sampling period.
+* The clocks number is converted to maximum possible number of
+* memory events using the ratio of 1/4.
 */
stat->busy_time = readl_relaxed(tegra->regs + MC_STAT_EMC_COUNT);
-   stat->total_time = readl_relaxed(tegra->regs + MC_STAT_EMC_CLOCKS) / 8;
+   stat->total_time = readl_relaxed(tegra->regs + MC_STAT_EMC_CLOCKS) / 4;
stat->current_frequency = clk_get_rate(tegra->emc_clock);
 
writel_relaxed(EMC_GATHER_CLEAR, tegra->regs + MC_STAT_CONTROL);
@@ -98,7 +94,7 @@ static int tegra_devfreq_get_dev_status(struct device *dev,
 }
 
 static struct devfreq_dev_profile tegra_devfreq_profile = {
-   .polling_ms = 500,
+   .polling_ms = 30,
.target = tegra_devfreq_target,
.get_dev_status = tegra_devfreq_get_dev_status,
 };
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 30/39] memory: tegra20-emc: Continue probing if timings are missing in device-tree

2020-06-07 Thread Dmitry Osipenko
EMC driver will become mandatory after turning it into interconnect
provider because interconnect users, like display controller driver, will
fail to probe using newer device-trees that have interconnect properties.
Thus make EMC driver to probe even if timings are missing in device-tree.

Signed-off-by: Dmitry Osipenko 
---
 drivers/memory/tegra/tegra20-emc.c | 34 ++
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/drivers/memory/tegra/tegra20-emc.c 
b/drivers/memory/tegra/tegra20-emc.c
index 79fdae042b57..8d1967f4b4aa 100644
--- a/drivers/memory/tegra/tegra20-emc.c
+++ b/drivers/memory/tegra/tegra20-emc.c
@@ -386,6 +386,11 @@ tegra_emc_find_node_by_ram_code(struct device *dev)
u32 value, ram_code;
int err;
 
+   if (of_get_child_count(dev->of_node) == 0) {
+   dev_info(dev, "device-tree doesn't have memory timings\n");
+   return NULL;
+   }
+
if (!of_property_read_bool(dev->of_node, "nvidia,use-ram-code"))
return of_node_get(dev->of_node);
 
@@ -454,6 +459,9 @@ static long emc_round_rate(unsigned long rate,
struct tegra_emc *emc = arg;
unsigned int i;
 
+   if (!emc->num_timings)
+   return clk_get_rate(emc->clk);
+
min_rate = min(min_rate, emc->timings[emc->num_timings - 1].rate);
 
for (i = 0; i < emc->num_timings; i++) {
@@ -691,13 +699,6 @@ static int tegra_emc_probe(struct platform_device *pdev)
struct tegra_emc *emc;
int irq, err;
 
-   /* driver has nothing to do in a case of memory timing absence */
-   if (of_get_child_count(pdev->dev.of_node) == 0) {
-   dev_info(&pdev->dev,
-"EMC device tree node doesn't have memory timings\n");
-   return 0;
-   }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "interrupt not specified\n");
@@ -705,23 +706,20 @@ static int tegra_emc_probe(struct platform_device *pdev)
return irq;
}
 
-   np = tegra_emc_find_node_by_ram_code(&pdev->dev);
-   if (!np)
-   return -EINVAL;
-
emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
-   if (!emc) {
-   of_node_put(np);
+   if (!emc)
return -ENOMEM;
-   }
 
emc->clk_nb.notifier_call = tegra_emc_clk_change_notify;
emc->dev = &pdev->dev;
 
-   err = tegra_emc_load_timings_from_dt(emc, np);
-   of_node_put(np);
-   if (err)
-   return err;
+   np = tegra_emc_find_node_by_ram_code(&pdev->dev);
+   if (np) {
+   err = tegra_emc_load_timings_from_dt(emc, np);
+   of_node_put(np);
+   if (err)
+   return err;
+   }
 
emc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(emc->regs))
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 11/39] PM / devfreq: tegra30: Silence deferred probe error

2020-06-07 Thread Dmitry Osipenko
Tegra EMC driver was turned into a regular kernel driver, it also could
be compiled as a loadable kernel module now. Hence EMC clock isn't
guaranteed to be available and clk_get("emc") may return -EPROBE_DEFER and
there is no good reason to spam KMSG with a error about missing EMC clock
in this case, so let's silence the deferred probe error.

Signed-off-by: Dmitry Osipenko 
---
 drivers/devfreq/tegra30-devfreq.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/devfreq/tegra30-devfreq.c 
b/drivers/devfreq/tegra30-devfreq.c
index e94a27804c20..423dd35c95b3 100644
--- a/drivers/devfreq/tegra30-devfreq.c
+++ b/drivers/devfreq/tegra30-devfreq.c
@@ -801,9 +801,12 @@ static int tegra_devfreq_probe(struct platform_device 
*pdev)
}
 
tegra->emc_clock = devm_clk_get(&pdev->dev, "emc");
-   if (IS_ERR(tegra->emc_clock)) {
-   dev_err(&pdev->dev, "Failed to get emc clock\n");
-   return PTR_ERR(tegra->emc_clock);
+   err = PTR_ERR_OR_ZERO(tegra->emc_clock);
+   if (err) {
+   if (err != -EPROBE_DEFER)
+   dev_err(&pdev->dev, "Failed to get emc clock: %d\n",
+   err);
+   return err;
}
 
err = platform_get_irq(pdev, 0);
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 00/39] Introduce memory interconnect for NVIDIA Tegra SoCs

2020-06-07 Thread Dmitry Osipenko
Hello,

This series brings initial support for memory interconnect to Tegra20 and
Tegra30 SoCs.

For the starter only display controllers are getting interconnect API
support, others could be supported later on. The display controllers
have the biggest demand for interconnect API right now because dynamic
memory frequency scaling can't be done safely without taking into account
bandwidth requirement from the displays.

Changelog:

v3: - Added acks from Rob Herring that were given to some of the v2 patches.

- Specified name of the TRM documentation chapter in the patch
  "dt-bindings: host1x: Document new interconnect properties", which was
  suggested by Rob Herring in the review comment to v2.

- Added patches that allow EMC drivers to be compiled as a loadable kernel
  modules. This came up during of the v2 review when Georgi Djakov pointed
  out that interconnect-core could be compiled as a kernel module. Please
  note that the Tegra124 EMC driver is compile-tested only, I don't have
  Tegra124 HW.

- In the review comment to [1] Stephen Boyd suggested that it will be
  better not to make changes to clk API, which was needed in order to
  avoid clashing of the interconnect driver with the devfreq in regards
  to memory clk-rate rounding.

  [1] 
https://patchwork.ozlabs.org/project/linux-tegra/patch/20200330231617.17079-3-dig...@gmail.com/

  Stephen Boyd suggested that instead we should provide OPP table via DT.
  I tried to investigate whether this could be done and turned out
  it's a bit complicated. Technically it should be doable, but:

1. For now we don't fully support voltage scaling of the CORE regulator
   and so OPP table in the DT isn't really needed today. We can
   generate table from the memory timings, which is what Tegra devfreq
   drivers already do.

2. The OPP table should be defined in the DT for the Memory Controller
   node and then its usage somehow should be shared by both interconnect
   and devfreq drivers. It's not obvious what's the best way to do it.

  So, it will be much better to postpone the DT OPP table addition
  until these questions are resolved. We can infer OPPs from the
  memory timings and we could get the memory rates from the memory
  driver directly, avoiding the problems induced by the clk API usage.
  This idea is implemented in v3, see these patches:

PM / devfreq: tegra20: Use MC timings for building OPP table
PM / devfreq: tegra30: Use MC timings for building OPP table

v2: - Instead of a single dma-mem interconnect path, the paths are now
  defined per memory client.

- The EMC provider now uses #interconnect-cells=<0>.

- Dropped Tegra124 because there is no enough information about how to
  properly calculate required EMC clock rate for it and I don't have
  hardware for testing. Somebody else will have to work on it.

- Moved interconnect providers code into drivers/memory/tegra/*.

- Added "Create tegra20-devfreq device" patch because interconnect
  is not very usable without the devfreq memory auto-scaling since
  memory freq will be fixed to the display's requirement.

Artur Świgoń (1):
  interconnect: Relax requirement in of_icc_get_from_provider()

Dmitry Osipenko (38):
  clk: Export clk_hw_reparent()
  clk: tegra: Remove Memory Controller lock
  clk: tegra: Export Tegra20 EMC kernel symbols
  memory: tegra20-emc: Make driver modular
  memory: tegra30-emc: Make driver modular
  memory: tegra124-emc: Make driver modular
  memory: tegra124-emc: Use devm_platform_ioremap_resource
  soc/tegra: fuse: Export tegra_read_ram_code()
  memory: tegra20-emc: Initialize MC timings
  PM / devfreq: tegra20: Silence deferred probe error
  PM / devfreq: tegra30: Silence deferred probe error
  PM / devfreq: tegra20: Use MC timings for building OPP table
  PM / devfreq: tegra30: Use MC timings for building OPP table
  PM / devfreq: tegra20: Add error messages to tegra_devfreq_target()
  PM / devfreq: tegra30: Add error messages to tegra_devfreq_target()
  PM / devfreq: tegra20: Adjust clocks conversion ratio and polling
interval
  PM / devfreq: tegra20: Relax Kconfig dependency
  dt-bindings: memory: tegra20: mc: Document new interconnect property
  dt-bindings: memory: tegra20: emc: Document new interconnect property
  dt-bindings: memory: tegra30: mc: Document new interconnect property
  dt-bindings: memory: tegra30: emc: Document new interconnect property
  dt-bindings: host1x: Document new interconnect properties
  dt-bindings: memory: tegra20: Add memory client IDs
  dt-bindings: memory: tegra30: Add memory client IDs
  ARM: tegra: Add interconnect properties to Tegra20 device-tree
  ARM: tegra: Add interconnect properties to Tegra30 device-tree
  memory: tegra: Register as interconnect provider
  memory: tegra20-emc: Use devm_platform_ioremap_resource
  memory: teg

Re: [PATCH v3 070/105] drm/vc4: hdmi: rework connectors and encoders

2020-06-07 Thread Maxime Ripard
Hi Stefan,

On Wed, Jun 03, 2020 at 07:32:30PM +0200, Stefan Wahren wrote:
> Am 02.06.20 um 17:54 schrieb Maxime Ripard:
> > On Wed, May 27, 2020 at 11:41:24AM -0700, Eric Anholt wrote:
> >> On Wed, May 27, 2020 at 8:51 AM Maxime Ripard  wrote:
> >>> the vc4_hdmi driver has some custom structures to hold the data it needs 
> >>> to
> >>> associate with the drm_encoder and drm_connector structures.
> >>>
> >>> However, it allocates them separately from the vc4_hdmi structure which
> >>> makes it more complicated than it needs to be.
> >>>
> >>> Move those structures to be contained by vc4_hdmi and update the code
> >>> accordingly.
> >>
> >>> @@ -1220,7 +1219,7 @@ static int vc4_hdmi_bind(struct device *dev, struct 
> >>> device *master, void *data)
> >>> struct drm_device *drm = dev_get_drvdata(master);
> >>> struct vc4_dev *vc4 = drm->dev_private;
> >>> struct vc4_hdmi *hdmi;
> >>> -   struct vc4_hdmi_encoder *vc4_hdmi_encoder;
> >>> +   struct drm_encoder *encoder;
> >>> struct device_node *ddc_node;
> >>> u32 value;
> >>> int ret;
> >>> @@ -1229,14 +1228,10 @@ static int vc4_hdmi_bind(struct device *dev, 
> >>> struct device *master, void *data)
> >>> if (!hdmi)
> >>> return -ENOMEM;
> >>>
> >>> -   vc4_hdmi_encoder = devm_kzalloc(dev, sizeof(*vc4_hdmi_encoder),
> >>> -   GFP_KERNEL);
> >>> -   if (!vc4_hdmi_encoder)
> >>> -   return -ENOMEM;
> >>> -   vc4_hdmi_encoder->base.type = VC4_ENCODER_TYPE_HDMI0;
> >>> -   hdmi->encoder = &vc4_hdmi_encoder->base.base;
> >>> -
> >>> hdmi->pdev = pdev;
> >>> +   encoder = &hdmi->encoder.base.base;
> >>> +   encoder->base.type = VC4_ENCODER_TYPE_HDMI0;
> >> Wait, does this patch build?
> > All those patches were build tested, so yep
> >
> >> setting struct drm_encoder->base.type = VC4_* seems very wrong, when
> >> previously we were setting struct vc4_hdmi_encoder->base.type (struct
> >> vc4_encoder->type).
> > So the structure layout now is that vc4_hdmi embeds vc4_hdmi_encoder as
> > encoder. So &hdmi->encoder is a pointer to vc4_hdmi_encoder.
> > vc4_hdmi_encoder's base is since that patch a struct vc4_encoder. and
> > vc4_encoder's base is a drm_encoder.
> >
> > so encoder being a drm_encoder is correct there.
> >
> > However, drm_encoder's base is drm_mode_object that does have a type
> > field, which is an uint32_t, which will accept a VC4_ENCODER_TYPE_* just
> > fine...
> >
> > Now, drm_encoder_init will then kick in and call drm_mode_object_add
> > which will override it to a proper value and since the clock select bit
> > in the PV is the same for both HDMI0 and HDMI1, everything works just
> > fine...
> >
> > Good catch, I'll fix it. And I guess it's a good indication we don't
> > need a separate HDMI0 and HDMI1 encoder type.
> >
> FWIW this is the first patch which breaks X on my Raspberry Pi 3 B.
> 
> Here are the bisect results:
> 
> 587d6e4a529a8d807a5c0bae583dd432d77064d6 bad (black screen, no heartbeat)
> 
> b0523c7b1c9d0edcd6c0fe6d2cb558a9ad5c60a8 good
> 
> 2c6a651cac6359cb0244a40d3b7a14e72918f169 good
> 
> 1705c3cb40906863ec0d24ee5ea5092f5ee2e994 bad (black screen, but heartbeat)
> 
> 601527fea6bb226abd088a864e74b25368218e87 good
> 
> 2165607ede34d229d0cbce916c70c7fb6c0337be good
> 
> f094f388fc2df848227e2ae648df2c97872df42b good
> 
> 020de18840a1075b2671736c6cc2e451030fad74 bad (black screen, but heartbeat)
> 
> 4c4da3823e4d1a8189e96a59a79451fff372f70b good
> 
> 020de18840a1075b2671736c6cc2e451030fad74 is the first bad commit
> commit 020de18840a1075b2671736c6cc2e451030fad74
> Author: Maxime Ripard 
> Date:   Mon Jan 6 17:17:29 2020 +0100
> 
>     drm/vc4: hdmi: rework connectors and encoders
>    
>     the vc4_hdmi driver has some custom structures to hold the data it
> needs to
>     associate with the drm_encoder and drm_connector structures.
>    
>     However, it allocates them separately from the vc4_hdmi structure which
>     makes it more complicated than it needs to be.
>    
>     Move those structures to be contained by vc4_hdmi and update the code
>     accordingly.
>    
>     Signed-off-by: Maxime Ripard 

So it looks like there was two issues on the Pi3. The first one was
causing the timeouts (and therefore likely the black screen but
heartbeat case you had) and I've fixed it.

However, I can indeed reproduce the case with the black screen / no
heartbeat you mentionned. My bisection however returns that it's the
patch "drm/vc4: hdmi: Implement finer-grained hooks" that is at fault.
I've pushed my updated branch, if you have some spare time, it would be
great if you could confirm it on your Pi.

Thanks!
Maxime


signature.asc
Description: PGP signature
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2] fbdev: geode: Add the missed pci_disable_device() in gx1fb_map_video_memory()

2020-06-07 Thread Chuhong Yuan
Although gx1fb_probe() has handled the failure of gx1fb_map_video_memory()
partly, it does not call pci_disable_device() as gx1fb_map_video_memory()
calls pci_enable_device().
Add the missed function call to fix the bug.

Fixes: 53eed4ec8bcd ("[PATCH] fbdev: geode updates]")
Signed-off-by: Chuhong Yuan 
---
Changes in v2:
  - Fix the typo in the subject.
  - Modify the label of error handler.
  - Refactor the code.
 
 drivers/video/fbdev/geode/gx1fb_core.c | 24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/video/fbdev/geode/gx1fb_core.c 
b/drivers/video/fbdev/geode/gx1fb_core.c
index 5d34d89fb665..15645244e4d0 100644
--- a/drivers/video/fbdev/geode/gx1fb_core.c
+++ b/drivers/video/fbdev/geode/gx1fb_core.c
@@ -208,29 +208,39 @@ static int gx1fb_map_video_memory(struct fb_info *info, 
struct pci_dev *dev)
 
ret = pci_request_region(dev, 0, "gx1fb (video)");
if (ret < 0)
-   return ret;
+   goto err_disable_device;
par->vid_regs = pci_ioremap_bar(dev, 0);
if (!par->vid_regs)
-   return -ENOMEM;
+   goto err_nomem;
 
-   if (!request_mem_region(gx_base + 0x8300, 0x100, "gx1fb (display 
controller)"))
-   return -EBUSY;
+   if (!request_mem_region(gx_base + 0x8300, 0x100,
+   "gx1fb (display controller)")) {
+   ret = -EBUSY;
+   goto err_disable_device;
+   }
par->dc_regs = ioremap(gx_base + 0x8300, 0x100);
if (!par->dc_regs)
-   return -ENOMEM;
+   goto err_nomem;
 
if ((fb_len = gx1_frame_buffer_size()) < 0)
-   return -ENOMEM;
+   goto err_nomem;
+
info->fix.smem_start = gx_base + 0x80;
info->fix.smem_len = fb_len;
info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
if (!info->screen_base)
-   return -ENOMEM;
+   goto err_nomem;
 
dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
 info->fix.smem_len / 1024, info->fix.smem_start);
 
return 0;
+
+err_nomem:
+   ret = -ENOMEM;
+err_disable_device:
+   pci_disable_device(dev);
+   return ret;
 }
 
 static int parse_panel_option(struct fb_info *info)
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v3 35/39] drm/tegra: dc: Support memory bandwidth management

2020-06-07 Thread Dmitry Osipenko
Display controller (DC) performs isochronous memory transfers, and thus,
has a requirement for a minimum memory bandwidth that shall be fulfilled,
otherwise framebuffer data can't be fetched fast enough and this results
in a DC's data-FIFO underflow that follows by a visual corruption.

The Memory Controller drivers provide facility for memory bandwidth
management via interconnect API. This patch wires up the interconnect
API support to the DC driver.

Signed-off-by: Dmitry Osipenko 
---
 drivers/gpu/drm/tegra/dc.c| 271 +-
 drivers/gpu/drm/tegra/dc.h|   8 +
 drivers/gpu/drm/tegra/drm.c   |  19 +++
 drivers/gpu/drm/tegra/plane.c |   1 +
 drivers/gpu/drm/tegra/plane.h |   4 +-
 5 files changed, 299 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 83f31c6e891c..12b318bb8475 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -519,6 +519,136 @@ static void tegra_dc_setup_window(struct tegra_plane 
*plane,
tegra_plane_setup_blending(plane, window);
 }
 
+static unsigned long
+tegra_plane_memory_bandwidth(struct drm_plane_state *state,
+struct tegra_dc_window *window,
+unsigned int num,
+unsigned int denum)
+{
+   struct tegra_plane_state *tegra_state;
+   struct drm_crtc_state *crtc_state;
+   const struct drm_format_info *fmt;
+   struct tegra_dc_window win;
+   unsigned long long bandwidth;
+   unsigned int bpp_plane;
+   unsigned int bpp;
+   unsigned int mul;
+   unsigned int i;
+
+   if (!state->fb || !state->visible)
+   return 0;
+
+   crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
+   tegra_state = to_tegra_plane_state(state);
+
+   if (!window)
+   window = &win;
+
+   window->src.w = drm_rect_width(&state->src) >> 16;
+   window->src.h = drm_rect_height(&state->src) >> 16;
+   window->dst.w = drm_rect_width(&state->dst);
+   window->dst.h = drm_rect_height(&state->dst);
+   window->tiling = tegra_state->tiling;
+
+   fmt = state->fb->format;
+
+   /*
+* Note that real memory bandwidth vary depending on format and
+* memory layout, we are not taking that into account because small
+* estimation error isn't important since bandwidth is rounded up
+* anyway.
+*/
+   for (i = 0, bpp = 0; i < fmt->num_planes; i++) {
+   bpp_plane = fmt->cpp[i] * 8;
+
+   /*
+* Sub-sampling is relevant for chroma planes only and vertical
+* readouts are not cached, hence only horizontal sub-sampling
+* matters.
+*/
+   if (i > 0)
+   bpp_plane /= fmt->hsub;
+
+   bpp += bpp_plane;
+   }
+
+   /*
+* Horizontal downscale takes extra bandwidth which roughly depends
+* on the scaled width.
+*/
+   if (window->src.w > window->dst.w)
+   mul = (window->src.w - window->dst.w) * bpp / 2048 + 1;
+   else
+   mul = 1;
+
+   /*
+* Ignore cursor window if its width is small enough such that
+* data-prefetch FIFO will easily help to overcome temporal memory
+* pressure.
+*
+* Window A has a 128bit x 128 deep read FIFO, while windows B/C
+* have a 128bit x 64 deep read FIFO.
+*
+* This allows us to not overestimate memory frequency requirement.
+* Even if it will happen that cursor gets a temporal underflow, this
+* won't be fatal.
+*/
+   if (state->plane->type == DRM_PLANE_TYPE_CURSOR &&
+   mul == 1 && window->src.w * bpp <= 128 * 16)
+   return 0;
+
+   /* mode.clock in kHz, bandwidth in kbit/s */
+   bandwidth = kbps_to_icc(crtc_state->mode.clock * bpp * mul);
+
+   /* the requested bandwidth should be higher than required */
+   bandwidth *= num;
+   do_div(bandwidth, denum);
+
+   return min_t(u64, bandwidth, ULONG_MAX);
+}
+
+static unsigned long
+tegra20_plane_memory_bandwidth(struct drm_plane_state *state)
+{
+   return tegra_plane_memory_bandwidth(state, NULL, 29, 10);
+}
+
+static unsigned long
+tegra30_plane_memory_bandwidth(struct drm_plane_state *state)
+{
+   struct tegra_dc_window window;
+   unsigned long bandwidth;
+
+   bandwidth = tegra_plane_memory_bandwidth(state, &window, 29, 10);
+
+   /* x2: memory overfetch for tiled framebuffer and DDR3 */
+   if (window.tiling.mode == TEGRA_BO_TILING_MODE_TILED)
+   bandwidth *= 2;
+
+   return bandwidth;
+}
+
+static unsigned long
+tegra114_plane_memory_bandwidth(struct drm_plane_state *state)
+{
+   struct tegra_dc_window window;
+   unsigned long bandwidth;
+
+   bandwidth = tegra_plane_memory_bandwidth(sta

Re: [PATCH v2 00/91] drm/vc4: Support BCM2711 Display Pipelin

2020-06-07 Thread Jian-Hong Pan
Maxime Ripard  於 2020年6月2日 週二 下午7:04寫道:
>
> Hi,
>
> On Mon, Jun 01, 2020 at 03:58:26PM +0800, Jian-Hong Pan wrote:
> > Maxime Ripard  於 2020年5月28日 週四 下午3:30寫道:
> > >
> > > Hi Daniel,
> > >
> > > On Wed, May 27, 2020 at 05:15:12PM +0800, Daniel Drake wrote:
> > > > On Wed, May 27, 2020 at 5:13 PM Maxime Ripard  wrote:
> > > > > I'm about to send a v3 today or tomorrow, I can Cc you (and 
> > > > > Jian-Hong) if you
> > > > > want.
> > > >
> > > > That would be great, although given the potentially inconsistent
> > > > results we've been seeing so far it would be great if you could
> > > > additionally push a git branch somewhere.
> > > > That way we can have higher confidence that we are applying exactly
> > > > the same patches to the same base etc.
> > >
> > > So I sent a new iteration yesterday, and of course forgot to cc you... 
> > > Sorry for
> > > that.
> > >
> > > I've pushed my current branch here:
> > > https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git/log/?h=rpi4-kms
> >
> > Thanks to Maxime!
> >
> > I have tried your repository on branch rpi4-kms.  The DRM VC4 is used!
> > But got some issues:
> > 1. Some weird error message in dmesg.  Not sure it is related, or not
> > [5.219321] [drm:vc5_hdmi_init_resources] *ERROR* Failed to get
> > HDMI state machine clock
> > https://gist.github.com/starnight/3f317dca121065a361cf08e91225e389
>
> That's a deferred probing. The first time the HDMI driver is being
> probed, the firmware clock driver has not been probed yet. It's making
> another attempt later on, which succeeds.
>
> > 2. The screen flashes suddenly sometimes.

I append drm.debug=0x3 to boot command.  Whenever, the screen flashes,
I notice the logs like this:

Jun 01 15:22:40 endless kernel: [drm:drm_calc_timestamping_constants]
crtc 64: hwmode: htotal 2200, vtotal 1125, vdisplay 1080
Jun 01 15:22:40 endless kernel: [drm:drm_calc_timestamping_constants]
crtc 64: clock 148500 kHz framedur 1666 linedur 14814
Jun 01 15:22:40 endless kernel: [drm:drm_vblank_enable] enabling
vblank on crtc 3, ret: 0
Jun 01 15:22:40 endless kernel: [drm:drm_mode_object_put.part.0] OBJ ID: 159 (2)
Jun 01 15:22:40 endless kernel: [drm:drm_mode_object_put.part.0] OBJ ID: 154 (1)
Jun 01 15:22:40 endless kernel: [drm:vblank_disable_fn] disabling
vblank on crtc 3
Jun 01 15:22:42 endless kernel: [drm:drm_ioctl] pid=584, dev=0xe200,
auth=1, DRM_IOCTL_MODE_CURSOR
Jun 01 15:22:42 endless kernel: [drm:drm_ioctl] pid=584, dev=0xe200,
auth=1, DRM_IOCTL_MODE_CURSOR2
Jun 01 15:22:42 endless kernel: [drm:drm_mode_object_get] OBJ ID: 159 (1)
Jun 01 15:22:42 endless kernel: [drm:drm_mode_object_get] OBJ ID: 154 (1)
Jun 01 15:22:42 endless kernel: [drm:drm_calc_timestamping_constants]
crtc 64: hwmode: htotal 2200, vtotal 1125, vdisplay 1080
Jun 01 15:22:42 endless kernel: [drm:drm_calc_timestamping_constants]
crtc 64: clock 148500 kHz framedur 1666 linedur 14814
Jun 01 15:22:42 endless kernel: [drm:drm_vblank_enable] enabling
vblank on crtc 3, ret: 0
Jun 01 15:22:42 endless kernel: [drm:drm_mode_object_put.part.0] OBJ ID: 159 (2)
Jun 01 15:22:42 endless kernel: [drm:drm_mode_object_put.part.0] OBJ ID: 154 (2)

Here is the full log
https://gist.github.com/starnight/85d641819839eddc7a55ca7173990a56

> > 3. The higher resolutions, like 1920x1080 ... are lost after hot
> > re-plug HDMI cable (HDMI0)

I should explain this in more detail.  Here are the steps to reproduce
this issue:
1. Before unplug the HDMI cable from HDMI0 port.
$ xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 2048 x 2048
HDMI-1 connected primary 1920x1080+0+0 (normal left inverted right x
axis y axis) 521mm x 293mm
   1920x1080 60.00*+  50.0059.94
   1920x1080i60.0050.0059.94
   1680x1050 59.88
   1280x1024 75.0260.02
   1440x900  59.90
   1280x960  60.00
   1152x864  75.00
   1280x720  60.0050.0059.94
   1440x576  50.00
   1024x768  75.0370.0760.00
   1440x480  60.0059.94
   832x624   74.55
   800x600   72.1975.0060.3256.25
   720x576   50.00
   720x480   60.0059.94
   640x480   75.0072.8166.6760.0059.94
   720x400   70.08
HDMI-2 disconnected (normal left inverted right x axis y axis)

2. Unplug the HDMI cable from HDMI0 port.
3. Plug the HDMI cable to **HDMI1** port.
$ xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 2048 x 2048
HDMI-1 disconnected (normal left inverted right x axis y axis)
HDMI-2 connected primary 1920x1080+0+0 (normal left inverted right x
axis y axis) 521mm x 293mm
   1920x1080 60.00*+  50.0059.94
   1920x1080i60.0050.0059.94
   1680x1050 59.88
   1280x1024 75.0260.02
   1440x900  59.90
   1280x960  60.00
   1152x864  75.00
   1280x720  60.0050.0059.94
   1440x576  50.00
   1024x768  75.0370.0760.00
   1440x480  60.0059.94
   832x624   74.55
   800x600   72.1975.00

[PATCH v3 38/39] ARM: tegra: Enable interconnect API in tegra_defconfig

2020-06-07 Thread Dmitry Osipenko
Tegra now has interconnect providers that are used for memory bandwidth
allocation.

Signed-off-by: Dmitry Osipenko 
---
 arch/arm/configs/tegra_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index aa94369bdd0f..0029259a6bf5 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -268,6 +268,7 @@ CONFIG_AK8975=y
 CONFIG_PWM=y
 CONFIG_PWM_TEGRA=y
 CONFIG_PHY_TEGRA_XUSB=y
+CONFIG_INTERCONNECT=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC PATCH 4/4] gpu/drm: Add Ilitek ILI9341 DBI panel driver

2020-06-07 Thread Paul Cercueil
This driver is for the Ilitek ILI9341 based YX240QV29-T 2.4" 240x320 TFT
LCD panel from Adafruit.

Signed-off-by: Paul Cercueil 
---
 drivers/gpu/drm/panel/Kconfig|   9 +
 drivers/gpu/drm/panel/Makefile   |   1 +
 drivers/gpu/drm/panel/panel-ilitek-ili9341.c | 347 +++
 3 files changed, 357 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-ilitek-ili9341.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index a1723c1b5fbf..2eb2ca77cab2 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -95,6 +95,15 @@ config DRM_PANEL_ILITEK_IL9322
  Say Y here if you want to enable support for Ilitek IL9322
  QVGA (320x240) RGB, YUV and ITU-T BT.656 panels.
 
+config DRM_PANEL_ILITEK_IL9341
+   tristate "Ilitek ILI9341 320x240 QVGA panels"
+   depends on OF
+   depends on DRM_MIPI_DSI
+   depends on BACKLIGHT_CLASS_DEVICE
+   help
+ Say Y here if you want to enable support for Ilitek IL9341
+ QVGA (320x240) RGB, YUV and ITU-T BT.656 panels.
+
 config DRM_PANEL_ILITEK_ILI9881C
tristate "Ilitek ILI9881C-based panels"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 96a883cd6630..d1235431691a 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_PANEL_ELIDA_KD35T133) += panel-elida-kd35t133.o
 obj-$(CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02) += panel-feixin-k101-im2ba02.o
 obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += 
panel-feiyang-fy07024di26a30d.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
+obj-$(CONFIG_DRM_PANEL_ILITEK_IL9341) += panel-ilitek-ili9341.o
 obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c 
b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
new file mode 100644
index ..6fb253b49f8a
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DRM driver for Ilitek ILI9341 panels
+ *
+ * Copyright 2018 David Lechner 
+ * Copyright 2020 Paul Cercueil 
+ *
+ * Based on mi0283qt.c:
+ * Copyright 2016 Noralf Trønnes
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#define ILI9341_FRMCTR10xb1
+#define ILI9341_DISCTRL0xb6
+#define ILI9341_ETMOD  0xb7
+
+#define ILI9341_PWCTRL10xc0
+#define ILI9341_PWCTRL20xc1
+#define ILI9341_VMCTRL10xc5
+#define ILI9341_VMCTRL20xc7
+#define ILI9341_PWCTRLA0xcb
+#define ILI9341_PWCTRLB0xcf
+
+#define ILI9341_PGAMCTRL   0xe0
+#define ILI9341_NGAMCTRL   0xe1
+#define ILI9341_DTCTRLA0xe8
+#define ILI9341_DTCTRLB0xea
+#define ILI9341_PWRSEQ 0xed
+
+#define ILI9341_EN3GAM 0xf2
+#define ILI9341_PUMPCTRL   0xf7
+
+#define ILI9341_MADCTL_BGR BIT(3)
+#define ILI9341_MADCTL_MV  BIT(5)
+#define ILI9341_MADCTL_MX  BIT(6)
+#define ILI9341_MADCTL_MY  BIT(7)
+
+struct ili9341_pdata {
+   struct drm_display_mode mode;
+   unsigned int width_mm;
+   unsigned int height_mm;
+   unsigned int bus_type;
+   unsigned int lanes;
+};
+
+struct ili9341 {
+   struct drm_panel panel;
+   struct mipi_dsi_device *dsi;
+   const struct ili9341_pdata *pdata;
+
+   struct gpio_desc*reset_gpiod;
+   struct backlight_device *backlight;
+   u32 rotation;
+};
+
+#define mipi_dcs_command(dsi, cmd, seq...) \
+({ \
+   u8 d[] = { seq }; \
+   mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
+})
+
+static inline struct ili9341 *panel_to_ili9341(struct drm_panel *panel)
+{
+   return container_of(panel, struct ili9341, panel);
+}
+
+static int ili9341_prepare(struct drm_panel *panel)
+{
+   struct ili9341 *priv = panel_to_ili9341(panel);
+   struct mipi_dsi_device *dsi = priv->dsi;
+   u8 addr_mode;
+   int ret;
+
+   gpiod_set_value_cansleep(priv->reset_gpiod, 0);
+   usleep_range(20, 1000);
+   gpiod_set_value_cansleep(priv->reset_gpiod, 1);
+   msleep(120);
+
+   ret = mipi_dcs_command(dsi, MIPI_DCS_SOFT_RESET);
+   if (ret) {
+   dev_err(panel->dev, "Failed to send reset command: %d\n", ret);
+   return ret;
+   }
+
+   /* Wait 5ms after soft reset per MIPI DCS spec */
+   usleep_range(5000, 2);
+
+   mipi_dcs_command(dsi, MIPI_DCS_SET_DISPLAY_OFF);
+
+   mipi_dcs_command(dsi, ILI9341_PWCTRLB, 0x00, 0xc1, 0x30);
+   mipi_dcs_command(dsi, ILI9341_PWRSEQ, 0x64, 0x03, 0x12, 0x8

[RFC PATCH 3/4] gpu/drm: Add TinyDRM for DSI/DBI panels

2020-06-07 Thread Paul Cercueil
The new API function mipi_dsi_maybe_register_tiny_driver() is supposed
to be called by DSI/DBI panel drivers at the end of their probe.

If it is detected that the panel is not connected to any controller,
because it has no port #0 node in Device Tree that points back to it,
then a TinyDRM driver is registered with it.

This TinyDRM driver expects that a DCS-compliant protocol is used by the
DSI/DBI panel and can only be used with these.

Signed-off-by: Paul Cercueil 
---
 drivers/gpu/drm/tiny/Kconfig|   8 +
 drivers/gpu/drm/tiny/Makefile   |   1 +
 drivers/gpu/drm/tiny/tiny-dsi.c | 262 
 include/drm/drm_mipi_dsi.h  |  19 +++
 4 files changed, 290 insertions(+)
 create mode 100644 drivers/gpu/drm/tiny/tiny-dsi.c

diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig
index 4160e74e4751..54ee58aecf66 100644
--- a/drivers/gpu/drm/tiny/Kconfig
+++ b/drivers/gpu/drm/tiny/Kconfig
@@ -9,6 +9,14 @@ config DRM_GM12U320
 This is a KMS driver for projectors which use the GM12U320 chipset
 for video transfer over USB2/3, such as the Acer C120 mini projector.
 
+config TINYDRM_DSI
+   tristate "DRM support for generic DBI/DSI display panels"
+   depends on DRM && DRM_MIPI_DSI
+   select DRM_MIPI_DBI
+   select DRM_KMS_CMA_HELPER
+   help
+ DRM driver for generic DBI/DSI display panels
+
 config TINYDRM_HX8357D
tristate "DRM support for HX8357D display panels"
depends on DRM && SPI
diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile
index c96ceee71453..49513db9a307 100644
--- a/drivers/gpu/drm/tiny/Makefile
+++ b/drivers/gpu/drm/tiny/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 obj-$(CONFIG_DRM_GM12U320) += gm12u320.o
+obj-$(CONFIG_TINYDRM_DSI)  += tiny-dsi.o
 obj-$(CONFIG_TINYDRM_HX8357D)  += hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)  += ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)  += ili9341.o
diff --git a/drivers/gpu/drm/tiny/tiny-dsi.c b/drivers/gpu/drm/tiny/tiny-dsi.c
new file mode 100644
index ..915e598844bd
--- /dev/null
+++ b/drivers/gpu/drm/tiny/tiny-dsi.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * TinyDRM driver for standard DSI/DBI panels
+ *
+ * Copyright 2020 Paul Cercueil 
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+struct tiny_dsi {
+   struct drm_device drm;
+   struct drm_connector connector;
+   struct drm_simple_display_pipe pipe;
+
+   struct mipi_dsi_device *dsi;
+   struct drm_panel *panel;
+};
+
+#define mipi_dcs_command(dsi, cmd, seq...) \
+({ \
+   u8 d[] = { seq }; \
+   mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
+})
+
+static inline struct tiny_dsi *drm_to_tiny_dsi(struct drm_device *drm)
+{
+   return container_of(drm, struct tiny_dsi, drm);
+}
+
+static void tiny_dsi_fb_dirty(struct drm_framebuffer *fb, struct drm_rect 
*rect)
+{
+   struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0);
+   struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(gem);
+   struct tiny_dsi *priv = drm_to_tiny_dsi(fb->dev);
+   unsigned int height = rect->y2 - rect->y1;
+   unsigned int width = rect->x2 - rect->x1;
+   bool fb_convert;
+   int idx, ret;
+   void *tr;
+
+   if (!drm_dev_enter(fb->dev, &idx))
+   return;
+
+   DRM_DEBUG_KMS("Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, 
DRM_RECT_ARG(rect));
+
+   fb_convert = width != fb->width || height != fb->height
+   || fb->format->format == DRM_FORMAT_XRGB;
+   if (fb_convert) {
+   tr = kzalloc(width * height * 2, GFP_KERNEL);
+
+   /* TODO: swap pixels if needed */
+   ret = mipi_dbi_buf_copy(tr, fb, rect, false);
+   if (ret)
+   goto err_msg;
+   } else {
+   tr = cma_obj->vaddr;
+   }
+
+   mipi_dcs_command(priv->dsi, MIPI_DCS_SET_COLUMN_ADDRESS,
+(rect->x1 >> 8) & 0xff, rect->x1 & 0xff,
+(rect->x2 >> 8) & 0xff, rect->x2 & 0xff);
+   mipi_dcs_command(priv->dsi, MIPI_DCS_SET_PAGE_ADDRESS,
+(rect->y1 >> 8) & 0xff, rect->y1 & 0xff,
+(rect->y2 >> 8) & 0xff, rect->y2 & 0xff);
+
+   ret = mipi_dsi_dcs_write(priv->dsi, MIPI_DCS_WRITE_MEMORY_START,
+tr, width * height * 2);
+err_msg:
+   if (ret)
+   dev_err_once(fb->dev->dev, "Failed to update display %d\n", 
ret);
+
+   if (fb_convert)
+   kfree(tr);
+   drm_dev_exit(idx);
+}
+
+static void tiny_dsi_enable(struct drm_simple_display_pipe *pipe,
+   struct drm_crtc_state *crtc_state,
+   struct drm_plane_state *plan

[PATCH v3 21/39] dt-bindings: memory: tegra30: emc: Document new interconnect property

2020-06-07 Thread Dmitry Osipenko
External memory controller is interconnected with memory controller and
with external memory. Document new interconnect property which turns
external memory controller into interconnect provider.

Acked-by: Rob Herring 
Signed-off-by: Dmitry Osipenko 
---
 .../bindings/memory-controllers/nvidia,tegra30-emc.yaml | 6 ++
 1 file changed, 6 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml
index 112bae2fcbbd..c243986db420 100644
--- 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml
+++ 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra30-emc.yaml
@@ -31,6 +31,9 @@ properties:
   interrupts:
 maxItems: 1
 
+  "#interconnect-cells":
+const: 0
+
   nvidia,memory-controller:
 $ref: /schemas/types.yaml#/definitions/phandle
 description:
@@ -214,6 +217,7 @@ required:
   - interrupts
   - clocks
   - nvidia,memory-controller
+  - "#interconnect-cells"
 
 additionalProperties: false
 
@@ -227,6 +231,8 @@ examples:
 
 nvidia,memory-controller = <&mc>;
 
+#interconnect-cells = <0>;
+
 emc-timings-1 {
 nvidia,ram-code = <1>;
 
-- 
2.26.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 12/15] drm/i915: panel: Add get_vbt_pwm_freq() helper

2020-06-07 Thread Hans de Goede
Factor the code which checks and drm_dbg_kms-s the VBT PWM frequency
out of get_backlight_max_vbt().

This is a preparation patch for honering the VBT PWM frequency for
devices which use an external PWM controller (devices using
pwm_setup_backlight()).

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 27 ++
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 3c5056dbf607..8efdd9f08a08 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1543,18 +1543,9 @@ static u32 vlv_hz_to_pwm(struct intel_connector 
*connector, u32 pwm_freq_hz)
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
 }
 
-static u32 get_backlight_max_vbt(struct intel_connector *connector)
+static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv)
 {
-   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-   struct intel_panel *panel = &connector->panel;
u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
-   u32 pwm;
-
-   if (!panel->backlight.hz_to_pwm) {
-   drm_dbg_kms(&dev_priv->drm,
-   "backlight frequency conversion not supported\n");
-   return 0;
-   }
 
if (pwm_freq_hz) {
drm_dbg_kms(&dev_priv->drm,
@@ -1567,6 +1558,22 @@ static u32 get_backlight_max_vbt(struct intel_connector 
*connector)
pwm_freq_hz);
}
 
+   return pwm_freq_hz;
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+   struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+   struct intel_panel *panel = &connector->panel;
+   u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv);
+   u32 pwm;
+
+   if (!panel->backlight.hz_to_pwm) {
+   drm_dbg_kms(&dev_priv->drm,
+   "backlight frequency conversion not supported\n");
+   return 0;
+   }
+
pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
if (!pwm) {
drm_dbg_kms(&dev_priv->drm,
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 11/15] pwm: crc: Implement get_state() method

2020-06-07 Thread Hans de Goede
Implement the pwm_ops.get_state() method to complete the support for the
new atomic PWM API.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 58c7e9ef7278..6c75a3470bc8 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -114,8 +114,37 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
return 0;
 }
 
+static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+  struct pwm_state *state)
+{
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   struct device *dev = crc_pwm->chip.dev;
+   unsigned int clk_div, clk_div_reg, duty_cycle_reg;
+   int error;
+
+   error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
+   return;
+   }
+
+   error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg);
+   if (error) {
+   dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
+   return;
+   }
+
+   clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
+
+   state->period = clk_div * NSEC_PER_MHZ * 256 / PWM_BASE_CLK_MHZ;
+   state->duty_cycle = duty_cycle_reg * state->period / PWM_MAX_LEVEL;
+   state->polarity   = PWM_POLARITY_NORMAL;
+   state->enabled= !!(clk_div_reg & PWM_OUTPUT_ENABLE);
+}
+
 static const struct pwm_ops crc_pwm_ops = {
.apply = crc_pwm_apply,
+   .get_state = crc_pwm_get_state,
 };
 
 static int crystalcove_pwm_probe(struct platform_device *pdev)
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 09/15] pwm: crc: Enable/disable PWM output on enable/disable

2020-06-07 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

So far we've kept the PWM_OUTPUT_ENABLE bit set when disabling the PWM,
this commit makes crc_pwm_disable() clear it on disable and makes
crc_pwm_enable() set it again on re-enable.

This should disable the internal (divided) PWM clock and tri-state the
PWM output pin when disabled, saving some power.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 24 +---
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index ef49a6e3c4d6..53734bcf67e1 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -41,10 +41,24 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
+static int crc_pwm_calc_clk_div(int period_ns)
+{
+   int clk_div;
+
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   return clk_div;
+}
+
 static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
 
return 0;
@@ -53,8 +67,10 @@ static int crc_pwm_enable(struct pwm_chip *c, struct 
pwm_device *pwm)
 static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
 {
struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
 
regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
 }
 
 static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
@@ -70,16 +86,10 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
}
 
if (pwm_get_period(pwm) != period_ns) {
-   int clk_div;
+   int clk_div = crc_pwm_calc_clk_div(period_ns);
 
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
}
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 10/15] pwm: crc: Implement apply() method to support the new atomic PWM API

2020-06-07 Thread Hans de Goede
Replace the enable, disable and config pwm_ops with an apply op,
to support the new atomic PWM API.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 107 +++---
 1 file changed, 59 insertions(+), 48 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 53734bcf67e1..58c7e9ef7278 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -41,70 +41,81 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct 
pwm_chip *pc)
return container_of(pc, struct crystalcove_pwm, chip);
 }
 
-static int crc_pwm_calc_clk_div(int period_ns)
+static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+const struct pwm_state *state)
 {
-   int clk_div;
-
-   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
-   /* clk_div 1 - 128, maps to register values 0-127 */
-   if (clk_div > 0)
-   clk_div--;
-
-   return clk_div;
-}
-
-static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div | PWM_OUTPUT_ENABLE);
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
-
-   return 0;
-}
-
-static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
-   int div = crc_pwm_calc_clk_div(pwm_get_period(pwm));
-
-   regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, div);
-}
-
-static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
- int duty_ns, int period_ns)
-{
-   struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
+   struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
+   int err, clk_div, level, pwm_output_enable;
struct device *dev = crc_pwm->chip.dev;
-   int level;
 
-   if (period_ns > PWM_MAX_PERIOD_NS) {
+   if (state->period > PWM_MAX_PERIOD_NS) {
dev_err(dev, "un-supported period_ns\n");
return -EINVAL;
}
 
-   if (pwm_get_period(pwm) != period_ns) {
-   int clk_div = crc_pwm_calc_clk_div(period_ns);
+   if (state->polarity != PWM_POLARITY_NORMAL)
+   return -ENOTSUPP;
+
+   if (pwm_is_enabled(pwm) && !state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
+   if (err) {
+   dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
+   pwm_get_period(pwm) != state->period) {
+   level = state->duty_cycle * PWM_MAX_LEVEL / state->period;
 
+   err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err);
+   return err;
+   }
+   }
+
+   if (pwm_is_enabled(pwm) && state->enabled &&
+   pwm_get_period(pwm) != state->period) {
/* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
-   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
-   clk_div | PWM_OUTPUT_ENABLE);
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
}
 
-   /* change the pwm duty cycle */
-   level = duty_ns * PWM_MAX_LEVEL / period_ns;
-   regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
+   if (pwm_get_period(pwm) != state->period ||
+   pwm_is_enabled(pwm) != state->enabled) {
+   clk_div = PWM_BASE_CLK_MHZ * state->period /
+ (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
+
+   pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0;
+
+   err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
+  clk_div | pwm_output_enable);
+   if (err) {
+   dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
+   return err;
+   }
+   }
+
+   if (!pwm_is_enabled(pwm) && state->enabled) {
+   err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
+   if (err) {
+   dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
+   return err;
+   }
+   }
 
return 0;
 }
 
 static const struc

[PATCH v2 05/15] pwm: lpss: Set SW_UPDATE bit when enabling the PWM

2020-06-07 Thread Hans de Goede
On the LPSS PWM controller found on Bay Trail (BYT) and Cherry Trail (CHT)
platforms, the following sequence results in an output duty-cycle of 100%
independent of what the duty-cycle requested in the ctrl-reg is:

1. Clear ENABLE bit in ctrl register
2. Let the machine reach a S0i3 low power state
3. Set the ENABLE bit in the ctrl register

The LPSS PWM controller has a mechanism where the ctrl register value
and the actual base-unit and on-time-div values used are latched. When
software sets the SW_UPDATE bit then at the end of the current PWM cycle,
the new values from the ctrl-register will be latched into the actual
registers, and the SW_UPDATE bit will be cleared.  Note on BYT and CHT
the ENABLE bit must be set before waiting for the SW_UPDATE bit to clear,
otherwise the SW_UPDATE bit will never clear (this is indicated in the
pwm-lpss.c code by lpwm->info->bypass being false).

My theory about why this is happening is that when we hit S0i3 the part
which holds the latched values gets turned off and when its turned back on
again at least the on-time-div value has been lost and gets reset to 0
which corresponds to an output duty-cycle of 100%. Testing has shown that
setting the SW_UPDATE bit to request latching the ctrl-register values into
the actual registers (again) fixes this, confirming this theory.

In the past there have been issues where setting the SW_UPDATE bit when
nothing has changed would lead to the next ctrl register changing being
ignored, see commit 2153bbc12f77 ("pwm: lpss: Only set update bit if we are
actually changing the settings"), so we should only set the SW_UPDATE bit
when actually changing the ENABLE bit from 0 to 1.

When looking into how to fix this I noticed that on platforms where
lpwm->info->bypass == false we unnecessarily do 2 read-modify-write cycles
of the ctrl register, one to set the base-unit and on-time-div, immediately
followed by another to set the ENABLE bit.

This commit fixes the 100% duty cycle issue by folding the setting of the
ENABLE bit into pwm_lpss_prepare(), which already checks if any bits in
the ctrl-register have actually changed and if that is the case then sets
the SW_UPDATE bit.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index a764e062103b..2cb0e2a9c08c 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -80,7 +80,7 @@ static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
 }
 
 static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device 
*pwm,
-int duty_ns, int period_ns)
+int duty_ns, int period_ns, bool enable)
 {
unsigned long long on_time_div;
unsigned long c = lpwm->info->clk_rate, base_unit_range;
@@ -115,6 +115,8 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
+   if (enable)
+   ctrl |= PWM_ENABLE;
 
if (orig_ctrl != ctrl) {
pwm_lpss_write(pwm, ctrl);
@@ -142,8 +144,9 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
pm_runtime_put(chip->dev);
return ret;
}
-   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
-   pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
+   pwm_lpss_prepare(lpwm, pwm,
+state->duty_cycle, state->period,
+lpwm->info->bypass == false);
ret = pwm_lpss_wait_for_update(pwm);
if (ret) {
pm_runtime_put(chip->dev);
@@ -154,7 +157,8 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct 
pwm_device *pwm,
ret = pwm_lpss_is_updating(pwm);
if (ret)
return ret;
-   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, 
state->period);
+   pwm_lpss_prepare(lpwm, pwm, state->duty_cycle,
+state->period, false);
return pwm_lpss_wait_for_update(pwm);
}
} else if (pwm_is_enabled(pwm)) {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 06/15] pwm: crc: Fix period / duty_cycle times being off by a factor of 256

2020-06-07 Thread Hans de Goede
While looking into adding atomic-pwm support to the pwm-crc driver I
noticed something odd, there is a PWM_BASE_CLK define of 6 MHz and
there is a clock-divider which divides this with a value between 1-128,
and there are 256 duty-cycle steps.

The pwm-crc code before this commit assumed that a clock-divider
setting of 1 means that the PWM output is running at 6 MHZ, if that
is true, where do these 256 duty-cycle steps come from?

This would require an internal frequency of 256 * 6 MHz = 1.5 GHz, that
seems unlikely for a PMIC which is using a silicon process optimized for
power-switching transistors. It is way more likely that there is an 8
bit counter for the duty cycle which acts as an extra fixed divider
wrt the PWM output frequency.

The main user of the pwm-crc driver is the i915 GPU driver which uses it
for backlight control. Lets compare the PWM register values set by the
video-BIOS (the GOP), assuming the extra fixed divider is present versus
the PWM frequency specified in the Video-BIOS-Tables:

Device: PWM Hz set by BIOS  PWM Hz specified in VBT
Asus T100TA 200 200
Asus T100HA 200 200
Lenovo Miix 2 8 23437   2
Toshiba WT8-A   23437   2

So as we can see if we assume the extra division by 256 then the register
values set by the GOP are an exact match for the VBT values, where as
otherwise the values would be of by a factor of 256.

This commit fixes the period / duty_cycle calculations to take the
extra division by 256 into account.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 272eeb071147..43fc912c1fe9 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -21,8 +21,10 @@
 
 #define PWM_MAX_LEVEL  0xFF
 
-#define PWM_BASE_CLK   600  /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  21333/* 46.875KHz */
+#define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
+#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+
+#define NSEC_PER_MHZ   1000
 
 /**
  * struct crystalcove_pwm - Crystal Cove PWM controller
@@ -72,7 +74,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
-   clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
+   clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 14/15] drm/i915: panel: Honor the VBT PWM min setting for devs with an external PWM controller

2020-06-07 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the minimum allowed
PWM level to 0. But several of these devices specify a non 0 minimum
setting in their VBT.

Change pwm_setup_backlight() to use get_backlight_min_vbt() to get
the minimum level.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/display/intel_panel.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 14e611c92194..cb28b9908ca4 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -1925,8 +1925,8 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 */
pwm_apply_args(panel->backlight.pwm);
 
-   panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
+   panel->backlight.min = get_backlight_min_vbt(connector);
level = intel_panel_compute_brightness(connector, 100);
ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
@@ -1941,8 +1941,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
 
level = DIV_ROUND_UP(pwm_get_duty_cycle(panel->backlight.pwm) * 100,
 panel->backlight.pwm_period_ns);
-   panel->backlight.level =
-   intel_panel_compute_brightness(connector, level);
+   level = intel_panel_compute_brightness(connector, level);
+   panel->backlight.level = clamp(level, panel->backlight.min,
+  panel->backlight.max);
panel->backlight.enabled = panel->backlight.level != 0;
 
drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n",
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 08/15] pwm: crc: Fix period changes not having any effect

2020-06-07 Thread Hans de Goede
The pwm-crc code is using 2 different enable bits:
1. bit 7 of the PWM0_CLK_DIV (PWM_OUTPUT_ENABLE)
2. bit 0 of the BACKLIGHT_EN register

I strongly suspect that the BACKLIGHT_EN register at address 0x51 really
controls a separate output-only GPIO which is connected to the LCD panels
backlight-enable input. Like how the PANEL_EN register at address 0x52
controls an output-only GPIO which is earmarked for the LCD panel's
enable pin. If this is correct then this GPIO should really be added to
the gpio-crystalcove.c driver and the PWM driver should stop poking it.
But I've been unable to come up with a definitive answer here, so I'm
keeping this as is for now.

As the comment in the old code already indicates we must disable the PWM
before we can change the clock divider. But the crc_pwm_disable() and
crc_pwm_enable() calls the old code make for this only change the
BACKLIGHT_EN register; and the value of that register does not matter for
changing the period / the divider. What does matter is that the
PWM_OUTPUT_ENABLE bit must be cleared before a new value can be written.

This commit modifies crc_pwm_config() to clear PWM_OUTPUT_ENABLE instead
when changing the period, so that period changes actually work.

Note this fix will cause a significant behavior change on some devices
using the CRC PWM output to drive their backlight. Before the PWM would
always run with the output frequency configured by the BIOS at boot, now
the period time specified by the i915 driver will actually be honored.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 5ba2a65c524c..ef49a6e3c4d6 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -72,8 +72,9 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
if (pwm_get_period(pwm) != period_ns) {
int clk_div;
 
-   /* changing the clk divisor, need to disable fisrt */
-   crc_pwm_disable(c, pwm);
+   /* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
+   regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
+
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
/* clk_div 1 - 128, maps to register values 0-127 */
if (clk_div > 0)
@@ -81,9 +82,6 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-
-   /* enable back */
-   crc_pwm_enable(c, pwm);
}
 
/* change the pwm duty cycle */
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 15/15] drm/i915: panel: Use atomic PWM API for devs with an external PWM controller

2020-06-07 Thread Hans de Goede
Now that the PWM drivers which we use have been converted to the atomic
PWM API, we can move the i915 panel code over to using the atomic PWM API.

The removes a long standing FIXME and this removes a flicker where
the backlight brightness would jump to 100% when i915 loads even if
using the fastset path.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  3 +-
 drivers/gpu/drm/i915/display/intel_panel.c| 73 +--
 2 files changed, 37 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index 24ea4a7b6dde..48afb2925271 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -223,7 +224,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
-   int pwm_period_ns;
+   struct pwm_state pwm_state;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index cb28b9908ca4..a0f76343f381 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -592,10 +592,11 @@ static u32 bxt_get_backlight(struct intel_connector 
*connector)
 static u32 pwm_get_backlight(struct intel_connector *connector)
 {
struct intel_panel *panel = &connector->panel;
-   int duty_ns;
+   int duty_ns, period_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
+   period_ns = pwm_get_period(panel->backlight.pwm);
+   return DIV_ROUND_UP(duty_ns * 100, period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -669,10 +670,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
&to_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns,
-  panel->backlight.pwm_period_ns);
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
 }
 
 static void
@@ -841,10 +842,8 @@ static void pwm_disable_backlight(const struct 
drm_connector_state *old_conn_sta
struct intel_connector *connector = 
to_intel_connector(old_conn_state->connector);
struct intel_panel *panel = &connector->panel;
 
-   /* Disable the backlight */
-   intel_panel_actually_set_backlight(old_conn_state, 0);
-   usleep_range(2000, 3000);
-   pwm_disable(panel->backlight.pwm);
+   panel->backlight.pwm_state.enabled = false;
+   pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
 }
 
 void intel_panel_disable_backlight(const struct drm_connector_state 
*old_conn_state)
@@ -1176,9 +1175,14 @@ static void pwm_enable_backlight(const struct 
intel_crtc_state *crtc_state,
 {
struct intel_connector *connector = 
to_intel_connector(conn_state->connector);
struct intel_panel *panel = &connector->panel;
+   int level = panel->backlight.level;
 
-   pwm_enable(panel->backlight.pwm);
-   intel_panel_actually_set_backlight(conn_state, panel->backlight.level);
+   level = intel_panel_compute_brightness(connector, level);
+
+   panel->backlight.pwm_state.duty_cycle =
+   DIV_ROUND_UP(level * panel->backlight.pwm_state.period, 100);
+   panel->backlight.pwm_state.enabled = true;
+   pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
 }
 
 static void __intel_panel_enable_backlight(const struct intel_crtc_state 
*crtc_state,
@@ -1897,8 +1901,7 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_panel *panel = &connector->panel;
const char *desc;
-   u32 level, ns;
-   int retval;
+   u32 level;
 
/* Get the right PWM chip for DSI backlight according to VBT */
if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) {
@@ -1916,36 +1919,30 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
-   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
-get_vbt_pwm_freq(dev_priv);
-
-   /*
-* FIXME: pwm_apply_args() should be removed when switc

[PATCH v2 13/15] drm/i915: panel: Honor the VBT PWM frequency for devs with an external PWM controller

2020-06-07 Thread Hans de Goede
So far for devices using an external PWM controller (devices using
pwm_setup_backlight()), we have been hardcoding the period-time passed to
pwm_config() to 21333 ns.

I suspect this was done because many VBTs set the PWM frequency to 200
which corresponds to a period-time of 500 ns, which greatly exceeds
the PWM_MAX_PERIOD_NS define in the Crystal Cove PMIC PWM driver, which
used to be 21333.

This PWM_MAX_PERIOD_NS define was actually based on a bug in the PWM
driver where its period and duty-cycle times where off by a factor of 256.

Due to this bug the hardcoded CRC_PMIC_PWM_PERIOD_NS value of 21333 would
result in the PWM driver using its divider of 128, which would result in
a PWM output frequency of 600 Hz / 256 / 128 = 183 Hz. So actually
pretty close to the default VBT value of 200 Hz.

Now that this bug in the pwm-crc driver is fixed, we can actually use
the VBT defined frequency.

This is important because:

a) With the pwm-crc driver fixed it will now translate the hardcoded
CRC_PMIC_PWM_PERIOD_NS value of 21333 ns / 46 Khz to a PWM output
frequency of 23 KHz (the max it can do).

b) The pwm-lpss driver used on many models has always honored the
21333 ns / 46 Khz request

Some panels do not like such high output frequencies. E.g. on a Terra
Pad 1061 tablet, using the LPSS PWM controller, the backlight would go
from off to max, when changing the sysfs backlight brightness value from
90-100%, anything under aprox. 90% would turn the backlight fully off.

Honoring the VBT specified PWM frequency will also hopefully fix the
various bug reports which we have received about users perceiving the
backlight to flicker after a suspend/resume cycle.

Signed-off-by: Hans de Goede 
---
 .../drm/i915/display/intel_display_types.h|  1 +
 drivers/gpu/drm/i915/display/intel_panel.c| 19 +++
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h 
b/drivers/gpu/drm/i915/display/intel_display_types.h
index b24266c624fa..24ea4a7b6dde 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -223,6 +223,7 @@ struct intel_panel {
bool util_pin_active_low;   /* bxt+ */
u8 controller;  /* bxt+ only */
struct pwm_device *pwm;
+   int pwm_period_ns;
 
/* DPCD backlight */
u8 pwmgen_bit_count;
diff --git a/drivers/gpu/drm/i915/display/intel_panel.c 
b/drivers/gpu/drm/i915/display/intel_panel.c
index 8efdd9f08a08..14e611c92194 100644
--- a/drivers/gpu/drm/i915/display/intel_panel.c
+++ b/drivers/gpu/drm/i915/display/intel_panel.c
@@ -40,8 +40,6 @@
 #include "intel_dsi_dcs_backlight.h"
 #include "intel_panel.h"
 
-#define CRC_PMIC_PWM_PERIOD_NS 21333
-
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
   struct drm_display_mode *adjusted_mode)
@@ -597,7 +595,7 @@ static u32 pwm_get_backlight(struct intel_connector 
*connector)
int duty_ns;
 
duty_ns = pwm_get_duty_cycle(panel->backlight.pwm);
-   return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
+   return DIV_ROUND_UP(duty_ns * 100, panel->backlight.pwm_period_ns);
 }
 
 static void lpt_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
@@ -671,9 +669,10 @@ static void bxt_set_backlight(const struct 
drm_connector_state *conn_state, u32
 static void pwm_set_backlight(const struct drm_connector_state *conn_state, 
u32 level)
 {
struct intel_panel *panel = 
&to_intel_connector(conn_state->connector)->panel;
-   int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   int duty_ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
+   pwm_config(panel->backlight.pwm, duty_ns,
+  panel->backlight.pwm_period_ns);
 }
 
 static void
@@ -1917,6 +1916,9 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
return -ENODEV;
}
 
+   panel->backlight.pwm_period_ns = NSEC_PER_SEC /
+get_vbt_pwm_freq(dev_priv);
+
/*
 * FIXME: pwm_apply_args() should be removed when switching to
 * the atomic PWM API.
@@ -1926,9 +1928,10 @@ static int pwm_setup_backlight(struct intel_connector 
*connector,
panel->backlight.min = 0; /* 0% */
panel->backlight.max = 100; /* 100% */
level = intel_panel_compute_brightness(connector, 100);
-   ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100);
+   ns = DIV_ROUND_UP(level * panel->backlight.pwm_period_ns, 100);
 
-   retval = pwm_config(panel->backlight.pwm, ns, CRC_PMIC_PWM_PERIOD_NS);
+   retval = pwm_config(panel->backlight.pwm, ns,
+   panel->backlight.pwm_period_ns);
if (retval < 0) {
  

[PATCH v2 07/15] pwm: crc: Fix off-by-one error in the clock-divider calculations

2020-06-07 Thread Hans de Goede
The CRC PWM controller has a clock-divider which divides the clock with
a value between 1-128. But as can seen from the PWM_DIV_CLK_xxx
defines, this range maps to a register value of 0-127.

So after calculating the clock-divider we must subtract 1 to get the
register value, unless the requested frequency was so high that the
calculation has already resulted in a (rounded) divider value of 0.

Note that before this fix, setting a period of PWM_MAX_PERIOD_NS which
corresponds to the max. divider value of 128 could have resulted in a
bug where the code would use 128 as divider-register value which would
have resulted in an actual divider value of 0 (and the enable bit being
set). A rounding error stopped this bug from actually happen. This
same rounding error means that after the subtraction of 1 it is impossible
to set the divider to 128. Also bump PWM_MAX_PERIOD_NS by 1 ns to allow
setting a divider of 128 (register-value 127).

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-crc.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 43fc912c1fe9..5ba2a65c524c 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -22,7 +22,7 @@
 #define PWM_MAX_LEVEL  0xFF
 
 #define PWM_BASE_CLK_MHZ   6   /* 6 MHz */
-#define PWM_MAX_PERIOD_NS  5461333 /* 183 Hz */
+#define PWM_MAX_PERIOD_NS  5461334 /* 183 Hz */
 
 #define NSEC_PER_MHZ   1000
 
@@ -75,6 +75,9 @@ static int crc_pwm_config(struct pwm_chip *c, struct 
pwm_device *pwm,
/* changing the clk divisor, need to disable fisrt */
crc_pwm_disable(c, pwm);
clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_MHZ);
+   /* clk_div 1 - 128, maps to register values 0-127 */
+   if (clk_div > 0)
+   clk_div--;
 
regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
clk_div | PWM_OUTPUT_ENABLE);
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 04/15] pwm: lpss: Fix off by one error in base_unit math in pwm_lpss_prepare()

2020-06-07 Thread Hans de Goede
According to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency.

So assuming e.g. a 16 bit counter this means that if base_unit is set to 1,
after 65535 input clock-cycles the counter has been increased from 0 to
65535 and it will overflow on the next cycle, so it will overflow after
every 65536 clock cycles and thus the calculations done in
pwm_lpss_prepare() should use 65536 and not 65535.

This commit fixes this. Note this also aligns the calculations in
pwm_lpss_prepare() with those in pwm_lpss_get_state().

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index cae74ce61654..a764e062103b 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -93,7 +93,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 * The equation is:
 * base_unit = round(base_unit_range * freq / c)
 */
-   base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
+   base_unit_range = BIT(lpwm->info->base_unit_bits);
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
@@ -112,7 +112,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
 
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
-   ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
+   ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT);
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 01/15] ACPI / LPSS: Resume Cherry Trail PWM controller in no-irq phase

2020-06-07 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets poked from the _PS0 method of the graphics-card device:

Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
If (((Local0 & 0x03) == 0x03))
{
PSAT &= 0xFFFC
Local1 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
RSTA = Zero
RSTF = Zero
RSTA = One
RSTF = One
PWMB |= 0xC000
PWMC = PWMB /* \_SB_.PCI0.GFX0.PWMB */
}

Where PSAT is the power-status register of the PWM controller, so if it
is in D3 when the GFX0 device's PS0 method runs then it will turn it on
and restore the PWM ctrl register value it saved from its PS3 handler.
Note not only does it restore it, it ors it with 0xC000 turning it
on at a time where we may not want it to get turned on at all.

The pwm_get call which the i915 driver does to get a reference to the
PWM controller, already adds a device-link making the GFX0 device a
consumer of the PWM device. So it should already have been resumed when
the above AML runs and the AML should thus not do its undesirable poking
of the PWM controller register.

But the PCI core powers on PCI devices in the no-irq resume phase and
thus calls the troublesome PS0 method in the no-irq resume phase.
Where as LPSS devices by default are resumed in the early resume phase.

This commit sets the resume_from_noirq flag in the bsw_pwm_dev_desc
struct, so that Cherry Trail PWM controllers will be resumed in the
no-irq phase. Together with the device-link added by the pwm-get this
ensures that the PWM controller will be on when the troublesome PS0
method runs, which stops it from poking the PWM controller.

Signed-off-by: Hans de Goede 
---
 drivers/acpi/acpi_lpss.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 5e2bfbcf526f..67892fc0b822 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -257,6 +257,7 @@ static const struct lpss_device_desc bsw_pwm_dev_desc = {
.flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
.prv_offset = 0x800,
.setup = bsw_pwm_setup,
+   .resume_from_noirq = true,
 };
 
 static const struct lpss_device_desc byt_uart_dev_desc = {
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 02/15] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-07 Thread Hans de Goede
The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets turned off from the _PS3 method of the graphics-card dev:

Method (_PS3, 0, Serialized)  // _PS3: Power State 3
{
...
PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
PSAT |= 0x03
Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
...
}

Where PSAT is the power-status register of the PWM controller.

Since the i915 driver will do a pwm_get on the pwm device as it uses it to
control the LCD panel backlight, there is a device-link marking the i915
device as a consumer of the pwm device. So that the PWM controller will
always be suspended after the i915 driver suspends (which is the right
thing to do). This causes the above GFX0 PS3 AML code to run before
acpi_lpss.c calls acpi_lpss_save_ctx().

So on these devices the PWM controller will already be off when
acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
as ctx register values.

When these bogus values get restored on resume the PWM controller actually
keeps working, since most bits are reserved, but this does set bit 3 of
the LPSS General purpose register, which for the PWM controller has the
following function: "This bit is re-used to support 32kHz slow mode.
Default is 19.2MHz as PWM source clock".

This causes the clock of the PWM controller to switch from 19.2MHz to
32KHz, which is a slow-down of a factor 600. Surprisingly enough so far
there have been few bug reports about this. This is likely because the
i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
by 600 would result in a PWM frequency of approx. 78 Hz, which mostly
still works fine. There are some bug reports about the LCD backlight
flickering after suspend/resume which are likely caused by this issue.

But with the upcoming patch-series to finally switch the i915 drivers
code for external PWM controllers to use the atomic API and to honor
the PWM frequency specified in the video BIOS (VBT), this becomes a much
bigger problem. On most cases the VBT specifies either 200 Hz or 20
KHz as PWM frequency, which with the mentioned issue ends up being either
1/3 Hz, where the backlight actually visible blinks on and off every 3s,
or in 33 Hz and horrible flickering of the backlight.

There are a number of possible solutions to this problem:

1. Make acpi_lpss_save_ctx() run before GFX0._PS3
 Pro: Clean solution from pov of not medling with save/restore ctx code
 Con: As mentioned the current ordering is the right thing to do
 Con: Requires assymmetry in at what suspend/resume phase we do the save vs
  restore, requiring more suspend/resume ordering hacks in already
  convoluted acpi_lpss.c suspend/resume code.
2. Do some sort of save once mode for the LPSS ctx
 Pro: Reasonably clean
 Con: Needs a new LPSS flag + code changes to handle the flag
3. Detect we have failed to save the ctx registers and do not restore them
 Pro: Not PWM specific, might help with issues on other LPSS devices too
 Con: If we can get away with not restoring the ctx why bother with it at
  all?
4. Do not save the ctx for CHT PWM controllers
 Pro: Clean, as simple as dropping a flag?
 Con: Not so simple as dropping a flag, needs a new flag to ensure that
  we still do lpss_deassert_reset() on device activation.
5. Make the pwm-lpss code fixup the LPSS-context registers
 Pro: Keeps acpi_lpss.c code clean
 Con: Moves knowledge of LPSS-context into the pwm-lpss.c code

1 and 5 both do not seem to be a desirable way forward.

3 and 4 seem ok, but they both assume that restoring the LPSS-context
registers is not necessary. I have done a couple of test and those do
show that restoring the LPSS-context indeed does not seem to be necessary
on devices using s2idle suspend (and successfully reaching S0i3). But I
have no hardware to test deep / S3 suspend. So I'm not sure that not
restoring the context is safe.

That leaves solution 2, which is about as simple / clean as 3 and 4,
so this commit fixes the described problem by implementing a new
LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.

Signed-off-by: Hans de Goede 
---
Changes in v2:
- Move #define LPSS_SAVE_CTX_ONCE define to group it with LPSS_SAVE_CTX
---
 drivers/acpi/acpi_lpss.c | 21 +
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 67892fc0b822..a8d7d83ac761 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -67,7 +67,15 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_CLK_DIVIDER   BIT(2)
 #define LPSS_LTR   BIT(3)
 #define LPSS_SAVE_CTX  BIT(4)
-#define LPSS_NO_D3_DELAY   BIT(5)
+/*
+ * For some devices the DSDT AML code for another device turns off the device
+ * before our suspend handler runs, causing 

[PATCH v2 00/15] pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-07 Thread Hans de Goede
Hi All,

Here is v2 dropping a debugging-patch which I accidentally kept for v1
and addressing a minor review remark from Andy for the 2nd patch.

This patch series converts the i915 driver's code for controlling the
panel's backlight with an external PWM controller to use the atomic PWM API.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.

The involved acpi_lpss and pwm drivers do not see a whole lot of churn,
so we could just merge everything through dinq, or we could use immutable
branch and merge those into dinq.

So Rafael and Thierry, can I either get your Acked-by for directly merging
this into dinq, or can you provide an immutable branch with these patches?

This series has been tested (and re-tested after adding various bug-fixes)
extensively. It has been tested on the following devices:

-Asus T100TA  BYT + CRC-PMIC PWM
-Toshiba WT8-A  BYT + CRC-PMIC PWM
-Thundersoft TS178 BYT + CRC-PMIC PWM, inverse PWM
-Asus T100HA  CHT + CRC-PMIC PWM
-Terra Pad 1061  BYT + LPSS PWM
-Trekstor Twin 10.1 BYT + LPSS PWM
-Asus T101HA  CHT + CRC-PMIC PWM
-GPD Pocket  CHT + CRC-PMIC PWM

Regards,

Hans

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH v2 03/15] pwm: lpss: Add range limit check for the base_unit register value

2020-06-07 Thread Hans de Goede
When the user requests a high enough period ns value, then the
calculations in pwm_lpss_prepare() might result in a base_unit value of 0.

But according to the data-sheet the way the PWM controller works is that
each input clock-cycle the base_unit gets added to a N bit counter and
that counter overflowing determines the PWM output frequency. Adding 0
to the counter is a no-op. The data-sheet even explicitly states that
writing 0 to the base_unit bits will result in the PWM outputting a
continuous 0 signal.

base_unit values > (base_unit_range / 256), or iow base_unit values using
the 8 most significant bits, cause loss of resolution of the duty-cycle.
E.g. assuming a base_unit_range of 65536 steps, then a base_unit value of
768 (256 * 3), limits the duty-cycle resolution to 65536 / 768 = 85 steps.
Clamp the max base_unit value to base_unit_range / 32 to ensure a
duty-cycle resolution of at least 32 steps. This limits the maximum
output frequency to 600 KHz / 780 KHz depending on the base clock.

Signed-off-by: Hans de Goede 
---
 drivers/pwm/pwm-lpss.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 9d965ffe66d1..cae74ce61654 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -97,6 +97,14 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
freq *= base_unit_range;
 
base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
+   /*
+* base_unit must not be 0 and for values > (base_unit_range / 256)
+* (values using the 8 most significant bits) the duty-cycle resolution
+* degrades. Clamp the maximum value to base_unit_range / 32 which
+* leaves a duty-cycle resolution of 32 steps.
+*/
+   base_unit = clamp_t(unsigned long long, base_unit, 1,
+   base_unit_range / 32);
 
on_time_div = 255ULL * duty_ns;
do_div(on_time_div, period_ns);
@@ -105,7 +113,6 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, 
struct pwm_device *pwm,
orig_ctrl = ctrl = pwm_lpss_read(pwm);
ctrl &= ~PWM_ON_TIME_DIV_MASK;
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
-   base_unit &= base_unit_range;
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
 
-- 
2.26.2

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: pwm/i915: Convert pwm-crc and i915 driver's PWM code to use the atomic PWM API

2020-06-07 Thread Hans de Goede

Hi All,

I forgot the [PATCH 0/16] part of the subject here and I accidentally
left a patch adding some debugging printk-s in the series. I will
send out a v2 addressing this.

Regards,

Hans

On 6/6/20 10:25 PM, Hans de Goede wrote:

Hi All,

This patch series converts the i915 driver's cpde for controlling the
panel's backlight with an external PWM controller to use the atomic PWM API.

Initially the plan was for this series to consist of 2 parts:
1. convert the pwm-crc driver to support the atomic PWM API and
2. convert the i915 driver's PWM code to use the atomic PWM API.

But during testing I've found a number of bugs in the pwm-lpss and I
found that the acpi_lpss code needs some special handling because of
some ugliness found in most Cherry Trail DSDTs.

So now this series has grown somewhat large and consists of 4 parts:

1. acpi_lpss fixes workarounds for Cherry Trail DSTD nastiness
2. various fixes to the pwm-lpss driver
3. convert the pwm-crc driver to support the atomic PWM API and
4. convert the i915 driver's PWM code to use the atomic PWM API

So we need to discuss how to merge this (once it passes review).
Although the inter-dependencies are only runtime I still think we should
make sure that 1-3 are in the drm-intel-next-queued (dinq) tree before
merging the i915 changes. Both to make sure that the intel-gfx CI system
does not become unhappy and for bisecting reasons.

The involved acpi_lpss and pwm drivers do not see a whole lot of churn,
so we could just merge everything through dinq, or we could use immutable
branch and merge those into dinq.

So Rafael and Thierry, can I either get your Acked-by for directly merging
this into dinq, or can you provide an immutable branch with these patches?

This series has been tested (and re-tested after adding various bug-fixes)
extensively. It has been tested on the following devices:

-Asus T100TABYT + CRC-PMIC PWM
-Toshiba WT8-A  BYT + CRC-PMIC PWM
-Thundersoft TS178  BYT + CRC-PMIC PWM, inverse PWM
-Asus T100HACHT + CRC-PMIC PWM
-Terra Pad 1061 BYT + LPSS PWM
-Trekstor Twin 10.1 BYT + LPSS PWM
-Asus T101HACHT + CRC-PMIC PWM
-GPD Pocket CHT + CRC-PMIC PWM

Regards,

Hans



___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [PATCH 02/16] ACPI / LPSS: Save Cherry Trail PWM ctx registers only once (at activation)

2020-06-07 Thread Hans de Goede

Hi,

On 6/7/20 7:03 PM, Andy Shevchenko wrote:

On Sat, Jun 06, 2020 at 10:25:47PM +0200, Hans de Goede wrote:

The DSDTs on most Cherry Trail devices have an ugly clutch where the PWM
controller gets turned off from the _PS3 method of the graphics-card dev:

 Method (_PS3, 0, Serialized)  // _PS3: Power State 3
 {
 ...
 PWMB = PWMC /* \_SB_.PCI0.GFX0.PWMC */
 PSAT |= 0x03
 Local0 = PSAT /* \_SB_.PCI0.GFX0.PSAT */
 ...
 }

Where PSAT is the power-status register of the PWM controller.

Since the i915 driver will do a pwm_get on the pwm device as it uses it to
control the LCD panel backlight, there is a device-link marking the i915
device as a consumer of the pwm device. So that the PWM controller will
always be suspended after the i915 driver suspends (which is the right
thing to do). This causes the above GFX0 PS3 AML code to run before
acpi_lpss.c calls acpi_lpss_save_ctx().

So on these devices the PWM controller will already be off when
acpi_lpss_save_ctx() runs. This causes it to read/save all 1-s (0x)
as ctx register values.

When these bogus values get restored on resume the PWM controller actually
keeps working, since most bits are reserved, but this does set bit 3 of
the LPSS General purpose register, which for the PWM controller has the
following function: "This bit is re-used to support 32kHz slow mode.
Default is 19.2MHz as PWM source clock".

This causes the clock of the PWM controller to switch from 19.2MHz to
32KHz, which is a slow-down of a factor 600. Suprisingly enough so far
there have been few bug reports about this. This is likely because the
i915 driver was hardcoding the PWM frequency to 46 KHz, which divided
by 600 would result in a PWM frequency of approx. 78 Hz, which mostly
still works fine. There are some bug reports about the LCD backlight
flickering after suspend/resume which are likely caused by this issue.

But with the upcoming patch-series to finally switch the i915 drivers
code for external PWM controllers to use the atomic API and to honor
the PWM frequency specified in the video BIOS (VBT), this becomes a much
bigger problem. On most cases the VBT specifies either 200 Hz or 20
KHz as PWM frequency, which with the mentioned issue ends up being either
1/3 Hz, where the backlight actually visible blinks on and off every 3s,
or in 33 Hz and horrible flickering of the backlight.

There are a number of possible solutions to this problem:

1. Make acpi_lpss_save_ctx() run before GFX0._PS3
  Pro: Clean solution from pov of not medling with save/restore ctx code
  Con: As mentioned the current ordering is the right thing to do
  Con: Requires assymmetry in at what suspend/resume phase we do the save vs
   restore, requiring more suspend/resume ordering hacks in already
   convoluted acpi_lpss.c suspend/resume code.
2. Do some sort of save once mode for the LPSS ctx
  Pro: Reasonably clean
  Con: Needs a new LPSS flag + code changes to handle the flag
3. Detect we have failed to save the ctx registers and do not restore them
  Pro: Not PWM specific, might help with issues on other LPSS devices too
  Con: If we can get away with not restoring the ctx why bother with it at
   all?
4. Do not save the ctx for CHT PWM controllers
  Pro: Clean, as simple as dropping a flag?
  Con: Not so simple as dropping a flag, needs a new flag to ensure that
   we still do lpss_deassert_reset() on device activation.
5. Make the pwm-lpss code fixup the LPSS-context registers
  Pro: Keeps acpi_lpss.c code clean
  Con: Moves knowledge of LPSS-context into the pwm-lpss.c code

1 and 5 both do not seem to be a desirable way forward.

3 and 4 seem ok, but they both assume that restoring the LPSS-context
registers is not necessary. I have done a couple of test and those do
show that restoring the LPSS-context indeed does not seem to be necessary
on devices using s2idle suspend (and successfully reaching S0i3). But I
have no hardware to test deep / S3 suspend. So I'm not sure that not
restoring the context is safe.

That leaves solution 2, which is about as simple / clean as 3 and 4,
so this commit fixes the described problem by implementing a new
LPSS_SAVE_CTX_ONCE flag and setting that for the CHT PWM controllers.

Signed-off-by: Hans de Goede 
---
  drivers/acpi/acpi_lpss.c | 19 ---
  1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 67892fc0b822..26933e6b7b8c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -68,6 +68,14 @@ ACPI_MODULE_NAME("acpi_lpss");
  #define LPSS_LTR  BIT(3)
  #define LPSS_SAVE_CTX BIT(4)
  #define LPSS_NO_D3_DELAY  BIT(5)
+/*
+ * For some devices the DSDT AML code for another device turns off the device
+ * before our suspend handler runs, causing us 

[PATCH v3 1/1] drm/mm: add ig_frag selftest

2020-06-07 Thread Nirmoy Das
This patch introduces fragmentation in the address range
and measures time taken by 10k and 20k insertions. ig_frag()
will fail if the time taken by 20k insertions takes more than
4 times of 10k insertions as we know that insertions should at
most scale quadratically.

v2:
introduce fragmentation by freeing every other node.
only test bottom-up and top-down for now.

v3:
fix incorrect mode check

Signed-off-by: Nirmoy Das 
---
 drivers/gpu/drm/selftests/drm_mm_selftests.h |   1 +
 drivers/gpu/drm/selftests/test-drm_mm.c  | 124 +++
 2 files changed, 125 insertions(+)

diff --git a/drivers/gpu/drm/selftests/drm_mm_selftests.h 
b/drivers/gpu/drm/selftests/drm_mm_selftests.h
index 6b943ea1c57d..8c87c964176b 100644
--- a/drivers/gpu/drm/selftests/drm_mm_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_mm_selftests.h
@@ -14,6 +14,7 @@ selftest(insert, igt_insert)
 selftest(replace, igt_replace)
 selftest(insert_range, igt_insert_range)
 selftest(align, igt_align)
+selftest(frag, igt_frag)
 selftest(align32, igt_align32)
 selftest(align64, igt_align64)
 selftest(evict, igt_evict)
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c 
b/drivers/gpu/drm/selftests/test-drm_mm.c
index 9aabe82dcd3a..ca5f35def905 100644
--- a/drivers/gpu/drm/selftests/test-drm_mm.c
+++ b/drivers/gpu/drm/selftests/test-drm_mm.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -1033,6 +1034,129 @@ static int igt_insert_range(void *ignored)
return 0;
 }
 
+static int prepare_igt_frag(struct drm_mm *mm,
+   struct drm_mm_node *nodes,
+   unsigned int num_insert,
+   const struct insert_mode *mode)
+{
+   unsigned int size = 4096;
+   unsigned int i;
+   u64 ret = -EINVAL;
+
+   for (i = 0; i < num_insert; i++) {
+   if (!expect_insert(mm, &nodes[i], size, 0, i,
+  mode) != 0) {
+   pr_err("%s insert failed\n", mode->name);
+   goto out;
+   }
+   }
+
+   /* introduce fragmentation by freeing every other node */
+   for (i = 0; i < num_insert; i++) {
+   if (i % 2 == 0)
+   drm_mm_remove_node(&nodes[i]);
+   }
+
+out:
+   return ret;
+
+}
+
+static u64 get_insert_time(struct drm_mm *mm,
+  unsigned int num_insert,
+  struct drm_mm_node *nodes,
+  const struct insert_mode *mode)
+{
+   unsigned int size = 8192;
+   ktime_t start;
+   unsigned int i;
+   u64 ret = -EINVAL;
+
+   start = ktime_get();
+   for (i = 0; i < num_insert; i++) {
+   if (!expect_insert(mm, &nodes[i], size, 0, i, mode) != 0) {
+   pr_err("%s insert failed\n", mode->name);
+   goto out;
+   }
+   }
+
+   ret = ktime_to_ns(ktime_sub(ktime_get(), start));
+
+out:
+   return ret;
+
+}
+
+static int igt_frag(void *ignored)
+{
+   struct drm_mm mm;
+   const struct insert_mode *mode;
+   struct drm_mm_node *nodes, *node, *next;
+   unsigned int insert_size = 1;
+   unsigned int scale_factor = 4;
+   int ret = -EINVAL;
+
+   /* We need 4 * insert_size nodes to hold intermediate allocated
+* drm_mm nodes.
+* 1 times for prepare_igt_frag()
+* 1 times for get_insert_time()
+* 2 times for get_insert_time()
+*/
+   nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes)));
+   if (!nodes)
+   return -ENOMEM;
+
+   /* For BOTTOMUP and TOPDOWN, we first fragment the
+* address space using prepare_igt_frag() and then try to verify
+* that that insertions scale quadratically from 10k to 20k insertions
+*/
+   drm_mm_init(&mm, 1, U64_MAX - 2);
+   for (mode = insert_modes; mode->name; mode++) {
+   u64 insert_time1, insert_time2;
+
+   if (mode->mode != DRM_MM_INSERT_LOW &&
+   mode->mode != DRM_MM_INSERT_HIGH)
+   continue;
+
+   ret = prepare_igt_frag(&mm, nodes, insert_size, mode);
+   if (!ret)
+   goto err;
+
+   insert_time1 = get_insert_time(&mm, insert_size,
+  nodes + insert_size, mode);
+   if (insert_time1 < 0)
+   goto err;
+
+   insert_time2 = get_insert_time(&mm, (insert_size * 2),
+  nodes + insert_size * 2, mode);
+   if (insert_time2 < 0)
+   goto err;
+
+   pr_info("%s fragmented insert of %u and %u insertions took %llu 
and %llu nsecs\n",
+   mode->name, insert_size, insert_size * 2,
+   insert_time1, insert_time2);
+
+   if (insert_time2 > (sca