mirror of
				https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
				synced 2025-11-04 16:52:06 +10:00 
			
		
		
		
	media fixes for v4.20-rc8
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJcG4weAAoJEAhfPr2O5OEVMu8P/j5a3+qringy/94NgmpHBQop aOACNWTRE746CG8T0yKgHV13iiLTHhlVxrRfhADKomWFit0DOiE2G1QXDsw6jptl gfMKMz3tE7MNOt0E+1tFzkezduJ7TIvFw9rorJ9MuACr9RGc+jMc+8muu1Uhu+fS JArKYrn1xlBEP9k2pcgbxFIjzdRr1jEJ9MCdyxybaU4QWyH4rUq0u+i6RJ2JlLcV urXGeDaNwgq7uTcOdUIwcbB0lKCi3hhkuPyl850IaQHWkR1cIzRoMWk5ilW9YYR3 8zDix9hORmPAdRIwhj0kJElTLZlTzF/u4+1fARmwKJlOYnAfRzSyFhC5P4huvmeA 6KXP1jg3OcyU5mB/Ys0YpZDhUtlhpRmMCMKtZW0x4BPpYTfRkAz6almUM6kIyaKp Dv1cp4UJ8SGpqVxEFBSr6qPsoO0by8jdkgRsupaCn6tAtkG7VXDGR8yhzZB8Leai pdCXP/7Z5t3kWI0XceVlpgOjkC7qLbEQKLDk0dqg0XqFLEuXm7sifLGamGhqubVy BmRPzH9oVISutmM/8DL8MHBkAv5IESF1lwhOzM75LTtA7aDaBuHS6zRhh45VtdJx r8/+R9KEvKdWTFgnRpvaERJk64I0hU44gmPLOtt/kkCfaTOonbhIsZ55uZxKjkqg rHPVHJORalrJGy9Hnhpl =uZDa -----END PGP SIGNATURE----- Merge tag 'media/v4.20-7' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull more media updates from Mauro Carvalho Chehab: "The Intel IPU3 camera driver" * tag 'media/v4.20-7' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (23 commits) media: staging/ipu3-imgu: Add MAINTAINERS entry media: staging/ipu3-imgu: Address documentation comments media: v4l: Add Intel IPU3 meta buffer formats media: doc-rst: Add Intel IPU3 documentation media: ipu3-imgu: Fix firmware binary location media: ipu3-imgu: Fix compiler warnings media: staging/intel-ipu3: Add dual pipe support media: staging/intel-ipu3: Add Intel IPU3 meta data uAPI media: staging/intel-ipu3: Add imgu top level pci device driver media: staging/intel-ipu3: Add v4l2 driver based on media framework media: staging/intel-ipu3: Add css pipeline programming media: staging/intel-ipu3: css: Initialize css hardware media: staging/intel-ipu3: css: Compute and program ccs media: staging/intel-ipu3: css: Add static settings for image pipeline media: staging/intel-ipu3: css: Add support for firmware management media: staging/intel-ipu3: css: Add dma buff pool utility functions media: staging/intel-ipu3: Implement DMA mapping functions media: staging/intel-ipu3: mmu: Implement driver media: staging/intel-ipu3: abi: Add structs media: staging/intel-ipu3: abi: Add register definitions and enum ...
This commit is contained in:
		
						commit
						996680d461
					
				@ -472,6 +472,9 @@ enum v4l2_buf_type
 | 
			
		||||
    * - ``V4L2_BUF_TYPE_META_CAPTURE``
 | 
			
		||||
      - 13
 | 
			
		||||
      - Buffer for metadata capture, see :ref:`metadata`.
 | 
			
		||||
    * - ``V4L2_BUF_TYPE_META_OUTPUT``
 | 
			
		||||
      - 14
 | 
			
		||||
      - Buffer for metadata output, see :ref:`metadata`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,21 +14,27 @@ Metadata Interface
 | 
			
		||||
******************
 | 
			
		||||
 | 
			
		||||
Metadata refers to any non-image data that supplements video frames with
 | 
			
		||||
additional information. This may include statistics computed over the image
 | 
			
		||||
or frame capture parameters supplied by the image source. This interface is
 | 
			
		||||
intended for transfer of metadata to userspace and control of that operation.
 | 
			
		||||
additional information. This may include statistics computed over the image,
 | 
			
		||||
frame capture parameters supplied by the image source or device specific
 | 
			
		||||
parameters for specifying how the device processes images. This interface is
 | 
			
		||||
intended for transfer of metadata between the userspace and the hardware and
 | 
			
		||||
control of that operation.
 | 
			
		||||
 | 
			
		||||
The metadata interface is implemented on video capture device nodes. The device
 | 
			
		||||
can be dedicated to metadata or can implement both video and metadata capture
 | 
			
		||||
as specified in its reported capabilities.
 | 
			
		||||
The metadata interface is implemented on video device nodes. The device can be
 | 
			
		||||
dedicated to metadata or can support both video and metadata as specified in its
 | 
			
		||||
reported capabilities.
 | 
			
		||||
 | 
			
		||||
Querying Capabilities
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
Device nodes supporting the metadata interface set the ``V4L2_CAP_META_CAPTURE``
 | 
			
		||||
flag in the ``device_caps`` field of the
 | 
			
		||||
Device nodes supporting the metadata capture interface set the
 | 
			
		||||
``V4L2_CAP_META_CAPTURE`` flag in the ``device_caps`` field of the
 | 
			
		||||
:c:type:`v4l2_capability` structure returned by the :c:func:`VIDIOC_QUERYCAP`
 | 
			
		||||
ioctl. That flag means the device can capture metadata to memory.
 | 
			
		||||
ioctl. That flag means the device can capture metadata to memory. Similarly,
 | 
			
		||||
device nodes supporting metadata output interface set the
 | 
			
		||||
``V4L2_CAP_META_OUTPUT`` flag in the ``device_caps`` field of
 | 
			
		||||
:c:type:`v4l2_capability` structure. That flag means the device can read
 | 
			
		||||
metadata from memory.
 | 
			
		||||
 | 
			
		||||
At least one of the read/write or streaming I/O methods must be supported.
 | 
			
		||||
 | 
			
		||||
@ -42,10 +48,11 @@ to the basic :ref:`format` ioctls, the :c:func:`VIDIOC_ENUM_FMT` ioctl must be
 | 
			
		||||
supported as well.
 | 
			
		||||
 | 
			
		||||
To use the :ref:`format` ioctls applications set the ``type`` field of the
 | 
			
		||||
:c:type:`v4l2_format` structure to ``V4L2_BUF_TYPE_META_CAPTURE`` and use the
 | 
			
		||||
:c:type:`v4l2_meta_format` ``meta`` member of the ``fmt`` union as needed per
 | 
			
		||||
the desired operation. Both drivers and applications must set the remainder of
 | 
			
		||||
the :c:type:`v4l2_format` structure to 0.
 | 
			
		||||
:c:type:`v4l2_format` structure to ``V4L2_BUF_TYPE_META_CAPTURE`` or to
 | 
			
		||||
``V4L2_BUF_TYPE_META_OUTPUT`` and use the :c:type:`v4l2_meta_format` ``meta``
 | 
			
		||||
member of the ``fmt`` union as needed per the desired operation. Both drivers
 | 
			
		||||
and applications must set the remainder of the :c:type:`v4l2_format` structure
 | 
			
		||||
to 0.
 | 
			
		||||
 | 
			
		||||
.. c:type:: v4l2_meta_format
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ These formats are used for the :ref:`metadata` interface only.
 | 
			
		||||
.. toctree::
 | 
			
		||||
    :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
    pixfmt-meta-intel-ipu3
 | 
			
		||||
    pixfmt-meta-d4xx
 | 
			
		||||
    pixfmt-meta-uvc
 | 
			
		||||
    pixfmt-meta-vsp1-hgo
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										178
									
								
								Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,178 @@
 | 
			
		||||
.. -*- coding: utf-8; mode: rst -*-
 | 
			
		||||
 | 
			
		||||
.. _v4l2-meta-fmt-params:
 | 
			
		||||
.. _v4l2-meta-fmt-stat-3a:
 | 
			
		||||
 | 
			
		||||
******************************************************************
 | 
			
		||||
V4L2_META_FMT_IPU3_PARAMS ('ip3p'), V4L2_META_FMT_IPU3_3A ('ip3s')
 | 
			
		||||
******************************************************************
 | 
			
		||||
 | 
			
		||||
.. c:type:: ipu3_uapi_stats_3a
 | 
			
		||||
 | 
			
		||||
3A statistics
 | 
			
		||||
=============
 | 
			
		||||
 | 
			
		||||
For IPU3 ImgU, the 3A statistics accelerators collect different statistics over
 | 
			
		||||
an input bayer frame. Those statistics, defined in data struct :c:type:`ipu3_uapi_stats_3a`,
 | 
			
		||||
are obtained from "ipu3-imgu 3a stat" metadata capture video node, which are then
 | 
			
		||||
passed to user space for statistics analysis using :c:type:`v4l2_meta_format` interface.
 | 
			
		||||
 | 
			
		||||
The statistics collected are AWB (Auto-white balance) RGBS (Red, Green, Blue and
 | 
			
		||||
Saturation measure) cells, AWB filter response, AF (Auto-focus) filter response,
 | 
			
		||||
and AE (Auto-exposure) histogram.
 | 
			
		||||
 | 
			
		||||
struct :c:type:`ipu3_uapi_4a_config` saves configurable parameters for all above.
 | 
			
		||||
 | 
			
		||||
.. code-block:: c
 | 
			
		||||
 | 
			
		||||
	struct ipu3_uapi_stats_3a {
 | 
			
		||||
		struct ipu3_uapi_awb_raw_buffer awb_raw_buffer;
 | 
			
		||||
		struct ipu3_uapi_ae_raw_buffer_aligned ae_raw_buffer[IPU3_UAPI_MAX_STRIPES];
 | 
			
		||||
		struct ipu3_uapi_af_raw_buffer af_raw_buffer;
 | 
			
		||||
		struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer;
 | 
			
		||||
		struct ipu3_uapi_4a_config stats_4a_config;
 | 
			
		||||
		__u32 ae_join_buffers;
 | 
			
		||||
		__u8 padding[28];
 | 
			
		||||
		struct ipu3_uapi_stats_3a_bubble_info_per_stripe stats_3a_bubble_per_stripe;
 | 
			
		||||
		struct ipu3_uapi_ff_status stats_3a_status;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
.. c:type:: ipu3_uapi_params
 | 
			
		||||
 | 
			
		||||
Pipeline parameters
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
IPU3 pipeline has a number of image processing stages, each of which takes a
 | 
			
		||||
set of parameters as input. The major stages of pipelines are shown here:
 | 
			
		||||
 | 
			
		||||
Raw pixels -> Bayer Downscaling -> Optical Black Correction ->
 | 
			
		||||
 | 
			
		||||
Linearization -> Lens Shading Correction -> White Balance / Exposure /
 | 
			
		||||
 | 
			
		||||
Focus Apply -> Bayer Noise Reduction -> ANR -> Demosaicing -> Color
 | 
			
		||||
 | 
			
		||||
Correction Matrix -> Gamma correction -> Color Space Conversion ->
 | 
			
		||||
 | 
			
		||||
Chroma Down Scaling -> Chromatic Noise Reduction -> Total Color
 | 
			
		||||
 | 
			
		||||
Correction -> XNR3 -> TNR -> DDR
 | 
			
		||||
 | 
			
		||||
The table below presents a description of the above algorithms.
 | 
			
		||||
 | 
			
		||||
======================== =======================================================
 | 
			
		||||
Name			 Description
 | 
			
		||||
======================== =======================================================
 | 
			
		||||
Optical Black Correction Optical Black Correction block subtracts a pre-defined
 | 
			
		||||
			 value from the respective pixel values to obtain better
 | 
			
		||||
			 image quality.
 | 
			
		||||
			 Defined in :c:type:`ipu3_uapi_obgrid_param`.
 | 
			
		||||
Linearization		 This algo block uses linearization parameters to
 | 
			
		||||
			 address non-linearity sensor effects. The Lookup table
 | 
			
		||||
			 table is defined in
 | 
			
		||||
			 :c:type:`ipu3_uapi_isp_lin_vmem_params`.
 | 
			
		||||
SHD			 Lens shading correction is used to correct spatial
 | 
			
		||||
			 non-uniformity of the pixel response due to optical
 | 
			
		||||
			 lens shading. This is done by applying a different gain
 | 
			
		||||
			 for each pixel. The gain, black level etc are
 | 
			
		||||
			 configured in :c:type:`ipu3_uapi_shd_config_static`.
 | 
			
		||||
BNR			 Bayer noise reduction block removes image noise by
 | 
			
		||||
			 applying a bilateral filter.
 | 
			
		||||
			 See :c:type:`ipu3_uapi_bnr_static_config` for details.
 | 
			
		||||
ANR			 Advanced Noise Reduction is a block based algorithm
 | 
			
		||||
			 that performs noise reduction in the Bayer domain. The
 | 
			
		||||
			 convolution matrix etc can be found in
 | 
			
		||||
			 :c:type:`ipu3_uapi_anr_config`.
 | 
			
		||||
Demosaicing		 Demosaicing converts raw sensor data in Bayer format
 | 
			
		||||
			 into RGB (Red, Green, Blue) presentation. Then add
 | 
			
		||||
			 outputs of estimation of Y channel for following stream
 | 
			
		||||
			 processing by Firmware. The struct is defined as
 | 
			
		||||
			 :c:type:`ipu3_uapi_dm_config`. (TODO)
 | 
			
		||||
Color Correction	 Color Correction algo transforms sensor specific color
 | 
			
		||||
			 space to the standard "sRGB" color space. This is done
 | 
			
		||||
			 by applying 3x3 matrix defined in
 | 
			
		||||
			 :c:type:`ipu3_uapi_ccm_mat_config`.
 | 
			
		||||
Gamma correction	 Gamma correction :c:type:`ipu3_uapi_gamma_config` is a
 | 
			
		||||
			 basic non-linear tone mapping correction that is
 | 
			
		||||
			 applied per pixel for each pixel component.
 | 
			
		||||
CSC			 Color space conversion transforms each pixel from the
 | 
			
		||||
			 RGB primary presentation to YUV (Y: brightness,
 | 
			
		||||
			 UV: Luminance) presentation. This is done by applying
 | 
			
		||||
			 a 3x3 matrix defined in
 | 
			
		||||
			 :c:type:`ipu3_uapi_csc_mat_config`
 | 
			
		||||
CDS			 Chroma down sampling
 | 
			
		||||
			 After the CSC is performed, the Chroma Down Sampling
 | 
			
		||||
			 is applied for a UV plane down sampling by a factor
 | 
			
		||||
			 of 2 in each direction for YUV 4:2:0 using a 4x2
 | 
			
		||||
			 configurable filter :c:type:`ipu3_uapi_cds_params`.
 | 
			
		||||
CHNR			 Chroma noise reduction
 | 
			
		||||
			 This block processes only the chrominance pixels and
 | 
			
		||||
			 performs noise reduction by cleaning the high
 | 
			
		||||
			 frequency noise.
 | 
			
		||||
			 See struct :c:type:`ipu3_uapi_yuvp1_chnr_config`.
 | 
			
		||||
TCC			 Total color correction as defined in struct
 | 
			
		||||
			 :c:type:`ipu3_uapi_yuvp2_tcc_static_config`.
 | 
			
		||||
XNR3			 eXtreme Noise Reduction V3 is the third revision of
 | 
			
		||||
			 noise reduction algorithm used to improve image
 | 
			
		||||
			 quality. This removes the low frequency noise in the
 | 
			
		||||
			 captured image. Two related structs are  being defined,
 | 
			
		||||
			 :c:type:`ipu3_uapi_isp_xnr3_params` for ISP data memory
 | 
			
		||||
			 and :c:type:`ipu3_uapi_isp_xnr3_vmem_params` for vector
 | 
			
		||||
			 memory.
 | 
			
		||||
TNR			 Temporal Noise Reduction block compares successive
 | 
			
		||||
			 frames in time to remove anomalies / noise in pixel
 | 
			
		||||
			 values. :c:type:`ipu3_uapi_isp_tnr3_vmem_params` and
 | 
			
		||||
			 :c:type:`ipu3_uapi_isp_tnr3_params` are defined for ISP
 | 
			
		||||
			 vector and data memory respectively.
 | 
			
		||||
======================== =======================================================
 | 
			
		||||
 | 
			
		||||
A few stages of the pipeline will be executed by firmware running on the ISP
 | 
			
		||||
processor, while many others will use a set of fixed hardware blocks also
 | 
			
		||||
called accelerator cluster (ACC) to crunch pixel data and produce statistics.
 | 
			
		||||
 | 
			
		||||
ACC parameters of individual algorithms, as defined by
 | 
			
		||||
:c:type:`ipu3_uapi_acc_param`, can be chosen to be applied by the user
 | 
			
		||||
space through struct :c:type:`ipu3_uapi_flags` embedded in
 | 
			
		||||
:c:type:`ipu3_uapi_params` structure. For parameters that are configured as
 | 
			
		||||
not enabled by the user space, the corresponding structs are ignored by the
 | 
			
		||||
driver, in which case the existing configuration of the algorithm will be
 | 
			
		||||
preserved.
 | 
			
		||||
 | 
			
		||||
Both 3A statistics and pipeline parameters described here are closely tied to
 | 
			
		||||
the underlying camera sub-system (CSS) APIs. They are usually consumed and
 | 
			
		||||
produced by dedicated user space libraries that comprise the important tuning
 | 
			
		||||
tools, thus freeing the developers from being bothered with the low level
 | 
			
		||||
hardware and algorithm details.
 | 
			
		||||
 | 
			
		||||
It should be noted that IPU3 DMA operations require the addresses of all data
 | 
			
		||||
structures (that includes both input and output) to be aligned on 32 byte
 | 
			
		||||
boundaries.
 | 
			
		||||
 | 
			
		||||
The meta data :c:type:`ipu3_uapi_params` will be sent to "ipu3-imgu parameters"
 | 
			
		||||
video node in ``V4L2_BUF_TYPE_META_CAPTURE`` format.
 | 
			
		||||
 | 
			
		||||
.. code-block:: c
 | 
			
		||||
 | 
			
		||||
	struct ipu3_uapi_params {
 | 
			
		||||
		/* Flags which of the settings below are to be applied */
 | 
			
		||||
		struct ipu3_uapi_flags use;
 | 
			
		||||
 | 
			
		||||
		/* Accelerator cluster parameters */
 | 
			
		||||
		struct ipu3_uapi_acc_param acc_param;
 | 
			
		||||
 | 
			
		||||
		/* ISP vector address space parameters */
 | 
			
		||||
		struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params;
 | 
			
		||||
		struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params;
 | 
			
		||||
		struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params;
 | 
			
		||||
 | 
			
		||||
		/* ISP data memory (DMEM) parameters */
 | 
			
		||||
		struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params;
 | 
			
		||||
		struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params;
 | 
			
		||||
 | 
			
		||||
		/* Optical black level compensation */
 | 
			
		||||
		struct ipu3_uapi_obgrid_param obgrid_param;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
Intel IPU3 ImgU uAPI data types
 | 
			
		||||
===============================
 | 
			
		||||
 | 
			
		||||
.. kernel-doc:: drivers/staging/media/ipu3/include/intel-ipu3.h
 | 
			
		||||
@ -258,6 +258,9 @@ specification the ioctl returns an ``EINVAL`` error code.
 | 
			
		||||
    * - ``V4L2_CAP_STREAMING``
 | 
			
		||||
      - 0x04000000
 | 
			
		||||
      - The device supports the :ref:`streaming <mmap>` I/O method.
 | 
			
		||||
    * - ``V4L2_CAP_META_OUTPUT``
 | 
			
		||||
      - 0x08000000
 | 
			
		||||
      - The device supports the :ref:`metadata` output interface.
 | 
			
		||||
    * - ``V4L2_CAP_TOUCH``
 | 
			
		||||
      - 0x10000000
 | 
			
		||||
      - This is a touch device.
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,7 @@ For more details see the file COPYING in the source distribution of Linux.
 | 
			
		||||
	davinci-vpbe
 | 
			
		||||
	fimc
 | 
			
		||||
	imx
 | 
			
		||||
	ipu3
 | 
			
		||||
	ivtv
 | 
			
		||||
	max2175
 | 
			
		||||
	meye
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										369
									
								
								Documentation/media/v4l-drivers/ipu3.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								Documentation/media/v4l-drivers/ipu3.rst
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,369 @@
 | 
			
		||||
.. include:: <isonum.txt>
 | 
			
		||||
 | 
			
		||||
===============================================================
 | 
			
		||||
Intel Image Processing Unit 3 (IPU3) Imaging Unit (ImgU) driver
 | 
			
		||||
===============================================================
 | 
			
		||||
 | 
			
		||||
Copyright |copy| 2018 Intel Corporation
 | 
			
		||||
 | 
			
		||||
Introduction
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
This file documents the Intel IPU3 (3rd generation Image Processing Unit)
 | 
			
		||||
Imaging Unit drivers located under drivers/media/pci/intel/ipu3 (CIO2) as well
 | 
			
		||||
as under drivers/staging/media/ipu3 (ImgU).
 | 
			
		||||
 | 
			
		||||
The Intel IPU3 found in certain Kaby Lake (as well as certain Sky Lake)
 | 
			
		||||
platforms (U/Y processor lines) is made up of two parts namely the Imaging Unit
 | 
			
		||||
(ImgU) and the CIO2 device (MIPI CSI2 receiver).
 | 
			
		||||
 | 
			
		||||
The CIO2 device receives the raw Bayer data from the sensors and outputs the
 | 
			
		||||
frames in a format that is specific to the IPU3 (for consumption by the IPU3
 | 
			
		||||
ImgU). The CIO2 driver is available as drivers/media/pci/intel/ipu3/ipu3-cio2*
 | 
			
		||||
and is enabled through the CONFIG_VIDEO_IPU3_CIO2 config option.
 | 
			
		||||
 | 
			
		||||
The Imaging Unit (ImgU) is responsible for processing images captured
 | 
			
		||||
by the IPU3 CIO2 device. The ImgU driver sources can be found under
 | 
			
		||||
drivers/staging/media/ipu3 directory. The driver is enabled through the
 | 
			
		||||
CONFIG_VIDEO_IPU3_IMGU config option.
 | 
			
		||||
 | 
			
		||||
The two driver modules are named ipu3_csi2 and ipu3_imgu, respectively.
 | 
			
		||||
 | 
			
		||||
The drivers has been tested on Kaby Lake platforms (U/Y processor lines).
 | 
			
		||||
 | 
			
		||||
Both of the drivers implement V4L2, Media Controller and V4L2 sub-device
 | 
			
		||||
interfaces. The IPU3 CIO2 driver supports camera sensors connected to the CIO2
 | 
			
		||||
MIPI CSI-2 interfaces through V4L2 sub-device sensor drivers.
 | 
			
		||||
 | 
			
		||||
CIO2
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
The CIO2 is represented as a single V4L2 subdev, which provides a V4L2 subdev
 | 
			
		||||
interface to the user space. There is a video node for each CSI-2 receiver,
 | 
			
		||||
with a single media controller interface for the entire device.
 | 
			
		||||
 | 
			
		||||
The CIO2 contains four independent capture channel, each with its own MIPI CSI-2
 | 
			
		||||
receiver and DMA engine. Each channel is modelled as a V4L2 sub-device exposed
 | 
			
		||||
to userspace as a V4L2 sub-device node and has two pads:
 | 
			
		||||
 | 
			
		||||
.. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}|
 | 
			
		||||
 | 
			
		||||
.. flat-table::
 | 
			
		||||
 | 
			
		||||
    * - pad
 | 
			
		||||
      - direction
 | 
			
		||||
      - purpose
 | 
			
		||||
 | 
			
		||||
    * - 0
 | 
			
		||||
      - sink
 | 
			
		||||
      - MIPI CSI-2 input, connected to the sensor subdev
 | 
			
		||||
 | 
			
		||||
    * - 1
 | 
			
		||||
      - source
 | 
			
		||||
      - Raw video capture, connected to the V4L2 video interface
 | 
			
		||||
 | 
			
		||||
The V4L2 video interfaces model the DMA engines. They are exposed to userspace
 | 
			
		||||
as V4L2 video device nodes.
 | 
			
		||||
 | 
			
		||||
Capturing frames in raw Bayer format
 | 
			
		||||
------------------------------------
 | 
			
		||||
 | 
			
		||||
CIO2 MIPI CSI2 receiver is used to capture frames (in packed raw Bayer format)
 | 
			
		||||
from the raw sensors connected to the CSI2 ports. The captured frames are used
 | 
			
		||||
as input to the ImgU driver.
 | 
			
		||||
 | 
			
		||||
Image processing using IPU3 ImgU requires tools such as raw2pnm [#f1]_, and
 | 
			
		||||
yavta [#f2]_ due to the following unique requirements and / or features specific
 | 
			
		||||
to IPU3.
 | 
			
		||||
 | 
			
		||||
-- The IPU3 CSI2 receiver outputs the captured frames from the sensor in packed
 | 
			
		||||
raw Bayer format that is specific to IPU3.
 | 
			
		||||
 | 
			
		||||
-- Multiple video nodes have to be operated simultaneously.
 | 
			
		||||
 | 
			
		||||
Let us take the example of ov5670 sensor connected to CSI2 port 0, for a
 | 
			
		||||
2592x1944 image capture.
 | 
			
		||||
 | 
			
		||||
Using the media contorller APIs, the ov5670 sensor is configured to send
 | 
			
		||||
frames in packed raw Bayer format to IPU3 CSI2 receiver.
 | 
			
		||||
 | 
			
		||||
# This example assumes /dev/media0 as the CIO2 media device
 | 
			
		||||
 | 
			
		||||
export MDEV=/dev/media0
 | 
			
		||||
 | 
			
		||||
# and that ov5670 sensor is connected to i2c bus 10 with address 0x36
 | 
			
		||||
 | 
			
		||||
export SDEV=$(media-ctl -d $MDEV -e "ov5670 10-0036")
 | 
			
		||||
 | 
			
		||||
# Establish the link for the media devices using media-ctl [#f3]_
 | 
			
		||||
media-ctl -d $MDEV -l "ov5670:0 -> ipu3-csi2 0:0[1]"
 | 
			
		||||
 | 
			
		||||
# Set the format for the media devices
 | 
			
		||||
media-ctl -d $MDEV -V "ov5670:0 [fmt:SGRBG10/2592x1944]"
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -V "ipu3-csi2 0:0 [fmt:SGRBG10/2592x1944]"
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -V "ipu3-csi2 0:1 [fmt:SGRBG10/2592x1944]"
 | 
			
		||||
 | 
			
		||||
Once the media pipeline is configured, desired sensor specific settings
 | 
			
		||||
(such as exposure and gain settings) can be set, using the yavta tool.
 | 
			
		||||
 | 
			
		||||
e.g
 | 
			
		||||
 | 
			
		||||
yavta -w 0x009e0903 444 $SDEV
 | 
			
		||||
 | 
			
		||||
yavta -w 0x009e0913 1024 $SDEV
 | 
			
		||||
 | 
			
		||||
yavta -w 0x009e0911 2046 $SDEV
 | 
			
		||||
 | 
			
		||||
Once the desired sensor settings are set, frame captures can be done as below.
 | 
			
		||||
 | 
			
		||||
e.g
 | 
			
		||||
 | 
			
		||||
yavta --data-prefix -u -c10 -n5 -I -s2592x1944 --file=/tmp/frame-#.bin \
 | 
			
		||||
      -f IPU3_SGRBG10 $(media-ctl -d $MDEV -e "ipu3-cio2 0")
 | 
			
		||||
 | 
			
		||||
With the above command, 10 frames are captured at 2592x1944 resolution, with
 | 
			
		||||
sGRBG10 format and output as IPU3_SGRBG10 format.
 | 
			
		||||
 | 
			
		||||
The captured frames are available as /tmp/frame-#.bin files.
 | 
			
		||||
 | 
			
		||||
ImgU
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
The ImgU is represented as two V4L2 subdevs, each of which provides a V4L2
 | 
			
		||||
subdev interface to the user space.
 | 
			
		||||
 | 
			
		||||
Each V4L2 subdev represents a pipe, which can support a maximum of 2 streams.
 | 
			
		||||
This helps to support advanced camera features like Continuous View Finder (CVF)
 | 
			
		||||
and Snapshot During Video(SDV).
 | 
			
		||||
 | 
			
		||||
The ImgU contains two independent pipes, each modelled as a V4L2 sub-device
 | 
			
		||||
exposed to userspace as a V4L2 sub-device node.
 | 
			
		||||
 | 
			
		||||
Each pipe has two sink pads and three source pads for the following purpose:
 | 
			
		||||
 | 
			
		||||
.. tabularcolumns:: |p{0.8cm}|p{4.0cm}|p{4.0cm}|
 | 
			
		||||
 | 
			
		||||
.. flat-table::
 | 
			
		||||
 | 
			
		||||
    * - pad
 | 
			
		||||
      - direction
 | 
			
		||||
      - purpose
 | 
			
		||||
 | 
			
		||||
    * - 0
 | 
			
		||||
      - sink
 | 
			
		||||
      - Input raw video stream
 | 
			
		||||
 | 
			
		||||
    * - 1
 | 
			
		||||
      - sink
 | 
			
		||||
      - Processing parameters
 | 
			
		||||
 | 
			
		||||
    * - 2
 | 
			
		||||
      - source
 | 
			
		||||
      - Output processed video stream
 | 
			
		||||
 | 
			
		||||
    * - 3
 | 
			
		||||
      - source
 | 
			
		||||
      - Output viewfinder video stream
 | 
			
		||||
 | 
			
		||||
    * - 4
 | 
			
		||||
      - source
 | 
			
		||||
      - 3A statistics
 | 
			
		||||
 | 
			
		||||
Each pad is connected to a corresponding V4L2 video interface, exposed to 
 | 
			
		||||
userspace as a V4L2 video device node.
 | 
			
		||||
 | 
			
		||||
Device operation
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
With ImgU, once the input video node ("ipu3-imgu 0/1":0, in
 | 
			
		||||
<entity>:<pad-number> format) is queued with buffer (in packed raw Bayer
 | 
			
		||||
format), ImgU starts processing the buffer and produces the video output in YUV
 | 
			
		||||
format and statistics output on respective output nodes. The driver is expected
 | 
			
		||||
to have buffers ready for all of parameter, output and statistics nodes, when
 | 
			
		||||
input video node is queued with buffer.
 | 
			
		||||
 | 
			
		||||
At a minimum, all of input, main output, 3A statistics and viewfinder
 | 
			
		||||
video nodes should be enabled for IPU3 to start image processing.
 | 
			
		||||
 | 
			
		||||
Each ImgU V4L2 subdev has the following set of video nodes.
 | 
			
		||||
 | 
			
		||||
input, output and viewfinder video nodes
 | 
			
		||||
----------------------------------------
 | 
			
		||||
 | 
			
		||||
The frames (in packed raw Bayer format specific to the IPU3) received by the
 | 
			
		||||
input video node is processed by the IPU3 Imaging Unit and are output to 2 video
 | 
			
		||||
nodes, with each targeting a different purpose (main output and viewfinder
 | 
			
		||||
output).
 | 
			
		||||
 | 
			
		||||
Details onand the Bayer format specific to the IPU3 can be found in
 | 
			
		||||
:ref:`v4l2-pix-fmt-ipu3-sbggr10`.
 | 
			
		||||
 | 
			
		||||
The driver supports V4L2 Video Capture Interface as defined at :ref:`devices`.
 | 
			
		||||
 | 
			
		||||
Only the multi-planar API is supported. More details can be found at
 | 
			
		||||
:ref:`planar-apis`.
 | 
			
		||||
 | 
			
		||||
Parameters video node
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
The parameters video node receives the ImgU algorithm parameters that are used
 | 
			
		||||
to configure how the ImgU algorithms process the image.
 | 
			
		||||
 | 
			
		||||
Details on processing parameters specific to the IPU3 can be found in
 | 
			
		||||
:ref:`v4l2-meta-fmt-params`.
 | 
			
		||||
 | 
			
		||||
3A statistics video node
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
3A statistics video node is used by the ImgU driver to output the 3A (auto
 | 
			
		||||
focus, auto exposure and auto white balance) statistics for the frames that are
 | 
			
		||||
being processed by the ImgU to user space applications. User space applications
 | 
			
		||||
can use this statistics data to compute the desired algorithm parameters for
 | 
			
		||||
the ImgU.
 | 
			
		||||
 | 
			
		||||
Configuring the Intel IPU3
 | 
			
		||||
==========================
 | 
			
		||||
 | 
			
		||||
The IPU3 ImgU pipelines can be configured using the Media Controller, defined at
 | 
			
		||||
:ref:`media_controller`.
 | 
			
		||||
 | 
			
		||||
Firmware binary selection
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
The firmware binary is selected using the V4L2_CID_INTEL_IPU3_MODE, currently
 | 
			
		||||
defined in drivers/staging/media/ipu3/include/intel-ipu3.h . "VIDEO" and "STILL"
 | 
			
		||||
modes are available.
 | 
			
		||||
 | 
			
		||||
Processing the image in raw Bayer format
 | 
			
		||||
----------------------------------------
 | 
			
		||||
 | 
			
		||||
Configuring ImgU V4L2 subdev for image processing
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
The ImgU V4L2 subdevs have to be configured with media controller APIs to have
 | 
			
		||||
all the video nodes setup correctly.
 | 
			
		||||
 | 
			
		||||
Let us take "ipu3-imgu 0" subdev as an example.
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -r
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -l "ipu3-imgu 0 input":0 -> "ipu3-imgu 0":0[1]
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -l "ipu3-imgu 0":2 -> "ipu3-imgu 0 output":0[1]
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -l "ipu3-imgu 0":3 -> "ipu3-imgu 0 viewfinder":0[1]
 | 
			
		||||
 | 
			
		||||
media-ctl -d $MDEV -l "ipu3-imgu 0":4 -> "ipu3-imgu 0 3a stat":0[1]
 | 
			
		||||
 | 
			
		||||
Also the pipe mode of the corresponding V4L2 subdev should be set as desired
 | 
			
		||||
(e.g 0 for video mode or 1 for still mode) through the control id 0x009819a1 as
 | 
			
		||||
below.
 | 
			
		||||
 | 
			
		||||
yavta -w "0x009819A1 1" /dev/v4l-subdev7
 | 
			
		||||
 | 
			
		||||
RAW Bayer frames go through the following ImgU pipeline HW blocks to have the
 | 
			
		||||
processed image output to the DDR memory.
 | 
			
		||||
 | 
			
		||||
RAW Bayer frame -> Input Feeder -> Bayer Down Scaling (BDS) -> Geometric
 | 
			
		||||
Distortion Correction (GDC) -> DDR
 | 
			
		||||
 | 
			
		||||
The ImgU V4L2 subdev has to be configured with the supported resolutions in all
 | 
			
		||||
the above HW blocks, for a given input resolution.
 | 
			
		||||
 | 
			
		||||
For a given supported resolution for an input frame, the Input Feeder, Bayer
 | 
			
		||||
Down Scaling and GDC blocks should be configured with the supported resolutions.
 | 
			
		||||
This information can be obtained by looking at the following IPU3 ImgU
 | 
			
		||||
configuration table.
 | 
			
		||||
 | 
			
		||||
https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master
 | 
			
		||||
 | 
			
		||||
Under baseboard-poppy/media-libs/cros-camera-hal-configs-poppy/files/gcss
 | 
			
		||||
directory, graph_settings_ov5670.xml can be used as an example.
 | 
			
		||||
 | 
			
		||||
The following steps prepare the ImgU pipeline for the image processing.
 | 
			
		||||
 | 
			
		||||
1. The ImgU V4L2 subdev data format should be set by using the
 | 
			
		||||
VIDIOC_SUBDEV_S_FMT on pad 0, using the GDC width and height obtained above.
 | 
			
		||||
 | 
			
		||||
2. The ImgU V4L2 subdev cropping should be set by using the
 | 
			
		||||
VIDIOC_SUBDEV_S_SELECTION on pad 0, with V4L2_SEL_TGT_CROP as the target,
 | 
			
		||||
using the input feeder height and width.
 | 
			
		||||
 | 
			
		||||
3. The ImgU V4L2 subdev composing should be set by using the
 | 
			
		||||
VIDIOC_SUBDEV_S_SELECTION on pad 0, with V4L2_SEL_TGT_COMPOSE as the target,
 | 
			
		||||
using the BDS height and width.
 | 
			
		||||
 | 
			
		||||
For the ov5670 example, for an input frame with a resolution of 2592x1944
 | 
			
		||||
(which is input to the ImgU subdev pad 0), the corresponding resolutions
 | 
			
		||||
for input feeder, BDS and GDC are 2592x1944, 2592x1944 and 2560x1920
 | 
			
		||||
respectively.
 | 
			
		||||
 | 
			
		||||
Once this is done, the received raw Bayer frames can be input to the ImgU
 | 
			
		||||
V4L2 subdev as below, using the open source application v4l2n [#f1]_.
 | 
			
		||||
 | 
			
		||||
For an image captured with 2592x1944 [#f4]_ resolution, with desired output
 | 
			
		||||
resolution as 2560x1920 and viewfinder resolution as 2560x1920, the following
 | 
			
		||||
v4l2n command can be used. This helps process the raw Bayer frames and produces
 | 
			
		||||
the desired results for the main output image and the viewfinder output, in NV12
 | 
			
		||||
format.
 | 
			
		||||
 | 
			
		||||
v4l2n --pipe=4 --load=/tmp/frame-#.bin --open=/dev/video4
 | 
			
		||||
--fmt=type:VIDEO_OUTPUT_MPLANE,width=2592,height=1944,pixelformat=0X47337069
 | 
			
		||||
--reqbufs=type:VIDEO_OUTPUT_MPLANE,count:1 --pipe=1 --output=/tmp/frames.out
 | 
			
		||||
--open=/dev/video5
 | 
			
		||||
--fmt=type:VIDEO_CAPTURE_MPLANE,width=2560,height=1920,pixelformat=NV12
 | 
			
		||||
--reqbufs=type:VIDEO_CAPTURE_MPLANE,count:1 --pipe=2 --output=/tmp/frames.vf
 | 
			
		||||
--open=/dev/video6
 | 
			
		||||
--fmt=type:VIDEO_CAPTURE_MPLANE,width=2560,height=1920,pixelformat=NV12
 | 
			
		||||
--reqbufs=type:VIDEO_CAPTURE_MPLANE,count:1 --pipe=3 --open=/dev/video7
 | 
			
		||||
--output=/tmp/frames.3A --fmt=type:META_CAPTURE,?
 | 
			
		||||
--reqbufs=count:1,type:META_CAPTURE --pipe=1,2,3,4 --stream=5
 | 
			
		||||
 | 
			
		||||
where /dev/video4, /dev/video5, /dev/video6 and /dev/video7 devices point to
 | 
			
		||||
input, output, viewfinder and 3A statistics video nodes respectively.
 | 
			
		||||
 | 
			
		||||
Converting the raw Bayer image into YUV domain
 | 
			
		||||
----------------------------------------------
 | 
			
		||||
 | 
			
		||||
The processed images after the above step, can be converted to YUV domain
 | 
			
		||||
as below.
 | 
			
		||||
 | 
			
		||||
Main output frames
 | 
			
		||||
~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
raw2pnm -x2560 -y1920 -fNV12 /tmp/frames.out /tmp/frames.out.ppm
 | 
			
		||||
 | 
			
		||||
where 2560x1920 is output resolution, NV12 is the video format, followed
 | 
			
		||||
by input frame and output PNM file.
 | 
			
		||||
 | 
			
		||||
Viewfinder output frames
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
raw2pnm -x2560 -y1920 -fNV12 /tmp/frames.vf /tmp/frames.vf.ppm
 | 
			
		||||
 | 
			
		||||
where 2560x1920 is output resolution, NV12 is the video format, followed
 | 
			
		||||
by input frame and output PNM file.
 | 
			
		||||
 | 
			
		||||
Example user space code for IPU3
 | 
			
		||||
================================
 | 
			
		||||
 | 
			
		||||
User space code that configures and uses IPU3 is available here.
 | 
			
		||||
 | 
			
		||||
https://chromium.googlesource.com/chromiumos/platform/arc-camera/+/master/
 | 
			
		||||
 | 
			
		||||
The source can be located under hal/intel directory.
 | 
			
		||||
 | 
			
		||||
References
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
.. [#f5] include/uapi/linux/intel-ipu3.h
 | 
			
		||||
 | 
			
		||||
.. [#f1] https://github.com/intel/nvt
 | 
			
		||||
 | 
			
		||||
.. [#f2] http://git.ideasonboard.org/yavta.git
 | 
			
		||||
 | 
			
		||||
.. [#f3] http://git.ideasonboard.org/?p=media-ctl.git;a=summary
 | 
			
		||||
 | 
			
		||||
.. [#f4] ImgU limitation requires an additional 16x16 for all input resolutions
 | 
			
		||||
@ -30,6 +30,7 @@ replace symbol V4L2_FIELD_TOP :c:type:`v4l2_field`
 | 
			
		||||
 | 
			
		||||
# Documented enum v4l2_buf_type
 | 
			
		||||
replace symbol V4L2_BUF_TYPE_META_CAPTURE :c:type:`v4l2_buf_type`
 | 
			
		||||
replace symbol V4L2_BUF_TYPE_META_OUTPUT :c:type:`v4l2_buf_type`
 | 
			
		||||
replace symbol V4L2_BUF_TYPE_SDR_CAPTURE :c:type:`v4l2_buf_type`
 | 
			
		||||
replace symbol V4L2_BUF_TYPE_SDR_OUTPUT :c:type:`v4l2_buf_type`
 | 
			
		||||
replace symbol V4L2_BUF_TYPE_SLICED_VBI_CAPTURE :c:type:`v4l2_buf_type`
 | 
			
		||||
@ -163,6 +164,7 @@ replace define V4L2_CAP_META_CAPTURE device-capabilities
 | 
			
		||||
replace define V4L2_CAP_READWRITE device-capabilities
 | 
			
		||||
replace define V4L2_CAP_ASYNCIO device-capabilities
 | 
			
		||||
replace define V4L2_CAP_STREAMING device-capabilities
 | 
			
		||||
replace define V4L2_CAP_META_OUTPUT device-capabilities
 | 
			
		||||
replace define V4L2_CAP_DEVICE_CAPS device-capabilities
 | 
			
		||||
replace define V4L2_CAP_TOUCH device-capabilities
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7645,6 +7645,14 @@ S:	Maintained
 | 
			
		||||
F:	drivers/media/pci/intel/ipu3/
 | 
			
		||||
F:	Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst
 | 
			
		||||
 | 
			
		||||
INTEL IPU3 CSI-2 IMGU DRIVER
 | 
			
		||||
M:	Sakari Ailus <sakari.ailus@linux.intel.com>
 | 
			
		||||
L:	linux-media@vger.kernel.org
 | 
			
		||||
S:	Maintained
 | 
			
		||||
F:	drivers/staging/media/ipu3/
 | 
			
		||||
F:	Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst
 | 
			
		||||
F:	Documentation/media/v4l-drivers/ipu3.rst
 | 
			
		||||
 | 
			
		||||
INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 | 
			
		||||
M:	Krzysztof Halasa <khalasa@piap.pl>
 | 
			
		||||
S:	Maintained
 | 
			
		||||
 | 
			
		||||
@ -709,6 +709,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 | 
			
		||||
		requested_sizes[0] = f->fmt.sdr.buffersize;
 | 
			
		||||
		break;
 | 
			
		||||
	case V4L2_BUF_TYPE_META_CAPTURE:
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		requested_sizes[0] = f->fmt.meta.buffersize;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
 | 
			
		||||
@ -323,6 +323,7 @@ static int __get_v4l2_format32(struct v4l2_format __user *p64,
 | 
			
		||||
		return copy_in_user(&p64->fmt.sdr, &p32->fmt.sdr,
 | 
			
		||||
				    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
 | 
			
		||||
	case V4L2_BUF_TYPE_META_CAPTURE:
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		return copy_in_user(&p64->fmt.meta, &p32->fmt.meta,
 | 
			
		||||
				    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
 | 
			
		||||
	default:
 | 
			
		||||
@ -392,6 +393,7 @@ static int __put_v4l2_format32(struct v4l2_format __user *p64,
 | 
			
		||||
		return copy_in_user(&p32->fmt.sdr, &p64->fmt.sdr,
 | 
			
		||||
				    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
 | 
			
		||||
	case V4L2_BUF_TYPE_META_CAPTURE:
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		return copy_in_user(&p32->fmt.meta, &p64->fmt.meta,
 | 
			
		||||
				    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
 | 
			
		||||
	default:
 | 
			
		||||
 | 
			
		||||
@ -597,7 +597,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 | 
			
		||||
			       ops->vidioc_enum_fmt_vid_overlay ||
 | 
			
		||||
			       ops->vidioc_enum_fmt_meta_cap)) ||
 | 
			
		||||
		    (is_tx && (ops->vidioc_enum_fmt_vid_out ||
 | 
			
		||||
			       ops->vidioc_enum_fmt_vid_out_mplane)))
 | 
			
		||||
			       ops->vidioc_enum_fmt_vid_out_mplane ||
 | 
			
		||||
			       ops->vidioc_enum_fmt_meta_out)))
 | 
			
		||||
			set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
 | 
			
		||||
		if ((is_rx && (ops->vidioc_g_fmt_vid_cap ||
 | 
			
		||||
			       ops->vidioc_g_fmt_vid_cap_mplane ||
 | 
			
		||||
@ -605,7 +606,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 | 
			
		||||
			       ops->vidioc_g_fmt_meta_cap)) ||
 | 
			
		||||
		    (is_tx && (ops->vidioc_g_fmt_vid_out ||
 | 
			
		||||
			       ops->vidioc_g_fmt_vid_out_mplane ||
 | 
			
		||||
			       ops->vidioc_g_fmt_vid_out_overlay)))
 | 
			
		||||
			       ops->vidioc_g_fmt_vid_out_overlay ||
 | 
			
		||||
			       ops->vidioc_g_fmt_meta_out)))
 | 
			
		||||
			 set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
 | 
			
		||||
		if ((is_rx && (ops->vidioc_s_fmt_vid_cap ||
 | 
			
		||||
			       ops->vidioc_s_fmt_vid_cap_mplane ||
 | 
			
		||||
@ -613,7 +615,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 | 
			
		||||
			       ops->vidioc_s_fmt_meta_cap)) ||
 | 
			
		||||
		    (is_tx && (ops->vidioc_s_fmt_vid_out ||
 | 
			
		||||
			       ops->vidioc_s_fmt_vid_out_mplane ||
 | 
			
		||||
			       ops->vidioc_s_fmt_vid_out_overlay)))
 | 
			
		||||
			       ops->vidioc_s_fmt_vid_out_overlay ||
 | 
			
		||||
			       ops->vidioc_s_fmt_meta_out)))
 | 
			
		||||
			 set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
 | 
			
		||||
		if ((is_rx && (ops->vidioc_try_fmt_vid_cap ||
 | 
			
		||||
			       ops->vidioc_try_fmt_vid_cap_mplane ||
 | 
			
		||||
@ -621,7 +624,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 | 
			
		||||
			       ops->vidioc_try_fmt_meta_cap)) ||
 | 
			
		||||
		    (is_tx && (ops->vidioc_try_fmt_vid_out ||
 | 
			
		||||
			       ops->vidioc_try_fmt_vid_out_mplane ||
 | 
			
		||||
			       ops->vidioc_try_fmt_vid_out_overlay)))
 | 
			
		||||
			       ops->vidioc_try_fmt_vid_out_overlay ||
 | 
			
		||||
			       ops->vidioc_try_fmt_meta_out)))
 | 
			
		||||
			 set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
 | 
			
		||||
		SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
 | 
			
		||||
		SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
 | 
			
		||||
 | 
			
		||||
@ -310,8 +310,8 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
 | 
			
		||||
		flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
 | 
			
		||||
			   V4L2_MBUS_PCLK_SAMPLE_FALLING);
 | 
			
		||||
		flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
 | 
			
		||||
			   V4L2_MBUS_DATA_ACTIVE_LOW);
 | 
			
		||||
		flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
 | 
			
		||||
			V4L2_MBUS_DATA_ACTIVE_LOW;
 | 
			
		||||
		pr_debug("data-active %s\n", v ? "high" : "low");
 | 
			
		||||
 | 
			
		||||
@ -194,6 +194,7 @@ const char *v4l2_type_names[] = {
 | 
			
		||||
	[V4L2_BUF_TYPE_SDR_CAPTURE]        = "sdr-cap",
 | 
			
		||||
	[V4L2_BUF_TYPE_SDR_OUTPUT]         = "sdr-out",
 | 
			
		||||
	[V4L2_BUF_TYPE_META_CAPTURE]       = "meta-cap",
 | 
			
		||||
	[V4L2_BUF_TYPE_META_OUTPUT]	   = "meta-out",
 | 
			
		||||
};
 | 
			
		||||
EXPORT_SYMBOL(v4l2_type_names);
 | 
			
		||||
 | 
			
		||||
@ -366,6 +367,7 @@ static void v4l_print_format(const void *arg, bool write_only)
 | 
			
		||||
			(sdr->pixelformat >> 24) & 0xff);
 | 
			
		||||
		break;
 | 
			
		||||
	case V4L2_BUF_TYPE_META_CAPTURE:
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		meta = &p->fmt.meta;
 | 
			
		||||
		pr_cont(", dataformat=%c%c%c%c, buffersize=%u\n",
 | 
			
		||||
			(meta->dataformat >>  0) & 0xff,
 | 
			
		||||
@ -999,6 +1001,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
 | 
			
		||||
		if (is_vid && is_rx && ops->vidioc_g_fmt_meta_cap)
 | 
			
		||||
			return 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		if (is_vid && is_tx && ops->vidioc_g_fmt_meta_out)
 | 
			
		||||
			return 0;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
@ -1410,6 +1416,11 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
 | 
			
		||||
			break;
 | 
			
		||||
		ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg);
 | 
			
		||||
		break;
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		if (unlikely(!ops->vidioc_enum_fmt_meta_out))
 | 
			
		||||
			break;
 | 
			
		||||
		ret = ops->vidioc_enum_fmt_meta_out(file, fh, arg);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		v4l_fill_fmtdesc(p);
 | 
			
		||||
@ -1488,6 +1499,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 | 
			
		||||
		return ops->vidioc_g_fmt_sdr_out(file, fh, arg);
 | 
			
		||||
	case V4L2_BUF_TYPE_META_CAPTURE:
 | 
			
		||||
		return ops->vidioc_g_fmt_meta_cap(file, fh, arg);
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		return ops->vidioc_g_fmt_meta_out(file, fh, arg);
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
@ -1601,6 +1614,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 | 
			
		||||
			break;
 | 
			
		||||
		CLEAR_AFTER_FIELD(p, fmt.meta);
 | 
			
		||||
		return ops->vidioc_s_fmt_meta_cap(file, fh, arg);
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		if (unlikely(!ops->vidioc_s_fmt_meta_out))
 | 
			
		||||
			break;
 | 
			
		||||
		CLEAR_AFTER_FIELD(p, fmt.meta);
 | 
			
		||||
		return ops->vidioc_s_fmt_meta_out(file, fh, arg);
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
@ -1693,6 +1711,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
 | 
			
		||||
			break;
 | 
			
		||||
		CLEAR_AFTER_FIELD(p, fmt.meta);
 | 
			
		||||
		return ops->vidioc_try_fmt_meta_cap(file, fh, arg);
 | 
			
		||||
	case V4L2_BUF_TYPE_META_OUTPUT:
 | 
			
		||||
		if (unlikely(!ops->vidioc_try_fmt_meta_out))
 | 
			
		||||
			break;
 | 
			
		||||
		CLEAR_AFTER_FIELD(p, fmt.meta);
 | 
			
		||||
		return ops->vidioc_try_fmt_meta_out(file, fh, arg);
 | 
			
		||||
	}
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,4 +39,6 @@ source "drivers/staging/media/tegra-vde/Kconfig"
 | 
			
		||||
 | 
			
		||||
source "drivers/staging/media/zoran/Kconfig"
 | 
			
		||||
 | 
			
		||||
source "drivers/staging/media/ipu3/Kconfig"
 | 
			
		||||
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
@ -9,3 +9,4 @@ obj-$(CONFIG_VIDEO_SUNXI)	+= sunxi/
 | 
			
		||||
obj-$(CONFIG_TEGRA_VDE)		+= tegra-vde/
 | 
			
		||||
obj-$(CONFIG_VIDEO_ZORAN)	+= zoran/
 | 
			
		||||
obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip/vpu/
 | 
			
		||||
obj-$(CONFIG_VIDEO_IPU3_IMGU)	+= ipu3/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								drivers/staging/media/ipu3/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								drivers/staging/media/ipu3/Kconfig
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
config VIDEO_IPU3_IMGU
 | 
			
		||||
	tristate "Intel ipu3-imgu driver"
 | 
			
		||||
	depends on PCI && VIDEO_V4L2
 | 
			
		||||
	depends on MEDIA_CONTROLLER && VIDEO_V4L2_SUBDEV_API
 | 
			
		||||
	depends on X86
 | 
			
		||||
	select IOMMU_IOVA
 | 
			
		||||
	select VIDEOBUF2_DMA_SG
 | 
			
		||||
	---help---
 | 
			
		||||
	  This is the Video4Linux2 driver for Intel IPU3 image processing unit,
 | 
			
		||||
	  found in Intel Skylake and Kaby Lake SoCs and used for processing
 | 
			
		||||
	  images and video.
 | 
			
		||||
 | 
			
		||||
	  Say Y or M here if you have a Skylake/Kaby Lake SoC with a MIPI
 | 
			
		||||
	  camera. The module will be called ipu3-imgu.
 | 
			
		||||
							
								
								
									
										11
									
								
								drivers/staging/media/ipu3/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								drivers/staging/media/ipu3/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
#
 | 
			
		||||
# Makefile for the IPU3 ImgU drivers
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
ipu3-imgu-objs += \
 | 
			
		||||
		ipu3-mmu.o ipu3-dmamap.o \
 | 
			
		||||
		ipu3-tables.o ipu3-css-pool.o \
 | 
			
		||||
		ipu3-css-fw.o ipu3-css-params.o \
 | 
			
		||||
		ipu3-css.o ipu3-v4l2.o ipu3.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3-imgu.o
 | 
			
		||||
							
								
								
									
										34
									
								
								drivers/staging/media/ipu3/TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								drivers/staging/media/ipu3/TODO
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
This is a list of things that need to be done to get this driver out of the
 | 
			
		||||
staging directory.
 | 
			
		||||
 | 
			
		||||
- Request API conversion. Remove of the dual pipeline and associate buffers
 | 
			
		||||
  as well as formats and the binary used to a request. Remove the
 | 
			
		||||
  opportunistic buffer management. (Sakari)
 | 
			
		||||
 | 
			
		||||
- Using ENABLED and IMMUTABLE link flags for the links where those are
 | 
			
		||||
  relevant. (Sakari)
 | 
			
		||||
 | 
			
		||||
- Prefix imgu for all public APIs, i.e. change ipu3_v4l2_register() to
 | 
			
		||||
  imgu_v4l2_register(). (Sakari)
 | 
			
		||||
 | 
			
		||||
- Use V4L2_CTRL_TYPE_MENU for dual-pipe mode control. (Sakari)
 | 
			
		||||
 | 
			
		||||
- IPU3 driver documentation (Laurent)
 | 
			
		||||
  Add diagram in driver rst to describe output capability.
 | 
			
		||||
  Comments on configuring v4l2 subdevs for CIO2 and ImgU.
 | 
			
		||||
 | 
			
		||||
- uAPI documentation:
 | 
			
		||||
  Further clarification on some ambiguities such as data type conversion of
 | 
			
		||||
  IEFD CU inputs. (Sakari)
 | 
			
		||||
  Move acronyms to doc-rst file. (Mauro)
 | 
			
		||||
 | 
			
		||||
- Switch to yavta from v4l2n in driver docs.
 | 
			
		||||
 | 
			
		||||
- Elaborate the functionality of different selection rectangles in driver
 | 
			
		||||
  documentation. This may require driver changes as well.
 | 
			
		||||
 | 
			
		||||
- More detailed documentation on calculating BDS, GCD etc. sizes needed.
 | 
			
		||||
 | 
			
		||||
- Document different operation modes, and which buffer queues are relevant
 | 
			
		||||
  in each mode. To process an image, which queues require a buffer an in
 | 
			
		||||
  which ones is it optional?
 | 
			
		||||
							
								
								
									
										2785
									
								
								drivers/staging/media/ipu3/include/intel-ipu3.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2785
									
								
								drivers/staging/media/ipu3/include/intel-ipu3.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2011
									
								
								drivers/staging/media/ipu3/ipu3-abi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2011
									
								
								drivers/staging/media/ipu3/ipu3-abi.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										265
									
								
								drivers/staging/media/ipu3/ipu3-css-fw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								drivers/staging/media/ipu3/ipu3-css-fw.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,265 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
// Copyright (C) 2018 Intel Corporation
 | 
			
		||||
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/firmware.h>
 | 
			
		||||
#include <linux/mm.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3-css.h"
 | 
			
		||||
#include "ipu3-css-fw.h"
 | 
			
		||||
#include "ipu3-dmamap.h"
 | 
			
		||||
 | 
			
		||||
static void ipu3_css_fw_show_binary(struct device *dev, struct imgu_fw_info *bi,
 | 
			
		||||
				    const char *name)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "found firmware binary type %i size %i name %s\n",
 | 
			
		||||
		bi->type, bi->blob.size, name);
 | 
			
		||||
	if (bi->type != IMGU_FW_ISP_FIRMWARE)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "    id %i mode %i bds 0x%x veceven %i/%i out_pins %i\n",
 | 
			
		||||
		bi->info.isp.sp.id, bi->info.isp.sp.pipeline.mode,
 | 
			
		||||
		bi->info.isp.sp.bds.supported_bds_factors,
 | 
			
		||||
		bi->info.isp.sp.enable.vf_veceven,
 | 
			
		||||
		bi->info.isp.sp.vf_dec.is_variable,
 | 
			
		||||
		bi->info.isp.num_output_pins);
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "    input (%i,%i)-(%i,%i) formats %s%s%s\n",
 | 
			
		||||
		bi->info.isp.sp.input.min_width,
 | 
			
		||||
		bi->info.isp.sp.input.min_height,
 | 
			
		||||
		bi->info.isp.sp.input.max_width,
 | 
			
		||||
		bi->info.isp.sp.input.max_height,
 | 
			
		||||
		bi->info.isp.sp.enable.input_yuv ? "yuv420 " : "",
 | 
			
		||||
		bi->info.isp.sp.enable.input_feeder ||
 | 
			
		||||
		bi->info.isp.sp.enable.input_raw ? "raw8 raw10 " : "",
 | 
			
		||||
		bi->info.isp.sp.enable.input_raw ? "raw12" : "");
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "    internal (%i,%i)\n",
 | 
			
		||||
		bi->info.isp.sp.internal.max_width,
 | 
			
		||||
		bi->info.isp.sp.internal.max_height);
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "    output (%i,%i)-(%i,%i) formats",
 | 
			
		||||
		bi->info.isp.sp.output.min_width,
 | 
			
		||||
		bi->info.isp.sp.output.min_height,
 | 
			
		||||
		bi->info.isp.sp.output.max_width,
 | 
			
		||||
		bi->info.isp.sp.output.max_height);
 | 
			
		||||
	for (i = 0; i < bi->info.isp.num_output_formats; i++)
 | 
			
		||||
		dev_dbg(dev, " %i", bi->info.isp.output_formats[i]);
 | 
			
		||||
	dev_dbg(dev, " vf");
 | 
			
		||||
	for (i = 0; i < bi->info.isp.num_vf_formats; i++)
 | 
			
		||||
		dev_dbg(dev, " %i", bi->info.isp.vf_formats[i]);
 | 
			
		||||
	dev_dbg(dev, "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int width = DIV_ROUND_UP(bi->info.isp.sp.internal.max_width,
 | 
			
		||||
					  IMGU_OBGRID_TILE_SIZE * 2) + 1;
 | 
			
		||||
	unsigned int height = DIV_ROUND_UP(bi->info.isp.sp.internal.max_height,
 | 
			
		||||
					   IMGU_OBGRID_TILE_SIZE * 2) + 1;
 | 
			
		||||
	unsigned int obgrid_size;
 | 
			
		||||
 | 
			
		||||
	width = ALIGN(width, IPU3_UAPI_ISP_VEC_ELEMS / 4);
 | 
			
		||||
	obgrid_size = PAGE_ALIGN(width * height *
 | 
			
		||||
				 sizeof(struct ipu3_uapi_obgrid_param)) *
 | 
			
		||||
				 bi->info.isp.sp.iterator.num_stripes;
 | 
			
		||||
	return obgrid_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ipu3_css_fw_pipeline_params(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
				  enum imgu_abi_param_class cls,
 | 
			
		||||
				  enum imgu_abi_memories mem,
 | 
			
		||||
				  struct imgu_fw_isp_parameter *par,
 | 
			
		||||
				  size_t par_size, void *binary_params)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_fw_info *bi =
 | 
			
		||||
		&css->fwp->binary_header[css->pipes[pipe].bindex];
 | 
			
		||||
 | 
			
		||||
	if (par->offset + par->size >
 | 
			
		||||
	    bi->info.isp.sp.mem_initializers.params[cls][mem].size)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (par->size != par_size)
 | 
			
		||||
		pr_warn("parameter size doesn't match defined size\n");
 | 
			
		||||
 | 
			
		||||
	if (par->size < par_size)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return binary_params + par->offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ipu3_css_fw_cleanup(struct ipu3_css *css)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_device *imgu = dev_get_drvdata(css->dev);
 | 
			
		||||
 | 
			
		||||
	if (css->binary) {
 | 
			
		||||
		unsigned int i;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < css->fwp->file_header.binary_nr; i++)
 | 
			
		||||
			ipu3_dmamap_free(imgu, &css->binary[i]);
 | 
			
		||||
		kfree(css->binary);
 | 
			
		||||
	}
 | 
			
		||||
	if (css->fw)
 | 
			
		||||
		release_firmware(css->fw);
 | 
			
		||||
 | 
			
		||||
	css->binary = NULL;
 | 
			
		||||
	css->fw = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ipu3_css_fw_init(struct ipu3_css *css)
 | 
			
		||||
{
 | 
			
		||||
	static const u32 BLOCK_MAX = 65536;
 | 
			
		||||
	struct imgu_device *imgu = dev_get_drvdata(css->dev);
 | 
			
		||||
	struct device *dev = css->dev;
 | 
			
		||||
	unsigned int i, j, binary_nr;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	r = request_firmware(&css->fw, IMGU_FW_NAME, css->dev);
 | 
			
		||||
	if (r)
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	/* Check and display fw header info */
 | 
			
		||||
 | 
			
		||||
	css->fwp = (struct imgu_fw_header *)css->fw->data;
 | 
			
		||||
	if (css->fw->size < sizeof(struct imgu_fw_header *) ||
 | 
			
		||||
	    css->fwp->file_header.h_size != sizeof(struct imgu_fw_bi_file_h))
 | 
			
		||||
		goto bad_fw;
 | 
			
		||||
	if (sizeof(struct imgu_fw_bi_file_h) +
 | 
			
		||||
	    css->fwp->file_header.binary_nr * sizeof(struct imgu_fw_info) >
 | 
			
		||||
	    css->fw->size)
 | 
			
		||||
		goto bad_fw;
 | 
			
		||||
 | 
			
		||||
	dev_info(dev, "loaded firmware version %.64s, %u binaries, %zu bytes\n",
 | 
			
		||||
		 css->fwp->file_header.version, css->fwp->file_header.binary_nr,
 | 
			
		||||
		 css->fw->size);
 | 
			
		||||
 | 
			
		||||
	/* Validate and display info on fw binaries */
 | 
			
		||||
 | 
			
		||||
	binary_nr = css->fwp->file_header.binary_nr;
 | 
			
		||||
 | 
			
		||||
	css->fw_bl = -1;
 | 
			
		||||
	css->fw_sp[0] = -1;
 | 
			
		||||
	css->fw_sp[1] = -1;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < binary_nr; i++) {
 | 
			
		||||
		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
 | 
			
		||||
		const char *name = (void *)css->fwp + bi->blob.prog_name_offset;
 | 
			
		||||
		size_t len;
 | 
			
		||||
 | 
			
		||||
		if (bi->blob.prog_name_offset >= css->fw->size)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
		len = strnlen(name, css->fw->size - bi->blob.prog_name_offset);
 | 
			
		||||
		if (len + 1 > css->fw->size - bi->blob.prog_name_offset ||
 | 
			
		||||
		    len + 1 >= IMGU_ABI_MAX_BINARY_NAME)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		if (bi->blob.size != bi->blob.text_size + bi->blob.icache_size
 | 
			
		||||
		    + bi->blob.data_size + bi->blob.padding_size)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
		if (bi->blob.offset + bi->blob.size > css->fw->size)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		if (bi->type == IMGU_FW_BOOTLOADER_FIRMWARE) {
 | 
			
		||||
			css->fw_bl = i;
 | 
			
		||||
			if (bi->info.bl.sw_state >= css->iomem_length ||
 | 
			
		||||
			    bi->info.bl.num_dma_cmds >= css->iomem_length ||
 | 
			
		||||
			    bi->info.bl.dma_cmd_list >= css->iomem_length)
 | 
			
		||||
				goto bad_fw;
 | 
			
		||||
		}
 | 
			
		||||
		if (bi->type == IMGU_FW_SP_FIRMWARE ||
 | 
			
		||||
		    bi->type == IMGU_FW_SP1_FIRMWARE) {
 | 
			
		||||
			css->fw_sp[bi->type == IMGU_FW_SP_FIRMWARE ? 0 : 1] = i;
 | 
			
		||||
			if (bi->info.sp.per_frame_data >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.init_dmem_data >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.host_sp_queue >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.isp_started >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.sw_state >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.sleep_mode >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.invalidate_tlb >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.host_sp_com >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.output + 12 >= css->iomem_length ||
 | 
			
		||||
			    bi->info.sp.host_sp_queues_initialized >=
 | 
			
		||||
			    css->iomem_length)
 | 
			
		||||
				goto bad_fw;
 | 
			
		||||
		}
 | 
			
		||||
		if (bi->type != IMGU_FW_ISP_FIRMWARE)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (bi->info.isp.sp.pipeline.mode >= IPU3_CSS_PIPE_ID_NUM)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		if (bi->info.isp.sp.iterator.num_stripes >
 | 
			
		||||
		    IPU3_UAPI_MAX_STRIPES)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		if (bi->info.isp.num_vf_formats > IMGU_ABI_FRAME_FORMAT_NUM ||
 | 
			
		||||
		    bi->info.isp.num_output_formats > IMGU_ABI_FRAME_FORMAT_NUM)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		for (j = 0; j < bi->info.isp.num_output_formats; j++)
 | 
			
		||||
			if (bi->info.isp.output_formats[j] < 0 ||
 | 
			
		||||
			    bi->info.isp.output_formats[j] >=
 | 
			
		||||
			    IMGU_ABI_FRAME_FORMAT_NUM)
 | 
			
		||||
				goto bad_fw;
 | 
			
		||||
		for (j = 0; j < bi->info.isp.num_vf_formats; j++)
 | 
			
		||||
			if (bi->info.isp.vf_formats[j] < 0 ||
 | 
			
		||||
			    bi->info.isp.vf_formats[j] >=
 | 
			
		||||
			    IMGU_ABI_FRAME_FORMAT_NUM)
 | 
			
		||||
				goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		if (bi->info.isp.sp.block.block_width <= 0 ||
 | 
			
		||||
		    bi->info.isp.sp.block.block_width > BLOCK_MAX ||
 | 
			
		||||
		    bi->info.isp.sp.block.output_block_height <= 0 ||
 | 
			
		||||
		    bi->info.isp.sp.block.output_block_height > BLOCK_MAX)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		if (bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]
 | 
			
		||||
		    + sizeof(struct imgu_fw_param_memory_offsets) >
 | 
			
		||||
		    css->fw->size ||
 | 
			
		||||
		    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG]
 | 
			
		||||
		    + sizeof(struct imgu_fw_config_memory_offsets) >
 | 
			
		||||
		    css->fw->size ||
 | 
			
		||||
		    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE]
 | 
			
		||||
		    + sizeof(struct imgu_fw_state_memory_offsets) >
 | 
			
		||||
		    css->fw->size)
 | 
			
		||||
			goto bad_fw;
 | 
			
		||||
 | 
			
		||||
		ipu3_css_fw_show_binary(dev, bi, name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (css->fw_bl == -1 || css->fw_sp[0] == -1 || css->fw_sp[1] == -1)
 | 
			
		||||
		goto bad_fw;
 | 
			
		||||
 | 
			
		||||
	/* Allocate and map fw binaries into IMGU */
 | 
			
		||||
 | 
			
		||||
	css->binary = kcalloc(binary_nr, sizeof(*css->binary), GFP_KERNEL);
 | 
			
		||||
	if (!css->binary) {
 | 
			
		||||
		r = -ENOMEM;
 | 
			
		||||
		goto error_out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < css->fwp->file_header.binary_nr; i++) {
 | 
			
		||||
		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
 | 
			
		||||
		void *blob = (void *)css->fwp + bi->blob.offset;
 | 
			
		||||
		size_t size = bi->blob.size;
 | 
			
		||||
 | 
			
		||||
		if (!ipu3_dmamap_alloc(imgu, &css->binary[i], size)) {
 | 
			
		||||
			r = -ENOMEM;
 | 
			
		||||
			goto error_out;
 | 
			
		||||
		}
 | 
			
		||||
		memcpy(css->binary[i].vaddr, blob, size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
bad_fw:
 | 
			
		||||
	dev_err(dev, "invalid firmware binary, size %u\n", (int)css->fw->size);
 | 
			
		||||
	r = -ENODEV;
 | 
			
		||||
 | 
			
		||||
error_out:
 | 
			
		||||
	ipu3_css_fw_cleanup(css);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										188
									
								
								drivers/staging/media/ipu3/ipu3-css-fw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								drivers/staging/media/ipu3/ipu3-css-fw.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,188 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_CSS_FW_H
 | 
			
		||||
#define __IPU3_CSS_FW_H
 | 
			
		||||
 | 
			
		||||
/******************* Firmware file definitions *******************/
 | 
			
		||||
 | 
			
		||||
#define IMGU_FW_NAME			"intel/ipu3-fw.bin"
 | 
			
		||||
 | 
			
		||||
typedef u32 imgu_fw_ptr;
 | 
			
		||||
 | 
			
		||||
enum imgu_fw_type {
 | 
			
		||||
	IMGU_FW_SP_FIRMWARE,	/* Firmware for the SP */
 | 
			
		||||
	IMGU_FW_SP1_FIRMWARE,	/* Firmware for the SP1 */
 | 
			
		||||
	IMGU_FW_ISP_FIRMWARE,	/* Firmware for the ISP */
 | 
			
		||||
	IMGU_FW_BOOTLOADER_FIRMWARE,	/* Firmware for the BootLoader */
 | 
			
		||||
	IMGU_FW_ACC_FIRMWARE	/* Firmware for accelerations */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum imgu_fw_acc_type {
 | 
			
		||||
	IMGU_FW_ACC_NONE,	/* Normal binary */
 | 
			
		||||
	IMGU_FW_ACC_OUTPUT,	/* Accelerator stage on output frame */
 | 
			
		||||
	IMGU_FW_ACC_VIEWFINDER,	/* Accelerator stage on viewfinder frame */
 | 
			
		||||
	IMGU_FW_ACC_STANDALONE,	/* Stand-alone acceleration */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_isp_parameter {
 | 
			
		||||
	u32 offset;		/* Offset in isp_<mem> config, params, etc. */
 | 
			
		||||
	u32 size;		/* Disabled if 0 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_param_memory_offsets {
 | 
			
		||||
	struct {
 | 
			
		||||
		struct imgu_fw_isp_parameter lin;	/* lin_vmem_params */
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr3;	/* tnr3_vmem_params */
 | 
			
		||||
		struct imgu_fw_isp_parameter xnr3;	/* xnr3_vmem_params */
 | 
			
		||||
	} vmem;
 | 
			
		||||
	struct {
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr;
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr3;	/* tnr3_params */
 | 
			
		||||
		struct imgu_fw_isp_parameter xnr3;	/* xnr3_params */
 | 
			
		||||
		struct imgu_fw_isp_parameter plane_io_config;	/* 192 bytes */
 | 
			
		||||
		struct imgu_fw_isp_parameter rgbir;	/* rgbir_params */
 | 
			
		||||
	} dmem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_config_memory_offsets {
 | 
			
		||||
	struct {
 | 
			
		||||
		struct imgu_fw_isp_parameter iterator;
 | 
			
		||||
		struct imgu_fw_isp_parameter dvs;
 | 
			
		||||
		struct imgu_fw_isp_parameter output;
 | 
			
		||||
		struct imgu_fw_isp_parameter raw;
 | 
			
		||||
		struct imgu_fw_isp_parameter input_yuv;
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr;
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr3;
 | 
			
		||||
		struct imgu_fw_isp_parameter ref;
 | 
			
		||||
	} dmem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_state_memory_offsets {
 | 
			
		||||
	struct {
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr;
 | 
			
		||||
		struct imgu_fw_isp_parameter tnr3;
 | 
			
		||||
		struct imgu_fw_isp_parameter ref;
 | 
			
		||||
	} dmem;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union imgu_fw_all_memory_offsets {
 | 
			
		||||
	struct {
 | 
			
		||||
		u64 imgu_fw_mem_offsets[3]; /* params, config, state */
 | 
			
		||||
	} offsets;
 | 
			
		||||
	struct {
 | 
			
		||||
		u64 ptr;
 | 
			
		||||
	} array[IMGU_ABI_PARAM_CLASS_NUM];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_binary_xinfo {
 | 
			
		||||
	/* Part that is of interest to the SP. */
 | 
			
		||||
	struct imgu_abi_binary_info sp;
 | 
			
		||||
 | 
			
		||||
	/* Rest of the binary info, only interesting to the host. */
 | 
			
		||||
	u32 type;	/* enum imgu_fw_acc_type */
 | 
			
		||||
 | 
			
		||||
	u32 num_output_formats __aligned(8);
 | 
			
		||||
	u32 output_formats[IMGU_ABI_FRAME_FORMAT_NUM];	/* enum frame_format */
 | 
			
		||||
 | 
			
		||||
	/* number of supported vf formats */
 | 
			
		||||
	u32 num_vf_formats __aligned(8);
 | 
			
		||||
	/* types of supported vf formats */
 | 
			
		||||
	u32 vf_formats[IMGU_ABI_FRAME_FORMAT_NUM];	/* enum frame_format */
 | 
			
		||||
	u8 num_output_pins;
 | 
			
		||||
	imgu_fw_ptr xmem_addr;
 | 
			
		||||
 | 
			
		||||
	u64 imgu_fw_blob_descr_ptr __aligned(8);
 | 
			
		||||
	u32 blob_index __aligned(8);
 | 
			
		||||
	union imgu_fw_all_memory_offsets mem_offsets __aligned(8);
 | 
			
		||||
	struct imgu_fw_binary_xinfo *next __aligned(8);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_sp_info {
 | 
			
		||||
	u32 init_dmem_data;	/* data sect config, stored to dmem */
 | 
			
		||||
	u32 per_frame_data;	/* Per frame data, stored to dmem */
 | 
			
		||||
	u32 group;		/* Per pipeline data, loaded by dma */
 | 
			
		||||
	u32 output;		/* SP output data, loaded by dmem */
 | 
			
		||||
	u32 host_sp_queue;	/* Host <-> SP queues */
 | 
			
		||||
	u32 host_sp_com;	/* Host <-> SP commands */
 | 
			
		||||
	u32 isp_started;	/* P'ed from sensor thread, csim only */
 | 
			
		||||
	u32 sw_state;		/* Polled from css, enum imgu_abi_sp_swstate */
 | 
			
		||||
	u32 host_sp_queues_initialized;	/* Polled from the SP */
 | 
			
		||||
	u32 sleep_mode;		/* different mode to halt SP */
 | 
			
		||||
	u32 invalidate_tlb;	/* inform SP to invalidate mmu TLB */
 | 
			
		||||
	u32 debug_buffer_ddr_address;	/* the addr of DDR debug queue */
 | 
			
		||||
 | 
			
		||||
	/* input system perf count array */
 | 
			
		||||
	u32 perf_counter_input_system_error;
 | 
			
		||||
	u32 threads_stack;	/* sp thread's stack pointers */
 | 
			
		||||
	u32 threads_stack_size;	/* sp thread's stack sizes */
 | 
			
		||||
	u32 curr_binary_id;	/* current binary id */
 | 
			
		||||
	u32 raw_copy_line_count;	/* raw copy line counter */
 | 
			
		||||
	u32 ddr_parameter_address;	/* acc param ddrptr, sp dmem */
 | 
			
		||||
	u32 ddr_parameter_size;	/* acc param size, sp dmem */
 | 
			
		||||
	/* Entry functions */
 | 
			
		||||
	u32 sp_entry;		/* The SP entry function */
 | 
			
		||||
	u32 tagger_frames_addr;	/* Base address of tagger state */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_bl_info {
 | 
			
		||||
	u32 num_dma_cmds;	/* Number of cmds sent by CSS */
 | 
			
		||||
	u32 dma_cmd_list;	/* Dma command list sent by CSS */
 | 
			
		||||
	u32 sw_state;		/* Polled from css, enum imgu_abi_bl_swstate */
 | 
			
		||||
	/* Entry functions */
 | 
			
		||||
	u32 bl_entry;		/* The SP entry function */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_acc_info {
 | 
			
		||||
	u32 per_frame_data;	/* Dummy for now */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
union imgu_fw_union {
 | 
			
		||||
	struct imgu_fw_binary_xinfo isp;	/* ISP info */
 | 
			
		||||
	struct imgu_fw_sp_info sp;	/* SP info */
 | 
			
		||||
	struct imgu_fw_sp_info sp1;	/* SP1 info */
 | 
			
		||||
	struct imgu_fw_bl_info bl;	/* Bootloader info */
 | 
			
		||||
	struct imgu_fw_acc_info acc;	/* Accelerator info */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_info {
 | 
			
		||||
	size_t header_size;	/* size of fw header */
 | 
			
		||||
	u32 type __aligned(8);	/* enum imgu_fw_type */
 | 
			
		||||
	union imgu_fw_union info;	/* Binary info */
 | 
			
		||||
	struct imgu_abi_blob_info blob;	/* Blob info */
 | 
			
		||||
	/* Dynamic part */
 | 
			
		||||
	u64 next;
 | 
			
		||||
 | 
			
		||||
	u32 loaded __aligned(8);	/* Firmware has been loaded */
 | 
			
		||||
	const u64 isp_code __aligned(8);	/* ISP pointer to code */
 | 
			
		||||
	/* Firmware handle between user space and kernel */
 | 
			
		||||
	u32 handle __aligned(8);
 | 
			
		||||
	/* Sections to copy from/to ISP */
 | 
			
		||||
	struct imgu_abi_isp_param_segments mem_initializers;
 | 
			
		||||
	/* Initializer for local ISP memories */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_bi_file_h {
 | 
			
		||||
	char version[64];	/* branch tag + week day + time */
 | 
			
		||||
	int binary_nr;		/* Number of binaries */
 | 
			
		||||
	unsigned int h_size;	/* sizeof(struct imgu_fw_bi_file_h) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_fw_header {
 | 
			
		||||
	struct imgu_fw_bi_file_h file_header;
 | 
			
		||||
	struct imgu_fw_info binary_header[1];	/* binary_nr items */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/******************* Firmware functions *******************/
 | 
			
		||||
 | 
			
		||||
int ipu3_css_fw_init(struct ipu3_css *css);
 | 
			
		||||
void ipu3_css_fw_cleanup(struct ipu3_css *css);
 | 
			
		||||
 | 
			
		||||
unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi);
 | 
			
		||||
void *ipu3_css_fw_pipeline_params(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
				  enum imgu_abi_param_class cls,
 | 
			
		||||
				  enum imgu_abi_memories mem,
 | 
			
		||||
				  struct imgu_fw_isp_parameter *par,
 | 
			
		||||
				  size_t par_size, void *binary_params);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										2943
									
								
								drivers/staging/media/ipu3/ipu3-css-params.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2943
									
								
								drivers/staging/media/ipu3/ipu3-css-params.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										28
									
								
								drivers/staging/media/ipu3/ipu3-css-params.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								drivers/staging/media/ipu3/ipu3-css-params.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_PARAMS_H
 | 
			
		||||
#define __IPU3_PARAMS_H
 | 
			
		||||
 | 
			
		||||
int ipu3_css_cfg_acc(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
		     struct ipu3_uapi_flags *use,
 | 
			
		||||
		     struct imgu_abi_acc_param *acc,
 | 
			
		||||
		     struct imgu_abi_acc_param *acc_old,
 | 
			
		||||
		     struct ipu3_uapi_acc_param *acc_user);
 | 
			
		||||
 | 
			
		||||
int ipu3_css_cfg_vmem0(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
		       struct ipu3_uapi_flags *use,
 | 
			
		||||
		       void *vmem0, void *vmem0_old,
 | 
			
		||||
		       struct ipu3_uapi_params *user);
 | 
			
		||||
 | 
			
		||||
int ipu3_css_cfg_dmem0(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
		       struct ipu3_uapi_flags *use,
 | 
			
		||||
		       void *dmem0, void *dmem0_old,
 | 
			
		||||
		       struct ipu3_uapi_params *user);
 | 
			
		||||
 | 
			
		||||
void ipu3_css_cfg_gdc_table(struct imgu_abi_gdc_warp_param *gdc,
 | 
			
		||||
			    int frame_in_x, int frame_in_y,
 | 
			
		||||
			    int frame_out_x, int frame_out_y,
 | 
			
		||||
			    int env_w, int env_h);
 | 
			
		||||
 | 
			
		||||
#endif /*__IPU3_PARAMS_H */
 | 
			
		||||
							
								
								
									
										100
									
								
								drivers/staging/media/ipu3/ipu3-css-pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								drivers/staging/media/ipu3/ipu3-css-pool.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
// Copyright (C) 2018 Intel Corporation
 | 
			
		||||
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3.h"
 | 
			
		||||
#include "ipu3-css-pool.h"
 | 
			
		||||
#include "ipu3-dmamap.h"
 | 
			
		||||
 | 
			
		||||
int ipu3_css_dma_buffer_resize(struct imgu_device *imgu,
 | 
			
		||||
			       struct ipu3_css_map *map, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	if (map->size < size && map->vaddr) {
 | 
			
		||||
		dev_warn(&imgu->pci_dev->dev, "dma buf resized from %zu to %zu",
 | 
			
		||||
			 map->size, size);
 | 
			
		||||
 | 
			
		||||
		ipu3_dmamap_free(imgu, map);
 | 
			
		||||
		if (!ipu3_dmamap_alloc(imgu, map, size))
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ipu3_css_pool_cleanup(struct imgu_device *imgu, struct ipu3_css_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++)
 | 
			
		||||
		ipu3_dmamap_free(imgu, &pool->entry[i].param);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ipu3_css_pool_init(struct imgu_device *imgu, struct ipu3_css_pool *pool,
 | 
			
		||||
		       size_t size)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++) {
 | 
			
		||||
		pool->entry[i].valid = false;
 | 
			
		||||
		if (size == 0) {
 | 
			
		||||
			pool->entry[i].param.vaddr = NULL;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!ipu3_dmamap_alloc(imgu, &pool->entry[i].param, size))
 | 
			
		||||
			goto fail;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool->last = IPU3_CSS_POOL_SIZE;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	ipu3_css_pool_cleanup(imgu, pool);
 | 
			
		||||
	return -ENOMEM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Allocate a new parameter via recycling the oldest entry in the pool.
 | 
			
		||||
 */
 | 
			
		||||
void ipu3_css_pool_get(struct ipu3_css_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	/* Get the oldest entry */
 | 
			
		||||
	u32 n = (pool->last + 1) % IPU3_CSS_POOL_SIZE;
 | 
			
		||||
 | 
			
		||||
	pool->entry[n].valid = true;
 | 
			
		||||
	pool->last = n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Undo, for all practical purposes, the effect of pool_get().
 | 
			
		||||
 */
 | 
			
		||||
void ipu3_css_pool_put(struct ipu3_css_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	pool->entry[pool->last].valid = false;
 | 
			
		||||
	pool->last = (pool->last + IPU3_CSS_POOL_SIZE - 1) % IPU3_CSS_POOL_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_css_pool_last - Retrieve the nth pool entry from last
 | 
			
		||||
 *
 | 
			
		||||
 * @pool: a pointer to &struct ipu3_css_pool.
 | 
			
		||||
 * @n: the distance to the last index.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *  The nth entry from last or null map to indicate no frame stored.
 | 
			
		||||
 */
 | 
			
		||||
const struct ipu3_css_map *
 | 
			
		||||
ipu3_css_pool_last(struct ipu3_css_pool *pool, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	static const struct ipu3_css_map null_map = { 0 };
 | 
			
		||||
	int i = (pool->last + IPU3_CSS_POOL_SIZE - n) % IPU3_CSS_POOL_SIZE;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(n >= IPU3_CSS_POOL_SIZE);
 | 
			
		||||
 | 
			
		||||
	if (!pool->entry[i].valid)
 | 
			
		||||
		return &null_map;
 | 
			
		||||
 | 
			
		||||
	return &pool->entry[i].param;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								drivers/staging/media/ipu3/ipu3-css-pool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								drivers/staging/media/ipu3/ipu3-css-pool.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_UTIL_H
 | 
			
		||||
#define __IPU3_UTIL_H
 | 
			
		||||
 | 
			
		||||
struct device;
 | 
			
		||||
struct imgu_device;
 | 
			
		||||
 | 
			
		||||
#define IPU3_CSS_POOL_SIZE		4
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_css_map - store DMA mapping info for buffer
 | 
			
		||||
 *
 | 
			
		||||
 * @size:		size of the buffer in bytes.
 | 
			
		||||
 * @vaddr:		kernel virtual address.
 | 
			
		||||
 * @daddr:		iova dma address to access IPU3.
 | 
			
		||||
 * @vma:		private, a pointer to &struct vm_struct,
 | 
			
		||||
 *			used for ipu3_dmamap_free.
 | 
			
		||||
 */
 | 
			
		||||
struct ipu3_css_map {
 | 
			
		||||
	size_t size;
 | 
			
		||||
	void *vaddr;
 | 
			
		||||
	dma_addr_t daddr;
 | 
			
		||||
	struct vm_struct *vma;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_css_pool - circular buffer pool definition
 | 
			
		||||
 *
 | 
			
		||||
 * @entry:		array with IPU3_CSS_POOL_SIZE elements.
 | 
			
		||||
 * @entry.param:	a &struct ipu3_css_map for storing the mem mapping.
 | 
			
		||||
 * @entry.valid:	used to mark if the entry has valid data.
 | 
			
		||||
 * @last:		write pointer, initialized to IPU3_CSS_POOL_SIZE.
 | 
			
		||||
 */
 | 
			
		||||
struct ipu3_css_pool {
 | 
			
		||||
	struct {
 | 
			
		||||
		struct ipu3_css_map param;
 | 
			
		||||
		bool valid;
 | 
			
		||||
	} entry[IPU3_CSS_POOL_SIZE];
 | 
			
		||||
	u32 last;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int ipu3_css_dma_buffer_resize(struct imgu_device *imgu,
 | 
			
		||||
			       struct ipu3_css_map *map, size_t size);
 | 
			
		||||
void ipu3_css_pool_cleanup(struct imgu_device *imgu,
 | 
			
		||||
			   struct ipu3_css_pool *pool);
 | 
			
		||||
int ipu3_css_pool_init(struct imgu_device *imgu, struct ipu3_css_pool *pool,
 | 
			
		||||
		       size_t size);
 | 
			
		||||
void ipu3_css_pool_get(struct ipu3_css_pool *pool);
 | 
			
		||||
void ipu3_css_pool_put(struct ipu3_css_pool *pool);
 | 
			
		||||
const struct ipu3_css_map *ipu3_css_pool_last(struct ipu3_css_pool *pool,
 | 
			
		||||
					      u32 last);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										2391
									
								
								drivers/staging/media/ipu3/ipu3-css.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2391
									
								
								drivers/staging/media/ipu3/ipu3-css.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										213
									
								
								drivers/staging/media/ipu3/ipu3-css.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								drivers/staging/media/ipu3/ipu3-css.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,213 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_CSS_H
 | 
			
		||||
#define __IPU3_CSS_H
 | 
			
		||||
 | 
			
		||||
#include <linux/videodev2.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3-abi.h"
 | 
			
		||||
#include "ipu3-css-pool.h"
 | 
			
		||||
 | 
			
		||||
/* 2 stages for split isp pipeline, 1 for scaling */
 | 
			
		||||
#define IMGU_NUM_SP			2
 | 
			
		||||
#define IMGU_MAX_PIPELINE_NUM		20
 | 
			
		||||
#define IMGU_MAX_PIPE_NUM		2
 | 
			
		||||
 | 
			
		||||
/* For DVS etc., format FRAME_FMT_YUV420_16 */
 | 
			
		||||
#define IPU3_CSS_AUX_FRAME_REF		0
 | 
			
		||||
/* For temporal noise reduction DVS etc., format FRAME_FMT_YUV_LINE */
 | 
			
		||||
#define IPU3_CSS_AUX_FRAME_TNR		1
 | 
			
		||||
#define IPU3_CSS_AUX_FRAME_TYPES	2	/* REF and TNR */
 | 
			
		||||
#define IPU3_CSS_AUX_FRAMES		2	/* 2 for REF and 2 for TNR */
 | 
			
		||||
 | 
			
		||||
#define IPU3_CSS_QUEUE_IN		0
 | 
			
		||||
#define IPU3_CSS_QUEUE_PARAMS		1
 | 
			
		||||
#define IPU3_CSS_QUEUE_OUT		2
 | 
			
		||||
#define IPU3_CSS_QUEUE_VF		3
 | 
			
		||||
#define IPU3_CSS_QUEUE_STAT_3A		4
 | 
			
		||||
#define IPU3_CSS_QUEUES			5
 | 
			
		||||
 | 
			
		||||
#define IPU3_CSS_RECT_EFFECTIVE		0	/* Effective resolution */
 | 
			
		||||
#define IPU3_CSS_RECT_BDS		1	/* Resolution after BDS */
 | 
			
		||||
#define IPU3_CSS_RECT_ENVELOPE		2	/* DVS envelope size */
 | 
			
		||||
#define IPU3_CSS_RECT_GDC		3	/* gdc output res */
 | 
			
		||||
#define IPU3_CSS_RECTS			4	/* number of rects */
 | 
			
		||||
 | 
			
		||||
#define IA_CSS_BINARY_MODE_PRIMARY	2
 | 
			
		||||
#define IA_CSS_BINARY_MODE_VIDEO	3
 | 
			
		||||
#define IPU3_CSS_DEFAULT_BINARY		3	/* default binary index */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The pipe id type, distinguishes the kind of pipes that
 | 
			
		||||
 * can be run in parallel.
 | 
			
		||||
 */
 | 
			
		||||
enum ipu3_css_pipe_id {
 | 
			
		||||
	IPU3_CSS_PIPE_ID_PREVIEW,
 | 
			
		||||
	IPU3_CSS_PIPE_ID_COPY,
 | 
			
		||||
	IPU3_CSS_PIPE_ID_VIDEO,
 | 
			
		||||
	IPU3_CSS_PIPE_ID_CAPTURE,
 | 
			
		||||
	IPU3_CSS_PIPE_ID_YUVPP,
 | 
			
		||||
	IPU3_CSS_PIPE_ID_ACC,
 | 
			
		||||
	IPU3_CSS_PIPE_ID_NUM
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_resolution {
 | 
			
		||||
	u32 w;
 | 
			
		||||
	u32 h;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ipu3_css_buffer_state {
 | 
			
		||||
	IPU3_CSS_BUFFER_NEW,	/* Not yet queued */
 | 
			
		||||
	IPU3_CSS_BUFFER_QUEUED,	/* Queued, waiting to be filled */
 | 
			
		||||
	IPU3_CSS_BUFFER_DONE,	/* Finished processing, removed from queue */
 | 
			
		||||
	IPU3_CSS_BUFFER_FAILED,	/* Was not processed, removed from queue */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_buffer {
 | 
			
		||||
	/* Private fields: user doesn't touch */
 | 
			
		||||
	dma_addr_t daddr;
 | 
			
		||||
	unsigned int queue;
 | 
			
		||||
	enum ipu3_css_buffer_state state;
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	u8 queue_pos;
 | 
			
		||||
	unsigned int pipe;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_format {
 | 
			
		||||
	u32 pixelformat;
 | 
			
		||||
	enum v4l2_colorspace colorspace;
 | 
			
		||||
	enum imgu_abi_frame_format frame_format;
 | 
			
		||||
	enum imgu_abi_bayer_order bayer_order;
 | 
			
		||||
	enum imgu_abi_osys_format osys_format;
 | 
			
		||||
	enum imgu_abi_osys_tiling osys_tiling;
 | 
			
		||||
	u32 bytesperpixel_num;	/* Bytes per pixel in first plane * 50 */
 | 
			
		||||
	u8 bit_depth;		/* Effective bits per pixel */
 | 
			
		||||
	u8 chroma_decim;	/* Chroma plane decimation, 0=no chroma plane */
 | 
			
		||||
	u8 width_align;		/* Alignment requirement for width_pad */
 | 
			
		||||
	u8 flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_queue {
 | 
			
		||||
	union {
 | 
			
		||||
		struct v4l2_pix_format_mplane mpix;
 | 
			
		||||
		struct v4l2_meta_format	meta;
 | 
			
		||||
 | 
			
		||||
	} fmt;
 | 
			
		||||
	const struct ipu3_css_format *css_fmt;
 | 
			
		||||
	unsigned int width_pad;
 | 
			
		||||
	struct list_head bufs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_pipe {
 | 
			
		||||
	enum ipu3_css_pipe_id pipe_id;
 | 
			
		||||
	unsigned int bindex;
 | 
			
		||||
 | 
			
		||||
	struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
 | 
			
		||||
	struct v4l2_rect rect[IPU3_CSS_RECTS];
 | 
			
		||||
 | 
			
		||||
	bool vf_output_en;
 | 
			
		||||
	/* Protect access to queue[IPU3_CSS_QUEUES] */
 | 
			
		||||
	spinlock_t qlock;
 | 
			
		||||
 | 
			
		||||
	/* Data structures shared with IMGU and driver, always allocated */
 | 
			
		||||
	struct ipu3_css_map sp_ddr_ptrs;
 | 
			
		||||
	struct ipu3_css_map xmem_sp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
 | 
			
		||||
					    [IMGU_ABI_MAX_STAGES];
 | 
			
		||||
	struct ipu3_css_map xmem_isp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
 | 
			
		||||
					    [IMGU_ABI_MAX_STAGES];
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Data structures shared with IMGU and driver, binary specific.
 | 
			
		||||
	 * PARAM_CLASS_CONFIG and PARAM_CLASS_STATE parameters.
 | 
			
		||||
	 */
 | 
			
		||||
	struct ipu3_css_map binary_params_cs[IMGU_ABI_PARAM_CLASS_NUM - 1]
 | 
			
		||||
					    [IMGU_ABI_NUM_MEMORIES];
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct ipu3_css_map mem[IPU3_CSS_AUX_FRAMES];
 | 
			
		||||
		unsigned int width;
 | 
			
		||||
		unsigned int height;
 | 
			
		||||
		unsigned int bytesperline;
 | 
			
		||||
		unsigned int bytesperpixel;
 | 
			
		||||
	} aux_frames[IPU3_CSS_AUX_FRAME_TYPES];
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		struct ipu3_css_pool parameter_set_info;
 | 
			
		||||
		struct ipu3_css_pool acc;
 | 
			
		||||
		struct ipu3_css_pool gdc;
 | 
			
		||||
		struct ipu3_css_pool obgrid;
 | 
			
		||||
		/* PARAM_CLASS_PARAM parameters for binding while streaming */
 | 
			
		||||
		struct ipu3_css_pool binary_params_p[IMGU_ABI_NUM_MEMORIES];
 | 
			
		||||
	} pool;
 | 
			
		||||
 | 
			
		||||
	struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
 | 
			
		||||
				    [IMGU_ABI_HOST2SP_BUFQ_SIZE];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* IPU3 Camera Sub System structure */
 | 
			
		||||
struct ipu3_css {
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	void __iomem *base;
 | 
			
		||||
	const struct firmware *fw;
 | 
			
		||||
	struct imgu_fw_header *fwp;
 | 
			
		||||
	int iomem_length;
 | 
			
		||||
	int fw_bl, fw_sp[IMGU_NUM_SP];	/* Indices of bl and SP binaries */
 | 
			
		||||
	struct ipu3_css_map *binary;	/* fw binaries mapped to device */
 | 
			
		||||
	bool streaming;		/* true when streaming is enabled */
 | 
			
		||||
 | 
			
		||||
	struct ipu3_css_pipe pipes[IMGU_MAX_PIPE_NUM];
 | 
			
		||||
	struct ipu3_css_map xmem_sp_group_ptrs;
 | 
			
		||||
 | 
			
		||||
	/* enabled pipe(s) */
 | 
			
		||||
	DECLARE_BITMAP(enabled_pipes, IMGU_MAX_PIPE_NUM);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/******************* css v4l *******************/
 | 
			
		||||
int ipu3_css_init(struct device *dev, struct ipu3_css *css,
 | 
			
		||||
		  void __iomem *base, int length);
 | 
			
		||||
void ipu3_css_cleanup(struct ipu3_css *css);
 | 
			
		||||
int ipu3_css_fmt_try(struct ipu3_css *css,
 | 
			
		||||
		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
 | 
			
		||||
		     struct v4l2_rect *rects[IPU3_CSS_RECTS],
 | 
			
		||||
		     unsigned int pipe);
 | 
			
		||||
int ipu3_css_fmt_set(struct ipu3_css *css,
 | 
			
		||||
		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
 | 
			
		||||
		     struct v4l2_rect *rects[IPU3_CSS_RECTS],
 | 
			
		||||
		     unsigned int pipe);
 | 
			
		||||
int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
 | 
			
		||||
int ipu3_css_buf_queue(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
		       struct ipu3_css_buffer *b);
 | 
			
		||||
struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
 | 
			
		||||
int ipu3_css_start_streaming(struct ipu3_css *css);
 | 
			
		||||
void ipu3_css_stop_streaming(struct ipu3_css *css);
 | 
			
		||||
bool ipu3_css_queue_empty(struct ipu3_css *css);
 | 
			
		||||
bool ipu3_css_is_streaming(struct ipu3_css *css);
 | 
			
		||||
bool ipu3_css_pipe_queue_empty(struct ipu3_css *css, unsigned int pipe);
 | 
			
		||||
 | 
			
		||||
/******************* css hw *******************/
 | 
			
		||||
int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
 | 
			
		||||
void ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
 | 
			
		||||
int ipu3_css_irq_ack(struct ipu3_css *css);
 | 
			
		||||
 | 
			
		||||
/******************* set parameters ************/
 | 
			
		||||
int ipu3_css_set_parameters(struct ipu3_css *css, unsigned int pipe,
 | 
			
		||||
			    struct ipu3_uapi_params *set_params);
 | 
			
		||||
 | 
			
		||||
/******************* auxiliary helpers *******************/
 | 
			
		||||
static inline enum ipu3_css_buffer_state
 | 
			
		||||
ipu3_css_buf_state(struct ipu3_css_buffer *b)
 | 
			
		||||
{
 | 
			
		||||
	return b->state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize given buffer. May be called several times. */
 | 
			
		||||
static inline void ipu3_css_buf_init(struct ipu3_css_buffer *b,
 | 
			
		||||
				     unsigned int queue, dma_addr_t daddr)
 | 
			
		||||
{
 | 
			
		||||
	b->state = IPU3_CSS_BUFFER_NEW;
 | 
			
		||||
	b->queue = queue;
 | 
			
		||||
	b->daddr = daddr;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										270
									
								
								drivers/staging/media/ipu3/ipu3-dmamap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								drivers/staging/media/ipu3/ipu3-dmamap.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,270 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Intel Corporation
 | 
			
		||||
 * Copyright 2018 Google LLC.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Tomasz Figa <tfiga@chromium.org>
 | 
			
		||||
 * Author: Yong Zhi <yong.zhi@intel.com>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/vmalloc.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3.h"
 | 
			
		||||
#include "ipu3-css-pool.h"
 | 
			
		||||
#include "ipu3-mmu.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Free a buffer allocated by ipu3_dmamap_alloc_buffer()
 | 
			
		||||
 */
 | 
			
		||||
static void ipu3_dmamap_free_buffer(struct page **pages,
 | 
			
		||||
				    size_t size)
 | 
			
		||||
{
 | 
			
		||||
	int count = size >> PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	while (count--)
 | 
			
		||||
		__free_page(pages[count]);
 | 
			
		||||
	kvfree(pages);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Based on the implementation of __iommu_dma_alloc_pages()
 | 
			
		||||
 * defined in drivers/iommu/dma-iommu.c
 | 
			
		||||
 */
 | 
			
		||||
static struct page **ipu3_dmamap_alloc_buffer(size_t size,
 | 
			
		||||
					      unsigned long order_mask,
 | 
			
		||||
					      gfp_t gfp)
 | 
			
		||||
{
 | 
			
		||||
	struct page **pages;
 | 
			
		||||
	unsigned int i = 0, count = size >> PAGE_SHIFT;
 | 
			
		||||
	const gfp_t high_order_gfp = __GFP_NOWARN | __GFP_NORETRY;
 | 
			
		||||
 | 
			
		||||
	/* Allocate mem for array of page ptrs */
 | 
			
		||||
	pages = kvmalloc_array(count, sizeof(*pages), GFP_KERNEL);
 | 
			
		||||
 | 
			
		||||
	if (!pages)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	order_mask &= (2U << MAX_ORDER) - 1;
 | 
			
		||||
	if (!order_mask)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	gfp |= __GFP_HIGHMEM | __GFP_ZERO;
 | 
			
		||||
 | 
			
		||||
	while (count) {
 | 
			
		||||
		struct page *page = NULL;
 | 
			
		||||
		unsigned int order_size;
 | 
			
		||||
 | 
			
		||||
		for (order_mask &= (2U << __fls(count)) - 1;
 | 
			
		||||
		     order_mask; order_mask &= ~order_size) {
 | 
			
		||||
			unsigned int order = __fls(order_mask);
 | 
			
		||||
 | 
			
		||||
			order_size = 1U << order;
 | 
			
		||||
			page = alloc_pages((order_mask - order_size) ?
 | 
			
		||||
					   gfp | high_order_gfp : gfp, order);
 | 
			
		||||
			if (!page)
 | 
			
		||||
				continue;
 | 
			
		||||
			if (!order)
 | 
			
		||||
				break;
 | 
			
		||||
			if (!PageCompound(page)) {
 | 
			
		||||
				split_page(page, order);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			__free_pages(page, order);
 | 
			
		||||
		}
 | 
			
		||||
		if (!page) {
 | 
			
		||||
			ipu3_dmamap_free_buffer(pages, i << PAGE_SHIFT);
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		count -= order_size;
 | 
			
		||||
		while (order_size--)
 | 
			
		||||
			pages[i++] = page++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pages;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_dmamap_alloc - allocate and map a buffer into KVA
 | 
			
		||||
 * @imgu: struct device pointer
 | 
			
		||||
 * @map: struct to store mapping variables
 | 
			
		||||
 * @len: size required
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *  KVA on success
 | 
			
		||||
 *  %NULL on failure
 | 
			
		||||
 */
 | 
			
		||||
void *ipu3_dmamap_alloc(struct imgu_device *imgu, struct ipu3_css_map *map,
 | 
			
		||||
			size_t len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long shift = iova_shift(&imgu->iova_domain);
 | 
			
		||||
	unsigned int alloc_sizes = imgu->mmu->pgsize_bitmap;
 | 
			
		||||
	struct device *dev = &imgu->pci_dev->dev;
 | 
			
		||||
	size_t size = PAGE_ALIGN(len);
 | 
			
		||||
	struct page **pages;
 | 
			
		||||
	dma_addr_t iovaddr;
 | 
			
		||||
	struct iova *iova;
 | 
			
		||||
	int i, rval;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "%s: allocating %zu\n", __func__, size);
 | 
			
		||||
 | 
			
		||||
	iova = alloc_iova(&imgu->iova_domain, size >> shift,
 | 
			
		||||
			  imgu->mmu->aperture_end >> shift, 0);
 | 
			
		||||
	if (!iova)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	pages = ipu3_dmamap_alloc_buffer(size, alloc_sizes >> PAGE_SHIFT,
 | 
			
		||||
					 GFP_KERNEL);
 | 
			
		||||
	if (!pages)
 | 
			
		||||
		goto out_free_iova;
 | 
			
		||||
 | 
			
		||||
	/* Call IOMMU driver to setup pgt */
 | 
			
		||||
	iovaddr = iova_dma_addr(&imgu->iova_domain, iova);
 | 
			
		||||
	for (i = 0; i < size / PAGE_SIZE; ++i) {
 | 
			
		||||
		rval = ipu3_mmu_map(imgu->mmu, iovaddr,
 | 
			
		||||
				    page_to_phys(pages[i]), PAGE_SIZE);
 | 
			
		||||
		if (rval)
 | 
			
		||||
			goto out_unmap;
 | 
			
		||||
 | 
			
		||||
		iovaddr += PAGE_SIZE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Now grab a virtual region */
 | 
			
		||||
	map->vma = __get_vm_area(size, VM_USERMAP, VMALLOC_START, VMALLOC_END);
 | 
			
		||||
	if (!map->vma)
 | 
			
		||||
		goto out_unmap;
 | 
			
		||||
 | 
			
		||||
	map->vma->pages = pages;
 | 
			
		||||
	/* And map it in KVA */
 | 
			
		||||
	if (map_vm_area(map->vma, PAGE_KERNEL, pages))
 | 
			
		||||
		goto out_vunmap;
 | 
			
		||||
 | 
			
		||||
	map->size = size;
 | 
			
		||||
	map->daddr = iova_dma_addr(&imgu->iova_domain, iova);
 | 
			
		||||
	map->vaddr = map->vma->addr;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "%s: allocated %zu @ IOVA %pad @ VA %p\n", __func__,
 | 
			
		||||
		size, &map->daddr, map->vma->addr);
 | 
			
		||||
 | 
			
		||||
	return map->vma->addr;
 | 
			
		||||
 | 
			
		||||
out_vunmap:
 | 
			
		||||
	vunmap(map->vma->addr);
 | 
			
		||||
 | 
			
		||||
out_unmap:
 | 
			
		||||
	ipu3_dmamap_free_buffer(pages, size);
 | 
			
		||||
	ipu3_mmu_unmap(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
 | 
			
		||||
		       i * PAGE_SIZE);
 | 
			
		||||
	map->vma = NULL;
 | 
			
		||||
 | 
			
		||||
out_free_iova:
 | 
			
		||||
	__free_iova(&imgu->iova_domain, iova);
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ipu3_dmamap_unmap(struct imgu_device *imgu, struct ipu3_css_map *map)
 | 
			
		||||
{
 | 
			
		||||
	struct iova *iova;
 | 
			
		||||
 | 
			
		||||
	iova = find_iova(&imgu->iova_domain,
 | 
			
		||||
			 iova_pfn(&imgu->iova_domain, map->daddr));
 | 
			
		||||
	if (WARN_ON(!iova))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ipu3_mmu_unmap(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
 | 
			
		||||
		       iova_size(iova) << iova_shift(&imgu->iova_domain));
 | 
			
		||||
 | 
			
		||||
	__free_iova(&imgu->iova_domain, iova);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Counterpart of ipu3_dmamap_alloc
 | 
			
		||||
 */
 | 
			
		||||
void ipu3_dmamap_free(struct imgu_device *imgu, struct ipu3_css_map *map)
 | 
			
		||||
{
 | 
			
		||||
	struct vm_struct *area = map->vma;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(&imgu->pci_dev->dev, "%s: freeing %zu @ IOVA %pad @ VA %p\n",
 | 
			
		||||
		__func__, map->size, &map->daddr, map->vaddr);
 | 
			
		||||
 | 
			
		||||
	if (!map->vaddr)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ipu3_dmamap_unmap(imgu, map);
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(!area) || WARN_ON(!area->pages))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	ipu3_dmamap_free_buffer(area->pages, map->size);
 | 
			
		||||
	vunmap(map->vaddr);
 | 
			
		||||
	map->vaddr = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ipu3_dmamap_map_sg(struct imgu_device *imgu, struct scatterlist *sglist,
 | 
			
		||||
		       int nents, struct ipu3_css_map *map)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long shift = iova_shift(&imgu->iova_domain);
 | 
			
		||||
	struct scatterlist *sg;
 | 
			
		||||
	struct iova *iova;
 | 
			
		||||
	size_t size = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for_each_sg(sglist, sg, nents, i) {
 | 
			
		||||
		if (sg->offset)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		if (i != nents - 1 && !PAGE_ALIGNED(sg->length))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		size += sg->length;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size = iova_align(&imgu->iova_domain, size);
 | 
			
		||||
	dev_dbg(&imgu->pci_dev->dev, "dmamap: mapping sg %d entries, %zu pages\n",
 | 
			
		||||
		nents, size >> shift);
 | 
			
		||||
 | 
			
		||||
	iova = alloc_iova(&imgu->iova_domain, size >> shift,
 | 
			
		||||
			  imgu->mmu->aperture_end >> shift, 0);
 | 
			
		||||
	if (!iova)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(&imgu->pci_dev->dev, "dmamap: iova low pfn %lu, high pfn %lu\n",
 | 
			
		||||
		iova->pfn_lo, iova->pfn_hi);
 | 
			
		||||
 | 
			
		||||
	if (ipu3_mmu_map_sg(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
 | 
			
		||||
			    sglist, nents) < size)
 | 
			
		||||
		goto out_fail;
 | 
			
		||||
 | 
			
		||||
	memset(map, 0, sizeof(*map));
 | 
			
		||||
	map->daddr = iova_dma_addr(&imgu->iova_domain, iova);
 | 
			
		||||
	map->size = size;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_fail:
 | 
			
		||||
	__free_iova(&imgu->iova_domain, iova);
 | 
			
		||||
 | 
			
		||||
	return -EFAULT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ipu3_dmamap_init(struct imgu_device *imgu)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long order, base_pfn;
 | 
			
		||||
	int ret = iova_cache_get();
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	order = __ffs(imgu->mmu->pgsize_bitmap);
 | 
			
		||||
	base_pfn = max_t(unsigned long, 1, imgu->mmu->aperture_start >> order);
 | 
			
		||||
	init_iova_domain(&imgu->iova_domain, 1UL << order, base_pfn);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ipu3_dmamap_exit(struct imgu_device *imgu)
 | 
			
		||||
{
 | 
			
		||||
	put_iova_domain(&imgu->iova_domain);
 | 
			
		||||
	iova_cache_put();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								drivers/staging/media/ipu3/ipu3-dmamap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								drivers/staging/media/ipu3/ipu3-dmamap.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
/* Copyright 2018 Google LLC. */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_DMAMAP_H
 | 
			
		||||
#define __IPU3_DMAMAP_H
 | 
			
		||||
 | 
			
		||||
struct imgu_device;
 | 
			
		||||
struct scatterlist;
 | 
			
		||||
 | 
			
		||||
void *ipu3_dmamap_alloc(struct imgu_device *imgu, struct ipu3_css_map *map,
 | 
			
		||||
			size_t len);
 | 
			
		||||
void ipu3_dmamap_free(struct imgu_device *imgu, struct ipu3_css_map *map);
 | 
			
		||||
 | 
			
		||||
int ipu3_dmamap_map_sg(struct imgu_device *imgu, struct scatterlist *sglist,
 | 
			
		||||
		       int nents, struct ipu3_css_map *map);
 | 
			
		||||
void ipu3_dmamap_unmap(struct imgu_device *imgu, struct ipu3_css_map *map);
 | 
			
		||||
 | 
			
		||||
int ipu3_dmamap_init(struct imgu_device *imgu);
 | 
			
		||||
void ipu3_dmamap_exit(struct imgu_device *imgu);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										561
									
								
								drivers/staging/media/ipu3/ipu3-mmu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										561
									
								
								drivers/staging/media/ipu3/ipu3-mmu.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,561 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Intel Corporation.
 | 
			
		||||
 * Copyright 2018 Google LLC.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Tuukka Toivonen <tuukka.toivonen@intel.com>
 | 
			
		||||
 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
 | 
			
		||||
 * Author: Samu Onkalo <samu.onkalo@intel.com>
 | 
			
		||||
 * Author: Tomasz Figa <tfiga@chromium.org>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/dma-mapping.h>
 | 
			
		||||
#include <linux/iopoll.h>
 | 
			
		||||
#include <linux/pm_runtime.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/vmalloc.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/set_memory.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3-mmu.h"
 | 
			
		||||
 | 
			
		||||
#define IPU3_PAGE_SHIFT		12
 | 
			
		||||
#define IPU3_PAGE_SIZE		(1UL << IPU3_PAGE_SHIFT)
 | 
			
		||||
 | 
			
		||||
#define IPU3_PT_BITS		10
 | 
			
		||||
#define IPU3_PT_PTES		(1UL << IPU3_PT_BITS)
 | 
			
		||||
#define IPU3_PT_SIZE		(IPU3_PT_PTES << 2)
 | 
			
		||||
#define IPU3_PT_ORDER		(IPU3_PT_SIZE >> PAGE_SHIFT)
 | 
			
		||||
 | 
			
		||||
#define IPU3_ADDR2PTE(addr)	((addr) >> IPU3_PAGE_SHIFT)
 | 
			
		||||
#define IPU3_PTE2ADDR(pte)	((phys_addr_t)(pte) << IPU3_PAGE_SHIFT)
 | 
			
		||||
 | 
			
		||||
#define IPU3_L2PT_SHIFT		IPU3_PT_BITS
 | 
			
		||||
#define IPU3_L2PT_MASK		((1UL << IPU3_L2PT_SHIFT) - 1)
 | 
			
		||||
 | 
			
		||||
#define IPU3_L1PT_SHIFT		IPU3_PT_BITS
 | 
			
		||||
#define IPU3_L1PT_MASK		((1UL << IPU3_L1PT_SHIFT) - 1)
 | 
			
		||||
 | 
			
		||||
#define IPU3_MMU_ADDRESS_BITS	(IPU3_PAGE_SHIFT + \
 | 
			
		||||
				 IPU3_L2PT_SHIFT + \
 | 
			
		||||
				 IPU3_L1PT_SHIFT)
 | 
			
		||||
 | 
			
		||||
#define IMGU_REG_BASE		0x4000
 | 
			
		||||
#define REG_TLB_INVALIDATE	(IMGU_REG_BASE + 0x300)
 | 
			
		||||
#define TLB_INVALIDATE		1
 | 
			
		||||
#define REG_L1_PHYS		(IMGU_REG_BASE + 0x304) /* 27-bit pfn */
 | 
			
		||||
#define REG_GP_HALT		(IMGU_REG_BASE + 0x5dc)
 | 
			
		||||
#define REG_GP_HALTED		(IMGU_REG_BASE + 0x5e0)
 | 
			
		||||
 | 
			
		||||
struct ipu3_mmu {
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	void __iomem *base;
 | 
			
		||||
	/* protect access to l2pts, l1pt */
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
 | 
			
		||||
	void *dummy_page;
 | 
			
		||||
	u32 dummy_page_pteval;
 | 
			
		||||
 | 
			
		||||
	u32 *dummy_l2pt;
 | 
			
		||||
	u32 dummy_l2pt_pteval;
 | 
			
		||||
 | 
			
		||||
	u32 **l2pts;
 | 
			
		||||
	u32 *l1pt;
 | 
			
		||||
 | 
			
		||||
	struct ipu3_mmu_info geometry;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline struct ipu3_mmu *to_ipu3_mmu(struct ipu3_mmu_info *info)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(info, struct ipu3_mmu, geometry);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_mmu_tlb_invalidate - invalidate translation look-aside buffer
 | 
			
		||||
 * @mmu: MMU to perform the invalidate operation on
 | 
			
		||||
 *
 | 
			
		||||
 * This function invalidates the whole TLB. Must be called when the hardware
 | 
			
		||||
 * is powered on.
 | 
			
		||||
 */
 | 
			
		||||
static void ipu3_mmu_tlb_invalidate(struct ipu3_mmu *mmu)
 | 
			
		||||
{
 | 
			
		||||
	writel(TLB_INVALIDATE, mmu->base + REG_TLB_INVALIDATE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void call_if_ipu3_is_powered(struct ipu3_mmu *mmu,
 | 
			
		||||
				    void (*func)(struct ipu3_mmu *mmu))
 | 
			
		||||
{
 | 
			
		||||
	if (!pm_runtime_get_if_in_use(mmu->dev))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	func(mmu);
 | 
			
		||||
	pm_runtime_put(mmu->dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_mmu_set_halt - set CIO gate halt bit
 | 
			
		||||
 * @mmu: MMU to set the CIO gate bit in.
 | 
			
		||||
 * @halt: Desired state of the gate bit.
 | 
			
		||||
 *
 | 
			
		||||
 * This function sets the CIO gate bit that controls whether external memory
 | 
			
		||||
 * accesses are allowed. Must be called when the hardware is powered on.
 | 
			
		||||
 */
 | 
			
		||||
static void ipu3_mmu_set_halt(struct ipu3_mmu *mmu, bool halt)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	writel(halt, mmu->base + REG_GP_HALT);
 | 
			
		||||
	ret = readl_poll_timeout(mmu->base + REG_GP_HALTED,
 | 
			
		||||
				 val, (val & 1) == halt, 1000, 100000);
 | 
			
		||||
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_err(mmu->dev, "failed to %s CIO gate halt\n",
 | 
			
		||||
			halt ? "set" : "clear");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_mmu_alloc_page_table - allocate a pre-filled page table
 | 
			
		||||
 * @pteval: Value to initialize for page table entries with.
 | 
			
		||||
 *
 | 
			
		||||
 * Return: Pointer to allocated page table or NULL on failure.
 | 
			
		||||
 */
 | 
			
		||||
static u32 *ipu3_mmu_alloc_page_table(u32 pteval)
 | 
			
		||||
{
 | 
			
		||||
	u32 *pt;
 | 
			
		||||
	int pte;
 | 
			
		||||
 | 
			
		||||
	pt = (u32 *)__get_free_page(GFP_KERNEL);
 | 
			
		||||
	if (!pt)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	for (pte = 0; pte < IPU3_PT_PTES; pte++)
 | 
			
		||||
		pt[pte] = pteval;
 | 
			
		||||
 | 
			
		||||
	set_memory_uc((unsigned long int)pt, IPU3_PT_ORDER);
 | 
			
		||||
 | 
			
		||||
	return pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_mmu_free_page_table - free page table
 | 
			
		||||
 * @pt: Page table to free.
 | 
			
		||||
 */
 | 
			
		||||
static void ipu3_mmu_free_page_table(u32 *pt)
 | 
			
		||||
{
 | 
			
		||||
	set_memory_wb((unsigned long int)pt, IPU3_PT_ORDER);
 | 
			
		||||
	free_page((unsigned long)pt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * address_to_pte_idx - split IOVA into L1 and L2 page table indices
 | 
			
		||||
 * @iova: IOVA to split.
 | 
			
		||||
 * @l1pt_idx: Output for the L1 page table index.
 | 
			
		||||
 * @l2pt_idx: Output for the L2 page index.
 | 
			
		||||
 */
 | 
			
		||||
static inline void address_to_pte_idx(unsigned long iova, u32 *l1pt_idx,
 | 
			
		||||
				      u32 *l2pt_idx)
 | 
			
		||||
{
 | 
			
		||||
	iova >>= IPU3_PAGE_SHIFT;
 | 
			
		||||
 | 
			
		||||
	if (l2pt_idx)
 | 
			
		||||
		*l2pt_idx = iova & IPU3_L2PT_MASK;
 | 
			
		||||
 | 
			
		||||
	iova >>= IPU3_L2PT_SHIFT;
 | 
			
		||||
 | 
			
		||||
	if (l1pt_idx)
 | 
			
		||||
		*l1pt_idx = iova & IPU3_L1PT_MASK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 *ipu3_mmu_get_l2pt(struct ipu3_mmu *mmu, u32 l1pt_idx)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	u32 *l2pt, *new_l2pt;
 | 
			
		||||
	u32 pteval;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	l2pt = mmu->l2pts[l1pt_idx];
 | 
			
		||||
	if (l2pt)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	new_l2pt = ipu3_mmu_alloc_page_table(mmu->dummy_page_pteval);
 | 
			
		||||
	if (!new_l2pt)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	dev_dbg(mmu->dev, "allocated page table %p for l1pt_idx %u\n",
 | 
			
		||||
		new_l2pt, l1pt_idx);
 | 
			
		||||
 | 
			
		||||
	l2pt = mmu->l2pts[l1pt_idx];
 | 
			
		||||
	if (l2pt) {
 | 
			
		||||
		ipu3_mmu_free_page_table(new_l2pt);
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l2pt = new_l2pt;
 | 
			
		||||
	mmu->l2pts[l1pt_idx] = new_l2pt;
 | 
			
		||||
 | 
			
		||||
	pteval = IPU3_ADDR2PTE(virt_to_phys(new_l2pt));
 | 
			
		||||
	mmu->l1pt[l1pt_idx] = pteval;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	spin_unlock_irqrestore(&mmu->lock, flags);
 | 
			
		||||
	return l2pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __ipu3_mmu_map(struct ipu3_mmu *mmu, unsigned long iova,
 | 
			
		||||
			  phys_addr_t paddr)
 | 
			
		||||
{
 | 
			
		||||
	u32 l1pt_idx, l2pt_idx;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	u32 *l2pt;
 | 
			
		||||
 | 
			
		||||
	if (!mmu)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	address_to_pte_idx(iova, &l1pt_idx, &l2pt_idx);
 | 
			
		||||
 | 
			
		||||
	l2pt = ipu3_mmu_get_l2pt(mmu, l1pt_idx);
 | 
			
		||||
	if (!l2pt)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (l2pt[l2pt_idx] != mmu->dummy_page_pteval) {
 | 
			
		||||
		spin_unlock_irqrestore(&mmu->lock, flags);
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l2pt[l2pt_idx] = IPU3_ADDR2PTE(paddr);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The following four functions are implemented based on iommu.c
 | 
			
		||||
 * drivers/iommu/iommu.c/iommu_pgsize().
 | 
			
		||||
 */
 | 
			
		||||
static size_t ipu3_mmu_pgsize(unsigned long pgsize_bitmap,
 | 
			
		||||
			      unsigned long addr_merge, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int pgsize_idx;
 | 
			
		||||
	size_t pgsize;
 | 
			
		||||
 | 
			
		||||
	/* Max page size that still fits into 'size' */
 | 
			
		||||
	pgsize_idx = __fls(size);
 | 
			
		||||
 | 
			
		||||
	/* need to consider alignment requirements ? */
 | 
			
		||||
	if (likely(addr_merge)) {
 | 
			
		||||
		/* Max page size allowed by address */
 | 
			
		||||
		unsigned int align_pgsize_idx = __ffs(addr_merge);
 | 
			
		||||
 | 
			
		||||
		pgsize_idx = min(pgsize_idx, align_pgsize_idx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* build a mask of acceptable page sizes */
 | 
			
		||||
	pgsize = (1UL << (pgsize_idx + 1)) - 1;
 | 
			
		||||
 | 
			
		||||
	/* throw away page sizes not supported by the hardware */
 | 
			
		||||
	pgsize &= pgsize_bitmap;
 | 
			
		||||
 | 
			
		||||
	/* make sure we're still sane */
 | 
			
		||||
	WARN_ON(!pgsize);
 | 
			
		||||
 | 
			
		||||
	/* pick the biggest page */
 | 
			
		||||
	pgsize_idx = __fls(pgsize);
 | 
			
		||||
	pgsize = 1UL << pgsize_idx;
 | 
			
		||||
 | 
			
		||||
	return pgsize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* drivers/iommu/iommu.c/iommu_map() */
 | 
			
		||||
int ipu3_mmu_map(struct ipu3_mmu_info *info, unsigned long iova,
 | 
			
		||||
		 phys_addr_t paddr, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu = to_ipu3_mmu(info);
 | 
			
		||||
	unsigned int min_pagesz;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	/* find out the minimum page size supported */
 | 
			
		||||
	min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * both the virtual address and the physical one, as well as
 | 
			
		||||
	 * the size of the mapping, must be aligned (at least) to the
 | 
			
		||||
	 * size of the smallest page supported by the hardware
 | 
			
		||||
	 */
 | 
			
		||||
	if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
 | 
			
		||||
		dev_err(mmu->dev, "unaligned: iova 0x%lx pa %pa size 0x%zx min_pagesz 0x%x\n",
 | 
			
		||||
			iova, &paddr, size, min_pagesz);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_dbg(mmu->dev, "map: iova 0x%lx pa %pa size 0x%zx\n",
 | 
			
		||||
		iova, &paddr, size);
 | 
			
		||||
 | 
			
		||||
	while (size) {
 | 
			
		||||
		size_t pgsize = ipu3_mmu_pgsize(mmu->geometry.pgsize_bitmap,
 | 
			
		||||
						iova | paddr, size);
 | 
			
		||||
 | 
			
		||||
		dev_dbg(mmu->dev, "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
 | 
			
		||||
			iova, &paddr, pgsize);
 | 
			
		||||
 | 
			
		||||
		ret = __ipu3_mmu_map(mmu, iova, paddr);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		iova += pgsize;
 | 
			
		||||
		paddr += pgsize;
 | 
			
		||||
		size -= pgsize;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	call_if_ipu3_is_powered(mmu, ipu3_mmu_tlb_invalidate);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* drivers/iommu/iommu.c/default_iommu_map_sg() */
 | 
			
		||||
size_t ipu3_mmu_map_sg(struct ipu3_mmu_info *info, unsigned long iova,
 | 
			
		||||
		       struct scatterlist *sg, unsigned int nents)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu = to_ipu3_mmu(info);
 | 
			
		||||
	struct scatterlist *s;
 | 
			
		||||
	size_t s_length, mapped = 0;
 | 
			
		||||
	unsigned int i, min_pagesz;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
 | 
			
		||||
 | 
			
		||||
	for_each_sg(sg, s, nents, i) {
 | 
			
		||||
		phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
 | 
			
		||||
 | 
			
		||||
		s_length = s->length;
 | 
			
		||||
 | 
			
		||||
		if (!IS_ALIGNED(s->offset, min_pagesz))
 | 
			
		||||
			goto out_err;
 | 
			
		||||
 | 
			
		||||
		/* must be min_pagesz aligned to be mapped singlely */
 | 
			
		||||
		if (i == nents - 1 && !IS_ALIGNED(s->length, min_pagesz))
 | 
			
		||||
			s_length = PAGE_ALIGN(s->length);
 | 
			
		||||
 | 
			
		||||
		ret = ipu3_mmu_map(info, iova + mapped, phys, s_length);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto out_err;
 | 
			
		||||
 | 
			
		||||
		mapped += s_length;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	call_if_ipu3_is_powered(mmu, ipu3_mmu_tlb_invalidate);
 | 
			
		||||
 | 
			
		||||
	return mapped;
 | 
			
		||||
 | 
			
		||||
out_err:
 | 
			
		||||
	/* undo mappings already done */
 | 
			
		||||
	ipu3_mmu_unmap(info, iova, mapped);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t __ipu3_mmu_unmap(struct ipu3_mmu *mmu,
 | 
			
		||||
			       unsigned long iova, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	u32 l1pt_idx, l2pt_idx;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	size_t unmap = size;
 | 
			
		||||
	u32 *l2pt;
 | 
			
		||||
 | 
			
		||||
	if (!mmu)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	address_to_pte_idx(iova, &l1pt_idx, &l2pt_idx);
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	l2pt = mmu->l2pts[l1pt_idx];
 | 
			
		||||
	if (!l2pt) {
 | 
			
		||||
		spin_unlock_irqrestore(&mmu->lock, flags);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (l2pt[l2pt_idx] == mmu->dummy_page_pteval)
 | 
			
		||||
		unmap = 0;
 | 
			
		||||
 | 
			
		||||
	l2pt[l2pt_idx] = mmu->dummy_page_pteval;
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(&mmu->lock, flags);
 | 
			
		||||
 | 
			
		||||
	return unmap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* drivers/iommu/iommu.c/iommu_unmap() */
 | 
			
		||||
size_t ipu3_mmu_unmap(struct ipu3_mmu_info *info, unsigned long iova,
 | 
			
		||||
		      size_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu = to_ipu3_mmu(info);
 | 
			
		||||
	size_t unmapped_page, unmapped = 0;
 | 
			
		||||
	unsigned int min_pagesz;
 | 
			
		||||
 | 
			
		||||
	/* find out the minimum page size supported */
 | 
			
		||||
	min_pagesz = 1 << __ffs(mmu->geometry.pgsize_bitmap);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The virtual address, as well as the size of the mapping, must be
 | 
			
		||||
	 * aligned (at least) to the size of the smallest page supported
 | 
			
		||||
	 * by the hardware
 | 
			
		||||
	 */
 | 
			
		||||
	if (!IS_ALIGNED(iova | size, min_pagesz)) {
 | 
			
		||||
		dev_err(mmu->dev, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
 | 
			
		||||
			iova, size, min_pagesz);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_dbg(mmu->dev, "unmap this: iova 0x%lx size 0x%zx\n", iova, size);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Keep iterating until we either unmap 'size' bytes (or more)
 | 
			
		||||
	 * or we hit an area that isn't mapped.
 | 
			
		||||
	 */
 | 
			
		||||
	while (unmapped < size) {
 | 
			
		||||
		size_t pgsize = ipu3_mmu_pgsize(mmu->geometry.pgsize_bitmap,
 | 
			
		||||
						iova, size - unmapped);
 | 
			
		||||
 | 
			
		||||
		unmapped_page = __ipu3_mmu_unmap(mmu, iova, pgsize);
 | 
			
		||||
		if (!unmapped_page)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		dev_dbg(mmu->dev, "unmapped: iova 0x%lx size 0x%zx\n",
 | 
			
		||||
			iova, unmapped_page);
 | 
			
		||||
 | 
			
		||||
		iova += unmapped_page;
 | 
			
		||||
		unmapped += unmapped_page;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	call_if_ipu3_is_powered(mmu, ipu3_mmu_tlb_invalidate);
 | 
			
		||||
 | 
			
		||||
	return unmapped;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_mmu_init() - initialize IPU3 MMU block
 | 
			
		||||
 * @base:	IOMEM base of hardware registers.
 | 
			
		||||
 *
 | 
			
		||||
 * Return: Pointer to IPU3 MMU private data pointer or ERR_PTR() on error.
 | 
			
		||||
 */
 | 
			
		||||
struct ipu3_mmu_info *ipu3_mmu_init(struct device *parent, void __iomem *base)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu;
 | 
			
		||||
	u32 pteval;
 | 
			
		||||
 | 
			
		||||
	mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
 | 
			
		||||
	if (!mmu)
 | 
			
		||||
		return ERR_PTR(-ENOMEM);
 | 
			
		||||
 | 
			
		||||
	mmu->dev = parent;
 | 
			
		||||
	mmu->base = base;
 | 
			
		||||
	spin_lock_init(&mmu->lock);
 | 
			
		||||
 | 
			
		||||
	/* Disallow external memory access when having no valid page tables. */
 | 
			
		||||
	ipu3_mmu_set_halt(mmu, true);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The MMU does not have a "valid" bit, so we have to use a dummy
 | 
			
		||||
	 * page for invalid entries.
 | 
			
		||||
	 */
 | 
			
		||||
	mmu->dummy_page = (void *)__get_free_page(GFP_KERNEL);
 | 
			
		||||
	if (!mmu->dummy_page)
 | 
			
		||||
		goto fail_group;
 | 
			
		||||
	pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->dummy_page));
 | 
			
		||||
	mmu->dummy_page_pteval = pteval;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Allocate a dummy L2 page table with all entries pointing to
 | 
			
		||||
	 * the dummy page.
 | 
			
		||||
	 */
 | 
			
		||||
	mmu->dummy_l2pt = ipu3_mmu_alloc_page_table(pteval);
 | 
			
		||||
	if (!mmu->dummy_l2pt)
 | 
			
		||||
		goto fail_dummy_page;
 | 
			
		||||
	pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->dummy_l2pt));
 | 
			
		||||
	mmu->dummy_l2pt_pteval = pteval;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Allocate the array of L2PT CPU pointers, initialized to zero,
 | 
			
		||||
	 * which means the dummy L2PT allocated above.
 | 
			
		||||
	 */
 | 
			
		||||
	mmu->l2pts = vzalloc(IPU3_PT_PTES * sizeof(*mmu->l2pts));
 | 
			
		||||
	if (!mmu->l2pts)
 | 
			
		||||
		goto fail_l2pt;
 | 
			
		||||
 | 
			
		||||
	/* Allocate the L1 page table. */
 | 
			
		||||
	mmu->l1pt = ipu3_mmu_alloc_page_table(mmu->dummy_l2pt_pteval);
 | 
			
		||||
	if (!mmu->l1pt)
 | 
			
		||||
		goto fail_l2pts;
 | 
			
		||||
 | 
			
		||||
	pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->l1pt));
 | 
			
		||||
	writel(pteval, mmu->base + REG_L1_PHYS);
 | 
			
		||||
	ipu3_mmu_tlb_invalidate(mmu);
 | 
			
		||||
	ipu3_mmu_set_halt(mmu, false);
 | 
			
		||||
 | 
			
		||||
	mmu->geometry.aperture_start = 0;
 | 
			
		||||
	mmu->geometry.aperture_end = DMA_BIT_MASK(IPU3_MMU_ADDRESS_BITS);
 | 
			
		||||
	mmu->geometry.pgsize_bitmap = IPU3_PAGE_SIZE;
 | 
			
		||||
 | 
			
		||||
	return &mmu->geometry;
 | 
			
		||||
 | 
			
		||||
fail_l2pts:
 | 
			
		||||
	vfree(mmu->l2pts);
 | 
			
		||||
fail_l2pt:
 | 
			
		||||
	ipu3_mmu_free_page_table(mmu->dummy_l2pt);
 | 
			
		||||
fail_dummy_page:
 | 
			
		||||
	free_page((unsigned long)mmu->dummy_page);
 | 
			
		||||
fail_group:
 | 
			
		||||
	kfree(mmu);
 | 
			
		||||
 | 
			
		||||
	return ERR_PTR(-ENOMEM);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ipu3_mmu_exit() - clean up IPU3 MMU block
 | 
			
		||||
 * @mmu: IPU3 MMU private data
 | 
			
		||||
 */
 | 
			
		||||
void ipu3_mmu_exit(struct ipu3_mmu_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu = to_ipu3_mmu(info);
 | 
			
		||||
 | 
			
		||||
	/* We are going to free our page tables, no more memory access. */
 | 
			
		||||
	ipu3_mmu_set_halt(mmu, true);
 | 
			
		||||
	ipu3_mmu_tlb_invalidate(mmu);
 | 
			
		||||
 | 
			
		||||
	ipu3_mmu_free_page_table(mmu->l1pt);
 | 
			
		||||
	vfree(mmu->l2pts);
 | 
			
		||||
	ipu3_mmu_free_page_table(mmu->dummy_l2pt);
 | 
			
		||||
	free_page((unsigned long)mmu->dummy_page);
 | 
			
		||||
	kfree(mmu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ipu3_mmu_suspend(struct ipu3_mmu_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu = to_ipu3_mmu(info);
 | 
			
		||||
 | 
			
		||||
	ipu3_mmu_set_halt(mmu, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ipu3_mmu_resume(struct ipu3_mmu_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct ipu3_mmu *mmu = to_ipu3_mmu(info);
 | 
			
		||||
	u32 pteval;
 | 
			
		||||
 | 
			
		||||
	ipu3_mmu_set_halt(mmu, true);
 | 
			
		||||
 | 
			
		||||
	pteval = IPU3_ADDR2PTE(virt_to_phys(mmu->l1pt));
 | 
			
		||||
	writel(pteval, mmu->base + REG_L1_PHYS);
 | 
			
		||||
 | 
			
		||||
	ipu3_mmu_tlb_invalidate(mmu);
 | 
			
		||||
	ipu3_mmu_set_halt(mmu, false);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								drivers/staging/media/ipu3/ipu3-mmu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								drivers/staging/media/ipu3/ipu3-mmu.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
/* Copyright 2018 Google LLC. */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_MMU_H
 | 
			
		||||
#define __IPU3_MMU_H
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct ipu3_mmu_info - Describes mmu geometry
 | 
			
		||||
 *
 | 
			
		||||
 * @aperture_start:	First address that can be mapped
 | 
			
		||||
 * @aperture_end:	Last address that can be mapped
 | 
			
		||||
 * @pgsize_bitmap:	Bitmap of page sizes in use
 | 
			
		||||
 */
 | 
			
		||||
struct ipu3_mmu_info {
 | 
			
		||||
	dma_addr_t aperture_start;
 | 
			
		||||
	dma_addr_t aperture_end;
 | 
			
		||||
	unsigned long pgsize_bitmap;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct device;
 | 
			
		||||
struct scatterlist;
 | 
			
		||||
 | 
			
		||||
struct ipu3_mmu_info *ipu3_mmu_init(struct device *parent, void __iomem *base);
 | 
			
		||||
void ipu3_mmu_exit(struct ipu3_mmu_info *info);
 | 
			
		||||
void ipu3_mmu_suspend(struct ipu3_mmu_info *info);
 | 
			
		||||
void ipu3_mmu_resume(struct ipu3_mmu_info *info);
 | 
			
		||||
 | 
			
		||||
int ipu3_mmu_map(struct ipu3_mmu_info *info, unsigned long iova,
 | 
			
		||||
		 phys_addr_t paddr, size_t size);
 | 
			
		||||
size_t ipu3_mmu_unmap(struct ipu3_mmu_info *info, unsigned long iova,
 | 
			
		||||
		      size_t size);
 | 
			
		||||
size_t ipu3_mmu_map_sg(struct ipu3_mmu_info *info, unsigned long iova,
 | 
			
		||||
		       struct scatterlist *sg, unsigned int nents);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										9609
									
								
								drivers/staging/media/ipu3/ipu3-tables.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9609
									
								
								drivers/staging/media/ipu3/ipu3-tables.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										66
									
								
								drivers/staging/media/ipu3/ipu3-tables.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								drivers/staging/media/ipu3/ipu3-tables.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_TABLES_H
 | 
			
		||||
#define __IPU3_TABLES_H
 | 
			
		||||
 | 
			
		||||
#include "ipu3-abi.h"
 | 
			
		||||
 | 
			
		||||
#define IMGU_BDS_GRANULARITY		32	/* Downscaling granularity */
 | 
			
		||||
#define IMGU_BDS_MIN_SF_INV		IMGU_BDS_GRANULARITY
 | 
			
		||||
#define IMGU_BDS_CONFIG_LEN		97
 | 
			
		||||
 | 
			
		||||
#define IMGU_SCALER_DOWNSCALE_4TAPS_LEN	128
 | 
			
		||||
#define IMGU_SCALER_DOWNSCALE_2TAPS_LEN	64
 | 
			
		||||
#define IMGU_SCALER_FP			((u32)1 << 31) /* 1.0 in fixed point */
 | 
			
		||||
 | 
			
		||||
#define IMGU_XNR3_VMEM_LUT_LEN		16
 | 
			
		||||
 | 
			
		||||
#define IMGU_GDC_LUT_UNIT		4
 | 
			
		||||
#define IMGU_GDC_LUT_LEN		256
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_bds_config {
 | 
			
		||||
	struct imgu_abi_bds_phase_arr hor_phase_arr;
 | 
			
		||||
	struct imgu_abi_bds_phase_arr ver_phase_arr;
 | 
			
		||||
	struct imgu_abi_bds_ptrn_arr ptrn_arr;
 | 
			
		||||
	u16 sample_patrn_length;
 | 
			
		||||
	u8 hor_ds_en;
 | 
			
		||||
	u8 ver_ds_en;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ipu3_css_xnr3_vmem_defaults {
 | 
			
		||||
	s16 x[IMGU_XNR3_VMEM_LUT_LEN];
 | 
			
		||||
	s16 a[IMGU_XNR3_VMEM_LUT_LEN];
 | 
			
		||||
	s16 b[IMGU_XNR3_VMEM_LUT_LEN];
 | 
			
		||||
	s16 c[IMGU_XNR3_VMEM_LUT_LEN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct ipu3_css_bds_config
 | 
			
		||||
			ipu3_css_bds_configs[IMGU_BDS_CONFIG_LEN];
 | 
			
		||||
extern const s32 ipu3_css_downscale_4taps[IMGU_SCALER_DOWNSCALE_4TAPS_LEN];
 | 
			
		||||
extern const s32 ipu3_css_downscale_2taps[IMGU_SCALER_DOWNSCALE_2TAPS_LEN];
 | 
			
		||||
extern const s16 ipu3_css_gdc_lut[IMGU_GDC_LUT_UNIT][IMGU_GDC_LUT_LEN];
 | 
			
		||||
extern const struct ipu3_css_xnr3_vmem_defaults ipu3_css_xnr3_vmem_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_bnr_static_config ipu3_css_bnr_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_dm_config ipu3_css_dm_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_ccm_mat_config ipu3_css_ccm_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_gamma_corr_lut ipu3_css_gamma_lut;
 | 
			
		||||
extern const struct ipu3_uapi_csc_mat_config ipu3_css_csc_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_cds_params ipu3_css_cds_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_shd_config_static ipu3_css_shd_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_yuvp1_iefd_config ipu3_css_iefd_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_yuvp1_yds_config ipu3_css_yds_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_yuvp1_chnr_config ipu3_css_chnr_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_yuvp1_y_ee_nr_config ipu3_css_y_ee_nr_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config
 | 
			
		||||
						ipu3_css_tcc_gain_pcwl_lut;
 | 
			
		||||
extern const struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config
 | 
			
		||||
						ipu3_css_tcc_r_sqr_lut;
 | 
			
		||||
extern const struct imgu_abi_anr_config ipu3_css_anr_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_awb_fr_config_s ipu3_css_awb_fr_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_ae_grid_config ipu3_css_ae_grid_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_ae_ccm ipu3_css_ae_ccm_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_af_config_s ipu3_css_af_defaults;
 | 
			
		||||
extern const struct ipu3_uapi_awb_config_s ipu3_css_awb_defaults;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1419
									
								
								drivers/staging/media/ipu3/ipu3-v4l2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1419
									
								
								drivers/staging/media/ipu3/ipu3-v4l2.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										830
									
								
								drivers/staging/media/ipu3/ipu3.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										830
									
								
								drivers/staging/media/ipu3/ipu3.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,830 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2017 - 2018 Intel Corporation
 | 
			
		||||
 * Copyright 2017 Google LLC
 | 
			
		||||
 *
 | 
			
		||||
 * Based on Intel IPU4 driver.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/pm_runtime.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3.h"
 | 
			
		||||
#include "ipu3-dmamap.h"
 | 
			
		||||
#include "ipu3-mmu.h"
 | 
			
		||||
 | 
			
		||||
#define IMGU_PCI_ID			0x1919
 | 
			
		||||
#define IMGU_PCI_BAR			0
 | 
			
		||||
#define IMGU_DMA_MASK			DMA_BIT_MASK(39)
 | 
			
		||||
#define IMGU_MAX_QUEUE_DEPTH		(2 + 2)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pre-allocated buffer size for IMGU dummy buffers. Those
 | 
			
		||||
 * values should be tuned to big enough to avoid buffer
 | 
			
		||||
 * re-allocation when streaming to lower streaming latency.
 | 
			
		||||
 */
 | 
			
		||||
#define CSS_QUEUE_IN_BUF_SIZE		0
 | 
			
		||||
#define CSS_QUEUE_PARAMS_BUF_SIZE	0
 | 
			
		||||
#define CSS_QUEUE_OUT_BUF_SIZE		(4160 * 3120 * 12 / 8)
 | 
			
		||||
#define CSS_QUEUE_VF_BUF_SIZE		(1920 * 1080 * 12 / 8)
 | 
			
		||||
#define CSS_QUEUE_STAT_3A_BUF_SIZE	sizeof(struct ipu3_uapi_stats_3a)
 | 
			
		||||
 | 
			
		||||
static const size_t css_queue_buf_size_map[IPU3_CSS_QUEUES] = {
 | 
			
		||||
	[IPU3_CSS_QUEUE_IN] = CSS_QUEUE_IN_BUF_SIZE,
 | 
			
		||||
	[IPU3_CSS_QUEUE_PARAMS] = CSS_QUEUE_PARAMS_BUF_SIZE,
 | 
			
		||||
	[IPU3_CSS_QUEUE_OUT] = CSS_QUEUE_OUT_BUF_SIZE,
 | 
			
		||||
	[IPU3_CSS_QUEUE_VF] = CSS_QUEUE_VF_BUF_SIZE,
 | 
			
		||||
	[IPU3_CSS_QUEUE_STAT_3A] = CSS_QUEUE_STAT_3A_BUF_SIZE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct imgu_node_mapping imgu_node_map[IMGU_NODE_NUM] = {
 | 
			
		||||
	[IMGU_NODE_IN] = {IPU3_CSS_QUEUE_IN, "input"},
 | 
			
		||||
	[IMGU_NODE_PARAMS] = {IPU3_CSS_QUEUE_PARAMS, "parameters"},
 | 
			
		||||
	[IMGU_NODE_OUT] = {IPU3_CSS_QUEUE_OUT, "output"},
 | 
			
		||||
	[IMGU_NODE_VF] = {IPU3_CSS_QUEUE_VF, "viewfinder"},
 | 
			
		||||
	[IMGU_NODE_STAT_3A] = {IPU3_CSS_QUEUE_STAT_3A, "3a stat"},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
unsigned int imgu_node_to_queue(unsigned int node)
 | 
			
		||||
{
 | 
			
		||||
	return imgu_node_map[node].css_queue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IMGU_NODE_NUM; i++)
 | 
			
		||||
		if (imgu_node_map[i].css_queue == css_queue)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**************** Dummy buffers ****************/
 | 
			
		||||
 | 
			
		||||
static void imgu_dummybufs_cleanup(struct imgu_device *imgu, unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IPU3_CSS_QUEUES; i++)
 | 
			
		||||
		ipu3_dmamap_free(imgu,
 | 
			
		||||
				 &imgu_pipe->queues[i].dmap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int imgu_dummybufs_preallocate(struct imgu_device *imgu,
 | 
			
		||||
				      unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
 | 
			
		||||
		size = css_queue_buf_size_map[i];
 | 
			
		||||
		/*
 | 
			
		||||
		 * Do not enable dummy buffers for master queue,
 | 
			
		||||
		 * always require that real buffers from user are
 | 
			
		||||
		 * available.
 | 
			
		||||
		 */
 | 
			
		||||
		if (i == IMGU_QUEUE_MASTER || size == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!ipu3_dmamap_alloc(imgu,
 | 
			
		||||
				       &imgu_pipe->queues[i].dmap, size)) {
 | 
			
		||||
			imgu_dummybufs_cleanup(imgu, pipe);
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int imgu_dummybufs_init(struct imgu_device *imgu, unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	const struct v4l2_pix_format_mplane *mpix;
 | 
			
		||||
	const struct v4l2_meta_format	*meta;
 | 
			
		||||
	unsigned int i, k, node;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	/* Allocate a dummy buffer for each queue where buffer is optional */
 | 
			
		||||
	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
 | 
			
		||||
		node = imgu_map_node(imgu, i);
 | 
			
		||||
		if (!imgu_pipe->queue_enabled[node] || i == IMGU_QUEUE_MASTER)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!imgu_pipe->nodes[IMGU_NODE_VF].enabled &&
 | 
			
		||||
		    i == IPU3_CSS_QUEUE_VF)
 | 
			
		||||
			/*
 | 
			
		||||
			 * Do not enable dummy buffers for VF if it is not
 | 
			
		||||
			 * requested by the user.
 | 
			
		||||
			 */
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		meta = &imgu_pipe->nodes[node].vdev_fmt.fmt.meta;
 | 
			
		||||
		mpix = &imgu_pipe->nodes[node].vdev_fmt.fmt.pix_mp;
 | 
			
		||||
 | 
			
		||||
		if (node == IMGU_NODE_STAT_3A || node == IMGU_NODE_PARAMS)
 | 
			
		||||
			size = meta->buffersize;
 | 
			
		||||
		else
 | 
			
		||||
			size = mpix->plane_fmt[0].sizeimage;
 | 
			
		||||
 | 
			
		||||
		if (ipu3_css_dma_buffer_resize(imgu,
 | 
			
		||||
					       &imgu_pipe->queues[i].dmap,
 | 
			
		||||
					       size)) {
 | 
			
		||||
			imgu_dummybufs_cleanup(imgu, pipe);
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (k = 0; k < IMGU_MAX_QUEUE_DEPTH; k++)
 | 
			
		||||
			ipu3_css_buf_init(&imgu_pipe->queues[i].dummybufs[k], i,
 | 
			
		||||
					  imgu_pipe->queues[i].dmap.daddr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* May be called from atomic context */
 | 
			
		||||
static struct ipu3_css_buffer *imgu_dummybufs_get(struct imgu_device *imgu,
 | 
			
		||||
						   int queue, unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	/* dummybufs are not allocated for master q */
 | 
			
		||||
	if (queue == IPU3_CSS_QUEUE_IN)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(!imgu_pipe->queues[queue].dmap.vaddr))
 | 
			
		||||
		/* Buffer should not be allocated here */
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IMGU_MAX_QUEUE_DEPTH; i++)
 | 
			
		||||
		if (ipu3_css_buf_state(&imgu_pipe->queues[queue].dummybufs[i]) !=
 | 
			
		||||
			IPU3_CSS_BUFFER_QUEUED)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	if (i == IMGU_MAX_QUEUE_DEPTH)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	ipu3_css_buf_init(&imgu_pipe->queues[queue].dummybufs[i], queue,
 | 
			
		||||
			  imgu_pipe->queues[queue].dmap.daddr);
 | 
			
		||||
 | 
			
		||||
	return &imgu_pipe->queues[queue].dummybufs[i];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check if given buffer is a dummy buffer */
 | 
			
		||||
static bool imgu_dummybufs_check(struct imgu_device *imgu,
 | 
			
		||||
				 struct ipu3_css_buffer *buf,
 | 
			
		||||
				 unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IMGU_MAX_QUEUE_DEPTH; i++)
 | 
			
		||||
		if (buf == &imgu_pipe->queues[buf->queue].dummybufs[i])
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	return i < IMGU_MAX_QUEUE_DEPTH;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void imgu_buffer_done(struct imgu_device *imgu, struct vb2_buffer *vb,
 | 
			
		||||
			     enum vb2_buffer_state state)
 | 
			
		||||
{
 | 
			
		||||
	mutex_lock(&imgu->lock);
 | 
			
		||||
	imgu_v4l2_buffer_done(vb, state);
 | 
			
		||||
	mutex_unlock(&imgu->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct ipu3_css_buffer *imgu_queue_getbuf(struct imgu_device *imgu,
 | 
			
		||||
						 unsigned int node,
 | 
			
		||||
						 unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_buffer *buf;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(node >= IMGU_NODE_NUM))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* Find first free buffer from the node */
 | 
			
		||||
	list_for_each_entry(buf, &imgu_pipe->nodes[node].buffers, vid_buf.list) {
 | 
			
		||||
		if (ipu3_css_buf_state(&buf->css_buf) == IPU3_CSS_BUFFER_NEW)
 | 
			
		||||
			return &buf->css_buf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* There were no free buffers, try to return a dummy buffer */
 | 
			
		||||
	return imgu_dummybufs_get(imgu, imgu_node_map[node].css_queue, pipe);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Queue as many buffers to CSS as possible. If all buffers don't fit into
 | 
			
		||||
 * CSS buffer queues, they remain unqueued and will be queued later.
 | 
			
		||||
 */
 | 
			
		||||
int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int node;
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
 | 
			
		||||
	if (!ipu3_css_is_streaming(&imgu->css))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(&imgu->pci_dev->dev, "Queue buffers to pipe %d", pipe);
 | 
			
		||||
	mutex_lock(&imgu->lock);
 | 
			
		||||
 | 
			
		||||
	/* Buffer set is queued to FW only when input buffer is ready */
 | 
			
		||||
	for (node = IMGU_NODE_NUM - 1;
 | 
			
		||||
	     imgu_queue_getbuf(imgu, IMGU_NODE_IN, pipe);
 | 
			
		||||
	     node = node ? node - 1 : IMGU_NODE_NUM - 1) {
 | 
			
		||||
 | 
			
		||||
		if (node == IMGU_NODE_VF &&
 | 
			
		||||
		    !imgu_pipe->nodes[IMGU_NODE_VF].enabled) {
 | 
			
		||||
			dev_warn(&imgu->pci_dev->dev,
 | 
			
		||||
				 "Vf not enabled, ignore queue");
 | 
			
		||||
			continue;
 | 
			
		||||
		} else if (imgu_pipe->queue_enabled[node]) {
 | 
			
		||||
			struct ipu3_css_buffer *buf =
 | 
			
		||||
				imgu_queue_getbuf(imgu, node, pipe);
 | 
			
		||||
			struct imgu_buffer *ibuf = NULL;
 | 
			
		||||
			bool dummy;
 | 
			
		||||
 | 
			
		||||
			if (!buf)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			r = ipu3_css_buf_queue(&imgu->css, pipe, buf);
 | 
			
		||||
			if (r)
 | 
			
		||||
				break;
 | 
			
		||||
			dummy = imgu_dummybufs_check(imgu, buf, pipe);
 | 
			
		||||
			if (!dummy)
 | 
			
		||||
				ibuf = container_of(buf, struct imgu_buffer,
 | 
			
		||||
						    css_buf);
 | 
			
		||||
			dev_dbg(&imgu->pci_dev->dev,
 | 
			
		||||
				"queue %s %s buffer %u to css da: 0x%08x\n",
 | 
			
		||||
				dummy ? "dummy" : "user",
 | 
			
		||||
				imgu_node_map[node].name,
 | 
			
		||||
				dummy ? 0 : ibuf->vid_buf.vbb.vb2_buf.index,
 | 
			
		||||
				(u32)buf->daddr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&imgu->lock);
 | 
			
		||||
 | 
			
		||||
	if (r && r != -EBUSY)
 | 
			
		||||
		goto failed;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
failed:
 | 
			
		||||
	/*
 | 
			
		||||
	 * On error, mark all buffers as failed which are not
 | 
			
		||||
	 * yet queued to CSS
 | 
			
		||||
	 */
 | 
			
		||||
	dev_err(&imgu->pci_dev->dev,
 | 
			
		||||
		"failed to queue buffer to CSS on queue %i (%d)\n",
 | 
			
		||||
		node, r);
 | 
			
		||||
 | 
			
		||||
	if (initial)
 | 
			
		||||
		/* If we were called from streamon(), no need to finish bufs */
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	for (node = 0; node < IMGU_NODE_NUM; node++) {
 | 
			
		||||
		struct imgu_buffer *buf, *buf0;
 | 
			
		||||
 | 
			
		||||
		if (!imgu_pipe->queue_enabled[node])
 | 
			
		||||
			continue;	/* Skip disabled queues */
 | 
			
		||||
 | 
			
		||||
		mutex_lock(&imgu->lock);
 | 
			
		||||
		list_for_each_entry_safe(buf, buf0,
 | 
			
		||||
					 &imgu_pipe->nodes[node].buffers,
 | 
			
		||||
					 vid_buf.list) {
 | 
			
		||||
			if (ipu3_css_buf_state(&buf->css_buf) ==
 | 
			
		||||
			    IPU3_CSS_BUFFER_QUEUED)
 | 
			
		||||
				continue;	/* Was already queued, skip */
 | 
			
		||||
 | 
			
		||||
			imgu_v4l2_buffer_done(&buf->vid_buf.vbb.vb2_buf,
 | 
			
		||||
					      VB2_BUF_STATE_ERROR);
 | 
			
		||||
		}
 | 
			
		||||
		mutex_unlock(&imgu->lock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int imgu_powerup(struct imgu_device *imgu)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	r = ipu3_css_set_powerup(&imgu->pci_dev->dev, imgu->base);
 | 
			
		||||
	if (r)
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	ipu3_mmu_resume(imgu->mmu);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void imgu_powerdown(struct imgu_device *imgu)
 | 
			
		||||
{
 | 
			
		||||
	ipu3_mmu_suspend(imgu->mmu);
 | 
			
		||||
	ipu3_css_set_powerdown(&imgu->pci_dev->dev, imgu->base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int imgu_s_stream(struct imgu_device *imgu, int enable)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &imgu->pci_dev->dev;
 | 
			
		||||
	int r, pipe;
 | 
			
		||||
 | 
			
		||||
	if (!enable) {
 | 
			
		||||
		/* Stop streaming */
 | 
			
		||||
		dev_dbg(dev, "stream off\n");
 | 
			
		||||
		/* Block new buffers to be queued to CSS. */
 | 
			
		||||
		atomic_set(&imgu->qbuf_barrier, 1);
 | 
			
		||||
		ipu3_css_stop_streaming(&imgu->css);
 | 
			
		||||
		synchronize_irq(imgu->pci_dev->irq);
 | 
			
		||||
		atomic_set(&imgu->qbuf_barrier, 0);
 | 
			
		||||
		imgu_powerdown(imgu);
 | 
			
		||||
		pm_runtime_put(&imgu->pci_dev->dev);
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set Power */
 | 
			
		||||
	r = pm_runtime_get_sync(dev);
 | 
			
		||||
	if (r < 0) {
 | 
			
		||||
		dev_err(dev, "failed to set imgu power\n");
 | 
			
		||||
		pm_runtime_put(dev);
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = imgu_powerup(imgu);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(dev, "failed to power up imgu\n");
 | 
			
		||||
		pm_runtime_put(dev);
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Start CSS streaming */
 | 
			
		||||
	r = ipu3_css_start_streaming(&imgu->css);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(dev, "failed to start css streaming (%d)", r);
 | 
			
		||||
		goto fail_start_streaming;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
 | 
			
		||||
		/* Initialize dummy buffers */
 | 
			
		||||
		r = imgu_dummybufs_init(imgu, pipe);
 | 
			
		||||
		if (r) {
 | 
			
		||||
			dev_err(dev, "failed to initialize dummy buffers (%d)", r);
 | 
			
		||||
			goto fail_dummybufs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Queue as many buffers from queue as possible */
 | 
			
		||||
		r = imgu_queue_buffers(imgu, true, pipe);
 | 
			
		||||
		if (r) {
 | 
			
		||||
			dev_err(dev, "failed to queue initial buffers (%d)", r);
 | 
			
		||||
			goto fail_queueing;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
fail_queueing:
 | 
			
		||||
	for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM)
 | 
			
		||||
		imgu_dummybufs_cleanup(imgu, pipe);
 | 
			
		||||
fail_dummybufs:
 | 
			
		||||
	ipu3_css_stop_streaming(&imgu->css);
 | 
			
		||||
fail_start_streaming:
 | 
			
		||||
	pm_runtime_put(dev);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int imgu_video_nodes_init(struct imgu_device *imgu)
 | 
			
		||||
{
 | 
			
		||||
	struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
 | 
			
		||||
	struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe;
 | 
			
		||||
	unsigned int i, j;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	imgu->buf_struct_size = sizeof(struct imgu_buffer);
 | 
			
		||||
 | 
			
		||||
	for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) {
 | 
			
		||||
		imgu_pipe = &imgu->imgu_pipe[j];
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < IMGU_NODE_NUM; i++) {
 | 
			
		||||
			imgu_pipe->nodes[i].name = imgu_node_map[i].name;
 | 
			
		||||
			imgu_pipe->nodes[i].output = i < IMGU_QUEUE_FIRST_INPUT;
 | 
			
		||||
			imgu_pipe->nodes[i].enabled = false;
 | 
			
		||||
 | 
			
		||||
			if (i != IMGU_NODE_PARAMS && i != IMGU_NODE_STAT_3A)
 | 
			
		||||
				fmts[imgu_node_map[i].css_queue] =
 | 
			
		||||
					&imgu_pipe->nodes[i].vdev_fmt.fmt.pix_mp;
 | 
			
		||||
			atomic_set(&imgu_pipe->nodes[i].sequence, 0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = imgu_v4l2_register(imgu);
 | 
			
		||||
	if (r)
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	/* Set initial formats and initialize formats of video nodes */
 | 
			
		||||
	for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) {
 | 
			
		||||
		imgu_pipe = &imgu->imgu_pipe[j];
 | 
			
		||||
 | 
			
		||||
		rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_pipe->imgu_sd.rect.eff;
 | 
			
		||||
		rects[IPU3_CSS_RECT_BDS] = &imgu_pipe->imgu_sd.rect.bds;
 | 
			
		||||
		ipu3_css_fmt_set(&imgu->css, fmts, rects, j);
 | 
			
		||||
 | 
			
		||||
		/* Pre-allocate dummy buffers */
 | 
			
		||||
		r = imgu_dummybufs_preallocate(imgu, j);
 | 
			
		||||
		if (r) {
 | 
			
		||||
			dev_err(&imgu->pci_dev->dev,
 | 
			
		||||
				"failed to pre-allocate dummy buffers (%d)", r);
 | 
			
		||||
			goto out_cleanup;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_cleanup:
 | 
			
		||||
	for (j = 0; j < IMGU_MAX_PIPE_NUM; j++)
 | 
			
		||||
		imgu_dummybufs_cleanup(imgu, j);
 | 
			
		||||
 | 
			
		||||
	imgu_v4l2_unregister(imgu);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void imgu_video_nodes_exit(struct imgu_device *imgu)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IMGU_MAX_PIPE_NUM; i++)
 | 
			
		||||
		imgu_dummybufs_cleanup(imgu, i);
 | 
			
		||||
 | 
			
		||||
	imgu_v4l2_unregister(imgu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**************** PCI interface ****************/
 | 
			
		||||
 | 
			
		||||
static irqreturn_t imgu_isr_threaded(int irq, void *imgu_ptr)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_device *imgu = imgu_ptr;
 | 
			
		||||
	struct imgu_media_pipe *imgu_pipe;
 | 
			
		||||
	int p;
 | 
			
		||||
 | 
			
		||||
	/* Dequeue / queue buffers */
 | 
			
		||||
	do {
 | 
			
		||||
		u64 ns = ktime_get_ns();
 | 
			
		||||
		struct ipu3_css_buffer *b;
 | 
			
		||||
		struct imgu_buffer *buf = NULL;
 | 
			
		||||
		unsigned int node, pipe;
 | 
			
		||||
		bool dummy;
 | 
			
		||||
 | 
			
		||||
		do {
 | 
			
		||||
			mutex_lock(&imgu->lock);
 | 
			
		||||
			b = ipu3_css_buf_dequeue(&imgu->css);
 | 
			
		||||
			mutex_unlock(&imgu->lock);
 | 
			
		||||
		} while (PTR_ERR(b) == -EAGAIN);
 | 
			
		||||
 | 
			
		||||
		if (IS_ERR_OR_NULL(b)) {
 | 
			
		||||
			if (!b || PTR_ERR(b) == -EBUSY)	/* All done */
 | 
			
		||||
				break;
 | 
			
		||||
			dev_err(&imgu->pci_dev->dev,
 | 
			
		||||
				"failed to dequeue buffers (%ld)\n",
 | 
			
		||||
				PTR_ERR(b));
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		node = imgu_map_node(imgu, b->queue);
 | 
			
		||||
		pipe = b->pipe;
 | 
			
		||||
		dummy = imgu_dummybufs_check(imgu, b, pipe);
 | 
			
		||||
		if (!dummy)
 | 
			
		||||
			buf = container_of(b, struct imgu_buffer, css_buf);
 | 
			
		||||
		dev_dbg(&imgu->pci_dev->dev,
 | 
			
		||||
			"dequeue %s %s buffer %d daddr 0x%x from css\n",
 | 
			
		||||
			dummy ? "dummy" : "user",
 | 
			
		||||
			imgu_node_map[node].name,
 | 
			
		||||
			dummy ? 0 : buf->vid_buf.vbb.vb2_buf.index,
 | 
			
		||||
			(u32)b->daddr);
 | 
			
		||||
 | 
			
		||||
		if (dummy)
 | 
			
		||||
			/* It was a dummy buffer, skip it */
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Fill vb2 buffer entries and tell it's ready */
 | 
			
		||||
		imgu_pipe = &imgu->imgu_pipe[pipe];
 | 
			
		||||
		if (!imgu_pipe->nodes[node].output) {
 | 
			
		||||
			buf->vid_buf.vbb.vb2_buf.timestamp = ns;
 | 
			
		||||
			buf->vid_buf.vbb.field = V4L2_FIELD_NONE;
 | 
			
		||||
			buf->vid_buf.vbb.sequence =
 | 
			
		||||
				atomic_inc_return(
 | 
			
		||||
				&imgu_pipe->nodes[node].sequence);
 | 
			
		||||
			dev_dbg(&imgu->pci_dev->dev, "vb2 buffer sequence %d",
 | 
			
		||||
				buf->vid_buf.vbb.sequence);
 | 
			
		||||
		}
 | 
			
		||||
		imgu_buffer_done(imgu, &buf->vid_buf.vbb.vb2_buf,
 | 
			
		||||
				 ipu3_css_buf_state(&buf->css_buf) ==
 | 
			
		||||
						    IPU3_CSS_BUFFER_DONE ?
 | 
			
		||||
						    VB2_BUF_STATE_DONE :
 | 
			
		||||
						    VB2_BUF_STATE_ERROR);
 | 
			
		||||
		mutex_lock(&imgu->lock);
 | 
			
		||||
		if (ipu3_css_queue_empty(&imgu->css))
 | 
			
		||||
			wake_up_all(&imgu->buf_drain_wq);
 | 
			
		||||
		mutex_unlock(&imgu->lock);
 | 
			
		||||
	} while (1);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Try to queue more buffers for CSS.
 | 
			
		||||
	 * qbuf_barrier is used to disable new buffers
 | 
			
		||||
	 * to be queued to CSS.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!atomic_read(&imgu->qbuf_barrier))
 | 
			
		||||
		for_each_set_bit(p, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM)
 | 
			
		||||
			imgu_queue_buffers(imgu, false, p);
 | 
			
		||||
 | 
			
		||||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static irqreturn_t imgu_isr(int irq, void *imgu_ptr)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_device *imgu = imgu_ptr;
 | 
			
		||||
 | 
			
		||||
	/* acknowledge interruption */
 | 
			
		||||
	if (ipu3_css_irq_ack(&imgu->css) < 0)
 | 
			
		||||
		return IRQ_NONE;
 | 
			
		||||
 | 
			
		||||
	return IRQ_WAKE_THREAD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int imgu_pci_config_setup(struct pci_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	u16 pci_command;
 | 
			
		||||
	int r = pci_enable_msi(dev);
 | 
			
		||||
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&dev->dev, "failed to enable MSI (%d)\n", r);
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
 | 
			
		||||
	pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
 | 
			
		||||
			PCI_COMMAND_INTX_DISABLE;
 | 
			
		||||
	pci_write_config_word(dev, PCI_COMMAND, pci_command);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int imgu_pci_probe(struct pci_dev *pci_dev,
 | 
			
		||||
			  const struct pci_device_id *id)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_device *imgu;
 | 
			
		||||
	phys_addr_t phys;
 | 
			
		||||
	unsigned long phys_len;
 | 
			
		||||
	void __iomem *const *iomap;
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	imgu = devm_kzalloc(&pci_dev->dev, sizeof(*imgu), GFP_KERNEL);
 | 
			
		||||
	if (!imgu)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	imgu->pci_dev = pci_dev;
 | 
			
		||||
 | 
			
		||||
	r = pcim_enable_device(pci_dev);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to enable device (%d)\n", r);
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dev_info(&pci_dev->dev, "device 0x%x (rev: 0x%x)\n",
 | 
			
		||||
		 pci_dev->device, pci_dev->revision);
 | 
			
		||||
 | 
			
		||||
	phys = pci_resource_start(pci_dev, IMGU_PCI_BAR);
 | 
			
		||||
	phys_len = pci_resource_len(pci_dev, IMGU_PCI_BAR);
 | 
			
		||||
 | 
			
		||||
	r = pcim_iomap_regions(pci_dev, 1 << IMGU_PCI_BAR, pci_name(pci_dev));
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to remap I/O memory (%d)\n", r);
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
	dev_info(&pci_dev->dev, "physical base address %pap, %lu bytes\n",
 | 
			
		||||
		 &phys, phys_len);
 | 
			
		||||
 | 
			
		||||
	iomap = pcim_iomap_table(pci_dev);
 | 
			
		||||
	if (!iomap) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to iomap table\n");
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imgu->base = iomap[IMGU_PCI_BAR];
 | 
			
		||||
 | 
			
		||||
	pci_set_drvdata(pci_dev, imgu);
 | 
			
		||||
 | 
			
		||||
	pci_set_master(pci_dev);
 | 
			
		||||
 | 
			
		||||
	r = dma_coerce_mask_and_coherent(&pci_dev->dev, IMGU_DMA_MASK);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to set DMA mask (%d)\n", r);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = imgu_pci_config_setup(pci_dev);
 | 
			
		||||
	if (r)
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	mutex_init(&imgu->lock);
 | 
			
		||||
	atomic_set(&imgu->qbuf_barrier, 0);
 | 
			
		||||
	init_waitqueue_head(&imgu->buf_drain_wq);
 | 
			
		||||
 | 
			
		||||
	r = ipu3_css_set_powerup(&pci_dev->dev, imgu->base);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev,
 | 
			
		||||
			"failed to power up CSS (%d)\n", r);
 | 
			
		||||
		goto out_mutex_destroy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imgu->mmu = ipu3_mmu_init(&pci_dev->dev, imgu->base);
 | 
			
		||||
	if (IS_ERR(imgu->mmu)) {
 | 
			
		||||
		r = PTR_ERR(imgu->mmu);
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to initialize MMU (%d)\n", r);
 | 
			
		||||
		goto out_css_powerdown;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = ipu3_dmamap_init(imgu);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev,
 | 
			
		||||
			"failed to initialize DMA mapping (%d)\n", r);
 | 
			
		||||
		goto out_mmu_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* ISP programming */
 | 
			
		||||
	r = ipu3_css_init(&pci_dev->dev, &imgu->css, imgu->base, phys_len);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to initialize CSS (%d)\n", r);
 | 
			
		||||
		goto out_dmamap_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* v4l2 sub-device registration */
 | 
			
		||||
	r = imgu_video_nodes_init(imgu);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to create V4L2 devices (%d)\n",
 | 
			
		||||
			r);
 | 
			
		||||
		goto out_css_cleanup;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = devm_request_threaded_irq(&pci_dev->dev, pci_dev->irq,
 | 
			
		||||
				      imgu_isr, imgu_isr_threaded,
 | 
			
		||||
				      IRQF_SHARED, IMGU_NAME, imgu);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r);
 | 
			
		||||
		goto out_video_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pm_runtime_put_noidle(&pci_dev->dev);
 | 
			
		||||
	pm_runtime_allow(&pci_dev->dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
out_video_exit:
 | 
			
		||||
	imgu_video_nodes_exit(imgu);
 | 
			
		||||
out_css_cleanup:
 | 
			
		||||
	ipu3_css_cleanup(&imgu->css);
 | 
			
		||||
out_dmamap_exit:
 | 
			
		||||
	ipu3_dmamap_exit(imgu);
 | 
			
		||||
out_mmu_exit:
 | 
			
		||||
	ipu3_mmu_exit(imgu->mmu);
 | 
			
		||||
out_css_powerdown:
 | 
			
		||||
	ipu3_css_set_powerdown(&pci_dev->dev, imgu->base);
 | 
			
		||||
out_mutex_destroy:
 | 
			
		||||
	mutex_destroy(&imgu->lock);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void imgu_pci_remove(struct pci_dev *pci_dev)
 | 
			
		||||
{
 | 
			
		||||
	struct imgu_device *imgu = pci_get_drvdata(pci_dev);
 | 
			
		||||
 | 
			
		||||
	pm_runtime_forbid(&pci_dev->dev);
 | 
			
		||||
	pm_runtime_get_noresume(&pci_dev->dev);
 | 
			
		||||
 | 
			
		||||
	imgu_video_nodes_exit(imgu);
 | 
			
		||||
	ipu3_css_cleanup(&imgu->css);
 | 
			
		||||
	ipu3_css_set_powerdown(&pci_dev->dev, imgu->base);
 | 
			
		||||
	ipu3_dmamap_exit(imgu);
 | 
			
		||||
	ipu3_mmu_exit(imgu->mmu);
 | 
			
		||||
	mutex_destroy(&imgu->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __maybe_unused imgu_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct pci_dev *pci_dev = to_pci_dev(dev);
 | 
			
		||||
	struct imgu_device *imgu = pci_get_drvdata(pci_dev);
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "enter %s\n", __func__);
 | 
			
		||||
	imgu->suspend_in_stream = ipu3_css_is_streaming(&imgu->css);
 | 
			
		||||
	if (!imgu->suspend_in_stream)
 | 
			
		||||
		goto out;
 | 
			
		||||
	/* Block new buffers to be queued to CSS. */
 | 
			
		||||
	atomic_set(&imgu->qbuf_barrier, 1);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Wait for currently running irq handler to be done so that
 | 
			
		||||
	 * no new buffers will be queued to fw later.
 | 
			
		||||
	 */
 | 
			
		||||
	synchronize_irq(pci_dev->irq);
 | 
			
		||||
	/* Wait until all buffers in CSS are done. */
 | 
			
		||||
	if (!wait_event_timeout(imgu->buf_drain_wq,
 | 
			
		||||
	    ipu3_css_queue_empty(&imgu->css), msecs_to_jiffies(1000)))
 | 
			
		||||
		dev_err(dev, "wait buffer drain timeout.\n");
 | 
			
		||||
 | 
			
		||||
	ipu3_css_stop_streaming(&imgu->css);
 | 
			
		||||
	atomic_set(&imgu->qbuf_barrier, 0);
 | 
			
		||||
	imgu_powerdown(imgu);
 | 
			
		||||
	pm_runtime_force_suspend(dev);
 | 
			
		||||
out:
 | 
			
		||||
	dev_dbg(dev, "leave %s\n", __func__);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int __maybe_unused imgu_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct pci_dev *pci_dev = to_pci_dev(dev);
 | 
			
		||||
	struct imgu_device *imgu = pci_get_drvdata(pci_dev);
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	unsigned int pipe;
 | 
			
		||||
 | 
			
		||||
	dev_dbg(dev, "enter %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	if (!imgu->suspend_in_stream)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	pm_runtime_force_resume(dev);
 | 
			
		||||
 | 
			
		||||
	r = imgu_powerup(imgu);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(dev, "failed to power up imgu\n");
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Start CSS streaming */
 | 
			
		||||
	r = ipu3_css_start_streaming(&imgu->css);
 | 
			
		||||
	if (r) {
 | 
			
		||||
		dev_err(dev, "failed to resume css streaming (%d)", r);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
 | 
			
		||||
		r = imgu_queue_buffers(imgu, true, pipe);
 | 
			
		||||
		if (r)
 | 
			
		||||
			dev_err(dev, "failed to queue buffers to pipe %d (%d)",
 | 
			
		||||
				pipe, r);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	dev_dbg(dev, "leave %s\n", __func__);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * PCI rpm framework checks the existence of driver rpm callbacks.
 | 
			
		||||
 * Place a dummy callback here to avoid rpm going into error state.
 | 
			
		||||
 */
 | 
			
		||||
static int imgu_rpm_dummy_cb(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct dev_pm_ops imgu_pm_ops = {
 | 
			
		||||
	SET_RUNTIME_PM_OPS(&imgu_rpm_dummy_cb, &imgu_rpm_dummy_cb, NULL)
 | 
			
		||||
	SET_SYSTEM_SLEEP_PM_OPS(&imgu_suspend, &imgu_resume)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct pci_device_id imgu_pci_tbl[] = {
 | 
			
		||||
	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, IMGU_PCI_ID) },
 | 
			
		||||
	{ 0, }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
MODULE_DEVICE_TABLE(pci, imgu_pci_tbl);
 | 
			
		||||
 | 
			
		||||
static struct pci_driver imgu_pci_driver = {
 | 
			
		||||
	.name = IMGU_NAME,
 | 
			
		||||
	.id_table = imgu_pci_tbl,
 | 
			
		||||
	.probe = imgu_pci_probe,
 | 
			
		||||
	.remove = imgu_pci_remove,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.pm = &imgu_pm_ops,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_pci_driver(imgu_pci_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Tuukka Toivonen <tuukka.toivonen@intel.com>");
 | 
			
		||||
MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
 | 
			
		||||
MODULE_AUTHOR("Jian Xu Zheng <jian.xu.zheng@intel.com>");
 | 
			
		||||
MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>");
 | 
			
		||||
MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
 | 
			
		||||
MODULE_LICENSE("GPL v2");
 | 
			
		||||
MODULE_DESCRIPTION("Intel ipu3_imgu PCI driver");
 | 
			
		||||
							
								
								
									
										168
									
								
								drivers/staging/media/ipu3/ipu3.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								drivers/staging/media/ipu3/ipu3.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,168 @@
 | 
			
		||||
/* SPDX-License-Identifier: GPL-2.0 */
 | 
			
		||||
/* Copyright (C) 2018 Intel Corporation */
 | 
			
		||||
 | 
			
		||||
#ifndef __IPU3_H
 | 
			
		||||
#define __IPU3_H
 | 
			
		||||
 | 
			
		||||
#include <linux/iova.h>
 | 
			
		||||
#include <linux/pci.h>
 | 
			
		||||
 | 
			
		||||
#include <media/v4l2-ctrls.h>
 | 
			
		||||
#include <media/v4l2-device.h>
 | 
			
		||||
#include <media/videobuf2-dma-sg.h>
 | 
			
		||||
 | 
			
		||||
#include "ipu3-css.h"
 | 
			
		||||
 | 
			
		||||
#define IMGU_NAME			"ipu3-imgu"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The semantics of the driver is that whenever there is a buffer available in
 | 
			
		||||
 * master queue, the driver queues a buffer also to all other active nodes.
 | 
			
		||||
 * If user space hasn't provided a buffer to all other video nodes first,
 | 
			
		||||
 * the driver gets an internal dummy buffer and queues it.
 | 
			
		||||
 */
 | 
			
		||||
#define IMGU_QUEUE_MASTER		IPU3_CSS_QUEUE_IN
 | 
			
		||||
#define IMGU_QUEUE_FIRST_INPUT		IPU3_CSS_QUEUE_OUT
 | 
			
		||||
#define IMGU_MAX_QUEUE_DEPTH		(2 + 2)
 | 
			
		||||
 | 
			
		||||
#define IMGU_NODE_IN			0 /* Input RAW image */
 | 
			
		||||
#define IMGU_NODE_PARAMS		1 /* Input parameters */
 | 
			
		||||
#define IMGU_NODE_OUT			2 /* Main output for still or video */
 | 
			
		||||
#define IMGU_NODE_VF			3 /* Preview */
 | 
			
		||||
#define IMGU_NODE_STAT_3A		4 /* 3A statistics */
 | 
			
		||||
#define IMGU_NODE_NUM			5
 | 
			
		||||
 | 
			
		||||
#define file_to_intel_ipu3_node(__file) \
 | 
			
		||||
	container_of(video_devdata(__file), struct imgu_video_device, vdev)
 | 
			
		||||
 | 
			
		||||
#define IPU3_INPUT_MIN_WIDTH		0U
 | 
			
		||||
#define IPU3_INPUT_MIN_HEIGHT		0U
 | 
			
		||||
#define IPU3_INPUT_MAX_WIDTH		5120U
 | 
			
		||||
#define IPU3_INPUT_MAX_HEIGHT		38404U
 | 
			
		||||
#define IPU3_OUTPUT_MIN_WIDTH		2U
 | 
			
		||||
#define IPU3_OUTPUT_MIN_HEIGHT		2U
 | 
			
		||||
#define IPU3_OUTPUT_MAX_WIDTH		4480U
 | 
			
		||||
#define IPU3_OUTPUT_MAX_HEIGHT		34004U
 | 
			
		||||
 | 
			
		||||
struct ipu3_vb2_buffer {
 | 
			
		||||
	/* Public fields */
 | 
			
		||||
	struct vb2_v4l2_buffer vbb;	/* Must be the first field */
 | 
			
		||||
 | 
			
		||||
	/* Private fields */
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_buffer {
 | 
			
		||||
	struct ipu3_vb2_buffer vid_buf;	/* Must be the first field */
 | 
			
		||||
	struct ipu3_css_buffer css_buf;
 | 
			
		||||
	struct ipu3_css_map map;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_node_mapping {
 | 
			
		||||
	unsigned int css_queue;
 | 
			
		||||
	const char *name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct imgu_video_device
 | 
			
		||||
 * each node registers as video device and maintains its
 | 
			
		||||
 * own vb2_queue.
 | 
			
		||||
 */
 | 
			
		||||
struct imgu_video_device {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	bool output;
 | 
			
		||||
	bool enabled;
 | 
			
		||||
	struct v4l2_format vdev_fmt;	/* Currently set format */
 | 
			
		||||
 | 
			
		||||
	/* Private fields */
 | 
			
		||||
	struct video_device vdev;
 | 
			
		||||
	struct media_pad vdev_pad;
 | 
			
		||||
	struct v4l2_mbus_framefmt pad_fmt;
 | 
			
		||||
	struct vb2_queue vbq;
 | 
			
		||||
	struct list_head buffers;
 | 
			
		||||
	/* Protect vb2_queue and vdev structs*/
 | 
			
		||||
	struct mutex lock;
 | 
			
		||||
	atomic_t sequence;
 | 
			
		||||
	unsigned int id;
 | 
			
		||||
	unsigned int pipe;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_v4l2_subdev {
 | 
			
		||||
	unsigned int pipe;
 | 
			
		||||
	struct v4l2_subdev subdev;
 | 
			
		||||
	struct media_pad subdev_pads[IMGU_NODE_NUM];
 | 
			
		||||
	struct {
 | 
			
		||||
		struct v4l2_rect eff; /* effective resolution */
 | 
			
		||||
		struct v4l2_rect bds; /* bayer-domain scaled resolution*/
 | 
			
		||||
		struct v4l2_rect gdc; /* gdc output resolution */
 | 
			
		||||
	} rect;
 | 
			
		||||
	struct v4l2_ctrl_handler ctrl_handler;
 | 
			
		||||
	struct v4l2_ctrl *ctrl;
 | 
			
		||||
	atomic_t running_mode;
 | 
			
		||||
	bool active;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgu_media_pipe {
 | 
			
		||||
	unsigned int pipe;
 | 
			
		||||
 | 
			
		||||
	/* Internally enabled queues */
 | 
			
		||||
	struct {
 | 
			
		||||
		struct ipu3_css_map dmap;
 | 
			
		||||
		struct ipu3_css_buffer dummybufs[IMGU_MAX_QUEUE_DEPTH];
 | 
			
		||||
	} queues[IPU3_CSS_QUEUES];
 | 
			
		||||
	struct imgu_video_device nodes[IMGU_NODE_NUM];
 | 
			
		||||
	bool queue_enabled[IMGU_NODE_NUM];
 | 
			
		||||
	struct media_pipeline pipeline;
 | 
			
		||||
	struct imgu_v4l2_subdev imgu_sd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * imgu_device -- ImgU (Imaging Unit) driver
 | 
			
		||||
 */
 | 
			
		||||
struct imgu_device {
 | 
			
		||||
	struct pci_dev *pci_dev;
 | 
			
		||||
	void __iomem *base;
 | 
			
		||||
 | 
			
		||||
	/* Public fields, fill before registering */
 | 
			
		||||
	unsigned int buf_struct_size;
 | 
			
		||||
	bool streaming;		/* Public read only */
 | 
			
		||||
 | 
			
		||||
	struct imgu_media_pipe imgu_pipe[IMGU_MAX_PIPE_NUM];
 | 
			
		||||
 | 
			
		||||
	/* Private fields */
 | 
			
		||||
	struct v4l2_device v4l2_dev;
 | 
			
		||||
	struct media_device media_dev;
 | 
			
		||||
	struct v4l2_file_operations v4l2_file_ops;
 | 
			
		||||
 | 
			
		||||
	/* MMU driver for css */
 | 
			
		||||
	struct ipu3_mmu_info *mmu;
 | 
			
		||||
	struct iova_domain iova_domain;
 | 
			
		||||
 | 
			
		||||
	/* css - Camera Sub-System */
 | 
			
		||||
	struct ipu3_css css;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Coarse-grained lock to protect
 | 
			
		||||
	 * vid_buf.list and css->queue
 | 
			
		||||
	 */
 | 
			
		||||
	struct mutex lock;
 | 
			
		||||
	/* Forbit streaming and buffer queuing during system suspend. */
 | 
			
		||||
	atomic_t qbuf_barrier;
 | 
			
		||||
	/* Indicate if system suspend take place while imgu is streaming. */
 | 
			
		||||
	bool suspend_in_stream;
 | 
			
		||||
	/* Used to wait for FW buffer queue drain. */
 | 
			
		||||
	wait_queue_head_t buf_drain_wq;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
unsigned int imgu_node_to_queue(unsigned int node);
 | 
			
		||||
unsigned int imgu_map_node(struct imgu_device *imgu, unsigned int css_queue);
 | 
			
		||||
int imgu_queue_buffers(struct imgu_device *imgu, bool initial,
 | 
			
		||||
		       unsigned int pipe);
 | 
			
		||||
 | 
			
		||||
int imgu_v4l2_register(struct imgu_device *dev);
 | 
			
		||||
int imgu_v4l2_unregister(struct imgu_device *dev);
 | 
			
		||||
void imgu_v4l2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
 | 
			
		||||
 | 
			
		||||
int imgu_s_stream(struct imgu_device *imgu, int enable);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -48,6 +48,9 @@ struct v4l2_fh;
 | 
			
		||||
 * @vidioc_enum_fmt_meta_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_ENUM_FMT <vidioc_enum_fmt>` ioctl logic
 | 
			
		||||
 *	for metadata capture
 | 
			
		||||
 * @vidioc_enum_fmt_meta_out: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_ENUM_FMT <vidioc_enum_fmt>` ioctl logic
 | 
			
		||||
 *	for metadata output
 | 
			
		||||
 * @vidioc_g_fmt_vid_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_G_FMT <vidioc_g_fmt>` ioctl logic for video capture
 | 
			
		||||
 *	in single plane mode
 | 
			
		||||
@ -80,6 +83,8 @@ struct v4l2_fh;
 | 
			
		||||
 *	Radio output
 | 
			
		||||
 * @vidioc_g_fmt_meta_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_G_FMT <vidioc_g_fmt>` ioctl logic for metadata capture
 | 
			
		||||
 * @vidioc_g_fmt_meta_out: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_G_FMT <vidioc_g_fmt>` ioctl logic for metadata output
 | 
			
		||||
 * @vidioc_s_fmt_vid_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_S_FMT <vidioc_g_fmt>` ioctl logic for video capture
 | 
			
		||||
 *	in single plane mode
 | 
			
		||||
@ -112,6 +117,8 @@ struct v4l2_fh;
 | 
			
		||||
 *	Radio output
 | 
			
		||||
 * @vidioc_s_fmt_meta_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_S_FMT <vidioc_g_fmt>` ioctl logic for metadata capture
 | 
			
		||||
 * @vidioc_s_fmt_meta_out: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_S_FMT <vidioc_g_fmt>` ioctl logic for metadata output
 | 
			
		||||
 * @vidioc_try_fmt_vid_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_TRY_FMT <vidioc_g_fmt>` ioctl logic for video capture
 | 
			
		||||
 *	in single plane mode
 | 
			
		||||
@ -146,6 +153,8 @@ struct v4l2_fh;
 | 
			
		||||
 *	Radio output
 | 
			
		||||
 * @vidioc_try_fmt_meta_cap: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_TRY_FMT <vidioc_g_fmt>` ioctl logic for metadata capture
 | 
			
		||||
 * @vidioc_try_fmt_meta_out: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_TRY_FMT <vidioc_g_fmt>` ioctl logic for metadata output
 | 
			
		||||
 * @vidioc_reqbufs: pointer to the function that implements
 | 
			
		||||
 *	:ref:`VIDIOC_REQBUFS <vidioc_reqbufs>` ioctl
 | 
			
		||||
 * @vidioc_querybuf: pointer to the function that implements
 | 
			
		||||
@ -314,6 +323,8 @@ struct v4l2_ioctl_ops {
 | 
			
		||||
				       struct v4l2_fmtdesc *f);
 | 
			
		||||
	int (*vidioc_enum_fmt_meta_cap)(struct file *file, void *fh,
 | 
			
		||||
					struct v4l2_fmtdesc *f);
 | 
			
		||||
	int (*vidioc_enum_fmt_meta_out)(struct file *file, void *fh,
 | 
			
		||||
					struct v4l2_fmtdesc *f);
 | 
			
		||||
 | 
			
		||||
	/* VIDIOC_G_FMT handlers */
 | 
			
		||||
	int (*vidioc_g_fmt_vid_cap)(struct file *file, void *fh,
 | 
			
		||||
@ -342,6 +353,8 @@ struct v4l2_ioctl_ops {
 | 
			
		||||
				    struct v4l2_format *f);
 | 
			
		||||
	int (*vidioc_g_fmt_meta_cap)(struct file *file, void *fh,
 | 
			
		||||
				     struct v4l2_format *f);
 | 
			
		||||
	int (*vidioc_g_fmt_meta_out)(struct file *file, void *fh,
 | 
			
		||||
				     struct v4l2_format *f);
 | 
			
		||||
 | 
			
		||||
	/* VIDIOC_S_FMT handlers */
 | 
			
		||||
	int (*vidioc_s_fmt_vid_cap)(struct file *file, void *fh,
 | 
			
		||||
@ -370,6 +383,8 @@ struct v4l2_ioctl_ops {
 | 
			
		||||
				    struct v4l2_format *f);
 | 
			
		||||
	int (*vidioc_s_fmt_meta_cap)(struct file *file, void *fh,
 | 
			
		||||
				     struct v4l2_format *f);
 | 
			
		||||
	int (*vidioc_s_fmt_meta_out)(struct file *file, void *fh,
 | 
			
		||||
				     struct v4l2_format *f);
 | 
			
		||||
 | 
			
		||||
	/* VIDIOC_TRY_FMT handlers */
 | 
			
		||||
	int (*vidioc_try_fmt_vid_cap)(struct file *file, void *fh,
 | 
			
		||||
@ -398,6 +413,8 @@ struct v4l2_ioctl_ops {
 | 
			
		||||
				      struct v4l2_format *f);
 | 
			
		||||
	int (*vidioc_try_fmt_meta_cap)(struct file *file, void *fh,
 | 
			
		||||
				       struct v4l2_format *f);
 | 
			
		||||
	int (*vidioc_try_fmt_meta_out)(struct file *file, void *fh,
 | 
			
		||||
				       struct v4l2_format *f);
 | 
			
		||||
 | 
			
		||||
	/* Buffer handlers */
 | 
			
		||||
	int (*vidioc_reqbufs)(struct file *file, void *fh,
 | 
			
		||||
 | 
			
		||||
@ -145,6 +145,7 @@ enum v4l2_buf_type {
 | 
			
		||||
	V4L2_BUF_TYPE_SDR_CAPTURE          = 11,
 | 
			
		||||
	V4L2_BUF_TYPE_SDR_OUTPUT           = 12,
 | 
			
		||||
	V4L2_BUF_TYPE_META_CAPTURE         = 13,
 | 
			
		||||
	V4L2_BUF_TYPE_META_OUTPUT	   = 14,
 | 
			
		||||
	/* Deprecated, do not use */
 | 
			
		||||
	V4L2_BUF_TYPE_PRIVATE              = 0x80,
 | 
			
		||||
};
 | 
			
		||||
@ -469,6 +470,7 @@ struct v4l2_capability {
 | 
			
		||||
#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
 | 
			
		||||
#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
 | 
			
		||||
#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
 | 
			
		||||
#define V4L2_CAP_META_OUTPUT		0x08000000  /* Is a metadata output device */
 | 
			
		||||
 | 
			
		||||
#define V4L2_CAP_TOUCH                  0x10000000  /* Is a touch device */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user