* [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