All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH/RFC 00/48] Request API and proof-of-concept implementation
@ 2015-12-17  8:39 ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Hello,

This patch series is my first proposal for the V4L2 request API.

The concept is based on Hans Verkuil's initial implementation. A recently
rebased version is available at

	http://git.linuxtv.org/hverkuil/media_tree.git/log/?h=requests2

I have reworked the initial proposal extensively and implemented proof of
concept support for requests in the Renesas VSP1 driver. The VSP1 hardware is
a good candidate here as it supports applying configurations stored in system
memory atomically.

As the first use case for the request API with the VSP1 driver is to configure
pad formats I have decided to concentrate on that feature and have dropped
Hans' support for the API in the V4L2 control framework. By no mean does this
imply that I consider controls as a invalid or even second class use case, I
just had to pick a reasonable initial target without trying to save the world
straight away. I will include support for controls as a second step as I will
eventually need them for the VSP1 driver as well.


Patches 01/48 to 20/48 rework the VSP1 driver to prepare for request API
support. I won't go as far as saying there's nothing interesting there, but
feel free to skip review of those patches if your main interest here is the
request API itself.

Patches 21/48 to 24/48 add support for the request API to the media controller
framework. The corresponding DocBook documentation is available in patch
35/48. As those patches touch the media controller core I will rebase them on
top of the ongoing media controller rework when it will be finalized.

Patches 25/48 to 27/48 then add support for the request API to the V4L2
userspace API, in particular for buffers (25/48), formats (26/48) and subdev
formats and selections (27/48). The corresponding DocBook documentation is
available in patches 36/48 to 38/40.

Patch 28/48 implement in-kernel support for requests in format operations,
patches 29/48 to 31/48 in the subdev operations, and patches 32/48 to 34/48 in
videobuf2.

Patches 39/48 to 48/48 finally make use of all the new infrastructure and
add request API support in the VSP1 driver.


The code depends on several VSP1 and DU patch series previously posted. For
convenience you can access it on top of its dependencies at

	git://linuxtv.org/pinchartl/media.git vsp1-kms-request-20151217


As this series introduces a new API, support for it in userspace is needed. I
have implemented quick & dirty request API support in yavta and media-ctl for
testing purpose. The code is available in the following git trees.

	git://git.ideasonboard.org/yavta.git requests
	git://linuxtv.org/pinchartl/v4l-utils.git requests


Last but not least, the procedure I've followed for the simplest tests on the
Renesas Koelsch board is as follows.

1. Configure a simple memory-to-memory pipeline

$ media-ctl -d /dev/media0 -r
$ media-ctl -d /dev/media0 -l "'fe928000.vsp1 rpf.0':1 -> 'fe928000.vsp1 wpf.0':0 [1]"
$ media-ctl -d /dev/media0 -l "'fe928000.vsp1 wpf.0':1 -> 'fe928000.vsp1 wpf.0 output':0 [1]"
$ media-ctl -d /dev/media0 -V "'fe928000.vsp1 rpf.0':0 [fmt:AYUV32/1024x768]"
$ media-ctl -d /dev/media0 -V "'fe928000.vsp1 wpf.0':0 [fmt:AYUV32/1024x768]"
$ media-ctl -d /dev/media0 -V "'fe928000.vsp1 wpf.0':1 [fmt:AYUV32/1024x768]"

2. Create and fill a request with media-ctl

$ media-ctl -i
req:alloc
'fe928000.vsp1 rpf.0':0 [fmt:AYUV32/1024x768]
'fe928000.vsp1 wpf.0':0 [fmt:AYUV32/1024x768]
'fe928000.vsp1 wpf.0':1 [fmt:AYUV32/1024x768]

(do not exit media-ctl at this point)

This allocates and fills request number 1.

3. Queue buffers on the input and output video nodes

$ yavta --request 1 -c1 -n 1 -f YUYV -s 1024x768 /dev/video0
$ yavta --request 1 -c1 -n 1 -f YUYV -s 1024x768 -F /dev/video5

4. Queue the request in the running media-ctl -i session

req:queue

At this point the two yavta commands should complete.

5. Create and fill a scond request with different parameters in the same
media-ctl -i session

req:alloc
'fe928000.vsp1 rpf.0':0 [fmt:AYUV32/640x480]
'fe928000.vsp1 wpf.0':0 [fmt:AYUV32/640x480]
'fe928000.vsp1 wpf.0':1 [fmt:AYUV32/640x480]

(do not exit media-ctl at this point)

This allocates and fills request number 2.

6. Queue buffers on the input and output video nodes

$ yavta --request 1 -c1 -n 1 -f YUYV -s 640x480 /dev/video0
$ yavta --request 1 -c1 -n 1 -f YUYV -s 640x480 -F /dev/video5

7. Queue the request in the running media-ctl -i session

req:queue

At this point the two yavta commands should complete.


I will work on automating the procedure and test tools, suggestions are
welcome.


Hans Verkuil (3):
  videodev2.h: Add request field to v4l2_buffer
  vb2: Add allow_requests flag
  vb2: Add helper function to queue request-specific buffer.

Laurent Pinchart (45):
  v4l: vsp1: Use pipeline display list to decide how to write to modules
  v4l: vsp1: Always setup the display list
  v4l: vsp1: Simplify frame end processing
  v4l: vsp1: Split display list manager from display list
  v4l: vsp1: Store the display list manager in the WPF
  v4l: vsp1: bru: Don't program background color in control set handler
  v4l: vsp1: rwpf: Don't program alpha value in control set handler
  v4l: vsp1: sru: Don't program intensity in control set handler
  v4l: vsp1: Don't setup control handler when starting streaming
  v4l: vsp1: Enable display list support for the HS[IT], LUT, SRU and
    UDS
  v4l: vsp1: Don't configure RPF memory buffers before calculating
    offsets
  v4l: vsp1: Remove unneeded entity streaming flag
  v4l: vsp1: Document calling context of vsp1_pipeline_propagate_alpha()
  v4l: vsp1: Fix 80 characters per line violations
  v4l: vsp1: Add header display list support
  v4l: vsp1: Use display lists with the userspace API
  v4l: vsp1: Move subdev initialization code to vsp1_entity_init()
  v4l: vsp1: Consolidate entity ops in a struct vsp1_entity_operations
  v4l: vsp1: Fix BRU try compose rectangle storage
  v4l: vsp1: Add race condition FIXME comment
  media: Move media_device link_notify operation to an ops structure
  media: Add per-file-handle data support
  media: Add request API
  media: Add per-entity request data support
  videodev2.h: Add request field to v4l2_pix_format_mplane
  v4l2-subdev.h: Add request field to format and selection structures
  v4l: Support the request API in format operations
  v4l: subdev: Add pad config allocator and init
  v4l: subdev: Call pad init_cfg operation when opening subdevs
  v4l: subdev: Support the request API in format and selection
    operations
  vb2: Add helper function to check for request buffers
  DocBook: media: Document the media request API
  DocBook: media: Document the V4L2 request API
  DocBook: media: Document the subdev selection API
  DocBook: media: Document the V4L2 subdev request API
  v4l: vsp1: Implement and use the subdev pad::init_cfg configuration
  v4l: vsp1: Store active formats in a pad config structure
  v4l: vsp1: Store active selection rectangles in a pad config structure
  v4l: vsp1: Create a new configure operation to setup modules
  v4l: vsp1: Merge RPF and WPF pad ops structures
  v4l: vsp1: Pass a media request to the module configure operations
  v4l: vsp1: Use __vsp1_video_try_format to initialize format at init
    time
  v4l: vsp1: Support video device formats stored in requests
  v4l: vsp1: Pass display list explicitly to configure functions
  v4l: vsp1: Support the request API

 Documentation/DocBook/media/v4l/common.xml         |   2 +
 Documentation/DocBook/media/v4l/io.xml             |  12 +-
 .../DocBook/media/v4l/media-controller.xml         |   1 +
 .../DocBook/media/v4l/media-ioc-request-cmd.xml    | 194 +++++++++++
 Documentation/DocBook/media/v4l/request-api.xml    |  90 ++++++
 .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   9 +
 Documentation/DocBook/media/v4l/vidioc-qbuf.xml    |   6 +
 .../DocBook/media/v4l/vidioc-subdev-g-fmt.xml      |  33 +-
 .../media/v4l/vidioc-subdev-g-selection.xml        |  65 +++-
 drivers/media/media-device.c                       | 275 ++++++++++++++++
 drivers/media/media-devnode.c                      |  19 +-
 drivers/media/media-entity.c                       |  11 +-
 drivers/media/platform/exynos4-is/media-dev.c      |   6 +-
 drivers/media/platform/omap3isp/isp.c              |   6 +-
 drivers/media/platform/vsp1/Makefile               |   3 +-
 drivers/media/platform/vsp1/vsp1.h                 |  13 -
 drivers/media/platform/vsp1/vsp1_bru.c             | 354 +++++++++++----------
 drivers/media/platform/vsp1/vsp1_bru.h             |   3 +-
 drivers/media/platform/vsp1/vsp1_dl.c              | 343 ++++++++++++--------
 drivers/media/platform/vsp1/vsp1_dl.h              |  42 ++-
 drivers/media/platform/vsp1/vsp1_drm.c             |  71 ++---
 drivers/media/platform/vsp1/vsp1_drm.h             |   5 +-
 drivers/media/platform/vsp1/vsp1_drv.c             |  28 +-
 drivers/media/platform/vsp1/vsp1_entity.c          | 200 +++++++-----
 drivers/media/platform/vsp1/vsp1_entity.h          |  53 ++-
 drivers/media/platform/vsp1/vsp1_hsit.c            | 104 +++---
 drivers/media/platform/vsp1/vsp1_lif.c             | 147 ++++-----
 drivers/media/platform/vsp1/vsp1_lut.c             | 113 ++++---
 drivers/media/platform/vsp1/vsp1_pipe.c            | 118 ++++---
 drivers/media/platform/vsp1/vsp1_pipe.h            |  13 +-
 drivers/media/platform/vsp1/vsp1_request.c         | 126 ++++++++
 drivers/media/platform/vsp1/vsp1_request.h         |  41 +++
 drivers/media/platform/vsp1/vsp1_rpf.c             | 226 +++++--------
 drivers/media/platform/vsp1/vsp1_rwpf.c            | 189 ++++++++---
 drivers/media/platform/vsp1/vsp1_rwpf.h            |  67 ++--
 drivers/media/platform/vsp1/vsp1_sru.c             | 205 ++++++------
 drivers/media/platform/vsp1/vsp1_sru.h             |   2 +
 drivers/media/platform/vsp1/vsp1_uds.c             | 209 ++++++------
 drivers/media/platform/vsp1/vsp1_uds.h             |   3 +-
 drivers/media/platform/vsp1/vsp1_video.c           | 170 ++++++----
 drivers/media/platform/vsp1/vsp1_wpf.c             | 267 +++++++---------
 drivers/media/usb/cpia2/cpia2_v4l.c                |   1 +
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c      |   4 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               | 125 +++++++-
 drivers/media/v4l2-core/v4l2-subdev.c              | 246 ++++++++++----
 drivers/media/v4l2-core/videobuf2-v4l2.c           |  55 ++++
 drivers/staging/media/omap4iss/iss.c               |   6 +-
 include/media/media-device.h                       |  62 +++-
 include/media/media-devnode.h                      |  18 +-
 include/media/media-entity.h                       |  12 +
 include/media/v4l2-dev.h                           |  13 +
 include/media/v4l2-subdev.h                        |  22 ++
 include/media/videobuf2-core.h                     |   2 +
 include/media/videobuf2-v4l2.h                     |   5 +
 include/uapi/linux/media.h                         |  12 +
 include/uapi/linux/v4l2-subdev.h                   |  15 +-
 include/uapi/linux/videodev2.h                     |   8 +-
 57 files changed, 2982 insertions(+), 1468 deletions(-)
 create mode 100644 Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml
 create mode 100644 Documentation/DocBook/media/v4l/request-api.xml
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.c
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.h

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* [PATCH/RFC 00/48] Request API and proof-of-concept implementation
@ 2015-12-17  8:39 ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Hello,

This patch series is my first proposal for the V4L2 request API.

The concept is based on Hans Verkuil's initial implementation. A recently
rebased version is available at

	http://git.linuxtv.org/hverkuil/media_tree.git/log/?h=requests2

I have reworked the initial proposal extensively and implemented proof of
concept support for requests in the Renesas VSP1 driver. The VSP1 hardware is
a good candidate here as it supports applying configurations stored in system
memory atomically.

As the first use case for the request API with the VSP1 driver is to configure
pad formats I have decided to concentrate on that feature and have dropped
Hans' support for the API in the V4L2 control framework. By no mean does this
imply that I consider controls as a invalid or even second class use case, I
just had to pick a reasonable initial target without trying to save the world
straight away. I will include support for controls as a second step as I will
eventually need them for the VSP1 driver as well.


Patches 01/48 to 20/48 rework the VSP1 driver to prepare for request API
support. I won't go as far as saying there's nothing interesting there, but
feel free to skip review of those patches if your main interest here is the
request API itself.

Patches 21/48 to 24/48 add support for the request API to the media controller
framework. The corresponding DocBook documentation is available in patch
35/48. As those patches touch the media controller core I will rebase them on
top of the ongoing media controller rework when it will be finalized.

Patches 25/48 to 27/48 then add support for the request API to the V4L2
userspace API, in particular for buffers (25/48), formats (26/48) and subdev
formats and selections (27/48). The corresponding DocBook documentation is
available in patches 36/48 to 38/40.

Patch 28/48 implement in-kernel support for requests in format operations,
patches 29/48 to 31/48 in the subdev operations, and patches 32/48 to 34/48 in
videobuf2.

Patches 39/48 to 48/48 finally make use of all the new infrastructure and
add request API support in the VSP1 driver.


The code depends on several VSP1 and DU patch series previously posted. For
convenience you can access it on top of its dependencies at

	git://linuxtv.org/pinchartl/media.git vsp1-kms-request-20151217


As this series introduces a new API, support for it in userspace is needed. I
have implemented quick & dirty request API support in yavta and media-ctl for
testing purpose. The code is available in the following git trees.

	git://git.ideasonboard.org/yavta.git requests
	git://linuxtv.org/pinchartl/v4l-utils.git requests


Last but not least, the procedure I've followed for the simplest tests on the
Renesas Koelsch board is as follows.

1. Configure a simple memory-to-memory pipeline

$ media-ctl -d /dev/media0 -r
$ media-ctl -d /dev/media0 -l "'fe928000.vsp1 rpf.0':1 -> 'fe928000.vsp1 wpf.0':0 [1]"
$ media-ctl -d /dev/media0 -l "'fe928000.vsp1 wpf.0':1 -> 'fe928000.vsp1 wpf.0 output':0 [1]"
$ media-ctl -d /dev/media0 -V "'fe928000.vsp1 rpf.0':0 [fmt:AYUV32/1024x768]"
$ media-ctl -d /dev/media0 -V "'fe928000.vsp1 wpf.0':0 [fmt:AYUV32/1024x768]"
$ media-ctl -d /dev/media0 -V "'fe928000.vsp1 wpf.0':1 [fmt:AYUV32/1024x768]"

2. Create and fill a request with media-ctl

$ media-ctl -i
req:alloc
'fe928000.vsp1 rpf.0':0 [fmt:AYUV32/1024x768]
'fe928000.vsp1 wpf.0':0 [fmt:AYUV32/1024x768]
'fe928000.vsp1 wpf.0':1 [fmt:AYUV32/1024x768]

(do not exit media-ctl at this point)

This allocates and fills request number 1.

3. Queue buffers on the input and output video nodes

$ yavta --request 1 -c1 -n 1 -f YUYV -s 1024x768 /dev/video0
$ yavta --request 1 -c1 -n 1 -f YUYV -s 1024x768 -F /dev/video5

4. Queue the request in the running media-ctl -i session

req:queue

At this point the two yavta commands should complete.

5. Create and fill a scond request with different parameters in the same
media-ctl -i session

req:alloc
'fe928000.vsp1 rpf.0':0 [fmt:AYUV32/640x480]
'fe928000.vsp1 wpf.0':0 [fmt:AYUV32/640x480]
'fe928000.vsp1 wpf.0':1 [fmt:AYUV32/640x480]

(do not exit media-ctl at this point)

This allocates and fills request number 2.

6. Queue buffers on the input and output video nodes

$ yavta --request 1 -c1 -n 1 -f YUYV -s 640x480 /dev/video0
$ yavta --request 1 -c1 -n 1 -f YUYV -s 640x480 -F /dev/video5

7. Queue the request in the running media-ctl -i session

req:queue

At this point the two yavta commands should complete.


I will work on automating the procedure and test tools, suggestions are
welcome.


Hans Verkuil (3):
  videodev2.h: Add request field to v4l2_buffer
  vb2: Add allow_requests flag
  vb2: Add helper function to queue request-specific buffer.

Laurent Pinchart (45):
  v4l: vsp1: Use pipeline display list to decide how to write to modules
  v4l: vsp1: Always setup the display list
  v4l: vsp1: Simplify frame end processing
  v4l: vsp1: Split display list manager from display list
  v4l: vsp1: Store the display list manager in the WPF
  v4l: vsp1: bru: Don't program background color in control set handler
  v4l: vsp1: rwpf: Don't program alpha value in control set handler
  v4l: vsp1: sru: Don't program intensity in control set handler
  v4l: vsp1: Don't setup control handler when starting streaming
  v4l: vsp1: Enable display list support for the HS[IT], LUT, SRU and
    UDS
  v4l: vsp1: Don't configure RPF memory buffers before calculating
    offsets
  v4l: vsp1: Remove unneeded entity streaming flag
  v4l: vsp1: Document calling context of vsp1_pipeline_propagate_alpha()
  v4l: vsp1: Fix 80 characters per line violations
  v4l: vsp1: Add header display list support
  v4l: vsp1: Use display lists with the userspace API
  v4l: vsp1: Move subdev initialization code to vsp1_entity_init()
  v4l: vsp1: Consolidate entity ops in a struct vsp1_entity_operations
  v4l: vsp1: Fix BRU try compose rectangle storage
  v4l: vsp1: Add race condition FIXME comment
  media: Move media_device link_notify operation to an ops structure
  media: Add per-file-handle data support
  media: Add request API
  media: Add per-entity request data support
  videodev2.h: Add request field to v4l2_pix_format_mplane
  v4l2-subdev.h: Add request field to format and selection structures
  v4l: Support the request API in format operations
  v4l: subdev: Add pad config allocator and init
  v4l: subdev: Call pad init_cfg operation when opening subdevs
  v4l: subdev: Support the request API in format and selection
    operations
  vb2: Add helper function to check for request buffers
  DocBook: media: Document the media request API
  DocBook: media: Document the V4L2 request API
  DocBook: media: Document the subdev selection API
  DocBook: media: Document the V4L2 subdev request API
  v4l: vsp1: Implement and use the subdev pad::init_cfg configuration
  v4l: vsp1: Store active formats in a pad config structure
  v4l: vsp1: Store active selection rectangles in a pad config structure
  v4l: vsp1: Create a new configure operation to setup modules
  v4l: vsp1: Merge RPF and WPF pad ops structures
  v4l: vsp1: Pass a media request to the module configure operations
  v4l: vsp1: Use __vsp1_video_try_format to initialize format at init
    time
  v4l: vsp1: Support video device formats stored in requests
  v4l: vsp1: Pass display list explicitly to configure functions
  v4l: vsp1: Support the request API

 Documentation/DocBook/media/v4l/common.xml         |   2 +
 Documentation/DocBook/media/v4l/io.xml             |  12 +-
 .../DocBook/media/v4l/media-controller.xml         |   1 +
 .../DocBook/media/v4l/media-ioc-request-cmd.xml    | 194 +++++++++++
 Documentation/DocBook/media/v4l/request-api.xml    |  90 ++++++
 .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   9 +
 Documentation/DocBook/media/v4l/vidioc-qbuf.xml    |   6 +
 .../DocBook/media/v4l/vidioc-subdev-g-fmt.xml      |  33 +-
 .../media/v4l/vidioc-subdev-g-selection.xml        |  65 +++-
 drivers/media/media-device.c                       | 275 ++++++++++++++++
 drivers/media/media-devnode.c                      |  19 +-
 drivers/media/media-entity.c                       |  11 +-
 drivers/media/platform/exynos4-is/media-dev.c      |   6 +-
 drivers/media/platform/omap3isp/isp.c              |   6 +-
 drivers/media/platform/vsp1/Makefile               |   3 +-
 drivers/media/platform/vsp1/vsp1.h                 |  13 -
 drivers/media/platform/vsp1/vsp1_bru.c             | 354 +++++++++++----------
 drivers/media/platform/vsp1/vsp1_bru.h             |   3 +-
 drivers/media/platform/vsp1/vsp1_dl.c              | 343 ++++++++++++--------
 drivers/media/platform/vsp1/vsp1_dl.h              |  42 ++-
 drivers/media/platform/vsp1/vsp1_drm.c             |  71 ++---
 drivers/media/platform/vsp1/vsp1_drm.h             |   5 +-
 drivers/media/platform/vsp1/vsp1_drv.c             |  28 +-
 drivers/media/platform/vsp1/vsp1_entity.c          | 200 +++++++-----
 drivers/media/platform/vsp1/vsp1_entity.h          |  53 ++-
 drivers/media/platform/vsp1/vsp1_hsit.c            | 104 +++---
 drivers/media/platform/vsp1/vsp1_lif.c             | 147 ++++-----
 drivers/media/platform/vsp1/vsp1_lut.c             | 113 ++++---
 drivers/media/platform/vsp1/vsp1_pipe.c            | 118 ++++---
 drivers/media/platform/vsp1/vsp1_pipe.h            |  13 +-
 drivers/media/platform/vsp1/vsp1_request.c         | 126 ++++++++
 drivers/media/platform/vsp1/vsp1_request.h         |  41 +++
 drivers/media/platform/vsp1/vsp1_rpf.c             | 226 +++++--------
 drivers/media/platform/vsp1/vsp1_rwpf.c            | 189 ++++++++---
 drivers/media/platform/vsp1/vsp1_rwpf.h            |  67 ++--
 drivers/media/platform/vsp1/vsp1_sru.c             | 205 ++++++------
 drivers/media/platform/vsp1/vsp1_sru.h             |   2 +
 drivers/media/platform/vsp1/vsp1_uds.c             | 209 ++++++------
 drivers/media/platform/vsp1/vsp1_uds.h             |   3 +-
 drivers/media/platform/vsp1/vsp1_video.c           | 170 ++++++----
 drivers/media/platform/vsp1/vsp1_wpf.c             | 267 +++++++---------
 drivers/media/usb/cpia2/cpia2_v4l.c                |   1 +
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c      |   4 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               | 125 +++++++-
 drivers/media/v4l2-core/v4l2-subdev.c              | 246 ++++++++++----
 drivers/media/v4l2-core/videobuf2-v4l2.c           |  55 ++++
 drivers/staging/media/omap4iss/iss.c               |   6 +-
 include/media/media-device.h                       |  62 +++-
 include/media/media-devnode.h                      |  18 +-
 include/media/media-entity.h                       |  12 +
 include/media/v4l2-dev.h                           |  13 +
 include/media/v4l2-subdev.h                        |  22 ++
 include/media/videobuf2-core.h                     |   2 +
 include/media/videobuf2-v4l2.h                     |   5 +
 include/uapi/linux/media.h                         |  12 +
 include/uapi/linux/v4l2-subdev.h                   |  15 +-
 include/uapi/linux/videodev2.h                     |   8 +-
 57 files changed, 2982 insertions(+), 1468 deletions(-)
 create mode 100644 Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml
 create mode 100644 Documentation/DocBook/media/v4l/request-api.xml
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.c
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.h

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* [PATCH/RFC 01/48] v4l: vsp1: Use pipeline display list to decide how to write to modules
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

This allows getting rid of the vsp1_device::use_dl field.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1.h        | 12 ------------
 drivers/media/platform/vsp1/vsp1_dl.c     |  4 +---
 drivers/media/platform/vsp1/vsp1_dl.h     | 12 ++----------
 drivers/media/platform/vsp1/vsp1_drv.c    |  9 +++------
 drivers/media/platform/vsp1/vsp1_entity.c | 12 ++++++++++++
 drivers/media/platform/vsp1/vsp1_entity.h |  2 ++
 6 files changed, 20 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 910d6b8e8b50..bea232820ead 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -85,8 +85,6 @@ struct vsp1_device {
 	struct media_entity_operations media_ops;
 
 	struct vsp1_drm *drm;
-
-	bool use_dl;
 };
 
 int vsp1_device_get(struct vsp1_device *vsp1);
@@ -104,14 +102,4 @@ static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data)
 	iowrite32(data, vsp1->mmio + reg);
 }
 
-#include "vsp1_dl.h"
-
-static inline void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-	if (e->vsp1->use_dl)
-		vsp1_dl_add(e, reg, data);
-	else
-		vsp1_write(e->vsp1, reg, data);
-}
-
 #endif /* __VSP1_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index a4dcccf0778b..1e5cff590e87 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -128,10 +128,8 @@ void vsp1_dl_begin(struct vsp1_dl *dl)
 	list->reg_count = 0;
 }
 
-void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data)
+void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data)
 {
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
-	struct vsp1_dl *dl = pipe->dl;
 	struct vsp1_dl_list *list = dl->lists.write;
 
 	list->body[list->reg_count].addr = reg;
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 448c4250e54c..f4116ca59c28 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -13,7 +13,7 @@
 #ifndef __VSP1_DL_H__
 #define __VSP1_DL_H__
 
-#include "vsp1_entity.h"
+#include <linux/types.h>
 
 struct vsp1_device;
 struct vsp1_dl;
@@ -25,18 +25,10 @@ void vsp1_dl_setup(struct vsp1_device *vsp1);
 
 void vsp1_dl_reset(struct vsp1_dl *dl);
 void vsp1_dl_begin(struct vsp1_dl *dl);
-void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data);
+void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data);
 void vsp1_dl_commit(struct vsp1_dl *dl);
 
 void vsp1_dl_irq_display_start(struct vsp1_dl *dl);
 void vsp1_dl_irq_frame_end(struct vsp1_dl *dl);
 
-static inline void vsp1_dl_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-	if (e->vsp1->use_dl)
-		vsp1_dl_add(e, reg, data);
-	else
-		vsp1_write(e->vsp1, reg, data);
-}
-
 #endif /* __VSP1_DL_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 1cfda6b6b659..cf469bd76f43 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -387,13 +387,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 			goto done;
 	}
 
-	if (vsp1->info->uapi) {
-		vsp1->use_dl = false;
+	if (vsp1->info->uapi)
 		ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
-	} else {
-		vsp1->use_dl = true;
+	else
 		ret = vsp1_drm_init(vsp1);
-	}
 
 done:
 	if (ret < 0)
@@ -461,7 +458,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-	if (vsp1->use_dl)
+	if (!vsp1->info->uapi)
 		vsp1_dl_setup(vsp1);
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index d65cf8035a92..5ba535809131 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -19,7 +19,19 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_entity.h"
+#include "vsp1_pipe.h"
+
+void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
+
+	if (pipe->dl)
+		vsp1_dl_add(pipe->dl, reg, data);
+	else
+		vsp1_write(e->vsp1, reg, data);
+}
 
 bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
 {
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 83570dfde8ec..311d5b64c9a5 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -103,4 +103,6 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
+void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data);
+
 #endif /* __VSP1_ENTITY_H__ */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 01/48] v4l: vsp1: Use pipeline display list to decide how to write to modules
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

This allows getting rid of the vsp1_device::use_dl field.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1.h        | 12 ------------
 drivers/media/platform/vsp1/vsp1_dl.c     |  4 +---
 drivers/media/platform/vsp1/vsp1_dl.h     | 12 ++----------
 drivers/media/platform/vsp1/vsp1_drv.c    |  9 +++------
 drivers/media/platform/vsp1/vsp1_entity.c | 12 ++++++++++++
 drivers/media/platform/vsp1/vsp1_entity.h |  2 ++
 6 files changed, 20 insertions(+), 31 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 910d6b8e8b50..bea232820ead 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -85,8 +85,6 @@ struct vsp1_device {
 	struct media_entity_operations media_ops;
 
 	struct vsp1_drm *drm;
-
-	bool use_dl;
 };
 
 int vsp1_device_get(struct vsp1_device *vsp1);
@@ -104,14 +102,4 @@ static inline void vsp1_write(struct vsp1_device *vsp1, u32 reg, u32 data)
 	iowrite32(data, vsp1->mmio + reg);
 }
 
-#include "vsp1_dl.h"
-
-static inline void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-	if (e->vsp1->use_dl)
-		vsp1_dl_add(e, reg, data);
-	else
-		vsp1_write(e->vsp1, reg, data);
-}
-
 #endif /* __VSP1_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index a4dcccf0778b..1e5cff590e87 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -128,10 +128,8 @@ void vsp1_dl_begin(struct vsp1_dl *dl)
 	list->reg_count = 0;
 }
 
-void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data)
+void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data)
 {
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
-	struct vsp1_dl *dl = pipe->dl;
 	struct vsp1_dl_list *list = dl->lists.write;
 
 	list->body[list->reg_count].addr = reg;
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 448c4250e54c..f4116ca59c28 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -13,7 +13,7 @@
 #ifndef __VSP1_DL_H__
 #define __VSP1_DL_H__
 
-#include "vsp1_entity.h"
+#include <linux/types.h>
 
 struct vsp1_device;
 struct vsp1_dl;
@@ -25,18 +25,10 @@ void vsp1_dl_setup(struct vsp1_device *vsp1);
 
 void vsp1_dl_reset(struct vsp1_dl *dl);
 void vsp1_dl_begin(struct vsp1_dl *dl);
-void vsp1_dl_add(struct vsp1_entity *e, u32 reg, u32 data);
+void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data);
 void vsp1_dl_commit(struct vsp1_dl *dl);
 
 void vsp1_dl_irq_display_start(struct vsp1_dl *dl);
 void vsp1_dl_irq_frame_end(struct vsp1_dl *dl);
 
-static inline void vsp1_dl_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-	if (e->vsp1->use_dl)
-		vsp1_dl_add(e, reg, data);
-	else
-		vsp1_write(e->vsp1, reg, data);
-}
-
 #endif /* __VSP1_DL_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 1cfda6b6b659..cf469bd76f43 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -387,13 +387,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 			goto done;
 	}
 
-	if (vsp1->info->uapi) {
-		vsp1->use_dl = false;
+	if (vsp1->info->uapi)
 		ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
-	} else {
-		vsp1->use_dl = true;
+	else
 		ret = vsp1_drm_init(vsp1);
-	}
 
 done:
 	if (ret < 0)
@@ -461,7 +458,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-	if (vsp1->use_dl)
+	if (!vsp1->info->uapi)
 		vsp1_dl_setup(vsp1);
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index d65cf8035a92..5ba535809131 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -19,7 +19,19 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_entity.h"
+#include "vsp1_pipe.h"
+
+void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
+
+	if (pipe->dl)
+		vsp1_dl_add(pipe->dl, reg, data);
+	else
+		vsp1_write(e->vsp1, reg, data);
+}
 
 bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
 {
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 83570dfde8ec..311d5b64c9a5 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -103,4 +103,6 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
+void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data);
+
 #endif /* __VSP1_ENTITY_H__ */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 02/48] v4l: vsp1: Always setup the display list
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Make sure display list usage is correctly disabled by always setting up
the corresponding registers, including when the display list feature
isn't used.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c  | 7 +++----
 drivers/media/platform/vsp1/vsp1_drv.c | 3 +--
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 1e5cff590e87..caf20f5f31f3 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -243,15 +243,14 @@ done:
 
 void vsp1_dl_setup(struct vsp1_device *vsp1)
 {
-	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
-		 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
-		 | VI6_DL_CTRL_DLE;
+	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT);
 
 	/* The DRM pipeline operates with header-less display lists in
 	 * Continuous Frame Mode.
 	 */
 	if (vsp1->drm)
-		ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
+		ctrl |= VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
+		     |  VI6_DL_CTRL_DLE | VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
 
 	vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
 	vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index cf469bd76f43..871cbeea5695 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -458,8 +458,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-	if (!vsp1->info->uapi)
-		vsp1_dl_setup(vsp1);
+	vsp1_dl_setup(vsp1);
 
 	return 0;
 }
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 02/48] v4l: vsp1: Always setup the display list
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Make sure display list usage is correctly disabled by always setting up
the corresponding registers, including when the display list feature
isn't used.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c  | 7 +++----
 drivers/media/platform/vsp1/vsp1_drv.c | 3 +--
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 1e5cff590e87..caf20f5f31f3 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -243,15 +243,14 @@ done:
 
 void vsp1_dl_setup(struct vsp1_device *vsp1)
 {
-	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
-		 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
-		 | VI6_DL_CTRL_DLE;
+	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT);
 
 	/* The DRM pipeline operates with header-less display lists in
 	 * Continuous Frame Mode.
 	 */
 	if (vsp1->drm)
-		ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
+		ctrl |= VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
+		     |  VI6_DL_CTRL_DLE | VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
 
 	vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
 	vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index cf469bd76f43..871cbeea5695 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -458,8 +458,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-	if (!vsp1->info->uapi)
-		vsp1_dl_setup(vsp1);
+	vsp1_dl_setup(vsp1);
 
 	return 0;
 }
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 03/48] v4l: vsp1: Simplify frame end processing
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The DRM pipeline, as it runs in automatic restart mode, never sees the
pipeline state set to VSP1_PIPELINE_STOPPING or VSP1_PIPELINE_STOPPED
when running the frame end interrupt handler. We can thus skip the
checks various checks in the handler and return immediately.

Similarly the DRM frame end handler calls vsp1_pipeline_run()
unnecessarily, as the state there is never VSP1_PIPELINE_STOPPED. Remove
the function call and the frame end handler is it's now empty.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c  | 15 ---------------
 drivers/media/platform/vsp1/vsp1_pipe.c |  9 ++++++---
 2 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 302d02a5c1c0..1cfa8a0e43b6 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -27,20 +27,6 @@
 #include "vsp1_rwpf.h"
 
 /* -----------------------------------------------------------------------------
- * Runtime Handling
- */
-
-static void vsp1_drm_pipeline_frame_end(struct vsp1_pipeline *pipe)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pipe->irqlock, flags);
-	if (pipe->num_inputs)
-		vsp1_pipeline_run(pipe);
-	spin_unlock_irqrestore(&pipe->irqlock, flags);
-}
-
-/* -----------------------------------------------------------------------------
  * DU Driver API
  */
 
@@ -569,7 +555,6 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
-	pipe->frame_end = vsp1_drm_pipeline_frame_end;
 
 	/* The DRM pipeline is static, add entities manually. */
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 96f0e7d4c400..9c6d295ca843 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -268,7 +268,8 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 		vsp1_dl_irq_frame_end(pipe->dl);
 
 	/* Signal frame end to the pipeline handler. */
-	pipe->frame_end(pipe);
+	if (pipe->frame_end)
+		pipe->frame_end(pipe);
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
@@ -277,8 +278,10 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 	/* When using display lists in continuous frame mode the pipeline is
 	 * automatically restarted by the hardware.
 	 */
-	if (!pipe->dl)
-		pipe->state = VSP1_PIPELINE_STOPPED;
+	if (pipe->dl)
+		goto done;
+
+	pipe->state = VSP1_PIPELINE_STOPPED;
 
 	/* If a stop has been requested, mark the pipeline as stopped and
 	 * return.
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 03/48] v4l: vsp1: Simplify frame end processing
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The DRM pipeline, as it runs in automatic restart mode, never sees the
pipeline state set to VSP1_PIPELINE_STOPPING or VSP1_PIPELINE_STOPPED
when running the frame end interrupt handler. We can thus skip the
checks various checks in the handler and return immediately.

Similarly the DRM frame end handler calls vsp1_pipeline_run()
unnecessarily, as the state there is never VSP1_PIPELINE_STOPPED. Remove
the function call and the frame end handler is it's now empty.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c  | 15 ---------------
 drivers/media/platform/vsp1/vsp1_pipe.c |  9 ++++++---
 2 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 302d02a5c1c0..1cfa8a0e43b6 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -27,20 +27,6 @@
 #include "vsp1_rwpf.h"
 
 /* -----------------------------------------------------------------------------
- * Runtime Handling
- */
-
-static void vsp1_drm_pipeline_frame_end(struct vsp1_pipeline *pipe)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pipe->irqlock, flags);
-	if (pipe->num_inputs)
-		vsp1_pipeline_run(pipe);
-	spin_unlock_irqrestore(&pipe->irqlock, flags);
-}
-
-/* -----------------------------------------------------------------------------
  * DU Driver API
  */
 
@@ -569,7 +555,6 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
-	pipe->frame_end = vsp1_drm_pipeline_frame_end;
 
 	/* The DRM pipeline is static, add entities manually. */
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 96f0e7d4c400..9c6d295ca843 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -268,7 +268,8 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 		vsp1_dl_irq_frame_end(pipe->dl);
 
 	/* Signal frame end to the pipeline handler. */
-	pipe->frame_end(pipe);
+	if (pipe->frame_end)
+		pipe->frame_end(pipe);
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
@@ -277,8 +278,10 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 	/* When using display lists in continuous frame mode the pipeline is
 	 * automatically restarted by the hardware.
 	 */
-	if (!pipe->dl)
-		pipe->state = VSP1_PIPELINE_STOPPED;
+	if (pipe->dl)
+		goto done;
+
+	pipe->state = VSP1_PIPELINE_STOPPED;
 
 	/* If a stop has been requested, mark the pipeline as stopped and
 	 * return.
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 04/48] v4l: vsp1: Split display list manager from display list
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

This clarifies the API and prepares display list support for being used
to implement the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1.h        |   1 -
 drivers/media/platform/vsp1/vsp1_dl.c     | 264 ++++++++++++++----------------
 drivers/media/platform/vsp1/vsp1_dl.h     |  40 +++--
 drivers/media/platform/vsp1/vsp1_drm.c    |  32 ++--
 drivers/media/platform/vsp1/vsp1_drm.h    |  12 +-
 drivers/media/platform/vsp1/vsp1_drv.c    |  11 +-
 drivers/media/platform/vsp1/vsp1_entity.c |   2 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  13 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   5 +-
 9 files changed, 194 insertions(+), 186 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index bea232820ead..dae987a11a70 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -26,7 +26,6 @@
 struct clk;
 struct device;
 
-struct vsp1_dl;
 struct vsp1_drm;
 struct vsp1_entity;
 struct vsp1_platform_data;
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index caf20f5f31f3..5f49f52e22f2 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -37,117 +37,109 @@ struct vsp1_dl_entry {
 } __attribute__((__packed__));
 
 struct vsp1_dl_list {
-	size_t size;
-	int reg_count;
+	struct list_head list;
 
-	bool in_use;
+	struct vsp1_dl_manager *dlm;
 
 	struct vsp1_dl_entry *body;
 	dma_addr_t dma;
-};
-
-/**
- * struct vsp1_dl - Display List manager
- * @vsp1: the VSP1 device
- * @lock: protects the active, queued and pending lists
- * @lists.all: array of all allocate display lists
- * @lists.active: list currently being processed (loaded) by hardware
- * @lists.queued: list queued to the hardware (written to the DL registers)
- * @lists.pending: list waiting to be queued to the hardware
- * @lists.write: list being written to by software
- */
-struct vsp1_dl {
-	struct vsp1_device *vsp1;
-
-	spinlock_t lock;
-
 	size_t size;
-	dma_addr_t dma;
-	void *mem;
 
-	struct {
-		struct vsp1_dl_list all[VSP1_DL_NUM_LISTS];
-
-		struct vsp1_dl_list *active;
-		struct vsp1_dl_list *queued;
-		struct vsp1_dl_list *pending;
-		struct vsp1_dl_list *write;
-	} lists;
+	int reg_count;
 };
 
 /* -----------------------------------------------------------------------------
  * Display List Transaction Management
  */
 
-static void vsp1_dl_free_list(struct vsp1_dl_list *list)
+static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
 {
-	if (!list)
-		return;
+	struct vsp1_dl_list *dl;
 
-	list->in_use = false;
-}
+	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
+	if (!dl)
+		return NULL;
 
-void vsp1_dl_reset(struct vsp1_dl *dl)
-{
-	unsigned int i;
+	dl->dlm = dlm;
+	dl->size = VSP1_DL_BODY_SIZE;
+
+	dl->body = dma_alloc_writecombine(dlm->vsp1->dev, dl->size, &dl->dma,
+					  GFP_KERNEL);
+	if (!dl->body) {
+		kfree(dl);
+		return NULL;
+	}
 
-	dl->lists.active = NULL;
-	dl->lists.queued = NULL;
-	dl->lists.pending = NULL;
-	dl->lists.write = NULL;
+	return dl;
+}
 
-	for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i)
-		dl->lists.all[i].in_use = false;
+static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
+{
+	dma_free_writecombine(dl->dlm->vsp1->dev, dl->size, dl->body, dl->dma);
+	kfree(dl);
 }
 
-void vsp1_dl_begin(struct vsp1_dl *dl)
+/**
+ * vsp1_dl_list_get - Get a free display list
+ * @dlm: The display list manager
+ *
+ * Get a display list from the pool of free lists and return it.
+ *
+ * This function must be called without the display list manager lock held.
+ */
+struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm)
 {
-	struct vsp1_dl_list *list = NULL;
+	struct vsp1_dl_list *dl = NULL;
 	unsigned long flags;
-	unsigned int i;
 
-	spin_lock_irqsave(&dl->lock, flags);
+	spin_lock_irqsave(&dlm->lock, flags);
 
-	for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
-		if (!dl->lists.all[i].in_use) {
-			list = &dl->lists.all[i];
-			break;
-		}
+	if (!list_empty(&dlm->free)) {
+		dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list);
+		list_del(&dl->list);
 	}
 
-	if (!list) {
-		list = dl->lists.pending;
-		dl->lists.pending = NULL;
-	}
+	spin_unlock_irqrestore(&dlm->lock, flags);
+
+	return dl;
+}
 
-	spin_unlock_irqrestore(&dl->lock, flags);
+/**
+ * vsp1_dl_list_put - Release a display list
+ * @dl: The display list
+ *
+ * Release the display list and return it to the pool of free lists.
+ *
+ * This function must be called with the display list manager lock held.
+ *
+ * Passing a NULL pointer to this function is safe, in that case no operation
+ * will be performed.
+ */
+void vsp1_dl_list_put(struct vsp1_dl_list *dl)
+{
+	if (!dl)
+		return;
 
-	dl->lists.write = list;
+	dl->reg_count = 0;
 
-	list->in_use = true;
-	list->reg_count = 0;
+	list_add_tail(&dl->list, &dl->dlm->free);
 }
 
-void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data)
+void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	struct vsp1_dl_list *list = dl->lists.write;
-
-	list->body[list->reg_count].addr = reg;
-	list->body[list->reg_count].data = data;
-	list->reg_count++;
+	dl->body[dl->reg_count].addr = reg;
+	dl->body[dl->reg_count].data = data;
+	dl->reg_count++;
 }
 
-void vsp1_dl_commit(struct vsp1_dl *dl)
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
 {
-	struct vsp1_device *vsp1 = dl->vsp1;
-	struct vsp1_dl_list *list;
+	struct vsp1_dl_manager *dlm = dl->dlm;
+	struct vsp1_device *vsp1 = dlm->vsp1;
 	unsigned long flags;
 	bool update;
 
-	list = dl->lists.write;
-	dl->lists.write = NULL;
-
-	spin_lock_irqsave(&dl->lock, flags);
+	spin_lock_irqsave(&dlm->lock, flags);
 
 	/* Once the UPD bit has been set the hardware can start processing the
 	 * display list at any time and we can't touch the address and size
@@ -156,8 +148,8 @@ void vsp1_dl_commit(struct vsp1_dl *dl)
 	 */
 	update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD);
 	if (update) {
-		vsp1_dl_free_list(dl->lists.pending);
-		dl->lists.pending = list;
+		vsp1_dl_list_put(dlm->pending);
+		dlm->pending = dl;
 		goto done;
 	}
 
@@ -165,42 +157,44 @@ void vsp1_dl_commit(struct vsp1_dl *dl)
 	 * The UPD bit will be cleared by the device when the display list is
 	 * processed.
 	 */
-	vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+	vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->dma);
 	vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
-		   (list->reg_count * 8));
+		   (dl->reg_count * 8));
 
-	vsp1_dl_free_list(dl->lists.queued);
-	dl->lists.queued = list;
+	vsp1_dl_list_put(dlm->queued);
+	dlm->queued = dl;
 
 done:
-	spin_unlock_irqrestore(&dl->lock, flags);
+	spin_unlock_irqrestore(&dlm->lock, flags);
 }
 
 /* -----------------------------------------------------------------------------
- * Interrupt Handling
+ * Display List Manager
  */
 
-void vsp1_dl_irq_display_start(struct vsp1_dl *dl)
+/* Interrupt Handling */
+void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm)
 {
-	spin_lock(&dl->lock);
+	spin_lock(&dlm->lock);
 
 	/* The display start interrupt signals the end of the display list
 	 * processing by the device. The active display list, if any, won't be
 	 * accessed anymore and can be reused.
 	 */
-	if (dl->lists.active) {
-		vsp1_dl_free_list(dl->lists.active);
-		dl->lists.active = NULL;
-	}
+	vsp1_dl_list_put(dlm->active);
+	dlm->active = NULL;
 
-	spin_unlock(&dl->lock);
+	spin_unlock(&dlm->lock);
 }
 
-void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
+void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 {
-	struct vsp1_device *vsp1 = dl->vsp1;
+	struct vsp1_device *vsp1 = dlm->vsp1;
 
-	spin_lock(&dl->lock);
+	spin_lock(&dlm->lock);
+
+	vsp1_dl_list_put(dlm->active);
+	dlm->active = NULL;
 
 	/* The UPD bit set indicates that the commit operation raced with the
 	 * interrupt and occurred after the frame end event and UPD clear but
@@ -213,35 +207,31 @@ void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
 	/* The device starts processing the queued display list right after the
 	 * frame end interrupt. The display list thus becomes active.
 	 */
-	if (dl->lists.queued) {
-		WARN_ON(dl->lists.active);
-		dl->lists.active = dl->lists.queued;
-		dl->lists.queued = NULL;
+	if (dlm->queued) {
+		dlm->active = dlm->queued;
+		dlm->queued = NULL;
 	}
 
 	/* Now that the UPD bit has been cleared we can queue the next display
 	 * list to the hardware if one has been prepared.
 	 */
-	if (dl->lists.pending) {
-		struct vsp1_dl_list *list = dl->lists.pending;
+	if (dlm->pending) {
+		struct vsp1_dl_list *dl = dlm->pending;
 
-		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->dma);
 		vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
-			   (list->reg_count * 8));
+			   (dl->reg_count * 8));
 
-		dl->lists.queued = list;
-		dl->lists.pending = NULL;
+		dlm->queued = dl;
+		dlm->pending = NULL;
 	}
 
 done:
-	spin_unlock(&dl->lock);
+	spin_unlock(&dlm->lock);
 }
 
-/* -----------------------------------------------------------------------------
- * Hardware Setup
- */
-
-void vsp1_dl_setup(struct vsp1_device *vsp1)
+/* Hardware Setup */
+void vsp1_dlm_setup(struct vsp1_device *vsp1)
 {
 	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT);
 
@@ -256,46 +246,46 @@ void vsp1_dl_setup(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
 }
 
-/* -----------------------------------------------------------------------------
- * Initialization and Cleanup
- */
+void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
+{
+	vsp1_dl_list_put(dlm->active);
+	vsp1_dl_list_put(dlm->queued);
+	vsp1_dl_list_put(dlm->pending);
+
+	dlm->active = NULL;
+	dlm->queued = NULL;
+	dlm->pending = NULL;
+}
 
-struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1)
+int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
+		  unsigned int prealloc)
 {
-	struct vsp1_dl *dl;
 	unsigned int i;
 
-	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
-	if (!dl)
-		return NULL;
-
-	spin_lock_init(&dl->lock);
+	dlm->vsp1 = vsp1;
 
-	dl->vsp1 = vsp1;
-	dl->size = VSP1_DL_BODY_SIZE * ARRAY_SIZE(dl->lists.all);
+	spin_lock_init(&dlm->lock);
+	INIT_LIST_HEAD(&dlm->free);
 
-	dl->mem = dma_alloc_writecombine(vsp1->dev, dl->size, &dl->dma,
-					 GFP_KERNEL);
-	if (!dl->mem) {
-		kfree(dl);
-		return NULL;
-	}
+	for (i = 0; i < prealloc; ++i) {
+		struct vsp1_dl_list *dl;
 
-	for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
-		struct vsp1_dl_list *list = &dl->lists.all[i];
+		dl = vsp1_dl_list_alloc(dlm);
+		if (!dl)
+			return -ENOMEM;
 
-		list->size = VSP1_DL_BODY_SIZE;
-		list->reg_count = 0;
-		list->in_use = false;
-		list->dma = dl->dma + VSP1_DL_BODY_SIZE * i;
-		list->body = dl->mem + VSP1_DL_BODY_SIZE * i;
+		list_add_tail(&dl->list, &dlm->free);
 	}
 
-	return dl;
+	return 0;
 }
 
-void vsp1_dl_destroy(struct vsp1_dl *dl)
+void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm)
 {
-	dma_free_writecombine(dl->vsp1->dev, dl->size, dl->mem, dl->dma);
-	kfree(dl);
+	struct vsp1_dl_list *dl, *next;
+
+	list_for_each_entry_safe(dl, next, &dlm->free, list) {
+		list_del(&dl->list);
+		vsp1_dl_list_free(dl);
+	}
 }
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index f4116ca59c28..caa6a85f6825 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -16,19 +16,39 @@
 #include <linux/types.h>
 
 struct vsp1_device;
-struct vsp1_dl;
+struct vsp1_dl_list;
 
-struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1);
-void vsp1_dl_destroy(struct vsp1_dl *dl);
+/**
+ * struct vsp1_dl_manager - Display List manager
+ * @vsp1: the VSP1 device
+ * @lock: protects the active, queued and pending lists
+ * @free: array of all free display lists
+ * @active: list currently being processed (loaded) by hardware
+ * @queued: list queued to the hardware (written to the DL registers)
+ * @pending: list waiting to be queued to the hardware
+ */
+struct vsp1_dl_manager {
+	struct vsp1_device *vsp1;
+
+	spinlock_t lock;
+	struct list_head free;
+	struct vsp1_dl_list *active;
+	struct vsp1_dl_list *queued;
+	struct vsp1_dl_list *pending;
+};
 
-void vsp1_dl_setup(struct vsp1_device *vsp1);
+void vsp1_dlm_setup(struct vsp1_device *vsp1);
 
-void vsp1_dl_reset(struct vsp1_dl *dl);
-void vsp1_dl_begin(struct vsp1_dl *dl);
-void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data);
-void vsp1_dl_commit(struct vsp1_dl *dl);
+int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
+		  unsigned int prealloc);
+void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
 
-void vsp1_dl_irq_display_start(struct vsp1_dl *dl);
-void vsp1_dl_irq_frame_end(struct vsp1_dl *dl);
+struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
+void vsp1_dl_list_put(struct vsp1_dl_list *dl);
+void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data);
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl);
 
 #endif /* __VSP1_DL_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 1cfa8a0e43b6..bc275bb38352 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -26,6 +26,18 @@
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 
+
+/* -----------------------------------------------------------------------------
+ * Interrupt Handling
+ */
+
+void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
+{
+	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+
+	vsp1_dlm_irq_frame_end(&vsp1->drm->dlm);
+}
+
 /* -----------------------------------------------------------------------------
  * DU Driver API
  */
@@ -89,6 +101,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
 
 		pipe->num_inputs = 0;
 
+		vsp1_dlm_reset(&vsp1->drm->dlm);
 		vsp1_device_put(vsp1);
 
 		dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
@@ -96,8 +109,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
 		return 0;
 	}
 
-	vsp1_dl_reset(vsp1->drm->dl);
-
 	/* Configure the format at the BRU sinks and propagate it through the
 	 * pipeline.
 	 */
@@ -217,7 +228,7 @@ void vsp1_du_atomic_begin(struct device *dev)
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
 	/* Prepare the display list. */
-	vsp1_dl_begin(vsp1->drm->dl);
+	pipe->dl = vsp1_dl_list_get(&vsp1->drm->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -467,7 +478,8 @@ void vsp1_du_atomic_flush(struct device *dev)
 		}
 	}
 
-	vsp1_dl_commit(vsp1->drm->dl);
+	vsp1_dl_list_commit(pipe->dl);
+	pipe->dl = NULL;
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
@@ -543,18 +555,20 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 {
 	struct vsp1_pipeline *pipe;
 	unsigned int i;
+	int ret;
 
 	vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
 	if (!vsp1->drm)
 		return -ENOMEM;
 
-	vsp1->drm->dl = vsp1_dl_create(vsp1);
-	if (!vsp1->drm->dl)
-		return -ENOMEM;
+	ret = vsp1_dlm_init(vsp1, &vsp1->drm->dlm, 4);
+	if (ret < 0)
+		return ret;
 
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
+	pipe->frame_end = vsp1_drm_frame_end;
 
 	/* The DRM pipeline is static, add entities manually. */
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
@@ -571,12 +585,10 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 	pipe->lif = &vsp1->lif->entity;
 	pipe->output = vsp1->wpf[0];
 
-	pipe->dl = vsp1->drm->dl;
-
 	return 0;
 }
 
 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 {
-	vsp1_dl_destroy(vsp1->drm->dl);
+	vsp1_dlm_cleanup(&vsp1->drm->dlm);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 7704038c3add..5ef32cff9601 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -13,26 +13,30 @@
 #ifndef __VSP1_DRM_H__
 #define __VSP1_DRM_H__
 
+#include "vsp1_dl.h"
 #include "vsp1_pipe.h"
 
-struct vsp1_dl;
-
 /**
  * vsp1_drm - State for the API exposed to the DRM driver
- * @dl: display list for DRM pipeline operation
  * @pipe: the VSP1 pipeline used for display
  * @num_inputs: number of active pipeline inputs at the beginning of an update
  * @update: the pipeline configuration has been updated
+ * @dlm: display list manager used for DRM operation
  */
 struct vsp1_drm {
-	struct vsp1_dl *dl;
 	struct vsp1_pipeline pipe;
 	unsigned int num_inputs;
 	bool update;
+	struct vsp1_dl_manager dlm;
 };
 
 int vsp1_drm_init(struct vsp1_device *vsp1);
 void vsp1_drm_cleanup(struct vsp1_device *vsp1);
 int vsp1_drm_create_links(struct vsp1_device *vsp1);
 
+static inline void vsp1_drm_display_start(struct vsp1_device *vsp1)
+{
+	vsp1_dlm_irq_display_start(&vsp1->drm->dlm);
+}
+
 #endif /* __VSP1_DRM_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 871cbeea5695..e0bcc67e2d07 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -68,14 +68,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
 	vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST);
 
 	if (status & VI6_DISP_IRQ_STA_DST) {
-		struct vsp1_rwpf *wpf = vsp1->wpf[0];
-		struct vsp1_pipeline *pipe;
-
-		if (wpf) {
-			pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
-			vsp1_pipeline_display_start(pipe);
-		}
-
+		vsp1_drm_display_start(vsp1);
 		ret = IRQ_HANDLED;
 	}
 
@@ -458,7 +451,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-	vsp1_dl_setup(vsp1);
+	vsp1_dlm_setup(vsp1);
 
 	return 0;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 5ba535809131..0d1163eb3362 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -28,7 +28,7 @@ void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
 
 	if (pipe->dl)
-		vsp1_dl_add(pipe->dl, reg, data);
+		vsp1_dl_list_write(pipe->dl, reg, data);
 	else
 		vsp1_write(e->vsp1, reg, data);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 9c6d295ca843..facf68f999ce 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -205,7 +205,7 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
 	unsigned long flags;
 	int ret;
 
-	if (pipe->dl) {
+	if (pipe->lif) {
 		/* When using display lists in continuous frame mode the only
 		 * way to stop the pipeline is to reset the hardware.
 		 */
@@ -250,12 +250,6 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 	return pipe->buffers_ready = mask;
 }
 
-void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe)
-{
-	if (pipe->dl)
-		vsp1_dl_irq_display_start(pipe->dl);
-}
-
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
 	enum vsp1_pipeline_state state;
@@ -264,9 +258,6 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 	if (pipe = NULL)
 		return;
 
-	if (pipe->dl)
-		vsp1_dl_irq_frame_end(pipe->dl);
-
 	/* Signal frame end to the pipeline handler. */
 	if (pipe->frame_end)
 		pipe->frame_end(pipe);
@@ -278,7 +269,7 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 	/* When using display lists in continuous frame mode the pipeline is
 	 * automatically restarted by the hardware.
 	 */
-	if (pipe->dl)
+	if (pipe->lif)
 		goto done;
 
 	pipe->state = VSP1_PIPELINE_STOPPED;
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index b2f3a8a896c9..f4bdfc943add 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -19,7 +19,7 @@
 
 #include <media/media-entity.h>
 
-struct vsp1_dl;
+struct vsp1_dl_list;
 struct vsp1_rwpf;
 
 /*
@@ -100,7 +100,7 @@ struct vsp1_pipeline {
 
 	struct list_head entities;
 
-	struct vsp1_dl *dl;
+	struct vsp1_dl_list *dl;
 };
 
 static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
@@ -119,7 +119,6 @@ bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
 
-void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 04/48] v4l: vsp1: Split display list manager from display list
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

This clarifies the API and prepares display list support for being used
to implement the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1.h        |   1 -
 drivers/media/platform/vsp1/vsp1_dl.c     | 264 ++++++++++++++----------------
 drivers/media/platform/vsp1/vsp1_dl.h     |  40 +++--
 drivers/media/platform/vsp1/vsp1_drm.c    |  32 ++--
 drivers/media/platform/vsp1/vsp1_drm.h    |  12 +-
 drivers/media/platform/vsp1/vsp1_drv.c    |  11 +-
 drivers/media/platform/vsp1/vsp1_entity.c |   2 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  13 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   5 +-
 9 files changed, 194 insertions(+), 186 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index bea232820ead..dae987a11a70 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -26,7 +26,6 @@
 struct clk;
 struct device;
 
-struct vsp1_dl;
 struct vsp1_drm;
 struct vsp1_entity;
 struct vsp1_platform_data;
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index caf20f5f31f3..5f49f52e22f2 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -37,117 +37,109 @@ struct vsp1_dl_entry {
 } __attribute__((__packed__));
 
 struct vsp1_dl_list {
-	size_t size;
-	int reg_count;
+	struct list_head list;
 
-	bool in_use;
+	struct vsp1_dl_manager *dlm;
 
 	struct vsp1_dl_entry *body;
 	dma_addr_t dma;
-};
-
-/**
- * struct vsp1_dl - Display List manager
- * @vsp1: the VSP1 device
- * @lock: protects the active, queued and pending lists
- * @lists.all: array of all allocate display lists
- * @lists.active: list currently being processed (loaded) by hardware
- * @lists.queued: list queued to the hardware (written to the DL registers)
- * @lists.pending: list waiting to be queued to the hardware
- * @lists.write: list being written to by software
- */
-struct vsp1_dl {
-	struct vsp1_device *vsp1;
-
-	spinlock_t lock;
-
 	size_t size;
-	dma_addr_t dma;
-	void *mem;
 
-	struct {
-		struct vsp1_dl_list all[VSP1_DL_NUM_LISTS];
-
-		struct vsp1_dl_list *active;
-		struct vsp1_dl_list *queued;
-		struct vsp1_dl_list *pending;
-		struct vsp1_dl_list *write;
-	} lists;
+	int reg_count;
 };
 
 /* -----------------------------------------------------------------------------
  * Display List Transaction Management
  */
 
-static void vsp1_dl_free_list(struct vsp1_dl_list *list)
+static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
 {
-	if (!list)
-		return;
+	struct vsp1_dl_list *dl;
 
-	list->in_use = false;
-}
+	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
+	if (!dl)
+		return NULL;
 
-void vsp1_dl_reset(struct vsp1_dl *dl)
-{
-	unsigned int i;
+	dl->dlm = dlm;
+	dl->size = VSP1_DL_BODY_SIZE;
+
+	dl->body = dma_alloc_writecombine(dlm->vsp1->dev, dl->size, &dl->dma,
+					  GFP_KERNEL);
+	if (!dl->body) {
+		kfree(dl);
+		return NULL;
+	}
 
-	dl->lists.active = NULL;
-	dl->lists.queued = NULL;
-	dl->lists.pending = NULL;
-	dl->lists.write = NULL;
+	return dl;
+}
 
-	for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i)
-		dl->lists.all[i].in_use = false;
+static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
+{
+	dma_free_writecombine(dl->dlm->vsp1->dev, dl->size, dl->body, dl->dma);
+	kfree(dl);
 }
 
-void vsp1_dl_begin(struct vsp1_dl *dl)
+/**
+ * vsp1_dl_list_get - Get a free display list
+ * @dlm: The display list manager
+ *
+ * Get a display list from the pool of free lists and return it.
+ *
+ * This function must be called without the display list manager lock held.
+ */
+struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm)
 {
-	struct vsp1_dl_list *list = NULL;
+	struct vsp1_dl_list *dl = NULL;
 	unsigned long flags;
-	unsigned int i;
 
-	spin_lock_irqsave(&dl->lock, flags);
+	spin_lock_irqsave(&dlm->lock, flags);
 
-	for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
-		if (!dl->lists.all[i].in_use) {
-			list = &dl->lists.all[i];
-			break;
-		}
+	if (!list_empty(&dlm->free)) {
+		dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list);
+		list_del(&dl->list);
 	}
 
-	if (!list) {
-		list = dl->lists.pending;
-		dl->lists.pending = NULL;
-	}
+	spin_unlock_irqrestore(&dlm->lock, flags);
+
+	return dl;
+}
 
-	spin_unlock_irqrestore(&dl->lock, flags);
+/**
+ * vsp1_dl_list_put - Release a display list
+ * @dl: The display list
+ *
+ * Release the display list and return it to the pool of free lists.
+ *
+ * This function must be called with the display list manager lock held.
+ *
+ * Passing a NULL pointer to this function is safe, in that case no operation
+ * will be performed.
+ */
+void vsp1_dl_list_put(struct vsp1_dl_list *dl)
+{
+	if (!dl)
+		return;
 
-	dl->lists.write = list;
+	dl->reg_count = 0;
 
-	list->in_use = true;
-	list->reg_count = 0;
+	list_add_tail(&dl->list, &dl->dlm->free);
 }
 
-void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data)
+void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	struct vsp1_dl_list *list = dl->lists.write;
-
-	list->body[list->reg_count].addr = reg;
-	list->body[list->reg_count].data = data;
-	list->reg_count++;
+	dl->body[dl->reg_count].addr = reg;
+	dl->body[dl->reg_count].data = data;
+	dl->reg_count++;
 }
 
-void vsp1_dl_commit(struct vsp1_dl *dl)
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
 {
-	struct vsp1_device *vsp1 = dl->vsp1;
-	struct vsp1_dl_list *list;
+	struct vsp1_dl_manager *dlm = dl->dlm;
+	struct vsp1_device *vsp1 = dlm->vsp1;
 	unsigned long flags;
 	bool update;
 
-	list = dl->lists.write;
-	dl->lists.write = NULL;
-
-	spin_lock_irqsave(&dl->lock, flags);
+	spin_lock_irqsave(&dlm->lock, flags);
 
 	/* Once the UPD bit has been set the hardware can start processing the
 	 * display list at any time and we can't touch the address and size
@@ -156,8 +148,8 @@ void vsp1_dl_commit(struct vsp1_dl *dl)
 	 */
 	update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD);
 	if (update) {
-		vsp1_dl_free_list(dl->lists.pending);
-		dl->lists.pending = list;
+		vsp1_dl_list_put(dlm->pending);
+		dlm->pending = dl;
 		goto done;
 	}
 
@@ -165,42 +157,44 @@ void vsp1_dl_commit(struct vsp1_dl *dl)
 	 * The UPD bit will be cleared by the device when the display list is
 	 * processed.
 	 */
-	vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+	vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->dma);
 	vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
-		   (list->reg_count * 8));
+		   (dl->reg_count * 8));
 
-	vsp1_dl_free_list(dl->lists.queued);
-	dl->lists.queued = list;
+	vsp1_dl_list_put(dlm->queued);
+	dlm->queued = dl;
 
 done:
-	spin_unlock_irqrestore(&dl->lock, flags);
+	spin_unlock_irqrestore(&dlm->lock, flags);
 }
 
 /* -----------------------------------------------------------------------------
- * Interrupt Handling
+ * Display List Manager
  */
 
-void vsp1_dl_irq_display_start(struct vsp1_dl *dl)
+/* Interrupt Handling */
+void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm)
 {
-	spin_lock(&dl->lock);
+	spin_lock(&dlm->lock);
 
 	/* The display start interrupt signals the end of the display list
 	 * processing by the device. The active display list, if any, won't be
 	 * accessed anymore and can be reused.
 	 */
-	if (dl->lists.active) {
-		vsp1_dl_free_list(dl->lists.active);
-		dl->lists.active = NULL;
-	}
+	vsp1_dl_list_put(dlm->active);
+	dlm->active = NULL;
 
-	spin_unlock(&dl->lock);
+	spin_unlock(&dlm->lock);
 }
 
-void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
+void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 {
-	struct vsp1_device *vsp1 = dl->vsp1;
+	struct vsp1_device *vsp1 = dlm->vsp1;
 
-	spin_lock(&dl->lock);
+	spin_lock(&dlm->lock);
+
+	vsp1_dl_list_put(dlm->active);
+	dlm->active = NULL;
 
 	/* The UPD bit set indicates that the commit operation raced with the
 	 * interrupt and occurred after the frame end event and UPD clear but
@@ -213,35 +207,31 @@ void vsp1_dl_irq_frame_end(struct vsp1_dl *dl)
 	/* The device starts processing the queued display list right after the
 	 * frame end interrupt. The display list thus becomes active.
 	 */
-	if (dl->lists.queued) {
-		WARN_ON(dl->lists.active);
-		dl->lists.active = dl->lists.queued;
-		dl->lists.queued = NULL;
+	if (dlm->queued) {
+		dlm->active = dlm->queued;
+		dlm->queued = NULL;
 	}
 
 	/* Now that the UPD bit has been cleared we can queue the next display
 	 * list to the hardware if one has been prepared.
 	 */
-	if (dl->lists.pending) {
-		struct vsp1_dl_list *list = dl->lists.pending;
+	if (dlm->pending) {
+		struct vsp1_dl_list *dl = dlm->pending;
 
-		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), list->dma);
+		vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->dma);
 		vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
-			   (list->reg_count * 8));
+			   (dl->reg_count * 8));
 
-		dl->lists.queued = list;
-		dl->lists.pending = NULL;
+		dlm->queued = dl;
+		dlm->pending = NULL;
 	}
 
 done:
-	spin_unlock(&dl->lock);
+	spin_unlock(&dlm->lock);
 }
 
-/* -----------------------------------------------------------------------------
- * Hardware Setup
- */
-
-void vsp1_dl_setup(struct vsp1_device *vsp1)
+/* Hardware Setup */
+void vsp1_dlm_setup(struct vsp1_device *vsp1)
 {
 	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT);
 
@@ -256,46 +246,46 @@ void vsp1_dl_setup(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
 }
 
-/* -----------------------------------------------------------------------------
- * Initialization and Cleanup
- */
+void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
+{
+	vsp1_dl_list_put(dlm->active);
+	vsp1_dl_list_put(dlm->queued);
+	vsp1_dl_list_put(dlm->pending);
+
+	dlm->active = NULL;
+	dlm->queued = NULL;
+	dlm->pending = NULL;
+}
 
-struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1)
+int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
+		  unsigned int prealloc)
 {
-	struct vsp1_dl *dl;
 	unsigned int i;
 
-	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
-	if (!dl)
-		return NULL;
-
-	spin_lock_init(&dl->lock);
+	dlm->vsp1 = vsp1;
 
-	dl->vsp1 = vsp1;
-	dl->size = VSP1_DL_BODY_SIZE * ARRAY_SIZE(dl->lists.all);
+	spin_lock_init(&dlm->lock);
+	INIT_LIST_HEAD(&dlm->free);
 
-	dl->mem = dma_alloc_writecombine(vsp1->dev, dl->size, &dl->dma,
-					 GFP_KERNEL);
-	if (!dl->mem) {
-		kfree(dl);
-		return NULL;
-	}
+	for (i = 0; i < prealloc; ++i) {
+		struct vsp1_dl_list *dl;
 
-	for (i = 0; i < ARRAY_SIZE(dl->lists.all); ++i) {
-		struct vsp1_dl_list *list = &dl->lists.all[i];
+		dl = vsp1_dl_list_alloc(dlm);
+		if (!dl)
+			return -ENOMEM;
 
-		list->size = VSP1_DL_BODY_SIZE;
-		list->reg_count = 0;
-		list->in_use = false;
-		list->dma = dl->dma + VSP1_DL_BODY_SIZE * i;
-		list->body = dl->mem + VSP1_DL_BODY_SIZE * i;
+		list_add_tail(&dl->list, &dlm->free);
 	}
 
-	return dl;
+	return 0;
 }
 
-void vsp1_dl_destroy(struct vsp1_dl *dl)
+void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm)
 {
-	dma_free_writecombine(dl->vsp1->dev, dl->size, dl->mem, dl->dma);
-	kfree(dl);
+	struct vsp1_dl_list *dl, *next;
+
+	list_for_each_entry_safe(dl, next, &dlm->free, list) {
+		list_del(&dl->list);
+		vsp1_dl_list_free(dl);
+	}
 }
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index f4116ca59c28..caa6a85f6825 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -16,19 +16,39 @@
 #include <linux/types.h>
 
 struct vsp1_device;
-struct vsp1_dl;
+struct vsp1_dl_list;
 
-struct vsp1_dl *vsp1_dl_create(struct vsp1_device *vsp1);
-void vsp1_dl_destroy(struct vsp1_dl *dl);
+/**
+ * struct vsp1_dl_manager - Display List manager
+ * @vsp1: the VSP1 device
+ * @lock: protects the active, queued and pending lists
+ * @free: array of all free display lists
+ * @active: list currently being processed (loaded) by hardware
+ * @queued: list queued to the hardware (written to the DL registers)
+ * @pending: list waiting to be queued to the hardware
+ */
+struct vsp1_dl_manager {
+	struct vsp1_device *vsp1;
+
+	spinlock_t lock;
+	struct list_head free;
+	struct vsp1_dl_list *active;
+	struct vsp1_dl_list *queued;
+	struct vsp1_dl_list *pending;
+};
 
-void vsp1_dl_setup(struct vsp1_device *vsp1);
+void vsp1_dlm_setup(struct vsp1_device *vsp1);
 
-void vsp1_dl_reset(struct vsp1_dl *dl);
-void vsp1_dl_begin(struct vsp1_dl *dl);
-void vsp1_dl_add(struct vsp1_dl *dl, u32 reg, u32 data);
-void vsp1_dl_commit(struct vsp1_dl *dl);
+int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
+		  unsigned int prealloc);
+void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
+void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
 
-void vsp1_dl_irq_display_start(struct vsp1_dl *dl);
-void vsp1_dl_irq_frame_end(struct vsp1_dl *dl);
+struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
+void vsp1_dl_list_put(struct vsp1_dl_list *dl);
+void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data);
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl);
 
 #endif /* __VSP1_DL_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 1cfa8a0e43b6..bc275bb38352 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -26,6 +26,18 @@
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
 
+
+/* -----------------------------------------------------------------------------
+ * Interrupt Handling
+ */
+
+void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
+{
+	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+
+	vsp1_dlm_irq_frame_end(&vsp1->drm->dlm);
+}
+
 /* -----------------------------------------------------------------------------
  * DU Driver API
  */
@@ -89,6 +101,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
 
 		pipe->num_inputs = 0;
 
+		vsp1_dlm_reset(&vsp1->drm->dlm);
 		vsp1_device_put(vsp1);
 
 		dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
@@ -96,8 +109,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
 		return 0;
 	}
 
-	vsp1_dl_reset(vsp1->drm->dl);
-
 	/* Configure the format at the BRU sinks and propagate it through the
 	 * pipeline.
 	 */
@@ -217,7 +228,7 @@ void vsp1_du_atomic_begin(struct device *dev)
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
 	/* Prepare the display list. */
-	vsp1_dl_begin(vsp1->drm->dl);
+	pipe->dl = vsp1_dl_list_get(&vsp1->drm->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -467,7 +478,8 @@ void vsp1_du_atomic_flush(struct device *dev)
 		}
 	}
 
-	vsp1_dl_commit(vsp1->drm->dl);
+	vsp1_dl_list_commit(pipe->dl);
+	pipe->dl = NULL;
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
@@ -543,18 +555,20 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 {
 	struct vsp1_pipeline *pipe;
 	unsigned int i;
+	int ret;
 
 	vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
 	if (!vsp1->drm)
 		return -ENOMEM;
 
-	vsp1->drm->dl = vsp1_dl_create(vsp1);
-	if (!vsp1->drm->dl)
-		return -ENOMEM;
+	ret = vsp1_dlm_init(vsp1, &vsp1->drm->dlm, 4);
+	if (ret < 0)
+		return ret;
 
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
+	pipe->frame_end = vsp1_drm_frame_end;
 
 	/* The DRM pipeline is static, add entities manually. */
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
@@ -571,12 +585,10 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 	pipe->lif = &vsp1->lif->entity;
 	pipe->output = vsp1->wpf[0];
 
-	pipe->dl = vsp1->drm->dl;
-
 	return 0;
 }
 
 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 {
-	vsp1_dl_destroy(vsp1->drm->dl);
+	vsp1_dlm_cleanup(&vsp1->drm->dlm);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 7704038c3add..5ef32cff9601 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -13,26 +13,30 @@
 #ifndef __VSP1_DRM_H__
 #define __VSP1_DRM_H__
 
+#include "vsp1_dl.h"
 #include "vsp1_pipe.h"
 
-struct vsp1_dl;
-
 /**
  * vsp1_drm - State for the API exposed to the DRM driver
- * @dl: display list for DRM pipeline operation
  * @pipe: the VSP1 pipeline used for display
  * @num_inputs: number of active pipeline inputs at the beginning of an update
  * @update: the pipeline configuration has been updated
+ * @dlm: display list manager used for DRM operation
  */
 struct vsp1_drm {
-	struct vsp1_dl *dl;
 	struct vsp1_pipeline pipe;
 	unsigned int num_inputs;
 	bool update;
+	struct vsp1_dl_manager dlm;
 };
 
 int vsp1_drm_init(struct vsp1_device *vsp1);
 void vsp1_drm_cleanup(struct vsp1_device *vsp1);
 int vsp1_drm_create_links(struct vsp1_device *vsp1);
 
+static inline void vsp1_drm_display_start(struct vsp1_device *vsp1)
+{
+	vsp1_dlm_irq_display_start(&vsp1->drm->dlm);
+}
+
 #endif /* __VSP1_DRM_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 871cbeea5695..e0bcc67e2d07 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -68,14 +68,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
 	vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST);
 
 	if (status & VI6_DISP_IRQ_STA_DST) {
-		struct vsp1_rwpf *wpf = vsp1->wpf[0];
-		struct vsp1_pipeline *pipe;
-
-		if (wpf) {
-			pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
-			vsp1_pipeline_display_start(pipe);
-		}
-
+		vsp1_drm_display_start(vsp1);
 		ret = IRQ_HANDLED;
 	}
 
@@ -458,7 +451,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
 	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 
-	vsp1_dl_setup(vsp1);
+	vsp1_dlm_setup(vsp1);
 
 	return 0;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 5ba535809131..0d1163eb3362 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -28,7 +28,7 @@ void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
 
 	if (pipe->dl)
-		vsp1_dl_add(pipe->dl, reg, data);
+		vsp1_dl_list_write(pipe->dl, reg, data);
 	else
 		vsp1_write(e->vsp1, reg, data);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 9c6d295ca843..facf68f999ce 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -205,7 +205,7 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
 	unsigned long flags;
 	int ret;
 
-	if (pipe->dl) {
+	if (pipe->lif) {
 		/* When using display lists in continuous frame mode the only
 		 * way to stop the pipeline is to reset the hardware.
 		 */
@@ -250,12 +250,6 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 	return pipe->buffers_ready == mask;
 }
 
-void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe)
-{
-	if (pipe->dl)
-		vsp1_dl_irq_display_start(pipe->dl);
-}
-
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
 	enum vsp1_pipeline_state state;
@@ -264,9 +258,6 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 	if (pipe == NULL)
 		return;
 
-	if (pipe->dl)
-		vsp1_dl_irq_frame_end(pipe->dl);
-
 	/* Signal frame end to the pipeline handler. */
 	if (pipe->frame_end)
 		pipe->frame_end(pipe);
@@ -278,7 +269,7 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 	/* When using display lists in continuous frame mode the pipeline is
 	 * automatically restarted by the hardware.
 	 */
-	if (pipe->dl)
+	if (pipe->lif)
 		goto done;
 
 	pipe->state = VSP1_PIPELINE_STOPPED;
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index b2f3a8a896c9..f4bdfc943add 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -19,7 +19,7 @@
 
 #include <media/media-entity.h>
 
-struct vsp1_dl;
+struct vsp1_dl_list;
 struct vsp1_rwpf;
 
 /*
@@ -100,7 +100,7 @@ struct vsp1_pipeline {
 
 	struct list_head entities;
 
-	struct vsp1_dl *dl;
+	struct vsp1_dl_list *dl;
 };
 
 static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
@@ -119,7 +119,6 @@ bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
 
-void vsp1_pipeline_display_start(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 05/48] v4l: vsp1: Store the display list manager in the WPF
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Each WPF can process display lists independently, move the manager to
the WPF to reflect that and prepare for display list support for non-DRM
pipelines.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c     | 37 ++++++++++++++++++++++++++-----
 drivers/media/platform/vsp1/vsp1_dl.h     | 26 ++++------------------
 drivers/media/platform/vsp1/vsp1_drm.c    | 19 +++++++---------
 drivers/media/platform/vsp1/vsp1_drm.h    |  9 +-------
 drivers/media/platform/vsp1/vsp1_entity.c |  2 ++
 drivers/media/platform/vsp1/vsp1_entity.h |  2 ++
 drivers/media/platform/vsp1/vsp1_rwpf.h   |  3 +++
 drivers/media/platform/vsp1/vsp1_wpf.c    | 18 +++++++++++++++
 8 files changed, 70 insertions(+), 46 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 5f49f52e22f2..32661daac7b0 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -48,6 +48,25 @@ struct vsp1_dl_list {
 	int reg_count;
 };
 
+/**
+ * struct vsp1_dl_manager - Display List manager
+ * @vsp1: the VSP1 device
+ * @lock: protects the active, queued and pending lists
+ * @free: array of all free display lists
+ * @active: list currently being processed (loaded) by hardware
+ * @queued: list queued to the hardware (written to the DL registers)
+ * @pending: list waiting to be queued to the hardware
+ */
+struct vsp1_dl_manager {
+	struct vsp1_device *vsp1;
+
+	spinlock_t lock;
+	struct list_head free;
+	struct vsp1_dl_list *active;
+	struct vsp1_dl_list *queued;
+	struct vsp1_dl_list *pending;
+};
+
 /* -----------------------------------------------------------------------------
  * Display List Transaction Management
  */
@@ -257,11 +276,16 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
 	dlm->pending = NULL;
 }
 
-int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
-		  unsigned int prealloc)
+struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int prealloc)
 {
+	struct vsp1_dl_manager *dlm;
 	unsigned int i;
 
+	dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL);
+	if (!dlm)
+		return NULL;
+
 	dlm->vsp1 = vsp1;
 
 	spin_lock_init(&dlm->lock);
@@ -272,18 +296,21 @@ int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
 
 		dl = vsp1_dl_list_alloc(dlm);
 		if (!dl)
-			return -ENOMEM;
+			return NULL;
 
 		list_add_tail(&dl->list, &dlm->free);
 	}
 
-	return 0;
+	return dlm;
 }
 
-void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm)
+void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
 {
 	struct vsp1_dl_list *dl, *next;
 
+	if (!dlm)
+		return;
+
 	list_for_each_entry_safe(dl, next, &dlm->free, list) {
 		list_del(&dl->list);
 		vsp1_dl_list_free(dl);
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index caa6a85f6825..46f7ae337374 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -17,31 +17,13 @@
 
 struct vsp1_device;
 struct vsp1_dl_list;
-
-/**
- * struct vsp1_dl_manager - Display List manager
- * @vsp1: the VSP1 device
- * @lock: protects the active, queued and pending lists
- * @free: array of all free display lists
- * @active: list currently being processed (loaded) by hardware
- * @queued: list queued to the hardware (written to the DL registers)
- * @pending: list waiting to be queued to the hardware
- */
-struct vsp1_dl_manager {
-	struct vsp1_device *vsp1;
-
-	spinlock_t lock;
-	struct list_head free;
-	struct vsp1_dl_list *active;
-	struct vsp1_dl_list *queued;
-	struct vsp1_dl_list *pending;
-};
+struct vsp1_dl_manager;
 
 void vsp1_dlm_setup(struct vsp1_device *vsp1);
 
-int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
-		  unsigned int prealloc);
-void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm);
+struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int prealloc);
+void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index bc275bb38352..b3df694569e7 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -31,11 +31,14 @@
  * Interrupt Handling
  */
 
-void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
+void vsp1_drm_display_start(struct vsp1_device *vsp1)
 {
-	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
+}
 
-	vsp1_dlm_irq_frame_end(&vsp1->drm->dlm);
+void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
+{
+	vsp1_dlm_irq_frame_end(pipe->output->dlm);
 }
 
 /* -----------------------------------------------------------------------------
@@ -101,7 +104,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
 
 		pipe->num_inputs = 0;
 
-		vsp1_dlm_reset(&vsp1->drm->dlm);
+		vsp1_dlm_reset(pipe->output->dlm);
 		vsp1_device_put(vsp1);
 
 		dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
@@ -228,7 +231,7 @@ void vsp1_du_atomic_begin(struct device *dev)
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
 	/* Prepare the display list. */
-	pipe->dl = vsp1_dl_list_get(&vsp1->drm->dlm);
+	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -555,16 +558,11 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 {
 	struct vsp1_pipeline *pipe;
 	unsigned int i;
-	int ret;
 
 	vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
 	if (!vsp1->drm)
 		return -ENOMEM;
 
-	ret = vsp1_dlm_init(vsp1, &vsp1->drm->dlm, 4);
-	if (ret < 0)
-		return ret;
-
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
@@ -590,5 +588,4 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 
 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 {
-	vsp1_dlm_cleanup(&vsp1->drm->dlm);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 5ef32cff9601..1acf6048841b 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -13,7 +13,6 @@
 #ifndef __VSP1_DRM_H__
 #define __VSP1_DRM_H__
 
-#include "vsp1_dl.h"
 #include "vsp1_pipe.h"
 
 /**
@@ -21,22 +20,16 @@
  * @pipe: the VSP1 pipeline used for display
  * @num_inputs: number of active pipeline inputs at the beginning of an update
  * @update: the pipeline configuration has been updated
- * @dlm: display list manager used for DRM operation
  */
 struct vsp1_drm {
 	struct vsp1_pipeline pipe;
 	unsigned int num_inputs;
 	bool update;
-	struct vsp1_dl_manager dlm;
 };
 
 int vsp1_drm_init(struct vsp1_device *vsp1);
 void vsp1_drm_cleanup(struct vsp1_device *vsp1);
 int vsp1_drm_create_links(struct vsp1_device *vsp1);
-
-static inline void vsp1_drm_display_start(struct vsp1_device *vsp1)
-{
-	vsp1_dlm_irq_display_start(&vsp1->drm->dlm);
-}
+void vsp1_drm_display_start(struct vsp1_device *vsp1);
 
 #endif /* __VSP1_DRM_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 0d1163eb3362..c005d374c254 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -244,6 +244,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
 {
+	if (entity->destroy)
+		entity->destroy(entity);
 	if (entity->subdev.ctrl_handler)
 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
 	media_entity_cleanup(&entity->subdev.entity);
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 311d5b64c9a5..259880e524fe 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -56,6 +56,8 @@ struct vsp1_route {
 struct vsp1_entity {
 	struct vsp1_device *vsp1;
 
+	void (*destroy)(struct vsp1_entity *);
+
 	enum vsp1_entity_type type;
 	unsigned int index;
 	const struct vsp1_route *route;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 8e8235682ada..d04df39b2737 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -24,6 +24,7 @@
 #define RWPF_PAD_SOURCE				1
 
 struct v4l2_ctrl;
+struct vsp1_dl_manager;
 struct vsp1_rwpf;
 struct vsp1_video;
 
@@ -60,6 +61,8 @@ struct vsp1_rwpf {
 
 	unsigned int offsets[2];
 	dma_addr_t buf_addr[3];
+
+	struct vsp1_dl_manager *dlm;
 };
 
 static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index c78d4af50fcf..6afc9c8d9adc 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -16,6 +16,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
@@ -218,6 +219,13 @@ static const struct vsp1_rwpf_operations wpf_vdev_ops = {
  * Initialization and Cleanup
  */
 
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = container_of(entity, struct vsp1_rwpf, entity);
+
+	vsp1_dlm_destroy(wpf->dlm);
+}
+
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
 	struct v4l2_subdev *subdev;
@@ -233,6 +241,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	wpf->max_width = WPF_MAX_WIDTH;
 	wpf->max_height = WPF_MAX_HEIGHT;
 
+	wpf->entity.destroy = vsp1_wpf_destroy;
 	wpf->entity.type = VSP1_ENTITY_WPF;
 	wpf->entity.index = index;
 
@@ -240,6 +249,15 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (ret < 0)
 		return ERR_PTR(ret);
 
+	/* Initialize the display list manager if the WPF is used for display */
+	if ((vsp1->info->features & VSP1_HAS_LIF) && index = 0) {
+		wpf->dlm = vsp1_dlm_create(vsp1, 4);
+		if (!wpf->dlm) {
+			ret = -ENOMEM;
+			goto error;
+		}
+	}
+
 	/* Initialize the V4L2 subdev. */
 	subdev = &wpf->entity.subdev;
 	v4l2_subdev_init(subdev, &wpf_ops);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 05/48] v4l: vsp1: Store the display list manager in the WPF
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Each WPF can process display lists independently, move the manager to
the WPF to reflect that and prepare for display list support for non-DRM
pipelines.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c     | 37 ++++++++++++++++++++++++++-----
 drivers/media/platform/vsp1/vsp1_dl.h     | 26 ++++------------------
 drivers/media/platform/vsp1/vsp1_drm.c    | 19 +++++++---------
 drivers/media/platform/vsp1/vsp1_drm.h    |  9 +-------
 drivers/media/platform/vsp1/vsp1_entity.c |  2 ++
 drivers/media/platform/vsp1/vsp1_entity.h |  2 ++
 drivers/media/platform/vsp1/vsp1_rwpf.h   |  3 +++
 drivers/media/platform/vsp1/vsp1_wpf.c    | 18 +++++++++++++++
 8 files changed, 70 insertions(+), 46 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 5f49f52e22f2..32661daac7b0 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -48,6 +48,25 @@ struct vsp1_dl_list {
 	int reg_count;
 };
 
+/**
+ * struct vsp1_dl_manager - Display List manager
+ * @vsp1: the VSP1 device
+ * @lock: protects the active, queued and pending lists
+ * @free: array of all free display lists
+ * @active: list currently being processed (loaded) by hardware
+ * @queued: list queued to the hardware (written to the DL registers)
+ * @pending: list waiting to be queued to the hardware
+ */
+struct vsp1_dl_manager {
+	struct vsp1_device *vsp1;
+
+	spinlock_t lock;
+	struct list_head free;
+	struct vsp1_dl_list *active;
+	struct vsp1_dl_list *queued;
+	struct vsp1_dl_list *pending;
+};
+
 /* -----------------------------------------------------------------------------
  * Display List Transaction Management
  */
@@ -257,11 +276,16 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
 	dlm->pending = NULL;
 }
 
-int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
-		  unsigned int prealloc)
+struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int prealloc)
 {
+	struct vsp1_dl_manager *dlm;
 	unsigned int i;
 
+	dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL);
+	if (!dlm)
+		return NULL;
+
 	dlm->vsp1 = vsp1;
 
 	spin_lock_init(&dlm->lock);
@@ -272,18 +296,21 @@ int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
 
 		dl = vsp1_dl_list_alloc(dlm);
 		if (!dl)
-			return -ENOMEM;
+			return NULL;
 
 		list_add_tail(&dl->list, &dlm->free);
 	}
 
-	return 0;
+	return dlm;
 }
 
-void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm)
+void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
 {
 	struct vsp1_dl_list *dl, *next;
 
+	if (!dlm)
+		return;
+
 	list_for_each_entry_safe(dl, next, &dlm->free, list) {
 		list_del(&dl->list);
 		vsp1_dl_list_free(dl);
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index caa6a85f6825..46f7ae337374 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -17,31 +17,13 @@
 
 struct vsp1_device;
 struct vsp1_dl_list;
-
-/**
- * struct vsp1_dl_manager - Display List manager
- * @vsp1: the VSP1 device
- * @lock: protects the active, queued and pending lists
- * @free: array of all free display lists
- * @active: list currently being processed (loaded) by hardware
- * @queued: list queued to the hardware (written to the DL registers)
- * @pending: list waiting to be queued to the hardware
- */
-struct vsp1_dl_manager {
-	struct vsp1_device *vsp1;
-
-	spinlock_t lock;
-	struct list_head free;
-	struct vsp1_dl_list *active;
-	struct vsp1_dl_list *queued;
-	struct vsp1_dl_list *pending;
-};
+struct vsp1_dl_manager;
 
 void vsp1_dlm_setup(struct vsp1_device *vsp1);
 
-int vsp1_dlm_init(struct vsp1_device *vsp1, struct vsp1_dl_manager *dlm,
-		  unsigned int prealloc);
-void vsp1_dlm_cleanup(struct vsp1_dl_manager *dlm);
+struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int prealloc);
+void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index bc275bb38352..b3df694569e7 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -31,11 +31,14 @@
  * Interrupt Handling
  */
 
-void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
+void vsp1_drm_display_start(struct vsp1_device *vsp1)
 {
-	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
+}
 
-	vsp1_dlm_irq_frame_end(&vsp1->drm->dlm);
+void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
+{
+	vsp1_dlm_irq_frame_end(pipe->output->dlm);
 }
 
 /* -----------------------------------------------------------------------------
@@ -101,7 +104,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
 
 		pipe->num_inputs = 0;
 
-		vsp1_dlm_reset(&vsp1->drm->dlm);
+		vsp1_dlm_reset(pipe->output->dlm);
 		vsp1_device_put(vsp1);
 
 		dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
@@ -228,7 +231,7 @@ void vsp1_du_atomic_begin(struct device *dev)
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
 	/* Prepare the display list. */
-	pipe->dl = vsp1_dl_list_get(&vsp1->drm->dlm);
+	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
 }
 EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
 
@@ -555,16 +558,11 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 {
 	struct vsp1_pipeline *pipe;
 	unsigned int i;
-	int ret;
 
 	vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
 	if (!vsp1->drm)
 		return -ENOMEM;
 
-	ret = vsp1_dlm_init(vsp1, &vsp1->drm->dlm, 4);
-	if (ret < 0)
-		return ret;
-
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
@@ -590,5 +588,4 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 
 void vsp1_drm_cleanup(struct vsp1_device *vsp1)
 {
-	vsp1_dlm_cleanup(&vsp1->drm->dlm);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 5ef32cff9601..1acf6048841b 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -13,7 +13,6 @@
 #ifndef __VSP1_DRM_H__
 #define __VSP1_DRM_H__
 
-#include "vsp1_dl.h"
 #include "vsp1_pipe.h"
 
 /**
@@ -21,22 +20,16 @@
  * @pipe: the VSP1 pipeline used for display
  * @num_inputs: number of active pipeline inputs at the beginning of an update
  * @update: the pipeline configuration has been updated
- * @dlm: display list manager used for DRM operation
  */
 struct vsp1_drm {
 	struct vsp1_pipeline pipe;
 	unsigned int num_inputs;
 	bool update;
-	struct vsp1_dl_manager dlm;
 };
 
 int vsp1_drm_init(struct vsp1_device *vsp1);
 void vsp1_drm_cleanup(struct vsp1_device *vsp1);
 int vsp1_drm_create_links(struct vsp1_device *vsp1);
-
-static inline void vsp1_drm_display_start(struct vsp1_device *vsp1)
-{
-	vsp1_dlm_irq_display_start(&vsp1->drm->dlm);
-}
+void vsp1_drm_display_start(struct vsp1_device *vsp1);
 
 #endif /* __VSP1_DRM_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 0d1163eb3362..c005d374c254 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -244,6 +244,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
 {
+	if (entity->destroy)
+		entity->destroy(entity);
 	if (entity->subdev.ctrl_handler)
 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
 	media_entity_cleanup(&entity->subdev.entity);
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 311d5b64c9a5..259880e524fe 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -56,6 +56,8 @@ struct vsp1_route {
 struct vsp1_entity {
 	struct vsp1_device *vsp1;
 
+	void (*destroy)(struct vsp1_entity *);
+
 	enum vsp1_entity_type type;
 	unsigned int index;
 	const struct vsp1_route *route;
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 8e8235682ada..d04df39b2737 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -24,6 +24,7 @@
 #define RWPF_PAD_SOURCE				1
 
 struct v4l2_ctrl;
+struct vsp1_dl_manager;
 struct vsp1_rwpf;
 struct vsp1_video;
 
@@ -60,6 +61,8 @@ struct vsp1_rwpf {
 
 	unsigned int offsets[2];
 	dma_addr_t buf_addr[3];
+
+	struct vsp1_dl_manager *dlm;
 };
 
 static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index c78d4af50fcf..6afc9c8d9adc 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -16,6 +16,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
@@ -218,6 +219,13 @@ static const struct vsp1_rwpf_operations wpf_vdev_ops = {
  * Initialization and Cleanup
  */
 
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = container_of(entity, struct vsp1_rwpf, entity);
+
+	vsp1_dlm_destroy(wpf->dlm);
+}
+
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
 	struct v4l2_subdev *subdev;
@@ -233,6 +241,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	wpf->max_width = WPF_MAX_WIDTH;
 	wpf->max_height = WPF_MAX_HEIGHT;
 
+	wpf->entity.destroy = vsp1_wpf_destroy;
 	wpf->entity.type = VSP1_ENTITY_WPF;
 	wpf->entity.index = index;
 
@@ -240,6 +249,15 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (ret < 0)
 		return ERR_PTR(ret);
 
+	/* Initialize the display list manager if the WPF is used for display */
+	if ((vsp1->info->features & VSP1_HAS_LIF) && index == 0) {
+		wpf->dlm = vsp1_dlm_create(vsp1, 4);
+		if (!wpf->dlm) {
+			ret = -ENOMEM;
+			goto error;
+		}
+	}
+
 	/* Initialize the V4L2 subdev. */
 	subdev = &wpf->entity.subdev;
 	v4l2_subdev_init(subdev, &wpf_ops);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 06/48] v4l: vsp1: bru: Don't program background color in control set handler
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The datasheet clearly states that all but a few registers can't be
modified when the device is running. Programming the background color
in the control set handler is thus prohibited. Program it when starting
the module instead.

This requires storing the background color value internally as the
module can be started from the frame completion interrupt handler, and
accessing control values requires taking a mutex.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c | 15 +++++++++------
 drivers/media/platform/vsp1/vsp1_bru.h |  2 ++
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index cb0dbc15ddad..4c1bd0419e12 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -42,13 +42,9 @@ static int bru_s_ctrl(struct v4l2_ctrl *ctrl)
 	struct vsp1_bru *bru  		container_of(ctrl->handler, struct vsp1_bru, ctrls);
 
-	if (!vsp1_entity_is_streaming(&bru->entity))
-		return 0;
-
 	switch (ctrl->id) {
 	case V4L2_CID_BG_COLOR:
-		vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, ctrl->val |
-			       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+		bru->bgcolor = ctrl->val;
 		break;
 	}
 
@@ -95,12 +91,17 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
 		       0 : VI6_BRU_INCTRL_NRM);
 
-	/* Set the background position to cover the whole output image. */
+	/* Set the background position to cover the whole output image and
+	 * configure its color.
+	 */
 	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
 		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
 		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
 	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
 
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+
 	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
 	 * unit with a NOP operation to make BRU input 1 available as the
 	 * Blend/ROP unit B SRC input.
@@ -438,6 +439,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 	v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR,
 			  0, 0xffffff, 1, 0);
 
+	bru->bgcolor = 0;
+
 	bru->entity.subdev.ctrl_handler = &bru->ctrls;
 
 	if (bru->ctrls.error) {
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
index dbac9686ea69..4e7d2e79b940 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.h
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -33,6 +33,8 @@ struct vsp1_bru {
 		struct vsp1_rwpf *rpf;
 		struct v4l2_rect compose;
 	} inputs[VSP1_MAX_RPF];
+
+	u32 bgcolor;
 };
 
 static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 06/48] v4l: vsp1: bru: Don't program background color in control set handler
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The datasheet clearly states that all but a few registers can't be
modified when the device is running. Programming the background color
in the control set handler is thus prohibited. Program it when starting
the module instead.

This requires storing the background color value internally as the
module can be started from the frame completion interrupt handler, and
accessing control values requires taking a mutex.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c | 15 +++++++++------
 drivers/media/platform/vsp1/vsp1_bru.h |  2 ++
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index cb0dbc15ddad..4c1bd0419e12 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -42,13 +42,9 @@ static int bru_s_ctrl(struct v4l2_ctrl *ctrl)
 	struct vsp1_bru *bru =
 		container_of(ctrl->handler, struct vsp1_bru, ctrls);
 
-	if (!vsp1_entity_is_streaming(&bru->entity))
-		return 0;
-
 	switch (ctrl->id) {
 	case V4L2_CID_BG_COLOR:
-		vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, ctrl->val |
-			       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+		bru->bgcolor = ctrl->val;
 		break;
 	}
 
@@ -95,12 +91,17 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
 		       0 : VI6_BRU_INCTRL_NRM);
 
-	/* Set the background position to cover the whole output image. */
+	/* Set the background position to cover the whole output image and
+	 * configure its color.
+	 */
 	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
 		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
 		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
 	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
 
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+
 	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
 	 * unit with a NOP operation to make BRU input 1 available as the
 	 * Blend/ROP unit B SRC input.
@@ -438,6 +439,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 	v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR,
 			  0, 0xffffff, 1, 0);
 
+	bru->bgcolor = 0;
+
 	bru->entity.subdev.ctrl_handler = &bru->ctrls;
 
 	if (bru->ctrls.error) {
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
index dbac9686ea69..4e7d2e79b940 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.h
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -33,6 +33,8 @@ struct vsp1_bru {
 		struct vsp1_rwpf *rpf;
 		struct v4l2_rect compose;
 	} inputs[VSP1_MAX_RPF];
+
+	u32 bgcolor;
 };
 
 static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 07/48] v4l: vsp1: rwpf: Don't program alpha value in control set handler
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The datasheet clearly states that all but a few registers can't be
modified when the device is running. Programming the alpha value in
the control set handler is thus prohibited. Program it when starting the
module instead.

This requires storing the alpha value internally as the module can be
started from the frame completion interrupt handler, and accessing
control values requires taking a mutex.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_rpf.c  | 51 +++---------------------------
 drivers/media/platform/vsp1/vsp1_rwpf.c | 35 +++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_rwpf.h |  5 ++-
 drivers/media/platform/vsp1/vsp1_wpf.c  | 55 ++-------------------------------
 4 files changed, 47 insertions(+), 99 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 5bc1d1574a43..9ccfb572b4a5 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -33,36 +33,6 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * Controls
- */
-
-static int rpf_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct vsp1_rwpf *rpf -		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
-	struct vsp1_pipeline *pipe;
-
-	if (!vsp1_entity_is_streaming(&rpf->entity))
-		return 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_ALPHA_COMPONENT:
-		vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-			       ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
-
-		pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity);
-		vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct v4l2_ctrl_ops rpf_ctrl_ops = {
-	.s_ctrl = rpf_s_ctrl,
-};
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Core Operations
  */
 
@@ -70,7 +40,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *rpf = to_rwpf(subdev);
-	struct vsp1_device *vsp1 = rpf->entity.vsp1;
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_rect *crop = &rpf->crop;
@@ -151,13 +120,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
 				       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
 
-	if (vsp1->info->uapi)
-		mutex_lock(rpf->ctrls.lock);
 	vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-		       rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
-	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val);
-	if (vsp1->info->uapi)
-		mutex_unlock(rpf->ctrls.lock);
+		       rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+
+	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
 
 	vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
 	vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
@@ -255,17 +221,10 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 	vsp1_entity_init_formats(subdev, NULL);
 
 	/* Initialize the control handler. */
-	v4l2_ctrl_handler_init(&rpf->ctrls, 1);
-	rpf->alpha = v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops,
-				       V4L2_CID_ALPHA_COMPONENT,
-				       0, 255, 1, 255);
-
-	rpf->entity.subdev.ctrl_handler = &rpf->ctrls;
-
-	if (rpf->ctrls.error) {
+	ret = vsp1_rwpf_init_ctrls(rpf);
+	if (ret < 0) {
 		dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
 			index);
-		ret = rpf->ctrls.error;
 		goto error;
 	}
 
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 9688c219b30e..ba50386db35c 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -230,3 +230,38 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 
 	return 0;
 }
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vsp1_rwpf *rwpf +		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
+
+	switch (ctrl->id) {
+	case V4L2_CID_ALPHA_COMPONENT:
+		rwpf->alpha = ctrl->val;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
+	.s_ctrl = vsp1_rwpf_s_ctrl,
+};
+
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
+{
+	rwpf->alpha = 255;
+
+	v4l2_ctrl_handler_init(&rwpf->ctrls, 1);
+	v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
+			  V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
+
+	rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls;
+
+	return rwpf->ctrls.error;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index d04df39b2737..66af2a06dd8b 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -42,7 +42,6 @@ struct vsp1_rwpf_operations {
 struct vsp1_rwpf {
 	struct vsp1_entity entity;
 	struct v4l2_ctrl_handler ctrls;
-	struct v4l2_ctrl *alpha;
 
 	struct vsp1_video *video;
 
@@ -59,6 +58,8 @@ struct vsp1_rwpf {
 	} location;
 	struct v4l2_rect crop;
 
+	unsigned int alpha;
+
 	unsigned int offsets[2];
 	dma_addr_t buf_addr[3];
 
@@ -73,6 +74,8 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
+
 int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 			     struct v4l2_subdev_pad_config *cfg,
 			     struct v4l2_subdev_mbus_code_enum *code);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 6afc9c8d9adc..2135cca2490e 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -27,12 +27,6 @@
  * Device Access
  */
 
-static inline u32 vsp1_wpf_read(struct vsp1_rwpf *wpf, u32 reg)
-{
-	return vsp1_read(wpf->entity.vsp1,
-			 reg + wpf->entity.index * VI6_WPF_OFFSET);
-}
-
 static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
 {
 	vsp1_mod_write(&wpf->entity,
@@ -40,35 +34,6 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * Controls
- */
-
-static int wpf_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct vsp1_rwpf *wpf -		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
-	u32 value;
-
-	if (!vsp1_entity_is_streaming(&wpf->entity))
-		return 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_ALPHA_COMPONENT:
-		value = vsp1_wpf_read(wpf, VI6_WPF_OUTFMT);
-		value &= ~VI6_WPF_OUTFMT_PDV_MASK;
-		value |= ctrl->val << VI6_WPF_OUTFMT_PDV_SHIFT;
-		vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, value);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct v4l2_ctrl_ops wpf_ctrl_ops = {
-	.s_ctrl = wpf_s_ctrl,
-};
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Core Operations
  */
 
@@ -153,15 +118,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	    wpf->entity.formats[RWPF_PAD_SOURCE].code)
 		outfmt |= VI6_WPF_OUTFMT_CSC;
 
-	/* Take the control handler lock to ensure that the PDV value won't be
-	 * changed behind our back by a set control operation.
-	 */
-	if (vsp1->info->uapi)
-		mutex_lock(wpf->ctrls.lock);
-	outfmt |= wpf->alpha->cur.val << VI6_WPF_OUTFMT_PDV_SHIFT;
+	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
 	vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
-	if (vsp1->info->uapi)
-		mutex_unlock(wpf->ctrls.lock);
 
 	vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index),
 		       VI6_DPR_WPF_FPORCH_FP_WPFN);
@@ -272,17 +230,10 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	vsp1_entity_init_formats(subdev, NULL);
 
 	/* Initialize the control handler. */
-	v4l2_ctrl_handler_init(&wpf->ctrls, 1);
-	wpf->alpha = v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops,
-				       V4L2_CID_ALPHA_COMPONENT,
-				       0, 255, 1, 255);
-
-	wpf->entity.subdev.ctrl_handler = &wpf->ctrls;
-
-	if (wpf->ctrls.error) {
+	ret = vsp1_rwpf_init_ctrls(wpf);
+	if (ret < 0) {
 		dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
 			index);
-		ret = wpf->ctrls.error;
 		goto error;
 	}
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 07/48] v4l: vsp1: rwpf: Don't program alpha value in control set handler
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The datasheet clearly states that all but a few registers can't be
modified when the device is running. Programming the alpha value in
the control set handler is thus prohibited. Program it when starting the
module instead.

This requires storing the alpha value internally as the module can be
started from the frame completion interrupt handler, and accessing
control values requires taking a mutex.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_rpf.c  | 51 +++---------------------------
 drivers/media/platform/vsp1/vsp1_rwpf.c | 35 +++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_rwpf.h |  5 ++-
 drivers/media/platform/vsp1/vsp1_wpf.c  | 55 ++-------------------------------
 4 files changed, 47 insertions(+), 99 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 5bc1d1574a43..9ccfb572b4a5 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -33,36 +33,6 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * Controls
- */
-
-static int rpf_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct vsp1_rwpf *rpf =
-		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
-	struct vsp1_pipeline *pipe;
-
-	if (!vsp1_entity_is_streaming(&rpf->entity))
-		return 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_ALPHA_COMPONENT:
-		vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-			       ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
-
-		pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity);
-		vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct v4l2_ctrl_ops rpf_ctrl_ops = {
-	.s_ctrl = rpf_s_ctrl,
-};
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Core Operations
  */
 
@@ -70,7 +40,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *rpf = to_rwpf(subdev);
-	struct vsp1_device *vsp1 = rpf->entity.vsp1;
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_rect *crop = &rpf->crop;
@@ -151,13 +120,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
 				       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
 
-	if (vsp1->info->uapi)
-		mutex_lock(rpf->ctrls.lock);
 	vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
-		       rpf->alpha->cur.val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
-	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha->cur.val);
-	if (vsp1->info->uapi)
-		mutex_unlock(rpf->ctrls.lock);
+		       rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+
+	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
 
 	vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
 	vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
@@ -255,17 +221,10 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 	vsp1_entity_init_formats(subdev, NULL);
 
 	/* Initialize the control handler. */
-	v4l2_ctrl_handler_init(&rpf->ctrls, 1);
-	rpf->alpha = v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops,
-				       V4L2_CID_ALPHA_COMPONENT,
-				       0, 255, 1, 255);
-
-	rpf->entity.subdev.ctrl_handler = &rpf->ctrls;
-
-	if (rpf->ctrls.error) {
+	ret = vsp1_rwpf_init_ctrls(rpf);
+	if (ret < 0) {
 		dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
 			index);
-		ret = rpf->ctrls.error;
 		goto error;
 	}
 
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 9688c219b30e..ba50386db35c 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -230,3 +230,38 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 
 	return 0;
 }
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct vsp1_rwpf *rwpf =
+		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
+
+	switch (ctrl->id) {
+	case V4L2_CID_ALPHA_COMPONENT:
+		rwpf->alpha = ctrl->val;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {
+	.s_ctrl = vsp1_rwpf_s_ctrl,
+};
+
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
+{
+	rwpf->alpha = 255;
+
+	v4l2_ctrl_handler_init(&rwpf->ctrls, 1);
+	v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,
+			  V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
+
+	rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls;
+
+	return rwpf->ctrls.error;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index d04df39b2737..66af2a06dd8b 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -42,7 +42,6 @@ struct vsp1_rwpf_operations {
 struct vsp1_rwpf {
 	struct vsp1_entity entity;
 	struct v4l2_ctrl_handler ctrls;
-	struct v4l2_ctrl *alpha;
 
 	struct vsp1_video *video;
 
@@ -59,6 +58,8 @@ struct vsp1_rwpf {
 	} location;
 	struct v4l2_rect crop;
 
+	unsigned int alpha;
+
 	unsigned int offsets[2];
 	dma_addr_t buf_addr[3];
 
@@ -73,6 +74,8 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
+int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
+
 int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 			     struct v4l2_subdev_pad_config *cfg,
 			     struct v4l2_subdev_mbus_code_enum *code);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 6afc9c8d9adc..2135cca2490e 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -27,12 +27,6 @@
  * Device Access
  */
 
-static inline u32 vsp1_wpf_read(struct vsp1_rwpf *wpf, u32 reg)
-{
-	return vsp1_read(wpf->entity.vsp1,
-			 reg + wpf->entity.index * VI6_WPF_OFFSET);
-}
-
 static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
 {
 	vsp1_mod_write(&wpf->entity,
@@ -40,35 +34,6 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * Controls
- */
-
-static int wpf_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-	struct vsp1_rwpf *wpf =
-		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
-	u32 value;
-
-	if (!vsp1_entity_is_streaming(&wpf->entity))
-		return 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_ALPHA_COMPONENT:
-		value = vsp1_wpf_read(wpf, VI6_WPF_OUTFMT);
-		value &= ~VI6_WPF_OUTFMT_PDV_MASK;
-		value |= ctrl->val << VI6_WPF_OUTFMT_PDV_SHIFT;
-		vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, value);
-		break;
-	}
-
-	return 0;
-}
-
-static const struct v4l2_ctrl_ops wpf_ctrl_ops = {
-	.s_ctrl = wpf_s_ctrl,
-};
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Core Operations
  */
 
@@ -153,15 +118,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	    wpf->entity.formats[RWPF_PAD_SOURCE].code)
 		outfmt |= VI6_WPF_OUTFMT_CSC;
 
-	/* Take the control handler lock to ensure that the PDV value won't be
-	 * changed behind our back by a set control operation.
-	 */
-	if (vsp1->info->uapi)
-		mutex_lock(wpf->ctrls.lock);
-	outfmt |= wpf->alpha->cur.val << VI6_WPF_OUTFMT_PDV_SHIFT;
+	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
 	vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
-	if (vsp1->info->uapi)
-		mutex_unlock(wpf->ctrls.lock);
 
 	vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index),
 		       VI6_DPR_WPF_FPORCH_FP_WPFN);
@@ -272,17 +230,10 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	vsp1_entity_init_formats(subdev, NULL);
 
 	/* Initialize the control handler. */
-	v4l2_ctrl_handler_init(&wpf->ctrls, 1);
-	wpf->alpha = v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops,
-				       V4L2_CID_ALPHA_COMPONENT,
-				       0, 255, 1, 255);
-
-	wpf->entity.subdev.ctrl_handler = &wpf->ctrls;
-
-	if (wpf->ctrls.error) {
+	ret = vsp1_rwpf_init_ctrls(wpf);
+	if (ret < 0) {
 		dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
 			index);
-		ret = wpf->ctrls.error;
 		goto error;
 	}
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 08/48] v4l: vsp1: sru: Don't program intensity in control set handler
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The datasheet clearly states that all but a few registers can't be
modified when the device is running. Programming the intensity
parameters in the control set handler is thus prohibited. Program it
when starting the module instead.

This requires storing the intensity value internally as the module can
be started from the frame completion interrupt handler, and accessing
control values requires taking a mutex.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_sru.c | 35 +++++++++-------------------------
 drivers/media/platform/vsp1/vsp1_sru.h |  2 ++
 2 files changed, 11 insertions(+), 26 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index cc09efbfb24f..ec4741efc7f8 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -26,11 +26,6 @@
  * Device Access
  */
 
-static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg)
-{
-	return vsp1_read(sru->entity.vsp1, reg);
-}
-
 static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
 {
 	vsp1_write(sru->entity.vsp1, reg, data);
@@ -82,20 +77,10 @@ static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct vsp1_sru *sru  		container_of(ctrl->handler, struct vsp1_sru, ctrls);
-	const struct vsp1_sru_param *param;
-	u32 value;
 
 	switch (ctrl->id) {
 	case V4L2_CID_VSP1_SRU_INTENSITY:
-		param = &vsp1_sru_params[ctrl->val - 1];
-
-		value = vsp1_sru_read(sru, VI6_SRU_CTRL0);
-		value &= ~(VI6_SRU_CTRL0_PARAM0_MASK |
-			   VI6_SRU_CTRL0_PARAM1_MASK);
-		value |= param->ctrl0;
-		vsp1_sru_write(sru, VI6_SRU_CTRL0, value);
-
-		vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+		sru->intensity = ctrl->val;
 		break;
 	}
 
@@ -123,6 +108,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
 
 static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 {
+	const struct vsp1_sru_param *param;
 	struct vsp1_sru *sru = to_sru(subdev);
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
@@ -148,18 +134,13 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (input->width != output->width)
 		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
 
-	/* Take the control handler lock to ensure that the CTRL0 value won't be
-	 * changed behind our back by a set control operation.
-	 */
-	if (sru->entity.vsp1->info->uapi)
-		mutex_lock(sru->ctrls.lock);
-	ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
-	       & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
-	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-	if (sru->entity.vsp1->info->uapi)
-		mutex_unlock(sru->ctrls.lock);
+	param = &vsp1_sru_params[sru->intensity - 1];
+
+	ctrl0 |= param->ctrl0;
 
+	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
 	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
 
 	return 0;
 }
@@ -376,6 +357,8 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 	v4l2_ctrl_handler_init(&sru->ctrls, 1);
 	v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
 
+	sru->intensity = 1;
+
 	sru->entity.subdev.ctrl_handler = &sru->ctrls;
 
 	if (sru->ctrls.error) {
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h
index b6768bf3dc47..85e241457af2 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.h
+++ b/drivers/media/platform/vsp1/vsp1_sru.h
@@ -28,6 +28,8 @@ struct vsp1_sru {
 	struct vsp1_entity entity;
 
 	struct v4l2_ctrl_handler ctrls;
+
+	unsigned int intensity;
 };
 
 static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 08/48] v4l: vsp1: sru: Don't program intensity in control set handler
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The datasheet clearly states that all but a few registers can't be
modified when the device is running. Programming the intensity
parameters in the control set handler is thus prohibited. Program it
when starting the module instead.

This requires storing the intensity value internally as the module can
be started from the frame completion interrupt handler, and accessing
control values requires taking a mutex.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_sru.c | 35 +++++++++-------------------------
 drivers/media/platform/vsp1/vsp1_sru.h |  2 ++
 2 files changed, 11 insertions(+), 26 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index cc09efbfb24f..ec4741efc7f8 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -26,11 +26,6 @@
  * Device Access
  */
 
-static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg)
-{
-	return vsp1_read(sru->entity.vsp1, reg);
-}
-
 static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
 {
 	vsp1_write(sru->entity.vsp1, reg, data);
@@ -82,20 +77,10 @@ static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct vsp1_sru *sru =
 		container_of(ctrl->handler, struct vsp1_sru, ctrls);
-	const struct vsp1_sru_param *param;
-	u32 value;
 
 	switch (ctrl->id) {
 	case V4L2_CID_VSP1_SRU_INTENSITY:
-		param = &vsp1_sru_params[ctrl->val - 1];
-
-		value = vsp1_sru_read(sru, VI6_SRU_CTRL0);
-		value &= ~(VI6_SRU_CTRL0_PARAM0_MASK |
-			   VI6_SRU_CTRL0_PARAM1_MASK);
-		value |= param->ctrl0;
-		vsp1_sru_write(sru, VI6_SRU_CTRL0, value);
-
-		vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+		sru->intensity = ctrl->val;
 		break;
 	}
 
@@ -123,6 +108,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
 
 static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 {
+	const struct vsp1_sru_param *param;
 	struct vsp1_sru *sru = to_sru(subdev);
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
@@ -148,18 +134,13 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (input->width != output->width)
 		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
 
-	/* Take the control handler lock to ensure that the CTRL0 value won't be
-	 * changed behind our back by a set control operation.
-	 */
-	if (sru->entity.vsp1->info->uapi)
-		mutex_lock(sru->ctrls.lock);
-	ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
-	       & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
-	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-	if (sru->entity.vsp1->info->uapi)
-		mutex_unlock(sru->ctrls.lock);
+	param = &vsp1_sru_params[sru->intensity - 1];
+
+	ctrl0 |= param->ctrl0;
 
+	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
 	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
 
 	return 0;
 }
@@ -376,6 +357,8 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 	v4l2_ctrl_handler_init(&sru->ctrls, 1);
 	v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
 
+	sru->intensity = 1;
+
 	sru->entity.subdev.ctrl_handler = &sru->ctrls;
 
 	if (sru->ctrls.error) {
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h
index b6768bf3dc47..85e241457af2 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.h
+++ b/drivers/media/platform/vsp1/vsp1_sru.h
@@ -28,6 +28,8 @@ struct vsp1_sru {
 	struct vsp1_entity entity;
 
 	struct v4l2_ctrl_handler ctrls;
+
+	unsigned int intensity;
 };
 
 static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 09/48] v4l: vsp1: Don't setup control handler when starting streaming
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The control handler set operations don't program the hardware anymore,
there's thus no need to call them when starting the stream.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  5 +----
 drivers/media/platform/vsp1/vsp1_entity.c | 18 +-----------------
 drivers/media/platform/vsp1/vsp1_entity.h |  2 +-
 drivers/media/platform/vsp1/vsp1_rpf.c    |  5 +----
 drivers/media/platform/vsp1/vsp1_sru.c    |  5 +----
 drivers/media/platform/vsp1/vsp1_wpf.c    |  5 +----
 6 files changed, 6 insertions(+), 34 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 4c1bd0419e12..27a9043b11e2 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -66,11 +66,8 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct v4l2_mbus_framefmt *format;
 	unsigned int flags;
 	unsigned int i;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&bru->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&bru->entity, enable);
 
 	if (!enable)
 		return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index c005d374c254..a366cb64ae9d 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -45,29 +45,13 @@ bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
 	return streaming;
 }
 
-int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
+void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
 {
 	unsigned long flags;
-	int ret;
 
 	spin_lock_irqsave(&entity->lock, flags);
 	entity->streaming = streaming;
 	spin_unlock_irqrestore(&entity->lock, flags);
-
-	if (!streaming)
-		return 0;
-
-	if (!entity->vsp1->info->uapi || !entity->subdev.ctrl_handler)
-		return 0;
-
-	ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler);
-	if (ret < 0) {
-		spin_lock_irqsave(&entity->lock, flags);
-		entity->streaming = false;
-		spin_unlock_irqrestore(&entity->lock, flags);
-	}
-
-	return ret;
 }
 
 void vsp1_entity_route_setup(struct vsp1_entity *source)
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 259880e524fe..c0d6db82ebfb 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -101,7 +101,7 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_pad_config *cfg);
 
 bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
-int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
+void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 9ccfb572b4a5..48870b257a81 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -45,11 +45,8 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	const struct v4l2_rect *crop = &rpf->crop;
 	u32 pstride;
 	u32 infmt;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&rpf->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&rpf->entity, enable);
 
 	if (!enable)
 		return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index ec4741efc7f8..15fc562a52da 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -113,11 +113,8 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
 	u32 ctrl0;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&sru->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&sru->entity, enable);
 
 	if (!enable)
 		return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 2135cca2490e..d68c90d45232 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -46,11 +46,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	unsigned int i;
 	u32 srcrpf = 0;
 	u32 outfmt = 0;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&wpf->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&wpf->entity, enable);
 
 	if (!enable) {
 		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 09/48] v4l: vsp1: Don't setup control handler when starting streaming
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The control handler set operations don't program the hardware anymore,
there's thus no need to call them when starting the stream.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  5 +----
 drivers/media/platform/vsp1/vsp1_entity.c | 18 +-----------------
 drivers/media/platform/vsp1/vsp1_entity.h |  2 +-
 drivers/media/platform/vsp1/vsp1_rpf.c    |  5 +----
 drivers/media/platform/vsp1/vsp1_sru.c    |  5 +----
 drivers/media/platform/vsp1/vsp1_wpf.c    |  5 +----
 6 files changed, 6 insertions(+), 34 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 4c1bd0419e12..27a9043b11e2 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -66,11 +66,8 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct v4l2_mbus_framefmt *format;
 	unsigned int flags;
 	unsigned int i;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&bru->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&bru->entity, enable);
 
 	if (!enable)
 		return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index c005d374c254..a366cb64ae9d 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -45,29 +45,13 @@ bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
 	return streaming;
 }
 
-int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
+void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
 {
 	unsigned long flags;
-	int ret;
 
 	spin_lock_irqsave(&entity->lock, flags);
 	entity->streaming = streaming;
 	spin_unlock_irqrestore(&entity->lock, flags);
-
-	if (!streaming)
-		return 0;
-
-	if (!entity->vsp1->info->uapi || !entity->subdev.ctrl_handler)
-		return 0;
-
-	ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler);
-	if (ret < 0) {
-		spin_lock_irqsave(&entity->lock, flags);
-		entity->streaming = false;
-		spin_unlock_irqrestore(&entity->lock, flags);
-	}
-
-	return ret;
 }
 
 void vsp1_entity_route_setup(struct vsp1_entity *source)
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 259880e524fe..c0d6db82ebfb 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -101,7 +101,7 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_pad_config *cfg);
 
 bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
-int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
+void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 9ccfb572b4a5..48870b257a81 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -45,11 +45,8 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	const struct v4l2_rect *crop = &rpf->crop;
 	u32 pstride;
 	u32 infmt;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&rpf->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&rpf->entity, enable);
 
 	if (!enable)
 		return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index ec4741efc7f8..15fc562a52da 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -113,11 +113,8 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
 	u32 ctrl0;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&sru->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&sru->entity, enable);
 
 	if (!enable)
 		return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 2135cca2490e..d68c90d45232 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -46,11 +46,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	unsigned int i;
 	u32 srcrpf = 0;
 	u32 outfmt = 0;
-	int ret;
 
-	ret = vsp1_entity_set_streaming(&wpf->entity, enable);
-	if (ret < 0)
-		return ret;
+	vsp1_entity_set_streaming(&wpf->entity, enable);
 
 	if (!enable) {
 		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 10/48] v4l: vsp1: Enable display list support for the HS[IT], LUT, SRU and UDS
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Those modules were left out of display list integration as they're not
used by the DRM pipeline. To prepare for display list support in non-DRM
pipelines use the module write API to set registers.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_hsit.c | 2 +-
 drivers/media/platform/vsp1/vsp1_lut.c  | 2 +-
 drivers/media/platform/vsp1/vsp1_sru.c  | 2 +-
 drivers/media/platform/vsp1/vsp1_uds.c  | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index c1087cff31a0..e820fe0b4f00 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -28,7 +28,7 @@
 
 static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
 {
-	vsp1_write(hsit->entity.vsp1, reg, data);
+	vsp1_mod_write(&hsit->entity, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 4b89095e7b5f..fc9011b12993 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -29,7 +29,7 @@
 
 static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
 {
-	vsp1_write(lut->entity.vsp1, reg, data);
+	vsp1_mod_write(&lut->entity, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 15fc562a52da..810c6b376e14 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -28,7 +28,7 @@
 
 static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
 {
-	vsp1_write(sru->entity.vsp1, reg, data);
+	vsp1_mod_write(&sru->entity, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index bba67770cf95..c608b06ed677 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -31,8 +31,8 @@
 
 static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
 {
-	vsp1_write(uds->entity.vsp1,
-		   reg + uds->entity.index * VI6_UDS_OFFSET, data);
+	vsp1_mod_write(&uds->entity, reg + uds->entity.index * VI6_UDS_OFFSET,
+		       data);
 }
 
 /* -----------------------------------------------------------------------------
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 10/48] v4l: vsp1: Enable display list support for the HS[IT], LUT, SRU and UDS
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Those modules were left out of display list integration as they're not
used by the DRM pipeline. To prepare for display list support in non-DRM
pipelines use the module write API to set registers.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_hsit.c | 2 +-
 drivers/media/platform/vsp1/vsp1_lut.c  | 2 +-
 drivers/media/platform/vsp1/vsp1_sru.c  | 2 +-
 drivers/media/platform/vsp1/vsp1_uds.c  | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index c1087cff31a0..e820fe0b4f00 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -28,7 +28,7 @@
 
 static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
 {
-	vsp1_write(hsit->entity.vsp1, reg, data);
+	vsp1_mod_write(&hsit->entity, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 4b89095e7b5f..fc9011b12993 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -29,7 +29,7 @@
 
 static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
 {
-	vsp1_write(lut->entity.vsp1, reg, data);
+	vsp1_mod_write(&lut->entity, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 15fc562a52da..810c6b376e14 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -28,7 +28,7 @@
 
 static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
 {
-	vsp1_write(sru->entity.vsp1, reg, data);
+	vsp1_mod_write(&sru->entity, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index bba67770cf95..c608b06ed677 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -31,8 +31,8 @@
 
 static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
 {
-	vsp1_write(uds->entity.vsp1,
-		   reg + uds->entity.index * VI6_UDS_OFFSET, data);
+	vsp1_mod_write(&uds->entity, reg + uds->entity.index * VI6_UDS_OFFSET,
+		       data);
 }
 
 /* -----------------------------------------------------------------------------
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 11/48] v4l: vsp1: Don't configure RPF memory buffers before calculating offsets
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The RPF source memory pointers need to be offset to take the crop
rectangle into account. Offsets are computed in the RPF stream start,
which can happen (when using the DRM pipeline) after calling the RPF
.set_memory() operation that programs the buffer addresses.

The .set_memory() operation tries to guard against the problem by
skipping programming of the registers when the module isn't streaming.
This will however only protect the first use of an RPF in a DRM
pipeline, as in all subsequent uses the module streaming flag will be
set and the .set_memory() operation will use potentially incorrect
offsets.

Fix this by allowing the caller to decide whether to program the
hardware immediately or just cache the addresses. While at it refactor
the memory set code and create a new vsp1_rwpf_set_memory() that cache
addresses and calls the .set_memory() operation to apply them to the
hardware.

As a side effect the driver now writes all three DMA address registers
regardless of the number of planes, and initializes unused addresses to
zero.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c   |  7 ++++--
 drivers/media/platform/vsp1/vsp1_rpf.c   | 37 ++++++++++----------------------
 drivers/media/platform/vsp1/vsp1_rwpf.c  | 26 ++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_rwpf.h  | 11 ++++++++--
 drivers/media/platform/vsp1/vsp1_video.c |  9 ++++++--
 drivers/media/platform/vsp1/vsp1_wpf.c   | 10 ++++-----
 6 files changed, 62 insertions(+), 38 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index b3df694569e7..52b50d0e54e3 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -420,12 +420,15 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 	rpf->location.left = dst->left;
 	rpf->location.top = dst->top;
 
-	/* Set the memory buffer address. */
+	/* Set the memory buffer address but don't apply the values to the
+	 * hardware as the crop offsets haven't been computed yet.
+	 */
 	memory.num_planes = fmtinfo->planes;
 	memory.addr[0] = mem[0];
 	memory.addr[1] = mem[1];
+	memory.addr[2] = 0;
 
-	rpf->ops->set_memory(rpf, &memory);
+	vsp1_rwpf_set_memory(rpf, &memory, false);
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 48870b257a81..62d898c0ad65 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -69,25 +69,20 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	pstride = format->plane_fmt[0].bytesperline
 		<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->buf_addr[0] + rpf->offsets[0]);
-
 	if (format->num_planes > 1) {
 		rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
 				+ crop->left * fmtinfo->bpp[1] / 8;
 		pstride |= format->plane_fmt[1].bytesperline
 			<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
-
-		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-			       rpf->buf_addr[1] + rpf->offsets[1]);
-
-		if (format->num_planes > 2)
-			vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-				       rpf->buf_addr[2] + rpf->offsets[1]);
+	} else {
+		rpf->offsets[1] = 0;
 	}
 
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
+	/* Now that the offsets have been computed program the DMA addresses. */
+	rpf->ops->set_memory(rpf);
+
 	/* Format */
 	infmt = VI6_RPF_INFMT_CIPM
 	      | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
@@ -154,24 +149,14 @@ static struct v4l2_subdev_ops rpf_ops = {
  * Video Device Operations
  */
 
-static void rpf_set_memory(struct vsp1_rwpf *rpf, struct vsp1_rwpf_memory *mem)
+static void rpf_set_memory(struct vsp1_rwpf *rpf)
 {
-	unsigned int i;
-
-	for (i = 0; i < 3; ++i)
-		rpf->buf_addr[i] = mem->addr[i];
-
-	if (!vsp1_entity_is_streaming(&rpf->entity))
-		return;
-
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       mem->addr[0] + rpf->offsets[0]);
-	if (mem->num_planes > 1)
-		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-			       mem->addr[1] + rpf->offsets[1]);
-	if (mem->num_planes > 2)
-		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-			       mem->addr[2] + rpf->offsets[1]);
+		       rpf->buf_addr[0] + rpf->offsets[0]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+		       rpf->buf_addr[1] + rpf->offsets[1]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+		       rpf->buf_addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_rwpf_operations rpf_vdev_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index ba50386db35c..54070ccdc2ff 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -265,3 +265,29 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
 
 	return rwpf->ctrls.error;
 }
+
+/* -----------------------------------------------------------------------------
+ * Buffers
+ */
+
+/**
+ * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
+ * @rwpf: the [RW]PF instance
+ * @mem: DMA memory addresses
+ * @apply: whether to apply the configuration to the hardware
+ *
+ * This function stores the DMA addresses for all planes in the rwpf instance
+ * and optionally applies the configuration to hardware registers if the apply
+ * argument is set to true.
+ */
+void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
+			  bool apply)
+{
+	unsigned int i;
+
+	for (i = 0; i < 3; ++i)
+		rwpf->buf_addr[i] = mem->addr[i];
+
+	if (apply)
+		rwpf->ops->set_memory(rwpf);
+}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 66af2a06dd8b..bda0416dc7db 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -34,9 +34,13 @@ struct vsp1_rwpf_memory {
 	unsigned int length[3];
 };
 
+/**
+ * struct vsp1_rwpf_operations - RPF and WPF operations
+ * @set_memory: Setup memory buffer access. This operation applies the settings
+ *		stored in the rwpf buf_addr field to the hardware.
+ */
 struct vsp1_rwpf_operations {
-	void (*set_memory)(struct vsp1_rwpf *rwpf,
-			   struct vsp1_rwpf_memory *mem);
+	void (*set_memory)(struct vsp1_rwpf *rwpf);
 };
 
 struct vsp1_rwpf {
@@ -93,4 +97,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_selection *sel);
 
+void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
+			  bool apply);
+
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 682e5b6f787d..facadc9f86cb 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -449,7 +449,7 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
+	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
@@ -530,6 +530,11 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
 			return -EINVAL;
 	}
 
+	for ( ; i < 3; ++i) {
+		buf->mem.addr[i] = 0;
+		buf->mem.length[i] = 0;
+	}
+
 	return 0;
 }
 
@@ -552,7 +557,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
+	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	if (vb2_is_streaming(&video->queue) &&
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d68c90d45232..28654cffeeca 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -157,13 +157,11 @@ static struct v4l2_subdev_ops wpf_ops = {
  * Video Device Operations
  */
 
-static void wpf_set_memory(struct vsp1_rwpf *wpf, struct vsp1_rwpf_memory *mem)
+static void wpf_set_memory(struct vsp1_rwpf *wpf)
 {
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, mem->addr[0]);
-	if (mem->num_planes > 1)
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, mem->addr[1]);
-	if (mem->num_planes > 2)
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, mem->addr[2]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->buf_addr[0]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->buf_addr[1]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->buf_addr[2]);
 }
 
 static const struct vsp1_rwpf_operations wpf_vdev_ops = {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 11/48] v4l: vsp1: Don't configure RPF memory buffers before calculating offsets
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The RPF source memory pointers need to be offset to take the crop
rectangle into account. Offsets are computed in the RPF stream start,
which can happen (when using the DRM pipeline) after calling the RPF
.set_memory() operation that programs the buffer addresses.

The .set_memory() operation tries to guard against the problem by
skipping programming of the registers when the module isn't streaming.
This will however only protect the first use of an RPF in a DRM
pipeline, as in all subsequent uses the module streaming flag will be
set and the .set_memory() operation will use potentially incorrect
offsets.

Fix this by allowing the caller to decide whether to program the
hardware immediately or just cache the addresses. While at it refactor
the memory set code and create a new vsp1_rwpf_set_memory() that cache
addresses and calls the .set_memory() operation to apply them to the
hardware.

As a side effect the driver now writes all three DMA address registers
regardless of the number of planes, and initializes unused addresses to
zero.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c   |  7 ++++--
 drivers/media/platform/vsp1/vsp1_rpf.c   | 37 ++++++++++----------------------
 drivers/media/platform/vsp1/vsp1_rwpf.c  | 26 ++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_rwpf.h  | 11 ++++++++--
 drivers/media/platform/vsp1/vsp1_video.c |  9 ++++++--
 drivers/media/platform/vsp1/vsp1_wpf.c   | 10 ++++-----
 6 files changed, 62 insertions(+), 38 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index b3df694569e7..52b50d0e54e3 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -420,12 +420,15 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 	rpf->location.left = dst->left;
 	rpf->location.top = dst->top;
 
-	/* Set the memory buffer address. */
+	/* Set the memory buffer address but don't apply the values to the
+	 * hardware as the crop offsets haven't been computed yet.
+	 */
 	memory.num_planes = fmtinfo->planes;
 	memory.addr[0] = mem[0];
 	memory.addr[1] = mem[1];
+	memory.addr[2] = 0;
 
-	rpf->ops->set_memory(rpf, &memory);
+	vsp1_rwpf_set_memory(rpf, &memory, false);
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 48870b257a81..62d898c0ad65 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -69,25 +69,20 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	pstride = format->plane_fmt[0].bytesperline
 		<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->buf_addr[0] + rpf->offsets[0]);
-
 	if (format->num_planes > 1) {
 		rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
 				+ crop->left * fmtinfo->bpp[1] / 8;
 		pstride |= format->plane_fmt[1].bytesperline
 			<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
-
-		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-			       rpf->buf_addr[1] + rpf->offsets[1]);
-
-		if (format->num_planes > 2)
-			vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-				       rpf->buf_addr[2] + rpf->offsets[1]);
+	} else {
+		rpf->offsets[1] = 0;
 	}
 
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
+	/* Now that the offsets have been computed program the DMA addresses. */
+	rpf->ops->set_memory(rpf);
+
 	/* Format */
 	infmt = VI6_RPF_INFMT_CIPM
 	      | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
@@ -154,24 +149,14 @@ static struct v4l2_subdev_ops rpf_ops = {
  * Video Device Operations
  */
 
-static void rpf_set_memory(struct vsp1_rwpf *rpf, struct vsp1_rwpf_memory *mem)
+static void rpf_set_memory(struct vsp1_rwpf *rpf)
 {
-	unsigned int i;
-
-	for (i = 0; i < 3; ++i)
-		rpf->buf_addr[i] = mem->addr[i];
-
-	if (!vsp1_entity_is_streaming(&rpf->entity))
-		return;
-
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       mem->addr[0] + rpf->offsets[0]);
-	if (mem->num_planes > 1)
-		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-			       mem->addr[1] + rpf->offsets[1]);
-	if (mem->num_planes > 2)
-		vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-			       mem->addr[2] + rpf->offsets[1]);
+		       rpf->buf_addr[0] + rpf->offsets[0]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+		       rpf->buf_addr[1] + rpf->offsets[1]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+		       rpf->buf_addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_rwpf_operations rpf_vdev_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index ba50386db35c..54070ccdc2ff 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -265,3 +265,29 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
 
 	return rwpf->ctrls.error;
 }
+
+/* -----------------------------------------------------------------------------
+ * Buffers
+ */
+
+/**
+ * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
+ * @rwpf: the [RW]PF instance
+ * @mem: DMA memory addresses
+ * @apply: whether to apply the configuration to the hardware
+ *
+ * This function stores the DMA addresses for all planes in the rwpf instance
+ * and optionally applies the configuration to hardware registers if the apply
+ * argument is set to true.
+ */
+void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
+			  bool apply)
+{
+	unsigned int i;
+
+	for (i = 0; i < 3; ++i)
+		rwpf->buf_addr[i] = mem->addr[i];
+
+	if (apply)
+		rwpf->ops->set_memory(rwpf);
+}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 66af2a06dd8b..bda0416dc7db 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -34,9 +34,13 @@ struct vsp1_rwpf_memory {
 	unsigned int length[3];
 };
 
+/**
+ * struct vsp1_rwpf_operations - RPF and WPF operations
+ * @set_memory: Setup memory buffer access. This operation applies the settings
+ *		stored in the rwpf buf_addr field to the hardware.
+ */
 struct vsp1_rwpf_operations {
-	void (*set_memory)(struct vsp1_rwpf *rwpf,
-			   struct vsp1_rwpf_memory *mem);
+	void (*set_memory)(struct vsp1_rwpf *rwpf);
 };
 
 struct vsp1_rwpf {
@@ -93,4 +97,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_selection *sel);
 
+void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
+			  bool apply);
+
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 682e5b6f787d..facadc9f86cb 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -449,7 +449,7 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
+	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
@@ -530,6 +530,11 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
 			return -EINVAL;
 	}
 
+	for ( ; i < 3; ++i) {
+		buf->mem.addr[i] = 0;
+		buf->mem.length[i] = 0;
+	}
+
 	return 0;
 }
 
@@ -552,7 +557,7 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	video->rwpf->ops->set_memory(video->rwpf, &buf->mem);
+	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	if (vb2_is_streaming(&video->queue) &&
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d68c90d45232..28654cffeeca 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -157,13 +157,11 @@ static struct v4l2_subdev_ops wpf_ops = {
  * Video Device Operations
  */
 
-static void wpf_set_memory(struct vsp1_rwpf *wpf, struct vsp1_rwpf_memory *mem)
+static void wpf_set_memory(struct vsp1_rwpf *wpf)
 {
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, mem->addr[0]);
-	if (mem->num_planes > 1)
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, mem->addr[1]);
-	if (mem->num_planes > 2)
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, mem->addr[2]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->buf_addr[0]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->buf_addr[1]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->buf_addr[2]);
 }
 
 static const struct vsp1_rwpf_operations wpf_vdev_ops = {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 12/48] v4l: vsp1: Remove unneeded entity streaming flag
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The flag is set but never read, remove it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  2 --
 drivers/media/platform/vsp1/vsp1_entity.c | 23 -----------------------
 drivers/media/platform/vsp1/vsp1_entity.h |  6 ------
 drivers/media/platform/vsp1/vsp1_rpf.c    |  2 --
 drivers/media/platform/vsp1/vsp1_sru.c    |  2 --
 drivers/media/platform/vsp1/vsp1_wpf.c    |  2 --
 6 files changed, 37 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 27a9043b11e2..74cc4903e858 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -67,8 +67,6 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 	unsigned int flags;
 	unsigned int i;
 
-	vsp1_entity_set_streaming(&bru->entity, enable);
-
 	if (!enable)
 		return 0;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index a366cb64ae9d..69e11586087c 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -33,27 +33,6 @@ void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
 		vsp1_write(e->vsp1, reg, data);
 }
 
-bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
-{
-	unsigned long flags;
-	bool streaming;
-
-	spin_lock_irqsave(&entity->lock, flags);
-	streaming = entity->streaming;
-	spin_unlock_irqrestore(&entity->lock, flags);
-
-	return streaming;
-}
-
-void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&entity->lock, flags);
-	entity->streaming = streaming;
-	spin_unlock_irqrestore(&entity->lock, flags);
-}
-
 void vsp1_entity_route_setup(struct vsp1_entity *source)
 {
 	struct vsp1_entity *sink;
@@ -198,8 +177,6 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	if (i = ARRAY_SIZE(vsp1_routes))
 		return -EINVAL;
 
-	spin_lock_init(&entity->lock);
-
 	entity->vsp1 = vsp1;
 	entity->source_pad = num_pads - 1;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index c0d6db82ebfb..203872164f8e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -73,9 +73,6 @@ struct vsp1_entity {
 
 	struct v4l2_subdev subdev;
 	struct v4l2_mbus_framefmt *formats;
-
-	spinlock_t lock;		/* Protects the streaming field */
-	bool streaming;
 };
 
 static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -100,9 +97,6 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_pad_config *cfg);
 
-bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
-void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
-
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
 void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data);
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 62d898c0ad65..ffe097b27a77 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -46,8 +46,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	u32 pstride;
 	u32 infmt;
 
-	vsp1_entity_set_streaming(&rpf->entity, enable);
-
 	if (!enable)
 		return 0;
 
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 810c6b376e14..371b20ec5d1b 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -114,8 +114,6 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct v4l2_mbus_framefmt *output;
 	u32 ctrl0;
 
-	vsp1_entity_set_streaming(&sru->entity, enable);
-
 	if (!enable)
 		return 0;
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 28654cffeeca..1013190e440b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -47,8 +47,6 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	u32 srcrpf = 0;
 	u32 outfmt = 0;
 
-	vsp1_entity_set_streaming(&wpf->entity, enable);
-
 	if (!enable) {
 		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
 		vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 12/48] v4l: vsp1: Remove unneeded entity streaming flag
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The flag is set but never read, remove it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  2 --
 drivers/media/platform/vsp1/vsp1_entity.c | 23 -----------------------
 drivers/media/platform/vsp1/vsp1_entity.h |  6 ------
 drivers/media/platform/vsp1/vsp1_rpf.c    |  2 --
 drivers/media/platform/vsp1/vsp1_sru.c    |  2 --
 drivers/media/platform/vsp1/vsp1_wpf.c    |  2 --
 6 files changed, 37 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 27a9043b11e2..74cc4903e858 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -67,8 +67,6 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 	unsigned int flags;
 	unsigned int i;
 
-	vsp1_entity_set_streaming(&bru->entity, enable);
-
 	if (!enable)
 		return 0;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index a366cb64ae9d..69e11586087c 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -33,27 +33,6 @@ void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
 		vsp1_write(e->vsp1, reg, data);
 }
 
-bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
-{
-	unsigned long flags;
-	bool streaming;
-
-	spin_lock_irqsave(&entity->lock, flags);
-	streaming = entity->streaming;
-	spin_unlock_irqrestore(&entity->lock, flags);
-
-	return streaming;
-}
-
-void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&entity->lock, flags);
-	entity->streaming = streaming;
-	spin_unlock_irqrestore(&entity->lock, flags);
-}
-
 void vsp1_entity_route_setup(struct vsp1_entity *source)
 {
 	struct vsp1_entity *sink;
@@ -198,8 +177,6 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	if (i == ARRAY_SIZE(vsp1_routes))
 		return -EINVAL;
 
-	spin_lock_init(&entity->lock);
-
 	entity->vsp1 = vsp1;
 	entity->source_pad = num_pads - 1;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index c0d6db82ebfb..203872164f8e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -73,9 +73,6 @@ struct vsp1_entity {
 
 	struct v4l2_subdev subdev;
 	struct v4l2_mbus_framefmt *formats;
-
-	spinlock_t lock;		/* Protects the streaming field */
-	bool streaming;
 };
 
 static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -100,9 +97,6 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_pad_config *cfg);
 
-bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
-void vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
-
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
 void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data);
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 62d898c0ad65..ffe097b27a77 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -46,8 +46,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	u32 pstride;
 	u32 infmt;
 
-	vsp1_entity_set_streaming(&rpf->entity, enable);
-
 	if (!enable)
 		return 0;
 
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 810c6b376e14..371b20ec5d1b 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -114,8 +114,6 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct v4l2_mbus_framefmt *output;
 	u32 ctrl0;
 
-	vsp1_entity_set_streaming(&sru->entity, enable);
-
 	if (!enable)
 		return 0;
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 28654cffeeca..1013190e440b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -47,8 +47,6 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	u32 srcrpf = 0;
 	u32 outfmt = 0;
 
-	vsp1_entity_set_streaming(&wpf->entity, enable);
-
 	if (!enable) {
 		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
 		vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 13/48] v4l: vsp1: Document calling context of vsp1_pipeline_propagate_alpha()
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The function can only be called from a s_stream handler as it requires a
valid display list context (due to calling vsp1_uds_set_alpha() which
writes to module registers). Document the requirement.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_pipe.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index facf68f999ce..9549aacab3cf 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -297,6 +297,9 @@ done:
  * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
  * value. The UDS then outputs a fixed alpha value which needs to be programmed
  * from the input RPF alpha.
+ *
+ * This function can only be called from a subdev s_stream handler as it
+ * requires a valid display list context.
  */
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_entity *input,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 13/48] v4l: vsp1: Document calling context of vsp1_pipeline_propagate_alpha()
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The function can only be called from a s_stream handler as it requires a
valid display list context (due to calling vsp1_uds_set_alpha() which
writes to module registers). Document the requirement.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_pipe.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index facf68f999ce..9549aacab3cf 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -297,6 +297,9 @@ done:
  * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
  * value. The UDS then outputs a fixed alpha value which needs to be programmed
  * from the input RPF alpha.
+ *
+ * This function can only be called from a subdev s_stream handler as it
+ * requires a valid display list context.
  */
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_entity *input,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 14/48] v4l: vsp1: Fix 80 characters per line violations
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Commit f7234138f14c ("v4l2-subdev: replace v4l2_subdev_fh by
v4l2_subdev_pad_config") introduced lots of 80 characters per line
violations. Fix them.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c  | 12 ++++++++----
 drivers/media/platform/vsp1/vsp1_lif.c  |  6 ++++--
 drivers/media/platform/vsp1/vsp1_lut.c  |  6 ++++--
 drivers/media/platform/vsp1/vsp1_rwpf.c | 12 ++++++++----
 drivers/media/platform/vsp1/vsp1_rwpf.h |  6 ++++--
 drivers/media/platform/vsp1/vsp1_sru.c  |  9 ++++++---
 drivers/media/platform/vsp1/vsp1_uds.c  |  9 ++++++---
 7 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 74cc4903e858..6a6e9d84f1ca 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -195,7 +195,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
 			return -EINVAL;
 
 		format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-						    BRU_PAD_SINK(0), code->which);
+						    BRU_PAD_SINK(0),
+						    code->which);
 		code->code = format->code;
 	}
 
@@ -235,7 +236,8 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
 	}
 }
 
-static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int bru_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
@@ -246,7 +248,8 @@ static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg,
+static void bru_try_format(struct vsp1_bru *bru,
+			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
@@ -274,7 +277,8 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int bru_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 433853ce8dbf..be0ea166016c 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -128,7 +128,8 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lif_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
@@ -139,7 +140,8 @@ static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lif_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index fc9011b12993..3af849dbee5a 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -139,7 +139,8 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lut_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
@@ -150,7 +151,8 @@ static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lut_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 54070ccdc2ff..0924079b920c 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -73,11 +73,13 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static struct v4l2_rect *
-vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which)
+vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg,
+		   u32 which)
 {
 	switch (which) {
 	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK);
+		return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg,
+						RWPF_PAD_SINK);
 	case V4L2_SUBDEV_FORMAT_ACTIVE:
 		return &rwpf->crop;
 	default:
@@ -85,7 +87,8 @@ vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u
 	}
 }
 
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
@@ -96,7 +99,8 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_conf
 	return 0;
 }
 
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index bda0416dc7db..57f15d45f8bb 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -86,9 +86,11 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_pad_config *cfg,
 			      struct v4l2_subdev_frame_size_enum *fse);
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt);
 int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 371b20ec5d1b..19b7923cb137 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -209,7 +209,8 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int sru_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
@@ -220,7 +221,8 @@ static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg,
+static void sru_try_format(struct vsp1_sru *sru,
+			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
@@ -271,7 +273,8 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int sru_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index c608b06ed677..83ec8942f8e7 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -222,7 +222,8 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int uds_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
@@ -233,7 +234,8 @@ static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg,
+static void uds_try_format(struct vsp1_uds *uds,
+			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
@@ -269,7 +271,8 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int uds_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 14/48] v4l: vsp1: Fix 80 characters per line violations
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Commit f7234138f14c ("v4l2-subdev: replace v4l2_subdev_fh by
v4l2_subdev_pad_config") introduced lots of 80 characters per line
violations. Fix them.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c  | 12 ++++++++----
 drivers/media/platform/vsp1/vsp1_lif.c  |  6 ++++--
 drivers/media/platform/vsp1/vsp1_lut.c  |  6 ++++--
 drivers/media/platform/vsp1/vsp1_rwpf.c | 12 ++++++++----
 drivers/media/platform/vsp1/vsp1_rwpf.h |  6 ++++--
 drivers/media/platform/vsp1/vsp1_sru.c  |  9 ++++++---
 drivers/media/platform/vsp1/vsp1_uds.c  |  9 ++++++---
 7 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 74cc4903e858..6a6e9d84f1ca 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -195,7 +195,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
 			return -EINVAL;
 
 		format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-						    BRU_PAD_SINK(0), code->which);
+						    BRU_PAD_SINK(0),
+						    code->which);
 		code->code = format->code;
 	}
 
@@ -235,7 +236,8 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
 	}
 }
 
-static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int bru_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
@@ -246,7 +248,8 @@ static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg,
+static void bru_try_format(struct vsp1_bru *bru,
+			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
@@ -274,7 +277,8 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int bru_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 433853ce8dbf..be0ea166016c 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -128,7 +128,8 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lif_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
@@ -139,7 +140,8 @@ static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lif_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index fc9011b12993..3af849dbee5a 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -139,7 +139,8 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lut_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
@@ -150,7 +151,8 @@ static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int lut_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 54070ccdc2ff..0924079b920c 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -73,11 +73,13 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 }
 
 static struct v4l2_rect *
-vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which)
+vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg,
+		   u32 which)
 {
 	switch (which) {
 	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK);
+		return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg,
+						RWPF_PAD_SINK);
 	case V4L2_SUBDEV_FORMAT_ACTIVE:
 		return &rwpf->crop;
 	default:
@@ -85,7 +87,8 @@ vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u
 	}
 }
 
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
@@ -96,7 +99,8 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_conf
 	return 0;
 }
 
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index bda0416dc7db..57f15d45f8bb 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -86,9 +86,11 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_pad_config *cfg,
 			      struct v4l2_subdev_frame_size_enum *fse);
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+			 struct v4l2_subdev_pad_config *cfg,
 			 struct v4l2_subdev_format *fmt);
 int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 371b20ec5d1b..19b7923cb137 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -209,7 +209,8 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int sru_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
@@ -220,7 +221,8 @@ static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg,
+static void sru_try_format(struct vsp1_sru *sru,
+			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
@@ -271,7 +273,8 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int sru_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index c608b06ed677..83ec8942f8e7 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -222,7 +222,8 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int uds_get_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
@@ -233,7 +234,8 @@ static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_con
 	return 0;
 }
 
-static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg,
+static void uds_try_format(struct vsp1_uds *uds,
+			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
 			   enum v4l2_subdev_format_whence which)
 {
@@ -269,7 +271,8 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *
 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
 }
 
-static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg,
+static int uds_set_format(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 15/48] v4l: vsp1: Add header display list support
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Display lists can operate in header or headerless mode. The headerless
mode is only available on WPF0, to be used with the display engine. All
other WPF instances can only use display lists in header mode.

Implement support for header mode to prepare for display list usage on
WPFs other than 0.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c  | 73 +++++++++++++++++++++++++++++++---
 drivers/media/platform/vsp1/vsp1_dl.h  |  1 +
 drivers/media/platform/vsp1/vsp1_wpf.c |  2 +-
 3 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 32661daac7b0..5cdd515470ac 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -28,9 +28,23 @@
  * - DL swap
  */
 
+#define VSP1_DL_HEADER_SIZE		76
 #define VSP1_DL_BODY_SIZE		(2 * 4 * 256)
 #define VSP1_DL_NUM_LISTS		3
 
+#define VSP1_DLH_INT_ENABLE		(1 << 1)
+#define VSP1_DLH_AUTO_START		(1 << 0)
+
+struct vsp1_dl_header {
+	u32 num_lists;
+	struct {
+		u32 num_bytes;
+		u32 addr;
+	} lists[8];
+	u32 next_header;
+	u32 flags;
+} __attribute__((__packed__));
+
 struct vsp1_dl_entry {
 	u32 addr;
 	u32 data;
@@ -41,6 +55,7 @@ struct vsp1_dl_list {
 
 	struct vsp1_dl_manager *dlm;
 
+	struct vsp1_dl_header *header;
 	struct vsp1_dl_entry *body;
 	dma_addr_t dma;
 	size_t size;
@@ -48,8 +63,15 @@ struct vsp1_dl_list {
 	int reg_count;
 };
 
+enum vsp1_dl_mode {
+	VSP1_DL_MODE_HEADER,
+	VSP1_DL_MODE_HEADERLESS,
+};
+
 /**
  * struct vsp1_dl_manager - Display List manager
+ * @index: index of the related WPF
+ * @mode: display list operation mode (header or headerless)
  * @vsp1: the VSP1 device
  * @lock: protects the active, queued and pending lists
  * @free: array of all free display lists
@@ -58,6 +80,8 @@ struct vsp1_dl_list {
  * @pending: list waiting to be queued to the hardware
  */
 struct vsp1_dl_manager {
+	unsigned int index;
+	enum vsp1_dl_mode mode;
 	struct vsp1_device *vsp1;
 
 	spinlock_t lock;
@@ -74,27 +98,43 @@ struct vsp1_dl_manager {
 static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
 {
 	struct vsp1_dl_list *dl;
+	size_t header_size;
+
+	/* The body needs to be aligned on a 8 bytes boundary, pad the header
+	 * size to allow allocating both in a single operation.
+	 */
+	header_size = dlm->mode = VSP1_DL_MODE_HEADER
+		    ? ALIGN(sizeof(struct vsp1_dl_header), 8)
+		    : 0;
 
 	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
 	if (!dl)
 		return NULL;
 
 	dl->dlm = dlm;
-	dl->size = VSP1_DL_BODY_SIZE;
+	dl->size = header_size + VSP1_DL_BODY_SIZE;
 
-	dl->body = dma_alloc_writecombine(dlm->vsp1->dev, dl->size, &dl->dma,
-					  GFP_KERNEL);
-	if (!dl->body) {
+	dl->header = dma_alloc_writecombine(dlm->vsp1->dev, dl->size, &dl->dma,
+					    GFP_KERNEL);
+	if (!dl->header) {
 		kfree(dl);
 		return NULL;
 	}
 
+	if (dlm->mode = VSP1_DL_MODE_HEADER) {
+		memset(dl->header, 0, sizeof(*dl->header));
+		dl->header->lists[0].addr = dl->dma + header_size;
+		dl->header->flags = VSP1_DLH_INT_ENABLE;
+	}
+
+	dl->body = ((void *)dl->header) + header_size;
+
 	return dl;
 }
 
 static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
 {
-	dma_free_writecombine(dl->dlm->vsp1->dev, dl->size, dl->body, dl->dma);
+	dma_free_writecombine(dl->dlm->vsp1->dev, dl->size, dl->header, dl->dma);
 	kfree(dl);
 }
 
@@ -160,6 +200,18 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
 
 	spin_lock_irqsave(&dlm->lock, flags);
 
+	if (dl->dlm->mode = VSP1_DL_MODE_HEADER) {
+		/* Program the hardware with the display list body address and
+		 * size. In header mode the caller guarantees that the hardware
+		 * is idle at this point.
+		 */
+		dl->header->lists[0].num_bytes = dl->reg_count * 8;
+		vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma);
+
+		dlm->active = dl;
+		goto done;
+	}
+
 	/* Once the UPD bit has been set the hardware can start processing the
 	 * display list at any time and we can't touch the address and size
 	 * registers. In that case mark the update as pending, it will be
@@ -215,6 +267,13 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 	vsp1_dl_list_put(dlm->active);
 	dlm->active = NULL;
 
+	/* Header mode is used for mem-to-mem pipelines only. We don't need to
+	 * perform any operation as there can't be any new display list queued
+	 * in that case.
+	 */
+	if (dlm->mode = VSP1_DL_MODE_HEADER)
+		goto done;
+
 	/* The UPD bit set indicates that the commit operation raced with the
 	 * interrupt and occurred after the frame end event and UPD clear but
 	 * before interrupt processing. The hardware hasn't taken the update
@@ -277,6 +336,7 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
 }
 
 struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int index,
 					unsigned int prealloc)
 {
 	struct vsp1_dl_manager *dlm;
@@ -286,6 +346,9 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
 	if (!dlm)
 		return NULL;
 
+	dlm->index = index;
+	dlm->mode = index = 0 && !vsp1->info->uapi
+		  ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER;
 	dlm->vsp1 = vsp1;
 
 	spin_lock_init(&dlm->lock);
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 46f7ae337374..571ed6d8e7c2 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -22,6 +22,7 @@ struct vsp1_dl_manager;
 void vsp1_dlm_setup(struct vsp1_device *vsp1);
 
 struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int index,
 					unsigned int prealloc);
 void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 1013190e440b..d1fad9effb9b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -202,7 +202,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 
 	/* Initialize the display list manager if the WPF is used for display */
 	if ((vsp1->info->features & VSP1_HAS_LIF) && index = 0) {
-		wpf->dlm = vsp1_dlm_create(vsp1, 4);
+		wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
 		if (!wpf->dlm) {
 			ret = -ENOMEM;
 			goto error;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 15/48] v4l: vsp1: Add header display list support
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Display lists can operate in header or headerless mode. The headerless
mode is only available on WPF0, to be used with the display engine. All
other WPF instances can only use display lists in header mode.

Implement support for header mode to prepare for display list usage on
WPFs other than 0.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c  | 73 +++++++++++++++++++++++++++++++---
 drivers/media/platform/vsp1/vsp1_dl.h  |  1 +
 drivers/media/platform/vsp1/vsp1_wpf.c |  2 +-
 3 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 32661daac7b0..5cdd515470ac 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -28,9 +28,23 @@
  * - DL swap
  */
 
+#define VSP1_DL_HEADER_SIZE		76
 #define VSP1_DL_BODY_SIZE		(2 * 4 * 256)
 #define VSP1_DL_NUM_LISTS		3
 
+#define VSP1_DLH_INT_ENABLE		(1 << 1)
+#define VSP1_DLH_AUTO_START		(1 << 0)
+
+struct vsp1_dl_header {
+	u32 num_lists;
+	struct {
+		u32 num_bytes;
+		u32 addr;
+	} lists[8];
+	u32 next_header;
+	u32 flags;
+} __attribute__((__packed__));
+
 struct vsp1_dl_entry {
 	u32 addr;
 	u32 data;
@@ -41,6 +55,7 @@ struct vsp1_dl_list {
 
 	struct vsp1_dl_manager *dlm;
 
+	struct vsp1_dl_header *header;
 	struct vsp1_dl_entry *body;
 	dma_addr_t dma;
 	size_t size;
@@ -48,8 +63,15 @@ struct vsp1_dl_list {
 	int reg_count;
 };
 
+enum vsp1_dl_mode {
+	VSP1_DL_MODE_HEADER,
+	VSP1_DL_MODE_HEADERLESS,
+};
+
 /**
  * struct vsp1_dl_manager - Display List manager
+ * @index: index of the related WPF
+ * @mode: display list operation mode (header or headerless)
  * @vsp1: the VSP1 device
  * @lock: protects the active, queued and pending lists
  * @free: array of all free display lists
@@ -58,6 +80,8 @@ struct vsp1_dl_list {
  * @pending: list waiting to be queued to the hardware
  */
 struct vsp1_dl_manager {
+	unsigned int index;
+	enum vsp1_dl_mode mode;
 	struct vsp1_device *vsp1;
 
 	spinlock_t lock;
@@ -74,27 +98,43 @@ struct vsp1_dl_manager {
 static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
 {
 	struct vsp1_dl_list *dl;
+	size_t header_size;
+
+	/* The body needs to be aligned on a 8 bytes boundary, pad the header
+	 * size to allow allocating both in a single operation.
+	 */
+	header_size = dlm->mode == VSP1_DL_MODE_HEADER
+		    ? ALIGN(sizeof(struct vsp1_dl_header), 8)
+		    : 0;
 
 	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
 	if (!dl)
 		return NULL;
 
 	dl->dlm = dlm;
-	dl->size = VSP1_DL_BODY_SIZE;
+	dl->size = header_size + VSP1_DL_BODY_SIZE;
 
-	dl->body = dma_alloc_writecombine(dlm->vsp1->dev, dl->size, &dl->dma,
-					  GFP_KERNEL);
-	if (!dl->body) {
+	dl->header = dma_alloc_writecombine(dlm->vsp1->dev, dl->size, &dl->dma,
+					    GFP_KERNEL);
+	if (!dl->header) {
 		kfree(dl);
 		return NULL;
 	}
 
+	if (dlm->mode == VSP1_DL_MODE_HEADER) {
+		memset(dl->header, 0, sizeof(*dl->header));
+		dl->header->lists[0].addr = dl->dma + header_size;
+		dl->header->flags = VSP1_DLH_INT_ENABLE;
+	}
+
+	dl->body = ((void *)dl->header) + header_size;
+
 	return dl;
 }
 
 static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
 {
-	dma_free_writecombine(dl->dlm->vsp1->dev, dl->size, dl->body, dl->dma);
+	dma_free_writecombine(dl->dlm->vsp1->dev, dl->size, dl->header, dl->dma);
 	kfree(dl);
 }
 
@@ -160,6 +200,18 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
 
 	spin_lock_irqsave(&dlm->lock, flags);
 
+	if (dl->dlm->mode == VSP1_DL_MODE_HEADER) {
+		/* Program the hardware with the display list body address and
+		 * size. In header mode the caller guarantees that the hardware
+		 * is idle at this point.
+		 */
+		dl->header->lists[0].num_bytes = dl->reg_count * 8;
+		vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma);
+
+		dlm->active = dl;
+		goto done;
+	}
+
 	/* Once the UPD bit has been set the hardware can start processing the
 	 * display list at any time and we can't touch the address and size
 	 * registers. In that case mark the update as pending, it will be
@@ -215,6 +267,13 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
 	vsp1_dl_list_put(dlm->active);
 	dlm->active = NULL;
 
+	/* Header mode is used for mem-to-mem pipelines only. We don't need to
+	 * perform any operation as there can't be any new display list queued
+	 * in that case.
+	 */
+	if (dlm->mode == VSP1_DL_MODE_HEADER)
+		goto done;
+
 	/* The UPD bit set indicates that the commit operation raced with the
 	 * interrupt and occurred after the frame end event and UPD clear but
 	 * before interrupt processing. The hardware hasn't taken the update
@@ -277,6 +336,7 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
 }
 
 struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int index,
 					unsigned int prealloc)
 {
 	struct vsp1_dl_manager *dlm;
@@ -286,6 +346,9 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
 	if (!dlm)
 		return NULL;
 
+	dlm->index = index;
+	dlm->mode = index == 0 && !vsp1->info->uapi
+		  ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER;
 	dlm->vsp1 = vsp1;
 
 	spin_lock_init(&dlm->lock);
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 46f7ae337374..571ed6d8e7c2 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -22,6 +22,7 @@ struct vsp1_dl_manager;
 void vsp1_dlm_setup(struct vsp1_device *vsp1);
 
 struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+					unsigned int index,
 					unsigned int prealloc);
 void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
 void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 1013190e440b..d1fad9effb9b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -202,7 +202,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 
 	/* Initialize the display list manager if the WPF is used for display */
 	if ((vsp1->info->features & VSP1_HAS_LIF) && index == 0) {
-		wpf->dlm = vsp1_dlm_create(vsp1, 4);
+		wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
 		if (!wpf->dlm) {
 			ret = -ENOMEM;
 			goto error;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 16/48] v4l: vsp1: Use display lists with the userspace API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Don't restrict display list usage to the DRM pipeline, use them
unconditionally. This prepares the driver to support the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c     |  11 +--
 drivers/media/platform/vsp1/vsp1_drm.c    |  23 ++---
 drivers/media/platform/vsp1/vsp1_entity.c |   5 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  33 +------
 drivers/media/platform/vsp1/vsp1_rpf.c    |   9 +-
 drivers/media/platform/vsp1/vsp1_rwpf.c   |  26 ------
 drivers/media/platform/vsp1/vsp1_rwpf.h   |  18 ++--
 drivers/media/platform/vsp1/vsp1_video.c  | 145 +++++++++++++++++++++---------
 drivers/media/platform/vsp1/vsp1_wpf.c    |  18 ++--
 9 files changed, 142 insertions(+), 146 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 5cdd515470ac..43597b38a433 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -311,14 +311,15 @@ done:
 /* Hardware Setup */
 void vsp1_dlm_setup(struct vsp1_device *vsp1)
 {
-	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT);
+	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
+		 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
+		 | VI6_DL_CTRL_DLE;
 
-	/* The DRM pipeline operates with header-less display lists in
-	 * Continuous Frame Mode.
+	/* The DRM pipeline operates with display lists in Continuous Frame
+	 * Mode, all other pipelines use manual start.
 	 */
 	if (vsp1->drm)
-		ctrl |= VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
-		     |  VI6_DL_CTRL_DLE | VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
+		ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
 
 	vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
 	vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 52b50d0e54e3..90157ac9b0b1 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -36,11 +36,6 @@ void vsp1_drm_display_start(struct vsp1_device *vsp1)
 	vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
 }
 
-void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
-{
-	vsp1_dlm_irq_frame_end(pipe->output->dlm);
-}
-
 /* -----------------------------------------------------------------------------
  * DU Driver API
  */
@@ -280,7 +275,6 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 	const struct vsp1_format_info *fmtinfo;
 	struct v4l2_subdev_selection sel;
 	struct v4l2_subdev_format format;
-	struct vsp1_rwpf_memory memory;
 	struct vsp1_rwpf *rpf;
 	unsigned long flags;
 	int ret;
@@ -420,15 +414,12 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 	rpf->location.left = dst->left;
 	rpf->location.top = dst->top;
 
-	/* Set the memory buffer address but don't apply the values to the
+	/* Cache the memory buffer address but don't apply the values to the
 	 * hardware as the crop offsets haven't been computed yet.
 	 */
-	memory.num_planes = fmtinfo->planes;
-	memory.addr[0] = mem[0];
-	memory.addr[1] = mem[1];
-	memory.addr[2] = 0;
-
-	vsp1_rwpf_set_memory(rpf, &memory, false);
+	rpf->mem.addr[0] = mem[0];
+	rpf->mem.addr[1] = mem[1];
+	rpf->mem.addr[2] = 0;
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
@@ -482,14 +473,17 @@ void vsp1_du_atomic_flush(struct device *dev)
 				entity->subdev.name);
 			return;
 		}
+
+		if (entity->type = VSP1_ENTITY_RPF)
+			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
 	}
 
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
 
+	/* Start or stop the pipeline if needed. */
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	/* Start or stop the pipeline if needed. */
 	if (!vsp1->drm->num_inputs && pipe->num_inputs) {
 		vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
 		vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE);
@@ -569,7 +563,6 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
-	pipe->frame_end = vsp1_drm_frame_end;
 
 	/* The DRM pipeline is static, add entities manually. */
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 69e11586087c..dfa0735e36f4 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -27,10 +27,7 @@ void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
 
-	if (pipe->dl)
-		vsp1_dl_list_write(pipe->dl, reg, data);
-	else
-		vsp1_write(e->vsp1, reg, data);
+	vsp1_dl_list_write(pipe->dl, reg, data);
 }
 
 void vsp1_entity_route_setup(struct vsp1_entity *source)
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 9549aacab3cf..dd0921b31e98 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -252,42 +252,13 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
-	enum vsp1_pipeline_state state;
-	unsigned long flags;
-
 	if (pipe = NULL)
 		return;
 
-	/* Signal frame end to the pipeline handler. */
+	vsp1_dlm_irq_frame_end(pipe->output->dlm);
+
 	if (pipe->frame_end)
 		pipe->frame_end(pipe);
-
-	spin_lock_irqsave(&pipe->irqlock, flags);
-
-	state = pipe->state;
-
-	/* When using display lists in continuous frame mode the pipeline is
-	 * automatically restarted by the hardware.
-	 */
-	if (pipe->lif)
-		goto done;
-
-	pipe->state = VSP1_PIPELINE_STOPPED;
-
-	/* If a stop has been requested, mark the pipeline as stopped and
-	 * return.
-	 */
-	if (state = VSP1_PIPELINE_STOPPING) {
-		wake_up(&pipe->wq);
-		goto done;
-	}
-
-	/* Restart the pipeline if ready. */
-	if (vsp1_pipeline_ready(pipe))
-		vsp1_pipeline_run(pipe);
-
-done:
-	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
 /*
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index ffe097b27a77..09919db7e0ea 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -78,9 +78,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
-	/* Now that the offsets have been computed program the DMA addresses. */
-	rpf->ops->set_memory(rpf);
-
 	/* Format */
 	infmt = VI6_RPF_INFMT_CIPM
 	      | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
@@ -150,11 +147,11 @@ static struct v4l2_subdev_ops rpf_ops = {
 static void rpf_set_memory(struct vsp1_rwpf *rpf)
 {
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->buf_addr[0] + rpf->offsets[0]);
+		       rpf->mem.addr[0] + rpf->offsets[0]);
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-		       rpf->buf_addr[1] + rpf->offsets[1]);
+		       rpf->mem.addr[1] + rpf->offsets[1]);
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-		       rpf->buf_addr[2] + rpf->offsets[1]);
+		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_rwpf_operations rpf_vdev_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 0924079b920c..38893ab06cd9 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -269,29 +269,3 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
 
 	return rwpf->ctrls.error;
 }
-
-/* -----------------------------------------------------------------------------
- * Buffers
- */
-
-/**
- * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
- * @rwpf: the [RW]PF instance
- * @mem: DMA memory addresses
- * @apply: whether to apply the configuration to the hardware
- *
- * This function stores the DMA addresses for all planes in the rwpf instance
- * and optionally applies the configuration to hardware registers if the apply
- * argument is set to true.
- */
-void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
-			  bool apply)
-{
-	unsigned int i;
-
-	for (i = 0; i < 3; ++i)
-		rwpf->buf_addr[i] = mem->addr[i];
-
-	if (apply)
-		rwpf->ops->set_memory(rwpf);
-}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 57f15d45f8bb..2bbcc331959b 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -29,15 +29,13 @@ struct vsp1_rwpf;
 struct vsp1_video;
 
 struct vsp1_rwpf_memory {
-	unsigned int num_planes;
 	dma_addr_t addr[3];
-	unsigned int length[3];
 };
 
 /**
  * struct vsp1_rwpf_operations - RPF and WPF operations
  * @set_memory: Setup memory buffer access. This operation applies the settings
- *		stored in the rwpf buf_addr field to the hardware.
+ *		stored in the rwpf mem field to the hardware.
  */
 struct vsp1_rwpf_operations {
 	void (*set_memory)(struct vsp1_rwpf *rwpf);
@@ -65,7 +63,7 @@ struct vsp1_rwpf {
 	unsigned int alpha;
 
 	unsigned int offsets[2];
-	dma_addr_t buf_addr[3];
+	struct vsp1_rwpf_memory mem;
 
 	struct vsp1_dl_manager *dlm;
 };
@@ -99,7 +97,15 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_selection *sel);
 
-void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
-			  bool apply);
+/**
+ * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
+ * @rwpf: the [RW]PF instance
+ *
+ * This function applies the cached memory buffer address to the hardware.
+ */
+static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf)
+{
+	rwpf->ops->set_memory(rwpf);
+}
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index facadc9f86cb..50fc91a2f509 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -29,6 +29,7 @@
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
+#include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
@@ -430,7 +431,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
 	v4l2_get_timestamp(&done->buf.timestamp);
 	for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
 		vb2_set_plane_payload(&done->buf.vb2_buf, i,
-				      done->mem.length[i]);
+				      vb2_plane_size(&done->buf.vb2_buf, i));
 	vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
 
 	return next;
@@ -449,15 +450,41 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
+	video->rwpf->mem = buf->mem;
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
+static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
+{
+	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	unsigned int i;
+
+	if (!pipe->dl)
+		pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+
+	for (i = 0; i < vsp1->info->rpf_count; ++i) {
+		struct vsp1_rwpf *rwpf = pipe->inputs[i];
+
+		if (rwpf)
+			vsp1_rwpf_set_memory(rwpf);
+	}
+
+	if (!pipe->lif)
+		vsp1_rwpf_set_memory(pipe->output);
+
+	vsp1_dl_list_commit(pipe->dl);
+	pipe->dl = NULL;
+
+	vsp1_pipeline_run(pipe);
+}
+
 static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	enum vsp1_pipeline_state state;
+	unsigned long flags;
 	unsigned int i;
 
 	/* Complete buffers on all video nodes. */
@@ -468,8 +495,22 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
 		vsp1_video_frame_end(pipe, pipe->inputs[i]);
 	}
 
-	if (!pipe->lif)
-		vsp1_video_frame_end(pipe, pipe->output);
+	vsp1_video_frame_end(pipe, pipe->output);
+
+	spin_lock_irqsave(&pipe->irqlock, flags);
+
+	state = pipe->state;
+	pipe->state = VSP1_PIPELINE_STOPPED;
+
+	/* If a stop has been requested, mark the pipeline as stopped and
+	 * return. Otherwise restart the pipeline if ready.
+	 */
+	if (state = VSP1_PIPELINE_STOPPING)
+		wake_up(&pipe->wq);
+	else if (vsp1_pipeline_ready(pipe))
+		vsp1_video_pipeline_run(pipe);
+
+	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
 /* -----------------------------------------------------------------------------
@@ -520,20 +561,15 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
 	if (vb->num_planes < format->num_planes)
 		return -EINVAL;
 
-	buf->mem.num_planes = vb->num_planes;
-
 	for (i = 0; i < vb->num_planes; ++i) {
 		buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
-		buf->mem.length[i] = vb2_plane_size(vb, i);
 
-		if (buf->mem.length[i] < format->plane_fmt[i].sizeimage)
+		if (vb2_plane_size(vb, i) < format->plane_fmt[i].sizeimage)
 			return -EINVAL;
 	}
 
-	for ( ; i < 3; ++i) {
+	for ( ; i < 3; ++i)
 		buf->mem.addr[i] = 0;
-		buf->mem.length[i] = 0;
-	}
 
 	return 0;
 }
@@ -557,54 +593,74 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
+	video->rwpf->mem = buf->mem;
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	if (vb2_is_streaming(&video->queue) &&
 	    vsp1_pipeline_ready(pipe))
-		vsp1_pipeline_run(pipe);
+		vsp1_video_pipeline_run(pipe);
 
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+{
+	struct vsp1_entity *entity;
+	int ret;
+
+	/* Prepare the display list. */
+	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+	if (!pipe->dl)
+		return -ENOMEM;
+
+	if (pipe->uds) {
+		struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
+
+		/* If a BRU is present in the pipeline before the UDS, the alpha
+		 * component doesn't need to be scaled as the BRU output alpha
+		 * value is fixed to 255. Otherwise we need to scale the alpha
+		 * component only when available at the input RPF.
+		 */
+		if (pipe->uds_input->type = VSP1_ENTITY_BRU) {
+			uds->scale_alpha = false;
+		} else {
+			struct vsp1_rwpf *rpf +				to_rwpf(&pipe->uds_input->subdev);
+
+			uds->scale_alpha = rpf->fmtinfo->alpha;
+		}
+	}
+
+	list_for_each_entry(entity, &pipe->entities, list_pipe) {
+		vsp1_entity_route_setup(entity);
+
+		ret = v4l2_subdev_call(&entity->subdev, video, s_stream, 1);
+		if (ret < 0)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	vsp1_dl_list_put(pipe->dl);
+	pipe->dl = NULL;
+
+	return ret;
+}
+
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct vsp1_video *video = vb2_get_drv_priv(vq);
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
-	struct vsp1_entity *entity;
 	unsigned long flags;
 	int ret;
 
 	mutex_lock(&pipe->lock);
 	if (pipe->stream_count = pipe->num_inputs) {
-		if (pipe->uds) {
-			struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
-
-			/* If a BRU is present in the pipeline before the UDS,
-			 * the alpha component doesn't need to be scaled as the
-			 * BRU output alpha value is fixed to 255. Otherwise we
-			 * need to scale the alpha component only when available
-			 * at the input RPF.
-			 */
-			if (pipe->uds_input->type = VSP1_ENTITY_BRU) {
-				uds->scale_alpha = false;
-			} else {
-				struct vsp1_rwpf *rpf -					to_rwpf(&pipe->uds_input->subdev);
-
-				uds->scale_alpha = rpf->fmtinfo->alpha;
-			}
-		}
-
-		list_for_each_entry(entity, &pipe->entities, list_pipe) {
-			vsp1_entity_route_setup(entity);
-
-			ret = v4l2_subdev_call(&entity->subdev, video,
-					       s_stream, 1);
-			if (ret < 0) {
-				mutex_unlock(&pipe->lock);
-				return ret;
-			}
+		ret = vsp1_video_setup_pipeline(pipe);
+		if (ret < 0) {
+			mutex_unlock(&pipe->lock);
+			return ret;
 		}
 	}
 
@@ -613,7 +669,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 	if (vsp1_pipeline_ready(pipe))
-		vsp1_pipeline_run(pipe);
+		vsp1_video_pipeline_run(pipe);
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
 	return 0;
@@ -633,6 +689,9 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
 		ret = vsp1_pipeline_stop(pipe);
 		if (ret = -ETIMEDOUT)
 			dev_err(video->vsp1->dev, "pipeline stop timeout\n");
+
+		vsp1_dl_list_put(pipe->dl);
+		pipe->dl = NULL;
 	}
 	mutex_unlock(&pipe->lock);
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d1fad9effb9b..d889997b7948 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -157,9 +157,9 @@ static struct v4l2_subdev_ops wpf_ops = {
 
 static void wpf_set_memory(struct vsp1_rwpf *wpf)
 {
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->buf_addr[0]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->buf_addr[1]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->buf_addr[2]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
 static const struct vsp1_rwpf_operations wpf_vdev_ops = {
@@ -200,13 +200,11 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the display list manager if the WPF is used for display */
-	if ((vsp1->info->features & VSP1_HAS_LIF) && index = 0) {
-		wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
-		if (!wpf->dlm) {
-			ret = -ENOMEM;
-			goto error;
-		}
+	/* Initialize the display list manager. */
+	wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
+	if (!wpf->dlm) {
+		ret = -ENOMEM;
+		goto error;
 	}
 
 	/* Initialize the V4L2 subdev. */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 16/48] v4l: vsp1: Use display lists with the userspace API
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Don't restrict display list usage to the DRM pipeline, use them
unconditionally. This prepares the driver to support the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_dl.c     |  11 +--
 drivers/media/platform/vsp1/vsp1_drm.c    |  23 ++---
 drivers/media/platform/vsp1/vsp1_entity.c |   5 +-
 drivers/media/platform/vsp1/vsp1_pipe.c   |  33 +------
 drivers/media/platform/vsp1/vsp1_rpf.c    |   9 +-
 drivers/media/platform/vsp1/vsp1_rwpf.c   |  26 ------
 drivers/media/platform/vsp1/vsp1_rwpf.h   |  18 ++--
 drivers/media/platform/vsp1/vsp1_video.c  | 145 +++++++++++++++++++++---------
 drivers/media/platform/vsp1/vsp1_wpf.c    |  18 ++--
 9 files changed, 142 insertions(+), 146 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 5cdd515470ac..43597b38a433 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -311,14 +311,15 @@ done:
 /* Hardware Setup */
 void vsp1_dlm_setup(struct vsp1_device *vsp1)
 {
-	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT);
+	u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
+		 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
+		 | VI6_DL_CTRL_DLE;
 
-	/* The DRM pipeline operates with header-less display lists in
-	 * Continuous Frame Mode.
+	/* The DRM pipeline operates with display lists in Continuous Frame
+	 * Mode, all other pipelines use manual start.
 	 */
 	if (vsp1->drm)
-		ctrl |= VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
-		     |  VI6_DL_CTRL_DLE | VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
+		ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
 
 	vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
 	vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 52b50d0e54e3..90157ac9b0b1 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -36,11 +36,6 @@ void vsp1_drm_display_start(struct vsp1_device *vsp1)
 	vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
 }
 
-void vsp1_drm_frame_end(struct vsp1_pipeline *pipe)
-{
-	vsp1_dlm_irq_frame_end(pipe->output->dlm);
-}
-
 /* -----------------------------------------------------------------------------
  * DU Driver API
  */
@@ -280,7 +275,6 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 	const struct vsp1_format_info *fmtinfo;
 	struct v4l2_subdev_selection sel;
 	struct v4l2_subdev_format format;
-	struct vsp1_rwpf_memory memory;
 	struct vsp1_rwpf *rpf;
 	unsigned long flags;
 	int ret;
@@ -420,15 +414,12 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 	rpf->location.left = dst->left;
 	rpf->location.top = dst->top;
 
-	/* Set the memory buffer address but don't apply the values to the
+	/* Cache the memory buffer address but don't apply the values to the
 	 * hardware as the crop offsets haven't been computed yet.
 	 */
-	memory.num_planes = fmtinfo->planes;
-	memory.addr[0] = mem[0];
-	memory.addr[1] = mem[1];
-	memory.addr[2] = 0;
-
-	vsp1_rwpf_set_memory(rpf, &memory, false);
+	rpf->mem.addr[0] = mem[0];
+	rpf->mem.addr[1] = mem[1];
+	rpf->mem.addr[2] = 0;
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
@@ -482,14 +473,17 @@ void vsp1_du_atomic_flush(struct device *dev)
 				entity->subdev.name);
 			return;
 		}
+
+		if (entity->type == VSP1_ENTITY_RPF)
+			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
 	}
 
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
 
+	/* Start or stop the pipeline if needed. */
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	/* Start or stop the pipeline if needed. */
 	if (!vsp1->drm->num_inputs && pipe->num_inputs) {
 		vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
 		vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE);
@@ -569,7 +563,6 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
 	pipe = &vsp1->drm->pipe;
 
 	vsp1_pipeline_init(pipe);
-	pipe->frame_end = vsp1_drm_frame_end;
 
 	/* The DRM pipeline is static, add entities manually. */
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 69e11586087c..dfa0735e36f4 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -27,10 +27,7 @@ void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
 
-	if (pipe->dl)
-		vsp1_dl_list_write(pipe->dl, reg, data);
-	else
-		vsp1_write(e->vsp1, reg, data);
+	vsp1_dl_list_write(pipe->dl, reg, data);
 }
 
 void vsp1_entity_route_setup(struct vsp1_entity *source)
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 9549aacab3cf..dd0921b31e98 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -252,42 +252,13 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
-	enum vsp1_pipeline_state state;
-	unsigned long flags;
-
 	if (pipe == NULL)
 		return;
 
-	/* Signal frame end to the pipeline handler. */
+	vsp1_dlm_irq_frame_end(pipe->output->dlm);
+
 	if (pipe->frame_end)
 		pipe->frame_end(pipe);
-
-	spin_lock_irqsave(&pipe->irqlock, flags);
-
-	state = pipe->state;
-
-	/* When using display lists in continuous frame mode the pipeline is
-	 * automatically restarted by the hardware.
-	 */
-	if (pipe->lif)
-		goto done;
-
-	pipe->state = VSP1_PIPELINE_STOPPED;
-
-	/* If a stop has been requested, mark the pipeline as stopped and
-	 * return.
-	 */
-	if (state == VSP1_PIPELINE_STOPPING) {
-		wake_up(&pipe->wq);
-		goto done;
-	}
-
-	/* Restart the pipeline if ready. */
-	if (vsp1_pipeline_ready(pipe))
-		vsp1_pipeline_run(pipe);
-
-done:
-	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
 /*
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index ffe097b27a77..09919db7e0ea 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -78,9 +78,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
-	/* Now that the offsets have been computed program the DMA addresses. */
-	rpf->ops->set_memory(rpf);
-
 	/* Format */
 	infmt = VI6_RPF_INFMT_CIPM
 	      | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
@@ -150,11 +147,11 @@ static struct v4l2_subdev_ops rpf_ops = {
 static void rpf_set_memory(struct vsp1_rwpf *rpf)
 {
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->buf_addr[0] + rpf->offsets[0]);
+		       rpf->mem.addr[0] + rpf->offsets[0]);
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-		       rpf->buf_addr[1] + rpf->offsets[1]);
+		       rpf->mem.addr[1] + rpf->offsets[1]);
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-		       rpf->buf_addr[2] + rpf->offsets[1]);
+		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_rwpf_operations rpf_vdev_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 0924079b920c..38893ab06cd9 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -269,29 +269,3 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf)
 
 	return rwpf->ctrls.error;
 }
-
-/* -----------------------------------------------------------------------------
- * Buffers
- */
-
-/**
- * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
- * @rwpf: the [RW]PF instance
- * @mem: DMA memory addresses
- * @apply: whether to apply the configuration to the hardware
- *
- * This function stores the DMA addresses for all planes in the rwpf instance
- * and optionally applies the configuration to hardware registers if the apply
- * argument is set to true.
- */
-void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
-			  bool apply)
-{
-	unsigned int i;
-
-	for (i = 0; i < 3; ++i)
-		rwpf->buf_addr[i] = mem->addr[i];
-
-	if (apply)
-		rwpf->ops->set_memory(rwpf);
-}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 57f15d45f8bb..2bbcc331959b 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -29,15 +29,13 @@ struct vsp1_rwpf;
 struct vsp1_video;
 
 struct vsp1_rwpf_memory {
-	unsigned int num_planes;
 	dma_addr_t addr[3];
-	unsigned int length[3];
 };
 
 /**
  * struct vsp1_rwpf_operations - RPF and WPF operations
  * @set_memory: Setup memory buffer access. This operation applies the settings
- *		stored in the rwpf buf_addr field to the hardware.
+ *		stored in the rwpf mem field to the hardware.
  */
 struct vsp1_rwpf_operations {
 	void (*set_memory)(struct vsp1_rwpf *rwpf);
@@ -65,7 +63,7 @@ struct vsp1_rwpf {
 	unsigned int alpha;
 
 	unsigned int offsets[2];
-	dma_addr_t buf_addr[3];
+	struct vsp1_rwpf_memory mem;
 
 	struct vsp1_dl_manager *dlm;
 };
@@ -99,7 +97,15 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_selection *sel);
 
-void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf, struct vsp1_rwpf_memory *mem,
-			  bool apply);
+/**
+ * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
+ * @rwpf: the [RW]PF instance
+ *
+ * This function applies the cached memory buffer address to the hardware.
+ */
+static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf)
+{
+	rwpf->ops->set_memory(rwpf);
+}
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index facadc9f86cb..50fc91a2f509 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -29,6 +29,7 @@
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
+#include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
 #include "vsp1_rwpf.h"
@@ -430,7 +431,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
 	v4l2_get_timestamp(&done->buf.timestamp);
 	for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
 		vb2_set_plane_payload(&done->buf.vb2_buf, i,
-				      done->mem.length[i]);
+				      vb2_plane_size(&done->buf.vb2_buf, i));
 	vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
 
 	return next;
@@ -449,15 +450,41 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
+	video->rwpf->mem = buf->mem;
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
+static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
+{
+	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	unsigned int i;
+
+	if (!pipe->dl)
+		pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+
+	for (i = 0; i < vsp1->info->rpf_count; ++i) {
+		struct vsp1_rwpf *rwpf = pipe->inputs[i];
+
+		if (rwpf)
+			vsp1_rwpf_set_memory(rwpf);
+	}
+
+	if (!pipe->lif)
+		vsp1_rwpf_set_memory(pipe->output);
+
+	vsp1_dl_list_commit(pipe->dl);
+	pipe->dl = NULL;
+
+	vsp1_pipeline_run(pipe);
+}
+
 static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	enum vsp1_pipeline_state state;
+	unsigned long flags;
 	unsigned int i;
 
 	/* Complete buffers on all video nodes. */
@@ -468,8 +495,22 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
 		vsp1_video_frame_end(pipe, pipe->inputs[i]);
 	}
 
-	if (!pipe->lif)
-		vsp1_video_frame_end(pipe, pipe->output);
+	vsp1_video_frame_end(pipe, pipe->output);
+
+	spin_lock_irqsave(&pipe->irqlock, flags);
+
+	state = pipe->state;
+	pipe->state = VSP1_PIPELINE_STOPPED;
+
+	/* If a stop has been requested, mark the pipeline as stopped and
+	 * return. Otherwise restart the pipeline if ready.
+	 */
+	if (state == VSP1_PIPELINE_STOPPING)
+		wake_up(&pipe->wq);
+	else if (vsp1_pipeline_ready(pipe))
+		vsp1_video_pipeline_run(pipe);
+
+	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
 /* -----------------------------------------------------------------------------
@@ -520,20 +561,15 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
 	if (vb->num_planes < format->num_planes)
 		return -EINVAL;
 
-	buf->mem.num_planes = vb->num_planes;
-
 	for (i = 0; i < vb->num_planes; ++i) {
 		buf->mem.addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
-		buf->mem.length[i] = vb2_plane_size(vb, i);
 
-		if (buf->mem.length[i] < format->plane_fmt[i].sizeimage)
+		if (vb2_plane_size(vb, i) < format->plane_fmt[i].sizeimage)
 			return -EINVAL;
 	}
 
-	for ( ; i < 3; ++i) {
+	for ( ; i < 3; ++i)
 		buf->mem.addr[i] = 0;
-		buf->mem.length[i] = 0;
-	}
 
 	return 0;
 }
@@ -557,54 +593,74 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 
-	vsp1_rwpf_set_memory(video->rwpf, &buf->mem, true);
+	video->rwpf->mem = buf->mem;
 	pipe->buffers_ready |= 1 << video->pipe_index;
 
 	if (vb2_is_streaming(&video->queue) &&
 	    vsp1_pipeline_ready(pipe))
-		vsp1_pipeline_run(pipe);
+		vsp1_video_pipeline_run(pipe);
 
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
+static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
+{
+	struct vsp1_entity *entity;
+	int ret;
+
+	/* Prepare the display list. */
+	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+	if (!pipe->dl)
+		return -ENOMEM;
+
+	if (pipe->uds) {
+		struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
+
+		/* If a BRU is present in the pipeline before the UDS, the alpha
+		 * component doesn't need to be scaled as the BRU output alpha
+		 * value is fixed to 255. Otherwise we need to scale the alpha
+		 * component only when available at the input RPF.
+		 */
+		if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+			uds->scale_alpha = false;
+		} else {
+			struct vsp1_rwpf *rpf =
+				to_rwpf(&pipe->uds_input->subdev);
+
+			uds->scale_alpha = rpf->fmtinfo->alpha;
+		}
+	}
+
+	list_for_each_entry(entity, &pipe->entities, list_pipe) {
+		vsp1_entity_route_setup(entity);
+
+		ret = v4l2_subdev_call(&entity->subdev, video, s_stream, 1);
+		if (ret < 0)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	vsp1_dl_list_put(pipe->dl);
+	pipe->dl = NULL;
+
+	return ret;
+}
+
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct vsp1_video *video = vb2_get_drv_priv(vq);
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
-	struct vsp1_entity *entity;
 	unsigned long flags;
 	int ret;
 
 	mutex_lock(&pipe->lock);
 	if (pipe->stream_count == pipe->num_inputs) {
-		if (pipe->uds) {
-			struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
-
-			/* If a BRU is present in the pipeline before the UDS,
-			 * the alpha component doesn't need to be scaled as the
-			 * BRU output alpha value is fixed to 255. Otherwise we
-			 * need to scale the alpha component only when available
-			 * at the input RPF.
-			 */
-			if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
-				uds->scale_alpha = false;
-			} else {
-				struct vsp1_rwpf *rpf =
-					to_rwpf(&pipe->uds_input->subdev);
-
-				uds->scale_alpha = rpf->fmtinfo->alpha;
-			}
-		}
-
-		list_for_each_entry(entity, &pipe->entities, list_pipe) {
-			vsp1_entity_route_setup(entity);
-
-			ret = v4l2_subdev_call(&entity->subdev, video,
-					       s_stream, 1);
-			if (ret < 0) {
-				mutex_unlock(&pipe->lock);
-				return ret;
-			}
+		ret = vsp1_video_setup_pipeline(pipe);
+		if (ret < 0) {
+			mutex_unlock(&pipe->lock);
+			return ret;
 		}
 	}
 
@@ -613,7 +669,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 
 	spin_lock_irqsave(&pipe->irqlock, flags);
 	if (vsp1_pipeline_ready(pipe))
-		vsp1_pipeline_run(pipe);
+		vsp1_video_pipeline_run(pipe);
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
 	return 0;
@@ -633,6 +689,9 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
 		ret = vsp1_pipeline_stop(pipe);
 		if (ret == -ETIMEDOUT)
 			dev_err(video->vsp1->dev, "pipeline stop timeout\n");
+
+		vsp1_dl_list_put(pipe->dl);
+		pipe->dl = NULL;
 	}
 	mutex_unlock(&pipe->lock);
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d1fad9effb9b..d889997b7948 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -157,9 +157,9 @@ static struct v4l2_subdev_ops wpf_ops = {
 
 static void wpf_set_memory(struct vsp1_rwpf *wpf)
 {
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->buf_addr[0]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->buf_addr[1]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->buf_addr[2]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
 static const struct vsp1_rwpf_operations wpf_vdev_ops = {
@@ -200,13 +200,11 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the display list manager if the WPF is used for display */
-	if ((vsp1->info->features & VSP1_HAS_LIF) && index == 0) {
-		wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
-		if (!wpf->dlm) {
-			ret = -ENOMEM;
-			goto error;
-		}
+	/* Initialize the display list manager. */
+	wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
+	if (!wpf->dlm) {
+		ret = -ENOMEM;
+		goto error;
 	}
 
 	/* Initialize the V4L2 subdev. */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 17/48] v4l: vsp1: Move subdev initialization code to vsp1_entity_init()
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Don't duplicate the code in every module driver, centralize it in a
single place.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 18 ++----------------
 drivers/media/platform/vsp1/vsp1_entity.c | 30 +++++++++++++++++++++++++-----
 drivers/media/platform/vsp1/vsp1_entity.h |  5 ++---
 drivers/media/platform/vsp1/vsp1_hsit.c   | 17 ++---------------
 drivers/media/platform/vsp1/vsp1_lif.c    | 16 +---------------
 drivers/media/platform/vsp1/vsp1_lut.c    | 16 +---------------
 drivers/media/platform/vsp1/vsp1_rpf.c    | 18 +++---------------
 drivers/media/platform/vsp1/vsp1_sru.c    | 16 +---------------
 drivers/media/platform/vsp1/vsp1_uds.c    | 18 +++---------------
 drivers/media/platform/vsp1/vsp1_wpf.c    | 18 +++---------------
 10 files changed, 43 insertions(+), 129 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 6a6e9d84f1ca..2ca80d3dda1f 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -405,7 +405,6 @@ static struct v4l2_subdev_ops bru_ops = {
 
 struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_bru *bru;
 	int ret;
 
@@ -415,24 +414,11 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 
 	bru->entity.type = VSP1_ENTITY_BRU;
 
-	ret = vsp1_entity_init(vsp1, &bru->entity,
-			       vsp1->info->num_bru_inputs + 1);
+	ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
+			       vsp1->info->num_bru_inputs + 1, &bru_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &bru->entity.subdev;
-	v4l2_subdev_init(subdev, &bru_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s bru",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, bru);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	v4l2_ctrl_handler_init(&bru->ctrls, 1);
 	v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR,
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index dfa0735e36f4..602e2a7a155e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -70,8 +70,8 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
  * formats are initialized on the file handle. Otherwise active formats are
  * initialized on the device.
  */
-void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg)
+static void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_pad_config *cfg)
 {
 	struct v4l2_subdev_format format;
 	unsigned int pad;
@@ -159,9 +159,12 @@ static const struct vsp1_route vsp1_routes[] = {
 };
 
 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
-		     unsigned int num_pads)
+		     const char *name, unsigned int num_pads,
+		     const struct v4l2_subdev_ops *ops)
 {
+	struct v4l2_subdev *subdev;
 	unsigned int i;
+	int ret;
 
 	for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
 		if (vsp1_routes[i].type = entity->type &&
@@ -196,8 +199,25 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
 
 	/* Initialize the media entity. */
-	return media_entity_init(&entity->subdev.entity, num_pads,
-				 entity->pads, 0);
+	ret = media_entity_init(&entity->subdev.entity, num_pads,
+				entity->pads, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Initialize the V4L2 subdev. */
+	subdev = &entity->subdev;
+	v4l2_subdev_init(subdev, ops);
+
+	subdev->entity.ops = &vsp1->media_ops;
+	subdev->internal_ops = &vsp1_subdev_internal_ops;
+	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
+		 dev_name(vsp1->dev), name);
+
+	vsp1_entity_init_formats(subdev, NULL);
+
+	return 0;
 }
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 203872164f8e..d76090059ced 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -81,7 +81,8 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
 }
 
 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
-		     unsigned int num_pads);
+		     const char *name, unsigned int num_pads,
+		     const struct v4l2_subdev_ops *ops);
 void vsp1_entity_destroy(struct vsp1_entity *entity);
 
 extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
@@ -94,8 +95,6 @@ struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, u32 which);
-void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-			      struct v4l2_subdev_pad_config *cfg);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index e820fe0b4f00..49ff74b51e03 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -180,7 +180,6 @@ static struct v4l2_subdev_ops hsit_ops = {
 
 struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_hsit *hsit;
 	int ret;
 
@@ -195,22 +194,10 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 	else
 		hsit->entity.type = VSP1_ENTITY_HST;
 
-	ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
+	ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2,
+			       &hsit_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &hsit->entity.subdev;
-	v4l2_subdev_init(subdev, &hsit_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
-		 dev_name(vsp1->dev), inverse ? "hsi" : "hst");
-	v4l2_set_subdevdata(subdev, hsit);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return hsit;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index be0ea166016c..ead6cc3aa3fa 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -207,7 +207,6 @@ static struct v4l2_subdev_ops lif_ops = {
 
 struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_lif *lif;
 	int ret;
 
@@ -217,22 +216,9 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 
 	lif->entity.type = VSP1_ENTITY_LIF;
 
-	ret = vsp1_entity_init(vsp1, &lif->entity, 2);
+	ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &lif->entity.subdev;
-	v4l2_subdev_init(subdev, &lif_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s lif",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, lif);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return lif;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 3af849dbee5a..6ba6a58fbac6 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -221,7 +221,6 @@ static struct v4l2_subdev_ops lut_ops = {
 
 struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_lut *lut;
 	int ret;
 
@@ -231,22 +230,9 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 
 	lut->entity.type = VSP1_ENTITY_LUT;
 
-	ret = vsp1_entity_init(vsp1, &lut->entity, 2);
+	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &lut->entity.subdev;
-	v4l2_subdev_init(subdev, &lut_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s lut",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, lut);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return lut;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 09919db7e0ea..8d9e511fd61a 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -164,8 +164,8 @@ static const struct vsp1_rwpf_operations rpf_vdev_ops = {
 
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_rwpf *rpf;
+	char name[6];
 	int ret;
 
 	rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
@@ -180,23 +180,11 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 	rpf->entity.type = VSP1_ENTITY_RPF;
 	rpf->entity.index = index;
 
-	ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
+	sprintf(name, "rpf.%u", index);
+	ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &rpf->entity.subdev;
-	v4l2_subdev_init(subdev, &rpf_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u",
-		 dev_name(vsp1->dev), index);
-	v4l2_set_subdevdata(subdev, rpf);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	ret = vsp1_rwpf_init_ctrls(rpf);
 	if (ret < 0) {
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 19b7923cb137..c8642bf8b1a1 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -324,7 +324,6 @@ static struct v4l2_subdev_ops sru_ops = {
 
 struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_sru *sru;
 	int ret;
 
@@ -334,23 +333,10 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 
 	sru->entity.type = VSP1_ENTITY_SRU;
 
-	ret = vsp1_entity_init(vsp1, &sru->entity, 2);
+	ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &sru->entity.subdev;
-	v4l2_subdev_init(subdev, &sru_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s sru",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, sru);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	v4l2_ctrl_handler_init(&sru->ctrls, 1);
 	v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 83ec8942f8e7..34689adda810 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -322,8 +322,8 @@ static struct v4l2_subdev_ops uds_ops = {
 
 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_uds *uds;
+	char name[6];
 	int ret;
 
 	uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL);
@@ -333,22 +333,10 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 	uds->entity.type = VSP1_ENTITY_UDS;
 	uds->entity.index = index;
 
-	ret = vsp1_entity_init(vsp1, &uds->entity, 2);
+	sprintf(name, "uds.%u", index);
+	ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &uds->entity.subdev;
-	v4l2_subdev_init(subdev, &uds_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u",
-		 dev_name(vsp1->dev), index);
-	v4l2_set_subdevdata(subdev, uds);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return uds;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d889997b7948..b81595eb51dc 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -179,8 +179,8 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_rwpf *wpf;
+	char name[6];
 	int ret;
 
 	wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
@@ -196,7 +196,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	wpf->entity.type = VSP1_ENTITY_WPF;
 	wpf->entity.index = index;
 
-	ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
+	sprintf(name, "wpf.%u", index);
+	ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
@@ -207,19 +208,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 		goto error;
 	}
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &wpf->entity.subdev;
-	v4l2_subdev_init(subdev, &wpf_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u",
-		 dev_name(vsp1->dev), index);
-	v4l2_set_subdevdata(subdev, wpf);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	ret = vsp1_rwpf_init_ctrls(wpf);
 	if (ret < 0) {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 17/48] v4l: vsp1: Move subdev initialization code to vsp1_entity_init()
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Don't duplicate the code in every module driver, centralize it in a
single place.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 18 ++----------------
 drivers/media/platform/vsp1/vsp1_entity.c | 30 +++++++++++++++++++++++++-----
 drivers/media/platform/vsp1/vsp1_entity.h |  5 ++---
 drivers/media/platform/vsp1/vsp1_hsit.c   | 17 ++---------------
 drivers/media/platform/vsp1/vsp1_lif.c    | 16 +---------------
 drivers/media/platform/vsp1/vsp1_lut.c    | 16 +---------------
 drivers/media/platform/vsp1/vsp1_rpf.c    | 18 +++---------------
 drivers/media/platform/vsp1/vsp1_sru.c    | 16 +---------------
 drivers/media/platform/vsp1/vsp1_uds.c    | 18 +++---------------
 drivers/media/platform/vsp1/vsp1_wpf.c    | 18 +++---------------
 10 files changed, 43 insertions(+), 129 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 6a6e9d84f1ca..2ca80d3dda1f 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -405,7 +405,6 @@ static struct v4l2_subdev_ops bru_ops = {
 
 struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_bru *bru;
 	int ret;
 
@@ -415,24 +414,11 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 
 	bru->entity.type = VSP1_ENTITY_BRU;
 
-	ret = vsp1_entity_init(vsp1, &bru->entity,
-			       vsp1->info->num_bru_inputs + 1);
+	ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
+			       vsp1->info->num_bru_inputs + 1, &bru_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &bru->entity.subdev;
-	v4l2_subdev_init(subdev, &bru_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s bru",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, bru);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	v4l2_ctrl_handler_init(&bru->ctrls, 1);
 	v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR,
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index dfa0735e36f4..602e2a7a155e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -70,8 +70,8 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
  * formats are initialized on the file handle. Otherwise active formats are
  * initialized on the device.
  */
-void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg)
+static void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_pad_config *cfg)
 {
 	struct v4l2_subdev_format format;
 	unsigned int pad;
@@ -159,9 +159,12 @@ static const struct vsp1_route vsp1_routes[] = {
 };
 
 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
-		     unsigned int num_pads)
+		     const char *name, unsigned int num_pads,
+		     const struct v4l2_subdev_ops *ops)
 {
+	struct v4l2_subdev *subdev;
 	unsigned int i;
+	int ret;
 
 	for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
 		if (vsp1_routes[i].type == entity->type &&
@@ -196,8 +199,25 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
 
 	/* Initialize the media entity. */
-	return media_entity_init(&entity->subdev.entity, num_pads,
-				 entity->pads, 0);
+	ret = media_entity_init(&entity->subdev.entity, num_pads,
+				entity->pads, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Initialize the V4L2 subdev. */
+	subdev = &entity->subdev;
+	v4l2_subdev_init(subdev, ops);
+
+	subdev->entity.ops = &vsp1->media_ops;
+	subdev->internal_ops = &vsp1_subdev_internal_ops;
+	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
+		 dev_name(vsp1->dev), name);
+
+	vsp1_entity_init_formats(subdev, NULL);
+
+	return 0;
 }
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 203872164f8e..d76090059ced 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -81,7 +81,8 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
 }
 
 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
-		     unsigned int num_pads);
+		     const char *name, unsigned int num_pads,
+		     const struct v4l2_subdev_ops *ops);
 void vsp1_entity_destroy(struct vsp1_entity *entity);
 
 extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops;
@@ -94,8 +95,6 @@ struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, u32 which);
-void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-			      struct v4l2_subdev_pad_config *cfg);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index e820fe0b4f00..49ff74b51e03 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -180,7 +180,6 @@ static struct v4l2_subdev_ops hsit_ops = {
 
 struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_hsit *hsit;
 	int ret;
 
@@ -195,22 +194,10 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 	else
 		hsit->entity.type = VSP1_ENTITY_HST;
 
-	ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
+	ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2,
+			       &hsit_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &hsit->entity.subdev;
-	v4l2_subdev_init(subdev, &hsit_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
-		 dev_name(vsp1->dev), inverse ? "hsi" : "hst");
-	v4l2_set_subdevdata(subdev, hsit);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return hsit;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index be0ea166016c..ead6cc3aa3fa 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -207,7 +207,6 @@ static struct v4l2_subdev_ops lif_ops = {
 
 struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_lif *lif;
 	int ret;
 
@@ -217,22 +216,9 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 
 	lif->entity.type = VSP1_ENTITY_LIF;
 
-	ret = vsp1_entity_init(vsp1, &lif->entity, 2);
+	ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &lif->entity.subdev;
-	v4l2_subdev_init(subdev, &lif_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s lif",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, lif);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return lif;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 3af849dbee5a..6ba6a58fbac6 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -221,7 +221,6 @@ static struct v4l2_subdev_ops lut_ops = {
 
 struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_lut *lut;
 	int ret;
 
@@ -231,22 +230,9 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 
 	lut->entity.type = VSP1_ENTITY_LUT;
 
-	ret = vsp1_entity_init(vsp1, &lut->entity, 2);
+	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &lut->entity.subdev;
-	v4l2_subdev_init(subdev, &lut_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s lut",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, lut);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return lut;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 09919db7e0ea..8d9e511fd61a 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -164,8 +164,8 @@ static const struct vsp1_rwpf_operations rpf_vdev_ops = {
 
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_rwpf *rpf;
+	char name[6];
 	int ret;
 
 	rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
@@ -180,23 +180,11 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 	rpf->entity.type = VSP1_ENTITY_RPF;
 	rpf->entity.index = index;
 
-	ret = vsp1_entity_init(vsp1, &rpf->entity, 2);
+	sprintf(name, "rpf.%u", index);
+	ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &rpf->entity.subdev;
-	v4l2_subdev_init(subdev, &rpf_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s rpf.%u",
-		 dev_name(vsp1->dev), index);
-	v4l2_set_subdevdata(subdev, rpf);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	ret = vsp1_rwpf_init_ctrls(rpf);
 	if (ret < 0) {
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 19b7923cb137..c8642bf8b1a1 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -324,7 +324,6 @@ static struct v4l2_subdev_ops sru_ops = {
 
 struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_sru *sru;
 	int ret;
 
@@ -334,23 +333,10 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 
 	sru->entity.type = VSP1_ENTITY_SRU;
 
-	ret = vsp1_entity_init(vsp1, &sru->entity, 2);
+	ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &sru->entity.subdev;
-	v4l2_subdev_init(subdev, &sru_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s sru",
-		 dev_name(vsp1->dev));
-	v4l2_set_subdevdata(subdev, sru);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	v4l2_ctrl_handler_init(&sru->ctrls, 1);
 	v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 83ec8942f8e7..34689adda810 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -322,8 +322,8 @@ static struct v4l2_subdev_ops uds_ops = {
 
 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_uds *uds;
+	char name[6];
 	int ret;
 
 	uds = devm_kzalloc(vsp1->dev, sizeof(*uds), GFP_KERNEL);
@@ -333,22 +333,10 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 	uds->entity.type = VSP1_ENTITY_UDS;
 	uds->entity.index = index;
 
-	ret = vsp1_entity_init(vsp1, &uds->entity, 2);
+	sprintf(name, "uds.%u", index);
+	ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &uds->entity.subdev;
-	v4l2_subdev_init(subdev, &uds_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s uds.%u",
-		 dev_name(vsp1->dev), index);
-	v4l2_set_subdevdata(subdev, uds);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	return uds;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d889997b7948..b81595eb51dc 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -179,8 +179,8 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
-	struct v4l2_subdev *subdev;
 	struct vsp1_rwpf *wpf;
+	char name[6];
 	int ret;
 
 	wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL);
@@ -196,7 +196,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	wpf->entity.type = VSP1_ENTITY_WPF;
 	wpf->entity.index = index;
 
-	ret = vsp1_entity_init(vsp1, &wpf->entity, 2);
+	sprintf(name, "wpf.%u", index);
+	ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
@@ -207,19 +208,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 		goto error;
 	}
 
-	/* Initialize the V4L2 subdev. */
-	subdev = &wpf->entity.subdev;
-	v4l2_subdev_init(subdev, &wpf_ops);
-
-	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
-	snprintf(subdev->name, sizeof(subdev->name), "%s wpf.%u",
-		 dev_name(vsp1->dev), index);
-	v4l2_set_subdevdata(subdev, wpf);
-	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-	vsp1_entity_init_formats(subdev, NULL);
-
 	/* Initialize the control handler. */
 	ret = vsp1_rwpf_init_ctrls(wpf);
 	if (ret < 0) {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 18/48] v4l: vsp1: Consolidate entity ops in a struct vsp1_entity_operations
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Entities have two operations, a destroy operation stored directly in
vsp1_entity and a set_memory operation stored in a vsp1_rwpf_operations
structure. Move the two to a more generic vsp1_entity_operations
structure that will serve to implement additional operations.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_entity.c |  4 ++--
 drivers/media/platform/vsp1/vsp1_entity.h | 14 +++++++++++++-
 drivers/media/platform/vsp1/vsp1_rpf.c    | 11 ++++++-----
 drivers/media/platform/vsp1/vsp1_rwpf.h   | 18 ++++++------------
 drivers/media/platform/vsp1/vsp1_wpf.c    | 27 ++++++++++++++-------------
 5 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 602e2a7a155e..caf8e413adeb 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -222,8 +222,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
 {
-	if (entity->destroy)
-		entity->destroy(entity);
+	if (entity->ops && entity->ops->destroy)
+		entity->ops->destroy(entity);
 	if (entity->subdev.ctrl_handler)
 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
 	media_entity_cleanup(&entity->subdev.entity);
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index d76090059ced..0fdda82a8d9a 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -53,10 +53,22 @@ struct vsp1_route {
 	unsigned int inputs[VSP1_ENTITY_MAX_INPUTS];
 };
 
+/**
+ * struct vsp1_entity_operations - Entity operations
+ * @destroy:	Destroy the entity.
+ * @set_memory:	Setup memory buffer access. This operation applies the settings
+ *		stored in the rwpf mem field to the hardware. Valid for RPF and
+ *		WPF only.
+ */
+struct vsp1_entity_operations {
+	void (*destroy)(struct vsp1_entity *);
+	void (*set_memory)(struct vsp1_entity *);
+};
+
 struct vsp1_entity {
 	struct vsp1_device *vsp1;
 
-	void (*destroy)(struct vsp1_entity *);
+	const struct vsp1_entity_operations *ops;
 
 	enum vsp1_entity_type type;
 	unsigned int index;
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 8d9e511fd61a..a68f26db9b3f 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -141,11 +141,13 @@ static struct v4l2_subdev_ops rpf_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * Video Device Operations
+ * VSP1 Entity Operations
  */
 
-static void rpf_set_memory(struct vsp1_rwpf *rpf)
+static void rpf_set_memory(struct vsp1_entity *entity)
 {
+	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
+
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
 		       rpf->mem.addr[0] + rpf->offsets[0]);
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
@@ -154,7 +156,7 @@ static void rpf_set_memory(struct vsp1_rwpf *rpf)
 		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
-static const struct vsp1_rwpf_operations rpf_vdev_ops = {
+static const struct vsp1_entity_operations rpf_entity_ops = {
 	.set_memory = rpf_set_memory,
 };
 
@@ -172,11 +174,10 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (rpf = NULL)
 		return ERR_PTR(-ENOMEM);
 
-	rpf->ops = &rpf_vdev_ops;
-
 	rpf->max_width = RPF_MAX_WIDTH;
 	rpf->max_height = RPF_MAX_HEIGHT;
 
+	rpf->entity.ops = &rpf_entity_ops;
 	rpf->entity.type = VSP1_ENTITY_RPF;
 	rpf->entity.index = index;
 
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 2bbcc331959b..e8ca9b6ee689 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -32,23 +32,12 @@ struct vsp1_rwpf_memory {
 	dma_addr_t addr[3];
 };
 
-/**
- * struct vsp1_rwpf_operations - RPF and WPF operations
- * @set_memory: Setup memory buffer access. This operation applies the settings
- *		stored in the rwpf mem field to the hardware.
- */
-struct vsp1_rwpf_operations {
-	void (*set_memory)(struct vsp1_rwpf *rwpf);
-};
-
 struct vsp1_rwpf {
 	struct vsp1_entity entity;
 	struct v4l2_ctrl_handler ctrls;
 
 	struct vsp1_video *video;
 
-	const struct vsp1_rwpf_operations *ops;
-
 	unsigned int max_width;
 	unsigned int max_height;
 
@@ -73,6 +62,11 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
 	return container_of(subdev, struct vsp1_rwpf, entity.subdev);
 }
 
+static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity)
+{
+	return container_of(entity, struct vsp1_rwpf, entity);
+}
+
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
@@ -105,7 +99,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
  */
 static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf)
 {
-	rwpf->ops->set_memory(rwpf);
+	rwpf->entity.ops->set_memory(&rwpf->entity);
 }
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index b81595eb51dc..84772fa258a5 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -152,17 +152,27 @@ static struct v4l2_subdev_ops wpf_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * Video Device Operations
+ * VSP1 Entity Operations
  */
 
-static void wpf_set_memory(struct vsp1_rwpf *wpf)
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 {
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
+	vsp1_dlm_destroy(wpf->dlm);
+}
+
+static void wpf_set_memory(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
-static const struct vsp1_rwpf_operations wpf_vdev_ops = {
+static const struct vsp1_entity_operations wpf_entity_ops = {
+	.destroy = vsp1_wpf_destroy,
 	.set_memory = wpf_set_memory,
 };
 
@@ -170,13 +180,6 @@ static const struct vsp1_rwpf_operations wpf_vdev_ops = {
  * Initialization and Cleanup
  */
 
-static void vsp1_wpf_destroy(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *wpf = container_of(entity, struct vsp1_rwpf, entity);
-
-	vsp1_dlm_destroy(wpf->dlm);
-}
-
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
 	struct vsp1_rwpf *wpf;
@@ -187,12 +190,10 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (wpf = NULL)
 		return ERR_PTR(-ENOMEM);
 
-	wpf->ops = &wpf_vdev_ops;
-
 	wpf->max_width = WPF_MAX_WIDTH;
 	wpf->max_height = WPF_MAX_HEIGHT;
 
-	wpf->entity.destroy = vsp1_wpf_destroy;
+	wpf->entity.ops = &wpf_entity_ops;
 	wpf->entity.type = VSP1_ENTITY_WPF;
 	wpf->entity.index = index;
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 18/48] v4l: vsp1: Consolidate entity ops in a struct vsp1_entity_operations
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Entities have two operations, a destroy operation stored directly in
vsp1_entity and a set_memory operation stored in a vsp1_rwpf_operations
structure. Move the two to a more generic vsp1_entity_operations
structure that will serve to implement additional operations.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_entity.c |  4 ++--
 drivers/media/platform/vsp1/vsp1_entity.h | 14 +++++++++++++-
 drivers/media/platform/vsp1/vsp1_rpf.c    | 11 ++++++-----
 drivers/media/platform/vsp1/vsp1_rwpf.h   | 18 ++++++------------
 drivers/media/platform/vsp1/vsp1_wpf.c    | 27 ++++++++++++++-------------
 5 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 602e2a7a155e..caf8e413adeb 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -222,8 +222,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
 {
-	if (entity->destroy)
-		entity->destroy(entity);
+	if (entity->ops && entity->ops->destroy)
+		entity->ops->destroy(entity);
 	if (entity->subdev.ctrl_handler)
 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
 	media_entity_cleanup(&entity->subdev.entity);
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index d76090059ced..0fdda82a8d9a 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -53,10 +53,22 @@ struct vsp1_route {
 	unsigned int inputs[VSP1_ENTITY_MAX_INPUTS];
 };
 
+/**
+ * struct vsp1_entity_operations - Entity operations
+ * @destroy:	Destroy the entity.
+ * @set_memory:	Setup memory buffer access. This operation applies the settings
+ *		stored in the rwpf mem field to the hardware. Valid for RPF and
+ *		WPF only.
+ */
+struct vsp1_entity_operations {
+	void (*destroy)(struct vsp1_entity *);
+	void (*set_memory)(struct vsp1_entity *);
+};
+
 struct vsp1_entity {
 	struct vsp1_device *vsp1;
 
-	void (*destroy)(struct vsp1_entity *);
+	const struct vsp1_entity_operations *ops;
 
 	enum vsp1_entity_type type;
 	unsigned int index;
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 8d9e511fd61a..a68f26db9b3f 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -141,11 +141,13 @@ static struct v4l2_subdev_ops rpf_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * Video Device Operations
+ * VSP1 Entity Operations
  */
 
-static void rpf_set_memory(struct vsp1_rwpf *rpf)
+static void rpf_set_memory(struct vsp1_entity *entity)
 {
+	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
+
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
 		       rpf->mem.addr[0] + rpf->offsets[0]);
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
@@ -154,7 +156,7 @@ static void rpf_set_memory(struct vsp1_rwpf *rpf)
 		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
-static const struct vsp1_rwpf_operations rpf_vdev_ops = {
+static const struct vsp1_entity_operations rpf_entity_ops = {
 	.set_memory = rpf_set_memory,
 };
 
@@ -172,11 +174,10 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (rpf == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	rpf->ops = &rpf_vdev_ops;
-
 	rpf->max_width = RPF_MAX_WIDTH;
 	rpf->max_height = RPF_MAX_HEIGHT;
 
+	rpf->entity.ops = &rpf_entity_ops;
 	rpf->entity.type = VSP1_ENTITY_RPF;
 	rpf->entity.index = index;
 
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 2bbcc331959b..e8ca9b6ee689 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -32,23 +32,12 @@ struct vsp1_rwpf_memory {
 	dma_addr_t addr[3];
 };
 
-/**
- * struct vsp1_rwpf_operations - RPF and WPF operations
- * @set_memory: Setup memory buffer access. This operation applies the settings
- *		stored in the rwpf mem field to the hardware.
- */
-struct vsp1_rwpf_operations {
-	void (*set_memory)(struct vsp1_rwpf *rwpf);
-};
-
 struct vsp1_rwpf {
 	struct vsp1_entity entity;
 	struct v4l2_ctrl_handler ctrls;
 
 	struct vsp1_video *video;
 
-	const struct vsp1_rwpf_operations *ops;
-
 	unsigned int max_width;
 	unsigned int max_height;
 
@@ -73,6 +62,11 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
 	return container_of(subdev, struct vsp1_rwpf, entity.subdev);
 }
 
+static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity)
+{
+	return container_of(entity, struct vsp1_rwpf, entity);
+}
+
 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index);
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
@@ -105,7 +99,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
  */
 static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf)
 {
-	rwpf->ops->set_memory(rwpf);
+	rwpf->entity.ops->set_memory(&rwpf->entity);
 }
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index b81595eb51dc..84772fa258a5 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -152,17 +152,27 @@ static struct v4l2_subdev_ops wpf_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * Video Device Operations
+ * VSP1 Entity Operations
  */
 
-static void wpf_set_memory(struct vsp1_rwpf *wpf)
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 {
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
+	vsp1_dlm_destroy(wpf->dlm);
+}
+
+static void wpf_set_memory(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
-static const struct vsp1_rwpf_operations wpf_vdev_ops = {
+static const struct vsp1_entity_operations wpf_entity_ops = {
+	.destroy = vsp1_wpf_destroy,
 	.set_memory = wpf_set_memory,
 };
 
@@ -170,13 +180,6 @@ static const struct vsp1_rwpf_operations wpf_vdev_ops = {
  * Initialization and Cleanup
  */
 
-static void vsp1_wpf_destroy(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *wpf = container_of(entity, struct vsp1_rwpf, entity);
-
-	vsp1_dlm_destroy(wpf->dlm);
-}
-
 struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 {
 	struct vsp1_rwpf *wpf;
@@ -187,12 +190,10 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
 	if (wpf == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	wpf->ops = &wpf_vdev_ops;
-
 	wpf->max_width = WPF_MAX_WIDTH;
 	wpf->max_height = WPF_MAX_HEIGHT;
 
-	wpf->entity.destroy = vsp1_wpf_destroy;
+	wpf->entity.ops = &wpf_entity_ops;
 	wpf->entity.type = VSP1_ENTITY_WPF;
 	wpf->entity.index = index;
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 19/48] v4l: vsp1: Fix BRU try compose rectangle storage
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Fix a typo that stored the try compose rectangle in the crop rectangle.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 2ca80d3dda1f..d8b7bdeb5af5 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -228,7 +228,8 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
 {
 	switch (which) {
 	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad);
+		return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg,
+						   pad);
 	case V4L2_SUBDEV_FORMAT_ACTIVE:
 		return &bru->inputs[pad].compose;
 	default:
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 19/48] v4l: vsp1: Fix BRU try compose rectangle storage
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Fix a typo that stored the try compose rectangle in the crop rectangle.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 2ca80d3dda1f..d8b7bdeb5af5 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -228,7 +228,8 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
 {
 	switch (which) {
 	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad);
+		return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg,
+						   pad);
 	case V4L2_SUBDEV_FORMAT_ACTIVE:
 		return &bru->inputs[pad].compose;
 	default:
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 20/48] v4l: vsp1: Add race condition FIXME comment
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 50fc91a2f509..ec1394289659 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -821,6 +821,9 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	 *
 	 * Use the VSP1 pipeline object embedded in the first video object that
 	 * starts streaming.
+	 *
+	 * FIXME: This is racy, the ioctl is only protected by the video node
+	 * lock.
 	 */
 	pipe = video->video.entity.pipe
 	     ? to_vsp1_pipeline(&video->video.entity) : &video->pipe;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 20/48] v4l: vsp1: Add race condition FIXME comment
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 50fc91a2f509..ec1394289659 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -821,6 +821,9 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 	 *
 	 * Use the VSP1 pipeline object embedded in the first video object that
 	 * starts streaming.
+	 *
+	 * FIXME: This is racy, the ioctl is only protected by the video node
+	 * lock.
 	 */
 	pipe = video->video.entity.pipe
 	     ? to_vsp1_pipeline(&video->video.entity) : &video->pipe;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 21/48] media: Move media_device link_notify operation to an ops structure
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:39   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

This will allow adding new operations without increasing the
media_device structure size for drivers that don't implement any media
device operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/media-entity.c                  | 11 ++++++-----
 drivers/media/platform/exynos4-is/media-dev.c |  6 +++++-
 drivers/media/platform/omap3isp/isp.c         |  6 +++++-
 drivers/staging/media/omap4iss/iss.c          |  6 +++++-
 include/media/media-device.h                  | 14 +++++++++++---
 5 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 767fe55ba08e..1e1c08c0c947 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -592,17 +592,18 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
 
 	mdev = source->parent;
 
-	if (mdev->link_notify) {
-		ret = mdev->link_notify(link, flags,
-					MEDIA_DEV_NOTIFY_PRE_LINK_CH);
+	if (mdev->ops && mdev->ops->link_notify) {
+		ret = mdev->ops->link_notify(link, flags,
+					     MEDIA_DEV_NOTIFY_PRE_LINK_CH);
 		if (ret < 0)
 			return ret;
 	}
 
 	ret = __media_entity_setup_link_notify(link, flags);
 
-	if (mdev->link_notify)
-		mdev->link_notify(link, flags, MEDIA_DEV_NOTIFY_POST_LINK_CH);
+	if (mdev->ops && mdev->ops->link_notify)
+		mdev->ops->link_notify(link, flags,
+				       MEDIA_DEV_NOTIFY_POST_LINK_CH);
 
 	return ret;
 }
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 9481ce3201a2..091f5930e424 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1111,6 +1111,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
 	return ret ? -EPIPE : 0;
 }
 
+static const struct media_device_ops fimc_md_ops = {
+	.link_notify = fimc_md_link_notify,
+};
+
 static ssize_t fimc_md_sysfs_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -1334,7 +1338,7 @@ static int fimc_md_probe(struct platform_device *pdev)
 
 	strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
 		sizeof(fmd->media_dev.model));
-	fmd->media_dev.link_notify = fimc_md_link_notify;
+	fmd->media_dev.ops = &fimc_md_ops;
 	fmd->media_dev.dev = dev;
 
 	v4l2_dev = &fmd->v4l2_dev;
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 56e683b19a73..a35c292955e7 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -851,6 +851,10 @@ static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
 	return 0;
 }
 
+static const struct media_device_ops isp_media_ops {
+	.link_notify = isp_pipeline_link_notify,
+};
+
 /* -----------------------------------------------------------------------------
  * Pipeline stream management
  */
@@ -1873,7 +1877,7 @@ static int isp_register_entities(struct isp_device *isp)
 	strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
 		sizeof(isp->media_dev.model));
 	isp->media_dev.hw_revision = isp->revision;
-	isp->media_dev.link_notify = isp_pipeline_link_notify;
+	isp->media_dev.ops = &isp_media_ops;
 	ret = media_device_register(&isp->media_dev);
 	if (ret < 0) {
 		dev_err(isp->dev, "%s: Media device registration failed (%d)\n",
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index e27a988540a6..dbff493c6a25 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -556,6 +556,10 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
 	return 0;
 }
 
+static const struct media_device_ops iss_media_ops = {
+	.link_notify = iss_pipeline_link_notify,
+};
+
 /* -----------------------------------------------------------------------------
  * Pipeline stream management
  */
@@ -1183,7 +1187,7 @@ static int iss_register_entities(struct iss_device *iss)
 	strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
 		sizeof(iss->media_dev.model));
 	iss->media_dev.hw_revision = iss->revision;
-	iss->media_dev.link_notify = iss_pipeline_link_notify;
+	iss->media_dev.ops = &iss_media_ops;
 	ret = media_device_register(&iss->media_dev);
 	if (ret < 0) {
 		dev_err(iss->dev, "Media device registration failed (%d)\n",
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 6e6db78f1ee2..7e6de4dbf497 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -33,6 +33,15 @@
 struct device;
 
 /**
+ * struct media_device_ops - Media device operations
+ * @link_notify: Link state change notification callback
+ */
+struct media_device_ops {
+	int (*link_notify)(struct media_link *link, u32 flags,
+			   unsigned int notification);
+};
+
+/**
  * struct media_device - Media device
  * @dev:	Parent device
  * @devnode:	Media device node
@@ -45,7 +54,7 @@ struct device;
  * @entities:	List of registered entities
  * @lock:	Entities list lock
  * @graph_mutex: Entities graph operation lock
- * @link_notify: Link state change notification callback
+ * @ops:	Operation handler callbacks
  *
  * This structure represents an abstract high-level media device. It allows easy
  * access to entities and provides basic media device-level support. The
@@ -76,8 +85,7 @@ struct media_device {
 	/* Serializes graph operations. */
 	struct mutex graph_mutex;
 
-	int (*link_notify)(struct media_link *link, u32 flags,
-			   unsigned int notification);
+	const struct media_device_ops *ops;
 };
 
 /* Supported link_notify @notification values. */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 21/48] media: Move media_device link_notify operation to an ops structure
@ 2015-12-17  8:39   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:39 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

This will allow adding new operations without increasing the
media_device structure size for drivers that don't implement any media
device operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/media-entity.c                  | 11 ++++++-----
 drivers/media/platform/exynos4-is/media-dev.c |  6 +++++-
 drivers/media/platform/omap3isp/isp.c         |  6 +++++-
 drivers/staging/media/omap4iss/iss.c          |  6 +++++-
 include/media/media-device.h                  | 14 +++++++++++---
 5 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 767fe55ba08e..1e1c08c0c947 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -592,17 +592,18 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
 
 	mdev = source->parent;
 
-	if (mdev->link_notify) {
-		ret = mdev->link_notify(link, flags,
-					MEDIA_DEV_NOTIFY_PRE_LINK_CH);
+	if (mdev->ops && mdev->ops->link_notify) {
+		ret = mdev->ops->link_notify(link, flags,
+					     MEDIA_DEV_NOTIFY_PRE_LINK_CH);
 		if (ret < 0)
 			return ret;
 	}
 
 	ret = __media_entity_setup_link_notify(link, flags);
 
-	if (mdev->link_notify)
-		mdev->link_notify(link, flags, MEDIA_DEV_NOTIFY_POST_LINK_CH);
+	if (mdev->ops && mdev->ops->link_notify)
+		mdev->ops->link_notify(link, flags,
+				       MEDIA_DEV_NOTIFY_POST_LINK_CH);
 
 	return ret;
 }
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 9481ce3201a2..091f5930e424 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1111,6 +1111,10 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
 	return ret ? -EPIPE : 0;
 }
 
+static const struct media_device_ops fimc_md_ops = {
+	.link_notify = fimc_md_link_notify,
+};
+
 static ssize_t fimc_md_sysfs_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -1334,7 +1338,7 @@ static int fimc_md_probe(struct platform_device *pdev)
 
 	strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
 		sizeof(fmd->media_dev.model));
-	fmd->media_dev.link_notify = fimc_md_link_notify;
+	fmd->media_dev.ops = &fimc_md_ops;
 	fmd->media_dev.dev = dev;
 
 	v4l2_dev = &fmd->v4l2_dev;
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 56e683b19a73..a35c292955e7 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -851,6 +851,10 @@ static int isp_pipeline_link_notify(struct media_link *link, u32 flags,
 	return 0;
 }
 
+static const struct media_device_ops isp_media_ops {
+	.link_notify = isp_pipeline_link_notify,
+};
+
 /* -----------------------------------------------------------------------------
  * Pipeline stream management
  */
@@ -1873,7 +1877,7 @@ static int isp_register_entities(struct isp_device *isp)
 	strlcpy(isp->media_dev.model, "TI OMAP3 ISP",
 		sizeof(isp->media_dev.model));
 	isp->media_dev.hw_revision = isp->revision;
-	isp->media_dev.link_notify = isp_pipeline_link_notify;
+	isp->media_dev.ops = &isp_media_ops;
 	ret = media_device_register(&isp->media_dev);
 	if (ret < 0) {
 		dev_err(isp->dev, "%s: Media device registration failed (%d)\n",
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index e27a988540a6..dbff493c6a25 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -556,6 +556,10 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
 	return 0;
 }
 
+static const struct media_device_ops iss_media_ops = {
+	.link_notify = iss_pipeline_link_notify,
+};
+
 /* -----------------------------------------------------------------------------
  * Pipeline stream management
  */
@@ -1183,7 +1187,7 @@ static int iss_register_entities(struct iss_device *iss)
 	strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
 		sizeof(iss->media_dev.model));
 	iss->media_dev.hw_revision = iss->revision;
-	iss->media_dev.link_notify = iss_pipeline_link_notify;
+	iss->media_dev.ops = &iss_media_ops;
 	ret = media_device_register(&iss->media_dev);
 	if (ret < 0) {
 		dev_err(iss->dev, "Media device registration failed (%d)\n",
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 6e6db78f1ee2..7e6de4dbf497 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -33,6 +33,15 @@
 struct device;
 
 /**
+ * struct media_device_ops - Media device operations
+ * @link_notify: Link state change notification callback
+ */
+struct media_device_ops {
+	int (*link_notify)(struct media_link *link, u32 flags,
+			   unsigned int notification);
+};
+
+/**
  * struct media_device - Media device
  * @dev:	Parent device
  * @devnode:	Media device node
@@ -45,7 +54,7 @@ struct device;
  * @entities:	List of registered entities
  * @lock:	Entities list lock
  * @graph_mutex: Entities graph operation lock
- * @link_notify: Link state change notification callback
+ * @ops:	Operation handler callbacks
  *
  * This structure represents an abstract high-level media device. It allows easy
  * access to entities and provides basic media device-level support. The
@@ -76,8 +85,7 @@ struct media_device {
 	/* Serializes graph operations. */
 	struct mutex graph_mutex;
 
-	int (*link_notify)(struct media_link *link, u32 flags,
-			   unsigned int notification);
+	const struct media_device_ops *ops;
 };
 
 /* Supported link_notify @notification values. */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 22/48] media: Add per-file-handle data support
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The media devnode core associates devnodes with files by storing the
devnode pointer in the file structure private_data field. In order to
allow tracking of per-file-handle data introduce a new media devnode
file handle structure that stores the devnode pointer, and store a
pointer to that structure in the file private_data field.

Users of the media devnode code (the only existing user being
media_device) are responsible for managing their own subclass of the
media_devnode_fh structure.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/media-device.c  | 22 ++++++++++++++++++++++
 drivers/media/media-devnode.c | 19 +++++++++----------
 include/media/media-devnode.h | 18 +++++++++++++++++-
 3 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 7b39440192d6..285f7d79d848 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -24,23 +24,45 @@
 #include <linux/export.h>
 #include <linux/ioctl.h>
 #include <linux/media.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 
 #include <media/media-device.h>
 #include <media/media-devnode.h>
 #include <media/media-entity.h>
 
+struct media_device_fh {
+	struct media_devnode_fh fh;
+};
+
+static inline struct media_device_fh *media_device_fh(struct file *filp)
+{
+	return container_of(filp->private_data, struct media_device_fh, fh);
+}
+
 /* -----------------------------------------------------------------------------
  * Userspace API
  */
 
 static int media_device_open(struct file *filp)
 {
+	struct media_device_fh *fh;
+
+	fh = kzalloc(sizeof(*media_device_fh), GFP_KERNEL);
+	if (!fh)
+		return -ENOMEM;
+
+	filp->private_data = &fh->fh;
+
 	return 0;
 }
 
 static int media_device_close(struct file *filp)
 {
+	struct media_device_fh *fh = media_device_fh(filp);
+
+	kfree(fh);
+
 	return 0;
 }
 
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index ebf9626e5ae5..67bac29838d3 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -154,6 +154,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
 /* Override for the open function */
 static int media_open(struct inode *inode, struct file *filp)
 {
+	struct media_devnode_fh *fh;
 	struct media_devnode *mdev;
 	int ret;
 
@@ -175,16 +176,15 @@ static int media_open(struct inode *inode, struct file *filp)
 	get_device(&mdev->dev);
 	mutex_unlock(&media_devnode_lock);
 
-	filp->private_data = mdev;
-
-	if (mdev->fops->open) {
-		ret = mdev->fops->open(filp);
-		if (ret) {
-			put_device(&mdev->dev);
-			return ret;
-		}
+	ret = mdev->fops->open(filp);
+	if (ret) {
+		put_device(&mdev->dev);
+		return ret;
 	}
 
+	fh = filp->private_data;
+	fh->devnode = mdev;
+
 	return 0;
 }
 
@@ -193,8 +193,7 @@ static int media_release(struct inode *inode, struct file *filp)
 {
 	struct media_devnode *mdev = media_devnode_data(filp);
 
-	if (mdev->fops->release)
-		mdev->fops->release(filp);
+	mdev->fops->release(filp);
 
 	/* decrease the refcount unconditionally since the release()
 	   return value is ignored. */
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
index 17ddae32060d..ce81047cb4fc 100644
--- a/include/media/media-devnode.h
+++ b/include/media/media-devnode.h
@@ -52,6 +52,20 @@ struct media_file_operations {
 };
 
 /**
+ * struct media_devnode_fh - Media device node file handle
+ * @devnode:	pointer to the media device node
+ *
+ * This structure serves as a base for per-file-handle data storage. Media
+ * device node users embed media_devnode_fh in their custom file handle data
+ * structures and store the media_devnode_fh in the file private_data in order
+ * to let the media device node core locate the media_devnode corresponding to a
+ * file handle.
+ */
+struct media_devnode_fh {
+	struct media_devnode *devnode;
+};
+
+/**
  * struct media_devnode - Media device node
  * @fops:	pointer to struct media_file_operations with media device ops
  * @dev:	struct device pointer for the media controller device
@@ -92,7 +106,9 @@ void media_devnode_unregister(struct media_devnode *mdev);
 
 static inline struct media_devnode *media_devnode_data(struct file *filp)
 {
-	return filp->private_data;
+	struct media_devnode_fh *fh = filp->private_data;
+
+	return fh->devnode;
 }
 
 static inline int media_devnode_is_registered(struct media_devnode *mdev)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 22/48] media: Add per-file-handle data support
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The media devnode core associates devnodes with files by storing the
devnode pointer in the file structure private_data field. In order to
allow tracking of per-file-handle data introduce a new media devnode
file handle structure that stores the devnode pointer, and store a
pointer to that structure in the file private_data field.

Users of the media devnode code (the only existing user being
media_device) are responsible for managing their own subclass of the
media_devnode_fh structure.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/media-device.c  | 22 ++++++++++++++++++++++
 drivers/media/media-devnode.c | 19 +++++++++----------
 include/media/media-devnode.h | 18 +++++++++++++++++-
 3 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 7b39440192d6..285f7d79d848 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -24,23 +24,45 @@
 #include <linux/export.h>
 #include <linux/ioctl.h>
 #include <linux/media.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 
 #include <media/media-device.h>
 #include <media/media-devnode.h>
 #include <media/media-entity.h>
 
+struct media_device_fh {
+	struct media_devnode_fh fh;
+};
+
+static inline struct media_device_fh *media_device_fh(struct file *filp)
+{
+	return container_of(filp->private_data, struct media_device_fh, fh);
+}
+
 /* -----------------------------------------------------------------------------
  * Userspace API
  */
 
 static int media_device_open(struct file *filp)
 {
+	struct media_device_fh *fh;
+
+	fh = kzalloc(sizeof(*media_device_fh), GFP_KERNEL);
+	if (!fh)
+		return -ENOMEM;
+
+	filp->private_data = &fh->fh;
+
 	return 0;
 }
 
 static int media_device_close(struct file *filp)
 {
+	struct media_device_fh *fh = media_device_fh(filp);
+
+	kfree(fh);
+
 	return 0;
 }
 
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index ebf9626e5ae5..67bac29838d3 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -154,6 +154,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
 /* Override for the open function */
 static int media_open(struct inode *inode, struct file *filp)
 {
+	struct media_devnode_fh *fh;
 	struct media_devnode *mdev;
 	int ret;
 
@@ -175,16 +176,15 @@ static int media_open(struct inode *inode, struct file *filp)
 	get_device(&mdev->dev);
 	mutex_unlock(&media_devnode_lock);
 
-	filp->private_data = mdev;
-
-	if (mdev->fops->open) {
-		ret = mdev->fops->open(filp);
-		if (ret) {
-			put_device(&mdev->dev);
-			return ret;
-		}
+	ret = mdev->fops->open(filp);
+	if (ret) {
+		put_device(&mdev->dev);
+		return ret;
 	}
 
+	fh = filp->private_data;
+	fh->devnode = mdev;
+
 	return 0;
 }
 
@@ -193,8 +193,7 @@ static int media_release(struct inode *inode, struct file *filp)
 {
 	struct media_devnode *mdev = media_devnode_data(filp);
 
-	if (mdev->fops->release)
-		mdev->fops->release(filp);
+	mdev->fops->release(filp);
 
 	/* decrease the refcount unconditionally since the release()
 	   return value is ignored. */
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
index 17ddae32060d..ce81047cb4fc 100644
--- a/include/media/media-devnode.h
+++ b/include/media/media-devnode.h
@@ -52,6 +52,20 @@ struct media_file_operations {
 };
 
 /**
+ * struct media_devnode_fh - Media device node file handle
+ * @devnode:	pointer to the media device node
+ *
+ * This structure serves as a base for per-file-handle data storage. Media
+ * device node users embed media_devnode_fh in their custom file handle data
+ * structures and store the media_devnode_fh in the file private_data in order
+ * to let the media device node core locate the media_devnode corresponding to a
+ * file handle.
+ */
+struct media_devnode_fh {
+	struct media_devnode *devnode;
+};
+
+/**
  * struct media_devnode - Media device node
  * @fops:	pointer to struct media_file_operations with media device ops
  * @dev:	struct device pointer for the media controller device
@@ -92,7 +106,9 @@ void media_devnode_unregister(struct media_devnode *mdev);
 
 static inline struct media_devnode *media_devnode_data(struct file *filp)
 {
-	return filp->private_data;
+	struct media_devnode_fh *fh = filp->private_data;
+
+	return fh->devnode;
 }
 
 static inline int media_devnode_is_registered(struct media_devnode *mdev)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 23/48] media: Add request API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The request API allows bundling media device parameters with request
objects and applying them atomically, either synchronously or
asynchronously.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

---

Changes since v0:

- Make the request ID 32 bits wide internally
---
 drivers/media/media-device.c | 175 +++++++++++++++++++++++++++++++++++++++++++
 include/media/media-device.h |  41 ++++++++++
 include/uapi/linux/media.h   |  12 +++
 3 files changed, 228 insertions(+)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 285f7d79d848..37da26806ed8 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -33,6 +33,7 @@
 
 struct media_device_fh {
 	struct media_devnode_fh fh;
+	struct list_head requests;
 };
 
 static inline struct media_device_fh *media_device_fh(struct file *filp)
@@ -41,6 +42,161 @@ static inline struct media_device_fh *media_device_fh(struct file *filp)
 }
 
 /* -----------------------------------------------------------------------------
+ * Requests
+ */
+
+/**
+ * media_device_request_find - Find a request based from its ID
+ * @mdev: The media device
+ * @reqid: The request ID
+ *
+ * Find and return the request associated with the given ID, or NULL if no such
+ * request exists.
+ *
+ * When the function returns a non-NULL request it increases its reference
+ * count. The caller is responsible for releasing the reference by calling
+ * media_device_request_put() on the request.
+ */
+struct media_device_request *
+media_device_request_find(struct media_device *mdev, u16 reqid)
+{
+	struct media_device_request *req;
+	unsigned long flags;
+	bool found = false;
+
+	spin_lock_irqsave(&mdev->req_lock, flags);
+	list_for_each_entry(req, &mdev->requests, list) {
+		if (req->id = reqid) {
+			kref_get(&req->kref);
+			found = true;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+	return found ? req : NULL;
+}
+EXPORT_SYMBOL_GPL(media_device_request_find);
+
+void media_device_request_get(struct media_device_request *req)
+{
+	kref_get(&req->kref);
+}
+EXPORT_SYMBOL_GPL(media_device_request_get);
+
+static void media_device_request_release(struct kref *kref)
+{
+	struct media_device_request *req +		container_of(kref, struct media_device_request, kref);
+	struct media_device *mdev = req->mdev;
+
+	mdev->ops->req_free(mdev, req);
+}
+
+void media_device_request_put(struct media_device_request *req)
+{
+	kref_put(&req->kref, media_device_request_release);
+}
+EXPORT_SYMBOL_GPL(media_device_request_put);
+
+static int media_device_request_alloc(struct media_device *mdev,
+				      struct media_device_fh *fh,
+				      struct media_request_cmd *cmd)
+{
+	struct media_device_request *req;
+	unsigned long flags;
+
+	req = mdev->ops->req_alloc(mdev);
+	if (!req)
+		return -ENOMEM;
+
+	req->mdev = mdev;
+	kref_init(&req->kref);
+
+	spin_lock_irqsave(&mdev->req_lock, flags);
+	req->id = ++mdev->req_id;
+	list_add_tail(&req->list, &mdev->requests);
+	list_add_tail(&req->fh_list, &fh->requests);
+	spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+	cmd->request = req->id;
+	return 0;
+}
+
+static void media_device_request_delete(struct media_device *mdev,
+					struct media_device_request *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->req_lock, flags);
+	list_del(&req->list);
+	spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+	media_device_request_put(req);
+}
+
+static long media_device_request_cmd(struct media_device *mdev,
+				     struct media_device_fh *fh,
+				     struct media_request_cmd __user *_cmd)
+{
+	struct media_device_request *req = NULL;
+	struct media_request_cmd cmd;
+	int ret;
+
+	if (!mdev->ops || !mdev->ops->req_alloc || !mdev->ops->req_free)
+		return -ENOTTY;
+
+	if (copy_from_user(&cmd, _cmd, sizeof(cmd)))
+		return -EFAULT;
+
+	if (cmd.cmd != MEDIA_REQ_CMD_ALLOC) {
+		req = media_device_request_find(mdev, cmd.request);
+		if (!req)
+			return -EINVAL;
+	}
+
+	switch (cmd.cmd) {
+	case MEDIA_REQ_CMD_ALLOC:
+		ret = media_device_request_alloc(mdev, fh, &cmd);
+		break;
+
+	case MEDIA_REQ_CMD_DELETE:
+		media_device_request_delete(mdev, req);
+		ret = 0;
+		break;
+
+	case MEDIA_REQ_CMD_APPLY:
+		if (!mdev->ops->req_apply)
+			return -ENOSYS;
+
+		ret = mdev->ops->req_apply(mdev, req);
+		break;
+
+	case MEDIA_REQ_CMD_QUEUE:
+		if (!mdev->ops->req_queue)
+			return -ENOSYS;
+
+		ret = mdev->ops->req_queue(mdev, req);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (req)
+		media_device_request_put(req);
+
+	if (ret < 0)
+		return ret;
+
+	if (copy_to_user(_cmd, &cmd, sizeof(cmd)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
  * Userspace API
  */
 
@@ -52,6 +208,7 @@ static int media_device_open(struct file *filp)
 	if (!fh)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&fh->requests);
 	filp->private_data = &fh->fh;
 
 	return 0;
@@ -60,6 +217,15 @@ static int media_device_open(struct file *filp)
 static int media_device_close(struct file *filp)
 {
 	struct media_device_fh *fh = media_device_fh(filp);
+	struct media_device *mdev = to_media_device(fh->fh.devnode);
+	struct media_device_request *req, *next;
+
+	spin_lock_irq(&mdev->req_lock);
+	list_for_each_entry_safe(req, next, &fh->requests, fh_list) {
+		list_del(&req->fh_list);
+		media_device_request_put(req);
+	}
+	spin_unlock_irq(&mdev->req_lock);
 
 	kfree(fh);
 
@@ -257,6 +423,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
 {
 	struct media_devnode *devnode = media_devnode_data(filp);
 	struct media_device *dev = to_media_device(devnode);
+	struct media_device_fh *fh = media_device_fh(filp);
 	long ret;
 
 	switch (cmd) {
@@ -284,6 +451,11 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
 		mutex_unlock(&dev->graph_mutex);
 		break;
 
+	case MEDIA_IOC_REQUEST_CMD:
+		ret = media_device_request_cmd(dev, fh,
+				(struct media_request_cmd __user *)arg);
+		break;
+
 	default:
 		ret = -ENOIOCTLCMD;
 	}
@@ -404,6 +576,9 @@ int __must_check __media_device_register(struct media_device *mdev,
 	spin_lock_init(&mdev->lock);
 	mutex_init(&mdev->graph_mutex);
 
+	spin_lock_init(&mdev->req_lock);
+	INIT_LIST_HEAD(&mdev->requests);
+
 	/* Register the device node. */
 	mdev->devnode.fops = &media_device_fops;
 	mdev->devnode.parent = mdev->dev;
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 7e6de4dbf497..bc003bedf087 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -23,6 +23,7 @@
 #ifndef _MEDIA_DEVICE_H
 #define _MEDIA_DEVICE_H
 
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
@@ -31,14 +32,42 @@
 #include <media/media-entity.h>
 
 struct device;
+struct media_device;
+
+/**
+ * struct media_device_request - Media device request
+ * @id: Request ID
+ * @mdev: Media device this request belongs to
+ * @kref: Reference count
+ * @list: List entry in the media device requests list
+ * @fh_list: List entry in the media file handle requests list
+ */
+struct media_device_request {
+	u32 id;
+	struct media_device *mdev;
+	struct kref kref;
+	struct list_head list;
+	struct list_head fh_list;
+};
 
 /**
  * struct media_device_ops - Media device operations
  * @link_notify: Link state change notification callback
+ * @req_alloc: Allocate a request
+ * @req_free: Free a request
+ * @req_apply: Apply a request
+ * @req_queue: Queue a request
  */
 struct media_device_ops {
 	int (*link_notify)(struct media_link *link, u32 flags,
 			   unsigned int notification);
+	struct media_device_request *(*req_alloc)(struct media_device *mdev);
+	void (*req_free)(struct media_device *mdev,
+			 struct media_device_request *req);
+	int (*req_apply)(struct media_device *mdev,
+			 struct media_device_request *req);
+	int (*req_queue)(struct media_device *mdev,
+			 struct media_device_request *req);
 };
 
 /**
@@ -55,6 +84,9 @@ struct media_device_ops {
  * @lock:	Entities list lock
  * @graph_mutex: Entities graph operation lock
  * @ops:	Operation handler callbacks
+ * @req_lock:	Protects the req_id and requests fields
+ * @req_id:	Last request ID that was allocated
+ * @requests:	List of allocated requests
  *
  * This structure represents an abstract high-level media device. It allows easy
  * access to entities and provides basic media device-level support. The
@@ -86,6 +118,10 @@ struct media_device {
 	struct mutex graph_mutex;
 
 	const struct media_device_ops *ops;
+
+	spinlock_t req_lock;
+	u32 req_id;
+	struct list_head requests;
 };
 
 /* Supported link_notify @notification values. */
@@ -108,4 +144,9 @@ void media_device_unregister_entity(struct media_entity *entity);
 #define media_device_for_each_entity(entity, mdev)			\
 	list_for_each_entry(entity, &(mdev)->entities, list)
 
+struct media_device_request *
+media_device_request_find(struct media_device *mdev, u16 reqid);
+void media_device_request_get(struct media_device_request *req);
+void media_device_request_put(struct media_device_request *req);
+
 #endif
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 4e816be3de39..fd8887a03988 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -167,9 +167,21 @@ struct media_links_enum {
 	__u32 reserved[4];
 };
 
+#define MEDIA_REQ_CMD_ALLOC		0
+#define MEDIA_REQ_CMD_DELETE		1
+#define MEDIA_REQ_CMD_APPLY		2
+#define MEDIA_REQ_CMD_QUEUE		3
+
+struct media_request_cmd {
+	__u32 cmd;
+	__u32 request;
+	__u32 reserved[9];
+};
+
 #define MEDIA_IOC_DEVICE_INFO		_IOWR('|', 0x00, struct media_device_info)
 #define MEDIA_IOC_ENUM_ENTITIES		_IOWR('|', 0x01, struct media_entity_desc)
 #define MEDIA_IOC_ENUM_LINKS		_IOWR('|', 0x02, struct media_links_enum)
 #define MEDIA_IOC_SETUP_LINK		_IOWR('|', 0x03, struct media_link_desc)
+#define MEDIA_IOC_REQUEST_CMD		_IOWR('|', 0x04, struct media_request_cmd)
 
 #endif /* __LINUX_MEDIA_H */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 23/48] media: Add request API
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The request API allows bundling media device parameters with request
objects and applying them atomically, either synchronously or
asynchronously.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

---

Changes since v0:

- Make the request ID 32 bits wide internally
---
 drivers/media/media-device.c | 175 +++++++++++++++++++++++++++++++++++++++++++
 include/media/media-device.h |  41 ++++++++++
 include/uapi/linux/media.h   |  12 +++
 3 files changed, 228 insertions(+)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 285f7d79d848..37da26806ed8 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -33,6 +33,7 @@
 
 struct media_device_fh {
 	struct media_devnode_fh fh;
+	struct list_head requests;
 };
 
 static inline struct media_device_fh *media_device_fh(struct file *filp)
@@ -41,6 +42,161 @@ static inline struct media_device_fh *media_device_fh(struct file *filp)
 }
 
 /* -----------------------------------------------------------------------------
+ * Requests
+ */
+
+/**
+ * media_device_request_find - Find a request based from its ID
+ * @mdev: The media device
+ * @reqid: The request ID
+ *
+ * Find and return the request associated with the given ID, or NULL if no such
+ * request exists.
+ *
+ * When the function returns a non-NULL request it increases its reference
+ * count. The caller is responsible for releasing the reference by calling
+ * media_device_request_put() on the request.
+ */
+struct media_device_request *
+media_device_request_find(struct media_device *mdev, u16 reqid)
+{
+	struct media_device_request *req;
+	unsigned long flags;
+	bool found = false;
+
+	spin_lock_irqsave(&mdev->req_lock, flags);
+	list_for_each_entry(req, &mdev->requests, list) {
+		if (req->id == reqid) {
+			kref_get(&req->kref);
+			found = true;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+	return found ? req : NULL;
+}
+EXPORT_SYMBOL_GPL(media_device_request_find);
+
+void media_device_request_get(struct media_device_request *req)
+{
+	kref_get(&req->kref);
+}
+EXPORT_SYMBOL_GPL(media_device_request_get);
+
+static void media_device_request_release(struct kref *kref)
+{
+	struct media_device_request *req =
+		container_of(kref, struct media_device_request, kref);
+	struct media_device *mdev = req->mdev;
+
+	mdev->ops->req_free(mdev, req);
+}
+
+void media_device_request_put(struct media_device_request *req)
+{
+	kref_put(&req->kref, media_device_request_release);
+}
+EXPORT_SYMBOL_GPL(media_device_request_put);
+
+static int media_device_request_alloc(struct media_device *mdev,
+				      struct media_device_fh *fh,
+				      struct media_request_cmd *cmd)
+{
+	struct media_device_request *req;
+	unsigned long flags;
+
+	req = mdev->ops->req_alloc(mdev);
+	if (!req)
+		return -ENOMEM;
+
+	req->mdev = mdev;
+	kref_init(&req->kref);
+
+	spin_lock_irqsave(&mdev->req_lock, flags);
+	req->id = ++mdev->req_id;
+	list_add_tail(&req->list, &mdev->requests);
+	list_add_tail(&req->fh_list, &fh->requests);
+	spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+	cmd->request = req->id;
+	return 0;
+}
+
+static void media_device_request_delete(struct media_device *mdev,
+					struct media_device_request *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mdev->req_lock, flags);
+	list_del(&req->list);
+	spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+	media_device_request_put(req);
+}
+
+static long media_device_request_cmd(struct media_device *mdev,
+				     struct media_device_fh *fh,
+				     struct media_request_cmd __user *_cmd)
+{
+	struct media_device_request *req = NULL;
+	struct media_request_cmd cmd;
+	int ret;
+
+	if (!mdev->ops || !mdev->ops->req_alloc || !mdev->ops->req_free)
+		return -ENOTTY;
+
+	if (copy_from_user(&cmd, _cmd, sizeof(cmd)))
+		return -EFAULT;
+
+	if (cmd.cmd != MEDIA_REQ_CMD_ALLOC) {
+		req = media_device_request_find(mdev, cmd.request);
+		if (!req)
+			return -EINVAL;
+	}
+
+	switch (cmd.cmd) {
+	case MEDIA_REQ_CMD_ALLOC:
+		ret = media_device_request_alloc(mdev, fh, &cmd);
+		break;
+
+	case MEDIA_REQ_CMD_DELETE:
+		media_device_request_delete(mdev, req);
+		ret = 0;
+		break;
+
+	case MEDIA_REQ_CMD_APPLY:
+		if (!mdev->ops->req_apply)
+			return -ENOSYS;
+
+		ret = mdev->ops->req_apply(mdev, req);
+		break;
+
+	case MEDIA_REQ_CMD_QUEUE:
+		if (!mdev->ops->req_queue)
+			return -ENOSYS;
+
+		ret = mdev->ops->req_queue(mdev, req);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (req)
+		media_device_request_put(req);
+
+	if (ret < 0)
+		return ret;
+
+	if (copy_to_user(_cmd, &cmd, sizeof(cmd)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
  * Userspace API
  */
 
@@ -52,6 +208,7 @@ static int media_device_open(struct file *filp)
 	if (!fh)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&fh->requests);
 	filp->private_data = &fh->fh;
 
 	return 0;
@@ -60,6 +217,15 @@ static int media_device_open(struct file *filp)
 static int media_device_close(struct file *filp)
 {
 	struct media_device_fh *fh = media_device_fh(filp);
+	struct media_device *mdev = to_media_device(fh->fh.devnode);
+	struct media_device_request *req, *next;
+
+	spin_lock_irq(&mdev->req_lock);
+	list_for_each_entry_safe(req, next, &fh->requests, fh_list) {
+		list_del(&req->fh_list);
+		media_device_request_put(req);
+	}
+	spin_unlock_irq(&mdev->req_lock);
 
 	kfree(fh);
 
@@ -257,6 +423,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
 {
 	struct media_devnode *devnode = media_devnode_data(filp);
 	struct media_device *dev = to_media_device(devnode);
+	struct media_device_fh *fh = media_device_fh(filp);
 	long ret;
 
 	switch (cmd) {
@@ -284,6 +451,11 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
 		mutex_unlock(&dev->graph_mutex);
 		break;
 
+	case MEDIA_IOC_REQUEST_CMD:
+		ret = media_device_request_cmd(dev, fh,
+				(struct media_request_cmd __user *)arg);
+		break;
+
 	default:
 		ret = -ENOIOCTLCMD;
 	}
@@ -404,6 +576,9 @@ int __must_check __media_device_register(struct media_device *mdev,
 	spin_lock_init(&mdev->lock);
 	mutex_init(&mdev->graph_mutex);
 
+	spin_lock_init(&mdev->req_lock);
+	INIT_LIST_HEAD(&mdev->requests);
+
 	/* Register the device node. */
 	mdev->devnode.fops = &media_device_fops;
 	mdev->devnode.parent = mdev->dev;
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 7e6de4dbf497..bc003bedf087 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -23,6 +23,7 @@
 #ifndef _MEDIA_DEVICE_H
 #define _MEDIA_DEVICE_H
 
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
@@ -31,14 +32,42 @@
 #include <media/media-entity.h>
 
 struct device;
+struct media_device;
+
+/**
+ * struct media_device_request - Media device request
+ * @id: Request ID
+ * @mdev: Media device this request belongs to
+ * @kref: Reference count
+ * @list: List entry in the media device requests list
+ * @fh_list: List entry in the media file handle requests list
+ */
+struct media_device_request {
+	u32 id;
+	struct media_device *mdev;
+	struct kref kref;
+	struct list_head list;
+	struct list_head fh_list;
+};
 
 /**
  * struct media_device_ops - Media device operations
  * @link_notify: Link state change notification callback
+ * @req_alloc: Allocate a request
+ * @req_free: Free a request
+ * @req_apply: Apply a request
+ * @req_queue: Queue a request
  */
 struct media_device_ops {
 	int (*link_notify)(struct media_link *link, u32 flags,
 			   unsigned int notification);
+	struct media_device_request *(*req_alloc)(struct media_device *mdev);
+	void (*req_free)(struct media_device *mdev,
+			 struct media_device_request *req);
+	int (*req_apply)(struct media_device *mdev,
+			 struct media_device_request *req);
+	int (*req_queue)(struct media_device *mdev,
+			 struct media_device_request *req);
 };
 
 /**
@@ -55,6 +84,9 @@ struct media_device_ops {
  * @lock:	Entities list lock
  * @graph_mutex: Entities graph operation lock
  * @ops:	Operation handler callbacks
+ * @req_lock:	Protects the req_id and requests fields
+ * @req_id:	Last request ID that was allocated
+ * @requests:	List of allocated requests
  *
  * This structure represents an abstract high-level media device. It allows easy
  * access to entities and provides basic media device-level support. The
@@ -86,6 +118,10 @@ struct media_device {
 	struct mutex graph_mutex;
 
 	const struct media_device_ops *ops;
+
+	spinlock_t req_lock;
+	u32 req_id;
+	struct list_head requests;
 };
 
 /* Supported link_notify @notification values. */
@@ -108,4 +144,9 @@ void media_device_unregister_entity(struct media_entity *entity);
 #define media_device_for_each_entity(entity, mdev)			\
 	list_for_each_entry(entity, &(mdev)->entities, list)
 
+struct media_device_request *
+media_device_request_find(struct media_device *mdev, u16 reqid);
+void media_device_request_get(struct media_device_request *req);
+void media_device_request_put(struct media_device_request *req);
+
 #endif
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 4e816be3de39..fd8887a03988 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -167,9 +167,21 @@ struct media_links_enum {
 	__u32 reserved[4];
 };
 
+#define MEDIA_REQ_CMD_ALLOC		0
+#define MEDIA_REQ_CMD_DELETE		1
+#define MEDIA_REQ_CMD_APPLY		2
+#define MEDIA_REQ_CMD_QUEUE		3
+
+struct media_request_cmd {
+	__u32 cmd;
+	__u32 request;
+	__u32 reserved[9];
+};
+
 #define MEDIA_IOC_DEVICE_INFO		_IOWR('|', 0x00, struct media_device_info)
 #define MEDIA_IOC_ENUM_ENTITIES		_IOWR('|', 0x01, struct media_entity_desc)
 #define MEDIA_IOC_ENUM_LINKS		_IOWR('|', 0x02, struct media_links_enum)
 #define MEDIA_IOC_SETUP_LINK		_IOWR('|', 0x03, struct media_link_desc)
+#define MEDIA_IOC_REQUEST_CMD		_IOWR('|', 0x04, struct media_request_cmd)
 
 #endif /* __LINUX_MEDIA_H */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 24/48] media: Add per-entity request data support
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Allow subsystems to associate data with entities in each request. This
will be used by the V4L2 subdev core to store pad formats in requests.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

---

Changes since v0:

- Dereference requests without holding the list lock
- Remove requests from global list when closing the fh
---
 drivers/media/media-device.c | 82 ++++++++++++++++++++++++++++++++++++++++++--
 include/media/media-device.h |  7 ++++
 include/media/media-entity.h | 12 +++++++
 3 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 37da26806ed8..7fc94bf23eff 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -86,10 +86,16 @@ EXPORT_SYMBOL_GPL(media_device_request_get);
 
 static void media_device_request_release(struct kref *kref)
 {
+	struct media_entity_request_data *data, *next;
 	struct media_device_request *req  		container_of(kref, struct media_device_request, kref);
 	struct media_device *mdev = req->mdev;
 
+	list_for_each_entry_safe(data, next, &req->data, list) {
+		list_del(&data->list);
+		data->release(data);
+	}
+
 	mdev->ops->req_free(mdev, req);
 }
 
@@ -99,6 +105,70 @@ void media_device_request_put(struct media_device_request *req)
 }
 EXPORT_SYMBOL_GPL(media_device_request_put);
 
+/**
+ * media_device_request_get_entity_data - Get per-entity data
+ * @req: The request
+ * @entity: The entity
+ *
+ * Search and return per-entity data (as a struct media_entity_request_data
+ * instance) associated with the given entity for the request, as previously
+ * registered by a call to media_device_request_set_entity_data().
+ *
+ * The caller is expected to hold a reference to the request. Per-entity data is
+ * not reference counted, the returned pointer will be valid only as long as the
+ * reference to the request is held.
+ *
+ * Return the data instance pointer or NULL if no data could be found.
+ */
+struct media_entity_request_data *
+media_device_request_get_entity_data(struct media_device_request *req,
+				     struct media_entity *entity)
+{
+	struct media_entity_request_data *data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&req->mdev->req_lock, flags);
+
+	list_for_each_entry(data, &req->data, list) {
+		if (data->entity = entity)
+			goto done;
+	}
+
+	data = NULL;
+
+done:
+	spin_unlock_irqrestore(&req->mdev->req_lock, flags);
+	return data;
+}
+EXPORT_SYMBOL_GPL(media_device_request_get_entity_data);
+
+/**
+ * media_device_request_set_entity_data - Set per-entity data
+ * @req: The request
+ * @entity: The entity
+ * @data: The data
+ *
+ * Record the given per-entity data as being associated with the entity for the
+ * request.
+ *
+ * Only one per-entity data instance can be associated with a request. The
+ * caller is responsible for enforcing this requirement.
+ *
+ * Ownership of the per-entity data is transferred to the request when calling
+ * this function. The data will be freed automatically when the last reference
+ * to the request is released.
+ */
+void media_device_request_set_entity_data(struct media_device_request *req,
+	struct media_entity *entity, struct media_entity_request_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&req->mdev->req_lock, flags);
+	list_add_tail(&data->list, &req->data);
+	spin_unlock_irqrestore(&req->mdev->req_lock, flags);
+}
+EXPORT_SYMBOL_GPL(media_device_request_set_entity_data);
+
 static int media_device_request_alloc(struct media_device *mdev,
 				      struct media_device_fh *fh,
 				      struct media_request_cmd *cmd)
@@ -112,6 +182,7 @@ static int media_device_request_alloc(struct media_device *mdev,
 
 	req->mdev = mdev;
 	kref_init(&req->kref);
+	INIT_LIST_HEAD(&req->data);
 
 	spin_lock_irqsave(&mdev->req_lock, flags);
 	req->id = ++mdev->req_id;
@@ -130,6 +201,7 @@ static void media_device_request_delete(struct media_device *mdev,
 
 	spin_lock_irqsave(&mdev->req_lock, flags);
 	list_del(&req->list);
+	list_del(&req->fh_list);
 	spin_unlock_irqrestore(&mdev->req_lock, flags);
 
 	media_device_request_put(req);
@@ -218,12 +290,18 @@ static int media_device_close(struct file *filp)
 {
 	struct media_device_fh *fh = media_device_fh(filp);
 	struct media_device *mdev = to_media_device(fh->fh.devnode);
-	struct media_device_request *req, *next;
 
 	spin_lock_irq(&mdev->req_lock);
-	list_for_each_entry_safe(req, next, &fh->requests, fh_list) {
+	while (!list_empty(&fh->requests)) {
+		struct media_device_request *req;
+
+		req = list_first_entry(&fh->requests, typeof(*req), fh_list);
+		list_del(&req->list);
 		list_del(&req->fh_list);
+
+		spin_unlock_irq(&mdev->req_lock);
 		media_device_request_put(req);
+		spin_lock_irq(&mdev->req_lock);
 	}
 	spin_unlock_irq(&mdev->req_lock);
 
diff --git a/include/media/media-device.h b/include/media/media-device.h
index bc003bedf087..0a374328a135 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -41,6 +41,7 @@ struct media_device;
  * @kref: Reference count
  * @list: List entry in the media device requests list
  * @fh_list: List entry in the media file handle requests list
+ * @data: Per-entity data list
  */
 struct media_device_request {
 	u32 id;
@@ -48,6 +49,7 @@ struct media_device_request {
 	struct kref kref;
 	struct list_head list;
 	struct list_head fh_list;
+	struct list_head data;
 };
 
 /**
@@ -148,5 +150,10 @@ struct media_device_request *
 media_device_request_find(struct media_device *mdev, u16 reqid);
 void media_device_request_get(struct media_device_request *req);
 void media_device_request_put(struct media_device_request *req);
+struct media_entity_request_data *
+media_device_request_get_entity_data(struct media_device_request *req,
+				     struct media_entity *entity);
+void media_device_request_set_entity_data(struct media_device_request *req,
+	struct media_entity *entity, struct media_entity_request_data *data);
 
 #endif
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 197f93799753..36e2129e61c6 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -133,6 +133,18 @@ struct media_entity_graph {
 	int top;
 };
 
+/**
+ * struct media_entity_request_data - Per-entity request data
+ * @entity: Entity this data belongs to
+ * @release: Release operation to free the data
+ * @list: List entry in the media_device_request data list
+ */
+struct media_entity_request_data {
+	struct media_entity *entity;
+	void (*release)(struct media_entity_request_data *data);
+	struct list_head list;
+};
+
 int media_entity_init(struct media_entity *entity, u16 num_pads,
 		struct media_pad *pads, u16 extra_links);
 void media_entity_cleanup(struct media_entity *entity);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 24/48] media: Add per-entity request data support
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Allow subsystems to associate data with entities in each request. This
will be used by the V4L2 subdev core to store pad formats in requests.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

---

Changes since v0:

- Dereference requests without holding the list lock
- Remove requests from global list when closing the fh
---
 drivers/media/media-device.c | 82 ++++++++++++++++++++++++++++++++++++++++++--
 include/media/media-device.h |  7 ++++
 include/media/media-entity.h | 12 +++++++
 3 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 37da26806ed8..7fc94bf23eff 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -86,10 +86,16 @@ EXPORT_SYMBOL_GPL(media_device_request_get);
 
 static void media_device_request_release(struct kref *kref)
 {
+	struct media_entity_request_data *data, *next;
 	struct media_device_request *req =
 		container_of(kref, struct media_device_request, kref);
 	struct media_device *mdev = req->mdev;
 
+	list_for_each_entry_safe(data, next, &req->data, list) {
+		list_del(&data->list);
+		data->release(data);
+	}
+
 	mdev->ops->req_free(mdev, req);
 }
 
@@ -99,6 +105,70 @@ void media_device_request_put(struct media_device_request *req)
 }
 EXPORT_SYMBOL_GPL(media_device_request_put);
 
+/**
+ * media_device_request_get_entity_data - Get per-entity data
+ * @req: The request
+ * @entity: The entity
+ *
+ * Search and return per-entity data (as a struct media_entity_request_data
+ * instance) associated with the given entity for the request, as previously
+ * registered by a call to media_device_request_set_entity_data().
+ *
+ * The caller is expected to hold a reference to the request. Per-entity data is
+ * not reference counted, the returned pointer will be valid only as long as the
+ * reference to the request is held.
+ *
+ * Return the data instance pointer or NULL if no data could be found.
+ */
+struct media_entity_request_data *
+media_device_request_get_entity_data(struct media_device_request *req,
+				     struct media_entity *entity)
+{
+	struct media_entity_request_data *data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&req->mdev->req_lock, flags);
+
+	list_for_each_entry(data, &req->data, list) {
+		if (data->entity == entity)
+			goto done;
+	}
+
+	data = NULL;
+
+done:
+	spin_unlock_irqrestore(&req->mdev->req_lock, flags);
+	return data;
+}
+EXPORT_SYMBOL_GPL(media_device_request_get_entity_data);
+
+/**
+ * media_device_request_set_entity_data - Set per-entity data
+ * @req: The request
+ * @entity: The entity
+ * @data: The data
+ *
+ * Record the given per-entity data as being associated with the entity for the
+ * request.
+ *
+ * Only one per-entity data instance can be associated with a request. The
+ * caller is responsible for enforcing this requirement.
+ *
+ * Ownership of the per-entity data is transferred to the request when calling
+ * this function. The data will be freed automatically when the last reference
+ * to the request is released.
+ */
+void media_device_request_set_entity_data(struct media_device_request *req,
+	struct media_entity *entity, struct media_entity_request_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&req->mdev->req_lock, flags);
+	list_add_tail(&data->list, &req->data);
+	spin_unlock_irqrestore(&req->mdev->req_lock, flags);
+}
+EXPORT_SYMBOL_GPL(media_device_request_set_entity_data);
+
 static int media_device_request_alloc(struct media_device *mdev,
 				      struct media_device_fh *fh,
 				      struct media_request_cmd *cmd)
@@ -112,6 +182,7 @@ static int media_device_request_alloc(struct media_device *mdev,
 
 	req->mdev = mdev;
 	kref_init(&req->kref);
+	INIT_LIST_HEAD(&req->data);
 
 	spin_lock_irqsave(&mdev->req_lock, flags);
 	req->id = ++mdev->req_id;
@@ -130,6 +201,7 @@ static void media_device_request_delete(struct media_device *mdev,
 
 	spin_lock_irqsave(&mdev->req_lock, flags);
 	list_del(&req->list);
+	list_del(&req->fh_list);
 	spin_unlock_irqrestore(&mdev->req_lock, flags);
 
 	media_device_request_put(req);
@@ -218,12 +290,18 @@ static int media_device_close(struct file *filp)
 {
 	struct media_device_fh *fh = media_device_fh(filp);
 	struct media_device *mdev = to_media_device(fh->fh.devnode);
-	struct media_device_request *req, *next;
 
 	spin_lock_irq(&mdev->req_lock);
-	list_for_each_entry_safe(req, next, &fh->requests, fh_list) {
+	while (!list_empty(&fh->requests)) {
+		struct media_device_request *req;
+
+		req = list_first_entry(&fh->requests, typeof(*req), fh_list);
+		list_del(&req->list);
 		list_del(&req->fh_list);
+
+		spin_unlock_irq(&mdev->req_lock);
 		media_device_request_put(req);
+		spin_lock_irq(&mdev->req_lock);
 	}
 	spin_unlock_irq(&mdev->req_lock);
 
diff --git a/include/media/media-device.h b/include/media/media-device.h
index bc003bedf087..0a374328a135 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -41,6 +41,7 @@ struct media_device;
  * @kref: Reference count
  * @list: List entry in the media device requests list
  * @fh_list: List entry in the media file handle requests list
+ * @data: Per-entity data list
  */
 struct media_device_request {
 	u32 id;
@@ -48,6 +49,7 @@ struct media_device_request {
 	struct kref kref;
 	struct list_head list;
 	struct list_head fh_list;
+	struct list_head data;
 };
 
 /**
@@ -148,5 +150,10 @@ struct media_device_request *
 media_device_request_find(struct media_device *mdev, u16 reqid);
 void media_device_request_get(struct media_device_request *req);
 void media_device_request_put(struct media_device_request *req);
+struct media_entity_request_data *
+media_device_request_get_entity_data(struct media_device_request *req,
+				     struct media_entity *entity);
+void media_device_request_set_entity_data(struct media_device_request *req,
+	struct media_entity *entity, struct media_entity_request_data *data);
 
 #endif
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 197f93799753..36e2129e61c6 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -133,6 +133,18 @@ struct media_entity_graph {
 	int top;
 };
 
+/**
+ * struct media_entity_request_data - Per-entity request data
+ * @entity: Entity this data belongs to
+ * @release: Release operation to free the data
+ * @list: List entry in the media_device_request data list
+ */
+struct media_entity_request_data {
+	struct media_entity *entity;
+	void (*release)(struct media_entity_request_data *data);
+	struct list_head list;
+};
+
 int media_entity_init(struct media_entity *entity, u16 num_pads,
 		struct media_pad *pads, u16 extra_links);
 void media_entity_cleanup(struct media_entity *entity);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 25/48] videodev2.h: Add request field to v4l2_buffer
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Hans Verkuil <hans.verkuil@cisco.com>

When queuing buffers allow for passing the request ID that
should be associated with this buffer. Split the u32 reserved2 field
into two u16 fields, one for request, one with the old reserved2 name.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/cpia2/cpia2_v4l.c           | 1 +
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 +++-
 drivers/media/v4l2-core/v4l2-ioctl.c          | 4 ++--
 drivers/media/v4l2-core/videobuf2-v4l2.c      | 2 ++
 include/media/videobuf2-v4l2.h                | 2 ++
 include/uapi/linux/videodev2.h                | 4 +++-
 6 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index 9caea8344547..01c596a4a760 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -952,6 +952,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 	buf->sequence = cam->buffers[buf->index].seq;
 	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
 	buf->length = cam->frame_size;
+	buf->request = 0;
 	buf->reserved2 = 0;
 	buf->reserved = 0;
 	memset(&buf->timecode, 0, sizeof(buf->timecode));
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 8fd84a67478a..ebd3cd4dee73 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -347,7 +347,8 @@ struct v4l2_buffer32 {
 		__s32		fd;
 	} m;
 	__u32			length;
-	__u32			reserved2;
+	__u16			request;
+	__u16			reserved2;
 	__u32			reserved;
 };
 
@@ -512,6 +513,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
 		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
 		put_user(kp->sequence, &up->sequence) ||
+		put_user(kp->request, &up->request) ||
 		put_user(kp->reserved2, &up->reserved2) ||
 		put_user(kp->reserved, &up->reserved))
 			return -EFAULT;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 8a018c6dd16a..67a4aa760aa3 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -441,14 +441,14 @@ static void v4l_print_buffer(const void *arg, bool write_only)
 	const struct v4l2_plane *plane;
 	int i;
 
-	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request=%u, "
 		"flags=0x%08x, field=%s, sequence=%d, memory=%s",
 			p->timestamp.tv_sec / 3600,
 			(int)(p->timestamp.tv_sec / 60) % 60,
 			(int)(p->timestamp.tv_sec % 60),
 			(long)p->timestamp.tv_usec,
 			p->index,
-			prt_names(p->type, v4l2_type_names),
+			prt_names(p->type, v4l2_type_names), p->request,
 			p->flags, prt_names(p->field, v4l2_field_names),
 			p->sequence, prt_names(p->memory, v4l2_memory_names));
 
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 2d1e5b7d85a2..f6a2800e5f66 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -194,6 +194,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 	b->timestamp = vbuf->timestamp;
 	b->timecode = vbuf->timecode;
 	b->sequence = vbuf->sequence;
+	b->request = vbuf->request;
 	b->reserved2 = 0;
 	b->reserved = 0;
 
@@ -311,6 +312,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 	vbuf->timestamp.tv_sec = 0;
 	vbuf->timestamp.tv_usec = 0;
 	vbuf->sequence = 0;
+	vbuf->request = b->request;
 
 	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
 		if (b->memory = VB2_MEMORY_USERPTR) {
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 5abab1e7c7e8..48d6a34dcdb4 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -31,6 +31,7 @@
  * @timestamp:	frame timestamp
  * @timecode:	frame timecode
  * @sequence:	sequence count of this frame
+ * @request:	request used by the buffer
  * Should contain enough information to be able to cover all the fields
  * of struct v4l2_buffer at videodev2.h
  */
@@ -42,6 +43,7 @@ struct vb2_v4l2_buffer {
 	struct timeval		timestamp;
 	struct v4l2_timecode	timecode;
 	__u32			sequence;
+	__u32			request;
 };
 
 /*
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 14cd5ebfee6d..5af1d2d87558 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -844,6 +844,7 @@ struct v4l2_plane {
  * @length:	size in bytes of the buffer (NOT its payload) for single-plane
  *		buffers (when type != *_MPLANE); number of elements in the
  *		planes array for multi-plane buffers
+ * @request: this buffer should use this request
  *
  * Contains data exchanged by application and driver using one of the Streaming
  * I/O methods.
@@ -867,7 +868,8 @@ struct v4l2_buffer {
 		__s32		fd;
 	} m;
 	__u32			length;
-	__u32			reserved2;
+	__u16			request;
+	__u16			reserved2;
 	__u32			reserved;
 };
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 25/48] videodev2.h: Add request field to v4l2_buffer
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Hans Verkuil <hans.verkuil@cisco.com>

When queuing buffers allow for passing the request ID that
should be associated with this buffer. Split the u32 reserved2 field
into two u16 fields, one for request, one with the old reserved2 name.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/cpia2/cpia2_v4l.c           | 1 +
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 +++-
 drivers/media/v4l2-core/v4l2-ioctl.c          | 4 ++--
 drivers/media/v4l2-core/videobuf2-v4l2.c      | 2 ++
 include/media/videobuf2-v4l2.h                | 2 ++
 include/uapi/linux/videodev2.h                | 4 +++-
 6 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index 9caea8344547..01c596a4a760 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -952,6 +952,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 	buf->sequence = cam->buffers[buf->index].seq;
 	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
 	buf->length = cam->frame_size;
+	buf->request = 0;
 	buf->reserved2 = 0;
 	buf->reserved = 0;
 	memset(&buf->timecode, 0, sizeof(buf->timecode));
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 8fd84a67478a..ebd3cd4dee73 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -347,7 +347,8 @@ struct v4l2_buffer32 {
 		__s32		fd;
 	} m;
 	__u32			length;
-	__u32			reserved2;
+	__u16			request;
+	__u16			reserved2;
 	__u32			reserved;
 };
 
@@ -512,6 +513,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
 		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
 		put_user(kp->sequence, &up->sequence) ||
+		put_user(kp->request, &up->request) ||
 		put_user(kp->reserved2, &up->reserved2) ||
 		put_user(kp->reserved, &up->reserved))
 			return -EFAULT;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 8a018c6dd16a..67a4aa760aa3 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -441,14 +441,14 @@ static void v4l_print_buffer(const void *arg, bool write_only)
 	const struct v4l2_plane *plane;
 	int i;
 
-	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request=%u, "
 		"flags=0x%08x, field=%s, sequence=%d, memory=%s",
 			p->timestamp.tv_sec / 3600,
 			(int)(p->timestamp.tv_sec / 60) % 60,
 			(int)(p->timestamp.tv_sec % 60),
 			(long)p->timestamp.tv_usec,
 			p->index,
-			prt_names(p->type, v4l2_type_names),
+			prt_names(p->type, v4l2_type_names), p->request,
 			p->flags, prt_names(p->field, v4l2_field_names),
 			p->sequence, prt_names(p->memory, v4l2_memory_names));
 
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 2d1e5b7d85a2..f6a2800e5f66 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -194,6 +194,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 	b->timestamp = vbuf->timestamp;
 	b->timecode = vbuf->timecode;
 	b->sequence = vbuf->sequence;
+	b->request = vbuf->request;
 	b->reserved2 = 0;
 	b->reserved = 0;
 
@@ -311,6 +312,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 	vbuf->timestamp.tv_sec = 0;
 	vbuf->timestamp.tv_usec = 0;
 	vbuf->sequence = 0;
+	vbuf->request = b->request;
 
 	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
 		if (b->memory == VB2_MEMORY_USERPTR) {
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 5abab1e7c7e8..48d6a34dcdb4 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -31,6 +31,7 @@
  * @timestamp:	frame timestamp
  * @timecode:	frame timecode
  * @sequence:	sequence count of this frame
+ * @request:	request used by the buffer
  * Should contain enough information to be able to cover all the fields
  * of struct v4l2_buffer at videodev2.h
  */
@@ -42,6 +43,7 @@ struct vb2_v4l2_buffer {
 	struct timeval		timestamp;
 	struct v4l2_timecode	timecode;
 	__u32			sequence;
+	__u32			request;
 };
 
 /*
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 14cd5ebfee6d..5af1d2d87558 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -844,6 +844,7 @@ struct v4l2_plane {
  * @length:	size in bytes of the buffer (NOT its payload) for single-plane
  *		buffers (when type != *_MPLANE); number of elements in the
  *		planes array for multi-plane buffers
+ * @request: this buffer should use this request
  *
  * Contains data exchanged by application and driver using one of the Streaming
  * I/O methods.
@@ -867,7 +868,8 @@ struct v4l2_buffer {
 		__s32		fd;
 	} m;
 	__u32			length;
-	__u32			reserved2;
+	__u16			request;
+	__u16			reserved2;
 	__u32			reserved;
 };
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Let userspace specify a request ID when getting or setting formats. The
support is limited to the multi-planar API at the moment, extending it
to the single-planar API is possible if needed.

From a userspace point of view the API change is also minimized and
doesn't require any new ioctl.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 include/uapi/linux/videodev2.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 5af1d2d87558..5b2a8bc80eb2 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1973,6 +1973,7 @@ struct v4l2_plane_pix_format {
  * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
  * @quantization:	enum v4l2_quantization, colorspace quantization
  * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
+ * @request:		request ID
  */
 struct v4l2_pix_format_mplane {
 	__u32				width;
@@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
 	__u8				ycbcr_enc;
 	__u8				quantization;
 	__u8				xfer_func;
-	__u8				reserved[7];
+	__u8				reserved[3];
+	__u32				request;
 } __attribute__ ((packed));
 
 /**
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Let userspace specify a request ID when getting or setting formats. The
support is limited to the multi-planar API at the moment, extending it
to the single-planar API is possible if needed.

>From a userspace point of view the API change is also minimized and
doesn't require any new ioctl.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 include/uapi/linux/videodev2.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 5af1d2d87558..5b2a8bc80eb2 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1973,6 +1973,7 @@ struct v4l2_plane_pix_format {
  * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
  * @quantization:	enum v4l2_quantization, colorspace quantization
  * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
+ * @request:		request ID
  */
 struct v4l2_pix_format_mplane {
 	__u32				width;
@@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
 	__u8				ycbcr_enc;
 	__u8				quantization;
 	__u8				xfer_func;
-	__u8				reserved[7];
+	__u8				reserved[3];
+	__u32				request;
 } __attribute__ ((packed));
 
 /**
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Let userspace specify a request ID when getting or setting formats or
selection rectangles.

From a userspace point of view the API change is minimized and doesn't
require any new ioctl.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 include/uapi/linux/v4l2-subdev.h | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index dbce2b554e02..2f1691ce9df5 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -32,10 +32,12 @@
  * enum v4l2_subdev_format_whence - Media bus format type
  * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
  * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
+ * @V4L2_SUBDEV_FORMAT_REQUEST: format stored in request
  */
 enum v4l2_subdev_format_whence {
 	V4L2_SUBDEV_FORMAT_TRY = 0,
 	V4L2_SUBDEV_FORMAT_ACTIVE = 1,
+	V4L2_SUBDEV_FORMAT_REQUEST = 2,
 };
 
 /**
@@ -43,12 +45,17 @@ enum v4l2_subdev_format_whence {
  * @which: format type (from enum v4l2_subdev_format_whence)
  * @pad: pad number, as reported by the media API
  * @format: media bus format (format code and frame size)
+ * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
+ * @reserved2: for future use, set to zero for now
+ * @reserved: for future use, set to zero for now
  */
 struct v4l2_subdev_format {
 	__u32 which;
 	__u32 pad;
 	struct v4l2_mbus_framefmt format;
-	__u32 reserved[8];
+	__u16 request;
+	__u16 reserved2;
+	__u32 reserved[7];
 };
 
 /**
@@ -139,6 +146,8 @@ struct v4l2_subdev_frame_interval_enum {
  *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
  * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
  * @r: coordinates of the selection window
+ * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
+ * @reserved2: for future use, set to zero for now
  * @reserved: for future use, set to zero for now
  *
  * Hardware may use multiple helper windows to process a video stream.
@@ -151,7 +160,9 @@ struct v4l2_subdev_selection {
 	__u32 target;
 	__u32 flags;
 	struct v4l2_rect r;
-	__u32 reserved[8];
+	__u16 request;
+	__u16 reserved2;
+	__u32 reserved[7];
 };
 
 /* Backwards compatibility define --- to be removed */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Let userspace specify a request ID when getting or setting formats or
selection rectangles.

>From a userspace point of view the API change is minimized and doesn't
require any new ioctl.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 include/uapi/linux/v4l2-subdev.h | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index dbce2b554e02..2f1691ce9df5 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -32,10 +32,12 @@
  * enum v4l2_subdev_format_whence - Media bus format type
  * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
  * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
+ * @V4L2_SUBDEV_FORMAT_REQUEST: format stored in request
  */
 enum v4l2_subdev_format_whence {
 	V4L2_SUBDEV_FORMAT_TRY = 0,
 	V4L2_SUBDEV_FORMAT_ACTIVE = 1,
+	V4L2_SUBDEV_FORMAT_REQUEST = 2,
 };
 
 /**
@@ -43,12 +45,17 @@ enum v4l2_subdev_format_whence {
  * @which: format type (from enum v4l2_subdev_format_whence)
  * @pad: pad number, as reported by the media API
  * @format: media bus format (format code and frame size)
+ * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
+ * @reserved2: for future use, set to zero for now
+ * @reserved: for future use, set to zero for now
  */
 struct v4l2_subdev_format {
 	__u32 which;
 	__u32 pad;
 	struct v4l2_mbus_framefmt format;
-	__u32 reserved[8];
+	__u16 request;
+	__u16 reserved2;
+	__u32 reserved[7];
 };
 
 /**
@@ -139,6 +146,8 @@ struct v4l2_subdev_frame_interval_enum {
  *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
  * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
  * @r: coordinates of the selection window
+ * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
+ * @reserved2: for future use, set to zero for now
  * @reserved: for future use, set to zero for now
  *
  * Hardware may use multiple helper windows to process a video stream.
@@ -151,7 +160,9 @@ struct v4l2_subdev_selection {
 	__u32 target;
 	__u32 flags;
 	struct v4l2_rect r;
-	__u32 reserved[8];
+	__u16 request;
+	__u16 reserved2;
+	__u32 reserved[7];
 };
 
 /* Backwards compatibility define --- to be removed */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 28/48] v4l: Support the request API in format operations
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Store the formats in per-entity request data. The get and set format
operations are completely handled by the V4L2 core with help of the try
format driver operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 121 +++++++++++++++++++++++++++++++++++
 include/media/v4l2-dev.h             |  13 ++++
 2 files changed, 134 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 67a4aa760aa3..1143d70d578a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1341,6 +1341,119 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
 	return ret;
 }
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static void vdev_request_data_release(struct media_entity_request_data *data)
+{
+	struct video_device_request_data *vdata +		to_video_device_request_data(data);
+
+	kfree(vdata);
+}
+
+static int vdev_request_format(struct video_device *vdev, unsigned int req_id,
+			       struct media_device_request **_req,
+			       struct v4l2_pix_format_mplane **_fmt)
+{
+	struct media_entity_request_data *data;
+	struct video_device_request_data *vdata;
+	struct media_device_request *req;
+
+	if (!vdev->v4l2_dev || !vdev->v4l2_dev->mdev)
+		return -EINVAL;
+
+	req = media_device_request_find(vdev->v4l2_dev->mdev, req_id);
+	if (!req)
+		return -EINVAL;
+
+	*_req = req;
+
+	data = media_device_request_get_entity_data(req, &vdev->entity);
+	if (data) {
+		vdata = to_video_device_request_data(data);
+		*_fmt = &vdata->format;
+		return 0;
+	}
+
+	vdata = kzalloc(sizeof(*vdata), GFP_KERNEL);
+	if (!vdata) {
+		media_device_request_put(req);
+		return -ENOMEM;
+	}
+
+	vdata->data.release = vdev_request_data_release;
+
+	media_device_request_set_entity_data(req, &vdev->entity, &vdata->data);
+
+	*_fmt = &vdata->format;
+	return 0;
+}
+
+static int v4l_g_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_pix_format_mplane *format;
+	struct media_device_request *req;
+	int ret;
+
+	ret = vdev_request_format(vdev, fmt->fmt.pix_mp.request,
+				  &req, &format);
+	if (ret < 0)
+		return ret;
+
+	fmt->fmt.pix_mp = *format;
+	media_device_request_put(req);
+	return 0;
+}
+
+static int v4l_s_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	int (*try_op)(struct file *file, void *fh, struct v4l2_format *fmt);
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_pix_format_mplane *format;
+	struct media_device_request *req;
+	int ret;
+
+	if (fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		try_op = ops->vidioc_try_fmt_vid_cap_mplane;
+	else
+		try_op = ops->vidioc_try_fmt_vid_out_mplane;
+
+	if (unlikely(!try_op))
+		return -ENOSYS;
+
+	ret = try_op(file, fh, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = vdev_request_format(vdev, fmt->fmt.pix_mp.request,
+				  &req, &format);
+	if (ret < 0)
+		return ret;
+
+	*format = fmt->fmt.pix_mp;
+	media_device_request_put(req);
+	return 0;
+}
+#else
+static int v4l_g_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return -ENOSYS;
+}
+
+static int v4l_s_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return -ENOSYS;
+}
+#endif
+
 static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -1388,6 +1501,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap_mplane))
 			break;
+		if (p->fmt.pix_mp.request)
+			return v4l_g_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_overlay))
@@ -1412,6 +1527,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_mplane))
 			break;
+		if (p->fmt.pix_mp.request)
+			return v4l_g_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_overlay))
@@ -1463,6 +1580,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane))
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+		if (p->fmt.pix_mp.request)
+			return v4l_s_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay))
@@ -1491,6 +1610,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane))
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+		if (p->fmt.pix_mp.request)
+			return v4l_s_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay))
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index acbcd2f5fe7f..9fb386a6e505 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -233,4 +233,17 @@ static inline int video_is_registered(struct video_device *vdev)
 	return test_bit(V4L2_FL_REGISTERED, &vdev->flags);
 }
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+struct video_device_request_data {
+	struct media_entity_request_data data;
+	struct v4l2_pix_format_mplane format;
+};
+
+static inline struct video_device_request_data *
+to_video_device_request_data(struct media_entity_request_data *data)
+{
+	return container_of(data, struct video_device_request_data, data);
+}
+#endif
+
 #endif /* _V4L2_DEV_H */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 28/48] v4l: Support the request API in format operations
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Store the formats in per-entity request data. The get and set format
operations are completely handled by the V4L2 core with help of the try
format driver operation.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 121 +++++++++++++++++++++++++++++++++++
 include/media/v4l2-dev.h             |  13 ++++
 2 files changed, 134 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 67a4aa760aa3..1143d70d578a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1341,6 +1341,119 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
 	return ret;
 }
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static void vdev_request_data_release(struct media_entity_request_data *data)
+{
+	struct video_device_request_data *vdata =
+		to_video_device_request_data(data);
+
+	kfree(vdata);
+}
+
+static int vdev_request_format(struct video_device *vdev, unsigned int req_id,
+			       struct media_device_request **_req,
+			       struct v4l2_pix_format_mplane **_fmt)
+{
+	struct media_entity_request_data *data;
+	struct video_device_request_data *vdata;
+	struct media_device_request *req;
+
+	if (!vdev->v4l2_dev || !vdev->v4l2_dev->mdev)
+		return -EINVAL;
+
+	req = media_device_request_find(vdev->v4l2_dev->mdev, req_id);
+	if (!req)
+		return -EINVAL;
+
+	*_req = req;
+
+	data = media_device_request_get_entity_data(req, &vdev->entity);
+	if (data) {
+		vdata = to_video_device_request_data(data);
+		*_fmt = &vdata->format;
+		return 0;
+	}
+
+	vdata = kzalloc(sizeof(*vdata), GFP_KERNEL);
+	if (!vdata) {
+		media_device_request_put(req);
+		return -ENOMEM;
+	}
+
+	vdata->data.release = vdev_request_data_release;
+
+	media_device_request_set_entity_data(req, &vdev->entity, &vdata->data);
+
+	*_fmt = &vdata->format;
+	return 0;
+}
+
+static int v4l_g_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_pix_format_mplane *format;
+	struct media_device_request *req;
+	int ret;
+
+	ret = vdev_request_format(vdev, fmt->fmt.pix_mp.request,
+				  &req, &format);
+	if (ret < 0)
+		return ret;
+
+	fmt->fmt.pix_mp = *format;
+	media_device_request_put(req);
+	return 0;
+}
+
+static int v4l_s_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	int (*try_op)(struct file *file, void *fh, struct v4l2_format *fmt);
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_pix_format_mplane *format;
+	struct media_device_request *req;
+	int ret;
+
+	if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		try_op = ops->vidioc_try_fmt_vid_cap_mplane;
+	else
+		try_op = ops->vidioc_try_fmt_vid_out_mplane;
+
+	if (unlikely(!try_op))
+		return -ENOSYS;
+
+	ret = try_op(file, fh, fmt);
+	if (ret < 0)
+		return ret;
+
+	ret = vdev_request_format(vdev, fmt->fmt.pix_mp.request,
+				  &req, &format);
+	if (ret < 0)
+		return ret;
+
+	*format = fmt->fmt.pix_mp;
+	media_device_request_put(req);
+	return 0;
+}
+#else
+static int v4l_g_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return -ENOSYS;
+}
+
+static int v4l_s_req_mplane_fmt(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh,
+				struct v4l2_format *fmt)
+{
+	return -ENOSYS;
+}
+#endif
+
 static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -1388,6 +1501,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap_mplane))
 			break;
+		if (p->fmt.pix_mp.request)
+			return v4l_g_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_overlay))
@@ -1412,6 +1527,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_mplane))
 			break;
+		if (p->fmt.pix_mp.request)
+			return v4l_g_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_overlay))
@@ -1463,6 +1580,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane))
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+		if (p->fmt.pix_mp.request)
+			return v4l_s_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay))
@@ -1491,6 +1610,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane))
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.pix_mp);
+		if (p->fmt.pix_mp.request)
+			return v4l_s_req_mplane_fmt(ops, file, fh, p);
 		return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg);
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay))
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index acbcd2f5fe7f..9fb386a6e505 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -233,4 +233,17 @@ static inline int video_is_registered(struct video_device *vdev)
 	return test_bit(V4L2_FL_REGISTERED, &vdev->flags);
 }
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+struct video_device_request_data {
+	struct media_entity_request_data data;
+	struct v4l2_pix_format_mplane format;
+};
+
+static inline struct video_device_request_data *
+to_video_device_request_data(struct media_entity_request_data *data)
+{
+	return container_of(data, struct video_device_request_data, data);
+}
+#endif
+
 #endif /* _V4L2_DEV_H */
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 29/48] v4l: subdev: Add pad config allocator and init
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Laurent Pinchart <laurent.pinchart@linaro.org>

Add a new subdev operation to initialize a subdev pad config array, and
a helper function to allocate and initialize the array. This can be used
by bridge drivers to implement try format based on subdev pad
operations.

Signed-off-by: Laurent Pinchart <laurent.pinchart@linaro.org>
Acked-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++++++++++-
 include/media/v4l2-subdev.h           | 11 +++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 83615b8fb46a..951a9cf7b47e 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -35,7 +35,7 @@
 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL);
+	fh->pad = v4l2_subdev_alloc_pad_config(sd);
 	if (fh->pad = NULL)
 		return -ENOMEM;
 #endif
@@ -569,6 +569,23 @@ int v4l2_subdev_link_validate(struct media_link *link)
 		sink, link, &source_fmt, &sink_fmt);
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
+
+struct v4l2_subdev_pad_config *v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd)
+{
+	struct v4l2_subdev_pad_config *cfg;
+
+	if (!sd->entity.num_pads)
+		return NULL;
+
+	cfg = kcalloc(sd->entity.num_pads, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return NULL;
+
+	v4l2_subdev_call(sd, pad, init_cfg, cfg);
+
+	return cfg;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config);
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index b273cf9ac047..c97935455669 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -21,6 +21,7 @@
 #ifndef _V4L2_SUBDEV_H
 #define _V4L2_SUBDEV_H
 
+#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/v4l2-subdev.h>
 #include <media/media-entity.h>
@@ -604,6 +605,8 @@ struct v4l2_subdev_pad_config {
  *                  may be adjusted by the subdev driver to device capabilities.
  */
 struct v4l2_subdev_pad_ops {
+	void (*init_cfg)(struct v4l2_subdev *sd,
+			 struct v4l2_subdev_pad_config *cfg);
 	int (*enum_mbus_code)(struct v4l2_subdev *sd,
 			      struct v4l2_subdev_pad_config *cfg,
 			      struct v4l2_subdev_mbus_code_enum *code);
@@ -798,7 +801,15 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
 				      struct v4l2_subdev_format *source_fmt,
 				      struct v4l2_subdev_format *sink_fmt);
 int v4l2_subdev_link_validate(struct media_link *link);
+
+struct v4l2_subdev_pad_config *v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd);
+
+static inline void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg)
+{
+	kfree(cfg);
+}
 #endif /* CONFIG_MEDIA_CONTROLLER */
+
 void v4l2_subdev_init(struct v4l2_subdev *sd,
 		      const struct v4l2_subdev_ops *ops);
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 29/48] v4l: subdev: Add pad config allocator and init
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Laurent Pinchart <laurent.pinchart@linaro.org>

Add a new subdev operation to initialize a subdev pad config array, and
a helper function to allocate and initialize the array. This can be used
by bridge drivers to implement try format based on subdev pad
operations.

Signed-off-by: Laurent Pinchart <laurent.pinchart@linaro.org>
Acked-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 19 ++++++++++++++++++-
 include/media/v4l2-subdev.h           | 11 +++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 83615b8fb46a..951a9cf7b47e 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -35,7 +35,7 @@
 static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
 {
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL);
+	fh->pad = v4l2_subdev_alloc_pad_config(sd);
 	if (fh->pad == NULL)
 		return -ENOMEM;
 #endif
@@ -569,6 +569,23 @@ int v4l2_subdev_link_validate(struct media_link *link)
 		sink, link, &source_fmt, &sink_fmt);
 }
 EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
+
+struct v4l2_subdev_pad_config *v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd)
+{
+	struct v4l2_subdev_pad_config *cfg;
+
+	if (!sd->entity.num_pads)
+		return NULL;
+
+	cfg = kcalloc(sd->entity.num_pads, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return NULL;
+
+	v4l2_subdev_call(sd, pad, init_cfg, cfg);
+
+	return cfg;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_pad_config);
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index b273cf9ac047..c97935455669 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -21,6 +21,7 @@
 #ifndef _V4L2_SUBDEV_H
 #define _V4L2_SUBDEV_H
 
+#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/v4l2-subdev.h>
 #include <media/media-entity.h>
@@ -604,6 +605,8 @@ struct v4l2_subdev_pad_config {
  *                  may be adjusted by the subdev driver to device capabilities.
  */
 struct v4l2_subdev_pad_ops {
+	void (*init_cfg)(struct v4l2_subdev *sd,
+			 struct v4l2_subdev_pad_config *cfg);
 	int (*enum_mbus_code)(struct v4l2_subdev *sd,
 			      struct v4l2_subdev_pad_config *cfg,
 			      struct v4l2_subdev_mbus_code_enum *code);
@@ -798,7 +801,15 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
 				      struct v4l2_subdev_format *source_fmt,
 				      struct v4l2_subdev_format *sink_fmt);
 int v4l2_subdev_link_validate(struct media_link *link);
+
+struct v4l2_subdev_pad_config *v4l2_subdev_alloc_pad_config(struct v4l2_subdev *sd);
+
+static inline void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg)
+{
+	kfree(cfg);
+}
 #endif /* CONFIG_MEDIA_CONTROLLER */
+
 void v4l2_subdev_init(struct v4l2_subdev *sd,
 		      const struct v4l2_subdev_ops *ops);
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 30/48] v4l: subdev: Call pad init_cfg operation when opening subdevs
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The subdev core code currently rely on the subdev open handler to
initialize the file handle's pad configuration, even though subdevs now
have a pad operation dedicated for that purpose.

As a first step towards migration to init_cfg, call the operation
operation in the subdev core open implementation. Subdevs that are
haven't been moved to init_cfg yet will just continue implementing pad
config initialization in their open handler.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 951a9cf7b47e..c9f507afe5ec 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -83,6 +83,8 @@ static int subdev_open(struct file *file)
 	}
 #endif
 
+	v4l2_subdev_call(sd, pad, init_cfg, subdev_fh->pad);
+
 	if (sd->internal_ops && sd->internal_ops->open) {
 		ret = sd->internal_ops->open(sd, subdev_fh);
 		if (ret < 0)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 30/48] v4l: subdev: Call pad init_cfg operation when opening subdevs
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The subdev core code currently rely on the subdev open handler to
initialize the file handle's pad configuration, even though subdevs now
have a pad operation dedicated for that purpose.

As a first step towards migration to init_cfg, call the operation
operation in the subdev core open implementation. Subdevs that are
haven't been moved to init_cfg yet will just continue implementing pad
config initialization in their open handler.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 951a9cf7b47e..c9f507afe5ec 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -83,6 +83,8 @@ static int subdev_open(struct file *file)
 	}
 #endif
 
+	v4l2_subdev_call(sd, pad, init_cfg, subdev_fh->pad);
+
 	if (sd->internal_ops && sd->internal_ops->open) {
 		ret = sd->internal_ops->open(sd, subdev_fh);
 		if (ret < 0)
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 31/48] v4l: subdev: Support the request API in format and selection operations
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Store the formats and selection rectangles in per-entity request data.
This minimizes changes to drivers by reusing the v4l2_subdev_pad_config
infrastructure.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 225 +++++++++++++++++++++++++---------
 include/media/v4l2-subdev.h           |  11 ++
 2 files changed, 181 insertions(+), 55 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index c9f507afe5ec..cea6a549ee1c 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -128,39 +128,184 @@ static int subdev_close(struct file *file)
 }
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
-			struct v4l2_subdev_format *format)
+static void subdev_request_data_release(struct media_entity_request_data *data)
 {
-	if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
+	struct v4l2_subdev_request_data *sddata +		to_v4l2_subdev_request_data(data);
 
-	if (format->pad >= sd->entity.num_pads)
-		return -EINVAL;
+	kfree(sddata->pad);
+	kfree(sddata);
+}
 
-	return 0;
+static struct v4l2_subdev_pad_config *
+subdev_request_pad_config(struct v4l2_subdev *sd,
+			  struct media_device_request *req)
+{
+	struct media_entity_request_data *data;
+	struct v4l2_subdev_request_data *sddata;
+
+	data = media_device_request_get_entity_data(req, &sd->entity);
+	if (data) {
+		sddata = to_v4l2_subdev_request_data(data);
+		return sddata->pad;
+	}
+
+	sddata = kzalloc(sizeof(*sddata), GFP_KERNEL);
+	if (!sddata)
+		return ERR_PTR(-ENOMEM);
+
+	sddata->data.release = subdev_request_data_release;
+
+	sddata->pad = v4l2_subdev_alloc_pad_config(sd);
+	if (sddata->pad = NULL) {
+		kfree(sddata);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	media_device_request_set_entity_data(req, &sd->entity, &sddata->data);
+
+	return sddata->pad;
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int subdev_prepare_pad_config(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_fh *fh,
+				     enum v4l2_subdev_format_whence which,
+				     unsigned int pad, unsigned int req_id,
+				     struct media_device_request **_req,
+				     struct v4l2_subdev_pad_config **_cfg)
 {
-	if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+
+	if (pad >= sd->entity.num_pads)
 		return -EINVAL;
 
-	if (crop->pad >= sd->entity.num_pads)
+
+	if (which = V4L2_SUBDEV_FORMAT_ACTIVE) {
+		*_req = NULL;
+		*_cfg = NULL;
+		return 0;
+	}
+
+	if (which = V4L2_SUBDEV_FORMAT_TRY) {
+		*_req = NULL;
+		*_cfg = fh->pad;
+		return 0;
+	}
+
+	if (which != V4L2_SUBDEV_FORMAT_REQUEST)
 		return -EINVAL;
 
+	if (!sd->v4l2_dev->mdev)
+		return -EINVAL;
+
+	req = media_device_request_find(sd->v4l2_dev->mdev, req_id);
+	if (!req)
+		return -EINVAL;
+
+	cfg = subdev_request_pad_config(sd, req);
+	if (IS_ERR(cfg)) {
+		media_device_request_put(req);
+		return PTR_ERR(cfg);
+	}
+
+	*_req = req;
+	*_cfg = cfg;
+
 	return 0;
 }
 
-static int check_selection(struct v4l2_subdev *sd,
-			   struct v4l2_subdev_selection *sel)
+static int subdev_get_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *format)
 {
-	if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, format->which, format->pad,
+					format->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, cfg, format);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int subdev_set_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *format)
+{
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, format->which, format->pad,
+					format->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, set_fmt, cfg, format);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int subdev_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, sel->which, sel->pad,
+					sel->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_selection, cfg, sel);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int subdev_set_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, sel->which, sel->pad,
+					sel->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, set_selection, cfg, sel);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+{
+	if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
+	    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
 		return -EINVAL;
 
-	if (sel->pad >= sd->entity.num_pads)
+	if (crop->pad >= sd->entity.num_pads)
 		return -EINVAL;
 
 	return 0;
@@ -256,25 +401,11 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	}
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	case VIDIOC_SUBDEV_G_FMT: {
-		struct v4l2_subdev_format *format = arg;
+	case VIDIOC_SUBDEV_G_FMT:
+		return subdev_get_format(sd, subdev_fh, arg);
 
-		rval = check_format(sd, format);
-		if (rval)
-			return rval;
-
-		return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
-	}
-
-	case VIDIOC_SUBDEV_S_FMT: {
-		struct v4l2_subdev_format *format = arg;
-
-		rval = check_format(sd, format);
-		if (rval)
-			return rval;
-
-		return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
-	}
+	case VIDIOC_SUBDEV_S_FMT:
+		return subdev_set_format(sd, subdev_fh, arg);
 
 	case VIDIOC_SUBDEV_G_CROP: {
 		struct v4l2_subdev_crop *crop = arg;
@@ -379,27 +510,11 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 					fie);
 	}
 
-	case VIDIOC_SUBDEV_G_SELECTION: {
-		struct v4l2_subdev_selection *sel = arg;
-
-		rval = check_selection(sd, sel);
-		if (rval)
-			return rval;
-
-		return v4l2_subdev_call(
-			sd, pad, get_selection, subdev_fh->pad, sel);
-	}
-
-	case VIDIOC_SUBDEV_S_SELECTION: {
-		struct v4l2_subdev_selection *sel = arg;
-
-		rval = check_selection(sd, sel);
-		if (rval)
-			return rval;
+	case VIDIOC_SUBDEV_G_SELECTION:
+		return subdev_get_selection(sd, subdev_fh, arg);
 
-		return v4l2_subdev_call(
-			sd, pad, set_selection, subdev_fh->pad, sel);
-	}
+	case VIDIOC_SUBDEV_S_SELECTION:
+		return subdev_set_selection(sd, subdev_fh, arg);
 
 	case VIDIOC_G_EDID: {
 		struct v4l2_subdev_edid *edid = arg;
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c97935455669..c3437776cb5f 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -808,6 +808,17 @@ static inline void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cf
 {
 	kfree(cfg);
 }
+
+struct v4l2_subdev_request_data {
+	struct media_entity_request_data data;
+	struct v4l2_subdev_pad_config *pad;
+};
+
+static inline struct v4l2_subdev_request_data *
+to_v4l2_subdev_request_data(struct media_entity_request_data *data)
+{
+	return container_of(data, struct v4l2_subdev_request_data, data);
+}
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 void v4l2_subdev_init(struct v4l2_subdev *sd,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 31/48] v4l: subdev: Support the request API in format and selection operations
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Store the formats and selection rectangles in per-entity request data.
This minimizes changes to drivers by reusing the v4l2_subdev_pad_config
infrastructure.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/v4l2-subdev.c | 225 +++++++++++++++++++++++++---------
 include/media/v4l2-subdev.h           |  11 ++
 2 files changed, 181 insertions(+), 55 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index c9f507afe5ec..cea6a549ee1c 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -128,39 +128,184 @@ static int subdev_close(struct file *file)
 }
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
-			struct v4l2_subdev_format *format)
+static void subdev_request_data_release(struct media_entity_request_data *data)
 {
-	if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-		return -EINVAL;
+	struct v4l2_subdev_request_data *sddata =
+		to_v4l2_subdev_request_data(data);
 
-	if (format->pad >= sd->entity.num_pads)
-		return -EINVAL;
+	kfree(sddata->pad);
+	kfree(sddata);
+}
 
-	return 0;
+static struct v4l2_subdev_pad_config *
+subdev_request_pad_config(struct v4l2_subdev *sd,
+			  struct media_device_request *req)
+{
+	struct media_entity_request_data *data;
+	struct v4l2_subdev_request_data *sddata;
+
+	data = media_device_request_get_entity_data(req, &sd->entity);
+	if (data) {
+		sddata = to_v4l2_subdev_request_data(data);
+		return sddata->pad;
+	}
+
+	sddata = kzalloc(sizeof(*sddata), GFP_KERNEL);
+	if (!sddata)
+		return ERR_PTR(-ENOMEM);
+
+	sddata->data.release = subdev_request_data_release;
+
+	sddata->pad = v4l2_subdev_alloc_pad_config(sd);
+	if (sddata->pad == NULL) {
+		kfree(sddata);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	media_device_request_set_entity_data(req, &sd->entity, &sddata->data);
+
+	return sddata->pad;
 }
 
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int subdev_prepare_pad_config(struct v4l2_subdev *sd,
+				     struct v4l2_subdev_fh *fh,
+				     enum v4l2_subdev_format_whence which,
+				     unsigned int pad, unsigned int req_id,
+				     struct media_device_request **_req,
+				     struct v4l2_subdev_pad_config **_cfg)
 {
-	if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+
+	if (pad >= sd->entity.num_pads)
 		return -EINVAL;
 
-	if (crop->pad >= sd->entity.num_pads)
+
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		*_req = NULL;
+		*_cfg = NULL;
+		return 0;
+	}
+
+	if (which == V4L2_SUBDEV_FORMAT_TRY) {
+		*_req = NULL;
+		*_cfg = fh->pad;
+		return 0;
+	}
+
+	if (which != V4L2_SUBDEV_FORMAT_REQUEST)
 		return -EINVAL;
 
+	if (!sd->v4l2_dev->mdev)
+		return -EINVAL;
+
+	req = media_device_request_find(sd->v4l2_dev->mdev, req_id);
+	if (!req)
+		return -EINVAL;
+
+	cfg = subdev_request_pad_config(sd, req);
+	if (IS_ERR(cfg)) {
+		media_device_request_put(req);
+		return PTR_ERR(cfg);
+	}
+
+	*_req = req;
+	*_cfg = cfg;
+
 	return 0;
 }
 
-static int check_selection(struct v4l2_subdev *sd,
-			   struct v4l2_subdev_selection *sel)
+static int subdev_get_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *format)
 {
-	if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-	    sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, format->which, format->pad,
+					format->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_fmt, cfg, format);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int subdev_set_format(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_fh *fh,
+			     struct v4l2_subdev_format *format)
+{
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, format->which, format->pad,
+					format->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, set_fmt, cfg, format);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int subdev_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, sel->which, sel->pad,
+					sel->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, get_selection, cfg, sel);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int subdev_set_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_selection *sel)
+{
+	struct v4l2_subdev_pad_config *cfg;
+	struct media_device_request *req;
+	int ret;
+
+	ret = subdev_prepare_pad_config(sd, fh, sel->which, sel->pad,
+					sel->request, &req, &cfg);
+	if (ret < 0)
+		return ret;
+
+	ret = v4l2_subdev_call(sd, pad, set_selection, cfg, sel);
+
+	if (req)
+		media_device_request_put(req);
+
+	return ret;
+}
+
+static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+{
+	if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
+	    crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
 		return -EINVAL;
 
-	if (sel->pad >= sd->entity.num_pads)
+	if (crop->pad >= sd->entity.num_pads)
 		return -EINVAL;
 
 	return 0;
@@ -256,25 +401,11 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 	}
 
 #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-	case VIDIOC_SUBDEV_G_FMT: {
-		struct v4l2_subdev_format *format = arg;
+	case VIDIOC_SUBDEV_G_FMT:
+		return subdev_get_format(sd, subdev_fh, arg);
 
-		rval = check_format(sd, format);
-		if (rval)
-			return rval;
-
-		return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format);
-	}
-
-	case VIDIOC_SUBDEV_S_FMT: {
-		struct v4l2_subdev_format *format = arg;
-
-		rval = check_format(sd, format);
-		if (rval)
-			return rval;
-
-		return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format);
-	}
+	case VIDIOC_SUBDEV_S_FMT:
+		return subdev_set_format(sd, subdev_fh, arg);
 
 	case VIDIOC_SUBDEV_G_CROP: {
 		struct v4l2_subdev_crop *crop = arg;
@@ -379,27 +510,11 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 					fie);
 	}
 
-	case VIDIOC_SUBDEV_G_SELECTION: {
-		struct v4l2_subdev_selection *sel = arg;
-
-		rval = check_selection(sd, sel);
-		if (rval)
-			return rval;
-
-		return v4l2_subdev_call(
-			sd, pad, get_selection, subdev_fh->pad, sel);
-	}
-
-	case VIDIOC_SUBDEV_S_SELECTION: {
-		struct v4l2_subdev_selection *sel = arg;
-
-		rval = check_selection(sd, sel);
-		if (rval)
-			return rval;
+	case VIDIOC_SUBDEV_G_SELECTION:
+		return subdev_get_selection(sd, subdev_fh, arg);
 
-		return v4l2_subdev_call(
-			sd, pad, set_selection, subdev_fh->pad, sel);
-	}
+	case VIDIOC_SUBDEV_S_SELECTION:
+		return subdev_set_selection(sd, subdev_fh, arg);
 
 	case VIDIOC_G_EDID: {
 		struct v4l2_subdev_edid *edid = arg;
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c97935455669..c3437776cb5f 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -808,6 +808,17 @@ static inline void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cf
 {
 	kfree(cfg);
 }
+
+struct v4l2_subdev_request_data {
+	struct media_entity_request_data data;
+	struct v4l2_subdev_pad_config *pad;
+};
+
+static inline struct v4l2_subdev_request_data *
+to_v4l2_subdev_request_data(struct media_entity_request_data *data)
+{
+	return container_of(data, struct v4l2_subdev_request_data, data);
+}
 #endif /* CONFIG_MEDIA_CONTROLLER */
 
 void v4l2_subdev_init(struct v4l2_subdev *sd,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 32/48] vb2: Add allow_requests flag
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Hans Verkuil <hans.verkuil@cisco.com>

The driver has to set allow_requests explicitly in order to allow
queuing or preparing buffers for a specific request ID.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/videobuf2-v4l2.c | 5 +++++
 include/media/videobuf2-core.h           | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index f6a2800e5f66..2c8776891535 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -169,6 +169,11 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
 		return -EINVAL;
 	}
 
+	if (!q->allow_requests && b->request) {
+		dprintk(1, "%s: unsupported request ID\n", opname);
+		return -EINVAL;
+	}
+
 	return __verify_planes_array(q->bufs[b->index], b);
 }
 
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 647ebfe5174f..5eb30071dcf1 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -379,6 +379,7 @@ struct vb2_buf_ops {
  * @fileio_read_once:		report EOF after reading the first buffer
  * @fileio_write_immediately:	queue buffer after each write() call
  * @allow_zero_bytesused:	allow bytesused = 0 to be passed to the driver
+ * @allow_requests:		allow request != 0 to be passed to the driver
  * @lock:	pointer to a mutex that protects the vb2_queue struct. The
  *		driver can set this to a mutex to let the v4l2 core serialize
  *		the queuing ioctls. If the driver wants to handle locking
@@ -441,6 +442,7 @@ struct vb2_queue {
 	unsigned			fileio_read_once:1;
 	unsigned			fileio_write_immediately:1;
 	unsigned			allow_zero_bytesused:1;
+	unsigned			allow_requests:1;
 
 	struct mutex			*lock;
 	void				*owner;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 32/48] vb2: Add allow_requests flag
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Hans Verkuil <hans.verkuil@cisco.com>

The driver has to set allow_requests explicitly in order to allow
queuing or preparing buffers for a specific request ID.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/videobuf2-v4l2.c | 5 +++++
 include/media/videobuf2-core.h           | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index f6a2800e5f66..2c8776891535 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -169,6 +169,11 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
 		return -EINVAL;
 	}
 
+	if (!q->allow_requests && b->request) {
+		dprintk(1, "%s: unsupported request ID\n", opname);
+		return -EINVAL;
+	}
+
 	return __verify_planes_array(q->bufs[b->index], b);
 }
 
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 647ebfe5174f..5eb30071dcf1 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -379,6 +379,7 @@ struct vb2_buf_ops {
  * @fileio_read_once:		report EOF after reading the first buffer
  * @fileio_write_immediately:	queue buffer after each write() call
  * @allow_zero_bytesused:	allow bytesused == 0 to be passed to the driver
+ * @allow_requests:		allow request != 0 to be passed to the driver
  * @lock:	pointer to a mutex that protects the vb2_queue struct. The
  *		driver can set this to a mutex to let the v4l2 core serialize
  *		the queuing ioctls. If the driver wants to handle locking
@@ -441,6 +442,7 @@ struct vb2_queue {
 	unsigned			fileio_read_once:1;
 	unsigned			fileio_write_immediately:1;
 	unsigned			allow_zero_bytesused:1;
+	unsigned			allow_requests:1;
 
 	struct mutex			*lock;
 	void				*owner;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 33/48] vb2: Add helper function to check for request buffers
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The vb2_queue_has_request() function will check whether a buffer has
been prepared for the given request ID.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/videobuf2-v4l2.c | 17 +++++++++++++++++
 include/media/videobuf2-v4l2.h           |  2 ++
 2 files changed, 19 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 2c8776891535..0db7d67092ab 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -753,6 +753,23 @@ void vb2_queue_release(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
+bool vb2_queue_has_request(struct vb2_queue *q, unsigned int request)
+{
+	unsigned int i;
+
+	for (i = 0; i < q->num_buffers; i++) {
+		struct vb2_buffer *vb = q->bufs[i];
+		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+		if (vb->state = VB2_BUF_STATE_PREPARED &&
+		    vbuf->request = request)
+			return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_has_request);
+
 /**
  * vb2_poll() - implements poll userspace operation
  * @q:		videobuf2 queue
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 48d6a34dcdb4..7cb428fc66ad 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -68,6 +68,8 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
 int __must_check vb2_queue_init(struct vb2_queue *q);
 void vb2_queue_release(struct vb2_queue *q);
 
+bool vb2_queue_has_request(struct vb2_queue *q, unsigned int request);
+
 unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
 size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
 		loff_t *ppos, int nonblock);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 33/48] vb2: Add helper function to check for request buffers
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The vb2_queue_has_request() function will check whether a buffer has
been prepared for the given request ID.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/v4l2-core/videobuf2-v4l2.c | 17 +++++++++++++++++
 include/media/videobuf2-v4l2.h           |  2 ++
 2 files changed, 19 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 2c8776891535..0db7d67092ab 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -753,6 +753,23 @@ void vb2_queue_release(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
+bool vb2_queue_has_request(struct vb2_queue *q, unsigned int request)
+{
+	unsigned int i;
+
+	for (i = 0; i < q->num_buffers; i++) {
+		struct vb2_buffer *vb = q->bufs[i];
+		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+		if (vb->state == VB2_BUF_STATE_PREPARED &&
+		    vbuf->request == request)
+			return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(vb2_queue_has_request);
+
 /**
  * vb2_poll() - implements poll userspace operation
  * @q:		videobuf2 queue
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 48d6a34dcdb4..7cb428fc66ad 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -68,6 +68,8 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
 int __must_check vb2_queue_init(struct vb2_queue *q);
 void vb2_queue_release(struct vb2_queue *q);
 
+bool vb2_queue_has_request(struct vb2_queue *q, unsigned int request);
+
 unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
 size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
 		loff_t *ppos, int nonblock);
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 34/48] vb2: Add helper function to queue request-specific buffer.
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Hans Verkuil <hans.verkuil@cisco.com>

The vb2_qbuf_request() function will queue any buffers for the given request
that are in state PREPARED.

Useful when drivers have to implement the req_queue callback.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/videobuf2-v4l2.c | 31 +++++++++++++++++++++++++++++++
 include/media/videobuf2-v4l2.h           |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 0db7d67092ab..1f649b15990f 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -113,6 +113,9 @@ static int __set_timestamp(struct vb2_buffer *vb, const void *pb)
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct vb2_queue *q = vb->vb2_queue;
 
+	if (!pb)
+		return 0;
+
 	if (q->is_output) {
 		/*
 		 * For output buffers copy the timestamp if needed,
@@ -188,6 +191,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned int plane;
 
+	if (!pb)
+		return 0;
+
 	/* Copy back data such as timestamp, flags, etc. */
 	b->index = vb->index;
 	b->type = vb->type;
@@ -578,6 +584,31 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 }
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
+int vb2_qbuf_request(struct vb2_queue *q, u16 request, struct vb2_buffer **p_buf)
+{
+	unsigned int buffer;
+
+	for (buffer = 0; buffer < q->num_buffers; buffer++) {
+		struct vb2_buffer *vb = q->bufs[buffer];
+		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+		if (vbuf->request = request &&
+		    vb->state = VB2_BUF_STATE_PREPARED) {
+			if (p_buf)
+				*p_buf = vb;
+			/*
+			 * The buffer has already been prepared so we can skip
+			 * the vb2_queue_or_prepare_buf() call in vb2_qbuf() and
+			 * call the core function directly.
+			 */
+			return vb2_core_qbuf(q, vb->index, NULL);
+		}
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(vb2_qbuf_request);
+
 static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
 		bool nonblocking)
 {
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 7cb428fc66ad..bc742a174f2b 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -59,6 +59,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create);
 int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
 
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_qbuf_request(struct vb2_queue *q, u16 request, struct vb2_buffer **p_buf);
 int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb);
 int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 34/48] vb2: Add helper function to queue request-specific buffer.
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

From: Hans Verkuil <hans.verkuil@cisco.com>

The vb2_qbuf_request() function will queue any buffers for the given request
that are in state PREPARED.

Useful when drivers have to implement the req_queue callback.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/videobuf2-v4l2.c | 31 +++++++++++++++++++++++++++++++
 include/media/videobuf2-v4l2.h           |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 0db7d67092ab..1f649b15990f 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -113,6 +113,9 @@ static int __set_timestamp(struct vb2_buffer *vb, const void *pb)
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct vb2_queue *q = vb->vb2_queue;
 
+	if (!pb)
+		return 0;
+
 	if (q->is_output) {
 		/*
 		 * For output buffers copy the timestamp if needed,
@@ -188,6 +191,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned int plane;
 
+	if (!pb)
+		return 0;
+
 	/* Copy back data such as timestamp, flags, etc. */
 	b->index = vb->index;
 	b->type = vb->type;
@@ -578,6 +584,31 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 }
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
+int vb2_qbuf_request(struct vb2_queue *q, u16 request, struct vb2_buffer **p_buf)
+{
+	unsigned int buffer;
+
+	for (buffer = 0; buffer < q->num_buffers; buffer++) {
+		struct vb2_buffer *vb = q->bufs[buffer];
+		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+		if (vbuf->request == request &&
+		    vb->state == VB2_BUF_STATE_PREPARED) {
+			if (p_buf)
+				*p_buf = vb;
+			/*
+			 * The buffer has already been prepared so we can skip
+			 * the vb2_queue_or_prepare_buf() call in vb2_qbuf() and
+			 * call the core function directly.
+			 */
+			return vb2_core_qbuf(q, vb->index, NULL);
+		}
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(vb2_qbuf_request);
+
 static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
 		bool nonblocking)
 {
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 7cb428fc66ad..bc742a174f2b 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -59,6 +59,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create);
 int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
 
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_qbuf_request(struct vb2_queue *q, u16 request, struct vb2_buffer **p_buf);
 int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb);
 int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 35/48] DocBook: media: Document the media request API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The media request API is made of a new ioctl to implement request
management. Document it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 .../DocBook/media/v4l/media-controller.xml         |   1 +
 .../DocBook/media/v4l/media-ioc-request-cmd.xml    | 194 +++++++++++++++++++++
 2 files changed, 195 insertions(+)
 create mode 100644 Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml

diff --git a/Documentation/DocBook/media/v4l/media-controller.xml b/Documentation/DocBook/media/v4l/media-controller.xml
index 873ac3a621f0..09be5231fd88 100644
--- a/Documentation/DocBook/media/v4l/media-controller.xml
+++ b/Documentation/DocBook/media/v4l/media-controller.xml
@@ -85,5 +85,6 @@
   &sub-media-ioc-device-info;
   &sub-media-ioc-enum-entities;
   &sub-media-ioc-enum-links;
+  &sub-media-ioc-request-cmd;
   &sub-media-ioc-setup-link;
 </appendix>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml b/Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml
new file mode 100644
index 000000000000..202b248c872c
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml
@@ -0,0 +1,194 @@
+<refentry id="media-ioc-request-cmd">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_REQUEST_CMD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_REQUEST_CMD</refname>
+    <refpurpose>Manage media device requests</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct media_request_cmd *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>File descriptor returned by
+	  <link linkend='media-func-open'><function>open()</function></link>.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>MEDIA_IOC_REQUEST_CMD</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The MEDIA_IOC_REQUEST_CMD ioctl allow applications to manage media
+    device requests. A request is an object that can group media device
+    configuration parameters, including subsystem-specific parameters, in order
+    to apply all the parameters atomically. Applications are responsible for
+    allocating and deleting requests, filling them with configuration parameters
+    and (synchronously) applying or (asynchronously) queuing them.</para>
+
+    <para>Request operations are performed by calling the MEDIA_IOC_REQUEST_CMD
+    ioctl with a pointer to a &media-request-cmd; with the
+    <structfield>cmd</structfield> set to the appropriate command.
+    <xref linkend="media-request-commands" /> lists the commands supported by
+    the ioctl.</para>
+
+    <para>The &media-request-cmd; <structfield>request</structfield> field
+    contains the ID of the request on which the command operates. For the
+    <constant>MEDIA_REQ_CMD_ALLOC</constant> command the field is set to zero
+    by applications and filled by the driver. For all other commands the field
+    is set by applications and left untouched by the driver.</para>
+
+    <para>To allocate a new request applications use the
+    <constant>MEDIA_REQ_CMD_ALLOC</constant>. The driver will allocate a new
+    request and return its ID in the <structfield>request</structfield> field.
+    </para>
+
+    <para>Requests are reference-counted. A newly allocate request is referenced
+    by the media device file handled on which it has been created, and can be
+    later referenced by subsystem-specific operations using the request ID.
+    Requests will thus be automatically deleted when they're not longer used
+    after the media device file handle is closed.</para>
+
+    <para>If a request isn't needed applications can delete it using the
+    <constant>MEDIA_REQ_CMD_DELETE</constant> command. The driver will drop the
+    reference to the request stored in the media device file handle. The request
+    will not be usable through the MEDIA_IOC_REQUEST_CMD ioctl anymore, but will
+    only be deleted when the last reference is released. If no other reference
+    exists when the delete command is invoked the request will be deleted
+    immediately.</para>
+
+    <para>After creating a request applications should fill it with
+    configuration parameters. This is performed through subsystem-specific
+    request APIs outside the scope of the media controller API. See the
+    appropriate subsystem APIs for more information, including how they interact
+    with the MEDIA_IOC_REQUEST_CMD ioctl.</para>
+
+    <para>Once a request contains all the desired configuration parameters it
+    can be applied synchronously or queued asynchronously. To apply a request
+    applications use the <constant>MEDIA_REQ_CMD_APPLY</constant> command. The
+    driver will apply all configuration parameters stored in the request to the
+    device atomically. The ioctl will return once all parameters have been
+    applied, but it should be noted that they might not have fully taken effect
+    yet.</para>
+
+    <para>To queue a request applications use the
+    <constant>MEDIA_REQ_CMD_QUEUE</constant> command. The driver will queue the
+    request for processing and return immediately. The request will then be
+    processed and applied after all previously queued requests.</para>
+
+    <para>Once a request has been queued applications are not allowed to modify
+    its configuration parameters until the request has been fully processed.
+    Any attempt to do so will result in the related subsystem API returning
+    an error. The media device request API doesn't notify applications of
+    request processing completion, this is left to the other subsystems APIs to
+    implement.</para>
+
+    <table pgwide="1" frame="none" id="media-request-cmd">
+      <title>struct <structname>media_request_cmd</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>cmd</structfield></entry>
+	    <entry>Command, set by the application. See
+	    <xref linkend="media-request-commands" /> for the list of supported
+	    commands.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry>Request ID, set by the driver for the
+	    <constant>MEDIA_REQ_CMD_ALLOC</constant> and by the application
+	    for all other commands.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[10]</entry>
+	    <entry>Reserved for future extensions. Drivers and applications must
+	    set this array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-request-commands">
+      <title>Media request commands</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_ALLOC</constant></entry>
+	    <entry>Allocate a new request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_DELETE</constant></entry>
+	    <entry>Delete a request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_APPLY</constant></entry>
+	    <entry>Apply all settings from a request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_QUEUE</constant></entry>
+	    <entry>Queue a request for processing.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The &media-request-cmd; specifies an invalid command or
+	  references a non-existing request.
+	  </para>
+	</listitem>
+	<term><errorcode>ENOSYS</errorcode></term>
+	<listitem>
+	  <para>The &media-request-cmd; specifies the
+	  <constant>MEDIA_REQ_CMD_QUEUE</constant> or
+	  <constant>MEDIA_REQ_CMD_APPLY</constant> and that command isn't
+	  implemented by the device.
+	  </para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 35/48] DocBook: media: Document the media request API
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The media request API is made of a new ioctl to implement request
management. Document it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 .../DocBook/media/v4l/media-controller.xml         |   1 +
 .../DocBook/media/v4l/media-ioc-request-cmd.xml    | 194 +++++++++++++++++++++
 2 files changed, 195 insertions(+)
 create mode 100644 Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml

diff --git a/Documentation/DocBook/media/v4l/media-controller.xml b/Documentation/DocBook/media/v4l/media-controller.xml
index 873ac3a621f0..09be5231fd88 100644
--- a/Documentation/DocBook/media/v4l/media-controller.xml
+++ b/Documentation/DocBook/media/v4l/media-controller.xml
@@ -85,5 +85,6 @@
   &sub-media-ioc-device-info;
   &sub-media-ioc-enum-entities;
   &sub-media-ioc-enum-links;
+  &sub-media-ioc-request-cmd;
   &sub-media-ioc-setup-link;
 </appendix>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml b/Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml
new file mode 100644
index 000000000000..202b248c872c
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/media-ioc-request-cmd.xml
@@ -0,0 +1,194 @@
+<refentry id="media-ioc-request-cmd">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_REQUEST_CMD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_REQUEST_CMD</refname>
+    <refpurpose>Manage media device requests</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct media_request_cmd *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>File descriptor returned by
+	  <link linkend='media-func-open'><function>open()</function></link>.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>MEDIA_IOC_REQUEST_CMD</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The MEDIA_IOC_REQUEST_CMD ioctl allow applications to manage media
+    device requests. A request is an object that can group media device
+    configuration parameters, including subsystem-specific parameters, in order
+    to apply all the parameters atomically. Applications are responsible for
+    allocating and deleting requests, filling them with configuration parameters
+    and (synchronously) applying or (asynchronously) queuing them.</para>
+
+    <para>Request operations are performed by calling the MEDIA_IOC_REQUEST_CMD
+    ioctl with a pointer to a &media-request-cmd; with the
+    <structfield>cmd</structfield> set to the appropriate command.
+    <xref linkend="media-request-commands" /> lists the commands supported by
+    the ioctl.</para>
+
+    <para>The &media-request-cmd; <structfield>request</structfield> field
+    contains the ID of the request on which the command operates. For the
+    <constant>MEDIA_REQ_CMD_ALLOC</constant> command the field is set to zero
+    by applications and filled by the driver. For all other commands the field
+    is set by applications and left untouched by the driver.</para>
+
+    <para>To allocate a new request applications use the
+    <constant>MEDIA_REQ_CMD_ALLOC</constant>. The driver will allocate a new
+    request and return its ID in the <structfield>request</structfield> field.
+    </para>
+
+    <para>Requests are reference-counted. A newly allocate request is referenced
+    by the media device file handled on which it has been created, and can be
+    later referenced by subsystem-specific operations using the request ID.
+    Requests will thus be automatically deleted when they're not longer used
+    after the media device file handle is closed.</para>
+
+    <para>If a request isn't needed applications can delete it using the
+    <constant>MEDIA_REQ_CMD_DELETE</constant> command. The driver will drop the
+    reference to the request stored in the media device file handle. The request
+    will not be usable through the MEDIA_IOC_REQUEST_CMD ioctl anymore, but will
+    only be deleted when the last reference is released. If no other reference
+    exists when the delete command is invoked the request will be deleted
+    immediately.</para>
+
+    <para>After creating a request applications should fill it with
+    configuration parameters. This is performed through subsystem-specific
+    request APIs outside the scope of the media controller API. See the
+    appropriate subsystem APIs for more information, including how they interact
+    with the MEDIA_IOC_REQUEST_CMD ioctl.</para>
+
+    <para>Once a request contains all the desired configuration parameters it
+    can be applied synchronously or queued asynchronously. To apply a request
+    applications use the <constant>MEDIA_REQ_CMD_APPLY</constant> command. The
+    driver will apply all configuration parameters stored in the request to the
+    device atomically. The ioctl will return once all parameters have been
+    applied, but it should be noted that they might not have fully taken effect
+    yet.</para>
+
+    <para>To queue a request applications use the
+    <constant>MEDIA_REQ_CMD_QUEUE</constant> command. The driver will queue the
+    request for processing and return immediately. The request will then be
+    processed and applied after all previously queued requests.</para>
+
+    <para>Once a request has been queued applications are not allowed to modify
+    its configuration parameters until the request has been fully processed.
+    Any attempt to do so will result in the related subsystem API returning
+    an error. The media device request API doesn't notify applications of
+    request processing completion, this is left to the other subsystems APIs to
+    implement.</para>
+
+    <table pgwide="1" frame="none" id="media-request-cmd">
+      <title>struct <structname>media_request_cmd</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>cmd</structfield></entry>
+	    <entry>Command, set by the application. See
+	    <xref linkend="media-request-commands" /> for the list of supported
+	    commands.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry>Request ID, set by the driver for the
+	    <constant>MEDIA_REQ_CMD_ALLOC</constant> and by the application
+	    for all other commands.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[10]</entry>
+	    <entry>Reserved for future extensions. Drivers and applications must
+	    set this array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-request-commands">
+      <title>Media request commands</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_ALLOC</constant></entry>
+	    <entry>Allocate a new request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_DELETE</constant></entry>
+	    <entry>Delete a request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_APPLY</constant></entry>
+	    <entry>Apply all settings from a request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>MEDIA_REQ_CMD_QUEUE</constant></entry>
+	    <entry>Queue a request for processing.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The &media-request-cmd; specifies an invalid command or
+	  references a non-existing request.
+	  </para>
+	</listitem>
+	<term><errorcode>ENOSYS</errorcode></term>
+	<listitem>
+	  <para>The &media-request-cmd; specifies the
+	  <constant>MEDIA_REQ_CMD_QUEUE</constant> or
+	  <constant>MEDIA_REQ_CMD_APPLY</constant> and that command isn't
+	  implemented by the device.
+	  </para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 36/48] DocBook: media: Document the V4L2 request API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The V4L2 request API consists in extensions to existing V4L2 ioctls.
Document it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 Documentation/DocBook/media/v4l/common.xml         |  2 +
 Documentation/DocBook/media/v4l/io.xml             | 12 ++-
 Documentation/DocBook/media/v4l/request-api.xml    | 90 ++++++++++++++++++++++
 .../DocBook/media/v4l/vidioc-prepare-buf.xml       |  9 +++
 Documentation/DocBook/media/v4l/vidioc-qbuf.xml    |  6 ++
 5 files changed, 118 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/DocBook/media/v4l/request-api.xml

diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index 8b5e014224d6..30cb0f244f06 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -1073,6 +1073,8 @@ dheight = format.fmt.pix.height;
 
   &sub-selection-api;
 
+  &sub-request-api;
+
   <section id="streaming-par">
     <title>Streaming Parameters</title>
 
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 144158b3a5ac..15ef027809dd 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -838,7 +838,17 @@ is the file descriptor associated with a DMABUF buffer.</entry>
 	    </entry>
 	  </row>
 	  <row>
-	    <entry>__u32</entry>
+	    <entry>__u16</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry></entry>
+	    <entry>ID of the request to associate the buffer to. Set by the
+	    application for &VIDIOC-QBUF; and &VIDIOC-PREPARE-BUF;. Set to zero
+	    by the application and the driver in all other cases. See
+	    <xref linkend="v4l2-requests" /> for more information.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u16</entry>
 	    <entry><structfield>reserved2</structfield></entry>
 	    <entry></entry>
 	    <entry>A place holder for future extensions. Drivers and applications
diff --git a/Documentation/DocBook/media/v4l/request-api.xml b/Documentation/DocBook/media/v4l/request-api.xml
new file mode 100644
index 000000000000..992f25ae59a9
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/request-api.xml
@@ -0,0 +1,90 @@
+<section id="v4l2-requests">
+
+  <title>Experimental API for request handling</title>
+
+  <note>
+    <title>Experimental</title>
+    <para>This is an <link linkend="experimental">experimental</link>
+    interface and may change in the future.</para>
+  </note>
+
+  <section>
+    <title>Introduction</title>
+
+<para>It is often useful to apply certain settings when a buffer is about to be
+filled by the DMA capture of a video capture device, ensuring that those
+settings are applied in time for them to be used with that buffer.</para>
+
+<para>One of the prime use-cases of this is Android's CameraHAL v3 which
+requires per-frame configuration support. Other use-cases are possible as well:
+changing codec settings (bit rate, etc.) starting with a specific buffer,
+preparing a configuration to be applied at a certain time, etc.</para>
+
+<para>The request API is the way V4L2 solves this problem.</para>
+
+  </section>
+
+  <section>
+    <title>Request Objects</title>
+
+<para>At the core of the request API is the request object. Applications store
+configuration parameters such as V4L2 controls, formats and selection rectangles
+in request objects and then associate those request objects for processing with
+specific buffers.</para>
+
+<para>Request objects are created and managed through the media controller
+device node. Details on request object management can be found in the
+<link linkend="media-ioc-request-cmd">media controller request API</link>
+documentation and are outside the scope of the V4L2 request API. Once a request
+object is created it can be referenced by its ID in the V4L2 ioctls that support
+requests.</para>
+
+<para>Applications can store controls, subdev formats and subdev selection
+rectangles in requests. To do so they use the usual V4L2 ioctls
+&VIDIOC-S-EXT-CTRLS;, &VIDIOC-SUBDEV-S-FMT; and &VIDIOC-SUBDEV-S-SELECTION; with
+the <structfield>request</structfield> field of the associated structure set to
+the request ID (for subdev formats and selection rectangles the
+<structfield>which</structfield> field need to be additionally set to
+<constant>V4L2_SUBDEV_FORMAT_REQUEST</constant>). Controls, formats and
+selection rectangles will be processed as usual but will be stored in the
+request instead of applied to the device.
+</para>
+
+<para>Parameters stored in requests can further be retrieved by calling the
+&VIDIOC-G-EXT-CTRLS;, &VIDIOC-SUBDEV-G-FMT; or &VIDIOC-SUBDEV-G-SELECTION;
+ioctls similarly with the <structfield>request</structfield> field of the
+associated structure set to the request ID.
+</para>
+
+  </section>
+
+  <section>
+    <title>Applying Requests</title>
+
+<para>The simplest way to apply a request is to associated it with a buffer.
+This is done by setting the <structfield>request</structfield> field of the
+&v4l2-buffer; to the request ID when queuing the buffer with the &VIDIOC-QBUF;
+ioctl.
+</para>
+
+<para>Once a buffer is queued with a non-zero request ID the driver will apply
+all parameters stored in the request atomically. The parameters are guaranteed
+to come in effect before the buffer starts being transferred and after all
+previous buffers have been complete.
+</para>
+
+<para>For devices with multiple video nodes requests might need to be applied
+synchronously with several buffers. This is achieved by first preparing (but not
+queuing) all the related buffers using the &VIDIOC-PREPARE-BUF; ioctl with the
+<structfield>request</structfield> field of the &v4l2-buffer; set to the request
+ID. Once this is done the request is queued using the
+<constant>MEDIA_REQ_CMD_QUEUE</constant> command of the &MEDIA-IOC-REQUEST-CMD;
+ioctl on the media controller device node. The driver will then queue all
+buffers prepared for the request as if the &VIDIOC-QBUF; ioctl was called on all
+of them and will apply the request parameters atomically and synchronously with
+the transfer of the buffers.
+</para>
+
+  </section>
+
+</section>
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
index fa7ad7e33228..c4726825ed7b 100644
--- a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
@@ -65,6 +65,15 @@ not required, the application can use one of
 <constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
 step.</para>
 
+    <para>Applications can prepare a buffer to be processed for a specific
+request. To do so they set the <structfield>request</structfield> field of the
+struct <structname>v4l2_buffer</structname> to the request ID. The buffer will
+then be automatically queued when the request is processed as if the
+<constant>VIDIOC_QBUF</constant> ioctl was called at that time by the
+application. For more information about requests see
+<xref linkend="v4l2-requests" />.
+</para>
+
     <para>The <structname>v4l2_buffer</structname> structure is
 specified in <xref linkend="buffer" />.</para>
   </refsect1>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
index 8b98a0e421fc..742f1dd3f670 100644
--- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
@@ -80,6 +80,12 @@ to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
 field must be set to the number of elements in that array.
 </para>
 
+    <para>Applications can reference a request to be applied when the buffer is
+processed. To do so they set the <structfield>request</structfield> field of the
+struct <structname>v4l2_buffer</structname> to the request ID. For more
+information about requests see <xref linkend="v4l2-requests" />.
+</para>
+
     <para>To enqueue a <link linkend="mmap">memory mapped</link>
 buffer applications set the <structfield>memory</structfield>
 field to <constant>V4L2_MEMORY_MMAP</constant>. When
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 36/48] DocBook: media: Document the V4L2 request API
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The V4L2 request API consists in extensions to existing V4L2 ioctls.
Document it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 Documentation/DocBook/media/v4l/common.xml         |  2 +
 Documentation/DocBook/media/v4l/io.xml             | 12 ++-
 Documentation/DocBook/media/v4l/request-api.xml    | 90 ++++++++++++++++++++++
 .../DocBook/media/v4l/vidioc-prepare-buf.xml       |  9 +++
 Documentation/DocBook/media/v4l/vidioc-qbuf.xml    |  6 ++
 5 files changed, 118 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/DocBook/media/v4l/request-api.xml

diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index 8b5e014224d6..30cb0f244f06 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -1073,6 +1073,8 @@ dheight = format.fmt.pix.height;
 
   &sub-selection-api;
 
+  &sub-request-api;
+
   <section id="streaming-par">
     <title>Streaming Parameters</title>
 
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 144158b3a5ac..15ef027809dd 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -838,7 +838,17 @@ is the file descriptor associated with a DMABUF buffer.</entry>
 	    </entry>
 	  </row>
 	  <row>
-	    <entry>__u32</entry>
+	    <entry>__u16</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry></entry>
+	    <entry>ID of the request to associate the buffer to. Set by the
+	    application for &VIDIOC-QBUF; and &VIDIOC-PREPARE-BUF;. Set to zero
+	    by the application and the driver in all other cases. See
+	    <xref linkend="v4l2-requests" /> for more information.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u16</entry>
 	    <entry><structfield>reserved2</structfield></entry>
 	    <entry></entry>
 	    <entry>A place holder for future extensions. Drivers and applications
diff --git a/Documentation/DocBook/media/v4l/request-api.xml b/Documentation/DocBook/media/v4l/request-api.xml
new file mode 100644
index 000000000000..992f25ae59a9
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/request-api.xml
@@ -0,0 +1,90 @@
+<section id="v4l2-requests">
+
+  <title>Experimental API for request handling</title>
+
+  <note>
+    <title>Experimental</title>
+    <para>This is an <link linkend="experimental">experimental</link>
+    interface and may change in the future.</para>
+  </note>
+
+  <section>
+    <title>Introduction</title>
+
+<para>It is often useful to apply certain settings when a buffer is about to be
+filled by the DMA capture of a video capture device, ensuring that those
+settings are applied in time for them to be used with that buffer.</para>
+
+<para>One of the prime use-cases of this is Android's CameraHAL v3 which
+requires per-frame configuration support. Other use-cases are possible as well:
+changing codec settings (bit rate, etc.) starting with a specific buffer,
+preparing a configuration to be applied at a certain time, etc.</para>
+
+<para>The request API is the way V4L2 solves this problem.</para>
+
+  </section>
+
+  <section>
+    <title>Request Objects</title>
+
+<para>At the core of the request API is the request object. Applications store
+configuration parameters such as V4L2 controls, formats and selection rectangles
+in request objects and then associate those request objects for processing with
+specific buffers.</para>
+
+<para>Request objects are created and managed through the media controller
+device node. Details on request object management can be found in the
+<link linkend="media-ioc-request-cmd">media controller request API</link>
+documentation and are outside the scope of the V4L2 request API. Once a request
+object is created it can be referenced by its ID in the V4L2 ioctls that support
+requests.</para>
+
+<para>Applications can store controls, subdev formats and subdev selection
+rectangles in requests. To do so they use the usual V4L2 ioctls
+&VIDIOC-S-EXT-CTRLS;, &VIDIOC-SUBDEV-S-FMT; and &VIDIOC-SUBDEV-S-SELECTION; with
+the <structfield>request</structfield> field of the associated structure set to
+the request ID (for subdev formats and selection rectangles the
+<structfield>which</structfield> field need to be additionally set to
+<constant>V4L2_SUBDEV_FORMAT_REQUEST</constant>). Controls, formats and
+selection rectangles will be processed as usual but will be stored in the
+request instead of applied to the device.
+</para>
+
+<para>Parameters stored in requests can further be retrieved by calling the
+&VIDIOC-G-EXT-CTRLS;, &VIDIOC-SUBDEV-G-FMT; or &VIDIOC-SUBDEV-G-SELECTION;
+ioctls similarly with the <structfield>request</structfield> field of the
+associated structure set to the request ID.
+</para>
+
+  </section>
+
+  <section>
+    <title>Applying Requests</title>
+
+<para>The simplest way to apply a request is to associated it with a buffer.
+This is done by setting the <structfield>request</structfield> field of the
+&v4l2-buffer; to the request ID when queuing the buffer with the &VIDIOC-QBUF;
+ioctl.
+</para>
+
+<para>Once a buffer is queued with a non-zero request ID the driver will apply
+all parameters stored in the request atomically. The parameters are guaranteed
+to come in effect before the buffer starts being transferred and after all
+previous buffers have been complete.
+</para>
+
+<para>For devices with multiple video nodes requests might need to be applied
+synchronously with several buffers. This is achieved by first preparing (but not
+queuing) all the related buffers using the &VIDIOC-PREPARE-BUF; ioctl with the
+<structfield>request</structfield> field of the &v4l2-buffer; set to the request
+ID. Once this is done the request is queued using the
+<constant>MEDIA_REQ_CMD_QUEUE</constant> command of the &MEDIA-IOC-REQUEST-CMD;
+ioctl on the media controller device node. The driver will then queue all
+buffers prepared for the request as if the &VIDIOC-QBUF; ioctl was called on all
+of them and will apply the request parameters atomically and synchronously with
+the transfer of the buffers.
+</para>
+
+  </section>
+
+</section>
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
index fa7ad7e33228..c4726825ed7b 100644
--- a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
@@ -65,6 +65,15 @@ not required, the application can use one of
 <constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
 step.</para>
 
+    <para>Applications can prepare a buffer to be processed for a specific
+request. To do so they set the <structfield>request</structfield> field of the
+struct <structname>v4l2_buffer</structname> to the request ID. The buffer will
+then be automatically queued when the request is processed as if the
+<constant>VIDIOC_QBUF</constant> ioctl was called at that time by the
+application. For more information about requests see
+<xref linkend="v4l2-requests" />.
+</para>
+
     <para>The <structname>v4l2_buffer</structname> structure is
 specified in <xref linkend="buffer" />.</para>
   </refsect1>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
index 8b98a0e421fc..742f1dd3f670 100644
--- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
@@ -80,6 +80,12 @@ to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
 field must be set to the number of elements in that array.
 </para>
 
+    <para>Applications can reference a request to be applied when the buffer is
+processed. To do so they set the <structfield>request</structfield> field of the
+struct <structname>v4l2_buffer</structname> to the request ID. For more
+information about requests see <xref linkend="v4l2-requests" />.
+</para>
+
     <para>To enqueue a <link linkend="mmap">memory mapped</link>
 buffer applications set the <structfield>memory</structfield>
 field to <constant>V4L2_MEMORY_MMAP</constant>. When
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 37/48] DocBook: media: Document the subdev selection API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Now that the subdev crop API is considered obsolete, the selection API
that replaces it deserves a full documentation instead of referring to
the crop API documentation.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 .../media/v4l/vidioc-subdev-g-selection.xml        | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
index c62a7360719b..9b59b49db0c3 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -69,6 +69,43 @@
     more information on how each selection target affects the image
     processing pipeline inside the subdevice.</para>
 
+    <para>To retrieve a current selection rectangle applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-selection; to the
+    desired pad number as reported by the media API, the
+    <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant> and the
+    <structfield>target</structfield> to the target selection rectangle. They
+    then call the <constant>VIDIOC_SUBDEV_G_SELECTION</constant> ioctl with a
+    pointer to this structure. The driver fills the members of the
+    <structfield>r</structfield> field or returns &EINVAL; if the input
+    arguments are invalid, or if selection is not supported on the given pad.
+    </para>
+
+    <para>To change a current selection rectangle applications set the
+    <structfield>pad</structfield>, <structfield>which</structfield> and
+    <structfield>target</structfield> fields and all members of the
+    <structfield>r</structfield> field. They then call the
+    <constant>VIDIOC_SUBDEV_S_SELECTION</constant> ioctl with a pointer to this
+    structure. The driver verifies the requested selection rectangle, adjusts it
+    based on the hardware capabilities and configures the device. Upon return
+    the &v4l2-subdev-selection; contains the current selection rectangle as
+    would be returned by a <constant>VIDIOC_SUBDEV_G_SELECTION</constant> call.
+    </para>
+
+    <para>Applications can query the device capabilities by setting the
+    <structfield>which</structfield> to
+    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' selection
+    rectangles are not applied to the device by the driver, but are mangled
+    exactly as active selection rectangles and stored in the sub-device file
+    handle. Two applications querying the same sub-device would thus not
+    interfere with each other.</para>
+
+    <para>Drivers must not return an error solely because the requested
+    selection rectangle doesn't match the device capabilities. They must instead
+    modify the rectangle to match what the hardware can provide. The modified
+    selection rectangle should be as close as possible to the original request.
+    </para>
+
     <refsect2>
       <title>Types of selection targets</title>
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 37/48] DocBook: media: Document the subdev selection API
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Now that the subdev crop API is considered obsolete, the selection API
that replaces it deserves a full documentation instead of referring to
the crop API documentation.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 .../media/v4l/vidioc-subdev-g-selection.xml        | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
index c62a7360719b..9b59b49db0c3 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -69,6 +69,43 @@
     more information on how each selection target affects the image
     processing pipeline inside the subdevice.</para>
 
+    <para>To retrieve a current selection rectangle applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-selection; to the
+    desired pad number as reported by the media API, the
+    <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant> and the
+    <structfield>target</structfield> to the target selection rectangle. They
+    then call the <constant>VIDIOC_SUBDEV_G_SELECTION</constant> ioctl with a
+    pointer to this structure. The driver fills the members of the
+    <structfield>r</structfield> field or returns &EINVAL; if the input
+    arguments are invalid, or if selection is not supported on the given pad.
+    </para>
+
+    <para>To change a current selection rectangle applications set the
+    <structfield>pad</structfield>, <structfield>which</structfield> and
+    <structfield>target</structfield> fields and all members of the
+    <structfield>r</structfield> field. They then call the
+    <constant>VIDIOC_SUBDEV_S_SELECTION</constant> ioctl with a pointer to this
+    structure. The driver verifies the requested selection rectangle, adjusts it
+    based on the hardware capabilities and configures the device. Upon return
+    the &v4l2-subdev-selection; contains the current selection rectangle as
+    would be returned by a <constant>VIDIOC_SUBDEV_G_SELECTION</constant> call.
+    </para>
+
+    <para>Applications can query the device capabilities by setting the
+    <structfield>which</structfield> to
+    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' selection
+    rectangles are not applied to the device by the driver, but are mangled
+    exactly as active selection rectangles and stored in the sub-device file
+    handle. Two applications querying the same sub-device would thus not
+    interfere with each other.</para>
+
+    <para>Drivers must not return an error solely because the requested
+    selection rectangle doesn't match the device capabilities. They must instead
+    modify the rectangle to match what the hardware can provide. The modified
+    selection rectangle should be as close as possible to the original request.
+    </para>
+
     <refsect2>
       <title>Types of selection targets</title>
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 38/48] DocBook: media: Document the V4L2 subdev request API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The V4L2 subdev request API consists in extensions to existing V4L2
subdev ioctls. Document it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 .../DocBook/media/v4l/vidioc-subdev-g-fmt.xml      | 33 ++++++++++++++++++++--
 .../media/v4l/vidioc-subdev-g-selection.xml        | 28 ++++++++++++++++--
 2 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
index a67cde6f8c54..2623e8f52362 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
@@ -97,6 +97,13 @@
     low-pass noise filter might crop pixels at the frame boundaries, modifying
     its output frame size.</para>
 
+    <para>Applications can get and set formats stored in a request by setting
+    the <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant> and the
+    <structfield>request</structfield> to the request ID. See
+    <xref linkend="v4l2-requests" /> for more information about the request
+    API.</para>
+
     <para>Drivers must not return an error solely because the requested format
     doesn't match the device capabilities. They must instead modify the format
     to match what the hardware can provide. The modified format should be as
@@ -124,8 +131,22 @@
 	    linkend="v4l2-mbus-framefmt" /> for details.</entry>
 	  </row>
 	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry>Request ID, only valid when the <structfield>which</structfield>
+	    field is set to <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant>.
+	    Applications and drivers must set the field to zero in all other
+	    cases.</entry>
+	  </row>
+	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>reserved2</structfield></entry>
+	    <entry>Reserved for future extensions. Applications and drivers must
+	    set the field to zero.</entry>
+	  </row>
+	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry><structfield>reserved</structfield>[7]</entry>
 	    <entry>Reserved for future extensions. Applications and drivers must
 	    set the array to zero.</entry>
 	  </row>
@@ -148,6 +169,11 @@
 	    <entry>1</entry>
 	    <entry>Active formats, applied to the hardware.</entry>
 	  </row>
+	  <row>
+	    <entry>V4L2_SUBDEV_FORMAT_REQUEST</entry>
+	    <entry>1</entry>
+	    <entry>Request formats, used with the requests API.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
@@ -171,8 +197,9 @@
 	<term><errorcode>EINVAL</errorcode></term>
 	<listitem>
 	  <para>The &v4l2-subdev-format; <structfield>pad</structfield>
-	  references a non-existing pad, or the <structfield>which</structfield>
-	  field references a non-existing format.</para>
+	  references a non-existing pad, the <structfield>which</structfield>
+	  field references a non-existing format or the request ID references
+	  a nonexistant request.</para>
 	</listitem>
       </varlistentry>
     </variablelist>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
index 9b59b49db0c3..f1f6a31baa63 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -100,6 +100,13 @@
     handle. Two applications querying the same sub-device would thus not
     interfere with each other.</para>
 
+    <para>Applications can get and set selection rectangles stored in a request
+    by setting the <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant> and the
+    <structfield>request</structfield> to the request ID. See
+    <xref linkend="v4l2-requests" /> for more information about the request
+    API.</para>
+
     <para>Drivers must not return an error solely because the requested
     selection rectangle doesn't match the device capabilities. They must instead
     modify the rectangle to match what the hardware can provide. The modified
@@ -160,8 +167,22 @@
 	    <entry>Selection rectangle, in pixels.</entry>
 	  </row>
 	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry>Request ID, only valid when the <structfield>which</structfield>
+	    field is set to <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant>.
+	    Applications and drivers must set the field to zero in all other
+	    cases.</entry>
+	  </row>
+	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>reserved2</structfield></entry>
+	    <entry>Reserved for future extensions. Applications and drivers must
+	    set the field to zero.</entry>
+	  </row>
+	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry><structfield>reserved</structfield>[7]</entry>
 	    <entry>Reserved for future extensions. Applications and drivers must
 	    set the array to zero.</entry>
 	  </row>
@@ -193,8 +214,9 @@
 	  <para>The &v4l2-subdev-selection;
 	  <structfield>pad</structfield> references a non-existing
 	  pad, the <structfield>which</structfield> field references a
-	  non-existing format, or the selection target is not
-	  supported on the given subdev pad.</para>
+	  non-existing format, the selection target is not supported on
+	  the given subdev pad or the request ID references a nonexistant
+	  request.</para>
 	</listitem>
       </varlistentry>
     </variablelist>
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 38/48] DocBook: media: Document the V4L2 subdev request API
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The V4L2 subdev request API consists in extensions to existing V4L2
subdev ioctls. Document it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 .../DocBook/media/v4l/vidioc-subdev-g-fmt.xml      | 33 ++++++++++++++++++++--
 .../media/v4l/vidioc-subdev-g-selection.xml        | 28 ++++++++++++++++--
 2 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
index a67cde6f8c54..2623e8f52362 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
@@ -97,6 +97,13 @@
     low-pass noise filter might crop pixels at the frame boundaries, modifying
     its output frame size.</para>
 
+    <para>Applications can get and set formats stored in a request by setting
+    the <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant> and the
+    <structfield>request</structfield> to the request ID. See
+    <xref linkend="v4l2-requests" /> for more information about the request
+    API.</para>
+
     <para>Drivers must not return an error solely because the requested format
     doesn't match the device capabilities. They must instead modify the format
     to match what the hardware can provide. The modified format should be as
@@ -124,8 +131,22 @@
 	    linkend="v4l2-mbus-framefmt" /> for details.</entry>
 	  </row>
 	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry>Request ID, only valid when the <structfield>which</structfield>
+	    field is set to <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant>.
+	    Applications and drivers must set the field to zero in all other
+	    cases.</entry>
+	  </row>
+	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>reserved2</structfield></entry>
+	    <entry>Reserved for future extensions. Applications and drivers must
+	    set the field to zero.</entry>
+	  </row>
+	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry><structfield>reserved</structfield>[7]</entry>
 	    <entry>Reserved for future extensions. Applications and drivers must
 	    set the array to zero.</entry>
 	  </row>
@@ -148,6 +169,11 @@
 	    <entry>1</entry>
 	    <entry>Active formats, applied to the hardware.</entry>
 	  </row>
+	  <row>
+	    <entry>V4L2_SUBDEV_FORMAT_REQUEST</entry>
+	    <entry>1</entry>
+	    <entry>Request formats, used with the requests API.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
@@ -171,8 +197,9 @@
 	<term><errorcode>EINVAL</errorcode></term>
 	<listitem>
 	  <para>The &v4l2-subdev-format; <structfield>pad</structfield>
-	  references a non-existing pad, or the <structfield>which</structfield>
-	  field references a non-existing format.</para>
+	  references a non-existing pad, the <structfield>which</structfield>
+	  field references a non-existing format or the request ID references
+	  a nonexistant request.</para>
 	</listitem>
       </varlistentry>
     </variablelist>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
index 9b59b49db0c3..f1f6a31baa63 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -100,6 +100,13 @@
     handle. Two applications querying the same sub-device would thus not
     interfere with each other.</para>
 
+    <para>Applications can get and set selection rectangles stored in a request
+    by setting the <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant> and the
+    <structfield>request</structfield> to the request ID. See
+    <xref linkend="v4l2-requests" /> for more information about the request
+    API.</para>
+
     <para>Drivers must not return an error solely because the requested
     selection rectangle doesn't match the device capabilities. They must instead
     modify the rectangle to match what the hardware can provide. The modified
@@ -160,8 +167,22 @@
 	    <entry>Selection rectangle, in pixels.</entry>
 	  </row>
 	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>request</structfield></entry>
+	    <entry>Request ID, only valid when the <structfield>which</structfield>
+	    field is set to <constant>V4L2_SUBDEV_FORMAT_REQUEST</constant>.
+	    Applications and drivers must set the field to zero in all other
+	    cases.</entry>
+	  </row>
+	  <row>
+	    <entry>__u16</entry>
+	    <entry><structfield>reserved2</structfield></entry>
+	    <entry>Reserved for future extensions. Applications and drivers must
+	    set the field to zero.</entry>
+	  </row>
+	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry><structfield>reserved</structfield>[7]</entry>
 	    <entry>Reserved for future extensions. Applications and drivers must
 	    set the array to zero.</entry>
 	  </row>
@@ -193,8 +214,9 @@
 	  <para>The &v4l2-subdev-selection;
 	  <structfield>pad</structfield> references a non-existing
 	  pad, the <structfield>which</structfield> field references a
-	  non-existing format, or the selection target is not
-	  supported on the given subdev pad.</para>
+	  non-existing format, the selection target is not supported on
+	  the given subdev pad or the request ID references a nonexistant
+	  request.</para>
 	</listitem>
       </varlistentry>
     </variablelist>
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 39/48] v4l: vsp1: Implement and use the subdev pad::init_cfg configuration
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Turn the custom formats initialization function into a standard
pad::init_cfg handler and use it in subdevs instead of initializing
formats in the subdev open handler.

This makes the subdev open handler empty, so remove it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  1 +
 drivers/media/platform/vsp1/vsp1_entity.c | 26 ++++++--------------------
 drivers/media/platform/vsp1/vsp1_entity.h |  2 ++
 drivers/media/platform/vsp1/vsp1_hsit.c   |  1 +
 drivers/media/platform/vsp1/vsp1_lif.c    |  1 +
 drivers/media/platform/vsp1/vsp1_lut.c    |  1 +
 drivers/media/platform/vsp1/vsp1_rpf.c    |  1 +
 drivers/media/platform/vsp1/vsp1_sru.c    |  1 +
 drivers/media/platform/vsp1/vsp1_uds.c    |  1 +
 drivers/media/platform/vsp1/vsp1_wpf.c    |  1 +
 10 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index d8b7bdeb5af5..879dc9c9d3f0 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -387,6 +387,7 @@ static struct v4l2_subdev_video_ops bru_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops bru_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = bru_enum_mbus_code,
 	.enum_frame_size = bru_enum_frame_size,
 	.get_fmt = bru_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index caf8e413adeb..77eaabf3c6ec 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -62,16 +62,15 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 }
 
 /*
- * vsp1_entity_init_formats - Initialize formats on all pads
+ * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
  * @cfg: V4L2 subdev pad configuration
  *
- * Initialize all pad formats with default values. If cfg is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
+ * Initialize all pad formats with default values in the given pad config. This
+ * function can be used as a handler for the subdev pad::init_cfg operation.
  */
-static void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-				     struct v4l2_subdev_pad_config *cfg)
+void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg)
 {
 	struct v4l2_subdev_format format;
 	unsigned int pad;
@@ -87,18 +86,6 @@ static void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 	}
 }
 
-static int vsp1_entity_open(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh)
-{
-	vsp1_entity_init_formats(subdev, fh->pad);
-
-	return 0;
-}
-
-const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
-	.open = vsp1_entity_open,
-};
-
 /* -----------------------------------------------------------------------------
  * Media Operations
  */
@@ -209,13 +196,12 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	v4l2_subdev_init(subdev, ops);
 
 	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
 	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
 		 dev_name(vsp1->dev), name);
 
-	vsp1_entity_init_formats(subdev, NULL);
+	vsp1_entity_init_cfg(subdev, NULL);
 
 	return 0;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 0fdda82a8d9a..3c298e2482ef 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -107,6 +107,8 @@ struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, u32 which);
+void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 49ff74b51e03..3e36755c8c2a 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -163,6 +163,7 @@ static struct v4l2_subdev_video_ops hsit_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops hsit_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = hsit_enum_mbus_code,
 	.enum_frame_size = hsit_enum_frame_size,
 	.get_fmt = hsit_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index ead6cc3aa3fa..5edf6a742c5b 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -190,6 +190,7 @@ static struct v4l2_subdev_video_ops lif_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops lif_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lif_enum_mbus_code,
 	.enum_frame_size = lif_enum_frame_size,
 	.get_fmt = lif_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 6ba6a58fbac6..f0afc4291387 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -203,6 +203,7 @@ static struct v4l2_subdev_video_ops lut_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops lut_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lut_enum_mbus_code,
 	.enum_frame_size = lut_enum_frame_size,
 	.get_fmt = lut_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index a68f26db9b3f..69fd76eed0bb 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -127,6 +127,7 @@ static struct v4l2_subdev_video_ops rpf_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops rpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
 	.enum_frame_size = vsp1_rwpf_enum_frame_size,
 	.get_fmt = vsp1_rwpf_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index c8642bf8b1a1..043dac6644c1 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -307,6 +307,7 @@ static struct v4l2_subdev_video_ops sru_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops sru_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = sru_enum_mbus_code,
 	.enum_frame_size = sru_enum_frame_size,
 	.get_fmt = sru_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 34689adda810..666fabcd0382 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -305,6 +305,7 @@ static struct v4l2_subdev_video_ops uds_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops uds_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = uds_enum_mbus_code,
 	.enum_frame_size = uds_enum_frame_size,
 	.get_fmt = uds_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 84772fa258a5..d46910db7e08 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -138,6 +138,7 @@ static struct v4l2_subdev_video_ops wpf_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops wpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
 	.enum_frame_size = vsp1_rwpf_enum_frame_size,
 	.get_fmt = vsp1_rwpf_get_format,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 39/48] v4l: vsp1: Implement and use the subdev pad::init_cfg configuration
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Turn the custom formats initialization function into a standard
pad::init_cfg handler and use it in subdevs instead of initializing
formats in the subdev open handler.

This makes the subdev open handler empty, so remove it.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  1 +
 drivers/media/platform/vsp1/vsp1_entity.c | 26 ++++++--------------------
 drivers/media/platform/vsp1/vsp1_entity.h |  2 ++
 drivers/media/platform/vsp1/vsp1_hsit.c   |  1 +
 drivers/media/platform/vsp1/vsp1_lif.c    |  1 +
 drivers/media/platform/vsp1/vsp1_lut.c    |  1 +
 drivers/media/platform/vsp1/vsp1_rpf.c    |  1 +
 drivers/media/platform/vsp1/vsp1_sru.c    |  1 +
 drivers/media/platform/vsp1/vsp1_uds.c    |  1 +
 drivers/media/platform/vsp1/vsp1_wpf.c    |  1 +
 10 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index d8b7bdeb5af5..879dc9c9d3f0 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -387,6 +387,7 @@ static struct v4l2_subdev_video_ops bru_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops bru_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = bru_enum_mbus_code,
 	.enum_frame_size = bru_enum_frame_size,
 	.get_fmt = bru_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index caf8e413adeb..77eaabf3c6ec 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -62,16 +62,15 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 }
 
 /*
- * vsp1_entity_init_formats - Initialize formats on all pads
+ * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
  * @cfg: V4L2 subdev pad configuration
  *
- * Initialize all pad formats with default values. If cfg is not NULL, try
- * formats are initialized on the file handle. Otherwise active formats are
- * initialized on the device.
+ * Initialize all pad formats with default values in the given pad config. This
+ * function can be used as a handler for the subdev pad::init_cfg operation.
  */
-static void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
-				     struct v4l2_subdev_pad_config *cfg)
+void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg)
 {
 	struct v4l2_subdev_format format;
 	unsigned int pad;
@@ -87,18 +86,6 @@ static void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
 	}
 }
 
-static int vsp1_entity_open(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_fh *fh)
-{
-	vsp1_entity_init_formats(subdev, fh->pad);
-
-	return 0;
-}
-
-const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
-	.open = vsp1_entity_open,
-};
-
 /* -----------------------------------------------------------------------------
  * Media Operations
  */
@@ -209,13 +196,12 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	v4l2_subdev_init(subdev, ops);
 
 	subdev->entity.ops = &vsp1->media_ops;
-	subdev->internal_ops = &vsp1_subdev_internal_ops;
 	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
 		 dev_name(vsp1->dev), name);
 
-	vsp1_entity_init_formats(subdev, NULL);
+	vsp1_entity_init_cfg(subdev, NULL);
 
 	return 0;
 }
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 0fdda82a8d9a..3c298e2482ef 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -107,6 +107,8 @@ struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad, u32 which);
+void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
+			  struct v4l2_subdev_pad_config *cfg);
 
 void vsp1_entity_route_setup(struct vsp1_entity *source);
 
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 49ff74b51e03..3e36755c8c2a 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -163,6 +163,7 @@ static struct v4l2_subdev_video_ops hsit_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops hsit_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = hsit_enum_mbus_code,
 	.enum_frame_size = hsit_enum_frame_size,
 	.get_fmt = hsit_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index ead6cc3aa3fa..5edf6a742c5b 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -190,6 +190,7 @@ static struct v4l2_subdev_video_ops lif_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops lif_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lif_enum_mbus_code,
 	.enum_frame_size = lif_enum_frame_size,
 	.get_fmt = lif_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 6ba6a58fbac6..f0afc4291387 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -203,6 +203,7 @@ static struct v4l2_subdev_video_ops lut_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops lut_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lut_enum_mbus_code,
 	.enum_frame_size = lut_enum_frame_size,
 	.get_fmt = lut_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index a68f26db9b3f..69fd76eed0bb 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -127,6 +127,7 @@ static struct v4l2_subdev_video_ops rpf_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops rpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
 	.enum_frame_size = vsp1_rwpf_enum_frame_size,
 	.get_fmt = vsp1_rwpf_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index c8642bf8b1a1..043dac6644c1 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -307,6 +307,7 @@ static struct v4l2_subdev_video_ops sru_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops sru_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = sru_enum_mbus_code,
 	.enum_frame_size = sru_enum_frame_size,
 	.get_fmt = sru_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 34689adda810..666fabcd0382 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -305,6 +305,7 @@ static struct v4l2_subdev_video_ops uds_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops uds_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = uds_enum_mbus_code,
 	.enum_frame_size = uds_enum_frame_size,
 	.get_fmt = uds_get_format,
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 84772fa258a5..d46910db7e08 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -138,6 +138,7 @@ static struct v4l2_subdev_video_ops wpf_video_ops = {
 };
 
 static struct v4l2_subdev_pad_ops wpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
 	.enum_frame_size = vsp1_rwpf_enum_frame_size,
 	.get_fmt = vsp1_rwpf_get_format,
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 40/48] v4l: vsp1: Store active formats in a pad config structure
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Add a pad config structure field to the vsp1_entity structure and use it
to store all active pad formats. This generalizes the code to operate on
pad config structures, a prerequisite to implement the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 59 ++++++++++++++++++++----------
 drivers/media/platform/vsp1/vsp1_entity.c | 61 +++++++++++++++++++++++--------
 drivers/media/platform/vsp1/vsp1_entity.h |  8 +++-
 drivers/media/platform/vsp1/vsp1_hsit.c   | 29 +++++++++++----
 drivers/media/platform/vsp1/vsp1_lif.c    | 41 +++++++++++++++------
 drivers/media/platform/vsp1/vsp1_lut.c    | 42 +++++++++++++++------
 drivers/media/platform/vsp1/vsp1_rpf.c    | 12 +++++-
 drivers/media/platform/vsp1/vsp1_rwpf.c   | 51 +++++++++++++++++++-------
 drivers/media/platform/vsp1/vsp1_sru.c    | 61 +++++++++++++++++++++----------
 drivers/media/platform/vsp1/vsp1_uds.c    | 59 ++++++++++++++++++++----------
 drivers/media/platform/vsp1/vsp1_wpf.c    | 12 +++++-
 11 files changed, 311 insertions(+), 124 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 879dc9c9d3f0..a0aa0fb2a5e1 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -70,7 +70,8 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (!enable)
 		return 0;
 
-	format = &bru->entity.formats[bru->entity.source_pad];
+	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+					    bru->entity.source_pad);
 
 	/* The hardware is extremely flexible but we have no userspace API to
 	 * expose all the parameters, nor is it clear whether we would have use
@@ -183,7 +184,6 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
 		MEDIA_BUS_FMT_AYUV8_1X32,
 	};
 	struct vsp1_bru *bru = to_bru(subdev);
-	struct v4l2_mbus_framefmt *format;
 
 	if (code->pad = BRU_PAD_SINK(0)) {
 		if (code->index >= ARRAY_SIZE(codes))
@@ -191,12 +191,19 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
+		struct v4l2_mbus_framefmt *format;
+
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-						    BRU_PAD_SINK(0),
+		config = vsp1_entity_get_pad_config(&bru->entity, cfg,
 						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&bru->entity, config,
+						    BRU_PAD_SINK(0));
 		code->code = format->code;
 	}
 
@@ -242,17 +249,21 @@ static int bru_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&bru->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
 
 static void bru_try_format(struct vsp1_bru *bru,
-			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-			   enum v4l2_subdev_format_whence which)
+			   struct v4l2_subdev_pad_config *config,
+			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
 	struct v4l2_mbus_framefmt *format;
 
@@ -266,8 +277,8 @@ static void bru_try_format(struct vsp1_bru *bru,
 
 	default:
 		/* The BRU can't perform format conversion. */
-		format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-						    BRU_PAD_SINK(0), which);
+		format = vsp1_entity_get_pad_format(&bru->entity, config,
+						    BRU_PAD_SINK(0));
 		fmt->code = format->code;
 		break;
 	}
@@ -283,12 +294,16 @@ static int bru_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which);
+	config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	bru_try_format(bru, config, fmt->pad, &fmt->format);
 
-	format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&bru->entity, config, fmt->pad);
 	*format = fmt->format;
 
 	/* Reset the compose rectangle */
@@ -307,8 +322,8 @@ static int bru_set_format(struct v4l2_subdev *subdev,
 		unsigned int i;
 
 		for (i = 0; i <= bru->entity.source_pad; ++i) {
-			format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-							    i, fmt->which);
+			format = vsp1_entity_get_pad_format(&bru->entity,
+							    config, i);
 			format->code = fmt->format.code;
 		}
 	}
@@ -347,6 +362,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 			     struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *compose;
 
@@ -356,19 +372,22 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 	if (sel->target != V4L2_SEL_TGT_COMPOSE)
 		return -EINVAL;
 
+	config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which);
+	if (!config)
+		return -EINVAL;
+
 	/* The compose rectangle top left corner must be inside the output
 	 * frame.
 	 */
-	format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-					    bru->entity.source_pad, sel->which);
+	format = vsp1_entity_get_pad_format(&bru->entity, config,
+					    bru->entity.source_pad);
 	sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
 	sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
 
 	/* Scaling isn't supported, the compose rectangle size must be identical
 	 * to the sink format size.
 	 */
-	format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad,
-					    sel->which);
+	format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad);
 	sel->r.width = format->width;
 	sel->r.height = format->height;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 77eaabf3c6ec..3ccc83781d4e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -46,21 +46,49 @@ void vsp1_entity_route_setup(struct vsp1_entity *source)
  * V4L2 Subdevice Operations
  */
 
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
+/**
+ * vsp1_entity_get_pad_config - Get the pad configuration for an entity
+ * @entity: the entity
+ * @cfg: the TRY or REQUEST pad configuration
+ * @which: configuration selector (ACTIVE, TRY or REQUEST)
+ *
+ * Return the pad configuration requested by the which argument. The TRY and
+ * REQUEST configurations are passed explicitly to the function through the cfg
+ * argument and simply returned when requested. The ACTIVE configuration comes
+ * from the entity structure.
+ */
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, u32 which)
+			   enum v4l2_subdev_format_whence which)
 {
 	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
 	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &entity->formats[pad];
+		return entity->config;
+	case V4L2_SUBDEV_FORMAT_TRY:
+	case V4L2_SUBDEV_FORMAT_REQUEST:
 	default:
-		return NULL;
+		return cfg;
 	}
 }
 
+/**
+ * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
+ * @entity: the entity
+ * @cfg: the configuration storage
+ * @pad: the pad number
+ *
+ * Return the format stored in the given configuration for an entity's pad. The
+ * configuration can be an ACTIVE, TRY or REQUEST configuration.
+ */
+struct v4l2_mbus_framefmt *
+vsp1_entity_get_pad_format(struct vsp1_entity *entity,
+			   struct v4l2_subdev_pad_config *cfg,
+			   unsigned int pad)
+{
+	return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
+}
+
 /*
  * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
@@ -167,19 +195,12 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	entity->vsp1 = vsp1;
 	entity->source_pad = num_pads - 1;
 
-	/* Allocate formats and pads. */
-	entity->formats = devm_kzalloc(vsp1->dev,
-				       num_pads * sizeof(*entity->formats),
-				       GFP_KERNEL);
-	if (entity->formats = NULL)
-		return -ENOMEM;
-
+	/* Allocate and initialize pads. */
 	entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
 				    GFP_KERNEL);
 	if (entity->pads = NULL)
 		return -ENOMEM;
 
-	/* Initialize pads. */
 	for (i = 0; i < num_pads - 1; ++i)
 		entity->pads[i].flags = MEDIA_PAD_FL_SINK;
 
@@ -203,6 +224,15 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 	vsp1_entity_init_cfg(subdev, NULL);
 
+	/* Allocate the pad configuration to store formats and selection
+	 * rectangles.
+	 */
+	entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
+	if (entity->config = NULL) {
+		media_entity_cleanup(&entity->subdev.entity);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -212,5 +242,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity)
 		entity->ops->destroy(entity);
 	if (entity->subdev.ctrl_handler)
 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
+	v4l2_subdev_free_pad_config(entity->config);
 	media_entity_cleanup(&entity->subdev.entity);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 3c298e2482ef..086dc2b22d61 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -84,7 +84,7 @@ struct vsp1_entity {
 	unsigned int sink_pad;
 
 	struct v4l2_subdev subdev;
-	struct v4l2_mbus_framefmt *formats;
+	struct v4l2_subdev_pad_config *config;
 };
 
 static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -103,10 +103,14 @@ int vsp1_entity_link_setup(struct media_entity *entity,
 			   const struct media_pad *local,
 			   const struct media_pad *remote, u32 flags);
 
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_pad_config(struct vsp1_entity *entity,
+			   struct v4l2_subdev_pad_config *cfg,
+			   enum v4l2_subdev_format_whence which);
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, u32 which);
+			   unsigned int pad);
 void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_pad_config *cfg);
 
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 3e36755c8c2a..4f87f6f8ee38 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -77,10 +77,14 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
 				struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_hsit *hsit = to_hsit(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad,
-					    fse->which);
+	config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&hsit->entity, config, fse->pad);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -108,9 +112,14 @@ static int hsit_get_format(struct v4l2_subdev *subdev,
 			   struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_hsit *hsit = to_hsit(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
@@ -120,10 +129,14 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
 			   struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_hsit *hsit = to_hsit(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
-					    fmt->which);
+	config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
 
 	if (fmt->pad = HSIT_PAD_SOURCE) {
 		/* The HST and HSI output format code and resolution can't be
@@ -145,8 +158,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&hsit->entity, config,
+					    HSIT_PAD_SOURCE);
 	*format = fmt->format;
 	format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
 		     : MEDIA_BUS_FMT_AHSV8888_1X32;
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 5edf6a742c5b..6a80a04ea392 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -48,7 +48,8 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
 		return 0;
 	}
 
-	format = &lif->entity.formats[LIF_PAD_SOURCE];
+	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+					    LIF_PAD_SOURCE);
 
 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
 
@@ -84,6 +85,7 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
 		struct v4l2_mbus_framefmt *format;
 
 		/* The LIF can't perform format conversion, the sink format is
@@ -92,8 +94,13 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&lif->entity, cfg,
-						    LIF_PAD_SINK, code->which);
+		config = vsp1_entity_get_pad_config(&lif->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&lif->entity, config,
+						    LIF_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -105,10 +112,14 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK,
-					    fse->which);
+	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&lif->entity, config, LIF_PAD_SINK);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -133,9 +144,13 @@ static int lif_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
+	struct v4l2_subdev_pad_config *config;
 
-	fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
-						  fmt->which);
+	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	fmt->format = *vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad);
 
 	return 0;
 }
@@ -145,15 +160,19 @@ static int lif_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
+	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Default to YUV if the requested format is not supported. */
 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-	format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad);
 
 	if (fmt->pad = LIF_PAD_SOURCE) {
 		/* The LIF source format is always identical to its sink
@@ -174,8 +193,8 @@ static int lif_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lif->entity, config,
+					    LIF_PAD_SOURCE);
 	*format = fmt->format;
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index f0afc4291387..a5b839b28320 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -86,7 +86,6 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
 		MEDIA_BUS_FMT_AYUV8_1X32,
 	};
 	struct vsp1_lut *lut = to_lut(subdev);
-	struct v4l2_mbus_framefmt *format;
 
 	if (code->pad = LUT_PAD_SINK) {
 		if (code->index >= ARRAY_SIZE(codes))
@@ -94,14 +93,22 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
+		struct v4l2_mbus_framefmt *format;
+
 		/* The LUT can't perform format conversion, the sink format is
 		 * always identical to the source format.
 		 */
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&lut->entity, cfg,
-						    LUT_PAD_SINK, code->which);
+		config = vsp1_entity_get_pad_config(&lut->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&lut->entity, config,
+						    LUT_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -113,10 +120,14 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&lut->entity, cfg,
-					    fse->pad, fse->which);
+	config = vsp1_entity_get_pad_config(&lut->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&lut->entity, config, fse->pad);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -144,9 +155,14 @@ static int lut_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&lut->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
@@ -156,16 +172,20 @@ static int lut_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
+	config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Default to YUV if the requested format is not supported. */
 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-	format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad);
 
 	if (fmt->pad = LUT_PAD_SOURCE) {
 		/* The LUT output format can't be modified. */
@@ -183,8 +203,8 @@ static int lut_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lut->entity, config,
+					    LUT_PAD_SOURCE);
 	*format = fmt->format;
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 69fd76eed0bb..3b55cd93983f 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -42,6 +42,8 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_rwpf *rpf = to_rwpf(subdev);
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
+	const struct v4l2_mbus_framefmt *source_format;
+	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop = &rpf->crop;
 	u32 pstride;
 	u32 infmt;
@@ -79,6 +81,13 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
+	sink_format = vsp1_entity_get_pad_format(&rpf->entity,
+						 rpf->entity.config,
+						 RWPF_PAD_SINK);
+	source_format = vsp1_entity_get_pad_format(&rpf->entity,
+						   rpf->entity.config,
+						   RWPF_PAD_SOURCE);
+
 	infmt = VI6_RPF_INFMT_CIPM
 	      | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
 
@@ -87,8 +96,7 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (fmtinfo->swap_uv)
 		infmt |= VI6_RPF_INFMT_SPUVS;
 
-	if (rpf->entity.formats[RWPF_PAD_SINK].code !-	    rpf->entity.formats[RWPF_PAD_SOURCE].code)
+	if (sink_format->code != source_format->code)
 		infmt |= VI6_RPF_INFMT_CSC;
 
 	vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 38893ab06cd9..e5216d39723e 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -46,10 +46,14 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad,
-					    fse->which);
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config, fse->pad);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -92,9 +96,14 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 
-	fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
-						  fmt->which);
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
@@ -104,16 +113,20 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *crop;
 
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Default to YUV if the requested format is not supported. */
 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad);
 
 	if (fmt->pad = RWPF_PAD_SOURCE) {
 		/* The RWPF performs format conversion but can't scale, only the
@@ -142,8 +155,8 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 	crop->height = fmt->format.height;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+					    RWPF_PAD_SOURCE);
 	*format = fmt->format;
 
 	return 0;
@@ -154,20 +167,25 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
 	/* Cropping is implemented on the sink pad. */
 	if (sel->pad != RWPF_PAD_SINK)
 		return -EINVAL;
 
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+	if (!config)
+		return -EINVAL;
+
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP:
 		sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
 		break;
 
 	case V4L2_SEL_TGT_CROP_BOUNDS:
-		format = vsp1_entity_get_pad_format(&rwpf->entity, cfg,
-						    RWPF_PAD_SINK, sel->which);
+		format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+						    RWPF_PAD_SINK);
 		sel->r.left = 0;
 		sel->r.top = 0;
 		sel->r.width = format->width;
@@ -186,6 +204,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *crop;
 
@@ -196,11 +215,15 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	if (sel->target != V4L2_SEL_TGT_CROP)
 		return -EINVAL;
 
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Make sure the crop rectangle is entirely contained in the image. The
 	 * WPF top and left offsets are limited to 255.
 	 */
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK,
-					    sel->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+					    RWPF_PAD_SINK);
 
 	/* Restrict the crop rectangle coordinates to multiples of 2 to avoid
 	 * shifting the color plane.
@@ -227,8 +250,8 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	*crop = sel->r;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
-					    sel->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+					    RWPF_PAD_SOURCE);
 	format->width = crop->width;
 	format->height = crop->height;
 
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 043dac6644c1..c9a97ba5a042 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -117,8 +117,10 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (!enable)
 		return 0;
 
-	input = &sru->entity.formats[SRU_PAD_SINK];
-	output = &sru->entity.formats[SRU_PAD_SOURCE];
+	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					   SRU_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					    SRU_PAD_SOURCE);
 
 	if (input->code = MEDIA_BUS_FMT_ARGB8888_1X32)
 		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
@@ -153,7 +155,6 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
 		MEDIA_BUS_FMT_AYUV8_1X32,
 	};
 	struct vsp1_sru *sru = to_sru(subdev);
-	struct v4l2_mbus_framefmt *format;
 
 	if (code->pad = SRU_PAD_SINK) {
 		if (code->index >= ARRAY_SIZE(codes))
@@ -161,14 +162,22 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
+		struct v4l2_mbus_framefmt *format;
+
 		/* The SRU can't perform format conversion, the sink format is
 		 * always identical to the source format.
 		 */
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-						    SRU_PAD_SINK, code->which);
+		config = vsp1_entity_get_pad_config(&sru->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&sru->entity, config,
+						    SRU_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -180,10 +189,14 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-					    SRU_PAD_SINK, fse->which);
+	config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -214,17 +227,21 @@ static int sru_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&sru->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
 
 static void sru_try_format(struct vsp1_sru *sru,
-			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-			   enum v4l2_subdev_format_whence which)
+			   struct v4l2_subdev_pad_config *config,
+			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
 	struct v4l2_mbus_framefmt *format;
 	unsigned int input_area;
@@ -243,8 +260,8 @@ static void sru_try_format(struct vsp1_sru *sru,
 
 	case SRU_PAD_SOURCE:
 		/* The SRU can't perform format conversion. */
-		format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-						    SRU_PAD_SINK, which);
+		format = vsp1_entity_get_pad_format(&sru->entity, config,
+						    SRU_PAD_SINK);
 		fmt->code = format->code;
 
 		/* We can upscale by 2 in both direction, but not independently.
@@ -278,21 +295,25 @@ static int sru_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which);
+	config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	sru_try_format(sru, config, fmt->pad, &fmt->format);
 
-	format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
 	*format = fmt->format;
 
 	if (fmt->pad = SRU_PAD_SINK) {
 		/* Propagate the format to the source pad. */
-		format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-						    SRU_PAD_SOURCE, fmt->which);
+		format = vsp1_entity_get_pad_format(&sru->entity, config,
+						    SRU_PAD_SOURCE);
 		*format = fmt->format;
 
-		sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which);
+		sru_try_format(sru, config, SRU_PAD_SOURCE, format);
 	}
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 666fabcd0382..3ba0f6844d1d 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -120,8 +120,10 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (!enable)
 		return 0;
 
-	input = &uds->entity.formats[UDS_PAD_SINK];
-	output = &uds->entity.formats[UDS_PAD_SOURCE];
+	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					   UDS_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					    UDS_PAD_SOURCE);
 
 	hscale = uds_compute_ratio(input->width, output->width);
 	vscale = uds_compute_ratio(input->height, output->height);
@@ -178,16 +180,22 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
 		struct v4l2_mbus_framefmt *format;
 
+		config = vsp1_entity_get_pad_config(&uds->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
 		/* The UDS can't perform format conversion, the sink format is
 		 * always identical to the source format.
 		 */
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-						    UDS_PAD_SINK, code->which);
+		format = vsp1_entity_get_pad_format(&uds->entity, config,
+						    UDS_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -199,10 +207,15 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-					    UDS_PAD_SINK, fse->which);
+	config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&uds->entity, config,
+					    UDS_PAD_SINK);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -227,17 +240,21 @@ static int uds_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
+	struct v4l2_subdev_pad_config *config;
 
-	fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
-						  fmt->which);
+	config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	fmt->format = *vsp1_entity_get_pad_format(&uds->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
 
 static void uds_try_format(struct vsp1_uds *uds,
-			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-			   enum v4l2_subdev_format_whence which)
+			   struct v4l2_subdev_pad_config *config,
+			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
 	struct v4l2_mbus_framefmt *format;
 	unsigned int minimum;
@@ -256,8 +273,8 @@ static void uds_try_format(struct vsp1_uds *uds,
 
 	case UDS_PAD_SOURCE:
 		/* The UDS scales but can't perform format conversion. */
-		format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-						    UDS_PAD_SINK, which);
+		format = vsp1_entity_get_pad_format(&uds->entity, config,
+						    UDS_PAD_SINK);
 		fmt->code = format->code;
 
 		uds_output_limits(format->width, &minimum, &maximum);
@@ -276,21 +293,25 @@ static int uds_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which);
+	config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	uds_try_format(uds, config, fmt->pad, &fmt->format);
 
-	format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad);
 	*format = fmt->format;
 
 	if (fmt->pad = UDS_PAD_SINK) {
 		/* Propagate the format to the source pad. */
-		format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-						    UDS_PAD_SOURCE, fmt->which);
+		format = vsp1_entity_get_pad_format(&uds->entity, config,
+						    UDS_PAD_SOURCE);
 		*format = fmt->format;
 
-		uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which);
+		uds_try_format(uds, config, UDS_PAD_SOURCE, format);
 	}
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d46910db7e08..c86d31f274bf 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -42,6 +42,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *wpf = to_rwpf(subdev);
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
+	const struct v4l2_mbus_framefmt *source_format;
+	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop = &wpf->crop;
 	unsigned int i;
 	u32 srcrpf = 0;
@@ -94,6 +96,13 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
 	/* Format */
+	sink_format = vsp1_entity_get_pad_format(&wpf->entity,
+						 wpf->entity.config,
+						 RWPF_PAD_SINK);
+	source_format = vsp1_entity_get_pad_format(&wpf->entity,
+						   wpf->entity.config,
+						   RWPF_PAD_SOURCE);
+
 	if (!pipe->lif) {
 		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
 
@@ -109,8 +118,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
 	}
 
-	if (wpf->entity.formats[RWPF_PAD_SINK].code !-	    wpf->entity.formats[RWPF_PAD_SOURCE].code)
+	if (sink_format->code != source_format->code)
 		outfmt |= VI6_WPF_OUTFMT_CSC;
 
 	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 40/48] v4l: vsp1: Store active formats in a pad config structure
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Add a pad config structure field to the vsp1_entity structure and use it
to store all active pad formats. This generalizes the code to operate on
pad config structures, a prerequisite to implement the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 59 ++++++++++++++++++++----------
 drivers/media/platform/vsp1/vsp1_entity.c | 61 +++++++++++++++++++++++--------
 drivers/media/platform/vsp1/vsp1_entity.h |  8 +++-
 drivers/media/platform/vsp1/vsp1_hsit.c   | 29 +++++++++++----
 drivers/media/platform/vsp1/vsp1_lif.c    | 41 +++++++++++++++------
 drivers/media/platform/vsp1/vsp1_lut.c    | 42 +++++++++++++++------
 drivers/media/platform/vsp1/vsp1_rpf.c    | 12 +++++-
 drivers/media/platform/vsp1/vsp1_rwpf.c   | 51 +++++++++++++++++++-------
 drivers/media/platform/vsp1/vsp1_sru.c    | 61 +++++++++++++++++++++----------
 drivers/media/platform/vsp1/vsp1_uds.c    | 59 ++++++++++++++++++++----------
 drivers/media/platform/vsp1/vsp1_wpf.c    | 12 +++++-
 11 files changed, 311 insertions(+), 124 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 879dc9c9d3f0..a0aa0fb2a5e1 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -70,7 +70,8 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (!enable)
 		return 0;
 
-	format = &bru->entity.formats[bru->entity.source_pad];
+	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+					    bru->entity.source_pad);
 
 	/* The hardware is extremely flexible but we have no userspace API to
 	 * expose all the parameters, nor is it clear whether we would have use
@@ -183,7 +184,6 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
 		MEDIA_BUS_FMT_AYUV8_1X32,
 	};
 	struct vsp1_bru *bru = to_bru(subdev);
-	struct v4l2_mbus_framefmt *format;
 
 	if (code->pad == BRU_PAD_SINK(0)) {
 		if (code->index >= ARRAY_SIZE(codes))
@@ -191,12 +191,19 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
+		struct v4l2_mbus_framefmt *format;
+
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-						    BRU_PAD_SINK(0),
+		config = vsp1_entity_get_pad_config(&bru->entity, cfg,
 						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&bru->entity, config,
+						    BRU_PAD_SINK(0));
 		code->code = format->code;
 	}
 
@@ -242,17 +249,21 @@ static int bru_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&bru->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
 
 static void bru_try_format(struct vsp1_bru *bru,
-			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-			   enum v4l2_subdev_format_whence which)
+			   struct v4l2_subdev_pad_config *config,
+			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
 	struct v4l2_mbus_framefmt *format;
 
@@ -266,8 +277,8 @@ static void bru_try_format(struct vsp1_bru *bru,
 
 	default:
 		/* The BRU can't perform format conversion. */
-		format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-						    BRU_PAD_SINK(0), which);
+		format = vsp1_entity_get_pad_format(&bru->entity, config,
+						    BRU_PAD_SINK(0));
 		fmt->code = format->code;
 		break;
 	}
@@ -283,12 +294,16 @@ static int bru_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which);
+	config = vsp1_entity_get_pad_config(&bru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	bru_try_format(bru, config, fmt->pad, &fmt->format);
 
-	format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&bru->entity, config, fmt->pad);
 	*format = fmt->format;
 
 	/* Reset the compose rectangle */
@@ -307,8 +322,8 @@ static int bru_set_format(struct v4l2_subdev *subdev,
 		unsigned int i;
 
 		for (i = 0; i <= bru->entity.source_pad; ++i) {
-			format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-							    i, fmt->which);
+			format = vsp1_entity_get_pad_format(&bru->entity,
+							    config, i);
 			format->code = fmt->format.code;
 		}
 	}
@@ -347,6 +362,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 			     struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *compose;
 
@@ -356,19 +372,22 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 	if (sel->target != V4L2_SEL_TGT_COMPOSE)
 		return -EINVAL;
 
+	config = vsp1_entity_get_pad_config(&bru->entity, cfg, sel->which);
+	if (!config)
+		return -EINVAL;
+
 	/* The compose rectangle top left corner must be inside the output
 	 * frame.
 	 */
-	format = vsp1_entity_get_pad_format(&bru->entity, cfg,
-					    bru->entity.source_pad, sel->which);
+	format = vsp1_entity_get_pad_format(&bru->entity, config,
+					    bru->entity.source_pad);
 	sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
 	sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
 
 	/* Scaling isn't supported, the compose rectangle size must be identical
 	 * to the sink format size.
 	 */
-	format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad,
-					    sel->which);
+	format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad);
 	sel->r.width = format->width;
 	sel->r.height = format->height;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 77eaabf3c6ec..3ccc83781d4e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -46,21 +46,49 @@ void vsp1_entity_route_setup(struct vsp1_entity *source)
  * V4L2 Subdevice Operations
  */
 
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
+/**
+ * vsp1_entity_get_pad_config - Get the pad configuration for an entity
+ * @entity: the entity
+ * @cfg: the TRY or REQUEST pad configuration
+ * @which: configuration selector (ACTIVE, TRY or REQUEST)
+ *
+ * Return the pad configuration requested by the which argument. The TRY and
+ * REQUEST configurations are passed explicitly to the function through the cfg
+ * argument and simply returned when requested. The ACTIVE configuration comes
+ * from the entity structure.
+ */
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, u32 which)
+			   enum v4l2_subdev_format_whence which)
 {
 	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
 	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &entity->formats[pad];
+		return entity->config;
+	case V4L2_SUBDEV_FORMAT_TRY:
+	case V4L2_SUBDEV_FORMAT_REQUEST:
 	default:
-		return NULL;
+		return cfg;
 	}
 }
 
+/**
+ * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
+ * @entity: the entity
+ * @cfg: the configuration storage
+ * @pad: the pad number
+ *
+ * Return the format stored in the given configuration for an entity's pad. The
+ * configuration can be an ACTIVE, TRY or REQUEST configuration.
+ */
+struct v4l2_mbus_framefmt *
+vsp1_entity_get_pad_format(struct vsp1_entity *entity,
+			   struct v4l2_subdev_pad_config *cfg,
+			   unsigned int pad)
+{
+	return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
+}
+
 /*
  * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
@@ -167,19 +195,12 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 	entity->vsp1 = vsp1;
 	entity->source_pad = num_pads - 1;
 
-	/* Allocate formats and pads. */
-	entity->formats = devm_kzalloc(vsp1->dev,
-				       num_pads * sizeof(*entity->formats),
-				       GFP_KERNEL);
-	if (entity->formats == NULL)
-		return -ENOMEM;
-
+	/* Allocate and initialize pads. */
 	entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
 				    GFP_KERNEL);
 	if (entity->pads == NULL)
 		return -ENOMEM;
 
-	/* Initialize pads. */
 	for (i = 0; i < num_pads - 1; ++i)
 		entity->pads[i].flags = MEDIA_PAD_FL_SINK;
 
@@ -203,6 +224,15 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 	vsp1_entity_init_cfg(subdev, NULL);
 
+	/* Allocate the pad configuration to store formats and selection
+	 * rectangles.
+	 */
+	entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
+	if (entity->config == NULL) {
+		media_entity_cleanup(&entity->subdev.entity);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -212,5 +242,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity)
 		entity->ops->destroy(entity);
 	if (entity->subdev.ctrl_handler)
 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
+	v4l2_subdev_free_pad_config(entity->config);
 	media_entity_cleanup(&entity->subdev.entity);
 }
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 3c298e2482ef..086dc2b22d61 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -84,7 +84,7 @@ struct vsp1_entity {
 	unsigned int sink_pad;
 
 	struct v4l2_subdev subdev;
-	struct v4l2_mbus_framefmt *formats;
+	struct v4l2_subdev_pad_config *config;
 };
 
 static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -103,10 +103,14 @@ int vsp1_entity_link_setup(struct media_entity *entity,
 			   const struct media_pad *local,
 			   const struct media_pad *remote, u32 flags);
 
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_pad_config(struct vsp1_entity *entity,
+			   struct v4l2_subdev_pad_config *cfg,
+			   enum v4l2_subdev_format_whence which);
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, u32 which);
+			   unsigned int pad);
 void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_pad_config *cfg);
 
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 3e36755c8c2a..4f87f6f8ee38 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -77,10 +77,14 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
 				struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_hsit *hsit = to_hsit(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad,
-					    fse->which);
+	config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&hsit->entity, config, fse->pad);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -108,9 +112,14 @@ static int hsit_get_format(struct v4l2_subdev *subdev,
 			   struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_hsit *hsit = to_hsit(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
@@ -120,10 +129,14 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
 			   struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_hsit *hsit = to_hsit(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad,
-					    fmt->which);
+	config = vsp1_entity_get_pad_config(&hsit->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
 
 	if (fmt->pad == HSIT_PAD_SOURCE) {
 		/* The HST and HSI output format code and resolution can't be
@@ -145,8 +158,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&hsit->entity, config,
+					    HSIT_PAD_SOURCE);
 	*format = fmt->format;
 	format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
 		     : MEDIA_BUS_FMT_AHSV8888_1X32;
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 5edf6a742c5b..6a80a04ea392 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -48,7 +48,8 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
 		return 0;
 	}
 
-	format = &lif->entity.formats[LIF_PAD_SOURCE];
+	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+					    LIF_PAD_SOURCE);
 
 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
 
@@ -84,6 +85,7 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
 		struct v4l2_mbus_framefmt *format;
 
 		/* The LIF can't perform format conversion, the sink format is
@@ -92,8 +94,13 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&lif->entity, cfg,
-						    LIF_PAD_SINK, code->which);
+		config = vsp1_entity_get_pad_config(&lif->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&lif->entity, config,
+						    LIF_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -105,10 +112,14 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK,
-					    fse->which);
+	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&lif->entity, config, LIF_PAD_SINK);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -133,9 +144,13 @@ static int lif_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
+	struct v4l2_subdev_pad_config *config;
 
-	fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
-						  fmt->which);
+	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	fmt->format = *vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad);
 
 	return 0;
 }
@@ -145,15 +160,19 @@ static int lif_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lif *lif = to_lif(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
+	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Default to YUV if the requested format is not supported. */
 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-	format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad);
 
 	if (fmt->pad == LIF_PAD_SOURCE) {
 		/* The LIF source format is always identical to its sink
@@ -174,8 +193,8 @@ static int lif_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lif->entity, config,
+					    LIF_PAD_SOURCE);
 	*format = fmt->format;
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index f0afc4291387..a5b839b28320 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -86,7 +86,6 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
 		MEDIA_BUS_FMT_AYUV8_1X32,
 	};
 	struct vsp1_lut *lut = to_lut(subdev);
-	struct v4l2_mbus_framefmt *format;
 
 	if (code->pad == LUT_PAD_SINK) {
 		if (code->index >= ARRAY_SIZE(codes))
@@ -94,14 +93,22 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
+		struct v4l2_mbus_framefmt *format;
+
 		/* The LUT can't perform format conversion, the sink format is
 		 * always identical to the source format.
 		 */
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&lut->entity, cfg,
-						    LUT_PAD_SINK, code->which);
+		config = vsp1_entity_get_pad_config(&lut->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&lut->entity, config,
+						    LUT_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -113,10 +120,14 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&lut->entity, cfg,
-					    fse->pad, fse->which);
+	config = vsp1_entity_get_pad_config(&lut->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&lut->entity, config, fse->pad);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -144,9 +155,14 @@ static int lut_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&lut->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
@@ -156,16 +172,20 @@ static int lut_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_lut *lut = to_lut(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
+	config = vsp1_entity_get_pad_config(&lut->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Default to YUV if the requested format is not supported. */
 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-	format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lut->entity, config, fmt->pad);
 
 	if (fmt->pad == LUT_PAD_SOURCE) {
 		/* The LUT output format can't be modified. */
@@ -183,8 +203,8 @@ static int lut_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&lut->entity, config,
+					    LUT_PAD_SOURCE);
 	*format = fmt->format;
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 69fd76eed0bb..3b55cd93983f 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -42,6 +42,8 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_rwpf *rpf = to_rwpf(subdev);
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
+	const struct v4l2_mbus_framefmt *source_format;
+	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop = &rpf->crop;
 	u32 pstride;
 	u32 infmt;
@@ -79,6 +81,13 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
+	sink_format = vsp1_entity_get_pad_format(&rpf->entity,
+						 rpf->entity.config,
+						 RWPF_PAD_SINK);
+	source_format = vsp1_entity_get_pad_format(&rpf->entity,
+						   rpf->entity.config,
+						   RWPF_PAD_SOURCE);
+
 	infmt = VI6_RPF_INFMT_CIPM
 	      | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
 
@@ -87,8 +96,7 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (fmtinfo->swap_uv)
 		infmt |= VI6_RPF_INFMT_SPUVS;
 
-	if (rpf->entity.formats[RWPF_PAD_SINK].code !=
-	    rpf->entity.formats[RWPF_PAD_SOURCE].code)
+	if (sink_format->code != source_format->code)
 		infmt |= VI6_RPF_INFMT_CSC;
 
 	vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 38893ab06cd9..e5216d39723e 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -46,10 +46,14 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 			      struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad,
-					    fse->which);
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config, fse->pad);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -92,9 +96,14 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 
-	fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
-						  fmt->which);
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
@@ -104,16 +113,20 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 			 struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *crop;
 
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Default to YUV if the requested format is not supported. */
 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
 
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad);
 
 	if (fmt->pad == RWPF_PAD_SOURCE) {
 		/* The RWPF performs format conversion but can't scale, only the
@@ -142,8 +155,8 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 	crop->height = fmt->format.height;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+					    RWPF_PAD_SOURCE);
 	*format = fmt->format;
 
 	return 0;
@@ -154,20 +167,25 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
 	/* Cropping is implemented on the sink pad. */
 	if (sel->pad != RWPF_PAD_SINK)
 		return -EINVAL;
 
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+	if (!config)
+		return -EINVAL;
+
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP:
 		sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
 		break;
 
 	case V4L2_SEL_TGT_CROP_BOUNDS:
-		format = vsp1_entity_get_pad_format(&rwpf->entity, cfg,
-						    RWPF_PAD_SINK, sel->which);
+		format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+						    RWPF_PAD_SINK);
 		sel->r.left = 0;
 		sel->r.top = 0;
 		sel->r.width = format->width;
@@ -186,6 +204,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 	struct v4l2_rect *crop;
 
@@ -196,11 +215,15 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	if (sel->target != V4L2_SEL_TGT_CROP)
 		return -EINVAL;
 
+	config = vsp1_entity_get_pad_config(&rwpf->entity, cfg, sel->which);
+	if (!config)
+		return -EINVAL;
+
 	/* Make sure the crop rectangle is entirely contained in the image. The
 	 * WPF top and left offsets are limited to 255.
 	 */
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK,
-					    sel->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+					    RWPF_PAD_SINK);
 
 	/* Restrict the crop rectangle coordinates to multiples of 2 to avoid
 	 * shifting the color plane.
@@ -227,8 +250,8 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	*crop = sel->r;
 
 	/* Propagate the format to the source pad. */
-	format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE,
-					    sel->which);
+	format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+					    RWPF_PAD_SOURCE);
 	format->width = crop->width;
 	format->height = crop->height;
 
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 043dac6644c1..c9a97ba5a042 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -117,8 +117,10 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (!enable)
 		return 0;
 
-	input = &sru->entity.formats[SRU_PAD_SINK];
-	output = &sru->entity.formats[SRU_PAD_SOURCE];
+	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					   SRU_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					    SRU_PAD_SOURCE);
 
 	if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
 		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
@@ -153,7 +155,6 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
 		MEDIA_BUS_FMT_AYUV8_1X32,
 	};
 	struct vsp1_sru *sru = to_sru(subdev);
-	struct v4l2_mbus_framefmt *format;
 
 	if (code->pad == SRU_PAD_SINK) {
 		if (code->index >= ARRAY_SIZE(codes))
@@ -161,14 +162,22 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
+		struct v4l2_mbus_framefmt *format;
+
 		/* The SRU can't perform format conversion, the sink format is
 		 * always identical to the source format.
 		 */
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-						    SRU_PAD_SINK, code->which);
+		config = vsp1_entity_get_pad_config(&sru->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
+		format = vsp1_entity_get_pad_format(&sru->entity, config,
+						    SRU_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -180,10 +189,14 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-					    SRU_PAD_SINK, fse->which);
+	config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -214,17 +227,21 @@ static int sru_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
+	struct v4l2_subdev_pad_config *config;
+
+	config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
 
-	fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
-						  fmt->which);
+	fmt->format = *vsp1_entity_get_pad_format(&sru->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
 
 static void sru_try_format(struct vsp1_sru *sru,
-			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-			   enum v4l2_subdev_format_whence which)
+			   struct v4l2_subdev_pad_config *config,
+			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
 	struct v4l2_mbus_framefmt *format;
 	unsigned int input_area;
@@ -243,8 +260,8 @@ static void sru_try_format(struct vsp1_sru *sru,
 
 	case SRU_PAD_SOURCE:
 		/* The SRU can't perform format conversion. */
-		format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-						    SRU_PAD_SINK, which);
+		format = vsp1_entity_get_pad_format(&sru->entity, config,
+						    SRU_PAD_SINK);
 		fmt->code = format->code;
 
 		/* We can upscale by 2 in both direction, but not independently.
@@ -278,21 +295,25 @@ static int sru_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_sru *sru = to_sru(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which);
+	config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	sru_try_format(sru, config, fmt->pad, &fmt->format);
 
-	format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
 	*format = fmt->format;
 
 	if (fmt->pad == SRU_PAD_SINK) {
 		/* Propagate the format to the source pad. */
-		format = vsp1_entity_get_pad_format(&sru->entity, cfg,
-						    SRU_PAD_SOURCE, fmt->which);
+		format = vsp1_entity_get_pad_format(&sru->entity, config,
+						    SRU_PAD_SOURCE);
 		*format = fmt->format;
 
-		sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which);
+		sru_try_format(sru, config, SRU_PAD_SOURCE, format);
 	}
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 666fabcd0382..3ba0f6844d1d 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -120,8 +120,10 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
 	if (!enable)
 		return 0;
 
-	input = &uds->entity.formats[UDS_PAD_SINK];
-	output = &uds->entity.formats[UDS_PAD_SOURCE];
+	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					   UDS_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					    UDS_PAD_SOURCE);
 
 	hscale = uds_compute_ratio(input->width, output->width);
 	vscale = uds_compute_ratio(input->height, output->height);
@@ -178,16 +180,22 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
 
 		code->code = codes[code->index];
 	} else {
+		struct v4l2_subdev_pad_config *config;
 		struct v4l2_mbus_framefmt *format;
 
+		config = vsp1_entity_get_pad_config(&uds->entity, cfg,
+						    code->which);
+		if (!config)
+			return -EINVAL;
+
 		/* The UDS can't perform format conversion, the sink format is
 		 * always identical to the source format.
 		 */
 		if (code->index)
 			return -EINVAL;
 
-		format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-						    UDS_PAD_SINK, code->which);
+		format = vsp1_entity_get_pad_format(&uds->entity, config,
+						    UDS_PAD_SINK);
 		code->code = format->code;
 	}
 
@@ -199,10 +207,15 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
 			       struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-					    UDS_PAD_SINK, fse->which);
+	config = vsp1_entity_get_pad_config(&uds->entity, cfg, fse->which);
+	if (!config)
+		return -EINVAL;
+
+	format = vsp1_entity_get_pad_format(&uds->entity, config,
+					    UDS_PAD_SINK);
 
 	if (fse->index || fse->code != format->code)
 		return -EINVAL;
@@ -227,17 +240,21 @@ static int uds_get_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
+	struct v4l2_subdev_pad_config *config;
 
-	fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
-						  fmt->which);
+	config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	fmt->format = *vsp1_entity_get_pad_format(&uds->entity, config,
+						  fmt->pad);
 
 	return 0;
 }
 
 static void uds_try_format(struct vsp1_uds *uds,
-			   struct v4l2_subdev_pad_config *cfg,
-			   unsigned int pad, struct v4l2_mbus_framefmt *fmt,
-			   enum v4l2_subdev_format_whence which)
+			   struct v4l2_subdev_pad_config *config,
+			   unsigned int pad, struct v4l2_mbus_framefmt *fmt)
 {
 	struct v4l2_mbus_framefmt *format;
 	unsigned int minimum;
@@ -256,8 +273,8 @@ static void uds_try_format(struct vsp1_uds *uds,
 
 	case UDS_PAD_SOURCE:
 		/* The UDS scales but can't perform format conversion. */
-		format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-						    UDS_PAD_SINK, which);
+		format = vsp1_entity_get_pad_format(&uds->entity, config,
+						    UDS_PAD_SINK);
 		fmt->code = format->code;
 
 		uds_output_limits(format->width, &minimum, &maximum);
@@ -276,21 +293,25 @@ static int uds_set_format(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_uds *uds = to_uds(subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *format;
 
-	uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which);
+	config = vsp1_entity_get_pad_config(&uds->entity, cfg, fmt->which);
+	if (!config)
+		return -EINVAL;
+
+	uds_try_format(uds, config, fmt->pad, &fmt->format);
 
-	format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad,
-					    fmt->which);
+	format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad);
 	*format = fmt->format;
 
 	if (fmt->pad == UDS_PAD_SINK) {
 		/* Propagate the format to the source pad. */
-		format = vsp1_entity_get_pad_format(&uds->entity, cfg,
-						    UDS_PAD_SOURCE, fmt->which);
+		format = vsp1_entity_get_pad_format(&uds->entity, config,
+						    UDS_PAD_SOURCE);
 		*format = fmt->format;
 
-		uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which);
+		uds_try_format(uds, config, UDS_PAD_SOURCE, format);
 	}
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d46910db7e08..c86d31f274bf 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -42,6 +42,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *wpf = to_rwpf(subdev);
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
+	const struct v4l2_mbus_framefmt *source_format;
+	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop = &wpf->crop;
 	unsigned int i;
 	u32 srcrpf = 0;
@@ -94,6 +96,13 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
 	/* Format */
+	sink_format = vsp1_entity_get_pad_format(&wpf->entity,
+						 wpf->entity.config,
+						 RWPF_PAD_SINK);
+	source_format = vsp1_entity_get_pad_format(&wpf->entity,
+						   wpf->entity.config,
+						   RWPF_PAD_SOURCE);
+
 	if (!pipe->lif) {
 		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
 
@@ -109,8 +118,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
 	}
 
-	if (wpf->entity.formats[RWPF_PAD_SINK].code !=
-	    wpf->entity.formats[RWPF_PAD_SOURCE].code)
+	if (sink_format->code != source_format->code)
 		outfmt |= VI6_WPF_OUTFMT_CSC;
 
 	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 41/48] v4l: vsp1: Store active selection rectangles in a pad config structure
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Use the pad config structure part of the vsp1_entity to store all active
pad selection rectangles. This generalizes the code to operate on pad
config structures, a prerequisite to implement the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 24 +++++++++++-------------
 drivers/media/platform/vsp1/vsp1_bru.h    |  1 -
 drivers/media/platform/vsp1/vsp1_drm.c    |  5 ++---
 drivers/media/platform/vsp1/vsp1_entity.c |  8 ++++++++
 drivers/media/platform/vsp1/vsp1_entity.h |  4 ++++
 drivers/media/platform/vsp1/vsp1_rpf.c    | 20 +++++++++++++++++---
 drivers/media/platform/vsp1/vsp1_rwpf.c   | 22 +++++++---------------
 drivers/media/platform/vsp1/vsp1_rwpf.h   |  8 +++-----
 drivers/media/platform/vsp1/vsp1_video.c  | 13 +++----------
 drivers/media/platform/vsp1/vsp1_wpf.c    |  4 +++-
 10 files changed, 58 insertions(+), 51 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index a0aa0fb2a5e1..c1848a3ac010 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -231,17 +231,9 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev,
 
 static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
 					 struct v4l2_subdev_pad_config *cfg,
-					 unsigned int pad, u32 which)
+					 unsigned int pad)
 {
-	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg,
-						   pad);
-	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &bru->inputs[pad].compose;
-	default:
-		return NULL;
-	}
+	return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg, pad);
 }
 
 static int bru_get_format(struct v4l2_subdev *subdev,
@@ -310,7 +302,7 @@ static int bru_set_format(struct v4l2_subdev *subdev,
 	if (fmt->pad != bru->entity.source_pad) {
 		struct v4l2_rect *compose;
 
-		compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which);
+		compose = bru_get_compose(bru, config, fmt->pad);
 		compose->left = 0;
 		compose->top = 0;
 		compose->width = format->width;
@@ -336,6 +328,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
 			     struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
 
 	if (sel->pad = bru->entity.source_pad)
 		return -EINVAL;
@@ -349,7 +342,12 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
 		return 0;
 
 	case V4L2_SEL_TGT_COMPOSE:
-		sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which);
+		config = vsp1_entity_get_pad_config(&bru->entity, cfg,
+						    sel->which);
+		if (!config)
+			return -EINVAL;
+
+		sel->r = *bru_get_compose(bru, config, sel->pad);
 		return 0;
 
 	default:
@@ -391,7 +389,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 	sel->r.width = format->width;
 	sel->r.height = format->height;
 
-	compose = bru_get_compose(bru, cfg, sel->pad, sel->which);
+	compose = bru_get_compose(bru, config, sel->pad);
 	*compose = sel->r;
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
index 4e7d2e79b940..828a3fcadea8 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.h
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -31,7 +31,6 @@ struct vsp1_bru {
 
 	struct {
 		struct vsp1_rwpf *rpf;
-		struct v4l2_rect compose;
 	} inputs[VSP1_MAX_RPF];
 
 	u32 bgcolor;
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 90157ac9b0b1..e1216732e192 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -410,9 +410,8 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 		__func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
 		sel.pad);
 
-	/* Store the compose rectangle coordinates in the RPF. */
-	rpf->location.left = dst->left;
-	rpf->location.top = dst->top;
+	/* Store the BRU input pad number in the RPF. */
+	rpf->bru_input = rpf->entity.index;
 
 	/* Cache the memory buffer address but don't apply the values to the
 	 * hardware as the crop offsets haven't been computed yet.
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 3ccc83781d4e..0620f1772cab 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -89,6 +89,14 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 	return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
 }
 
+struct v4l2_rect *
+vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
+			    struct v4l2_subdev_pad_config *cfg,
+			    unsigned int pad)
+{
+	return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
+}
+
 /*
  * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 086dc2b22d61..1b0e31ec0f1f 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -111,6 +111,10 @@ struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad);
+struct v4l2_rect *
+vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
+			    struct v4l2_subdev_pad_config *cfg,
+			    unsigned int pad);
 void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_pad_config *cfg);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 3b55cd93983f..cb3d5ed148cc 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -44,7 +44,9 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
-	const struct v4l2_rect *crop = &rpf->crop;
+	const struct v4l2_rect *crop;
+	unsigned int left = 0;
+	unsigned int top = 0;
 	u32 pstride;
 	u32 infmt;
 
@@ -57,6 +59,8 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	 * left corner in the plane buffer. Only two offsets are needed, as
 	 * planes 2 and 3 always have identical strides.
 	 */
+	crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+
 	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
 		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
@@ -103,9 +107,19 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
 
 	/* Output location */
+	if (pipe->bru) {
+		const struct v4l2_rect *compose;
+
+		compose = vsp1_entity_get_pad_compose(pipe->bru,
+						      pipe->bru->config,
+						      rpf->bru_input);
+		left = compose->left;
+		top = compose->top;
+	}
+
 	vsp1_rpf_write(rpf, VI6_RPF_LOC,
-		       (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) |
-		       (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT));
+		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
+		       (top << VI6_RPF_LOC_VCOORD_SHIFT));
 
 	/* Use the alpha channel (extended to 8 bits) when available or an
 	 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index e5216d39723e..0c5ad023adfb 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -76,19 +76,11 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static struct v4l2_rect *
-vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg,
-		   u32 which)
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+				     struct v4l2_subdev_pad_config *config)
 {
-	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg,
-						RWPF_PAD_SINK);
-	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &rwpf->crop;
-	default:
-		return NULL;
-	}
+	return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+					RWPF_PAD_SINK);
 }
 
 int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
@@ -148,7 +140,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Update the sink crop rectangle. */
-	crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which);
+	crop = vsp1_rwpf_get_crop(rwpf, config);
 	crop->left = 0;
 	crop->top = 0;
 	crop->width = fmt->format.width;
@@ -180,7 +172,7 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP:
-		sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
+		sel->r = *vsp1_rwpf_get_crop(rwpf, config);
 		break;
 
 	case V4L2_SEL_TGT_CROP_BOUNDS:
@@ -246,7 +238,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	sel->r.height = min_t(unsigned int, sel->r.height,
 			      format->height - sel->r.top);
 
-	crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
+	crop = vsp1_rwpf_get_crop(rwpf, config);
 	*crop = sel->r;
 
 	/* Propagate the format to the source pad. */
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index e8ca9b6ee689..4ebfab61e0ef 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -43,11 +43,7 @@ struct vsp1_rwpf {
 
 	struct v4l2_pix_format_mplane format;
 	const struct vsp1_format_info *fmtinfo;
-	struct {
-		unsigned int left;
-		unsigned int top;
-	} location;
-	struct v4l2_rect crop;
+	unsigned int bru_input;
 
 	unsigned int alpha;
 
@@ -91,6 +87,8 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_selection *sel);
 
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+				     struct v4l2_subdev_pad_config *config);
 /**
  * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
  * @rwpf: the [RW]PF instance
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index ec1394289659..b1cb6b8a2452 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -211,9 +211,6 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
 	struct media_pad *pad;
 	bool bru_found = false;
 
-	input->location.left = 0;
-	input->location.top = 0;
-
 	pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
 
 	while (1) {
@@ -226,18 +223,14 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
 
 		entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
 
-		/* A BRU is present in the pipeline, store the compose rectangle
-		 * location in the input RPF for use when configuring the RPF.
+		/* A BRU is present in the pipeline, store the BRU input pad
+		 * number in the input RPF for use when configuring the RPF.
 		 */
 		if (entity->type = VSP1_ENTITY_BRU) {
 			struct vsp1_bru *bru = to_bru(&entity->subdev);
-			struct v4l2_rect *rect -				&bru->inputs[pad->index].compose;
 
 			bru->inputs[pad->index].rpf = input;
-
-			input->location.left = rect->left;
-			input->location.top = rect->top;
+			input->bru_input = pad->index;
 
 			bru_found = true;
 		}
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index c86d31f274bf..0797927d14cf 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -44,7 +44,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
-	const struct v4l2_rect *crop = &wpf->crop;
+	const struct v4l2_rect *crop;
 	unsigned int i;
 	u32 srcrpf = 0;
 	u32 outfmt = 0;
@@ -88,6 +88,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 				       format->plane_fmt[1].bytesperline);
 	}
 
+	crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
+
 	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 41/48] v4l: vsp1: Store active selection rectangles in a pad config structure
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Use the pad config structure part of the vsp1_entity to store all active
pad selection rectangles. This generalizes the code to operate on pad
config structures, a prerequisite to implement the request API.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 24 +++++++++++-------------
 drivers/media/platform/vsp1/vsp1_bru.h    |  1 -
 drivers/media/platform/vsp1/vsp1_drm.c    |  5 ++---
 drivers/media/platform/vsp1/vsp1_entity.c |  8 ++++++++
 drivers/media/platform/vsp1/vsp1_entity.h |  4 ++++
 drivers/media/platform/vsp1/vsp1_rpf.c    | 20 +++++++++++++++++---
 drivers/media/platform/vsp1/vsp1_rwpf.c   | 22 +++++++---------------
 drivers/media/platform/vsp1/vsp1_rwpf.h   |  8 +++-----
 drivers/media/platform/vsp1/vsp1_video.c  | 13 +++----------
 drivers/media/platform/vsp1/vsp1_wpf.c    |  4 +++-
 10 files changed, 58 insertions(+), 51 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index a0aa0fb2a5e1..c1848a3ac010 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -231,17 +231,9 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev,
 
 static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
 					 struct v4l2_subdev_pad_config *cfg,
-					 unsigned int pad, u32 which)
+					 unsigned int pad)
 {
-	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg,
-						   pad);
-	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &bru->inputs[pad].compose;
-	default:
-		return NULL;
-	}
+	return v4l2_subdev_get_try_compose(&bru->entity.subdev, cfg, pad);
 }
 
 static int bru_get_format(struct v4l2_subdev *subdev,
@@ -310,7 +302,7 @@ static int bru_set_format(struct v4l2_subdev *subdev,
 	if (fmt->pad != bru->entity.source_pad) {
 		struct v4l2_rect *compose;
 
-		compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which);
+		compose = bru_get_compose(bru, config, fmt->pad);
 		compose->left = 0;
 		compose->top = 0;
 		compose->width = format->width;
@@ -336,6 +328,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
 			     struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_bru *bru = to_bru(subdev);
+	struct v4l2_subdev_pad_config *config;
 
 	if (sel->pad == bru->entity.source_pad)
 		return -EINVAL;
@@ -349,7 +342,12 @@ static int bru_get_selection(struct v4l2_subdev *subdev,
 		return 0;
 
 	case V4L2_SEL_TGT_COMPOSE:
-		sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which);
+		config = vsp1_entity_get_pad_config(&bru->entity, cfg,
+						    sel->which);
+		if (!config)
+			return -EINVAL;
+
+		sel->r = *bru_get_compose(bru, config, sel->pad);
 		return 0;
 
 	default:
@@ -391,7 +389,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 	sel->r.width = format->width;
 	sel->r.height = format->height;
 
-	compose = bru_get_compose(bru, cfg, sel->pad, sel->which);
+	compose = bru_get_compose(bru, config, sel->pad);
 	*compose = sel->r;
 
 	return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
index 4e7d2e79b940..828a3fcadea8 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.h
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -31,7 +31,6 @@ struct vsp1_bru {
 
 	struct {
 		struct vsp1_rwpf *rpf;
-		struct v4l2_rect compose;
 	} inputs[VSP1_MAX_RPF];
 
 	u32 bgcolor;
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 90157ac9b0b1..e1216732e192 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -410,9 +410,8 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 		__func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
 		sel.pad);
 
-	/* Store the compose rectangle coordinates in the RPF. */
-	rpf->location.left = dst->left;
-	rpf->location.top = dst->top;
+	/* Store the BRU input pad number in the RPF. */
+	rpf->bru_input = rpf->entity.index;
 
 	/* Cache the memory buffer address but don't apply the values to the
 	 * hardware as the crop offsets haven't been computed yet.
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 3ccc83781d4e..0620f1772cab 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -89,6 +89,14 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 	return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
 }
 
+struct v4l2_rect *
+vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
+			    struct v4l2_subdev_pad_config *cfg,
+			    unsigned int pad)
+{
+	return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
+}
+
 /*
  * vsp1_entity_init_cfg - Initialize formats on all pads
  * @subdev: V4L2 subdevice
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 086dc2b22d61..1b0e31ec0f1f 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -111,6 +111,10 @@ struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   unsigned int pad);
+struct v4l2_rect *
+vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
+			    struct v4l2_subdev_pad_config *cfg,
+			    unsigned int pad);
 void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_pad_config *cfg);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 3b55cd93983f..cb3d5ed148cc 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -44,7 +44,9 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
-	const struct v4l2_rect *crop = &rpf->crop;
+	const struct v4l2_rect *crop;
+	unsigned int left = 0;
+	unsigned int top = 0;
 	u32 pstride;
 	u32 infmt;
 
@@ -57,6 +59,8 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	 * left corner in the plane buffer. Only two offsets are needed, as
 	 * planes 2 and 3 always have identical strides.
 	 */
+	crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+
 	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
 		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
@@ -103,9 +107,19 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
 
 	/* Output location */
+	if (pipe->bru) {
+		const struct v4l2_rect *compose;
+
+		compose = vsp1_entity_get_pad_compose(pipe->bru,
+						      pipe->bru->config,
+						      rpf->bru_input);
+		left = compose->left;
+		top = compose->top;
+	}
+
 	vsp1_rpf_write(rpf, VI6_RPF_LOC,
-		       (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) |
-		       (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT));
+		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
+		       (top << VI6_RPF_LOC_VCOORD_SHIFT));
 
 	/* Use the alpha channel (extended to 8 bits) when available or an
 	 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index e5216d39723e..0c5ad023adfb 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -76,19 +76,11 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-static struct v4l2_rect *
-vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg,
-		   u32 which)
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+				     struct v4l2_subdev_pad_config *config)
 {
-	switch (which) {
-	case V4L2_SUBDEV_FORMAT_TRY:
-		return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg,
-						RWPF_PAD_SINK);
-	case V4L2_SUBDEV_FORMAT_ACTIVE:
-		return &rwpf->crop;
-	default:
-		return NULL;
-	}
+	return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+					RWPF_PAD_SINK);
 }
 
 int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
@@ -148,7 +140,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 	fmt->format = *format;
 
 	/* Update the sink crop rectangle. */
-	crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which);
+	crop = vsp1_rwpf_get_crop(rwpf, config);
 	crop->left = 0;
 	crop->top = 0;
 	crop->width = fmt->format.width;
@@ -180,7 +172,7 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 
 	switch (sel->target) {
 	case V4L2_SEL_TGT_CROP:
-		sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
+		sel->r = *vsp1_rwpf_get_crop(rwpf, config);
 		break;
 
 	case V4L2_SEL_TGT_CROP_BOUNDS:
@@ -246,7 +238,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	sel->r.height = min_t(unsigned int, sel->r.height,
 			      format->height - sel->r.top);
 
-	crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which);
+	crop = vsp1_rwpf_get_crop(rwpf, config);
 	*crop = sel->r;
 
 	/* Propagate the format to the source pad. */
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index e8ca9b6ee689..4ebfab61e0ef 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -43,11 +43,7 @@ struct vsp1_rwpf {
 
 	struct v4l2_pix_format_mplane format;
 	const struct vsp1_format_info *fmtinfo;
-	struct {
-		unsigned int left;
-		unsigned int top;
-	} location;
-	struct v4l2_rect crop;
+	unsigned int bru_input;
 
 	unsigned int alpha;
 
@@ -91,6 +87,8 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 			    struct v4l2_subdev_pad_config *cfg,
 			    struct v4l2_subdev_selection *sel);
 
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+				     struct v4l2_subdev_pad_config *config);
 /**
  * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
  * @rwpf: the [RW]PF instance
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index ec1394289659..b1cb6b8a2452 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -211,9 +211,6 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
 	struct media_pad *pad;
 	bool bru_found = false;
 
-	input->location.left = 0;
-	input->location.top = 0;
-
 	pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]);
 
 	while (1) {
@@ -226,18 +223,14 @@ static int vsp1_video_pipeline_validate_branch(struct vsp1_pipeline *pipe,
 
 		entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
 
-		/* A BRU is present in the pipeline, store the compose rectangle
-		 * location in the input RPF for use when configuring the RPF.
+		/* A BRU is present in the pipeline, store the BRU input pad
+		 * number in the input RPF for use when configuring the RPF.
 		 */
 		if (entity->type == VSP1_ENTITY_BRU) {
 			struct vsp1_bru *bru = to_bru(&entity->subdev);
-			struct v4l2_rect *rect =
-				&bru->inputs[pad->index].compose;
 
 			bru->inputs[pad->index].rpf = input;
-
-			input->location.left = rect->left;
-			input->location.top = rect->top;
+			input->bru_input = pad->index;
 
 			bru_found = true;
 		}
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index c86d31f274bf..0797927d14cf 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -44,7 +44,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
-	const struct v4l2_rect *crop = &wpf->crop;
+	const struct v4l2_rect *crop;
 	unsigned int i;
 	u32 srcrpf = 0;
 	u32 outfmt = 0;
@@ -88,6 +88,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 				       format->plane_fmt[1].bytesperline);
 	}
 
+	crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
+
 	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 42/48] v4l: vsp1: Create a new configure operation to setup modules
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The subdev s_stream operation is abused as a generic way to setup
modules at every frame. Move the code out to a new VSP1 entity configure
operation.

Most modules now have an empty s_stream operation that can be removed.
The only exception is the WPF module that needs to perform hardware
configuration when stopping the stream. The code can be simplified
accordingly as we know that that operation never fails.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 231 ++++++++++++++----------------
 drivers/media/platform/vsp1/vsp1_drm.c    |  14 +-
 drivers/media/platform/vsp1/vsp1_entity.h |   3 +
 drivers/media/platform/vsp1/vsp1_hsit.c   |  50 +++----
 drivers/media/platform/vsp1/vsp1_lif.c    |  77 +++++-----
 drivers/media/platform/vsp1/vsp1_lut.c    |  41 +++---
 drivers/media/platform/vsp1/vsp1_pipe.c   |   4 +-
 drivers/media/platform/vsp1/vsp1_rpf.c    |  83 +++++------
 drivers/media/platform/vsp1/vsp1_sru.c    |  91 ++++++------
 drivers/media/platform/vsp1/vsp1_uds.c    | 117 ++++++++-------
 drivers/media/platform/vsp1/vsp1_video.c  |  15 +-
 drivers/media/platform/vsp1/vsp1_wpf.c    | 118 ++++++++-------
 12 files changed, 394 insertions(+), 450 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index c1848a3ac010..4ab0a805d4b2 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -56,117 +56,7 @@ static const struct v4l2_ctrl_ops bru_ctrl_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-	struct vsp1_bru *bru = to_bru(subdev);
-	struct v4l2_mbus_framefmt *format;
-	unsigned int flags;
-	unsigned int i;
-
-	if (!enable)
-		return 0;
-
-	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
-					    bru->entity.source_pad);
-
-	/* The hardware is extremely flexible but we have no userspace API to
-	 * expose all the parameters, nor is it clear whether we would have use
-	 * cases for all the supported modes. Let's just harcode the parameters
-	 * to sane default values for now.
-	 */
-
-	/* Disable dithering and enable color data normalization unless the
-	 * format at the pipeline output is premultiplied.
-	 */
-	flags = pipe->output ? pipe->output->format.flags : 0;
-	vsp1_bru_write(bru, VI6_BRU_INCTRL,
-		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
-		       0 : VI6_BRU_INCTRL_NRM);
-
-	/* Set the background position to cover the whole output image and
-	 * configure its color.
-	 */
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
-		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
-		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
-
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
-		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
-
-	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
-	 * unit with a NOP operation to make BRU input 1 available as the
-	 * Blend/ROP unit B SRC input.
-	 */
-	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
-		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
-		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));
-
-	for (i = 0; i < bru->entity.source_pad; ++i) {
-		bool premultiplied = false;
-		u32 ctrl = 0;
-
-		/* Configure all Blend/ROP units corresponding to an enabled BRU
-		 * input for alpha blending. Blend/ROP units corresponding to
-		 * disabled BRU inputs are used in ROP NOP mode to ignore the
-		 * SRC input.
-		 */
-		if (bru->inputs[i].rpf) {
-			ctrl |= VI6_BRU_CTRL_RBC;
-
-			premultiplied = bru->inputs[i].rpf->format.flags
-				      & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
-		} else {
-			ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
-			     |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
-		}
-
-		/* Select the virtual RPF as the Blend/ROP unit A DST input to
-		 * serve as a background color.
-		 */
-		if (i = 0)
-			ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
-
-		/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
-		 * D in that order. The Blend/ROP unit B SRC is hardwired to the
-		 * ROP unit output, the corresponding register bits must be set
-		 * to 0.
-		 */
-		if (i != 1)
-			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
-
-		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
-
-		/* Harcode the blending formula to
-		 *
-		 *	DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
-		 *	DSTa = DSTa * (1 - SRCa) + SRCa
-		 *
-		 * when the SRC input isn't premultiplied, and to
-		 *
-		 *	DSTc = DSTc * (1 - SRCa) + SRCc
-		 *	DSTa = DSTa * (1 - SRCa) + SRCa
-		 *
-		 * otherwise.
-		 */
-		vsp1_bru_write(bru, VI6_BRU_BLD(i),
-			       VI6_BRU_BLD_CCMDX_255_SRC_A |
-			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
-						VI6_BRU_BLD_CCMDY_SRC_A) |
-			       VI6_BRU_BLD_ACMDX_255_SRC_A |
-			       VI6_BRU_BLD_ACMDY_COEFY |
-			       (0xff << VI6_BRU_BLD_COEFY_SHIFT));
-	}
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 /*
@@ -395,14 +285,6 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops bru_video_ops = {
-	.s_stream = bru_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops bru_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = bru_enum_mbus_code,
@@ -414,11 +296,119 @@ static struct v4l2_subdev_pad_ops bru_pad_ops = {
 };
 
 static struct v4l2_subdev_ops bru_ops = {
-	.video	= &bru_video_ops,
 	.pad    = &bru_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void bru_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
+	struct vsp1_bru *bru = to_bru(&entity->subdev);
+	struct v4l2_mbus_framefmt *format;
+	unsigned int flags;
+	unsigned int i;
+
+	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+					    bru->entity.source_pad);
+
+	/* The hardware is extremely flexible but we have no userspace API to
+	 * expose all the parameters, nor is it clear whether we would have use
+	 * cases for all the supported modes. Let's just harcode the parameters
+	 * to sane default values for now.
+	 */
+
+	/* Disable dithering and enable color data normalization unless the
+	 * format at the pipeline output is premultiplied.
+	 */
+	flags = pipe->output ? pipe->output->format.flags : 0;
+	vsp1_bru_write(bru, VI6_BRU_INCTRL,
+		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
+		       0 : VI6_BRU_INCTRL_NRM);
+
+	/* Set the background position to cover the whole output image and
+	 * configure its color.
+	 */
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
+		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
+		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
+
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+
+	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
+	 * unit with a NOP operation to make BRU input 1 available as the
+	 * Blend/ROP unit B SRC input.
+	 */
+	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
+		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
+		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));
+
+	for (i = 0; i < bru->entity.source_pad; ++i) {
+		bool premultiplied = false;
+		u32 ctrl = 0;
+
+		/* Configure all Blend/ROP units corresponding to an enabled BRU
+		 * input for alpha blending. Blend/ROP units corresponding to
+		 * disabled BRU inputs are used in ROP NOP mode to ignore the
+		 * SRC input.
+		 */
+		if (bru->inputs[i].rpf) {
+			ctrl |= VI6_BRU_CTRL_RBC;
+
+			premultiplied = bru->inputs[i].rpf->format.flags
+				      & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
+		} else {
+			ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
+			     |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
+		}
+
+		/* Select the virtual RPF as the Blend/ROP unit A DST input to
+		 * serve as a background color.
+		 */
+		if (i = 0)
+			ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
+
+		/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
+		 * D in that order. The Blend/ROP unit B SRC is hardwired to the
+		 * ROP unit output, the corresponding register bits must be set
+		 * to 0.
+		 */
+		if (i != 1)
+			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
+
+		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
+
+		/* Harcode the blending formula to
+		 *
+		 *	DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
+		 *	DSTa = DSTa * (1 - SRCa) + SRCa
+		 *
+		 * when the SRC input isn't premultiplied, and to
+		 *
+		 *	DSTc = DSTc * (1 - SRCa) + SRCc
+		 *	DSTa = DSTa * (1 - SRCa) + SRCa
+		 *
+		 * otherwise.
+		 */
+		vsp1_bru_write(bru, VI6_BRU_BLD(i),
+			       VI6_BRU_BLD_CCMDX_255_SRC_A |
+			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
+						VI6_BRU_BLD_CCMDY_SRC_A) |
+			       VI6_BRU_BLD_ACMDX_255_SRC_A |
+			       VI6_BRU_BLD_ACMDY_COEFY |
+			       (0xff << VI6_BRU_BLD_COEFY_SHIFT));
+	}
+}
+
+static const struct vsp1_entity_operations bru_entity_ops = {
+	.configure = bru_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -431,6 +421,7 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 	if (bru = NULL)
 		return ERR_PTR(-ENOMEM);
 
+	bru->entity.ops = &bru_entity_ops;
 	bru->entity.type = VSP1_ENTITY_BRU;
 
 	ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index e1216732e192..f1f728271cc3 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -448,7 +448,6 @@ void vsp1_du_atomic_flush(struct device *dev)
 	struct vsp1_entity *entity;
 	unsigned long flags;
 	bool stop = false;
-	int ret;
 
 	list_for_each_entry(entity, &pipe->entities, list_pipe) {
 		/* Disconnect unused RPFs from the pipeline. */
@@ -464,19 +463,16 @@ void vsp1_du_atomic_flush(struct device *dev)
 
 		vsp1_entity_route_setup(entity);
 
-		ret = v4l2_subdev_call(&entity->subdev, video,
-				       s_stream, 1);
-		if (ret < 0) {
-			dev_err(vsp1->dev,
-				"DRM pipeline start failure on entity %s\n",
-				entity->subdev.name);
-			return;
-		}
+		if (entity->ops->configure)
+			entity->ops->configure(entity);
 
 		if (entity->type = VSP1_ENTITY_RPF)
 			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
 	}
 
+	/* We know that the WPF s_stream operation never fails. */
+	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
+
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 1b0e31ec0f1f..c83b5a852bfc 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -59,10 +59,13 @@ struct vsp1_route {
  * @set_memory:	Setup memory buffer access. This operation applies the settings
  *		stored in the rwpf mem field to the hardware. Valid for RPF and
  *		WPF only.
+ * @configure:	Setup the hardware based on the entity state (pipeline, formats,
+ *		selection rectangles, ...)
  */
 struct vsp1_entity_operations {
 	void (*destroy)(struct vsp1_entity *);
 	void (*set_memory)(struct vsp1_entity *);
+	void (*configure)(struct vsp1_entity *);
 };
 
 struct vsp1_entity {
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 4f87f6f8ee38..7360586c902a 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -32,26 +32,7 @@ static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_hsit *hsit = to_hsit(subdev);
-
-	if (!enable)
-		return 0;
-
-	if (hsit->inverse)
-		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
-	else
-		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -167,14 +148,6 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops hsit_video_ops = {
-	.s_stream = hsit_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops hsit_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = hsit_enum_mbus_code,
@@ -184,11 +157,28 @@ static struct v4l2_subdev_pad_ops hsit_pad_ops = {
 };
 
 static struct v4l2_subdev_ops hsit_ops = {
-	.video	= &hsit_video_ops,
 	.pad    = &hsit_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void hsit_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
+
+	if (hsit->inverse)
+		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
+	else
+		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
+}
+
+static const struct vsp1_entity_operations hsit_entity_ops = {
+	.configure = hsit_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -203,6 +193,8 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 
 	hsit->inverse = inverse;
 
+	hsit->entity.ops = &hsit_entity_ops;
+
 	if (inverse)
 		hsit->entity.type = VSP1_ENTITY_HSI;
 	else
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 6a80a04ea392..a0fad552af5d 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -32,41 +32,7 @@ static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	const struct v4l2_mbus_framefmt *format;
-	struct vsp1_lif *lif = to_lif(subdev);
-	unsigned int hbth = 1300;
-	unsigned int obth = 400;
-	unsigned int lbth = 200;
-
-	if (!enable) {
-		vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0);
-		return 0;
-	}
-
-	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
-					    LIF_PAD_SOURCE);
-
-	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
-
-	vsp1_lif_write(lif, VI6_LIF_CSBTH,
-			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
-			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
-
-	vsp1_lif_write(lif, VI6_LIF_CTRL,
-			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
-			(format->code = 0 ? VI6_LIF_CTRL_CFMT : 0) |
-			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -200,14 +166,6 @@ static int lif_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops lif_video_ops = {
-	.s_stream = lif_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops lif_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lif_enum_mbus_code,
@@ -217,11 +175,41 @@ static struct v4l2_subdev_pad_ops lif_pad_ops = {
 };
 
 static struct v4l2_subdev_ops lif_ops = {
-	.video	= &lif_video_ops,
 	.pad    = &lif_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void lif_configure(struct vsp1_entity *entity)
+{
+	const struct v4l2_mbus_framefmt *format;
+	struct vsp1_lif *lif = to_lif(&entity->subdev);
+	unsigned int hbth = 1300;
+	unsigned int obth = 400;
+	unsigned int lbth = 200;
+
+	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+					    LIF_PAD_SOURCE);
+
+	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
+
+	vsp1_lif_write(lif, VI6_LIF_CSBTH,
+			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
+			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
+
+	vsp1_lif_write(lif, VI6_LIF_CTRL,
+			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
+			(format->code = 0 ? VI6_LIF_CTRL_CFMT : 0) |
+			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
+}
+
+static const struct vsp1_entity_operations lif_entity_ops = {
+	.configure = lif_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -234,6 +222,7 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 	if (lif = NULL)
 		return ERR_PTR(-ENOMEM);
 
+	lif->entity.ops = &lif_entity_ops;
 	lif->entity.type = VSP1_ENTITY_LIF;
 
 	ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index a5b839b28320..d5d32ce10f41 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -36,7 +36,7 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
  * V4L2 Subdevice Core Operations
  */
 
-static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config)
+static void lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config)
 {
 	memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
 		    sizeof(config->lut));
@@ -48,7 +48,7 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
 
 	switch (cmd) {
 	case VIDIOC_VSP1_LUT_CONFIG:
-		lut_configure(lut, arg);
+		lut_set_table(lut, arg);
 		return 0;
 
 	default:
@@ -57,22 +57,6 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Video Operations
- */
-
-static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_lut *lut = to_lut(subdev);
-
-	if (!enable)
-		return 0;
-
-	vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
@@ -218,10 +202,6 @@ static struct v4l2_subdev_core_ops lut_core_ops = {
 	.ioctl = lut_ioctl,
 };
 
-static struct v4l2_subdev_video_ops lut_video_ops = {
-	.s_stream = lut_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops lut_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lut_enum_mbus_code,
@@ -232,11 +212,25 @@ static struct v4l2_subdev_pad_ops lut_pad_ops = {
 
 static struct v4l2_subdev_ops lut_ops = {
 	.core	= &lut_core_ops,
-	.video	= &lut_video_ops,
 	.pad    = &lut_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void lut_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_lut *lut = to_lut(&entity->subdev);
+
+	vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
+}
+
+static const struct vsp1_entity_operations lut_entity_ops = {
+	.configure = lut_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -249,6 +243,7 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 	if (lut = NULL)
 		return ERR_PTR(-ENOMEM);
 
+	lut->entity.ops = &lut_entity_ops;
 	lut->entity.type = VSP1_ENTITY_LUT;
 
 	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index dd0921b31e98..5e91277c2972 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -232,10 +232,10 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
 		if (entity->route && entity->route->reg)
 			vsp1_write(entity->vsp1, entity->route->reg,
 				   VI6_DPR_NODE_UNUSED);
-
-		v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
 	}
 
+	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0);
+
 	return ret;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index cb3d5ed148cc..eb17fa134750 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -33,13 +33,43 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
+ * V4L2 Subdevice Operations
  */
 
-static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
+static struct v4l2_subdev_pad_ops rpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
+	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+	.enum_frame_size = vsp1_rwpf_enum_frame_size,
+	.get_fmt = vsp1_rwpf_get_format,
+	.set_fmt = vsp1_rwpf_set_format,
+	.get_selection = vsp1_rwpf_get_selection,
+	.set_selection = vsp1_rwpf_set_selection,
+};
+
+static struct v4l2_subdev_ops rpf_ops = {
+	.pad    = &rpf_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void rpf_set_memory(struct vsp1_entity *entity)
 {
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-	struct vsp1_rwpf *rpf = to_rwpf(subdev);
+	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
+
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
+		       rpf->mem.addr[0] + rpf->offsets[0]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+		       rpf->mem.addr[1] + rpf->offsets[1]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+		       rpf->mem.addr[2] + rpf->offsets[1]);
+}
+
+static void rpf_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
+	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_mbus_framefmt *source_format;
@@ -50,9 +80,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	u32 pstride;
 	u32 infmt;
 
-	if (!enable)
-		return 0;
-
 	/* Source size, stride and crop offsets.
 	 *
 	 * The crop offsets correspond to the location of the crop rectangle top
@@ -136,51 +163,11 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
 	vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
 	vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops rpf_video_ops = {
-	.s_stream = rpf_s_stream,
-};
-
-static struct v4l2_subdev_pad_ops rpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
-static struct v4l2_subdev_ops rpf_ops = {
-	.video	= &rpf_video_ops,
-	.pad    = &rpf_pad_ops,
-};
-
-/* -----------------------------------------------------------------------------
- * VSP1 Entity Operations
- */
-
-static void rpf_set_memory(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
-
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->mem.addr[0] + rpf->offsets[0]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-		       rpf->mem.addr[1] + rpf->offsets[1]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_entity_operations rpf_entity_ops = {
 	.set_memory = rpf_set_memory,
+	.configure = rpf_configure,
 };
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index c9a97ba5a042..e05149eabde9 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -103,47 +103,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	const struct vsp1_sru_param *param;
-	struct vsp1_sru *sru = to_sru(subdev);
-	struct v4l2_mbus_framefmt *input;
-	struct v4l2_mbus_framefmt *output;
-	u32 ctrl0;
-
-	if (!enable)
-		return 0;
-
-	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
-					   SRU_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
-					    SRU_PAD_SOURCE);
-
-	if (input->code = MEDIA_BUS_FMT_ARGB8888_1X32)
-		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
-		      | VI6_SRU_CTRL0_PARAM4;
-	else
-		ctrl0 = VI6_SRU_CTRL0_PARAM3;
-
-	if (input->width != output->width)
-		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
-
-	param = &vsp1_sru_params[sru->intensity - 1];
-
-	ctrl0 |= param->ctrl0;
-
-	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
-	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -319,14 +279,6 @@ static int sru_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops sru_video_ops = {
-	.s_stream = sru_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops sru_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = sru_enum_mbus_code,
@@ -336,11 +288,49 @@ static struct v4l2_subdev_pad_ops sru_pad_ops = {
 };
 
 static struct v4l2_subdev_ops sru_ops = {
-	.video	= &sru_video_ops,
 	.pad    = &sru_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void sru_configure(struct vsp1_entity *entity)
+{
+	const struct vsp1_sru_param *param;
+	struct vsp1_sru *sru = to_sru(&entity->subdev);
+	struct v4l2_mbus_framefmt *input;
+	struct v4l2_mbus_framefmt *output;
+	u32 ctrl0;
+
+	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					   SRU_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					    SRU_PAD_SOURCE);
+
+	if (input->code = MEDIA_BUS_FMT_ARGB8888_1X32)
+		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
+		      | VI6_SRU_CTRL0_PARAM4;
+	else
+		ctrl0 = VI6_SRU_CTRL0_PARAM3;
+
+	if (input->width != output->width)
+		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
+
+	param = &vsp1_sru_params[sru->intensity - 1];
+
+	ctrl0 |= param->ctrl0;
+
+	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
+	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+}
+
+static const struct vsp1_entity_operations sru_entity_ops = {
+	.configure = sru_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -353,6 +343,7 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 	if (sru = NULL)
 		return ERR_PTR(-ENOMEM);
 
+	sru->entity.ops = &sru_entity_ops;
 	sru->entity.type = VSP1_ENTITY_SRU;
 
 	ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 3ba0f6844d1d..1acbdd6d537f 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -105,62 +105,6 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_uds *uds = to_uds(subdev);
-	const struct v4l2_mbus_framefmt *output;
-	const struct v4l2_mbus_framefmt *input;
-	unsigned int hscale;
-	unsigned int vscale;
-	bool multitap;
-
-	if (!enable)
-		return 0;
-
-	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
-					   UDS_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
-					    UDS_PAD_SOURCE);
-
-	hscale = uds_compute_ratio(input->width, output->width);
-	vscale = uds_compute_ratio(input->height, output->height);
-
-	dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
-
-	/* Multi-tap scaling can't be enabled along with alpha scaling when
-	 * scaling down with a factor lower than or equal to 1/2 in either
-	 * direction.
-	 */
-	if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
-		multitap = false;
-	else
-		multitap = true;
-
-	vsp1_uds_write(uds, VI6_UDS_CTRL,
-		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
-		       (multitap ? VI6_UDS_CTRL_BC : 0));
-
-	vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
-		       (uds_passband_width(hscale)
-				<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
-		       (uds_passband_width(vscale)
-				<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
-
-	/* Set the scaling ratios and the output size. */
-	vsp1_uds_write(uds, VI6_UDS_SCALE,
-		       (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
-		       (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
-	vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
-		       (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
-		       (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
@@ -321,10 +265,6 @@ static int uds_set_format(struct v4l2_subdev *subdev,
  * V4L2 Subdevice Operations
  */
 
-static struct v4l2_subdev_video_ops uds_video_ops = {
-	.s_stream = uds_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops uds_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = uds_enum_mbus_code,
@@ -334,11 +274,65 @@ static struct v4l2_subdev_pad_ops uds_pad_ops = {
 };
 
 static struct v4l2_subdev_ops uds_ops = {
-	.video	= &uds_video_ops,
 	.pad    = &uds_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void uds_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_uds *uds = to_uds(&entity->subdev);
+	const struct v4l2_mbus_framefmt *output;
+	const struct v4l2_mbus_framefmt *input;
+	unsigned int hscale;
+	unsigned int vscale;
+	bool multitap;
+
+	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					   UDS_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					    UDS_PAD_SOURCE);
+
+	hscale = uds_compute_ratio(input->width, output->width);
+	vscale = uds_compute_ratio(input->height, output->height);
+
+	dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
+
+	/* Multi-tap scaling can't be enabled along with alpha scaling when
+	 * scaling down with a factor lower than or equal to 1/2 in either
+	 * direction.
+	 */
+	if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
+		multitap = false;
+	else
+		multitap = true;
+
+	vsp1_uds_write(uds, VI6_UDS_CTRL,
+		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
+		       (multitap ? VI6_UDS_CTRL_BC : 0));
+
+	vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
+		       (uds_passband_width(hscale)
+				<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
+		       (uds_passband_width(vscale)
+				<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
+
+	/* Set the scaling ratios and the output size. */
+	vsp1_uds_write(uds, VI6_UDS_SCALE,
+		       (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
+		       (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
+	vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
+		       (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
+		       (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
+}
+
+static const struct vsp1_entity_operations uds_entity_ops = {
+	.configure = uds_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -352,6 +346,7 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 	if (uds = NULL)
 		return ERR_PTR(-ENOMEM);
 
+	uds->entity.ops = &uds_entity_ops;
 	uds->entity.type = VSP1_ENTITY_UDS;
 	uds->entity.index = index;
 
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index b1cb6b8a2452..725759920611 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -599,7 +599,6 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_entity *entity;
-	int ret;
 
 	/* Prepare the display list. */
 	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
@@ -627,18 +626,14 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 	list_for_each_entry(entity, &pipe->entities, list_pipe) {
 		vsp1_entity_route_setup(entity);
 
-		ret = v4l2_subdev_call(&entity->subdev, video, s_stream, 1);
-		if (ret < 0)
-			goto error;
+		if (entity->ops->configure)
+			entity->ops->configure(entity);
 	}
 
-	return 0;
+	/* We know that the WPF s_stream operation never fails. */
+	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
 
-error:
-	vsp1_dl_list_put(pipe->dl);
-	pipe->dl = NULL;
-
-	return ret;
+	return 0;
 }
 
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 0797927d14cf..bdc7d6623fe1 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -42,14 +42,13 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *wpf = to_rwpf(subdev);
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
-	const struct v4l2_mbus_framefmt *source_format;
-	const struct v4l2_mbus_framefmt *sink_format;
-	const struct v4l2_rect *crop;
 	unsigned int i;
 	u32 srcrpf = 0;
-	u32 outfmt = 0;
 
 	if (!enable) {
+		/* Write to registers directly when stopping the stream as there
+		 * will be no pipeline run to apply the display list.
+		 */
 		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
 		vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
 			   VI6_WPF_SRCRPF, 0);
@@ -77,6 +76,66 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
 	vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
 
+	/* Enable interrupts */
+	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
+	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
+		   VI6_WFP_IRQ_ENB_FREE);
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static struct v4l2_subdev_video_ops wpf_video_ops = {
+	.s_stream = wpf_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops wpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
+	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+	.enum_frame_size = vsp1_rwpf_enum_frame_size,
+	.get_fmt = vsp1_rwpf_get_format,
+	.set_fmt = vsp1_rwpf_set_format,
+	.get_selection = vsp1_rwpf_get_selection,
+	.set_selection = vsp1_rwpf_set_selection,
+};
+
+static struct v4l2_subdev_ops wpf_ops = {
+	.video	= &wpf_video_ops,
+	.pad    = &wpf_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
+	vsp1_dlm_destroy(wpf->dlm);
+}
+
+static void wpf_set_memory(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
+}
+
+static void wpf_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
+	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+	const struct v4l2_mbus_framefmt *source_format;
+	const struct v4l2_mbus_framefmt *sink_format;
+	const struct v4l2_rect *crop;
+	u32 outfmt = 0;
+
 	/* Destination stride. */
 	if (!pipe->lif) {
 		struct v4l2_pix_format_mplane *format = &wpf->format;
@@ -130,61 +189,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		       VI6_DPR_WPF_FPORCH_FP_WPFN);
 
 	vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0);
-
-	/* Enable interrupts */
-	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
-	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
-		   VI6_WFP_IRQ_ENB_FREE);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops wpf_video_ops = {
-	.s_stream = wpf_s_stream,
-};
-
-static struct v4l2_subdev_pad_ops wpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
-static struct v4l2_subdev_ops wpf_ops = {
-	.video	= &wpf_video_ops,
-	.pad    = &wpf_pad_ops,
-};
-
-/* -----------------------------------------------------------------------------
- * VSP1 Entity Operations
- */
-
-static void vsp1_wpf_destroy(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
-
-	vsp1_dlm_destroy(wpf->dlm);
-}
-
-static void wpf_set_memory(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
-
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
 static const struct vsp1_entity_operations wpf_entity_ops = {
 	.destroy = vsp1_wpf_destroy,
 	.set_memory = wpf_set_memory,
+	.configure = wpf_configure,
 };
 
 /* -----------------------------------------------------------------------------
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 42/48] v4l: vsp1: Create a new configure operation to setup modules
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The subdev s_stream operation is abused as a generic way to setup
modules at every frame. Move the code out to a new VSP1 entity configure
operation.

Most modules now have an empty s_stream operation that can be removed.
The only exception is the WPF module that needs to perform hardware
configuration when stopping the stream. The code can be simplified
accordingly as we know that that operation never fails.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 231 ++++++++++++++----------------
 drivers/media/platform/vsp1/vsp1_drm.c    |  14 +-
 drivers/media/platform/vsp1/vsp1_entity.h |   3 +
 drivers/media/platform/vsp1/vsp1_hsit.c   |  50 +++----
 drivers/media/platform/vsp1/vsp1_lif.c    |  77 +++++-----
 drivers/media/platform/vsp1/vsp1_lut.c    |  41 +++---
 drivers/media/platform/vsp1/vsp1_pipe.c   |   4 +-
 drivers/media/platform/vsp1/vsp1_rpf.c    |  83 +++++------
 drivers/media/platform/vsp1/vsp1_sru.c    |  91 ++++++------
 drivers/media/platform/vsp1/vsp1_uds.c    | 117 ++++++++-------
 drivers/media/platform/vsp1/vsp1_video.c  |  15 +-
 drivers/media/platform/vsp1/vsp1_wpf.c    | 118 ++++++++-------
 12 files changed, 394 insertions(+), 450 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index c1848a3ac010..4ab0a805d4b2 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -56,117 +56,7 @@ static const struct v4l2_ctrl_ops bru_ctrl_ops = {
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-	struct vsp1_bru *bru = to_bru(subdev);
-	struct v4l2_mbus_framefmt *format;
-	unsigned int flags;
-	unsigned int i;
-
-	if (!enable)
-		return 0;
-
-	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
-					    bru->entity.source_pad);
-
-	/* The hardware is extremely flexible but we have no userspace API to
-	 * expose all the parameters, nor is it clear whether we would have use
-	 * cases for all the supported modes. Let's just harcode the parameters
-	 * to sane default values for now.
-	 */
-
-	/* Disable dithering and enable color data normalization unless the
-	 * format at the pipeline output is premultiplied.
-	 */
-	flags = pipe->output ? pipe->output->format.flags : 0;
-	vsp1_bru_write(bru, VI6_BRU_INCTRL,
-		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
-		       0 : VI6_BRU_INCTRL_NRM);
-
-	/* Set the background position to cover the whole output image and
-	 * configure its color.
-	 */
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
-		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
-		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
-
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
-		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
-
-	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
-	 * unit with a NOP operation to make BRU input 1 available as the
-	 * Blend/ROP unit B SRC input.
-	 */
-	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
-		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
-		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));
-
-	for (i = 0; i < bru->entity.source_pad; ++i) {
-		bool premultiplied = false;
-		u32 ctrl = 0;
-
-		/* Configure all Blend/ROP units corresponding to an enabled BRU
-		 * input for alpha blending. Blend/ROP units corresponding to
-		 * disabled BRU inputs are used in ROP NOP mode to ignore the
-		 * SRC input.
-		 */
-		if (bru->inputs[i].rpf) {
-			ctrl |= VI6_BRU_CTRL_RBC;
-
-			premultiplied = bru->inputs[i].rpf->format.flags
-				      & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
-		} else {
-			ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
-			     |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
-		}
-
-		/* Select the virtual RPF as the Blend/ROP unit A DST input to
-		 * serve as a background color.
-		 */
-		if (i == 0)
-			ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
-
-		/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
-		 * D in that order. The Blend/ROP unit B SRC is hardwired to the
-		 * ROP unit output, the corresponding register bits must be set
-		 * to 0.
-		 */
-		if (i != 1)
-			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
-
-		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
-
-		/* Harcode the blending formula to
-		 *
-		 *	DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
-		 *	DSTa = DSTa * (1 - SRCa) + SRCa
-		 *
-		 * when the SRC input isn't premultiplied, and to
-		 *
-		 *	DSTc = DSTc * (1 - SRCa) + SRCc
-		 *	DSTa = DSTa * (1 - SRCa) + SRCa
-		 *
-		 * otherwise.
-		 */
-		vsp1_bru_write(bru, VI6_BRU_BLD(i),
-			       VI6_BRU_BLD_CCMDX_255_SRC_A |
-			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
-						VI6_BRU_BLD_CCMDY_SRC_A) |
-			       VI6_BRU_BLD_ACMDX_255_SRC_A |
-			       VI6_BRU_BLD_ACMDY_COEFY |
-			       (0xff << VI6_BRU_BLD_COEFY_SHIFT));
-	}
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 /*
@@ -395,14 +285,6 @@ static int bru_set_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops bru_video_ops = {
-	.s_stream = bru_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops bru_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = bru_enum_mbus_code,
@@ -414,11 +296,119 @@ static struct v4l2_subdev_pad_ops bru_pad_ops = {
 };
 
 static struct v4l2_subdev_ops bru_ops = {
-	.video	= &bru_video_ops,
 	.pad    = &bru_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void bru_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
+	struct vsp1_bru *bru = to_bru(&entity->subdev);
+	struct v4l2_mbus_framefmt *format;
+	unsigned int flags;
+	unsigned int i;
+
+	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+					    bru->entity.source_pad);
+
+	/* The hardware is extremely flexible but we have no userspace API to
+	 * expose all the parameters, nor is it clear whether we would have use
+	 * cases for all the supported modes. Let's just harcode the parameters
+	 * to sane default values for now.
+	 */
+
+	/* Disable dithering and enable color data normalization unless the
+	 * format at the pipeline output is premultiplied.
+	 */
+	flags = pipe->output ? pipe->output->format.flags : 0;
+	vsp1_bru_write(bru, VI6_BRU_INCTRL,
+		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
+		       0 : VI6_BRU_INCTRL_NRM);
+
+	/* Set the background position to cover the whole output image and
+	 * configure its color.
+	 */
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
+		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
+		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
+
+	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+
+	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
+	 * unit with a NOP operation to make BRU input 1 available as the
+	 * Blend/ROP unit B SRC input.
+	 */
+	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
+		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
+		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));
+
+	for (i = 0; i < bru->entity.source_pad; ++i) {
+		bool premultiplied = false;
+		u32 ctrl = 0;
+
+		/* Configure all Blend/ROP units corresponding to an enabled BRU
+		 * input for alpha blending. Blend/ROP units corresponding to
+		 * disabled BRU inputs are used in ROP NOP mode to ignore the
+		 * SRC input.
+		 */
+		if (bru->inputs[i].rpf) {
+			ctrl |= VI6_BRU_CTRL_RBC;
+
+			premultiplied = bru->inputs[i].rpf->format.flags
+				      & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
+		} else {
+			ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
+			     |  VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
+		}
+
+		/* Select the virtual RPF as the Blend/ROP unit A DST input to
+		 * serve as a background color.
+		 */
+		if (i == 0)
+			ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
+
+		/* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to
+		 * D in that order. The Blend/ROP unit B SRC is hardwired to the
+		 * ROP unit output, the corresponding register bits must be set
+		 * to 0.
+		 */
+		if (i != 1)
+			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
+
+		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
+
+		/* Harcode the blending formula to
+		 *
+		 *	DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
+		 *	DSTa = DSTa * (1 - SRCa) + SRCa
+		 *
+		 * when the SRC input isn't premultiplied, and to
+		 *
+		 *	DSTc = DSTc * (1 - SRCa) + SRCc
+		 *	DSTa = DSTa * (1 - SRCa) + SRCa
+		 *
+		 * otherwise.
+		 */
+		vsp1_bru_write(bru, VI6_BRU_BLD(i),
+			       VI6_BRU_BLD_CCMDX_255_SRC_A |
+			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
+						VI6_BRU_BLD_CCMDY_SRC_A) |
+			       VI6_BRU_BLD_ACMDX_255_SRC_A |
+			       VI6_BRU_BLD_ACMDY_COEFY |
+			       (0xff << VI6_BRU_BLD_COEFY_SHIFT));
+	}
+}
+
+static const struct vsp1_entity_operations bru_entity_ops = {
+	.configure = bru_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -431,6 +421,7 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
 	if (bru == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	bru->entity.ops = &bru_entity_ops;
 	bru->entity.type = VSP1_ENTITY_BRU;
 
 	ret = vsp1_entity_init(vsp1, &bru->entity, "bru",
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index e1216732e192..f1f728271cc3 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -448,7 +448,6 @@ void vsp1_du_atomic_flush(struct device *dev)
 	struct vsp1_entity *entity;
 	unsigned long flags;
 	bool stop = false;
-	int ret;
 
 	list_for_each_entry(entity, &pipe->entities, list_pipe) {
 		/* Disconnect unused RPFs from the pipeline. */
@@ -464,19 +463,16 @@ void vsp1_du_atomic_flush(struct device *dev)
 
 		vsp1_entity_route_setup(entity);
 
-		ret = v4l2_subdev_call(&entity->subdev, video,
-				       s_stream, 1);
-		if (ret < 0) {
-			dev_err(vsp1->dev,
-				"DRM pipeline start failure on entity %s\n",
-				entity->subdev.name);
-			return;
-		}
+		if (entity->ops->configure)
+			entity->ops->configure(entity);
 
 		if (entity->type == VSP1_ENTITY_RPF)
 			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
 	}
 
+	/* We know that the WPF s_stream operation never fails. */
+	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
+
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 1b0e31ec0f1f..c83b5a852bfc 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -59,10 +59,13 @@ struct vsp1_route {
  * @set_memory:	Setup memory buffer access. This operation applies the settings
  *		stored in the rwpf mem field to the hardware. Valid for RPF and
  *		WPF only.
+ * @configure:	Setup the hardware based on the entity state (pipeline, formats,
+ *		selection rectangles, ...)
  */
 struct vsp1_entity_operations {
 	void (*destroy)(struct vsp1_entity *);
 	void (*set_memory)(struct vsp1_entity *);
+	void (*configure)(struct vsp1_entity *);
 };
 
 struct vsp1_entity {
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 4f87f6f8ee38..7360586c902a 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -32,26 +32,7 @@ static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_hsit *hsit = to_hsit(subdev);
-
-	if (!enable)
-		return 0;
-
-	if (hsit->inverse)
-		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
-	else
-		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -167,14 +148,6 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops hsit_video_ops = {
-	.s_stream = hsit_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops hsit_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = hsit_enum_mbus_code,
@@ -184,11 +157,28 @@ static struct v4l2_subdev_pad_ops hsit_pad_ops = {
 };
 
 static struct v4l2_subdev_ops hsit_ops = {
-	.video	= &hsit_video_ops,
 	.pad    = &hsit_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void hsit_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
+
+	if (hsit->inverse)
+		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
+	else
+		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
+}
+
+static const struct vsp1_entity_operations hsit_entity_ops = {
+	.configure = hsit_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -203,6 +193,8 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
 
 	hsit->inverse = inverse;
 
+	hsit->entity.ops = &hsit_entity_ops;
+
 	if (inverse)
 		hsit->entity.type = VSP1_ENTITY_HSI;
 	else
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 6a80a04ea392..a0fad552af5d 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -32,41 +32,7 @@ static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int lif_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	const struct v4l2_mbus_framefmt *format;
-	struct vsp1_lif *lif = to_lif(subdev);
-	unsigned int hbth = 1300;
-	unsigned int obth = 400;
-	unsigned int lbth = 200;
-
-	if (!enable) {
-		vsp1_write(lif->entity.vsp1, VI6_LIF_CTRL, 0);
-		return 0;
-	}
-
-	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
-					    LIF_PAD_SOURCE);
-
-	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
-
-	vsp1_lif_write(lif, VI6_LIF_CSBTH,
-			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
-			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
-
-	vsp1_lif_write(lif, VI6_LIF_CTRL,
-			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
-			(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
-			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -200,14 +166,6 @@ static int lif_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops lif_video_ops = {
-	.s_stream = lif_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops lif_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lif_enum_mbus_code,
@@ -217,11 +175,41 @@ static struct v4l2_subdev_pad_ops lif_pad_ops = {
 };
 
 static struct v4l2_subdev_ops lif_ops = {
-	.video	= &lif_video_ops,
 	.pad    = &lif_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void lif_configure(struct vsp1_entity *entity)
+{
+	const struct v4l2_mbus_framefmt *format;
+	struct vsp1_lif *lif = to_lif(&entity->subdev);
+	unsigned int hbth = 1300;
+	unsigned int obth = 400;
+	unsigned int lbth = 200;
+
+	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+					    LIF_PAD_SOURCE);
+
+	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
+
+	vsp1_lif_write(lif, VI6_LIF_CSBTH,
+			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
+			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
+
+	vsp1_lif_write(lif, VI6_LIF_CTRL,
+			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
+			(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
+			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
+}
+
+static const struct vsp1_entity_operations lif_entity_ops = {
+	.configure = lif_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -234,6 +222,7 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
 	if (lif == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	lif->entity.ops = &lif_entity_ops;
 	lif->entity.type = VSP1_ENTITY_LIF;
 
 	ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index a5b839b28320..d5d32ce10f41 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -36,7 +36,7 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
  * V4L2 Subdevice Core Operations
  */
 
-static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config)
+static void lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config)
 {
 	memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
 		    sizeof(config->lut));
@@ -48,7 +48,7 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
 
 	switch (cmd) {
 	case VIDIOC_VSP1_LUT_CONFIG:
-		lut_configure(lut, arg);
+		lut_set_table(lut, arg);
 		return 0;
 
 	default:
@@ -57,22 +57,6 @@ static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Video Operations
- */
-
-static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_lut *lut = to_lut(subdev);
-
-	if (!enable)
-		return 0;
-
-	vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
@@ -218,10 +202,6 @@ static struct v4l2_subdev_core_ops lut_core_ops = {
 	.ioctl = lut_ioctl,
 };
 
-static struct v4l2_subdev_video_ops lut_video_ops = {
-	.s_stream = lut_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops lut_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = lut_enum_mbus_code,
@@ -232,11 +212,25 @@ static struct v4l2_subdev_pad_ops lut_pad_ops = {
 
 static struct v4l2_subdev_ops lut_ops = {
 	.core	= &lut_core_ops,
-	.video	= &lut_video_ops,
 	.pad    = &lut_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void lut_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_lut *lut = to_lut(&entity->subdev);
+
+	vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
+}
+
+static const struct vsp1_entity_operations lut_entity_ops = {
+	.configure = lut_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -249,6 +243,7 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
 	if (lut == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	lut->entity.ops = &lut_entity_ops;
 	lut->entity.type = VSP1_ENTITY_LUT;
 
 	ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops);
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index dd0921b31e98..5e91277c2972 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -232,10 +232,10 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
 		if (entity->route && entity->route->reg)
 			vsp1_write(entity->vsp1, entity->route->reg,
 				   VI6_DPR_NODE_UNUSED);
-
-		v4l2_subdev_call(&entity->subdev, video, s_stream, 0);
 	}
 
+	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0);
+
 	return ret;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index cb3d5ed148cc..eb17fa134750 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -33,13 +33,43 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
+ * V4L2 Subdevice Operations
  */
 
-static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
+static struct v4l2_subdev_pad_ops rpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
+	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+	.enum_frame_size = vsp1_rwpf_enum_frame_size,
+	.get_fmt = vsp1_rwpf_get_format,
+	.set_fmt = vsp1_rwpf_set_format,
+	.get_selection = vsp1_rwpf_get_selection,
+	.set_selection = vsp1_rwpf_set_selection,
+};
+
+static struct v4l2_subdev_ops rpf_ops = {
+	.pad    = &rpf_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void rpf_set_memory(struct vsp1_entity *entity)
 {
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
-	struct vsp1_rwpf *rpf = to_rwpf(subdev);
+	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
+
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
+		       rpf->mem.addr[0] + rpf->offsets[0]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+		       rpf->mem.addr[1] + rpf->offsets[1]);
+	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+		       rpf->mem.addr[2] + rpf->offsets[1]);
+}
+
+static void rpf_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
+	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_mbus_framefmt *source_format;
@@ -50,9 +80,6 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	u32 pstride;
 	u32 infmt;
 
-	if (!enable)
-		return 0;
-
 	/* Source size, stride and crop offsets.
 	 *
 	 * The crop offsets correspond to the location of the crop rectangle top
@@ -136,51 +163,11 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
 	vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
 	vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops rpf_video_ops = {
-	.s_stream = rpf_s_stream,
-};
-
-static struct v4l2_subdev_pad_ops rpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
-static struct v4l2_subdev_ops rpf_ops = {
-	.video	= &rpf_video_ops,
-	.pad    = &rpf_pad_ops,
-};
-
-/* -----------------------------------------------------------------------------
- * VSP1 Entity Operations
- */
-
-static void rpf_set_memory(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
-
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
-		       rpf->mem.addr[0] + rpf->offsets[0]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
-		       rpf->mem.addr[1] + rpf->offsets[1]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
-		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_entity_operations rpf_entity_ops = {
 	.set_memory = rpf_set_memory,
+	.configure = rpf_configure,
 };
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index c9a97ba5a042..e05149eabde9 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -103,47 +103,7 @@ static const struct v4l2_ctrl_config sru_intensity_control = {
 };
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	const struct vsp1_sru_param *param;
-	struct vsp1_sru *sru = to_sru(subdev);
-	struct v4l2_mbus_framefmt *input;
-	struct v4l2_mbus_framefmt *output;
-	u32 ctrl0;
-
-	if (!enable)
-		return 0;
-
-	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
-					   SRU_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
-					    SRU_PAD_SOURCE);
-
-	if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
-		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
-		      | VI6_SRU_CTRL0_PARAM4;
-	else
-		ctrl0 = VI6_SRU_CTRL0_PARAM3;
-
-	if (input->width != output->width)
-		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
-
-	param = &vsp1_sru_params[sru->intensity - 1];
-
-	ctrl0 |= param->ctrl0;
-
-	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
-	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Pad Operations
+ * V4L2 Subdevice Operations
  */
 
 static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -319,14 +279,6 @@ static int sru_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops sru_video_ops = {
-	.s_stream = sru_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops sru_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = sru_enum_mbus_code,
@@ -336,11 +288,49 @@ static struct v4l2_subdev_pad_ops sru_pad_ops = {
 };
 
 static struct v4l2_subdev_ops sru_ops = {
-	.video	= &sru_video_ops,
 	.pad    = &sru_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void sru_configure(struct vsp1_entity *entity)
+{
+	const struct vsp1_sru_param *param;
+	struct vsp1_sru *sru = to_sru(&entity->subdev);
+	struct v4l2_mbus_framefmt *input;
+	struct v4l2_mbus_framefmt *output;
+	u32 ctrl0;
+
+	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					   SRU_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+					    SRU_PAD_SOURCE);
+
+	if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
+		ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
+		      | VI6_SRU_CTRL0_PARAM4;
+	else
+		ctrl0 = VI6_SRU_CTRL0_PARAM3;
+
+	if (input->width != output->width)
+		ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
+
+	param = &vsp1_sru_params[sru->intensity - 1];
+
+	ctrl0 |= param->ctrl0;
+
+	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
+	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+}
+
+static const struct vsp1_entity_operations sru_entity_ops = {
+	.configure = sru_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -353,6 +343,7 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
 	if (sru == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	sru->entity.ops = &sru_entity_ops;
 	sru->entity.type = VSP1_ENTITY_SRU;
 
 	ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 3ba0f6844d1d..1acbdd6d537f 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -105,62 +105,6 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
-static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
-{
-	struct vsp1_uds *uds = to_uds(subdev);
-	const struct v4l2_mbus_framefmt *output;
-	const struct v4l2_mbus_framefmt *input;
-	unsigned int hscale;
-	unsigned int vscale;
-	bool multitap;
-
-	if (!enable)
-		return 0;
-
-	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
-					   UDS_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
-					    UDS_PAD_SOURCE);
-
-	hscale = uds_compute_ratio(input->width, output->width);
-	vscale = uds_compute_ratio(input->height, output->height);
-
-	dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
-
-	/* Multi-tap scaling can't be enabled along with alpha scaling when
-	 * scaling down with a factor lower than or equal to 1/2 in either
-	 * direction.
-	 */
-	if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
-		multitap = false;
-	else
-		multitap = true;
-
-	vsp1_uds_write(uds, VI6_UDS_CTRL,
-		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
-		       (multitap ? VI6_UDS_CTRL_BC : 0));
-
-	vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
-		       (uds_passband_width(hscale)
-				<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
-		       (uds_passband_width(vscale)
-				<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
-
-	/* Set the scaling ratios and the output size. */
-	vsp1_uds_write(uds, VI6_UDS_SCALE,
-		       (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
-		       (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
-	vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
-		       (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
-		       (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
@@ -321,10 +265,6 @@ static int uds_set_format(struct v4l2_subdev *subdev,
  * V4L2 Subdevice Operations
  */
 
-static struct v4l2_subdev_video_ops uds_video_ops = {
-	.s_stream = uds_s_stream,
-};
-
 static struct v4l2_subdev_pad_ops uds_pad_ops = {
 	.init_cfg = vsp1_entity_init_cfg,
 	.enum_mbus_code = uds_enum_mbus_code,
@@ -334,11 +274,65 @@ static struct v4l2_subdev_pad_ops uds_pad_ops = {
 };
 
 static struct v4l2_subdev_ops uds_ops = {
-	.video	= &uds_video_ops,
 	.pad    = &uds_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void uds_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_uds *uds = to_uds(&entity->subdev);
+	const struct v4l2_mbus_framefmt *output;
+	const struct v4l2_mbus_framefmt *input;
+	unsigned int hscale;
+	unsigned int vscale;
+	bool multitap;
+
+	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					   UDS_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+					    UDS_PAD_SOURCE);
+
+	hscale = uds_compute_ratio(input->width, output->width);
+	vscale = uds_compute_ratio(input->height, output->height);
+
+	dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
+
+	/* Multi-tap scaling can't be enabled along with alpha scaling when
+	 * scaling down with a factor lower than or equal to 1/2 in either
+	 * direction.
+	 */
+	if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
+		multitap = false;
+	else
+		multitap = true;
+
+	vsp1_uds_write(uds, VI6_UDS_CTRL,
+		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
+		       (multitap ? VI6_UDS_CTRL_BC : 0));
+
+	vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
+		       (uds_passband_width(hscale)
+				<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
+		       (uds_passband_width(vscale)
+				<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
+
+	/* Set the scaling ratios and the output size. */
+	vsp1_uds_write(uds, VI6_UDS_SCALE,
+		       (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
+		       (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
+	vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
+		       (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
+		       (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
+}
+
+static const struct vsp1_entity_operations uds_entity_ops = {
+	.configure = uds_configure,
+};
+
+/* -----------------------------------------------------------------------------
  * Initialization and Cleanup
  */
 
@@ -352,6 +346,7 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index)
 	if (uds == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	uds->entity.ops = &uds_entity_ops;
 	uds->entity.type = VSP1_ENTITY_UDS;
 	uds->entity.index = index;
 
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index b1cb6b8a2452..725759920611 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -599,7 +599,6 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_entity *entity;
-	int ret;
 
 	/* Prepare the display list. */
 	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
@@ -627,18 +626,14 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 	list_for_each_entry(entity, &pipe->entities, list_pipe) {
 		vsp1_entity_route_setup(entity);
 
-		ret = v4l2_subdev_call(&entity->subdev, video, s_stream, 1);
-		if (ret < 0)
-			goto error;
+		if (entity->ops->configure)
+			entity->ops->configure(entity);
 	}
 
-	return 0;
+	/* We know that the WPF s_stream operation never fails. */
+	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
 
-error:
-	vsp1_dl_list_put(pipe->dl);
-	pipe->dl = NULL;
-
-	return ret;
+	return 0;
 }
 
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 0797927d14cf..bdc7d6623fe1 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -42,14 +42,13 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *wpf = to_rwpf(subdev);
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
-	const struct v4l2_mbus_framefmt *source_format;
-	const struct v4l2_mbus_framefmt *sink_format;
-	const struct v4l2_rect *crop;
 	unsigned int i;
 	u32 srcrpf = 0;
-	u32 outfmt = 0;
 
 	if (!enable) {
+		/* Write to registers directly when stopping the stream as there
+		 * will be no pipeline run to apply the display list.
+		 */
 		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
 		vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
 			   VI6_WPF_SRCRPF, 0);
@@ -77,6 +76,66 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
 	vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
 
+	/* Enable interrupts */
+	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
+	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
+		   VI6_WFP_IRQ_ENB_FREE);
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static struct v4l2_subdev_video_ops wpf_video_ops = {
+	.s_stream = wpf_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops wpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
+	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+	.enum_frame_size = vsp1_rwpf_enum_frame_size,
+	.get_fmt = vsp1_rwpf_get_format,
+	.set_fmt = vsp1_rwpf_set_format,
+	.get_selection = vsp1_rwpf_get_selection,
+	.set_selection = vsp1_rwpf_set_selection,
+};
+
+static struct v4l2_subdev_ops wpf_ops = {
+	.video	= &wpf_video_ops,
+	.pad    = &wpf_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * VSP1 Entity Operations
+ */
+
+static void vsp1_wpf_destroy(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
+	vsp1_dlm_destroy(wpf->dlm);
+}
+
+static void wpf_set_memory(struct vsp1_entity *entity)
+{
+	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
+
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
+}
+
+static void wpf_configure(struct vsp1_entity *entity)
+{
+	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
+	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+	const struct v4l2_mbus_framefmt *source_format;
+	const struct v4l2_mbus_framefmt *sink_format;
+	const struct v4l2_rect *crop;
+	u32 outfmt = 0;
+
 	/* Destination stride. */
 	if (!pipe->lif) {
 		struct v4l2_pix_format_mplane *format = &wpf->format;
@@ -130,61 +189,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 		       VI6_DPR_WPF_FPORCH_FP_WPFN);
 
 	vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0);
-
-	/* Enable interrupts */
-	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
-	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
-		   VI6_WFP_IRQ_ENB_FREE);
-
-	return 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Operations
- */
-
-static struct v4l2_subdev_video_ops wpf_video_ops = {
-	.s_stream = wpf_s_stream,
-};
-
-static struct v4l2_subdev_pad_ops wpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
-static struct v4l2_subdev_ops wpf_ops = {
-	.video	= &wpf_video_ops,
-	.pad    = &wpf_pad_ops,
-};
-
-/* -----------------------------------------------------------------------------
- * VSP1 Entity Operations
- */
-
-static void vsp1_wpf_destroy(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
-
-	vsp1_dlm_destroy(wpf->dlm);
-}
-
-static void wpf_set_memory(struct vsp1_entity *entity)
-{
-	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
-
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
 static const struct vsp1_entity_operations wpf_entity_ops = {
 	.destroy = vsp1_wpf_destroy,
 	.set_memory = wpf_set_memory,
+	.configure = wpf_configure,
 };
 
 /* -----------------------------------------------------------------------------
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 43/48] v4l: vsp1: Merge RPF and WPF pad ops structures
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The two structures are identical, merge them and move the result to
vsp1_rwpf.c. All rwpf pad operations can now be declared static.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_rpf.c  | 12 +------
 drivers/media/platform/vsp1/vsp1_rwpf.c | 60 +++++++++++++++++++--------------
 drivers/media/platform/vsp1/vsp1_rwpf.h | 19 +----------
 drivers/media/platform/vsp1/vsp1_wpf.c  | 12 +------
 4 files changed, 38 insertions(+), 65 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index eb17fa134750..84a3aedae768 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -36,18 +36,8 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
  * V4L2 Subdevice Operations
  */
 
-static struct v4l2_subdev_pad_ops rpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
 static struct v4l2_subdev_ops rpf_ops = {
-	.pad    = &rpf_pad_ops,
+	.pad    = &vsp1_rwpf_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 0c5ad023adfb..4d302f5cccb2 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -20,13 +20,20 @@
 #define RWPF_MIN_WIDTH				1
 #define RWPF_MIN_HEIGHT				1
 
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+				     struct v4l2_subdev_pad_config *config)
+{
+	return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+					RWPF_PAD_SINK);
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
-int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-			     struct v4l2_subdev_pad_config *cfg,
-			     struct v4l2_subdev_mbus_code_enum *code)
+static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_mbus_code_enum *code)
 {
 	static const unsigned int codes[] = {
 		MEDIA_BUS_FMT_ARGB8888_1X32,
@@ -41,9 +48,9 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-			      struct v4l2_subdev_pad_config *cfg,
-			      struct v4l2_subdev_frame_size_enum *fse)
+static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -76,16 +83,9 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
-				     struct v4l2_subdev_pad_config *config)
-{
-	return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
-					RWPF_PAD_SINK);
-}
-
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt)
+static int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -100,9 +100,9 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt)
+static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -154,9 +154,9 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel)
+static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -191,9 +191,9 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel)
+static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -250,6 +250,16 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
+const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
+	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+	.enum_frame_size = vsp1_rwpf_enum_frame_size,
+	.get_fmt = vsp1_rwpf_get_format,
+	.set_fmt = vsp1_rwpf_set_format,
+	.get_selection = vsp1_rwpf_get_selection,
+	.set_selection = vsp1_rwpf_set_selection,
+};
+
 /* -----------------------------------------------------------------------------
  * Controls
  */
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 4ebfab61e0ef..9502710977e8 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -68,24 +68,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
 int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
 
-int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-			     struct v4l2_subdev_pad_config *cfg,
-			     struct v4l2_subdev_mbus_code_enum *code);
-int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-			      struct v4l2_subdev_pad_config *cfg,
-			      struct v4l2_subdev_frame_size_enum *fse);
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel);
-int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel);
+extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
 
 struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
 				     struct v4l2_subdev_pad_config *config);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index bdc7d6623fe1..3f4b7208f3ef 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -92,19 +92,9 @@ static struct v4l2_subdev_video_ops wpf_video_ops = {
 	.s_stream = wpf_s_stream,
 };
 
-static struct v4l2_subdev_pad_ops wpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
 static struct v4l2_subdev_ops wpf_ops = {
 	.video	= &wpf_video_ops,
-	.pad    = &wpf_pad_ops,
+	.pad    = &vsp1_rwpf_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 43/48] v4l: vsp1: Merge RPF and WPF pad ops structures
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

The two structures are identical, merge them and move the result to
vsp1_rwpf.c. All rwpf pad operations can now be declared static.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_rpf.c  | 12 +------
 drivers/media/platform/vsp1/vsp1_rwpf.c | 60 +++++++++++++++++++--------------
 drivers/media/platform/vsp1/vsp1_rwpf.h | 19 +----------
 drivers/media/platform/vsp1/vsp1_wpf.c  | 12 +------
 4 files changed, 38 insertions(+), 65 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index eb17fa134750..84a3aedae768 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -36,18 +36,8 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
  * V4L2 Subdevice Operations
  */
 
-static struct v4l2_subdev_pad_ops rpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
 static struct v4l2_subdev_ops rpf_ops = {
-	.pad    = &rpf_pad_ops,
+	.pad    = &vsp1_rwpf_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 0c5ad023adfb..4d302f5cccb2 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -20,13 +20,20 @@
 #define RWPF_MIN_WIDTH				1
 #define RWPF_MIN_HEIGHT				1
 
+struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
+				     struct v4l2_subdev_pad_config *config)
+{
+	return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
+					RWPF_PAD_SINK);
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
 
-int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-			     struct v4l2_subdev_pad_config *cfg,
-			     struct v4l2_subdev_mbus_code_enum *code)
+static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_mbus_code_enum *code)
 {
 	static const unsigned int codes[] = {
 		MEDIA_BUS_FMT_ARGB8888_1X32,
@@ -41,9 +48,9 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-			      struct v4l2_subdev_pad_config *cfg,
-			      struct v4l2_subdev_frame_size_enum *fse)
+static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
+				     struct v4l2_subdev_pad_config *cfg,
+				     struct v4l2_subdev_frame_size_enum *fse)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -76,16 +83,9 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
-				     struct v4l2_subdev_pad_config *config)
-{
-	return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, config,
-					RWPF_PAD_SINK);
-}
-
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt)
+static int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -100,9 +100,9 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt)
+static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_format *fmt)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -154,9 +154,9 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel)
+static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -191,9 +191,9 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
-int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel)
+static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_selection *sel)
 {
 	struct vsp1_rwpf *rwpf = to_rwpf(subdev);
 	struct v4l2_subdev_pad_config *config;
@@ -250,6 +250,16 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
 	return 0;
 }
 
+const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
+	.init_cfg = vsp1_entity_init_cfg,
+	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
+	.enum_frame_size = vsp1_rwpf_enum_frame_size,
+	.get_fmt = vsp1_rwpf_get_format,
+	.set_fmt = vsp1_rwpf_set_format,
+	.get_selection = vsp1_rwpf_get_selection,
+	.set_selection = vsp1_rwpf_set_selection,
+};
+
 /* -----------------------------------------------------------------------------
  * Controls
  */
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 4ebfab61e0ef..9502710977e8 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -68,24 +68,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index);
 
 int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf);
 
-int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
-			     struct v4l2_subdev_pad_config *cfg,
-			     struct v4l2_subdev_mbus_code_enum *code);
-int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
-			      struct v4l2_subdev_pad_config *cfg,
-			      struct v4l2_subdev_frame_size_enum *fse);
-int vsp1_rwpf_get_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
-			 struct v4l2_subdev_pad_config *cfg,
-			 struct v4l2_subdev_format *fmt);
-int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel);
-int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
-			    struct v4l2_subdev_pad_config *cfg,
-			    struct v4l2_subdev_selection *sel);
+extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
 
 struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
 				     struct v4l2_subdev_pad_config *config);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index bdc7d6623fe1..3f4b7208f3ef 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -92,19 +92,9 @@ static struct v4l2_subdev_video_ops wpf_video_ops = {
 	.s_stream = wpf_s_stream,
 };
 
-static struct v4l2_subdev_pad_ops wpf_pad_ops = {
-	.init_cfg = vsp1_entity_init_cfg,
-	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
-	.enum_frame_size = vsp1_rwpf_enum_frame_size,
-	.get_fmt = vsp1_rwpf_get_format,
-	.set_fmt = vsp1_rwpf_set_format,
-	.get_selection = vsp1_rwpf_get_selection,
-	.set_selection = vsp1_rwpf_set_selection,
-};
-
 static struct v4l2_subdev_ops wpf_ops = {
 	.video	= &wpf_video_ops,
-	.pad    = &wpf_pad_ops,
+	.pad    = &vsp1_rwpf_pad_ops,
 };
 
 /* -----------------------------------------------------------------------------
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 44/48] v4l: vsp1: Pass a media request to the module configure operations
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Retrieve pad configuration from the request to configure modules. If the
request is NULL the active configuration is used as before.

Pass a NULL request unconditionally for now until support for the
request API gets implemented.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 10 +++++++---
 drivers/media/platform/vsp1/vsp1_drm.c    |  2 +-
 drivers/media/platform/vsp1/vsp1_entity.c | 33 +++++++++++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_entity.h |  6 +++++-
 drivers/media/platform/vsp1/vsp1_hsit.c   |  3 ++-
 drivers/media/platform/vsp1/vsp1_lif.c    |  8 ++++++--
 drivers/media/platform/vsp1/vsp1_lut.c    |  3 ++-
 drivers/media/platform/vsp1/vsp1_rpf.c    | 19 ++++++++++--------
 drivers/media/platform/vsp1/vsp1_sru.c    | 11 +++++++----
 drivers/media/platform/vsp1/vsp1_uds.c    | 11 +++++++----
 drivers/media/platform/vsp1/vsp1_video.c  |  2 +-
 drivers/media/platform/vsp1/vsp1_wpf.c    | 14 +++++++------
 12 files changed, 90 insertions(+), 32 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 4ab0a805d4b2..c570166008de 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -303,15 +303,19 @@ static struct v4l2_subdev_ops bru_ops = {
  * VSP1 Entity Operations
  */
 
-static void bru_configure(struct vsp1_entity *entity)
+static void bru_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_bru *bru = to_bru(&entity->subdev);
-	struct v4l2_mbus_framefmt *format;
+	const struct v4l2_mbus_framefmt *format;
+	struct v4l2_subdev_pad_config *config;
 	unsigned int flags;
 	unsigned int i;
 
-	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	format = vsp1_entity_get_pad_format(&bru->entity, config,
 					    bru->entity.source_pad);
 
 	/* The hardware is extremely flexible but we have no userspace API to
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index f1f728271cc3..5ac7e84b9a62 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -464,7 +464,7 @@ void vsp1_du_atomic_flush(struct device *dev)
 		vsp1_entity_route_setup(entity);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity);
+			entity->ops->configure(entity, NULL);
 
 		if (entity->type = VSP1_ENTITY_RPF)
 			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 0620f1772cab..bde530108717 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -73,6 +73,39 @@ vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 }
 
 /**
+ * vsp1_entity_get_req_pad_config - Get a pad configuration from a request
+ * @entity: the entity
+ * @req: the request
+ *
+ * Return the pad configuration stored in the request for the given entity. If
+ * the request argument is NULL or doesn't contain pad configuration for the
+ * entity the function will instead return the ACTIVE configuration stored in
+ * the entity.
+ */
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_req_pad_config(struct vsp1_entity *entity,
+			       struct media_device_request *req)
+{
+	struct media_entity_request_data *data;
+	struct v4l2_subdev_request_data *sddata;
+
+	/* If there's no request or if the request doesn't contain subdev data
+	 * return the entity active configuration.
+	 */
+	if (!req)
+		return entity->config;
+
+	data = media_device_request_get_entity_data(req,
+						    &entity->subdev.entity);
+	if (!data)
+		return entity->config;
+
+	/* Otherwise return the configuration stored in the request. */
+	sddata = to_v4l2_subdev_request_data(data);
+	return sddata->pad;
+}
+
+/**
  * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
  * @entity: the entity
  * @cfg: the configuration storage
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index c83b5a852bfc..438e743deca1 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -18,6 +18,7 @@
 
 #include <media/v4l2-subdev.h>
 
+struct media_device_request;
 struct vsp1_device;
 
 enum vsp1_entity_type {
@@ -65,7 +66,7 @@ struct vsp1_route {
 struct vsp1_entity_operations {
 	void (*destroy)(struct vsp1_entity *);
 	void (*set_memory)(struct vsp1_entity *);
-	void (*configure)(struct vsp1_entity *);
+	void (*configure)(struct vsp1_entity *, struct media_device_request *);
 };
 
 struct vsp1_entity {
@@ -110,6 +111,9 @@ struct v4l2_subdev_pad_config *
 vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   enum v4l2_subdev_format_whence which);
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_req_pad_config(struct vsp1_entity *entity,
+			       struct media_device_request *req);
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 7360586c902a..dda347cf077b 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -164,7 +164,8 @@ static struct v4l2_subdev_ops hsit_ops = {
  * VSP1 Entity Operations
  */
 
-static void hsit_configure(struct vsp1_entity *entity)
+static void hsit_configure(struct vsp1_entity *entity,
+			   struct media_device_request *req)
 {
 	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
 
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index a0fad552af5d..3f22e2a6d750 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -182,15 +182,19 @@ static struct v4l2_subdev_ops lif_ops = {
  * VSP1 Entity Operations
  */
 
-static void lif_configure(struct vsp1_entity *entity)
+static void lif_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	const struct v4l2_mbus_framefmt *format;
 	struct vsp1_lif *lif = to_lif(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	unsigned int hbth = 1300;
 	unsigned int obth = 400;
 	unsigned int lbth = 200;
 
-	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	format = vsp1_entity_get_pad_format(&lif->entity, config,
 					    LIF_PAD_SOURCE);
 
 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index d5d32ce10f41..76cf3ea73c71 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -219,7 +219,8 @@ static struct v4l2_subdev_ops lut_ops = {
  * VSP1 Entity Operations
  */
 
-static void lut_configure(struct vsp1_entity *entity)
+static void lut_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_lut *lut = to_lut(&entity->subdev);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 84a3aedae768..a1cff6feec30 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -56,10 +56,12 @@ static void rpf_set_memory(struct vsp1_entity *entity)
 		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
-static void rpf_configure(struct vsp1_entity *entity)
+static void rpf_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_mbus_framefmt *source_format;
@@ -70,13 +72,15 @@ static void rpf_configure(struct vsp1_entity *entity)
 	u32 pstride;
 	u32 infmt;
 
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
 	/* Source size, stride and crop offsets.
 	 *
 	 * The crop offsets correspond to the location of the crop rectangle top
 	 * left corner in the plane buffer. Only two offsets are needed, as
 	 * planes 2 and 3 always have identical strides.
 	 */
-	crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+	crop = vsp1_rwpf_get_crop(rpf, config);
 
 	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
 		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
@@ -102,11 +106,9 @@ static void rpf_configure(struct vsp1_entity *entity)
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
-	sink_format = vsp1_entity_get_pad_format(&rpf->entity,
-						 rpf->entity.config,
+	sink_format = vsp1_entity_get_pad_format(&rpf->entity, config,
 						 RWPF_PAD_SINK);
-	source_format = vsp1_entity_get_pad_format(&rpf->entity,
-						   rpf->entity.config,
+	source_format = vsp1_entity_get_pad_format(&rpf->entity, config,
 						   RWPF_PAD_SOURCE);
 
 	infmt = VI6_RPF_INFMT_CIPM
@@ -125,10 +127,11 @@ static void rpf_configure(struct vsp1_entity *entity)
 
 	/* Output location */
 	if (pipe->bru) {
+		struct v4l2_subdev_pad_config *bru_config;
 		const struct v4l2_rect *compose;
 
-		compose = vsp1_entity_get_pad_compose(pipe->bru,
-						      pipe->bru->config,
+		bru_config = vsp1_entity_get_req_pad_config(pipe->bru, req);
+		compose = vsp1_entity_get_pad_compose(pipe->bru, bru_config,
 						      rpf->bru_input);
 		left = compose->left;
 		top = compose->top;
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index e05149eabde9..0d6315c9ea17 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -295,17 +295,20 @@ static struct v4l2_subdev_ops sru_ops = {
  * VSP1 Entity Operations
  */
 
-static void sru_configure(struct vsp1_entity *entity)
+static void sru_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	const struct vsp1_sru_param *param;
 	struct vsp1_sru *sru = to_sru(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
 	u32 ctrl0;
 
-	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
-					   SRU_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	input = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&sru->entity, config,
 					    SRU_PAD_SOURCE);
 
 	if (input->code = MEDIA_BUS_FMT_ARGB8888_1X32)
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 1acbdd6d537f..7c6ad2c3967f 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -281,18 +281,21 @@ static struct v4l2_subdev_ops uds_ops = {
  * VSP1 Entity Operations
  */
 
-static void uds_configure(struct vsp1_entity *entity)
+static void uds_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_uds *uds = to_uds(&entity->subdev);
 	const struct v4l2_mbus_framefmt *output;
 	const struct v4l2_mbus_framefmt *input;
+	struct v4l2_subdev_pad_config *config;
 	unsigned int hscale;
 	unsigned int vscale;
 	bool multitap;
 
-	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
-					   UDS_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	input = vsp1_entity_get_pad_format(&uds->entity, config, UDS_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&uds->entity, config,
 					    UDS_PAD_SOURCE);
 
 	hscale = uds_compute_ratio(input->width, output->width);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 725759920611..c757847110ba 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -627,7 +627,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 		vsp1_entity_route_setup(entity);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity);
+			entity->ops->configure(entity, NULL);
 	}
 
 	/* We know that the WPF s_stream operation never fails. */
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 3f4b7208f3ef..bde990e010d4 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -117,15 +117,19 @@ static void wpf_set_memory(struct vsp1_entity *entity)
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
-static void wpf_configure(struct vsp1_entity *entity)
+static void wpf_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop;
 	u32 outfmt = 0;
 
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
 	/* Destination stride. */
 	if (!pipe->lif) {
 		struct v4l2_pix_format_mplane *format = &wpf->format;
@@ -137,7 +141,7 @@ static void wpf_configure(struct vsp1_entity *entity)
 				       format->plane_fmt[1].bytesperline);
 	}
 
-	crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
+	crop = vsp1_rwpf_get_crop(wpf, config);
 
 	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
@@ -147,11 +151,9 @@ static void wpf_configure(struct vsp1_entity *entity)
 		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
 	/* Format */
-	sink_format = vsp1_entity_get_pad_format(&wpf->entity,
-						 wpf->entity.config,
+	sink_format = vsp1_entity_get_pad_format(&wpf->entity, config,
 						 RWPF_PAD_SINK);
-	source_format = vsp1_entity_get_pad_format(&wpf->entity,
-						   wpf->entity.config,
+	source_format = vsp1_entity_get_pad_format(&wpf->entity, config,
 						   RWPF_PAD_SOURCE);
 
 	if (!pipe->lif) {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 44/48] v4l: vsp1: Pass a media request to the module configure operations
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Retrieve pad configuration from the request to configure modules. If the
request is NULL the active configuration is used as before.

Pass a NULL request unconditionally for now until support for the
request API gets implemented.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    | 10 +++++++---
 drivers/media/platform/vsp1/vsp1_drm.c    |  2 +-
 drivers/media/platform/vsp1/vsp1_entity.c | 33 +++++++++++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_entity.h |  6 +++++-
 drivers/media/platform/vsp1/vsp1_hsit.c   |  3 ++-
 drivers/media/platform/vsp1/vsp1_lif.c    |  8 ++++++--
 drivers/media/platform/vsp1/vsp1_lut.c    |  3 ++-
 drivers/media/platform/vsp1/vsp1_rpf.c    | 19 ++++++++++--------
 drivers/media/platform/vsp1/vsp1_sru.c    | 11 +++++++----
 drivers/media/platform/vsp1/vsp1_uds.c    | 11 +++++++----
 drivers/media/platform/vsp1/vsp1_video.c  |  2 +-
 drivers/media/platform/vsp1/vsp1_wpf.c    | 14 +++++++------
 12 files changed, 90 insertions(+), 32 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index 4ab0a805d4b2..c570166008de 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -303,15 +303,19 @@ static struct v4l2_subdev_ops bru_ops = {
  * VSP1 Entity Operations
  */
 
-static void bru_configure(struct vsp1_entity *entity)
+static void bru_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_bru *bru = to_bru(&entity->subdev);
-	struct v4l2_mbus_framefmt *format;
+	const struct v4l2_mbus_framefmt *format;
+	struct v4l2_subdev_pad_config *config;
 	unsigned int flags;
 	unsigned int i;
 
-	format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	format = vsp1_entity_get_pad_format(&bru->entity, config,
 					    bru->entity.source_pad);
 
 	/* The hardware is extremely flexible but we have no userspace API to
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index f1f728271cc3..5ac7e84b9a62 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -464,7 +464,7 @@ void vsp1_du_atomic_flush(struct device *dev)
 		vsp1_entity_route_setup(entity);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity);
+			entity->ops->configure(entity, NULL);
 
 		if (entity->type == VSP1_ENTITY_RPF)
 			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 0620f1772cab..bde530108717 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -73,6 +73,39 @@ vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 }
 
 /**
+ * vsp1_entity_get_req_pad_config - Get a pad configuration from a request
+ * @entity: the entity
+ * @req: the request
+ *
+ * Return the pad configuration stored in the request for the given entity. If
+ * the request argument is NULL or doesn't contain pad configuration for the
+ * entity the function will instead return the ACTIVE configuration stored in
+ * the entity.
+ */
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_req_pad_config(struct vsp1_entity *entity,
+			       struct media_device_request *req)
+{
+	struct media_entity_request_data *data;
+	struct v4l2_subdev_request_data *sddata;
+
+	/* If there's no request or if the request doesn't contain subdev data
+	 * return the entity active configuration.
+	 */
+	if (!req)
+		return entity->config;
+
+	data = media_device_request_get_entity_data(req,
+						    &entity->subdev.entity);
+	if (!data)
+		return entity->config;
+
+	/* Otherwise return the configuration stored in the request. */
+	sddata = to_v4l2_subdev_request_data(data);
+	return sddata->pad;
+}
+
+/**
  * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
  * @entity: the entity
  * @cfg: the configuration storage
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index c83b5a852bfc..438e743deca1 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -18,6 +18,7 @@
 
 #include <media/v4l2-subdev.h>
 
+struct media_device_request;
 struct vsp1_device;
 
 enum vsp1_entity_type {
@@ -65,7 +66,7 @@ struct vsp1_route {
 struct vsp1_entity_operations {
 	void (*destroy)(struct vsp1_entity *);
 	void (*set_memory)(struct vsp1_entity *);
-	void (*configure)(struct vsp1_entity *);
+	void (*configure)(struct vsp1_entity *, struct media_device_request *);
 };
 
 struct vsp1_entity {
@@ -110,6 +111,9 @@ struct v4l2_subdev_pad_config *
 vsp1_entity_get_pad_config(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
 			   enum v4l2_subdev_format_whence which);
+struct v4l2_subdev_pad_config *
+vsp1_entity_get_req_pad_config(struct vsp1_entity *entity,
+			       struct media_device_request *req);
 struct v4l2_mbus_framefmt *
 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
 			   struct v4l2_subdev_pad_config *cfg,
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 7360586c902a..dda347cf077b 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -164,7 +164,8 @@ static struct v4l2_subdev_ops hsit_ops = {
  * VSP1 Entity Operations
  */
 
-static void hsit_configure(struct vsp1_entity *entity)
+static void hsit_configure(struct vsp1_entity *entity,
+			   struct media_device_request *req)
 {
 	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
 
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index a0fad552af5d..3f22e2a6d750 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -182,15 +182,19 @@ static struct v4l2_subdev_ops lif_ops = {
  * VSP1 Entity Operations
  */
 
-static void lif_configure(struct vsp1_entity *entity)
+static void lif_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	const struct v4l2_mbus_framefmt *format;
 	struct vsp1_lif *lif = to_lif(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	unsigned int hbth = 1300;
 	unsigned int obth = 400;
 	unsigned int lbth = 200;
 
-	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	format = vsp1_entity_get_pad_format(&lif->entity, config,
 					    LIF_PAD_SOURCE);
 
 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index d5d32ce10f41..76cf3ea73c71 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -219,7 +219,8 @@ static struct v4l2_subdev_ops lut_ops = {
  * VSP1 Entity Operations
  */
 
-static void lut_configure(struct vsp1_entity *entity)
+static void lut_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_lut *lut = to_lut(&entity->subdev);
 
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 84a3aedae768..a1cff6feec30 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -56,10 +56,12 @@ static void rpf_set_memory(struct vsp1_entity *entity)
 		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
-static void rpf_configure(struct vsp1_entity *entity)
+static void rpf_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
 	const struct v4l2_pix_format_mplane *format = &rpf->format;
 	const struct v4l2_mbus_framefmt *source_format;
@@ -70,13 +72,15 @@ static void rpf_configure(struct vsp1_entity *entity)
 	u32 pstride;
 	u32 infmt;
 
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
 	/* Source size, stride and crop offsets.
 	 *
 	 * The crop offsets correspond to the location of the crop rectangle top
 	 * left corner in the plane buffer. Only two offsets are needed, as
 	 * planes 2 and 3 always have identical strides.
 	 */
-	crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+	crop = vsp1_rwpf_get_crop(rpf, config);
 
 	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
 		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
@@ -102,11 +106,9 @@ static void rpf_configure(struct vsp1_entity *entity)
 	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
-	sink_format = vsp1_entity_get_pad_format(&rpf->entity,
-						 rpf->entity.config,
+	sink_format = vsp1_entity_get_pad_format(&rpf->entity, config,
 						 RWPF_PAD_SINK);
-	source_format = vsp1_entity_get_pad_format(&rpf->entity,
-						   rpf->entity.config,
+	source_format = vsp1_entity_get_pad_format(&rpf->entity, config,
 						   RWPF_PAD_SOURCE);
 
 	infmt = VI6_RPF_INFMT_CIPM
@@ -125,10 +127,11 @@ static void rpf_configure(struct vsp1_entity *entity)
 
 	/* Output location */
 	if (pipe->bru) {
+		struct v4l2_subdev_pad_config *bru_config;
 		const struct v4l2_rect *compose;
 
-		compose = vsp1_entity_get_pad_compose(pipe->bru,
-						      pipe->bru->config,
+		bru_config = vsp1_entity_get_req_pad_config(pipe->bru, req);
+		compose = vsp1_entity_get_pad_compose(pipe->bru, bru_config,
 						      rpf->bru_input);
 		left = compose->left;
 		top = compose->top;
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index e05149eabde9..0d6315c9ea17 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -295,17 +295,20 @@ static struct v4l2_subdev_ops sru_ops = {
  * VSP1 Entity Operations
  */
 
-static void sru_configure(struct vsp1_entity *entity)
+static void sru_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	const struct vsp1_sru_param *param;
 	struct vsp1_sru *sru = to_sru(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	struct v4l2_mbus_framefmt *input;
 	struct v4l2_mbus_framefmt *output;
 	u32 ctrl0;
 
-	input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
-					   SRU_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	input = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&sru->entity, config,
 					    SRU_PAD_SOURCE);
 
 	if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 1acbdd6d537f..7c6ad2c3967f 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -281,18 +281,21 @@ static struct v4l2_subdev_ops uds_ops = {
  * VSP1 Entity Operations
  */
 
-static void uds_configure(struct vsp1_entity *entity)
+static void uds_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_uds *uds = to_uds(&entity->subdev);
 	const struct v4l2_mbus_framefmt *output;
 	const struct v4l2_mbus_framefmt *input;
+	struct v4l2_subdev_pad_config *config;
 	unsigned int hscale;
 	unsigned int vscale;
 	bool multitap;
 
-	input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
-					   UDS_PAD_SINK);
-	output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
+	input = vsp1_entity_get_pad_format(&uds->entity, config, UDS_PAD_SINK);
+	output = vsp1_entity_get_pad_format(&uds->entity, config,
 					    UDS_PAD_SOURCE);
 
 	hscale = uds_compute_ratio(input->width, output->width);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 725759920611..c757847110ba 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -627,7 +627,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 		vsp1_entity_route_setup(entity);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity);
+			entity->ops->configure(entity, NULL);
 	}
 
 	/* We know that the WPF s_stream operation never fails. */
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 3f4b7208f3ef..bde990e010d4 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -117,15 +117,19 @@ static void wpf_set_memory(struct vsp1_entity *entity)
 	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
-static void wpf_configure(struct vsp1_entity *entity)
+static void wpf_configure(struct vsp1_entity *entity,
+			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+	struct v4l2_subdev_pad_config *config;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop;
 	u32 outfmt = 0;
 
+	config = vsp1_entity_get_req_pad_config(entity, req);
+
 	/* Destination stride. */
 	if (!pipe->lif) {
 		struct v4l2_pix_format_mplane *format = &wpf->format;
@@ -137,7 +141,7 @@ static void wpf_configure(struct vsp1_entity *entity)
 				       format->plane_fmt[1].bytesperline);
 	}
 
-	crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config);
+	crop = vsp1_rwpf_get_crop(wpf, config);
 
 	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
@@ -147,11 +151,9 @@ static void wpf_configure(struct vsp1_entity *entity)
 		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
 	/* Format */
-	sink_format = vsp1_entity_get_pad_format(&wpf->entity,
-						 wpf->entity.config,
+	sink_format = vsp1_entity_get_pad_format(&wpf->entity, config,
 						 RWPF_PAD_SINK);
-	source_format = vsp1_entity_get_pad_format(&wpf->entity,
-						   wpf->entity.config,
+	source_format = vsp1_entity_get_pad_format(&wpf->entity, config,
 						   RWPF_PAD_SOURCE);
 
 	if (!pipe->lif) {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 45/48] v4l: vsp1: Use __vsp1_video_try_format to initialize format at init time
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Reuse the runtime logic to initialize the default format instead of
open-coding it. This ensures coherency between intialization and
runtime.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index c757847110ba..a1527d622734 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -966,17 +966,10 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 		return ERR_PTR(ret);
 
 	/* ... and the format ... */
-	rwpf->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
-	rwpf->format.pixelformat = rwpf->fmtinfo->fourcc;
-	rwpf->format.colorspace = V4L2_COLORSPACE_SRGB;
-	rwpf->format.field = V4L2_FIELD_NONE;
+	rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT;
 	rwpf->format.width = VSP1_VIDEO_DEF_WIDTH;
 	rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT;
-	rwpf->format.num_planes = 1;
-	rwpf->format.plane_fmt[0].bytesperline -		rwpf->format.width * rwpf->fmtinfo->bpp[0] / 8;
-	rwpf->format.plane_fmt[0].sizeimage -		rwpf->format.plane_fmt[0].bytesperline * rwpf->format.height;
+	__vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo);
 
 	/* ... and the video node... */
 	video->video.v4l2_dev = &video->vsp1->v4l2_dev;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 45/48] v4l: vsp1: Use __vsp1_video_try_format to initialize format at init time
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Reuse the runtime logic to initialize the default format instead of
open-coding it. This ensures coherency between intialization and
runtime.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_video.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index c757847110ba..a1527d622734 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -966,17 +966,10 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 		return ERR_PTR(ret);
 
 	/* ... and the format ... */
-	rwpf->fmtinfo = vsp1_get_format_info(VSP1_VIDEO_DEF_FORMAT);
-	rwpf->format.pixelformat = rwpf->fmtinfo->fourcc;
-	rwpf->format.colorspace = V4L2_COLORSPACE_SRGB;
-	rwpf->format.field = V4L2_FIELD_NONE;
+	rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT;
 	rwpf->format.width = VSP1_VIDEO_DEF_WIDTH;
 	rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT;
-	rwpf->format.num_planes = 1;
-	rwpf->format.plane_fmt[0].bytesperline =
-		rwpf->format.width * rwpf->fmtinfo->bpp[0] / 8;
-	rwpf->format.plane_fmt[0].sizeimage =
-		rwpf->format.plane_fmt[0].bytesperline * rwpf->format.height;
+	__vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo);
 
 	/* ... and the video node... */
 	video->video.v4l2_dev = &video->vsp1->v4l2_dev;
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 46/48] v4l: vsp1: Support video device formats stored in requests
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Use the video device format stored in the request object when
configuring modules if the request isn't NULL.

As the request object doesn't support storage of driver-specific data
format information needs to be looked up on the fly and can't be cached
anymore.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c   |  2 +-
 drivers/media/platform/vsp1/vsp1_rpf.c   |  7 +++++--
 drivers/media/platform/vsp1/vsp1_rwpf.c  | 33 ++++++++++++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_rwpf.h  |  5 ++++-
 drivers/media/platform/vsp1/vsp1_video.c | 25 ++++++++++++------------
 drivers/media/platform/vsp1/vsp1_wpf.c   | 25 ++++++++++++------------
 6 files changed, 68 insertions(+), 29 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 5ac7e84b9a62..a27a74bbb8f8 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -320,7 +320,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 		return -EINVAL;
 	}
 
-	rpf->fmtinfo = fmtinfo;
+	rpf->format.pixelformat = pixelformat;
 	rpf->format.num_planes = fmtinfo->planes;
 	rpf->format.plane_fmt[0].bytesperline = pitch;
 	rpf->format.plane_fmt[1].bytesperline = pitch;
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index a1cff6feec30..80038f30ba53 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -62,8 +62,8 @@ static void rpf_configure(struct vsp1_entity *entity,
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 	struct v4l2_subdev_pad_config *config;
-	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
-	const struct v4l2_pix_format_mplane *format = &rpf->format;
+	const struct vsp1_format_info *fmtinfo;
+	const struct v4l2_pix_format_mplane *format;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop;
@@ -89,6 +89,9 @@ static void rpf_configure(struct vsp1_entity *entity,
 		       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
 
+	format = vsp1_rwpf_get_pixformat(rpf, req);
+	fmtinfo = vsp1_get_format_info(format->pixelformat);
+
 	rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
 			+ crop->left * fmtinfo->bpp[0] / 8;
 	pstride = format->plane_fmt[0].bytesperline
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 4d302f5cccb2..1252d45d6aca 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -27,6 +27,39 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
 					RWPF_PAD_SINK);
 }
 
+/**
+ * vsp1_rwpf_get_pixformat - Get a pixel format from a request
+ * @entity: the [RW]PF
+ * @req: the request
+ *
+ * Return the pixel format stored in the request for the given [RW]PF. If
+ * the request argument is NULL or doesn't contain pad configuration for the
+ * entity the function will instead return the ACTIVE pixel format stored in the
+ * [RW]PF.
+ */
+const struct v4l2_pix_format_mplane *
+vsp1_rwpf_get_pixformat(struct vsp1_rwpf *rwpf,
+			struct media_device_request *req)
+{
+	struct media_entity_request_data *data;
+	struct video_device_request_data *vdata;
+
+	/* If there's no request or if the request doesn't contain video device
+	 * data return the rwpf active format.
+	 */
+	if (!req)
+		return &rwpf->format;
+
+	data = media_device_request_get_entity_data(req,
+					&rwpf->entity.subdev.entity);
+	if (!data)
+		return &rwpf->format;
+
+	/* Otherwise return the format stored in the request. */
+	vdata = to_video_device_request_data(data);
+	return &vdata->format;
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 9502710977e8..64f101e35232 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -42,7 +42,6 @@ struct vsp1_rwpf {
 	unsigned int max_height;
 
 	struct v4l2_pix_format_mplane format;
-	const struct vsp1_format_info *fmtinfo;
 	unsigned int bru_input;
 
 	unsigned int alpha;
@@ -72,6 +71,10 @@ extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
 
 struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
 				     struct v4l2_subdev_pad_config *config);
+const struct v4l2_pix_format_mplane *
+vsp1_rwpf_get_pixformat(struct vsp1_rwpf *rwpf,
+			struct media_device_request *req);
+
 /**
  * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
  * @rwpf: the [RW]PF instance
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index a1527d622734..33a1a142002c 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -67,6 +67,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad)
 
 static int vsp1_video_verify_format(struct vsp1_video *video)
 {
+	const struct vsp1_format_info *info;
 	struct v4l2_subdev_format fmt;
 	struct v4l2_subdev *subdev;
 	int ret;
@@ -80,7 +81,9 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
 	if (ret < 0)
 		return ret = -ENOIOCTLCMD ? -EINVAL : ret;
 
-	if (video->rwpf->fmtinfo->mbus != fmt.format.code ||
+	info = vsp1_get_format_info(video->rwpf->format.pixelformat);
+
+	if (info->mbus != fmt.format.code ||
 	    video->rwpf->format.height != fmt.format.height ||
 	    video->rwpf->format.width != fmt.format.width)
 		return -EINVAL;
@@ -89,8 +92,7 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
 }
 
 static int __vsp1_video_try_format(struct vsp1_video *video,
-				   struct v4l2_pix_format_mplane *pix,
-				   const struct vsp1_format_info **fmtinfo)
+				   struct v4l2_pix_format_mplane *pix)
 {
 	static const u32 xrgb_formats[][2] = {
 		{ V4L2_PIX_FMT_RGB444, V4L2_PIX_FMT_XRGB444 },
@@ -163,9 +165,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
 
 	pix->num_planes = info->planes;
 
-	if (fmtinfo)
-		*fmtinfo = info;
-
 	return 0;
 }
 
@@ -177,7 +176,7 @@ vsp1_video_format_adjust(struct vsp1_video *video,
 	unsigned int i;
 
 	*adjust = *format;
-	__vsp1_video_try_format(video, adjust, NULL);
+	__vsp1_video_try_format(video, adjust);
 
 	if (format->width != adjust->width ||
 	    format->height != adjust->height ||
@@ -616,10 +615,12 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 		if (pipe->uds_input->type = VSP1_ENTITY_BRU) {
 			uds->scale_alpha = false;
 		} else {
+			const struct vsp1_format_info *info;
 			struct vsp1_rwpf *rpf  				to_rwpf(&pipe->uds_input->subdev);
 
-			uds->scale_alpha = rpf->fmtinfo->alpha;
+			info = vsp1_get_format_info(rpf->format.pixelformat);
+			uds->scale_alpha = info->alpha;
 		}
 	}
 
@@ -758,7 +759,7 @@ vsp1_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
 	if (format->type != video->queue.type)
 		return -EINVAL;
 
-	return __vsp1_video_try_format(video, &format->fmt.pix_mp, NULL);
+	return __vsp1_video_try_format(video, &format->fmt.pix_mp);
 }
 
 static int
@@ -766,13 +767,12 @@ vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
 {
 	struct v4l2_fh *vfh = file->private_data;
 	struct vsp1_video *video = to_vsp1_video(vfh->vdev);
-	const struct vsp1_format_info *info;
 	int ret;
 
 	if (format->type != video->queue.type)
 		return -EINVAL;
 
-	ret = __vsp1_video_try_format(video, &format->fmt.pix_mp, &info);
+	ret = __vsp1_video_try_format(video, &format->fmt.pix_mp);
 	if (ret < 0)
 		return ret;
 
@@ -784,7 +784,6 @@ vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
 	}
 
 	video->rwpf->format = format->fmt.pix_mp;
-	video->rwpf->fmtinfo = info;
 
 done:
 	mutex_unlock(&video->lock);
@@ -969,7 +968,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 	rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT;
 	rwpf->format.width = VSP1_VIDEO_DEF_WIDTH;
 	rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT;
-	__vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo);
+	__vsp1_video_try_format(video, &rwpf->format);
 
 	/* ... and the video node... */
 	video->video.v4l2_dev = &video->vsp1->v4l2_dev;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index bde990e010d4..417067f8aae3 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -130,17 +130,7 @@ static void wpf_configure(struct vsp1_entity *entity,
 
 	config = vsp1_entity_get_req_pad_config(entity, req);
 
-	/* Destination stride. */
-	if (!pipe->lif) {
-		struct v4l2_pix_format_mplane *format = &wpf->format;
-
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
-			       format->plane_fmt[0].bytesperline);
-		if (format->num_planes > 1)
-			vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
-				       format->plane_fmt[1].bytesperline);
-	}
-
+	/* Cropping */
 	crop = vsp1_rwpf_get_crop(wpf, config);
 
 	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
@@ -157,7 +147,11 @@ static void wpf_configure(struct vsp1_entity *entity,
 						   RWPF_PAD_SOURCE);
 
 	if (!pipe->lif) {
-		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
+		const struct v4l2_pix_format_mplane *format;
+		const struct vsp1_format_info *fmtinfo;
+
+		format = vsp1_rwpf_get_pixformat(wpf, req);
+		fmtinfo = vsp1_get_format_info(format->pixelformat);
 
 		outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
 
@@ -168,6 +162,13 @@ static void wpf_configure(struct vsp1_entity *entity,
 		if (fmtinfo->swap_uv)
 			outfmt |= VI6_WPF_OUTFMT_SPUVS;
 
+		/* Destination stride and byte swapping. */
+		vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
+			       format->plane_fmt[0].bytesperline);
+		if (format->num_planes > 1)
+			vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
+				       format->plane_fmt[1].bytesperline);
+
 		vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
 	}
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 46/48] v4l: vsp1: Support video device formats stored in requests
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Use the video device format stored in the request object when
configuring modules if the request isn't NULL.

As the request object doesn't support storage of driver-specific data
format information needs to be looked up on the fly and can't be cached
anymore.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_drm.c   |  2 +-
 drivers/media/platform/vsp1/vsp1_rpf.c   |  7 +++++--
 drivers/media/platform/vsp1/vsp1_rwpf.c  | 33 ++++++++++++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_rwpf.h  |  5 ++++-
 drivers/media/platform/vsp1/vsp1_video.c | 25 ++++++++++++------------
 drivers/media/platform/vsp1/vsp1_wpf.c   | 25 ++++++++++++------------
 6 files changed, 68 insertions(+), 29 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 5ac7e84b9a62..a27a74bbb8f8 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -320,7 +320,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
 		return -EINVAL;
 	}
 
-	rpf->fmtinfo = fmtinfo;
+	rpf->format.pixelformat = pixelformat;
 	rpf->format.num_planes = fmtinfo->planes;
 	rpf->format.plane_fmt[0].bytesperline = pitch;
 	rpf->format.plane_fmt[1].bytesperline = pitch;
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index a1cff6feec30..80038f30ba53 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -62,8 +62,8 @@ static void rpf_configure(struct vsp1_entity *entity,
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 	struct v4l2_subdev_pad_config *config;
-	const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
-	const struct v4l2_pix_format_mplane *format = &rpf->format;
+	const struct vsp1_format_info *fmtinfo;
+	const struct v4l2_pix_format_mplane *format;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop;
@@ -89,6 +89,9 @@ static void rpf_configure(struct vsp1_entity *entity,
 		       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
 
+	format = vsp1_rwpf_get_pixformat(rpf, req);
+	fmtinfo = vsp1_get_format_info(format->pixelformat);
+
 	rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
 			+ crop->left * fmtinfo->bpp[0] / 8;
 	pstride = format->plane_fmt[0].bytesperline
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index 4d302f5cccb2..1252d45d6aca 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -27,6 +27,39 @@ struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
 					RWPF_PAD_SINK);
 }
 
+/**
+ * vsp1_rwpf_get_pixformat - Get a pixel format from a request
+ * @entity: the [RW]PF
+ * @req: the request
+ *
+ * Return the pixel format stored in the request for the given [RW]PF. If
+ * the request argument is NULL or doesn't contain pad configuration for the
+ * entity the function will instead return the ACTIVE pixel format stored in the
+ * [RW]PF.
+ */
+const struct v4l2_pix_format_mplane *
+vsp1_rwpf_get_pixformat(struct vsp1_rwpf *rwpf,
+			struct media_device_request *req)
+{
+	struct media_entity_request_data *data;
+	struct video_device_request_data *vdata;
+
+	/* If there's no request or if the request doesn't contain video device
+	 * data return the rwpf active format.
+	 */
+	if (!req)
+		return &rwpf->format;
+
+	data = media_device_request_get_entity_data(req,
+					&rwpf->entity.subdev.entity);
+	if (!data)
+		return &rwpf->format;
+
+	/* Otherwise return the format stored in the request. */
+	vdata = to_video_device_request_data(data);
+	return &vdata->format;
+}
+
 /* -----------------------------------------------------------------------------
  * V4L2 Subdevice Pad Operations
  */
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 9502710977e8..64f101e35232 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -42,7 +42,6 @@ struct vsp1_rwpf {
 	unsigned int max_height;
 
 	struct v4l2_pix_format_mplane format;
-	const struct vsp1_format_info *fmtinfo;
 	unsigned int bru_input;
 
 	unsigned int alpha;
@@ -72,6 +71,10 @@ extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops;
 
 struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
 				     struct v4l2_subdev_pad_config *config);
+const struct v4l2_pix_format_mplane *
+vsp1_rwpf_get_pixformat(struct vsp1_rwpf *rwpf,
+			struct media_device_request *req);
+
 /**
  * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
  * @rwpf: the [RW]PF instance
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index a1527d622734..33a1a142002c 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -67,6 +67,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad)
 
 static int vsp1_video_verify_format(struct vsp1_video *video)
 {
+	const struct vsp1_format_info *info;
 	struct v4l2_subdev_format fmt;
 	struct v4l2_subdev *subdev;
 	int ret;
@@ -80,7 +81,9 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
 	if (ret < 0)
 		return ret == -ENOIOCTLCMD ? -EINVAL : ret;
 
-	if (video->rwpf->fmtinfo->mbus != fmt.format.code ||
+	info = vsp1_get_format_info(video->rwpf->format.pixelformat);
+
+	if (info->mbus != fmt.format.code ||
 	    video->rwpf->format.height != fmt.format.height ||
 	    video->rwpf->format.width != fmt.format.width)
 		return -EINVAL;
@@ -89,8 +92,7 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
 }
 
 static int __vsp1_video_try_format(struct vsp1_video *video,
-				   struct v4l2_pix_format_mplane *pix,
-				   const struct vsp1_format_info **fmtinfo)
+				   struct v4l2_pix_format_mplane *pix)
 {
 	static const u32 xrgb_formats[][2] = {
 		{ V4L2_PIX_FMT_RGB444, V4L2_PIX_FMT_XRGB444 },
@@ -163,9 +165,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
 
 	pix->num_planes = info->planes;
 
-	if (fmtinfo)
-		*fmtinfo = info;
-
 	return 0;
 }
 
@@ -177,7 +176,7 @@ vsp1_video_format_adjust(struct vsp1_video *video,
 	unsigned int i;
 
 	*adjust = *format;
-	__vsp1_video_try_format(video, adjust, NULL);
+	__vsp1_video_try_format(video, adjust);
 
 	if (format->width != adjust->width ||
 	    format->height != adjust->height ||
@@ -616,10 +615,12 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 		if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
 			uds->scale_alpha = false;
 		} else {
+			const struct vsp1_format_info *info;
 			struct vsp1_rwpf *rpf =
 				to_rwpf(&pipe->uds_input->subdev);
 
-			uds->scale_alpha = rpf->fmtinfo->alpha;
+			info = vsp1_get_format_info(rpf->format.pixelformat);
+			uds->scale_alpha = info->alpha;
 		}
 	}
 
@@ -758,7 +759,7 @@ vsp1_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
 	if (format->type != video->queue.type)
 		return -EINVAL;
 
-	return __vsp1_video_try_format(video, &format->fmt.pix_mp, NULL);
+	return __vsp1_video_try_format(video, &format->fmt.pix_mp);
 }
 
 static int
@@ -766,13 +767,12 @@ vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
 {
 	struct v4l2_fh *vfh = file->private_data;
 	struct vsp1_video *video = to_vsp1_video(vfh->vdev);
-	const struct vsp1_format_info *info;
 	int ret;
 
 	if (format->type != video->queue.type)
 		return -EINVAL;
 
-	ret = __vsp1_video_try_format(video, &format->fmt.pix_mp, &info);
+	ret = __vsp1_video_try_format(video, &format->fmt.pix_mp);
 	if (ret < 0)
 		return ret;
 
@@ -784,7 +784,6 @@ vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
 	}
 
 	video->rwpf->format = format->fmt.pix_mp;
-	video->rwpf->fmtinfo = info;
 
 done:
 	mutex_unlock(&video->lock);
@@ -969,7 +968,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 	rwpf->format.pixelformat = VSP1_VIDEO_DEF_FORMAT;
 	rwpf->format.width = VSP1_VIDEO_DEF_WIDTH;
 	rwpf->format.height = VSP1_VIDEO_DEF_HEIGHT;
-	__vsp1_video_try_format(video, &rwpf->format, &rwpf->fmtinfo);
+	__vsp1_video_try_format(video, &rwpf->format);
 
 	/* ... and the video node... */
 	video->video.v4l2_dev = &video->vsp1->v4l2_dev;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index bde990e010d4..417067f8aae3 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -130,17 +130,7 @@ static void wpf_configure(struct vsp1_entity *entity,
 
 	config = vsp1_entity_get_req_pad_config(entity, req);
 
-	/* Destination stride. */
-	if (!pipe->lif) {
-		struct v4l2_pix_format_mplane *format = &wpf->format;
-
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
-			       format->plane_fmt[0].bytesperline);
-		if (format->num_planes > 1)
-			vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
-				       format->plane_fmt[1].bytesperline);
-	}
-
+	/* Cropping */
 	crop = vsp1_rwpf_get_crop(wpf, config);
 
 	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
@@ -157,7 +147,11 @@ static void wpf_configure(struct vsp1_entity *entity,
 						   RWPF_PAD_SOURCE);
 
 	if (!pipe->lif) {
-		const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
+		const struct v4l2_pix_format_mplane *format;
+		const struct vsp1_format_info *fmtinfo;
+
+		format = vsp1_rwpf_get_pixformat(wpf, req);
+		fmtinfo = vsp1_get_format_info(format->pixelformat);
 
 		outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
 
@@ -168,6 +162,13 @@ static void wpf_configure(struct vsp1_entity *entity,
 		if (fmtinfo->swap_uv)
 			outfmt |= VI6_WPF_OUTFMT_SPUVS;
 
+		/* Destination stride and byte swapping. */
+		vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
+			       format->plane_fmt[0].bytesperline);
+		if (format->num_planes > 1)
+			vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
+				       format->plane_fmt[1].bytesperline);
+
 		vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
 	}
 
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 47/48] v4l: vsp1: Pass display list explicitly to configure functions
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Modules write register values to the active display list pointed to by
the pipeline. In order to support the request API we need to fill
display lists ahead of time. This requires passing the display list
explicitly to all configuration functions.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  22 ++++---
 drivers/media/platform/vsp1/vsp1_drm.c    |  14 ++--
 drivers/media/platform/vsp1/vsp1_entity.c |  14 ++--
 drivers/media/platform/vsp1/vsp1_entity.h |  15 +++--
 drivers/media/platform/vsp1/vsp1_hsit.c   |  12 ++--
 drivers/media/platform/vsp1/vsp1_lif.c    |  12 ++--
 drivers/media/platform/vsp1/vsp1_lut.c    |  10 +--
 drivers/media/platform/vsp1/vsp1_pipe.c   |   3 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   1 +
 drivers/media/platform/vsp1/vsp1_rpf.c    |  39 +++++------
 drivers/media/platform/vsp1/vsp1_rwpf.h   |   8 ++-
 drivers/media/platform/vsp1/vsp1_sru.c    |  14 ++--
 drivers/media/platform/vsp1/vsp1_uds.c    |  22 ++++---
 drivers/media/platform/vsp1/vsp1_uds.h    |   3 +-
 drivers/media/platform/vsp1/vsp1_video.c  |  11 ++--
 drivers/media/platform/vsp1/vsp1_wpf.c    | 104 +++++++++++++++---------------
 16 files changed, 156 insertions(+), 148 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index c570166008de..4b22fe92de2f 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -18,6 +18,7 @@
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
+#include "vsp1_dl.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
@@ -28,9 +29,10 @@
  * Device Access
  */
 
-static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
+static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&bru->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -303,7 +305,7 @@ static struct v4l2_subdev_ops bru_ops = {
  * VSP1 Entity Operations
  */
 
-static void bru_configure(struct vsp1_entity *entity,
+static void bru_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
@@ -328,26 +330,26 @@ static void bru_configure(struct vsp1_entity *entity,
 	 * format at the pipeline output is premultiplied.
 	 */
 	flags = pipe->output ? pipe->output->format.flags : 0;
-	vsp1_bru_write(bru, VI6_BRU_INCTRL,
+	vsp1_bru_write(bru, dl, VI6_BRU_INCTRL,
 		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
 		       0 : VI6_BRU_INCTRL_NRM);
 
 	/* Set the background position to cover the whole output image and
 	 * configure its color.
 	 */
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
+	vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE,
 		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
 		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
+	vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0);
 
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+	vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor |
 		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
 
 	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
 	 * unit with a NOP operation to make BRU input 1 available as the
 	 * Blend/ROP unit B SRC input.
 	 */
-	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
+	vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
 		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
 		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));
 
@@ -384,7 +386,7 @@ static void bru_configure(struct vsp1_entity *entity,
 		if (i != 1)
 			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
 
-		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
+		vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl);
 
 		/* Harcode the blending formula to
 		 *
@@ -398,7 +400,7 @@ static void bru_configure(struct vsp1_entity *entity,
 		 *
 		 * otherwise.
 		 */
-		vsp1_bru_write(bru, VI6_BRU_BLD(i),
+		vsp1_bru_write(bru, dl, VI6_BRU_BLD(i),
 			       VI6_BRU_BLD_CCMDX_255_SRC_A |
 			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
 						VI6_BRU_BLD_CCMDY_SRC_A) |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index a27a74bbb8f8..cc2be3576cfa 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -455,24 +455,22 @@ void vsp1_du_atomic_flush(struct device *dev)
 			struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 
 			if (!pipe->inputs[rpf->entity.index]) {
-				vsp1_mod_write(entity, entity->route->reg,
-					   VI6_DPR_NODE_UNUSED);
+				vsp1_dl_list_write(pipe->dl, entity->route->reg,
+						   VI6_DPR_NODE_UNUSED);
 				continue;
 			}
 		}
 
-		vsp1_entity_route_setup(entity);
+		vsp1_entity_route_setup(entity, pipe->dl);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity, NULL);
+			entity->ops->configure(entity, pipe->dl, NULL);
 
 		if (entity->type = VSP1_ENTITY_RPF)
-			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
+			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev),
+					     pipe->dl);
 	}
 
-	/* We know that the WPF s_stream operation never fails. */
-	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
-
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index bde530108717..0182262603ed 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -23,14 +23,8 @@
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
 
-void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
-
-	vsp1_dl_list_write(pipe->dl, reg, data);
-}
-
-void vsp1_entity_route_setup(struct vsp1_entity *source)
+void vsp1_entity_route_setup(struct vsp1_entity *source,
+			     struct vsp1_dl_list *dl)
 {
 	struct vsp1_entity *sink;
 
@@ -38,8 +32,8 @@ void vsp1_entity_route_setup(struct vsp1_entity *source)
 		return;
 
 	sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
-	vsp1_mod_write(source, source->route->reg,
-		       sink->route->inputs[source->sink_pad]);
+	vsp1_dl_list_write(dl, source->route->reg,
+			   sink->route->inputs[source->sink_pad]);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 438e743deca1..c7c3c6b7f65a 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -20,6 +20,7 @@
 
 struct media_device_request;
 struct vsp1_device;
+struct vsp1_dl_list;
 
 enum vsp1_entity_type {
 	VSP1_ENTITY_BRU,
@@ -58,15 +59,16 @@ struct vsp1_route {
  * struct vsp1_entity_operations - Entity operations
  * @destroy:	Destroy the entity.
  * @set_memory:	Setup memory buffer access. This operation applies the settings
- *		stored in the rwpf mem field to the hardware. Valid for RPF and
- *		WPF only.
+ *		stored in the rwpf mem field to the display list. Valid for RPF
+ *		and WPF only.
  * @configure:	Setup the hardware based on the entity state (pipeline, formats,
  *		selection rectangles, ...)
  */
 struct vsp1_entity_operations {
 	void (*destroy)(struct vsp1_entity *);
-	void (*set_memory)(struct vsp1_entity *);
-	void (*configure)(struct vsp1_entity *, struct media_device_request *);
+	void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl);
+	void (*configure)(struct vsp1_entity *, struct vsp1_dl_list *dl,
+			  struct media_device_request *);
 };
 
 struct vsp1_entity {
@@ -125,8 +127,7 @@ vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
 void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_pad_config *cfg);
 
-void vsp1_entity_route_setup(struct vsp1_entity *source);
-
-void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data);
+void vsp1_entity_route_setup(struct vsp1_entity *source,
+			     struct vsp1_dl_list *dl);
 
 #endif /* __VSP1_ENTITY_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index dda347cf077b..6ed484f344e7 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_hsit.h"
 
 #define HSIT_MIN_SIZE				4U
@@ -26,9 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
+static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
+				   struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	vsp1_mod_write(&hsit->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -164,15 +166,15 @@ static struct v4l2_subdev_ops hsit_ops = {
  * VSP1 Entity Operations
  */
 
-static void hsit_configure(struct vsp1_entity *entity,
+static void hsit_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			   struct media_device_request *req)
 {
 	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
 
 	if (hsit->inverse)
-		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
+		vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
 	else
-		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
+		vsp1_hsit_write(hsit, dl, VI6_HST_CTRL, VI6_HST_CTRL_EN);
 }
 
 static const struct vsp1_entity_operations hsit_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 3f22e2a6d750..7c8fd5f0352d 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_lif.h"
 
 #define LIF_MIN_SIZE				2U
@@ -26,9 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
+static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&lif->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -182,7 +184,7 @@ static struct v4l2_subdev_ops lif_ops = {
  * VSP1 Entity Operations
  */
 
-static void lif_configure(struct vsp1_entity *entity,
+static void lif_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	const struct v4l2_mbus_framefmt *format;
@@ -199,11 +201,11 @@ static void lif_configure(struct vsp1_entity *entity,
 
 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
 
-	vsp1_lif_write(lif, VI6_LIF_CSBTH,
+	vsp1_lif_write(lif, dl, VI6_LIF_CSBTH,
 			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
 			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
 
-	vsp1_lif_write(lif, VI6_LIF_CTRL,
+	vsp1_lif_write(lif, dl, VI6_LIF_CTRL,
 			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
 			(format->code = 0 ? VI6_LIF_CTRL_CFMT : 0) |
 			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 76cf3ea73c71..803919e3706c 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -18,6 +18,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_lut.h"
 
 #define LUT_MIN_SIZE				4U
@@ -27,9 +28,10 @@
  * Device Access
  */
 
-static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
+static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&lut->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -219,12 +221,12 @@ static struct v4l2_subdev_ops lut_ops = {
  * VSP1 Entity Operations
  */
 
-static void lut_configure(struct vsp1_entity *entity,
+static void lut_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_lut *lut = to_lut(&entity->subdev);
 
-	vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
+	vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
 }
 
 static const struct vsp1_entity_operations lut_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 5e91277c2972..38157a2e4cbc 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -274,6 +274,7 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
  */
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_entity *input,
+				   struct vsp1_dl_list *dl,
 				   unsigned int alpha)
 {
 	struct vsp1_entity *entity;
@@ -296,7 +297,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 		if (entity->type = VSP1_ENTITY_UDS) {
 			struct vsp1_uds *uds = to_uds(&entity->subdev);
 
-			vsp1_uds_set_alpha(uds, alpha);
+			vsp1_uds_set_alpha(uds, dl, alpha);
 			break;
 		}
 
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index f4bdfc943add..1100229a1ed2 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -123,6 +123,7 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_entity *input,
+				   struct vsp1_dl_list *dl,
 				   unsigned int alpha);
 
 void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 80038f30ba53..01b189c93d4a 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -16,6 +16,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
@@ -26,10 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
+static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
+				  struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
-		       data);
+	vsp1_dl_list_write(dl, reg + rpf->entity.index * VI6_RPF_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -44,19 +45,19 @@ static struct v4l2_subdev_ops rpf_ops = {
  * VSP1 Entity Operations
  */
 
-static void rpf_set_memory(struct vsp1_entity *entity)
+static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
 {
 	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
 		       rpf->mem.addr[0] + rpf->offsets[0]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
 		       rpf->mem.addr[1] + rpf->offsets[1]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
 		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
-static void rpf_configure(struct vsp1_entity *entity,
+static void rpf_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
@@ -82,10 +83,10 @@ static void rpf_configure(struct vsp1_entity *entity,
 	 */
 	crop = vsp1_rwpf_get_crop(rpf, config);
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
 		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
-	vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
 		       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
 
@@ -106,7 +107,7 @@ static void rpf_configure(struct vsp1_entity *entity,
 		rpf->offsets[1] = 0;
 	}
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
 	sink_format = vsp1_entity_get_pad_format(&rpf->entity, config,
@@ -125,8 +126,8 @@ static void rpf_configure(struct vsp1_entity *entity,
 	if (sink_format->code != source_format->code)
 		infmt |= VI6_RPF_INFMT_CSC;
 
-	vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
-	vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap);
 
 	/* Output location */
 	if (pipe->bru) {
@@ -140,7 +141,7 @@ static void rpf_configure(struct vsp1_entity *entity,
 		top = compose->top;
 	}
 
-	vsp1_rpf_write(rpf, VI6_RPF_LOC,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
 		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
 		       (top << VI6_RPF_LOC_VCOORD_SHIFT));
 
@@ -148,17 +149,17 @@ static void rpf_configure(struct vsp1_entity *entity,
 	 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
 	 * otherwise. Disable color keying.
 	 */
-	vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
+	vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
 		       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
 				       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
 
-	vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
 		       rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
 
-	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
+	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha);
 
-	vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
-	vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0);
 }
 
 static const struct vsp1_entity_operations rpf_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 64f101e35232..2637ae1a4719 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -78,12 +78,14 @@ vsp1_rwpf_get_pixformat(struct vsp1_rwpf *rwpf,
 /**
  * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
  * @rwpf: the [RW]PF instance
+ * @dl: the display list
  *
- * This function applies the cached memory buffer address to the hardware.
+ * This function applies the cached memory buffer address to the display list.
  */
-static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf)
+static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf,
+					struct vsp1_dl_list *dl)
 {
-	rwpf->entity.ops->set_memory(&rwpf->entity);
+	rwpf->entity.ops->set_memory(&rwpf->entity, dl);
 }
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 0d6315c9ea17..4bb8ab98ac5f 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_sru.h"
 
 #define SRU_MIN_SIZE				4U
@@ -26,9 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
+static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&sru->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -295,7 +297,7 @@ static struct v4l2_subdev_ops sru_ops = {
  * VSP1 Entity Operations
  */
 
-static void sru_configure(struct vsp1_entity *entity,
+static void sru_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	const struct vsp1_sru_param *param;
@@ -324,9 +326,9 @@ static void sru_configure(struct vsp1_entity *entity,
 
 	ctrl0 |= param->ctrl0;
 
-	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
-	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+	vsp1_sru_write(sru, dl, VI6_SRU_CTRL0, ctrl0);
+	vsp1_sru_write(sru, dl, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+	vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2);
 }
 
 static const struct vsp1_entity_operations sru_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 7c6ad2c3967f..98ba7516d045 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_uds.h"
 
 #define UDS_MIN_SIZE				4U
@@ -29,19 +30,20 @@
  * Device Access
  */
 
-static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
+static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&uds->entity, reg + uds->entity.index * VI6_UDS_OFFSET,
-		       data);
+	vsp1_dl_list_write(dl, reg + uds->entity.index * VI6_UDS_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
  * Scaling Computation
  */
 
-void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha)
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+			unsigned int alpha)
 {
-	vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
+	vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
 }
 
 /*
@@ -281,7 +283,7 @@ static struct v4l2_subdev_ops uds_ops = {
  * VSP1 Entity Operations
  */
 
-static void uds_configure(struct vsp1_entity *entity,
+static void uds_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_uds *uds = to_uds(&entity->subdev);
@@ -312,21 +314,21 @@ static void uds_configure(struct vsp1_entity *entity,
 	else
 		multitap = true;
 
-	vsp1_uds_write(uds, VI6_UDS_CTRL,
+	vsp1_uds_write(uds, dl, VI6_UDS_CTRL,
 		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
 		       (multitap ? VI6_UDS_CTRL_BC : 0));
 
-	vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
+	vsp1_uds_write(uds, dl, VI6_UDS_PASS_BWIDTH,
 		       (uds_passband_width(hscale)
 				<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
 		       (uds_passband_width(vscale)
 				<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
 
 	/* Set the scaling ratios and the output size. */
-	vsp1_uds_write(uds, VI6_UDS_SCALE,
+	vsp1_uds_write(uds, dl, VI6_UDS_SCALE,
 		       (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
 		       (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
-	vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
+	vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
 		       (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
 		       (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
 }
diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h
index 031ac0da1b66..5c8cbfcad4cc 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.h
+++ b/drivers/media/platform/vsp1/vsp1_uds.h
@@ -35,6 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
 
 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index);
 
-void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha);
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+			unsigned int alpha);
 
 #endif /* __VSP1_UDS_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 33a1a142002c..c30e29a4eb07 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -460,11 +460,11 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
 		struct vsp1_rwpf *rwpf = pipe->inputs[i];
 
 		if (rwpf)
-			vsp1_rwpf_set_memory(rwpf);
+			vsp1_rwpf_set_memory(rwpf, pipe->dl);
 	}
 
 	if (!pipe->lif)
-		vsp1_rwpf_set_memory(pipe->output);
+		vsp1_rwpf_set_memory(pipe->output, pipe->dl);
 
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
@@ -625,15 +625,12 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 	}
 
 	list_for_each_entry(entity, &pipe->entities, list_pipe) {
-		vsp1_entity_route_setup(entity);
+		vsp1_entity_route_setup(entity, pipe->dl);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity, NULL);
+			entity->ops->configure(entity, pipe->dl, NULL);
 	}
 
-	/* We know that the WPF s_stream operation never fails. */
-	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
-
 	return 0;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 417067f8aae3..24308b8de22d 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -27,10 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
+static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
+				  struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	vsp1_mod_write(&wpf->entity,
-		       reg + wpf->entity.index * VI6_WPF_OFFSET, data);
+	vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -39,47 +39,18 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
 
 static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 {
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *wpf = to_rwpf(subdev);
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
-	unsigned int i;
-	u32 srcrpf = 0;
 
-	if (!enable) {
-		/* Write to registers directly when stopping the stream as there
-		 * will be no pipeline run to apply the display list.
-		 */
-		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
-		vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
-			   VI6_WPF_SRCRPF, 0);
+	if (enable)
 		return 0;
-	}
 
-	/* Sources. If the pipeline has a single input and BRU is not used,
-	 * configure it as the master layer. Otherwise configure all
-	 * inputs as sub-layers and select the virtual RPF as the master
-	 * layer.
+	/* Write to registers directly when stopping the stream as there
+	 * will be no pipeline run to apply the display list.
 	 */
-	for (i = 0; i < vsp1->info->rpf_count; ++i) {
-		struct vsp1_rwpf *input = pipe->inputs[i];
-
-		if (!input)
-			continue;
-
-		srcrpf |= (!pipe->bru && pipe->num_inputs = 1)
-			? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
-			: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
-	}
-
-	if (pipe->bru || pipe->num_inputs > 1)
-		srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
-
-	vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
-
-	/* Enable interrupts */
-	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
-	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
-		   VI6_WFP_IRQ_ENB_FREE);
+	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
+	vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
+		   VI6_WPF_SRCRPF, 0);
 
 	return 0;
 }
@@ -108,35 +79,38 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 	vsp1_dlm_destroy(wpf->dlm);
 }
 
-static void wpf_set_memory(struct vsp1_entity *entity)
+static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
 {
 	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
 
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
-static void wpf_configure(struct vsp1_entity *entity,
+static void wpf_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+	struct vsp1_device *vsp1 = wpf->entity.vsp1;
 	struct v4l2_subdev_pad_config *config;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop;
+	unsigned int i;
 	u32 outfmt = 0;
+	u32 srcrpf = 0;
 
 	config = vsp1_entity_get_req_pad_config(entity, req);
 
 	/* Cropping */
 	crop = vsp1_rwpf_get_crop(wpf, config);
 
-	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
+	vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
-	vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
+	vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
@@ -163,25 +137,51 @@ static void wpf_configure(struct vsp1_entity *entity,
 			outfmt |= VI6_WPF_OUTFMT_SPUVS;
 
 		/* Destination stride and byte swapping. */
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
+		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y,
 			       format->plane_fmt[0].bytesperline);
 		if (format->num_planes > 1)
-			vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
+			vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C,
 				       format->plane_fmt[1].bytesperline);
 
-		vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
+		vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
 	}
 
 	if (sink_format->code != source_format->code)
 		outfmt |= VI6_WPF_OUTFMT_CSC;
 
 	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
-	vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
+
+	vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+			   VI6_DPR_WPF_FPORCH_FP_WPFN);
+
+	vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0);
+
+	/* Sources. If the pipeline has a single input and BRU is not used,
+	 * configure it as the master layer. Otherwise configure all
+	 * inputs as sub-layers and select the virtual RPF as the master
+	 * layer.
+	 */
+	for (i = 0; i < vsp1->info->rpf_count; ++i) {
+		struct vsp1_rwpf *input = pipe->inputs[i];
 
-	vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index),
-		       VI6_DPR_WPF_FPORCH_FP_WPFN);
+		if (!input)
+			continue;
+
+		srcrpf |= (!pipe->bru && pipe->num_inputs = 1)
+			? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
+			: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
+	}
+
+	if (pipe->bru || pipe->num_inputs > 1)
+		srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
+
+	vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf);
 
-	vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0);
+	/* Enable interrupts */
+	vsp1_wpf_write(wpf, dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_IRQ_ENB(wpf->entity.index),
+		       VI6_WFP_IRQ_ENB_FREE);
 }
 
 static const struct vsp1_entity_operations wpf_entity_ops = {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 47/48] v4l: vsp1: Pass display list explicitly to configure functions
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Modules write register values to the active display list pointed to by
the pipeline. In order to support the request API we need to fill
display lists ahead of time. This requires passing the display list
explicitly to all configuration functions.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/vsp1_bru.c    |  22 ++++---
 drivers/media/platform/vsp1/vsp1_drm.c    |  14 ++--
 drivers/media/platform/vsp1/vsp1_entity.c |  14 ++--
 drivers/media/platform/vsp1/vsp1_entity.h |  15 +++--
 drivers/media/platform/vsp1/vsp1_hsit.c   |  12 ++--
 drivers/media/platform/vsp1/vsp1_lif.c    |  12 ++--
 drivers/media/platform/vsp1/vsp1_lut.c    |  10 +--
 drivers/media/platform/vsp1/vsp1_pipe.c   |   3 +-
 drivers/media/platform/vsp1/vsp1_pipe.h   |   1 +
 drivers/media/platform/vsp1/vsp1_rpf.c    |  39 +++++------
 drivers/media/platform/vsp1/vsp1_rwpf.h   |   8 ++-
 drivers/media/platform/vsp1/vsp1_sru.c    |  14 ++--
 drivers/media/platform/vsp1/vsp1_uds.c    |  22 ++++---
 drivers/media/platform/vsp1/vsp1_uds.h    |   3 +-
 drivers/media/platform/vsp1/vsp1_video.c  |  11 ++--
 drivers/media/platform/vsp1/vsp1_wpf.c    | 104 +++++++++++++++---------------
 16 files changed, 156 insertions(+), 148 deletions(-)

diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index c570166008de..4b22fe92de2f 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -18,6 +18,7 @@
 
 #include "vsp1.h"
 #include "vsp1_bru.h"
+#include "vsp1_dl.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
@@ -28,9 +29,10 @@
  * Device Access
  */
 
-static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
+static inline void vsp1_bru_write(struct vsp1_bru *bru, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&bru->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -303,7 +305,7 @@ static struct v4l2_subdev_ops bru_ops = {
  * VSP1 Entity Operations
  */
 
-static void bru_configure(struct vsp1_entity *entity,
+static void bru_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
@@ -328,26 +330,26 @@ static void bru_configure(struct vsp1_entity *entity,
 	 * format at the pipeline output is premultiplied.
 	 */
 	flags = pipe->output ? pipe->output->format.flags : 0;
-	vsp1_bru_write(bru, VI6_BRU_INCTRL,
+	vsp1_bru_write(bru, dl, VI6_BRU_INCTRL,
 		       flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
 		       0 : VI6_BRU_INCTRL_NRM);
 
 	/* Set the background position to cover the whole output image and
 	 * configure its color.
 	 */
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
+	vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE,
 		       (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
 		       (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
+	vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_LOC, 0);
 
-	vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, bru->bgcolor |
+	vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor |
 		       (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
 
 	/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
 	 * unit with a NOP operation to make BRU input 1 available as the
 	 * Blend/ROP unit B SRC input.
 	 */
-	vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
+	vsp1_bru_write(bru, dl, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) |
 		       VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
 		       VI6_BRU_ROP_AROP(VI6_ROP_NOP));
 
@@ -384,7 +386,7 @@ static void bru_configure(struct vsp1_entity *entity,
 		if (i != 1)
 			ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
 
-		vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl);
+		vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl);
 
 		/* Harcode the blending formula to
 		 *
@@ -398,7 +400,7 @@ static void bru_configure(struct vsp1_entity *entity,
 		 *
 		 * otherwise.
 		 */
-		vsp1_bru_write(bru, VI6_BRU_BLD(i),
+		vsp1_bru_write(bru, dl, VI6_BRU_BLD(i),
 			       VI6_BRU_BLD_CCMDX_255_SRC_A |
 			       (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
 						VI6_BRU_BLD_CCMDY_SRC_A) |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index a27a74bbb8f8..cc2be3576cfa 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -455,24 +455,22 @@ void vsp1_du_atomic_flush(struct device *dev)
 			struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
 
 			if (!pipe->inputs[rpf->entity.index]) {
-				vsp1_mod_write(entity, entity->route->reg,
-					   VI6_DPR_NODE_UNUSED);
+				vsp1_dl_list_write(pipe->dl, entity->route->reg,
+						   VI6_DPR_NODE_UNUSED);
 				continue;
 			}
 		}
 
-		vsp1_entity_route_setup(entity);
+		vsp1_entity_route_setup(entity, pipe->dl);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity, NULL);
+			entity->ops->configure(entity, pipe->dl, NULL);
 
 		if (entity->type == VSP1_ENTITY_RPF)
-			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev));
+			vsp1_rwpf_set_memory(to_rwpf(&entity->subdev),
+					     pipe->dl);
 	}
 
-	/* We know that the WPF s_stream operation never fails. */
-	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
-
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
 
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index bde530108717..0182262603ed 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -23,14 +23,8 @@
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
 
-void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data)
-{
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&e->subdev.entity);
-
-	vsp1_dl_list_write(pipe->dl, reg, data);
-}
-
-void vsp1_entity_route_setup(struct vsp1_entity *source)
+void vsp1_entity_route_setup(struct vsp1_entity *source,
+			     struct vsp1_dl_list *dl)
 {
 	struct vsp1_entity *sink;
 
@@ -38,8 +32,8 @@ void vsp1_entity_route_setup(struct vsp1_entity *source)
 		return;
 
 	sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
-	vsp1_mod_write(source, source->route->reg,
-		       sink->route->inputs[source->sink_pad]);
+	vsp1_dl_list_write(dl, source->route->reg,
+			   sink->route->inputs[source->sink_pad]);
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 438e743deca1..c7c3c6b7f65a 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -20,6 +20,7 @@
 
 struct media_device_request;
 struct vsp1_device;
+struct vsp1_dl_list;
 
 enum vsp1_entity_type {
 	VSP1_ENTITY_BRU,
@@ -58,15 +59,16 @@ struct vsp1_route {
  * struct vsp1_entity_operations - Entity operations
  * @destroy:	Destroy the entity.
  * @set_memory:	Setup memory buffer access. This operation applies the settings
- *		stored in the rwpf mem field to the hardware. Valid for RPF and
- *		WPF only.
+ *		stored in the rwpf mem field to the display list. Valid for RPF
+ *		and WPF only.
  * @configure:	Setup the hardware based on the entity state (pipeline, formats,
  *		selection rectangles, ...)
  */
 struct vsp1_entity_operations {
 	void (*destroy)(struct vsp1_entity *);
-	void (*set_memory)(struct vsp1_entity *);
-	void (*configure)(struct vsp1_entity *, struct media_device_request *);
+	void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl);
+	void (*configure)(struct vsp1_entity *, struct vsp1_dl_list *dl,
+			  struct media_device_request *);
 };
 
 struct vsp1_entity {
@@ -125,8 +127,7 @@ vsp1_entity_get_pad_compose(struct vsp1_entity *entity,
 void vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
 			  struct v4l2_subdev_pad_config *cfg);
 
-void vsp1_entity_route_setup(struct vsp1_entity *source);
-
-void vsp1_mod_write(struct vsp1_entity *e, u32 reg, u32 data);
+void vsp1_entity_route_setup(struct vsp1_entity *source,
+			     struct vsp1_dl_list *dl);
 
 #endif /* __VSP1_ENTITY_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index dda347cf077b..6ed484f344e7 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_hsit.h"
 
 #define HSIT_MIN_SIZE				4U
@@ -26,9 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
+static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
+				   struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	vsp1_mod_write(&hsit->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -164,15 +166,15 @@ static struct v4l2_subdev_ops hsit_ops = {
  * VSP1 Entity Operations
  */
 
-static void hsit_configure(struct vsp1_entity *entity,
+static void hsit_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			   struct media_device_request *req)
 {
 	struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
 
 	if (hsit->inverse)
-		vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
+		vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
 	else
-		vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
+		vsp1_hsit_write(hsit, dl, VI6_HST_CTRL, VI6_HST_CTRL_EN);
 }
 
 static const struct vsp1_entity_operations hsit_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 3f22e2a6d750..7c8fd5f0352d 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_lif.h"
 
 #define LIF_MIN_SIZE				2U
@@ -26,9 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_lif_write(struct vsp1_lif *lif, u32 reg, u32 data)
+static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&lif->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -182,7 +184,7 @@ static struct v4l2_subdev_ops lif_ops = {
  * VSP1 Entity Operations
  */
 
-static void lif_configure(struct vsp1_entity *entity,
+static void lif_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	const struct v4l2_mbus_framefmt *format;
@@ -199,11 +201,11 @@ static void lif_configure(struct vsp1_entity *entity,
 
 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
 
-	vsp1_lif_write(lif, VI6_LIF_CSBTH,
+	vsp1_lif_write(lif, dl, VI6_LIF_CSBTH,
 			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
 			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
 
-	vsp1_lif_write(lif, VI6_LIF_CTRL,
+	vsp1_lif_write(lif, dl, VI6_LIF_CTRL,
 			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
 			(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
 			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 76cf3ea73c71..803919e3706c 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -18,6 +18,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_lut.h"
 
 #define LUT_MIN_SIZE				4U
@@ -27,9 +28,10 @@
  * Device Access
  */
 
-static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
+static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&lut->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -219,12 +221,12 @@ static struct v4l2_subdev_ops lut_ops = {
  * VSP1 Entity Operations
  */
 
-static void lut_configure(struct vsp1_entity *entity,
+static void lut_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_lut *lut = to_lut(&entity->subdev);
 
-	vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
+	vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
 }
 
 static const struct vsp1_entity_operations lut_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 5e91277c2972..38157a2e4cbc 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -274,6 +274,7 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
  */
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_entity *input,
+				   struct vsp1_dl_list *dl,
 				   unsigned int alpha)
 {
 	struct vsp1_entity *entity;
@@ -296,7 +297,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 		if (entity->type == VSP1_ENTITY_UDS) {
 			struct vsp1_uds *uds = to_uds(&entity->subdev);
 
-			vsp1_uds_set_alpha(uds, alpha);
+			vsp1_uds_set_alpha(uds, dl, alpha);
 			break;
 		}
 
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index f4bdfc943add..1100229a1ed2 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -123,6 +123,7 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
 void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
 				   struct vsp1_entity *input,
+				   struct vsp1_dl_list *dl,
 				   unsigned int alpha);
 
 void vsp1_pipelines_suspend(struct vsp1_device *vsp1);
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 80038f30ba53..01b189c93d4a 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -16,6 +16,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_video.h"
 
@@ -26,10 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
+static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
+				  struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
-		       data);
+	vsp1_dl_list_write(dl, reg + rpf->entity.index * VI6_RPF_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -44,19 +45,19 @@ static struct v4l2_subdev_ops rpf_ops = {
  * VSP1 Entity Operations
  */
 
-static void rpf_set_memory(struct vsp1_entity *entity)
+static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
 {
 	struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
 		       rpf->mem.addr[0] + rpf->offsets[0]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
 		       rpf->mem.addr[1] + rpf->offsets[1]);
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
 		       rpf->mem.addr[2] + rpf->offsets[1]);
 }
 
-static void rpf_configure(struct vsp1_entity *entity,
+static void rpf_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
@@ -82,10 +83,10 @@ static void rpf_configure(struct vsp1_entity *entity,
 	 */
 	crop = vsp1_rwpf_get_crop(rpf, config);
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
 		       (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
-	vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
 		       (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
 		       (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
 
@@ -106,7 +107,7 @@ static void rpf_configure(struct vsp1_entity *entity,
 		rpf->offsets[1] = 0;
 	}
 
-	vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
 
 	/* Format */
 	sink_format = vsp1_entity_get_pad_format(&rpf->entity, config,
@@ -125,8 +126,8 @@ static void rpf_configure(struct vsp1_entity *entity,
 	if (sink_format->code != source_format->code)
 		infmt |= VI6_RPF_INFMT_CSC;
 
-	vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
-	vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap);
 
 	/* Output location */
 	if (pipe->bru) {
@@ -140,7 +141,7 @@ static void rpf_configure(struct vsp1_entity *entity,
 		top = compose->top;
 	}
 
-	vsp1_rpf_write(rpf, VI6_RPF_LOC,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
 		       (left << VI6_RPF_LOC_HCOORD_SHIFT) |
 		       (top << VI6_RPF_LOC_VCOORD_SHIFT));
 
@@ -148,17 +149,17 @@ static void rpf_configure(struct vsp1_entity *entity,
 	 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
 	 * otherwise. Disable color keying.
 	 */
-	vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
+	vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
 		       (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
 				       : VI6_RPF_ALPH_SEL_ASEL_FIXED));
 
-	vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
+	vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
 		       rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
 
-	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
+	vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha);
 
-	vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
-	vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0);
+	vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0);
 }
 
 static const struct vsp1_entity_operations rpf_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 64f101e35232..2637ae1a4719 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -78,12 +78,14 @@ vsp1_rwpf_get_pixformat(struct vsp1_rwpf *rwpf,
 /**
  * vsp1_rwpf_set_memory - Configure DMA addresses for a [RW]PF
  * @rwpf: the [RW]PF instance
+ * @dl: the display list
  *
- * This function applies the cached memory buffer address to the hardware.
+ * This function applies the cached memory buffer address to the display list.
  */
-static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf)
+static inline void vsp1_rwpf_set_memory(struct vsp1_rwpf *rwpf,
+					struct vsp1_dl_list *dl)
 {
-	rwpf->entity.ops->set_memory(&rwpf->entity);
+	rwpf->entity.ops->set_memory(&rwpf->entity, dl);
 }
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index 0d6315c9ea17..4bb8ab98ac5f 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_sru.h"
 
 #define SRU_MIN_SIZE				4U
@@ -26,9 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
+static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&sru->entity, reg, data);
+	vsp1_dl_list_write(dl, reg, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -295,7 +297,7 @@ static struct v4l2_subdev_ops sru_ops = {
  * VSP1 Entity Operations
  */
 
-static void sru_configure(struct vsp1_entity *entity,
+static void sru_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	const struct vsp1_sru_param *param;
@@ -324,9 +326,9 @@ static void sru_configure(struct vsp1_entity *entity,
 
 	ctrl0 |= param->ctrl0;
 
-	vsp1_sru_write(sru, VI6_SRU_CTRL0, ctrl0);
-	vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
-	vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+	vsp1_sru_write(sru, dl, VI6_SRU_CTRL0, ctrl0);
+	vsp1_sru_write(sru, dl, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+	vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2);
 }
 
 static const struct vsp1_entity_operations sru_entity_ops = {
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 7c6ad2c3967f..98ba7516d045 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
+#include "vsp1_dl.h"
 #include "vsp1_uds.h"
 
 #define UDS_MIN_SIZE				4U
@@ -29,19 +30,20 @@
  * Device Access
  */
 
-static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
+static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+				  u32 reg, u32 data)
 {
-	vsp1_mod_write(&uds->entity, reg + uds->entity.index * VI6_UDS_OFFSET,
-		       data);
+	vsp1_dl_list_write(dl, reg + uds->entity.index * VI6_UDS_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
  * Scaling Computation
  */
 
-void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha)
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+			unsigned int alpha)
 {
-	vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
+	vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
 }
 
 /*
@@ -281,7 +283,7 @@ static struct v4l2_subdev_ops uds_ops = {
  * VSP1 Entity Operations
  */
 
-static void uds_configure(struct vsp1_entity *entity,
+static void uds_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_uds *uds = to_uds(&entity->subdev);
@@ -312,21 +314,21 @@ static void uds_configure(struct vsp1_entity *entity,
 	else
 		multitap = true;
 
-	vsp1_uds_write(uds, VI6_UDS_CTRL,
+	vsp1_uds_write(uds, dl, VI6_UDS_CTRL,
 		       (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
 		       (multitap ? VI6_UDS_CTRL_BC : 0));
 
-	vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
+	vsp1_uds_write(uds, dl, VI6_UDS_PASS_BWIDTH,
 		       (uds_passband_width(hscale)
 				<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
 		       (uds_passband_width(vscale)
 				<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
 
 	/* Set the scaling ratios and the output size. */
-	vsp1_uds_write(uds, VI6_UDS_SCALE,
+	vsp1_uds_write(uds, dl, VI6_UDS_SCALE,
 		       (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
 		       (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
-	vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
+	vsp1_uds_write(uds, dl, VI6_UDS_CLIP_SIZE,
 		       (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
 		       (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
 }
diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h
index 031ac0da1b66..5c8cbfcad4cc 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.h
+++ b/drivers/media/platform/vsp1/vsp1_uds.h
@@ -35,6 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
 
 struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index);
 
-void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha);
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl,
+			unsigned int alpha);
 
 #endif /* __VSP1_UDS_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 33a1a142002c..c30e29a4eb07 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -460,11 +460,11 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
 		struct vsp1_rwpf *rwpf = pipe->inputs[i];
 
 		if (rwpf)
-			vsp1_rwpf_set_memory(rwpf);
+			vsp1_rwpf_set_memory(rwpf, pipe->dl);
 	}
 
 	if (!pipe->lif)
-		vsp1_rwpf_set_memory(pipe->output);
+		vsp1_rwpf_set_memory(pipe->output, pipe->dl);
 
 	vsp1_dl_list_commit(pipe->dl);
 	pipe->dl = NULL;
@@ -625,15 +625,12 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
 	}
 
 	list_for_each_entry(entity, &pipe->entities, list_pipe) {
-		vsp1_entity_route_setup(entity);
+		vsp1_entity_route_setup(entity, pipe->dl);
 
 		if (entity->ops->configure)
-			entity->ops->configure(entity, NULL);
+			entity->ops->configure(entity, pipe->dl, NULL);
 	}
 
-	/* We know that the WPF s_stream operation never fails. */
-	v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 1);
-
 	return 0;
 }
 
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 417067f8aae3..24308b8de22d 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -27,10 +27,10 @@
  * Device Access
  */
 
-static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
+static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf,
+				  struct vsp1_dl_list *dl, u32 reg, u32 data)
 {
-	vsp1_mod_write(&wpf->entity,
-		       reg + wpf->entity.index * VI6_WPF_OFFSET, data);
+	vsp1_dl_list_write(dl, reg + wpf->entity.index * VI6_WPF_OFFSET, data);
 }
 
 /* -----------------------------------------------------------------------------
@@ -39,47 +39,18 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
 
 static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 {
-	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
 	struct vsp1_rwpf *wpf = to_rwpf(subdev);
 	struct vsp1_device *vsp1 = wpf->entity.vsp1;
-	unsigned int i;
-	u32 srcrpf = 0;
 
-	if (!enable) {
-		/* Write to registers directly when stopping the stream as there
-		 * will be no pipeline run to apply the display list.
-		 */
-		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
-		vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
-			   VI6_WPF_SRCRPF, 0);
+	if (enable)
 		return 0;
-	}
 
-	/* Sources. If the pipeline has a single input and BRU is not used,
-	 * configure it as the master layer. Otherwise configure all
-	 * inputs as sub-layers and select the virtual RPF as the master
-	 * layer.
+	/* Write to registers directly when stopping the stream as there
+	 * will be no pipeline run to apply the display list.
 	 */
-	for (i = 0; i < vsp1->info->rpf_count; ++i) {
-		struct vsp1_rwpf *input = pipe->inputs[i];
-
-		if (!input)
-			continue;
-
-		srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
-			? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
-			: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
-	}
-
-	if (pipe->bru || pipe->num_inputs > 1)
-		srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
-
-	vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
-
-	/* Enable interrupts */
-	vsp1_write(vsp1, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
-	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index),
-		   VI6_WFP_IRQ_ENB_FREE);
+	vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
+	vsp1_write(vsp1, wpf->entity.index * VI6_WPF_OFFSET +
+		   VI6_WPF_SRCRPF, 0);
 
 	return 0;
 }
@@ -108,35 +79,38 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
 	vsp1_dlm_destroy(wpf->dlm);
 }
 
-static void wpf_set_memory(struct vsp1_entity *entity)
+static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
 {
 	struct vsp1_rwpf *wpf = entity_to_rwpf(entity);
 
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
-	vsp1_wpf_write(wpf, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]);
 }
 
-static void wpf_configure(struct vsp1_entity *entity,
+static void wpf_configure(struct vsp1_entity *entity, struct vsp1_dl_list *dl,
 			  struct media_device_request *req)
 {
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
 	struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
+	struct vsp1_device *vsp1 = wpf->entity.vsp1;
 	struct v4l2_subdev_pad_config *config;
 	const struct v4l2_mbus_framefmt *source_format;
 	const struct v4l2_mbus_framefmt *sink_format;
 	const struct v4l2_rect *crop;
+	unsigned int i;
 	u32 outfmt = 0;
+	u32 srcrpf = 0;
 
 	config = vsp1_entity_get_req_pad_config(entity, req);
 
 	/* Cropping */
 	crop = vsp1_rwpf_get_crop(wpf, config);
 
-	vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
+	vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
-	vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
+	vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
 		       (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
 		       (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
@@ -163,25 +137,51 @@ static void wpf_configure(struct vsp1_entity *entity,
 			outfmt |= VI6_WPF_OUTFMT_SPUVS;
 
 		/* Destination stride and byte swapping. */
-		vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_Y,
+		vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_Y,
 			       format->plane_fmt[0].bytesperline);
 		if (format->num_planes > 1)
-			vsp1_wpf_write(wpf, VI6_WPF_DSTM_STRIDE_C,
+			vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_STRIDE_C,
 				       format->plane_fmt[1].bytesperline);
 
-		vsp1_wpf_write(wpf, VI6_WPF_DSWAP, fmtinfo->swap);
+		vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap);
 	}
 
 	if (sink_format->code != source_format->code)
 		outfmt |= VI6_WPF_OUTFMT_CSC;
 
 	outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT;
-	vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt);
+
+	vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+			   VI6_DPR_WPF_FPORCH_FP_WPFN);
+
+	vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0);
+
+	/* Sources. If the pipeline has a single input and BRU is not used,
+	 * configure it as the master layer. Otherwise configure all
+	 * inputs as sub-layers and select the virtual RPF as the master
+	 * layer.
+	 */
+	for (i = 0; i < vsp1->info->rpf_count; ++i) {
+		struct vsp1_rwpf *input = pipe->inputs[i];
 
-	vsp1_mod_write(&wpf->entity, VI6_DPR_WPF_FPORCH(wpf->entity.index),
-		       VI6_DPR_WPF_FPORCH_FP_WPFN);
+		if (!input)
+			continue;
+
+		srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
+			? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
+			: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
+	}
+
+	if (pipe->bru || pipe->num_inputs > 1)
+		srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
+
+	vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf);
 
-	vsp1_mod_write(&wpf->entity, VI6_WPF_WRBCK_CTRL, 0);
+	/* Enable interrupts */
+	vsp1_wpf_write(wpf, dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
+	vsp1_wpf_write(wpf, dl, VI6_WPF_IRQ_ENB(wpf->entity.index),
+		       VI6_WFP_IRQ_ENB_FREE);
 }
 
 static const struct vsp1_entity_operations wpf_entity_ops = {
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 48/48] v4l: vsp1: Support the request API
  2015-12-17  8:39 ` Laurent Pinchart
@ 2015-12-17  8:40   ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Implement the request API on top of display lists. Queueing a request
creates and queues a display list containing the pipeline configuration
for processing, allowing back-to-back operation without waiting for
frame processing completion before preparing the pipeline for the next
frame.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/Makefile       |   3 +-
 drivers/media/platform/vsp1/vsp1_dl.c      |   3 +
 drivers/media/platform/vsp1/vsp1_dl.h      |   1 +
 drivers/media/platform/vsp1/vsp1_drv.c     |   9 +++
 drivers/media/platform/vsp1/vsp1_pipe.c    |  71 ++++++++++++++++
 drivers/media/platform/vsp1/vsp1_pipe.h    |   7 ++
 drivers/media/platform/vsp1/vsp1_request.c | 126 +++++++++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_request.h |  41 ++++++++++
 drivers/media/platform/vsp1/vsp1_video.c   |  84 ++++++++-----------
 9 files changed, 295 insertions(+), 50 deletions(-)
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.c
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.h

diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile
index 95b3ac2ea7ef..5df1346290d6 100644
--- a/drivers/media/platform/vsp1/Makefile
+++ b/drivers/media/platform/vsp1/Makefile
@@ -1,5 +1,6 @@
 vsp1-y					:= vsp1_drv.o vsp1_entity.o vsp1_pipe.o
-vsp1-y					+= vsp1_dl.o vsp1_drm.o vsp1_video.o
+vsp1-y					+= vsp1_dl.o vsp1_request.o
+vsp1-y					+= vsp1_drm.o vsp1_video.o
 vsp1-y					+= vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
 vsp1-y					+= vsp1_hsit.o vsp1_lif.o vsp1_lut.o
 vsp1-y					+= vsp1_bru.o vsp1_sru.o vsp1_uds.o
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 43597b38a433..1181757d5081 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -15,9 +15,12 @@
 #include <linux/dma-mapping.h>
 #include <linux/gfp.h>
 
+#include <media/v4l2-device.h>
+
 #include "vsp1.h"
 #include "vsp1_dl.h"
 #include "vsp1_pipe.h"
+#include "vsp1_video.h"
 
 /*
  * Global resources
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 571ed6d8e7c2..bc77db7ad4d1 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -15,6 +15,7 @@
 
 #include <linux/types.h>
 
+struct v4l2_device;
 struct vsp1_device;
 struct vsp1_dl_list;
 struct vsp1_dl_manager;
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index e0bcc67e2d07..d8bc92b7d5de 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -30,6 +30,7 @@
 #include "vsp1_hsit.h"
 #include "vsp1_lif.h"
 #include "vsp1_lut.h"
+#include "vsp1_request.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_sru.h"
 #include "vsp1_uds.h"
@@ -210,6 +211,12 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1)
 		vsp1_drm_cleanup(vsp1);
 }
 
+static const struct media_device_ops vsp1_media_device_ops = {
+	.req_alloc = vsp1_request_alloc,
+	.req_free = vsp1_request_free,
+	.req_queue = vsp1_request_queue,
+};
+
 static int vsp1_create_entities(struct vsp1_device *vsp1)
 {
 	struct media_device *mdev = &vsp1->media_dev;
@@ -219,6 +226,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 	int ret;
 
 	mdev->dev = vsp1->dev;
+	mdev->ops = &vsp1_media_device_ops;
 	strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
 	snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
 		 dev_name(mdev->dev));
@@ -238,6 +246,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 		vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
 
 	vdev->mdev = mdev;
+
 	ret = v4l2_device_register(vsp1->dev, vdev);
 	if (ret < 0) {
 		dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 38157a2e4cbc..b055b963e567 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -23,8 +23,10 @@
 #include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
+#include "vsp1_request.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_uds.h"
+#include "vsp1_video.h"
 
 /* -----------------------------------------------------------------------------
  * Helper Functions
@@ -136,6 +138,40 @@ const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc)
 	return NULL;
 }
 
+
+/* -----------------------------------------------------------------------------
+ * Requests Management
+ */
+
+void vsp1_pipeline_queue_request(struct vsp1_pipeline *pipe,
+				 struct vsp1_request *req)
+{
+	struct vsp1_video *video;
+	unsigned long flags;
+	unsigned int i;
+
+	media_device_request_get(&req->req);
+
+	spin_lock_irqsave(&pipe->irqlock, flags);
+	list_add_tail(&req->list, &pipe->requests);
+	spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+	for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
+		if (!pipe->inputs[i])
+			continue;
+
+		video = pipe->inputs[i]->video;
+		mutex_lock(&video->lock);
+		vb2_qbuf_request(&video->queue, req->req.id, NULL);
+		mutex_unlock(&video->lock);
+	}
+
+	video = pipe->output->video;
+	mutex_lock(&video->lock);
+	vb2_qbuf_request(&video->queue, req->req.id, NULL);
+	mutex_unlock(&video->lock);
+}
+
 /* -----------------------------------------------------------------------------
  * Pipeline Management
  */
@@ -155,6 +191,7 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
 		pipe->inputs[i] = NULL;
 
 	INIT_LIST_HEAD(&pipe->entities);
+	INIT_LIST_HEAD(&pipe->requests);
 	pipe->state = VSP1_PIPELINE_STOPPED;
 	pipe->buffers_ready = 0;
 	pipe->num_inputs = 0;
@@ -171,6 +208,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
 	init_waitqueue_head(&pipe->wq);
 
 	INIT_LIST_HEAD(&pipe->entities);
+	INIT_LIST_HEAD(&pipe->requests);
 	pipe->state = VSP1_PIPELINE_STOPPED;
 }
 
@@ -250,6 +288,39 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 	return pipe->buffers_ready = mask;
 }
 
+void vsp1_pipeline_setup(struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl,
+			 struct media_device_request *req)
+{
+	struct vsp1_entity *entity;
+
+	if (pipe->uds) {
+		struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
+
+		/* If a BRU is present in the pipeline before the UDS, the alpha
+		 * component doesn't need to be scaled as the BRU output alpha
+		 * value is fixed to 255. Otherwise we need to scale the alpha
+		 * component only when available at the input RPF.
+		 */
+		if (pipe->uds_input->type = VSP1_ENTITY_BRU) {
+			uds->scale_alpha = false;
+		} else {
+			const struct vsp1_format_info *info;
+			struct vsp1_rwpf *rpf +				to_rwpf(&pipe->uds_input->subdev);
+
+			info = vsp1_get_format_info(rpf->format.pixelformat);
+			uds->scale_alpha = info->alpha;
+		}
+	}
+
+	list_for_each_entry(entity, &pipe->entities, list_pipe) {
+		vsp1_entity_route_setup(entity, dl);
+
+		if (entity->ops->configure)
+			entity->ops->configure(entity, dl, req);
+	}
+}
+
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
 	if (pipe = NULL)
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index 1100229a1ed2..a26e4a7ae67d 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -20,6 +20,7 @@
 #include <media/media-entity.h>
 
 struct vsp1_dl_list;
+struct vsp1_request;
 struct vsp1_rwpf;
 
 /*
@@ -74,6 +75,7 @@ enum vsp1_pipeline_state {
  * @uds: UDS entity, if present
  * @uds_input: entity at the input of the UDS, if the UDS is present
  * @entities: list of entities in the pipeline
+ * @requests: list of pending requests
  * @dl: display list associated with the pipeline
  */
 struct vsp1_pipeline {
@@ -100,6 +102,7 @@ struct vsp1_pipeline {
 
 	struct list_head entities;
 
+	struct list_head requests;
 	struct vsp1_dl_list *dl;
 };
 
@@ -118,6 +121,10 @@ void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
+void vsp1_pipeline_setup(struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl,
+			 struct media_device_request *req);
+void vsp1_pipeline_queue_request(struct vsp1_pipeline *pipe,
+				 struct vsp1_request *req);
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
diff --git a/drivers/media/platform/vsp1/vsp1_request.c b/drivers/media/platform/vsp1/vsp1_request.c
new file mode 100644
index 000000000000..d78289f18fc0
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_request.c
@@ -0,0 +1,126 @@
+/*
+ * vsp1_request.c  --  R-Car VSP1 Request Management
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_dl.h"
+#include "vsp1_entity.h"
+#include "vsp1_pipe.h"
+#include "vsp1_request.h"
+#include "vsp1_rwpf.h"
+#include "vsp1_video.h"
+
+struct media_device_request *vsp1_request_alloc(struct media_device *mdev)
+{
+	struct vsp1_request *req;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return NULL;
+
+	return &req->req;
+}
+
+void vsp1_request_free(struct media_device *mdev,
+		       struct media_device_request *mreq)
+{
+	struct vsp1_request *req = to_vsp1_request(mreq);
+
+	kfree(req);
+}
+
+int vsp1_request_queue(struct media_device *mdev,
+		       struct media_device_request *mreq)
+{
+	struct vsp1_device *vsp1 +		container_of(mdev, struct vsp1_device, media_dev);
+	struct vsp1_request *req = to_vsp1_request(mreq);
+	struct vsp1_video *output = NULL;
+	struct vsp1_pipeline *pipe;
+	struct vsp1_video *video;
+	bool has_request;
+	unsigned int i;
+
+	/* 1. Find the capture video node for which a buffer corresponding to
+	 * the request has been prepared. This will be our main entry point to
+	 * the pipeline.
+	 *
+	 * TODO: Fix race condition. There would be no need to lock the list
+	 * walk as we don't add or remove video nodes at runtime. However, the
+	 * media device is registered before the video nodes, so userspace could
+	 * call us at probe time before all video nodes are registered.
+	 */
+	for (i = 0; i < ARRAY_SIZE(vsp1->wpf); ++i) {
+		if (!vsp1->wpf[i])
+			continue;
+
+		video = vsp1->wpf[i]->video;
+
+		if (mutex_lock_interruptible(&video->lock))
+			return -ERESTARTSYS;
+		has_request = vb2_is_streaming(&video->queue) &&
+			      vb2_queue_has_request(&video->queue, mreq->id);
+		mutex_unlock(&video->lock);
+
+		if (has_request) {
+			/* A pipeline has a single output. */
+			if (output)
+				return -EINVAL;
+			output = video;
+		}
+	}
+
+	if (!output)
+		return -EINVAL;
+
+	/* 2. Validate the pipeline. Verify streaming state, buffers and
+	 * formats.
+	 */
+	pipe = to_vsp1_pipeline(&output->video.entity);
+	if (!pipe)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
+		if (!pipe->inputs[i])
+			continue;
+
+		video = pipe->inputs[i]->video;
+
+		if (mutex_lock_interruptible(&video->lock))
+			return -ERESTARTSYS;
+		has_request = vb2_is_streaming(&video->queue) &&
+			      vb2_queue_has_request(&video->queue, mreq->id);
+		mutex_unlock(&video->lock);
+
+		if (!has_request)
+			return -EINVAL;
+	}
+
+	/* 3. Allocate and fill the display list. */
+	req->dl = vsp1_dl_list_get(pipe->output->dlm);
+	if (!req->dl)
+		return -ENOMEM;
+
+	vsp1_pipeline_setup(pipe, req->dl, mreq);
+
+	/* 3. Queue the request. */
+	vsp1_pipeline_queue_request(pipe, req);
+
+	return 0;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_request.h b/drivers/media/platform/vsp1/vsp1_request.h
new file mode 100644
index 000000000000..7cde04f86669
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_request.h
@@ -0,0 +1,41 @@
+/*
+ * vsp1_request.h  --  R-Car VSP1 Request Management
+ *
+ * Copyright (C) 2015 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __VSP1_REQUEST_H__
+#define __VSP1_REQUEST_H__
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct media_device;
+struct media_device_request;
+struct vsp1_dl_list;
+
+struct vsp1_request {
+	struct media_device_request req;
+	struct vsp1_dl_list *dl;
+	struct list_head list;
+};
+
+static inline struct vsp1_request *
+to_vsp1_request(struct media_device_request *req)
+{
+	return container_of(req, struct vsp1_request, req);
+}
+
+struct media_device_request *vsp1_request_alloc(struct media_device *mdev);
+void vsp1_request_free(struct media_device *mdev,
+		       struct media_device_request *req);
+int vsp1_request_queue(struct media_device *mdev,
+		       struct media_device_request *req);
+
+#endif /* __VSP1_REQUEST_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index c30e29a4eb07..10bd0c0a2d94 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -32,6 +32,7 @@
 #include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
+#include "vsp1_request.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_uds.h"
 #include "vsp1_video.h"
@@ -451,23 +452,44 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
 static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	struct vsp1_dl_list *dl;
 	unsigned int i;
 
-	if (!pipe->dl)
-		pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+	/* Get the display list from first available location:
+	 *
+	 * - the next request (when the request API is in use)
+	 * - the pipeline if set (for the first run after streamon)
+	 * - the request pool (for subsequent runs)
+	 */
+	dl = pipe->dl;
+	pipe->dl = NULL;
+
+	if (!list_empty(&pipe->requests)) {
+		struct vsp1_request *req;
+
+		req = list_first_entry(&pipe->requests, typeof(*req), list);
+		list_del(&req->list);
+
+		vsp1_dl_list_put(dl);
+		dl = req->dl;
+		media_device_request_put(&req->req);
+
+	}
+
+	if (!dl)
+		dl = vsp1_dl_list_get(pipe->output->dlm);
 
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
 		struct vsp1_rwpf *rwpf = pipe->inputs[i];
 
 		if (rwpf)
-			vsp1_rwpf_set_memory(rwpf, pipe->dl);
+			vsp1_rwpf_set_memory(rwpf, dl);
 	}
 
 	if (!pipe->lif)
-		vsp1_rwpf_set_memory(pipe->output, pipe->dl);
+		vsp1_rwpf_set_memory(pipe->output, dl);
 
-	vsp1_dl_list_commit(pipe->dl);
-	pipe->dl = NULL;
+	vsp1_dl_list_commit(dl);
 
 	vsp1_pipeline_run(pipe);
 }
@@ -595,59 +617,22 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
-{
-	struct vsp1_entity *entity;
-
-	/* Prepare the display list. */
-	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-	if (!pipe->dl)
-		return -ENOMEM;
-
-	if (pipe->uds) {
-		struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
-
-		/* If a BRU is present in the pipeline before the UDS, the alpha
-		 * component doesn't need to be scaled as the BRU output alpha
-		 * value is fixed to 255. Otherwise we need to scale the alpha
-		 * component only when available at the input RPF.
-		 */
-		if (pipe->uds_input->type = VSP1_ENTITY_BRU) {
-			uds->scale_alpha = false;
-		} else {
-			const struct vsp1_format_info *info;
-			struct vsp1_rwpf *rpf -				to_rwpf(&pipe->uds_input->subdev);
-
-			info = vsp1_get_format_info(rpf->format.pixelformat);
-			uds->scale_alpha = info->alpha;
-		}
-	}
-
-	list_for_each_entry(entity, &pipe->entities, list_pipe) {
-		vsp1_entity_route_setup(entity, pipe->dl);
-
-		if (entity->ops->configure)
-			entity->ops->configure(entity, pipe->dl, NULL);
-	}
-
-	return 0;
-}
-
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct vsp1_video *video = vb2_get_drv_priv(vq);
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
 	unsigned long flags;
-	int ret;
 
 	mutex_lock(&pipe->lock);
 	if (pipe->stream_count = pipe->num_inputs) {
-		ret = vsp1_video_setup_pipeline(pipe);
-		if (ret < 0) {
+		/* Prepare the display list. */
+		pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+		if (!pipe->dl) {
 			mutex_unlock(&pipe->lock);
-			return ret;
+			return -ENOMEM;
 		}
+
+		vsp1_pipeline_setup(pipe, pipe->dl, NULL);
 	}
 
 	pipe->stream_count++;
@@ -993,6 +978,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 	video->queue.ops = &vsp1_video_queue_qops;
 	video->queue.mem_ops = &vb2_dma_contig_memops;
 	video->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	video->queue.allow_requests = true;
 	ret = vb2_queue_init(&video->queue);
 	if (ret < 0) {
 		dev_err(video->vsp1->dev, "failed to initialize vb2 queue\n");
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* [PATCH/RFC 48/48] v4l: vsp1: Support the request API
@ 2015-12-17  8:40   ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-17  8:40 UTC (permalink / raw)
  To: linux-media; +Cc: linux-sh

Implement the request API on top of display lists. Queueing a request
creates and queues a display list containing the pipeline configuration
for processing, allowing back-to-back operation without waiting for
frame processing completion before preparing the pipeline for the next
frame.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/media/platform/vsp1/Makefile       |   3 +-
 drivers/media/platform/vsp1/vsp1_dl.c      |   3 +
 drivers/media/platform/vsp1/vsp1_dl.h      |   1 +
 drivers/media/platform/vsp1/vsp1_drv.c     |   9 +++
 drivers/media/platform/vsp1/vsp1_pipe.c    |  71 ++++++++++++++++
 drivers/media/platform/vsp1/vsp1_pipe.h    |   7 ++
 drivers/media/platform/vsp1/vsp1_request.c | 126 +++++++++++++++++++++++++++++
 drivers/media/platform/vsp1/vsp1_request.h |  41 ++++++++++
 drivers/media/platform/vsp1/vsp1_video.c   |  84 ++++++++-----------
 9 files changed, 295 insertions(+), 50 deletions(-)
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.c
 create mode 100644 drivers/media/platform/vsp1/vsp1_request.h

diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile
index 95b3ac2ea7ef..5df1346290d6 100644
--- a/drivers/media/platform/vsp1/Makefile
+++ b/drivers/media/platform/vsp1/Makefile
@@ -1,5 +1,6 @@
 vsp1-y					:= vsp1_drv.o vsp1_entity.o vsp1_pipe.o
-vsp1-y					+= vsp1_dl.o vsp1_drm.o vsp1_video.o
+vsp1-y					+= vsp1_dl.o vsp1_request.o
+vsp1-y					+= vsp1_drm.o vsp1_video.o
 vsp1-y					+= vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
 vsp1-y					+= vsp1_hsit.o vsp1_lif.o vsp1_lut.o
 vsp1-y					+= vsp1_bru.o vsp1_sru.o vsp1_uds.o
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 43597b38a433..1181757d5081 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -15,9 +15,12 @@
 #include <linux/dma-mapping.h>
 #include <linux/gfp.h>
 
+#include <media/v4l2-device.h>
+
 #include "vsp1.h"
 #include "vsp1_dl.h"
 #include "vsp1_pipe.h"
+#include "vsp1_video.h"
 
 /*
  * Global resources
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 571ed6d8e7c2..bc77db7ad4d1 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -15,6 +15,7 @@
 
 #include <linux/types.h>
 
+struct v4l2_device;
 struct vsp1_device;
 struct vsp1_dl_list;
 struct vsp1_dl_manager;
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index e0bcc67e2d07..d8bc92b7d5de 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -30,6 +30,7 @@
 #include "vsp1_hsit.h"
 #include "vsp1_lif.h"
 #include "vsp1_lut.h"
+#include "vsp1_request.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_sru.h"
 #include "vsp1_uds.h"
@@ -210,6 +211,12 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1)
 		vsp1_drm_cleanup(vsp1);
 }
 
+static const struct media_device_ops vsp1_media_device_ops = {
+	.req_alloc = vsp1_request_alloc,
+	.req_free = vsp1_request_free,
+	.req_queue = vsp1_request_queue,
+};
+
 static int vsp1_create_entities(struct vsp1_device *vsp1)
 {
 	struct media_device *mdev = &vsp1->media_dev;
@@ -219,6 +226,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 	int ret;
 
 	mdev->dev = vsp1->dev;
+	mdev->ops = &vsp1_media_device_ops;
 	strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
 	snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
 		 dev_name(mdev->dev));
@@ -238,6 +246,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 		vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
 
 	vdev->mdev = mdev;
+
 	ret = v4l2_device_register(vsp1->dev, vdev);
 	if (ret < 0) {
 		dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 38157a2e4cbc..b055b963e567 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -23,8 +23,10 @@
 #include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
+#include "vsp1_request.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_uds.h"
+#include "vsp1_video.h"
 
 /* -----------------------------------------------------------------------------
  * Helper Functions
@@ -136,6 +138,40 @@ const struct vsp1_format_info *vsp1_get_format_info(u32 fourcc)
 	return NULL;
 }
 
+
+/* -----------------------------------------------------------------------------
+ * Requests Management
+ */
+
+void vsp1_pipeline_queue_request(struct vsp1_pipeline *pipe,
+				 struct vsp1_request *req)
+{
+	struct vsp1_video *video;
+	unsigned long flags;
+	unsigned int i;
+
+	media_device_request_get(&req->req);
+
+	spin_lock_irqsave(&pipe->irqlock, flags);
+	list_add_tail(&req->list, &pipe->requests);
+	spin_unlock_irqrestore(&pipe->irqlock, flags);
+
+	for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
+		if (!pipe->inputs[i])
+			continue;
+
+		video = pipe->inputs[i]->video;
+		mutex_lock(&video->lock);
+		vb2_qbuf_request(&video->queue, req->req.id, NULL);
+		mutex_unlock(&video->lock);
+	}
+
+	video = pipe->output->video;
+	mutex_lock(&video->lock);
+	vb2_qbuf_request(&video->queue, req->req.id, NULL);
+	mutex_unlock(&video->lock);
+}
+
 /* -----------------------------------------------------------------------------
  * Pipeline Management
  */
@@ -155,6 +191,7 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
 		pipe->inputs[i] = NULL;
 
 	INIT_LIST_HEAD(&pipe->entities);
+	INIT_LIST_HEAD(&pipe->requests);
 	pipe->state = VSP1_PIPELINE_STOPPED;
 	pipe->buffers_ready = 0;
 	pipe->num_inputs = 0;
@@ -171,6 +208,7 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
 	init_waitqueue_head(&pipe->wq);
 
 	INIT_LIST_HEAD(&pipe->entities);
+	INIT_LIST_HEAD(&pipe->requests);
 	pipe->state = VSP1_PIPELINE_STOPPED;
 }
 
@@ -250,6 +288,39 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
 	return pipe->buffers_ready == mask;
 }
 
+void vsp1_pipeline_setup(struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl,
+			 struct media_device_request *req)
+{
+	struct vsp1_entity *entity;
+
+	if (pipe->uds) {
+		struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
+
+		/* If a BRU is present in the pipeline before the UDS, the alpha
+		 * component doesn't need to be scaled as the BRU output alpha
+		 * value is fixed to 255. Otherwise we need to scale the alpha
+		 * component only when available at the input RPF.
+		 */
+		if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+			uds->scale_alpha = false;
+		} else {
+			const struct vsp1_format_info *info;
+			struct vsp1_rwpf *rpf =
+				to_rwpf(&pipe->uds_input->subdev);
+
+			info = vsp1_get_format_info(rpf->format.pixelformat);
+			uds->scale_alpha = info->alpha;
+		}
+	}
+
+	list_for_each_entry(entity, &pipe->entities, list_pipe) {
+		vsp1_entity_route_setup(entity, dl);
+
+		if (entity->ops->configure)
+			entity->ops->configure(entity, dl, req);
+	}
+}
+
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
 {
 	if (pipe == NULL)
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index 1100229a1ed2..a26e4a7ae67d 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -20,6 +20,7 @@
 #include <media/media-entity.h>
 
 struct vsp1_dl_list;
+struct vsp1_request;
 struct vsp1_rwpf;
 
 /*
@@ -74,6 +75,7 @@ enum vsp1_pipeline_state {
  * @uds: UDS entity, if present
  * @uds_input: entity at the input of the UDS, if the UDS is present
  * @entities: list of entities in the pipeline
+ * @requests: list of pending requests
  * @dl: display list associated with the pipeline
  */
 struct vsp1_pipeline {
@@ -100,6 +102,7 @@ struct vsp1_pipeline {
 
 	struct list_head entities;
 
+	struct list_head requests;
 	struct vsp1_dl_list *dl;
 };
 
@@ -118,6 +121,10 @@ void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);
+void vsp1_pipeline_setup(struct vsp1_pipeline *pipe, struct vsp1_dl_list *dl,
+			 struct media_device_request *req);
+void vsp1_pipeline_queue_request(struct vsp1_pipeline *pipe,
+				 struct vsp1_request *req);
 
 void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
 
diff --git a/drivers/media/platform/vsp1/vsp1_request.c b/drivers/media/platform/vsp1/vsp1_request.c
new file mode 100644
index 000000000000..d78289f18fc0
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_request.c
@@ -0,0 +1,126 @@
+/*
+ * vsp1_request.c  --  R-Car VSP1 Request Management
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_dl.h"
+#include "vsp1_entity.h"
+#include "vsp1_pipe.h"
+#include "vsp1_request.h"
+#include "vsp1_rwpf.h"
+#include "vsp1_video.h"
+
+struct media_device_request *vsp1_request_alloc(struct media_device *mdev)
+{
+	struct vsp1_request *req;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return NULL;
+
+	return &req->req;
+}
+
+void vsp1_request_free(struct media_device *mdev,
+		       struct media_device_request *mreq)
+{
+	struct vsp1_request *req = to_vsp1_request(mreq);
+
+	kfree(req);
+}
+
+int vsp1_request_queue(struct media_device *mdev,
+		       struct media_device_request *mreq)
+{
+	struct vsp1_device *vsp1 =
+		container_of(mdev, struct vsp1_device, media_dev);
+	struct vsp1_request *req = to_vsp1_request(mreq);
+	struct vsp1_video *output = NULL;
+	struct vsp1_pipeline *pipe;
+	struct vsp1_video *video;
+	bool has_request;
+	unsigned int i;
+
+	/* 1. Find the capture video node for which a buffer corresponding to
+	 * the request has been prepared. This will be our main entry point to
+	 * the pipeline.
+	 *
+	 * TODO: Fix race condition. There would be no need to lock the list
+	 * walk as we don't add or remove video nodes at runtime. However, the
+	 * media device is registered before the video nodes, so userspace could
+	 * call us at probe time before all video nodes are registered.
+	 */
+	for (i = 0; i < ARRAY_SIZE(vsp1->wpf); ++i) {
+		if (!vsp1->wpf[i])
+			continue;
+
+		video = vsp1->wpf[i]->video;
+
+		if (mutex_lock_interruptible(&video->lock))
+			return -ERESTARTSYS;
+		has_request = vb2_is_streaming(&video->queue) &&
+			      vb2_queue_has_request(&video->queue, mreq->id);
+		mutex_unlock(&video->lock);
+
+		if (has_request) {
+			/* A pipeline has a single output. */
+			if (output)
+				return -EINVAL;
+			output = video;
+		}
+	}
+
+	if (!output)
+		return -EINVAL;
+
+	/* 2. Validate the pipeline. Verify streaming state, buffers and
+	 * formats.
+	 */
+	pipe = to_vsp1_pipeline(&output->video.entity);
+	if (!pipe)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
+		if (!pipe->inputs[i])
+			continue;
+
+		video = pipe->inputs[i]->video;
+
+		if (mutex_lock_interruptible(&video->lock))
+			return -ERESTARTSYS;
+		has_request = vb2_is_streaming(&video->queue) &&
+			      vb2_queue_has_request(&video->queue, mreq->id);
+		mutex_unlock(&video->lock);
+
+		if (!has_request)
+			return -EINVAL;
+	}
+
+	/* 3. Allocate and fill the display list. */
+	req->dl = vsp1_dl_list_get(pipe->output->dlm);
+	if (!req->dl)
+		return -ENOMEM;
+
+	vsp1_pipeline_setup(pipe, req->dl, mreq);
+
+	/* 3. Queue the request. */
+	vsp1_pipeline_queue_request(pipe, req);
+
+	return 0;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_request.h b/drivers/media/platform/vsp1/vsp1_request.h
new file mode 100644
index 000000000000..7cde04f86669
--- /dev/null
+++ b/drivers/media/platform/vsp1/vsp1_request.h
@@ -0,0 +1,41 @@
+/*
+ * vsp1_request.h  --  R-Car VSP1 Request Management
+ *
+ * Copyright (C) 2015 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __VSP1_REQUEST_H__
+#define __VSP1_REQUEST_H__
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct media_device;
+struct media_device_request;
+struct vsp1_dl_list;
+
+struct vsp1_request {
+	struct media_device_request req;
+	struct vsp1_dl_list *dl;
+	struct list_head list;
+};
+
+static inline struct vsp1_request *
+to_vsp1_request(struct media_device_request *req)
+{
+	return container_of(req, struct vsp1_request, req);
+}
+
+struct media_device_request *vsp1_request_alloc(struct media_device *mdev);
+void vsp1_request_free(struct media_device *mdev,
+		       struct media_device_request *req);
+int vsp1_request_queue(struct media_device *mdev,
+		       struct media_device_request *req);
+
+#endif /* __VSP1_REQUEST_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index c30e29a4eb07..10bd0c0a2d94 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -32,6 +32,7 @@
 #include "vsp1_dl.h"
 #include "vsp1_entity.h"
 #include "vsp1_pipe.h"
+#include "vsp1_request.h"
 #include "vsp1_rwpf.h"
 #include "vsp1_uds.h"
 #include "vsp1_video.h"
@@ -451,23 +452,44 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
 static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	struct vsp1_dl_list *dl;
 	unsigned int i;
 
-	if (!pipe->dl)
-		pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+	/* Get the display list from first available location:
+	 *
+	 * - the next request (when the request API is in use)
+	 * - the pipeline if set (for the first run after streamon)
+	 * - the request pool (for subsequent runs)
+	 */
+	dl = pipe->dl;
+	pipe->dl = NULL;
+
+	if (!list_empty(&pipe->requests)) {
+		struct vsp1_request *req;
+
+		req = list_first_entry(&pipe->requests, typeof(*req), list);
+		list_del(&req->list);
+
+		vsp1_dl_list_put(dl);
+		dl = req->dl;
+		media_device_request_put(&req->req);
+
+	}
+
+	if (!dl)
+		dl = vsp1_dl_list_get(pipe->output->dlm);
 
 	for (i = 0; i < vsp1->info->rpf_count; ++i) {
 		struct vsp1_rwpf *rwpf = pipe->inputs[i];
 
 		if (rwpf)
-			vsp1_rwpf_set_memory(rwpf, pipe->dl);
+			vsp1_rwpf_set_memory(rwpf, dl);
 	}
 
 	if (!pipe->lif)
-		vsp1_rwpf_set_memory(pipe->output, pipe->dl);
+		vsp1_rwpf_set_memory(pipe->output, dl);
 
-	vsp1_dl_list_commit(pipe->dl);
-	pipe->dl = NULL;
+	vsp1_dl_list_commit(dl);
 
 	vsp1_pipeline_run(pipe);
 }
@@ -595,59 +617,22 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 }
 
-static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
-{
-	struct vsp1_entity *entity;
-
-	/* Prepare the display list. */
-	pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
-	if (!pipe->dl)
-		return -ENOMEM;
-
-	if (pipe->uds) {
-		struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
-
-		/* If a BRU is present in the pipeline before the UDS, the alpha
-		 * component doesn't need to be scaled as the BRU output alpha
-		 * value is fixed to 255. Otherwise we need to scale the alpha
-		 * component only when available at the input RPF.
-		 */
-		if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
-			uds->scale_alpha = false;
-		} else {
-			const struct vsp1_format_info *info;
-			struct vsp1_rwpf *rpf =
-				to_rwpf(&pipe->uds_input->subdev);
-
-			info = vsp1_get_format_info(rpf->format.pixelformat);
-			uds->scale_alpha = info->alpha;
-		}
-	}
-
-	list_for_each_entry(entity, &pipe->entities, list_pipe) {
-		vsp1_entity_route_setup(entity, pipe->dl);
-
-		if (entity->ops->configure)
-			entity->ops->configure(entity, pipe->dl, NULL);
-	}
-
-	return 0;
-}
-
 static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct vsp1_video *video = vb2_get_drv_priv(vq);
 	struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
 	unsigned long flags;
-	int ret;
 
 	mutex_lock(&pipe->lock);
 	if (pipe->stream_count == pipe->num_inputs) {
-		ret = vsp1_video_setup_pipeline(pipe);
-		if (ret < 0) {
+		/* Prepare the display list. */
+		pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
+		if (!pipe->dl) {
 			mutex_unlock(&pipe->lock);
-			return ret;
+			return -ENOMEM;
 		}
+
+		vsp1_pipeline_setup(pipe, pipe->dl, NULL);
 	}
 
 	pipe->stream_count++;
@@ -993,6 +978,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 	video->queue.ops = &vsp1_video_queue_qops;
 	video->queue.mem_ops = &vb2_dma_contig_memops;
 	video->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	video->queue.allow_requests = true;
 	ret = vb2_queue_init(&video->queue);
 	if (ret < 0) {
 		dev_err(video->vsp1->dev, "failed to initialize vb2 queue\n");
-- 
2.4.10


^ permalink raw reply related	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
  2015-12-17  8:40   ` Laurent Pinchart
@ 2015-12-18 11:18     ` Hans Verkuil
  -1 siblings, 0 replies; 114+ messages in thread
From: Hans Verkuil @ 2015-12-18 11:18 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media; +Cc: linux-sh

Hi Laurent,

On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> Let userspace specify a request ID when getting or setting formats. The
> support is limited to the multi-planar API at the moment, extending it
> to the single-planar API is possible if needed.
> 
> From a userspace point of view the API change is also minimized and
> doesn't require any new ioctl.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  include/uapi/linux/videodev2.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 5af1d2d87558..5b2a8bc80eb2 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1973,6 +1973,7 @@ struct v4l2_plane_pix_format {
>   * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
>   * @quantization:	enum v4l2_quantization, colorspace quantization
>   * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
> + * @request:		request ID
>   */
>  struct v4l2_pix_format_mplane {
>  	__u32				width;
> @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
>  	__u8				ycbcr_enc;
>  	__u8				quantization;
>  	__u8				xfer_func;
> -	__u8				reserved[7];
> +	__u8				reserved[3];
> +	__u32				request;

I think I mentioned this before: I feel uncomfortable using 4 bytes of the reserved
fields when the request ID is limited to 16 bits anyway.

I would prefer a __u16 here. Also put the request field *before* the reserved
array, not after.

Regards,

	Hans

>  } __attribute__ ((packed));
>  
>  /**
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
@ 2015-12-18 11:18     ` Hans Verkuil
  0 siblings, 0 replies; 114+ messages in thread
From: Hans Verkuil @ 2015-12-18 11:18 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media; +Cc: linux-sh

Hi Laurent,

On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> Let userspace specify a request ID when getting or setting formats. The
> support is limited to the multi-planar API at the moment, extending it
> to the single-planar API is possible if needed.
> 
> From a userspace point of view the API change is also minimized and
> doesn't require any new ioctl.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  include/uapi/linux/videodev2.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 5af1d2d87558..5b2a8bc80eb2 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1973,6 +1973,7 @@ struct v4l2_plane_pix_format {
>   * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
>   * @quantization:	enum v4l2_quantization, colorspace quantization
>   * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
> + * @request:		request ID
>   */
>  struct v4l2_pix_format_mplane {
>  	__u32				width;
> @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
>  	__u8				ycbcr_enc;
>  	__u8				quantization;
>  	__u8				xfer_func;
> -	__u8				reserved[7];
> +	__u8				reserved[3];
> +	__u32				request;

I think I mentioned this before: I feel uncomfortable using 4 bytes of the reserved
fields when the request ID is limited to 16 bits anyway.

I would prefer a __u16 here. Also put the request field *before* the reserved
array, not after.

Regards,

	Hans

>  } __attribute__ ((packed));
>  
>  /**
> 

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures
  2015-12-17  8:40   ` Laurent Pinchart
@ 2015-12-18 11:20     ` Hans Verkuil
  -1 siblings, 0 replies; 114+ messages in thread
From: Hans Verkuil @ 2015-12-18 11:20 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media; +Cc: linux-sh



On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> Let userspace specify a request ID when getting or setting formats or
> selection rectangles.
> 
> From a userspace point of view the API change is minimized and doesn't
> require any new ioctl.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  include/uapi/linux/v4l2-subdev.h | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index dbce2b554e02..2f1691ce9df5 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -32,10 +32,12 @@
>   * enum v4l2_subdev_format_whence - Media bus format type
>   * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
>   * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
> + * @V4L2_SUBDEV_FORMAT_REQUEST: format stored in request
>   */
>  enum v4l2_subdev_format_whence {
>  	V4L2_SUBDEV_FORMAT_TRY = 0,
>  	V4L2_SUBDEV_FORMAT_ACTIVE = 1,
> +	V4L2_SUBDEV_FORMAT_REQUEST = 2,
>  };
>  
>  /**
> @@ -43,12 +45,17 @@ enum v4l2_subdev_format_whence {
>   * @which: format type (from enum v4l2_subdev_format_whence)
>   * @pad: pad number, as reported by the media API
>   * @format: media bus format (format code and frame size)
> + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> + * @reserved2: for future use, set to zero for now
> + * @reserved: for future use, set to zero for now
>   */
>  struct v4l2_subdev_format {
>  	__u32 which;
>  	__u32 pad;
>  	struct v4l2_mbus_framefmt format;
> -	__u32 reserved[8];
> +	__u16 request;
> +	__u16 reserved2;
> +	__u32 reserved[7];

I would prefer:

	__u16 request;
	__u16 reserved[15];

>  };
>  
>  /**
> @@ -139,6 +146,8 @@ struct v4l2_subdev_frame_interval_enum {
>   *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
>   * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
>   * @r: coordinates of the selection window
> + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> + * @reserved2: for future use, set to zero for now
>   * @reserved: for future use, set to zero for now
>   *
>   * Hardware may use multiple helper windows to process a video stream.
> @@ -151,7 +160,9 @@ struct v4l2_subdev_selection {
>  	__u32 target;
>  	__u32 flags;
>  	struct v4l2_rect r;
> -	__u32 reserved[8];
> +	__u16 request;
> +	__u16 reserved2;
> +	__u32 reserved[7];

Ditto.

Generally apps do a memset of reserved, and that will just keep working.
But adding a reserved2 field means that they have to explicitly set reserved2
to 0, which won't happen.

>  };
>  
>  /* Backwards compatibility define --- to be removed */
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures
@ 2015-12-18 11:20     ` Hans Verkuil
  0 siblings, 0 replies; 114+ messages in thread
From: Hans Verkuil @ 2015-12-18 11:20 UTC (permalink / raw)
  To: Laurent Pinchart, linux-media; +Cc: linux-sh



On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> Let userspace specify a request ID when getting or setting formats or
> selection rectangles.
> 
> From a userspace point of view the API change is minimized and doesn't
> require any new ioctl.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  include/uapi/linux/v4l2-subdev.h | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index dbce2b554e02..2f1691ce9df5 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -32,10 +32,12 @@
>   * enum v4l2_subdev_format_whence - Media bus format type
>   * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
>   * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
> + * @V4L2_SUBDEV_FORMAT_REQUEST: format stored in request
>   */
>  enum v4l2_subdev_format_whence {
>  	V4L2_SUBDEV_FORMAT_TRY = 0,
>  	V4L2_SUBDEV_FORMAT_ACTIVE = 1,
> +	V4L2_SUBDEV_FORMAT_REQUEST = 2,
>  };
>  
>  /**
> @@ -43,12 +45,17 @@ enum v4l2_subdev_format_whence {
>   * @which: format type (from enum v4l2_subdev_format_whence)
>   * @pad: pad number, as reported by the media API
>   * @format: media bus format (format code and frame size)
> + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> + * @reserved2: for future use, set to zero for now
> + * @reserved: for future use, set to zero for now
>   */
>  struct v4l2_subdev_format {
>  	__u32 which;
>  	__u32 pad;
>  	struct v4l2_mbus_framefmt format;
> -	__u32 reserved[8];
> +	__u16 request;
> +	__u16 reserved2;
> +	__u32 reserved[7];

I would prefer:

	__u16 request;
	__u16 reserved[15];

>  };
>  
>  /**
> @@ -139,6 +146,8 @@ struct v4l2_subdev_frame_interval_enum {
>   *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
>   * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
>   * @r: coordinates of the selection window
> + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> + * @reserved2: for future use, set to zero for now
>   * @reserved: for future use, set to zero for now
>   *
>   * Hardware may use multiple helper windows to process a video stream.
> @@ -151,7 +160,9 @@ struct v4l2_subdev_selection {
>  	__u32 target;
>  	__u32 flags;
>  	struct v4l2_rect r;
> -	__u32 reserved[8];
> +	__u16 request;
> +	__u16 reserved2;
> +	__u32 reserved[7];

Ditto.

Generally apps do a memset of reserved, and that will just keep working.
But adding a reserved2 field means that they have to explicitly set reserved2
to 0, which won't happen.

>  };
>  
>  /* Backwards compatibility define --- to be removed */
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
  2015-12-18 11:18     ` Hans Verkuil
@ 2015-12-18 17:16       ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-18 17:16 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Laurent Pinchart, linux-media, linux-sh

Hi Hans,

Thank you for the review.

On Friday 18 December 2015 12:18:26 Hans Verkuil wrote:
> On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> > Let userspace specify a request ID when getting or setting formats. The
> > support is limited to the multi-planar API at the moment, extending it
> > to the single-planar API is possible if needed.
> > 
> > From a userspace point of view the API change is also minimized and
> > doesn't require any new ioctl.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> > 
> >  include/uapi/linux/videodev2.h | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/include/uapi/linux/videodev2.h
> > b/include/uapi/linux/videodev2.h index 5af1d2d87558..5b2a8bc80eb2 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -1973,6 +1973,7 @@ struct v4l2_plane_pix_format {
> > 
> >   * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
> >   * @quantization:	enum v4l2_quantization, colorspace quantization
> >   * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
> > 
> > + * @request:		request ID
> > 
> >   */
> >  
> >  struct v4l2_pix_format_mplane {
> >  
> >  	__u32				width;
> > 
> > @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
> > 
> >  	__u8				ycbcr_enc;
> >  	__u8				quantization;
> >  	__u8				xfer_func;
> > 
> > -	__u8				reserved[7];
> > +	__u8				reserved[3];
> > +	__u32				request;
> 
> I think I mentioned this before: I feel uncomfortable using 4 bytes of the
> reserved fields when the request ID is limited to 16 bits anyway.

I'm still unsure whether request IDs should be 16 or 32 bits long. If we go 
for 16 bits then I'll of course make this field a __u16.

> I would prefer a __u16 here. Also put the request field *before* the
> reserved array, not after.

The reserved array isn't aligned to a 32 bit (or even 16 bit) boundary. I can 
put the request field before it, with a 8 bit hole before the field.

> >  } __attribute__ ((packed));
> >  
> >  /**

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
@ 2015-12-18 17:16       ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-18 17:16 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Laurent Pinchart, linux-media, linux-sh

Hi Hans,

Thank you for the review.

On Friday 18 December 2015 12:18:26 Hans Verkuil wrote:
> On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> > Let userspace specify a request ID when getting or setting formats. The
> > support is limited to the multi-planar API at the moment, extending it
> > to the single-planar API is possible if needed.
> > 
> > From a userspace point of view the API change is also minimized and
> > doesn't require any new ioctl.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> > 
> >  include/uapi/linux/videodev2.h | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/include/uapi/linux/videodev2.h
> > b/include/uapi/linux/videodev2.h index 5af1d2d87558..5b2a8bc80eb2 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -1973,6 +1973,7 @@ struct v4l2_plane_pix_format {
> > 
> >   * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
> >   * @quantization:	enum v4l2_quantization, colorspace quantization
> >   * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
> > 
> > + * @request:		request ID
> > 
> >   */
> >  
> >  struct v4l2_pix_format_mplane {
> >  
> >  	__u32				width;
> > 
> > @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
> > 
> >  	__u8				ycbcr_enc;
> >  	__u8				quantization;
> >  	__u8				xfer_func;
> > 
> > -	__u8				reserved[7];
> > +	__u8				reserved[3];
> > +	__u32				request;
> 
> I think I mentioned this before: I feel uncomfortable using 4 bytes of the
> reserved fields when the request ID is limited to 16 bits anyway.

I'm still unsure whether request IDs should be 16 or 32 bits long. If we go 
for 16 bits then I'll of course make this field a __u16.

> I would prefer a __u16 here. Also put the request field *before* the
> reserved array, not after.

The reserved array isn't aligned to a 32 bit (or even 16 bit) boundary. I can 
put the request field before it, with a 8 bit hole before the field.

> >  } __attribute__ ((packed));
> >  
> >  /**

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
  2015-12-18 17:16       ` Laurent Pinchart
@ 2015-12-18 17:37         ` Geert Uytterhoeven
  -1 siblings, 0 replies; 114+ messages in thread
From: Geert Uytterhoeven @ 2015-12-18 17:37 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Laurent Pinchart, Linux Media Mailing List, Linux-sh list

Hi Laurent,

On Fri, Dec 18, 2015 at 6:16 PM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>> > @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
>> >
>> >     __u8                            ycbcr_enc;
>> >     __u8                            quantization;
>> >     __u8                            xfer_func;
>> >
>> > -   __u8                            reserved[7];
>> > +   __u8                            reserved[3];
>> > +   __u32                           request;
>>
>> I think I mentioned this before: I feel uncomfortable using 4 bytes of the
>> reserved fields when the request ID is limited to 16 bits anyway.
>
> I'm still unsure whether request IDs should be 16 or 32 bits long. If we go
> for 16 bits then I'll of course make this field a __u16.
>
>> I would prefer a __u16 here. Also put the request field *before* the
>> reserved array, not after.
>
> The reserved array isn't aligned to a 32 bit (or even 16 bit) boundary. I can
> put the request field before it, with a 8 bit hole before the field.

There's no alignment at all due to:

>> >  } __attribute__ ((packed));

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
@ 2015-12-18 17:37         ` Geert Uytterhoeven
  0 siblings, 0 replies; 114+ messages in thread
From: Geert Uytterhoeven @ 2015-12-18 17:37 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Hans Verkuil, Laurent Pinchart, Linux Media Mailing List, Linux-sh list

Hi Laurent,

On Fri, Dec 18, 2015 at 6:16 PM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>> > @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
>> >
>> >     __u8                            ycbcr_enc;
>> >     __u8                            quantization;
>> >     __u8                            xfer_func;
>> >
>> > -   __u8                            reserved[7];
>> > +   __u8                            reserved[3];
>> > +   __u32                           request;
>>
>> I think I mentioned this before: I feel uncomfortable using 4 bytes of the
>> reserved fields when the request ID is limited to 16 bits anyway.
>
> I'm still unsure whether request IDs should be 16 or 32 bits long. If we go
> for 16 bits then I'll of course make this field a __u16.
>
>> I would prefer a __u16 here. Also put the request field *before* the
>> reserved array, not after.
>
> The reserved array isn't aligned to a 32 bit (or even 16 bit) boundary. I can
> put the request field before it, with a 8 bit hole before the field.

There's no alignment at all due to:

>> >  } __attribute__ ((packed));

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 21/48] media: Move media_device link_notify operation to an ops structure
  2015-12-17  8:39   ` Laurent Pinchart
@ 2015-12-18 22:24     ` Sakari Ailus
  -1 siblings, 0 replies; 114+ messages in thread
From: Sakari Ailus @ 2015-12-18 22:24 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, linux-sh

On Thu, Dec 17, 2015 at 10:39:59AM +0200, Laurent Pinchart wrote:
> This will allow adding new operations without increasing the
> media_device structure size for drivers that don't implement any media
> device operation.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 21/48] media: Move media_device link_notify operation to an ops structure
@ 2015-12-18 22:24     ` Sakari Ailus
  0 siblings, 0 replies; 114+ messages in thread
From: Sakari Ailus @ 2015-12-18 22:24 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, linux-sh

On Thu, Dec 17, 2015 at 10:39:59AM +0200, Laurent Pinchart wrote:
> This will allow adding new operations without increasing the
> media_device structure size for drivers that don't implement any media
> device operation.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 22/48] media: Add per-file-handle data support
  2015-12-17  8:40   ` Laurent Pinchart
@ 2015-12-19  0:40     ` Sakari Ailus
  -1 siblings, 0 replies; 114+ messages in thread
From: Sakari Ailus @ 2015-12-19  0:40 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, linux-sh

Hi Laurent,

Thanks for the set!

On Thu, Dec 17, 2015 at 10:40:00AM +0200, Laurent Pinchart wrote:
> The media devnode core associates devnodes with files by storing the
> devnode pointer in the file structure private_data field. In order to
> allow tracking of per-file-handle data introduce a new media devnode
> file handle structure that stores the devnode pointer, and store a
> pointer to that structure in the file private_data field.
> 
> Users of the media devnode code (the only existing user being
> media_device) are responsible for managing their own subclass of the
> media_devnode_fh structure.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  drivers/media/media-device.c  | 22 ++++++++++++++++++++++
>  drivers/media/media-devnode.c | 19 +++++++++----------
>  include/media/media-devnode.h | 18 +++++++++++++++++-
>  3 files changed, 48 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
> index 7b39440192d6..285f7d79d848 100644
> --- a/drivers/media/media-device.c
> +++ b/drivers/media/media-device.c
> @@ -24,23 +24,45 @@
>  #include <linux/export.h>
>  #include <linux/ioctl.h>
>  #include <linux/media.h>
> +#include <linux/slab.h>
>  #include <linux/types.h>
>  
>  #include <media/media-device.h>
>  #include <media/media-devnode.h>
>  #include <media/media-entity.h>
>  
> +struct media_device_fh {
> +	struct media_devnode_fh fh;
> +};
> +
> +static inline struct media_device_fh *media_device_fh(struct file *filp)
> +{
> +	return container_of(filp->private_data, struct media_device_fh, fh);
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Userspace API
>   */
>  
>  static int media_device_open(struct file *filp)
>  {
> +	struct media_device_fh *fh;
> +
> +	fh = kzalloc(sizeof(*media_device_fh), GFP_KERNEL);

sizeof(*fh) ?

With that fixed,

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>

> +	if (!fh)
> +		return -ENOMEM;
> +
> +	filp->private_data = &fh->fh;
> +
>  	return 0;
>  }
>  
>  static int media_device_close(struct file *filp)
>  {
> +	struct media_device_fh *fh = media_device_fh(filp);
> +
> +	kfree(fh);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
> index ebf9626e5ae5..67bac29838d3 100644
> --- a/drivers/media/media-devnode.c
> +++ b/drivers/media/media-devnode.c
> @@ -154,6 +154,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
>  /* Override for the open function */
>  static int media_open(struct inode *inode, struct file *filp)
>  {
> +	struct media_devnode_fh *fh;
>  	struct media_devnode *mdev;
>  	int ret;
>  
> @@ -175,16 +176,15 @@ static int media_open(struct inode *inode, struct file *filp)
>  	get_device(&mdev->dev);
>  	mutex_unlock(&media_devnode_lock);
>  
> -	filp->private_data = mdev;
> -
> -	if (mdev->fops->open) {
> -		ret = mdev->fops->open(filp);
> -		if (ret) {
> -			put_device(&mdev->dev);
> -			return ret;
> -		}
> +	ret = mdev->fops->open(filp);
> +	if (ret) {
> +		put_device(&mdev->dev);
> +		return ret;
>  	}
>  
> +	fh = filp->private_data;
> +	fh->devnode = mdev;
> +
>  	return 0;
>  }
>  
> @@ -193,8 +193,7 @@ static int media_release(struct inode *inode, struct file *filp)
>  {
>  	struct media_devnode *mdev = media_devnode_data(filp);
>  
> -	if (mdev->fops->release)
> -		mdev->fops->release(filp);
> +	mdev->fops->release(filp);
>  
>  	/* decrease the refcount unconditionally since the release()
>  	   return value is ignored. */
> diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
> index 17ddae32060d..ce81047cb4fc 100644
> --- a/include/media/media-devnode.h
> +++ b/include/media/media-devnode.h
> @@ -52,6 +52,20 @@ struct media_file_operations {
>  };
>  
>  /**
> + * struct media_devnode_fh - Media device node file handle
> + * @devnode:	pointer to the media device node
> + *
> + * This structure serves as a base for per-file-handle data storage. Media
> + * device node users embed media_devnode_fh in their custom file handle data
> + * structures and store the media_devnode_fh in the file private_data in order
> + * to let the media device node core locate the media_devnode corresponding to a
> + * file handle.
> + */
> +struct media_devnode_fh {
> +	struct media_devnode *devnode;
> +};
> +
> +/**
>   * struct media_devnode - Media device node
>   * @fops:	pointer to struct media_file_operations with media device ops
>   * @dev:	struct device pointer for the media controller device
> @@ -92,7 +106,9 @@ void media_devnode_unregister(struct media_devnode *mdev);
>  
>  static inline struct media_devnode *media_devnode_data(struct file *filp)
>  {
> -	return filp->private_data;
> +	struct media_devnode_fh *fh = filp->private_data;
> +
> +	return fh->devnode;
>  }
>  
>  static inline int media_devnode_is_registered(struct media_devnode *mdev)

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 22/48] media: Add per-file-handle data support
@ 2015-12-19  0:40     ` Sakari Ailus
  0 siblings, 0 replies; 114+ messages in thread
From: Sakari Ailus @ 2015-12-19  0:40 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: linux-media, linux-sh

Hi Laurent,

Thanks for the set!

On Thu, Dec 17, 2015 at 10:40:00AM +0200, Laurent Pinchart wrote:
> The media devnode core associates devnodes with files by storing the
> devnode pointer in the file structure private_data field. In order to
> allow tracking of per-file-handle data introduce a new media devnode
> file handle structure that stores the devnode pointer, and store a
> pointer to that structure in the file private_data field.
> 
> Users of the media devnode code (the only existing user being
> media_device) are responsible for managing their own subclass of the
> media_devnode_fh structure.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
>  drivers/media/media-device.c  | 22 ++++++++++++++++++++++
>  drivers/media/media-devnode.c | 19 +++++++++----------
>  include/media/media-devnode.h | 18 +++++++++++++++++-
>  3 files changed, 48 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
> index 7b39440192d6..285f7d79d848 100644
> --- a/drivers/media/media-device.c
> +++ b/drivers/media/media-device.c
> @@ -24,23 +24,45 @@
>  #include <linux/export.h>
>  #include <linux/ioctl.h>
>  #include <linux/media.h>
> +#include <linux/slab.h>
>  #include <linux/types.h>
>  
>  #include <media/media-device.h>
>  #include <media/media-devnode.h>
>  #include <media/media-entity.h>
>  
> +struct media_device_fh {
> +	struct media_devnode_fh fh;
> +};
> +
> +static inline struct media_device_fh *media_device_fh(struct file *filp)
> +{
> +	return container_of(filp->private_data, struct media_device_fh, fh);
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Userspace API
>   */
>  
>  static int media_device_open(struct file *filp)
>  {
> +	struct media_device_fh *fh;
> +
> +	fh = kzalloc(sizeof(*media_device_fh), GFP_KERNEL);

sizeof(*fh) ?

With that fixed,

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>

> +	if (!fh)
> +		return -ENOMEM;
> +
> +	filp->private_data = &fh->fh;
> +
>  	return 0;
>  }
>  
>  static int media_device_close(struct file *filp)
>  {
> +	struct media_device_fh *fh = media_device_fh(filp);
> +
> +	kfree(fh);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
> index ebf9626e5ae5..67bac29838d3 100644
> --- a/drivers/media/media-devnode.c
> +++ b/drivers/media/media-devnode.c
> @@ -154,6 +154,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
>  /* Override for the open function */
>  static int media_open(struct inode *inode, struct file *filp)
>  {
> +	struct media_devnode_fh *fh;
>  	struct media_devnode *mdev;
>  	int ret;
>  
> @@ -175,16 +176,15 @@ static int media_open(struct inode *inode, struct file *filp)
>  	get_device(&mdev->dev);
>  	mutex_unlock(&media_devnode_lock);
>  
> -	filp->private_data = mdev;
> -
> -	if (mdev->fops->open) {
> -		ret = mdev->fops->open(filp);
> -		if (ret) {
> -			put_device(&mdev->dev);
> -			return ret;
> -		}
> +	ret = mdev->fops->open(filp);
> +	if (ret) {
> +		put_device(&mdev->dev);
> +		return ret;
>  	}
>  
> +	fh = filp->private_data;
> +	fh->devnode = mdev;
> +
>  	return 0;
>  }
>  
> @@ -193,8 +193,7 @@ static int media_release(struct inode *inode, struct file *filp)
>  {
>  	struct media_devnode *mdev = media_devnode_data(filp);
>  
> -	if (mdev->fops->release)
> -		mdev->fops->release(filp);
> +	mdev->fops->release(filp);
>  
>  	/* decrease the refcount unconditionally since the release()
>  	   return value is ignored. */
> diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
> index 17ddae32060d..ce81047cb4fc 100644
> --- a/include/media/media-devnode.h
> +++ b/include/media/media-devnode.h
> @@ -52,6 +52,20 @@ struct media_file_operations {
>  };
>  
>  /**
> + * struct media_devnode_fh - Media device node file handle
> + * @devnode:	pointer to the media device node
> + *
> + * This structure serves as a base for per-file-handle data storage. Media
> + * device node users embed media_devnode_fh in their custom file handle data
> + * structures and store the media_devnode_fh in the file private_data in order
> + * to let the media device node core locate the media_devnode corresponding to a
> + * file handle.
> + */
> +struct media_devnode_fh {
> +	struct media_devnode *devnode;
> +};
> +
> +/**
>   * struct media_devnode - Media device node
>   * @fops:	pointer to struct media_file_operations with media device ops
>   * @dev:	struct device pointer for the media controller device
> @@ -92,7 +106,9 @@ void media_devnode_unregister(struct media_devnode *mdev);
>  
>  static inline struct media_devnode *media_devnode_data(struct file *filp)
>  {
> -	return filp->private_data;
> +	struct media_devnode_fh *fh = filp->private_data;
> +
> +	return fh->devnode;
>  }
>  
>  static inline int media_devnode_is_registered(struct media_devnode *mdev)

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi	XMPP: sailus@retiisi.org.uk

^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
  2015-12-18 17:37         ` Geert Uytterhoeven
@ 2015-12-21  3:53           ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-21  3:53 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Hans Verkuil, Laurent Pinchart, Linux Media Mailing List, Linux-sh list

Hi Geert,

On Friday 18 December 2015 18:37:51 Geert Uytterhoeven wrote:
> On Fri, Dec 18, 2015 at 6:16 PM, Laurent Pinchart wrote:
> >> > @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
> >> >     __u8                            ycbcr_enc;
> >> >     __u8                            quantization;
> >> >     __u8                            xfer_func;
> >> > -   __u8                            reserved[7];
> >> > +   __u8                            reserved[3];
> >> > +   __u32                           request;
> >> 
> >> I think I mentioned this before: I feel uncomfortable using 4 bytes of
> >> the reserved fields when the request ID is limited to 16 bits anyway.
> > 
> > I'm still unsure whether request IDs should be 16 or 32 bits long. If we
> > go for 16 bits then I'll of course make this field a __u16.
> > 
> >> I would prefer a __u16 here. Also put the request field *before* the
> >> reserved array, not after.
> > 
> > The reserved array isn't aligned to a 32 bit (or even 16 bit) boundary. I
> > can put the request field before it, with a 8 bit hole before the field.
>
> There's no alignment at all due to:
>
> >> >  } __attribute__ ((packed));

Oops, indeed. Still, isn't it better to keep 16-bit or 32-bit values aligned 
to 16-bit or 32-bit boundaries ?

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane
@ 2015-12-21  3:53           ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-21  3:53 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Hans Verkuil, Laurent Pinchart, Linux Media Mailing List, Linux-sh list

Hi Geert,

On Friday 18 December 2015 18:37:51 Geert Uytterhoeven wrote:
> On Fri, Dec 18, 2015 at 6:16 PM, Laurent Pinchart wrote:
> >> > @@ -1987,7 +1988,8 @@ struct v4l2_pix_format_mplane {
> >> >     __u8                            ycbcr_enc;
> >> >     __u8                            quantization;
> >> >     __u8                            xfer_func;
> >> > -   __u8                            reserved[7];
> >> > +   __u8                            reserved[3];
> >> > +   __u32                           request;
> >> 
> >> I think I mentioned this before: I feel uncomfortable using 4 bytes of
> >> the reserved fields when the request ID is limited to 16 bits anyway.
> > 
> > I'm still unsure whether request IDs should be 16 or 32 bits long. If we
> > go for 16 bits then I'll of course make this field a __u16.
> > 
> >> I would prefer a __u16 here. Also put the request field *before* the
> >> reserved array, not after.
> > 
> > The reserved array isn't aligned to a 32 bit (or even 16 bit) boundary. I
> > can put the request field before it, with a 8 bit hole before the field.
>
> There's no alignment at all due to:
>
> >> >  } __attribute__ ((packed));

Oops, indeed. Still, isn't it better to keep 16-bit or 32-bit values aligned 
to 16-bit or 32-bit boundaries ?

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures
  2015-12-18 11:20     ` Hans Verkuil
@ 2015-12-21  4:00       ` Laurent Pinchart
  -1 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-21  4:00 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Laurent Pinchart, linux-media, linux-sh

Hi Hans,

On Friday 18 December 2015 12:20:54 Hans Verkuil wrote:
> On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> > Let userspace specify a request ID when getting or setting formats or
> > selection rectangles.
> > 
> > From a userspace point of view the API change is minimized and doesn't
> > require any new ioctl.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> > 
> >  include/uapi/linux/v4l2-subdev.h | 15 +++++++++++++--
> >  1 file changed, 13 insertions(+), 2 deletions(-)
> > 
> > diff --git a/include/uapi/linux/v4l2-subdev.h
> > b/include/uapi/linux/v4l2-subdev.h index dbce2b554e02..2f1691ce9df5
> > 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -32,10 +32,12 @@
> >   * enum v4l2_subdev_format_whence - Media bus format type
> >   * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
> >   * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
> > + * @V4L2_SUBDEV_FORMAT_REQUEST: format stored in request
> >   */
> >  enum v4l2_subdev_format_whence {
> >  	V4L2_SUBDEV_FORMAT_TRY = 0,
> >  	V4L2_SUBDEV_FORMAT_ACTIVE = 1,
> > +	V4L2_SUBDEV_FORMAT_REQUEST = 2,
> >  };
> >  
> >  /**
> > @@ -43,12 +45,17 @@ enum v4l2_subdev_format_whence {
> >   * @which: format type (from enum v4l2_subdev_format_whence)
> >   * @pad: pad number, as reported by the media API
> >   * @format: media bus format (format code and frame size)
> > + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> > + * @reserved2: for future use, set to zero for now
> > + * @reserved: for future use, set to zero for now
> >   */
> >  struct v4l2_subdev_format {
> >  	__u32 which;
> >  	__u32 pad;
> >  	struct v4l2_mbus_framefmt format;
> > -	__u32 reserved[8];
> > +	__u16 request;
> > +	__u16 reserved2;
> > +	__u32 reserved[7];
> 
> I would prefer:
> 
> 	__u16 request;
> 	__u16 reserved[15];
> 
> >  };
> >  
> >  /**
> > @@ -139,6 +146,8 @@ struct v4l2_subdev_frame_interval_enum {
> >   *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
> >   * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
> >   * @r: coordinates of the selection window
> > + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> > + * @reserved2: for future use, set to zero for now
> >   * @reserved: for future use, set to zero for now
> >   *
> >   * Hardware may use multiple helper windows to process a video stream.
> > @@ -151,7 +160,9 @@ struct v4l2_subdev_selection {
> >  	__u32 target;
> >  	__u32 flags;
> >  	struct v4l2_rect r;
> > -	__u32 reserved[8];
> > +	__u16 request;
> > +	__u16 reserved2;
> > +	__u32 reserved[7];
> 
> Ditto.
> 
> Generally apps do a memset of reserved, and that will just keep working.
> But adding a reserved2 field means that they have to explicitly set
> reserved2 to 0, which won't happen.

Agreed. Consider it fixed.

> >  };
> >  
> >  /* Backwards compatibility define --- to be removed */

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

* Re: [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures
@ 2015-12-21  4:00       ` Laurent Pinchart
  0 siblings, 0 replies; 114+ messages in thread
From: Laurent Pinchart @ 2015-12-21  4:00 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Laurent Pinchart, linux-media, linux-sh

Hi Hans,

On Friday 18 December 2015 12:20:54 Hans Verkuil wrote:
> On 12/17/2015 09:40 AM, Laurent Pinchart wrote:
> > Let userspace specify a request ID when getting or setting formats or
> > selection rectangles.
> > 
> > From a userspace point of view the API change is minimized and doesn't
> > require any new ioctl.
> > 
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> > 
> >  include/uapi/linux/v4l2-subdev.h | 15 +++++++++++++--
> >  1 file changed, 13 insertions(+), 2 deletions(-)
> > 
> > diff --git a/include/uapi/linux/v4l2-subdev.h
> > b/include/uapi/linux/v4l2-subdev.h index dbce2b554e02..2f1691ce9df5
> > 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -32,10 +32,12 @@
> >   * enum v4l2_subdev_format_whence - Media bus format type
> >   * @V4L2_SUBDEV_FORMAT_TRY: try format, for negotiation only
> >   * @V4L2_SUBDEV_FORMAT_ACTIVE: active format, applied to the device
> > + * @V4L2_SUBDEV_FORMAT_REQUEST: format stored in request
> >   */
> >  enum v4l2_subdev_format_whence {
> >  	V4L2_SUBDEV_FORMAT_TRY = 0,
> >  	V4L2_SUBDEV_FORMAT_ACTIVE = 1,
> > +	V4L2_SUBDEV_FORMAT_REQUEST = 2,
> >  };
> >  
> >  /**
> > @@ -43,12 +45,17 @@ enum v4l2_subdev_format_whence {
> >   * @which: format type (from enum v4l2_subdev_format_whence)
> >   * @pad: pad number, as reported by the media API
> >   * @format: media bus format (format code and frame size)
> > + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> > + * @reserved2: for future use, set to zero for now
> > + * @reserved: for future use, set to zero for now
> >   */
> >  struct v4l2_subdev_format {
> >  	__u32 which;
> >  	__u32 pad;
> >  	struct v4l2_mbus_framefmt format;
> > -	__u32 reserved[8];
> > +	__u16 request;
> > +	__u16 reserved2;
> > +	__u32 reserved[7];
> 
> I would prefer:
> 
> 	__u16 request;
> 	__u16 reserved[15];
> 
> >  };
> >  
> >  /**
> > @@ -139,6 +146,8 @@ struct v4l2_subdev_frame_interval_enum {
> >   *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
> >   * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
> >   * @r: coordinates of the selection window
> > + * @request: request ID (when which is set to V4L2_SUBDEV_FORMAT_REQUEST)
> > + * @reserved2: for future use, set to zero for now
> >   * @reserved: for future use, set to zero for now
> >   *
> >   * Hardware may use multiple helper windows to process a video stream.
> > @@ -151,7 +160,9 @@ struct v4l2_subdev_selection {
> >  	__u32 target;
> >  	__u32 flags;
> >  	struct v4l2_rect r;
> > -	__u32 reserved[8];
> > +	__u16 request;
> > +	__u16 reserved2;
> > +	__u32 reserved[7];
> 
> Ditto.
> 
> Generally apps do a memset of reserved, and that will just keep working.
> But adding a reserved2 field means that they have to explicitly set
> reserved2 to 0, which won't happen.

Agreed. Consider it fixed.

> >  };
> >  
> >  /* Backwards compatibility define --- to be removed */

-- 
Regards,

Laurent Pinchart


^ permalink raw reply	[flat|nested] 114+ messages in thread

end of thread, other threads:[~2015-12-21  4:00 UTC | newest]

Thread overview: 114+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-17  8:39 [PATCH/RFC 00/48] Request API and proof-of-concept implementation Laurent Pinchart
2015-12-17  8:39 ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 01/48] v4l: vsp1: Use pipeline display list to decide how to write to modules Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 02/48] v4l: vsp1: Always setup the display list Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 03/48] v4l: vsp1: Simplify frame end processing Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 04/48] v4l: vsp1: Split display list manager from display list Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 05/48] v4l: vsp1: Store the display list manager in the WPF Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 06/48] v4l: vsp1: bru: Don't program background color in control set handler Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 07/48] v4l: vsp1: rwpf: Don't program alpha value " Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 08/48] v4l: vsp1: sru: Don't program intensity " Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 09/48] v4l: vsp1: Don't setup control handler when starting streaming Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 10/48] v4l: vsp1: Enable display list support for the HS[IT], LUT, SRU and UDS Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 11/48] v4l: vsp1: Don't configure RPF memory buffers before calculating offsets Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 12/48] v4l: vsp1: Remove unneeded entity streaming flag Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 13/48] v4l: vsp1: Document calling context of vsp1_pipeline_propagate_alpha() Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 14/48] v4l: vsp1: Fix 80 characters per line violations Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 15/48] v4l: vsp1: Add header display list support Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 16/48] v4l: vsp1: Use display lists with the userspace API Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 17/48] v4l: vsp1: Move subdev initialization code to vsp1_entity_init() Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 18/48] v4l: vsp1: Consolidate entity ops in a struct vsp1_entity_operations Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 19/48] v4l: vsp1: Fix BRU try compose rectangle storage Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 20/48] v4l: vsp1: Add race condition FIXME comment Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-17  8:39 ` [PATCH/RFC 21/48] media: Move media_device link_notify operation to an ops structure Laurent Pinchart
2015-12-17  8:39   ` Laurent Pinchart
2015-12-18 22:24   ` Sakari Ailus
2015-12-18 22:24     ` Sakari Ailus
2015-12-17  8:40 ` [PATCH/RFC 22/48] media: Add per-file-handle data support Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-19  0:40   ` Sakari Ailus
2015-12-19  0:40     ` Sakari Ailus
2015-12-17  8:40 ` [PATCH/RFC 23/48] media: Add request API Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 24/48] media: Add per-entity request data support Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 25/48] videodev2.h: Add request field to v4l2_buffer Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 26/48] videodev2.h: Add request field to v4l2_pix_format_mplane Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-18 11:18   ` Hans Verkuil
2015-12-18 11:18     ` Hans Verkuil
2015-12-18 17:16     ` Laurent Pinchart
2015-12-18 17:16       ` Laurent Pinchart
2015-12-18 17:37       ` Geert Uytterhoeven
2015-12-18 17:37         ` Geert Uytterhoeven
2015-12-21  3:53         ` Laurent Pinchart
2015-12-21  3:53           ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 27/48] v4l2-subdev.h: Add request field to format and selection structures Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-18 11:20   ` Hans Verkuil
2015-12-18 11:20     ` Hans Verkuil
2015-12-21  4:00     ` Laurent Pinchart
2015-12-21  4:00       ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 28/48] v4l: Support the request API in format operations Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 29/48] v4l: subdev: Add pad config allocator and init Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 30/48] v4l: subdev: Call pad init_cfg operation when opening subdevs Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 31/48] v4l: subdev: Support the request API in format and selection operations Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 32/48] vb2: Add allow_requests flag Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 33/48] vb2: Add helper function to check for request buffers Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 34/48] vb2: Add helper function to queue request-specific buffer Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 35/48] DocBook: media: Document the media request API Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 36/48] DocBook: media: Document the V4L2 " Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 37/48] DocBook: media: Document the subdev selection API Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 38/48] DocBook: media: Document the V4L2 subdev request API Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 39/48] v4l: vsp1: Implement and use the subdev pad::init_cfg configuration Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 40/48] v4l: vsp1: Store active formats in a pad config structure Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 41/48] v4l: vsp1: Store active selection rectangles " Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 42/48] v4l: vsp1: Create a new configure operation to setup modules Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 43/48] v4l: vsp1: Merge RPF and WPF pad ops structures Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 44/48] v4l: vsp1: Pass a media request to the module configure operations Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 45/48] v4l: vsp1: Use __vsp1_video_try_format to initialize format at init time Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 46/48] v4l: vsp1: Support video device formats stored in requests Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 47/48] v4l: vsp1: Pass display list explicitly to configure functions Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart
2015-12-17  8:40 ` [PATCH/RFC 48/48] v4l: vsp1: Support the request API Laurent Pinchart
2015-12-17  8:40   ` Laurent Pinchart

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.