All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] [RFC] Video HDMI Loop-back Test
@ 2017-12-14  0:25 Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 1/3] kms-tests: Provide .gitignore Kieran Bingham
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Kieran Bingham @ 2017-12-14  0:25 UTC (permalink / raw)
  To: linux-renesas-soc, laurent.pinchart, kieran.bingham; +Cc: Kieran Bingham

From: Kieran Bingham <kieran@bingham.xyz>

This short series works towards providing automated system validation by
introducing the ability to capture frames using the R-Car VIN device with an
HDMI cable connected to our HDMI output of the DU.

To support this test, relevant patches and support must be provided by kmsxx
which has been posted separately [0]:
 [PATCH 0/4] kms++util: Provide validation helpers

This series provides an rcar_vin module to assist in detecting and identifying
the correct video device to use for the video capture device.

The rcar_vin module provides a lot of code which is not used specifically by
the following kms-test-vin-loopback test but is kept in the module as an RFC
and to stimulate discussion on implementing convenient helpers to wrap our
R-Car interfaces in python modules, especially as so much platform knowledge is
required to set up a capture.

Finally the VIN loopback test is added which uses two pre-filled display
buffers to simulate an active running display but with constant content.

The display output is then captured by setting up a VideoDevice interface and
registering a handler (handle_frame_capture) to process buffers when the are
presented by the VIN driver.

The captured frames are compared against the constant output buffer - and
written to file in the event that there are any differences to allow for visual
inspection and analysis.

This test currently highlights potential colour space conversion issues in YUYV
pipelines, and a non-determined error in ARGB configured pipelines which will
be investigated separately.

Further future possibilities here:
 - Automatically configure the media device and links with a media-ctl abstraction
 - Add meta-data into the output frames so that they can be correctly matched
   against incoming captured frames. (I'm thinking adding a QR code to each frame)

--
Regards

Kieran

[0] https://www.mail-archive.com/linux-renesas-soc@vger.kernel.org/msg21303.html

Kieran Bingham (3):
  kms-tests: Provide .gitignore
  rcar_vin: Provide VIN configuration helpers
  tests: Add a DU->VIN loopback test

 .gitignore                     |   4 +-
 tests/kms-test-vin-loopback.py | 198 ++++++++++++++++++++++++++++++++++-
 tests/rcar_vin.py              | 107 ++++++++++++++++++-
 3 files changed, 309 insertions(+)
 create mode 100644 .gitignore
 create mode 100755 tests/kms-test-vin-loopback.py
 create mode 100755 tests/rcar_vin.py

base-commit: 724e38e6c5f511030d7cbdcd40ccc3d0f8749981
-- 
git-series 0.9.1

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

* [RFC PATCH 1/3] kms-tests: Provide .gitignore
  2017-12-14  0:25 [RFC PATCH 0/3] [RFC] Video HDMI Loop-back Test Kieran Bingham
@ 2017-12-14  0:25 ` Kieran Bingham
  2017-12-14  0:28   ` Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 2/3] rcar_vin: Provide VIN configuration helpers Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 3/3] tests: Add a DU->VIN loopback test Kieran Bingham
  2 siblings, 1 reply; 5+ messages in thread
From: Kieran Bingham @ 2017-12-14  0:25 UTC (permalink / raw)
  To: linux-renesas-soc, laurent.pinchart, kieran.bingham
  Cc: Kieran Bingham, Kieran Bingham

From: Kieran Bingham <kieran@bingham.xyz>

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

Provide an initial .gitignore file to hide python related
files that may be created in an active workspace

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 .gitignore | 4 ++++
 1 file changed, 4 insertions(+)
 create mode 100644 .gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..8df6f4ad55ab
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.log
+*.swp
+*.pyc
+__pycache__
-- 
git-series 0.9.1

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

* [RFC PATCH 2/3] rcar_vin: Provide VIN configuration helpers
  2017-12-14  0:25 [RFC PATCH 0/3] [RFC] Video HDMI Loop-back Test Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 1/3] kms-tests: Provide .gitignore Kieran Bingham
@ 2017-12-14  0:25 ` Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 3/3] tests: Add a DU->VIN loopback test Kieran Bingham
  2 siblings, 0 replies; 5+ messages in thread
From: Kieran Bingham @ 2017-12-14  0:25 UTC (permalink / raw)
  To: linux-renesas-soc, laurent.pinchart, kieran.bingham
  Cc: Kieran Bingham, Kieran Bingham

From: Kieran Bingham <kieran@bingham.xyz>

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

To handle capturing frames through the RCar VIN subsystem we must
correctly configure the device links and identify the device nodes
to capture from.

Implement a helper class to abstract and handle the VIN objects

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 tests/rcar_vin.py | 107 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 107 insertions(+)
 create mode 100755 tests/rcar_vin.py

diff --git a/tests/rcar_vin.py b/tests/rcar_vin.py
new file mode 100755
index 000000000000..77923617edb6
--- /dev/null
+++ b/tests/rcar_vin.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python3
+
+import os
+import glob
+
+# model strings are null terminated:
+rcar_gen3_models = [
+    'Renesas Salvator-X board based on r8a7795 ES1.x\0',
+    'Renesas Salvator-X 2nd version board based on r8a7795 ES2.0+\0',
+    'Renesas Salvator-X board based on r8a7796\0',
+    'Renesas Eagle board based on r8a77970\0',
+]
+
+rcar_gen3_vin = [
+    'e6ef0000',
+    'e6ef1000',
+    'e6ef2000',
+    'e6ef3000',
+    'e6ef4000',
+    'e6ef5000',
+    'e6ef6000',
+    'e6ef7000',
+]
+
+rcar_gen3_csi2 = [
+    'fea80000',
+    'fea90000',
+    'feaa0000',
+    'feab0000',
+]
+
+
+class MediaController(object):
+    def __init__(self, device):
+        for f in glob.glob("/dev/media*"):
+            print(f)
+        self.cmd = "/usr/bin/media-ctl -d " + device + " "
+
+    def reset(self):
+        os.system(self.cmd + "-r")
+
+
+class ADV748x(object):
+    entities = ['afe', 'hdmi', 'txa', 'txb']
+
+    def __init__(self, i2c_addr):
+        self.basename = "adv748x " + i2c_addr
+
+    def entity_name(self, entity):
+        return self.basename + " " + entity
+
+
+class RCar_VIN_G3(object):
+    def __init__(self):
+        self.model = open('/proc/device-tree/model', 'r').read()
+        if self.model not in rcar_gen3_models:
+            raise ValueError('Not a supported R-Car Gen3 platform: ' + self.model)
+
+    # Perhaps we need an interface or python bindings for media controller
+    def mc_get_mdev(self):
+        for f in glob.glob("/dev/media*"):
+            print(f)
+
+    def vin_v4l2_device(self, idx):
+        ''' Return the V4L2 device path (such as /dev/video23) for a given VIN '''
+        path = "/sys/devices/platform/soc/" + rcar_gen3_vin[idx] + ".video/video4linux/video*"
+        path = glob.glob(path)[0]
+        return "/dev/" + os.path.basename(path)
+
+    def vin_name(self, idx):
+        return "rcar_vin " + rcar_gen3_vin[idx] + ".video"
+
+    def csi2_name(self, idx):
+        return "rcar_csi2 " + rcar_gen3_csi2[idx] + ".csi2"
+
+    def hdmi_in(self):
+        print("Configure for HDMI input")
+
+
+#######################################################################################################################
+# Selftesting
+
+def selftest_MediaController():
+    mc = MediaController("/dev/media0")
+    mc.reset()
+
+
+def selftest_RCar_VIN_G3():
+    target = RCar_VIN_G3()
+    print("Detected: " + target.model)
+    print("Identifying VIN devices:")
+    for i in range(8):
+        print("    vin" + str(i) + ": " + target.vin_v4l2_device(i))
+    target.mc_get_mdev()
+    target.hdmi_in()
+
+
+def selftest_ADV748x():
+    adv = ADV748x("4-0070")
+    print("ADV748x Entities:")
+    for e in adv.entities:
+        print("    " + e + ": " + adv.entity_name(e))
+
+if __name__ == "__main__":
+    selftest_MediaController()
+    selftest_ADV748x()
+    selftest_RCar_VIN_G3()
-- 
git-series 0.9.1

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

* [RFC PATCH 3/3] tests: Add a DU->VIN loopback test
  2017-12-14  0:25 [RFC PATCH 0/3] [RFC] Video HDMI Loop-back Test Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 1/3] kms-tests: Provide .gitignore Kieran Bingham
  2017-12-14  0:25 ` [RFC PATCH 2/3] rcar_vin: Provide VIN configuration helpers Kieran Bingham
@ 2017-12-14  0:25 ` Kieran Bingham
  2 siblings, 0 replies; 5+ messages in thread
From: Kieran Bingham @ 2017-12-14  0:25 UTC (permalink / raw)
  To: linux-renesas-soc, laurent.pinchart, kieran.bingham
  Cc: Kieran Bingham, Kieran Bingham

From: Kieran Bingham <kieran@bingham.xyz>

From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

Provide an initial test which outputs an image over HDMI using the R-Car DU,
and captures from HDMI-in on the same board.

This test is targetted specifically to the Salvator-X(S) with an ADV748x
HDMI input, and the R-Car VIN driver as a capture interface.

Whilst the media device to collect frames from is automatically detected, the
media controller links and formats are not automatically set up, and thus the
capture pipeline must be correctly defined before running the test.

This can be done using the helper script 'yavta-hdmi.sh' in vin-tests.

Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
 tests/kms-test-vin-loopback.py | 198 ++++++++++++++++++++++++++++++++++-
 1 file changed, 198 insertions(+)
 create mode 100755 tests/kms-test-vin-loopback.py

diff --git a/tests/kms-test-vin-loopback.py b/tests/kms-test-vin-loopback.py
new file mode 100755
index 000000000000..f77ce290efab
--- /dev/null
+++ b/tests/kms-test-vin-loopback.py
@@ -0,0 +1,198 @@
+#!/usr/bin/python3
+
+import kmstest
+import pykms
+import selectors
+
+from rcar_vin import RCar_VIN_G3
+
+class VINLoopbackTest(kmstest.KMSTest):
+    """ Output a test image on a specific HDMI connector and capture using an HDMI
+        cable looped back to the VIN HDMI input device. """
+
+    def handle_page_flip(self, frame, time):
+        if self.flips == 1:
+            self.logger.log("first page flip frame %u time %f" % (frame, time))
+            self.frame_start = frame
+            self.time_start = time
+
+        if self.stop_requested:
+            self.logger.log("last page flip frame %u time %f" % (frame, time))
+            self.frame_end = frame
+            self.time_end = time
+            self.loop.stop()
+            self.stop_requested = False
+            return
+
+        # Flip between two constant (identical) pre-created buffers
+        fb = self.fbs[self.front_buf]
+        self.front_buf = self.front_buf ^ 1
+
+        source = kmstest.Rect(0, 0, fb.width, fb.height)
+        destination = kmstest.Rect(0, 0, fb.width, fb.height)
+        self.atomic_plane_set(self.plane, self.crtc, source, destination, fb)
+
+    def stop_page_flip(self):
+        self.stop_requested = True
+        self.cap.stream_off()
+
+    def configure_vin(self, mode):
+        vin = RCar_VIN_G3().vin_v4l2_device(0)
+        self.logger.log("Using VIN : " + vin)
+
+        # Capture frames using VIN
+        self.vid = pykms.VideoDevice(vin)
+        self.cap = self.vid.capture_streamer
+        self.cap.set_port(0)
+        self.cap.set_format(self.pixfmt, mode.hdisplay, mode.vdisplay)
+        self.cap.set_queue_size(len(self.vin))
+        self.captured = 0
+        self.failures = 0
+
+        for fb in self.vin:
+            self.cap.queue(fb)
+
+        self.cap.stream_on()
+
+        self.loop.register(self.cap.fd, selectors.EVENT_READ, self.handle_frame_capture)
+
+
+    def handle_frame_capture(self, fileobj, events):
+        if self.stop_requested:
+            return
+
+        fb = self.cap.dequeue()
+        diff = pykms.compare_framebuffers(fb, self.fbs[self.front_buf])
+
+        self.logger.log("Frame Capture: " + str(self.captured) + " with difference " + str(diff))
+
+        if diff:
+            filename = "/tmp/captured{}.{}x{}.raw".format(str(self.captured), str(self.mode.hdisplay), str(self.mode.vdisplay))
+            pykms.save_raw_frame(fb, filename)
+            self.logger.log("Corrupt frame written to " + filename)
+            self.failures += 1
+
+        self.cap.queue(fb)
+        self.captured += 1
+
+        # Stop capturing after 10 frames
+        if self.captured >= 10:
+            self.stop_page_flip()
+
+
+    def get_connector(self, name):
+        for connector in self.card.connectors:
+            # Skip unless we are HDMI-A-1
+            if connector.fullname == "HDMI-A-1":
+                return connector
+
+    def main(self):
+        connector_name = "HDMI-A-1"
+
+        self.start("VIN Loopback on connector %s" % connector_name)
+
+        connector = self.get_connector(connector_name)
+        if connector is None:
+            self.skip("HDMI output connector not found")
+            return
+
+        # Skip disconnected connectors
+        if not connector.connected():
+            self.skip("unconnected connector")
+            return
+
+        # Find a CRTC suitable for the connector
+        crtc = connector.get_current_crtc()
+        if not crtc:
+            crtcs = connector.get_possible_crtcs()
+            if len(crtcs) == 0:
+                self.skip("No CRTC available")
+                return
+
+            crtc = crtcs[0]
+
+        self.crtc = crtc
+
+        # Find a plane suitable for the CRTC
+        for plane in self.card.planes:
+            if plane.supports_crtc(crtc):
+                self.plane = plane
+                break
+        else:
+            self.skip("no plane available for CRTC %u" % crtc.id)
+            return
+
+        # Get the default mode for the connector
+        try:
+            mode = connector.get_default_mode()
+        except ValueError:
+            self.skip("no mode available")
+            return
+
+        self.mode = mode
+
+        self.logger.log("Testing connector %s, CRTC %u, plane %u, mode %s" % \
+              (connector.fullname, crtc.id, self.plane.id, mode.name))
+
+        # Create two frame buffers each for output and capture
+        self.fbs = []
+        self.vin = []
+        self.pixfmt = pykms.PixelFormat.XRGB8888
+
+        for i in range(2):
+            self.fbs.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, self.pixfmt))
+            self.vin.append(pykms.DumbFramebuffer(self.card, mode.hdisplay, mode.vdisplay, self.pixfmt))
+
+        # Draw test patterns on the output frame buffers
+        # We don't (yet) support comparing against changing patterns
+        pykms.draw_test_pattern(self.fbs[0])
+        pykms.draw_test_pattern(self.fbs[1])
+
+        # Set the mode and perform the initial page flip
+        ret = self.atomic_crtc_mode_set(crtc, connector, mode, self.fbs[0])
+        if ret < 0:
+            self.fail("atomic mode set failed with %d" % ret)
+            return
+
+        # Configure
+
+        # Flip pages for 10s
+        self.front_buf = 0
+        self.frame_start = 0
+        self.frame_end = 0
+        self.time_start = 0
+        self.time_end = 0
+        self.stop_requested = False
+
+        # Allow the output to settle before capturing
+        # VIN currently does not support dynamic input change
+        self.run(1)
+
+        self.configure_vin(mode)
+
+        # Set timeout at 5 seconds.
+        # We stop after capturing 10 frames
+        self.loop.add_timer(5, self.stop_page_flip)
+        self.run(6)
+
+        if not self.captured:
+            self.fail("No frames captured")
+            return
+
+        if self.failures:
+            self.fail("Frame comparisons failed")
+            self.logger.log("Saving output image as /tmp/original.bin")
+            pykms.save_raw_frame(self.fbs[0], "/tmp/original.bin")
+            return
+
+        if not self.flips:
+            self.fail("No page flip registered")
+            return
+
+        if self.stop_requested:
+            self.fail("Last page flip not registered")
+            return
+
+        self.success()
+
+VINLoopbackTest().execute()
-- 
git-series 0.9.1

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

* Re: [RFC PATCH 1/3] kms-tests: Provide .gitignore
  2017-12-14  0:25 ` [RFC PATCH 1/3] kms-tests: Provide .gitignore Kieran Bingham
@ 2017-12-14  0:28   ` Kieran Bingham
  0 siblings, 0 replies; 5+ messages in thread
From: Kieran Bingham @ 2017-12-14  0:28 UTC (permalink / raw)
  To: Kieran Bingham, linux-renesas-soc, laurent.pinchart; +Cc: Kieran Bingham

On 14/12/17 00:25, Kieran Bingham wrote:
> From: Kieran Bingham <kieran@bingham.xyz>

Ahem - Please excuse that person - he's not meant to be working.

> From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

This guy is.

One day I'll acknowledge that my e-mail aliasing is completely overcomplicated.

--
George (Must be one of my other alter-egos)



> 
> Provide an initial .gitignore file to hide python related
> files that may be created in an active workspace
> 
> Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> ---
>  .gitignore | 4 ++++
>  1 file changed, 4 insertions(+)
>  create mode 100644 .gitignore
> 
> diff --git a/.gitignore b/.gitignore
> new file mode 100644
> index 000000000000..8df6f4ad55ab
> --- /dev/null
> +++ b/.gitignore
> @@ -0,0 +1,4 @@
> +*.log
> +*.swp
> +*.pyc
> +__pycache__
> 

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

end of thread, other threads:[~2017-12-14  0:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-14  0:25 [RFC PATCH 0/3] [RFC] Video HDMI Loop-back Test Kieran Bingham
2017-12-14  0:25 ` [RFC PATCH 1/3] kms-tests: Provide .gitignore Kieran Bingham
2017-12-14  0:28   ` Kieran Bingham
2017-12-14  0:25 ` [RFC PATCH 2/3] rcar_vin: Provide VIN configuration helpers Kieran Bingham
2017-12-14  0:25 ` [RFC PATCH 3/3] tests: Add a DU->VIN loopback test Kieran Bingham

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.