* [PATCH RFC 00/24] Lima DRM driver
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
Kernel DRM driver for ARM Mali 400/450 GPUs.
This implementation mainly take amdgpu DRM driver as reference.
- Mali 4xx GPUs have two kinds of processors GP and PP. GP is for
OpenGL vertex shader processing and PP is for fragment shader
processing. Each processor has its own MMU so prcessors work in
virtual address space.
- There's only one GP but multiple PP (max 4 for mali 400 and 8
for mali 450) in the same mali 4xx GPU. All PPs are grouped
togather to handle a single fragment shader task divided by
FB output tiled pixels. Mali 400 user space driver is
responsible for assign target tiled pixels to each PP, but mali
450 has a HW module called DLBU to dynamically balance each
PP's load.
- User space driver allocate buffer object and map into GPU
virtual address space, upload command stream and draw data with
CPU mmap of the buffer object, then submit task to GP/PP with
a register frame indicating where is the command stream and misc
settings.
- There's no command stream validation/relocation due to each user
process has its own GPU virtual address space. GP/PP's MMU switch
virtual address space before running two tasks from different
user process. Error or evil user space code just get MMU fault
or GP/PP error IRQ, then the HW/SW will be recovered.
- Use TTM as MM. TTM_PL_TT type memory is used as the content of
lima buffer object which is allocated from TTM page pool. all
lima buffer object gets pinned with TTM_PL_FLAG_NO_EVICT when
allocation, so there's no buffer eviction and swap for now. We
need reverse engineering to see if and how GP/PP support MMU
fault recovery (continue execution). Otherwise we have to
pin/unpin each envolved buffer when task creation/deletion.
- Use drm_sched for GPU task schedule. Each OpenGL context should
have a lima context object in the kernel to distinguish tasks
from different user. drm_sched gets task from each lima context
in a fair way.
Not implemented:
- Dump buffer support
- Power management
- Performance counter
This patch serial just pack a pair of .c/.h files in each patch.
For whole history of this driver's development, see:
https://github.com/yuq/linux-lima/commits/lima-4.17-rc4
Mesa driver is still in development and not ready for daily usage,
but can run some simple tests like kmscube and glamrk2, see:
https://github.com/yuq/mesa-lima
Andrei Paulau (1):
arm64/dts: add switch-delay for meson mali
Lima Project Developers (10):
drm/lima: add mali 4xx GPU hardware regs
drm/lima: add lima core driver
drm/lima: add GPU device functions
drm/lima: add PMU related functions
drm/lima: add PP related functions
drm/lima: add MMU related functions
drm/lima: add GPU virtual memory space handing
drm/lima: add GEM related functions
drm/lima: add GEM Prime related functions
drm/lima: add makefile and kconfig
Qiang Yu (12):
dt-bindings: add switch-delay property for mali-utgard
arm64/dts: add switch-delay for meson mali
Revert "drm: Nerf the preclose callback for modern drivers"
drm/lima: add lima uapi header
drm/lima: add L2 cache functions
drm/lima: add GP related functions
drm/lima: add BCAST related function
drm/lima: add DLBU related functions
drm/lima: add TTM subsystem functions
drm/lima: add buffer object functions
drm/lima: add GPU schedule using DRM_SCHED
drm/lima: add context related functions
Simon Shields (1):
ARM: dts: add gpu node to exynos4
.../bindings/gpu/arm,mali-utgard.txt | 4 +
arch/arm/boot/dts/exynos4.dtsi | 33 ++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 +
.../boot/dts/amlogic/meson-gxl-mali.dtsi | 1 +
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/drm_file.c | 8 +-
drivers/gpu/drm/lima/Kconfig | 9 +
drivers/gpu/drm/lima/Makefile | 19 +
drivers/gpu/drm/lima/lima_bcast.c | 65 +++
drivers/gpu/drm/lima/lima_bcast.h | 34 ++
drivers/gpu/drm/lima/lima_ctx.c | 143 +++++
drivers/gpu/drm/lima/lima_ctx.h | 51 ++
drivers/gpu/drm/lima/lima_device.c | 407 ++++++++++++++
drivers/gpu/drm/lima/lima_device.h | 136 +++++
drivers/gpu/drm/lima/lima_dlbu.c | 75 +++
drivers/gpu/drm/lima/lima_dlbu.h | 37 ++
drivers/gpu/drm/lima/lima_drv.c | 466 ++++++++++++++++
drivers/gpu/drm/lima/lima_drv.h | 77 +++
drivers/gpu/drm/lima/lima_gem.c | 459 ++++++++++++++++
drivers/gpu/drm/lima/lima_gem.h | 41 ++
drivers/gpu/drm/lima/lima_gem_prime.c | 66 +++
drivers/gpu/drm/lima/lima_gem_prime.h | 31 ++
drivers/gpu/drm/lima/lima_gp.c | 293 +++++++++++
drivers/gpu/drm/lima/lima_gp.h | 34 ++
drivers/gpu/drm/lima/lima_l2_cache.c | 98 ++++
drivers/gpu/drm/lima/lima_l2_cache.h | 32 ++
drivers/gpu/drm/lima/lima_mmu.c | 154 ++++++
drivers/gpu/drm/lima/lima_mmu.h | 34 ++
drivers/gpu/drm/lima/lima_object.c | 120 +++++
drivers/gpu/drm/lima/lima_object.h | 87 +++
drivers/gpu/drm/lima/lima_pmu.c | 85 +++
drivers/gpu/drm/lima/lima_pmu.h | 30 ++
drivers/gpu/drm/lima/lima_pp.c | 418 +++++++++++++++
drivers/gpu/drm/lima/lima_pp.h | 37 ++
drivers/gpu/drm/lima/lima_regs.h | 304 +++++++++++
drivers/gpu/drm/lima/lima_sched.c | 497 ++++++++++++++++++
drivers/gpu/drm/lima/lima_sched.h | 126 +++++
drivers/gpu/drm/lima/lima_ttm.c | 409 ++++++++++++++
drivers/gpu/drm/lima/lima_ttm.h | 44 ++
drivers/gpu/drm/lima/lima_vm.c | 312 +++++++++++
drivers/gpu/drm/lima/lima_vm.h | 73 +++
include/drm/drm_drv.h | 23 +-
include/uapi/drm/lima_drm.h | 195 +++++++
44 files changed, 5565 insertions(+), 6 deletions(-)
create mode 100644 drivers/gpu/drm/lima/Kconfig
create mode 100644 drivers/gpu/drm/lima/Makefile
create mode 100644 drivers/gpu/drm/lima/lima_bcast.c
create mode 100644 drivers/gpu/drm/lima/lima_bcast.h
create mode 100644 drivers/gpu/drm/lima/lima_ctx.c
create mode 100644 drivers/gpu/drm/lima/lima_ctx.h
create mode 100644 drivers/gpu/drm/lima/lima_device.c
create mode 100644 drivers/gpu/drm/lima/lima_device.h
create mode 100644 drivers/gpu/drm/lima/lima_dlbu.c
create mode 100644 drivers/gpu/drm/lima/lima_dlbu.h
create mode 100644 drivers/gpu/drm/lima/lima_drv.c
create mode 100644 drivers/gpu/drm/lima/lima_drv.h
create mode 100644 drivers/gpu/drm/lima/lima_gem.c
create mode 100644 drivers/gpu/drm/lima/lima_gem.h
create mode 100644 drivers/gpu/drm/lima/lima_gem_prime.c
create mode 100644 drivers/gpu/drm/lima/lima_gem_prime.h
create mode 100644 drivers/gpu/drm/lima/lima_gp.c
create mode 100644 drivers/gpu/drm/lima/lima_gp.h
create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.c
create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.h
create mode 100644 drivers/gpu/drm/lima/lima_mmu.c
create mode 100644 drivers/gpu/drm/lima/lima_mmu.h
create mode 100644 drivers/gpu/drm/lima/lima_object.c
create mode 100644 drivers/gpu/drm/lima/lima_object.h
create mode 100644 drivers/gpu/drm/lima/lima_pmu.c
create mode 100644 drivers/gpu/drm/lima/lima_pmu.h
create mode 100644 drivers/gpu/drm/lima/lima_pp.c
create mode 100644 drivers/gpu/drm/lima/lima_pp.h
create mode 100644 drivers/gpu/drm/lima/lima_regs.h
create mode 100644 drivers/gpu/drm/lima/lima_sched.c
create mode 100644 drivers/gpu/drm/lima/lima_sched.h
create mode 100644 drivers/gpu/drm/lima/lima_ttm.c
create mode 100644 drivers/gpu/drm/lima/lima_ttm.h
create mode 100644 drivers/gpu/drm/lima/lima_vm.c
create mode 100644 drivers/gpu/drm/lima/lima_vm.h
create mode 100644 include/uapi/drm/lima_drm.h
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [PATCH RFC 01/24] ARM: dts: add gpu node to exynos4
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Simon Shields <simon@lineageos.org>
v2 (Qiang Yu):
add vender string to exynos4 mali gpu
Based off a similar commit for the Samsung Mali driver by
Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
Signed-off-by: Simon Shields <simon@lineageos.org>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
arch/arm/boot/dts/exynos4.dtsi | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 909a9f2bf5be..7509671c505e 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -731,6 +731,39 @@
status = "disabled";
};
+ gpu: gpu@13000000 {
+ compatible = "samsung,exynos4-mali", "arm,mali-400";
+ reg = <0x13000000 0x30000>;
+ power-domains = <&pd_g3d>;
+
+ /*
+ * Propagate VPLL output clock to SCLK_G3D and
+ * ensure that the DIV_G3D divider is 1.
+ */
+ assigned-clocks = <&clock CLK_MOUT_G3D1>, <&clock CLK_MOUT_G3D>,
+ <&clock CLK_FOUT_VPLL>, <&clock CLK_SCLK_G3D>;
+ assigned-clock-parents = <&clock CLK_SCLK_VPLL>,
+ <&clock CLK_MOUT_G3D1>;
+ assigned-clock-rates = <0>, <0>, <160000000>, <160000000>;
+
+ clocks = <&clock CLK_SCLK_G3D>, <&clock CLK_G3D>;
+ clock-names = "bus", "core";
+
+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ppmmu0", "ppmmu1", "ppmmu2", "ppmmu3",
+ "gpmmu", "pp0", "pp1", "pp2", "pp3", "gp";
+ status = "disabled";
+ };
+
tmu: tmu@100c0000 {
interrupt-parent = <&combiner>;
reg = <0x100C0000 0x100>;
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH RFC 02/24] dt-bindings: add switch-delay property for mali-utgard
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
index c1f65d1dac1d..062d4bee216a 100644
--- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
+++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
@@ -58,6 +58,10 @@ Optional properties:
A power domain consumer specifier as defined in
Documentation/devicetree/bindings/power/power_domain.txt
+ - switch-delay:
+ This value is the number of Mali clock cycles it takes to
+ enable the power gates and turn on the power mesh.
+
Vendor-specific bindings
------------------------
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 00/12] media: staging/imx7: add i.MX7 media driver
From: Rui Miguel Silva @ 2018-05-18 9:27 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
Hi,
This series introduces the Media driver to work with the i.MX7 SoC. it uses the
already existing imx media core drivers but since the i.MX7, contrary to
i.MX5/6, do not have an IPU and because of that some changes in the imx media
core are made along this series to make it support that case.
This patches adds CSI and MIPI-CSI2 drivers for i.MX7, along with several
configurations changes for this to work as a capture subsystem. Some bugs are
also fixed along the line. And necessary documentation.
For a more detailed view of the capture paths, pads links in the i.MX7 please
take a look at the documentation in PATCH 14.
The system used to test and develop this was the Warp7 board with an OV2680
sensor, which output format is 10-bit bayer. So, only MIPI interface was
tested, a scenario with an parallel input would nice to have.
*Important note*, this code depends on Steve Longerbeam series [0]:
[PATCH v4 00/13] media: imx: Switch to subdev notifiers
which the merging status is not clear to me, but the changes in there make
senses to this series
Bellow goes an example of the output of the pads and links and the output of
v4l2-compliance testing.
The v4l-utils version used is:
v4l2-compliance SHA : 47d43b130dc6e9e0edc900759fb37649208371e4 from Apr 4th.
The Media Driver fail some tests but this failures are coming from code out of
scope of this series (video-mux, imx-capture), and some from the sensor OV2680
but that I think not related with the sensor driver but with the testing and
core.
The csi and mipi-csi entities pass all compliance tests.
Cheers,
Rui
[0]: https://www.mail-archive.com/linux-media@vger.kernel.org/msg131186.html
v4->v5:
Sakari Ailus:
- fix remove of the capture entries in dts bindings in the right patch
Stephen Boyd:
- Send all series to clk list
v3->v4:
Philipp Zabel:
- refactor initialization code from media device probe to be possible to used
from other modules
- Remove index of csi from all accurrencs (dts, code, documentation)
- Remove need for capture node for imx7
- fix pinctrl for ov2680
- add reviewed tag to add multiplexer controls patch
Fabio Estevam:
- remove always on from new regulator
Randy Dunlap:
- several text editing fixes in documentation
Myself:
- rebase on top of v4 of Steve series
- change CSI probe to initialize imx media device
- remove csi mux parallel endpoint from mux to avoid warning message
v2->v3:
Philipp Zabel:
- use of_match_device in imx-media-dev instead of of_device_match
- fix number of data lanes from 4 to 2
- change the clock definitions and use of mipi
- move hs-settle from endpoint
Rob Herring:
- fix phy-supply description
- add vendor properties
- fix examples indentations
Stephen Boyd: patch 3/14
- fix double sign-off
- add fixes tag
Dong Aisheng: patch 3/14
- fix double sign-off
- add Acked-by tag
Shawn Guo:
patch 4/14
- remove line breakage in parent redifiniton
- added Acked-by tag
- dropped CMA area increase and add more verbose information in case of
dma allocation failure
patch 9/14
- remove extra line between cells and reg masks
Myself:
- rework on frame end in csi
- add rxcount in csi driver
- add power supplies to ov2680 node and fix gpio polarity
v1->v2:
Dan Carpenter:
- fix return paths and codes;
- fix clk_frequency validation and return code;
- handle the csi remove (release resources that was missing)
- revert the logic arround the ipu_present flag
Philipp Zabel:
- drop patch that changed the rgb formats and address the pixel/bus format in
mipi_csis code.
MySelf:
- add patch that add ov2680 node to the warp7 dts, so the all data path is
complete.
- add linux-clk mailing list to the clock patches cc:
media-ctl -p
Media controller API version 4.17.0
Media device information
------------------------
driver imx-media
model imx-media
serial
bus info
hw revision 0x0
driver version 4.17.0
Device topology
- entity 1: csi (2 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
[fmt:SBGGR10_1X10/800x600 field:none]
<- "csi_mux":2 [ENABLED]
pad1: Source
[fmt:SBGGR10_1X10/800x600 field:none]
-> "csi capture":0 [ENABLED]
- entity 4: csi capture (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video0
pad0: Sink
<- "csi":1 [ENABLED]
- entity 10: csi_mux (3 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[fmt:unknown/0x0]
pad1: Sink
[fmt:SBGGR10_1X10/800x600 field:none]
<- "imx7-mipi-csis.0":1 [ENABLED]
pad2: Source
[fmt:SBGGR10_1X10/800x600 field:none]
-> "csi":0 [ENABLED]
- entity 14: imx7-mipi-csis.0 (2 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev2
pad0: Sink
[fmt:SBGGR10_1X10/800x600 field:none]
<- "ov2680 1-0036":0 [ENABLED]
pad1: Source
[fmt:SBGGR10_1X10/800x600 field:none]
-> "csi_mux":1 [ENABLED]
- entity 17: ov2680 1-0036 (1 pad, 1 link)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev3
pad0: Source
[fmt:SBGGR10_1X10/800x600 field:none]
-> "imx7-mipi-csis.0":0 [ENABLED]
compliance tests:
v4l2-compliance SHA : 47d43b130dc6e9e0edc900759fb37649208371e4
Compliance test for device /dev/media0:
Media Driver Info:
Driver name : imx-media
Model : imx-media
Serial :
Bus info :
Media version : 4.17.0
Hardware revision: 0x00000000 (0)
Driver version : 4.17.0
Required ioctls:
test MEDIA_IOC_DEVICE_INFO: OK
Allow for multiple opens:
test second /dev/media0 open: OK
test MEDIA_IOC_DEVICE_INFO: OK
test for unlimited opens: OK
Media Controller ioctls:
Entity: 0x00000001 (Name: 'csi', Function: 0x00005002)
Entity: 0x00000004 (Name: 'csi capture', Function: 0x00010001)
Entity: 0x0000000a (Name: 'csi_mux', Function: 0x00005001)
Entity: 0x0000000e (Name: 'imx7-mipi-csis.0', Function: 0x00005002)
Entity: 0x00000011 (Name: 'ov2680 1-0036', Function: 0x00020001)
Interface: 0x03000005 (Type: 0x00000200)
Interface: 0x03000019 (Type: 0x00000203)
Interface: 0x0300001b (Type: 0x00000203)
Interface: 0x0300001d (Type: 0x00000203)
Interface: 0x0300001f (Type: 0x00000203)
Pad: 0x01000002
Pad: 0x01000003
Pad: 0x01000007
Pad: 0x0100000b
Pad: 0x0100000c
Pad: 0x0100000d
Pad: 0x0100000f
Pad: 0x01000010
Pad: 0x01000012
Link: 0x02000006
Link: 0x02000008
Link: 0x02000013
Link: 0x02000015
Link: 0x02000017
Link: 0x0200001a
Link: 0x0200001c
Link: 0x0200001e
Link: 0x02000020
test MEDIA_IOC_G_TOPOLOGY: OK
Entities: 5 Interfaces: 5 Pads: 9 Links: 9
Entity: 0x00000001 (Name: 'csi', Type: 0x00020000
Entity: 0x00000004 (Name: 'csi capture', Type: 0x00010001
Entity: 0x0000000a (Name: 'csi_mux', Type: 0x00020000
Entity: 0x0000000e (Name: 'imx7-mipi-csis.0', Type: 0x00020000
Entity: 0x00000011 (Name: 'ov2680 1-0036', Type: 0x00020001
Entity Links: 0x00000001 (Name: 'csi')
Entity Links: 0x00000004 (Name: 'csi capture')
Entity Links: 0x0000000a (Name: 'csi_mux')
Entity Links: 0x0000000e (Name: 'imx7-mipi-csis.0')
Entity Links: 0x00000011 (Name: 'ov2680 1-0036')
test MEDIA_IOC_ENUM_ENTITIES/LINKS: OK
test MEDIA_IOC_SETUP_LINK: OK
--------------------------------------------------------------------------------
Compliance test for device /dev/video0:
Driver Info:
Driver name : imx-media-captu
Card type : imx-media-capture
Bus info : platform:csi
Driver version : 4.17.0
Capabilities : 0x84200001
Video Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04200001
Video Capture
Streaming
Extended Pix Format
Media Driver Info:
Driver name : imx-media
Model : imx-media
Serial :
Bus info :
Media version : 4.17.0
Hardware revision: 0x00000000 (0)
Driver version : 4.17.0
Interface Info:
ID : 0x03000005
Type : V4L Video
Entity Info:
ID : 0x00000004 (4)
Name : csi capture
Function : V4L2 I/O
Pad 0x01000007 : Sink
Link 0x02000008: from remote pad 0x1000003 of entity 'csi': Data, Enabled
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
test VIDIOC_QUERYCAP: OK
Allow for multiple opens:
test second /dev/video0 open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
fail: v4l2-test-input-output.cpp(420): G_INPUT not supported for a capture device
test VIDIOC_G/S/ENUMINPUT: FAIL
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
info: checking v4l2_queryctrl of control 'User Controls' (0x00980001)
info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
info: checking v4l2_queryctrl of control 'Camera Controls' (0x009a0001)
info: checking v4l2_queryctrl of control 'Auto Exposure' (0x009a0901)
info: checking v4l2_queryctrl of control 'Image Processing Controls' (0x009f0001)
info: checking v4l2_queryctrl of control 'Test Pattern' (0x009f0903)
info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
info: checking control 'User Controls' (0x00980001)
info: checking control 'Exposure' (0x00980911)
info: checking control 'Gain, Automatic' (0x00980912)
info: checking control 'Gain' (0x00980913)
info: checking control 'Horizontal Flip' (0x00980914)
info: checking control 'Vertical Flip' (0x00980915)
info: checking control 'Camera Controls' (0x009a0001)
info: checking control 'Auto Exposure' (0x009a0901)
info: checking control 'Image Processing Controls' (0x009f0001)
info: checking control 'Test Pattern' (0x009f0903)
test VIDIOC_G/S_CTRL: OK
info: checking extended control 'User Controls' (0x00980001)
info: checking extended control 'Exposure' (0x00980911)
info: checking extended control 'Gain, Automatic' (0x00980912)
info: checking extended control 'Gain' (0x00980913)
info: checking extended control 'Horizontal Flip' (0x00980914)
info: checking extended control 'Vertical Flip' (0x00980915)
info: checking extended control 'Camera Controls' (0x009a0001)
info: checking extended control 'Auto Exposure' (0x009a0901)
info: checking extended control 'Image Processing Controls' (0x009f0001)
info: checking extended control 'Test Pattern' (0x009f0903)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
info: checking control event 'User Controls' (0x00980001)
fail: v4l2-test-controls.cpp(796): subscribe event for control 'User Controls' failed
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 10 Private Controls: 0
Format ioctls:
info: found 1 formats for buftype 1
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
info: test buftype Video Capture
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK
--------------------------------------------------------------------------------
Compliance test for device /dev/v4l-subdev0:
Media Driver Info:
Driver name : imx-media
Model : imx-media
Serial :
Bus info :
Media version : 4.17.0
Hardware revision: 0x00000000 (0)
Driver version : 4.17.0
Interface Info:
ID : 0x03000019
Type : V4L Sub-Device
Entity Info:
ID : 0x00000001 (1)
Name : csi
Function : Video Interface Bridge
Pad 0x01000002 : Sink
Link 0x02000015: from remote pad 0x100000d of entity 'csi_mux': Data, Enabled
Pad 0x01000003 : Source
Link 0x02000008: to remote pad 0x1000007 of entity 'csi capture': Data, Enabled
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
Allow for multiple opens:
test second /dev/v4l-subdev0 open: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Sub-Device ioctls (Sink Pad 0):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
test Try VIDIOC_SUBDEV_G/S_FMT: OK
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
test Active VIDIOC_SUBDEV_G/S_FMT: OK
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Sub-Device ioctls (Source Pad 1):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
test Try VIDIOC_SUBDEV_G/S_FMT: OK
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
test Active VIDIOC_SUBDEV_G/S_FMT: OK
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 0 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK (Not Supported)
test VIDIOC_TRY_FMT: OK (Not Supported)
test VIDIOC_S_FMT: OK (Not Supported)
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
test VIDIOC_EXPBUF: OK (Not Supported)
--------------------------------------------------------------------------------
Compliance test for device /dev/v4l-subdev1:
Media Driver Info:
Driver name : imx-media
Model : imx-media
Serial :
Bus info :
Media version : 4.17.0
Hardware revision: 0x00000000 (0)
Driver version : 4.17.0
Interface Info:
ID : 0x0300001b
Type : V4L Sub-Device
Entity Info:
ID : 0x0000000a (10)
Name : csi_mux
Function : Video Muxer
Pad 0x0100000b : Sink
Pad 0x0100000c : Sink
Link 0x02000013: from remote pad 0x1000010 of entity 'imx7-mipi-csis.0': Data, Enabled
Pad 0x0100000d : Source
Link 0x02000015: to remote pad 0x1000002 of entity 'csi': Data, Enabled
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
Allow for multiple opens:
test second /dev/v4l-subdev1 open: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Sub-Device ioctls (Sink Pad 0):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
test Try VIDIOC_SUBDEV_G/S_FMT: FAIL
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
test Active VIDIOC_SUBDEV_G/S_FMT: FAIL
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Sub-Device ioctls (Sink Pad 1):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
test Try VIDIOC_SUBDEV_G/S_FMT: FAIL
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
fail: v4l2-test-subdevs.cpp(381): s_fmt.format.code == ~0U
test Active VIDIOC_SUBDEV_G/S_FMT: FAIL
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Sub-Device ioctls (Source Pad 2):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
fail: v4l2-test-subdevs.cpp(311): fmt.width == 0 || fmt.width == ~0U
fail: v4l2-test-subdevs.cpp(356): checkMBusFrameFmt(node, fmt.format)
test Try VIDIOC_SUBDEV_G/S_FMT: FAIL
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
fail: v4l2-test-subdevs.cpp(313): fmt.code == 0 || fmt.code == ~0U
fail: v4l2-test-subdevs.cpp(369): checkMBusFrameFmt(node, s_fmt.format)
test Active VIDIOC_SUBDEV_G/S_FMT: FAIL
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
test VIDIOC_QUERYCTRL: OK (Not Supported)
test VIDIOC_G/S_CTRL: OK (Not Supported)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 0 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK (Not Supported)
test VIDIOC_TRY_FMT: OK (Not Supported)
test VIDIOC_S_FMT: OK (Not Supported)
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
test VIDIOC_EXPBUF: OK (Not Supported)
--------------------------------------------------------------------------------
Compliance test for device /dev/v4l-subdev2:
Media Driver Info:
Driver name : imx-media
Model : imx-media
Serial :
Bus info :
Media version : 4.17.0
Hardware revision: 0x00000000 (0)
Driver version : 4.17.0
Interface Info:
ID : 0x0300001d
Type : V4L Sub-Device
Entity Info:
ID : 0x0000000e (14)
Name : imx7-mipi-csis.0
Function : Video Interface Bridge
Pad 0x0100000f : Sink
Link 0x02000017: from remote pad 0x1000012 of entity 'ov2680 1-0036': Data, Enabled
Pad 0x01000010 : Source
Link 0x02000013: to remote pad 0x100000c of entity 'csi_mux': Data, Enabled
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
Allow for multiple opens:
test second /dev/v4l-subdev2 open: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_LOG_STATUS: OK
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Sub-Device ioctls (Sink Pad 0):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
test Try VIDIOC_SUBDEV_G/S_FMT: OK
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
test Active VIDIOC_SUBDEV_G/S_FMT: OK
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Sub-Device ioctls (Source Pad 1):
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
test Try VIDIOC_SUBDEV_G/S_FMT: OK
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK (Not Supported)
test Active VIDIOC_SUBDEV_G/S_FMT: OK
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
test VIDIOC_QUERYCTRL: OK (Not Supported)
test VIDIOC_G/S_CTRL: OK (Not Supported)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 0 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK (Not Supported)
test VIDIOC_TRY_FMT: OK (Not Supported)
test VIDIOC_S_FMT: OK (Not Supported)
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
test VIDIOC_EXPBUF: OK (Not Supported)
--------------------------------------------------------------------------------
Compliance test for device /dev/v4l-subdev3:
Media Driver Info:
Driver name : imx-media
Model : imx-media
Serial :
Bus info :
Media version : 4.17.0
Hardware revision: 0x00000000 (0)
Driver version : 4.17.0
Interface Info:
ID : 0x0300001f
Type : V4L Sub-Device
Entity Info:
ID : 0x00000011 (17)
Name : ov2680 1-0036
Function : Camera Sensor
Pad 0x01000012 : Source
Link 0x02000017: to remote pad 0x100000f of entity 'imx7-mipi-csis.0': Data, Enabled
Required ioctls:
test MC information (see 'Media Driver Info' above): OK
Allow for multiple opens:
test second /dev/v4l-subdev3 open: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Sub-Device ioctls (Source Pad 0):
fail: v4l2-test-subdevs.cpp(57): node->enum_frame_interval_pad >= 0
fail: v4l2-test-subdevs.cpp(183): ret && ret != ENOTTY
fail: v4l2-test-subdevs.cpp(248): ret && ret != ENOTTY
test Try VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: FAIL
test Try VIDIOC_SUBDEV_G/S_FMT: OK
test Try VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test Active VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: OK
test Active VIDIOC_SUBDEV_G/S_FMT: OK
test Active VIDIOC_SUBDEV_G/S_SELECTION/CROP: OK (Not Supported)
test VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: OK
Control ioctls:
info: checking v4l2_queryctrl of control 'User Controls' (0x00980001)
info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
info: checking v4l2_queryctrl of control 'Camera Controls' (0x009a0001)
info: checking v4l2_queryctrl of control 'Auto Exposure' (0x009a0901)
info: checking v4l2_queryctrl of control 'Image Processing Controls' (0x009f0001)
info: checking v4l2_queryctrl of control 'Test Pattern' (0x009f0903)
info: checking v4l2_queryctrl of control 'Exposure' (0x00980911)
info: checking v4l2_queryctrl of control 'Gain, Automatic' (0x00980912)
info: checking v4l2_queryctrl of control 'Gain' (0x00980913)
info: checking v4l2_queryctrl of control 'Horizontal Flip' (0x00980914)
info: checking v4l2_queryctrl of control 'Vertical Flip' (0x00980915)
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
info: checking control 'User Controls' (0x00980001)
info: checking control 'Exposure' (0x00980911)
info: checking control 'Gain, Automatic' (0x00980912)
info: checking control 'Gain' (0x00980913)
info: checking control 'Horizontal Flip' (0x00980914)
info: checking control 'Vertical Flip' (0x00980915)
info: checking control 'Camera Controls' (0x009a0001)
info: checking control 'Auto Exposure' (0x009a0901)
info: checking control 'Image Processing Controls' (0x009f0001)
info: checking control 'Test Pattern' (0x009f0903)
test VIDIOC_G/S_CTRL: OK
info: checking extended control 'User Controls' (0x00980001)
info: checking extended control 'Exposure' (0x00980911)
info: checking extended control 'Gain, Automatic' (0x00980912)
info: checking extended control 'Gain' (0x00980913)
info: checking extended control 'Horizontal Flip' (0x00980914)
info: checking extended control 'Vertical Flip' (0x00980915)
info: checking extended control 'Camera Controls' (0x009a0001)
info: checking extended control 'Auto Exposure' (0x009a0901)
info: checking extended control 'Image Processing Controls' (0x009f0001)
info: checking extended control 'Test Pattern' (0x009f0903)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
info: checking control event 'User Controls' (0x00980001)
fail: v4l2-test-controls.cpp(796): subscribe event for control 'User Controls' failed
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: FAIL
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 10 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK (Not Supported)
test VIDIOC_TRY_FMT: OK (Not Supported)
test VIDIOC_S_FMT: OK (Not Supported)
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK (Not Supported)
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
test VIDIOC_EXPBUF: OK (Not Supported)
Total: 267, Succeeded: 257, Failed: 10, Warnings: 0
Rui Miguel Silva (12):
media: staging/imx: refactor imx media device probe
media: staging/imx7: add imx7 CSI subdev driver
clk: imx7d: fix mipi dphy div parent
clk: imx7d: reset parent for mipi csi root
media: staging/imx7: add MIPI CSI-2 receiver subdev for i.MX7
media: dt-bindings: add bindings for i.MX7 media driver
ARM: dts: imx7s: add mipi phy power domain
ARM: dts: imx7s: add multiplexer controls
ARM: dts: imx7: Add video mux, csi and mipi_csi and connections
ARM: dts: imx7s-warp: add ov2680 sensor node
media: imx7.rst: add documentation for i.MX7 media driver
media: staging/imx: add i.MX7 entries to TODO file
.../devicetree/bindings/media/imx7.txt | 125 ++
Documentation/media/v4l-drivers/imx7.rst | 157 ++
Documentation/media/v4l-drivers/index.rst | 1 +
arch/arm/boot/dts/imx7s-warp.dts | 95 ++
arch/arm/boot/dts/imx7s.dtsi | 42 +-
drivers/clk/imx/clk-imx7d.c | 4 +-
drivers/staging/media/imx/Kconfig | 9 +-
drivers/staging/media/imx/Makefile | 4 +
drivers/staging/media/imx/TODO | 9 +
.../staging/media/imx/imx-media-dev-common.c | 102 ++
drivers/staging/media/imx/imx-media-dev.c | 89 +-
.../staging/media/imx/imx-media-internal-sd.c | 3 +
drivers/staging/media/imx/imx-media-of.c | 6 +-
drivers/staging/media/imx/imx-media.h | 18 +
drivers/staging/media/imx/imx7-media-csi.c | 1352 +++++++++++++++++
drivers/staging/media/imx/imx7-mipi-csis.c | 1154 ++++++++++++++
16 files changed, 3098 insertions(+), 72 deletions(-)
create mode 100644 Documentation/devicetree/bindings/media/imx7.txt
create mode 100644 Documentation/media/v4l-drivers/imx7.rst
create mode 100644 drivers/staging/media/imx/imx-media-dev-common.c
create mode 100644 drivers/staging/media/imx/imx7-media-csi.c
create mode 100644 drivers/staging/media/imx/imx7-mipi-csis.c
--
2.17.0
^ permalink raw reply
* [PATCH RFC 03/24] arm64/dts: add switch-delay for meson mali
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
Meson mali GPU operate in high clock frequency, need
this value be high to work in a stable state.
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi
index eb327664a4d8..8bed15267c9c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi
@@ -23,6 +23,7 @@
"pp2", "ppmmu2";
clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
clock-names = "bus", "core";
+ switch-delay = <0xffff>;
/*
* Mali clocking is provided by two identical clock paths
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 01/12] media: staging/imx: refactor imx media device probe
From: Rui Miguel Silva @ 2018-05-18 9:27 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
Refactor and move media device initialization code to a new common module, so it
can be used by other devices, this will allow for example a near to introduce
imx7 CSI driver, to use this media device.
Also introduce a new flag to control the presence of IPU or not (imx6/5 have
this but imx7 does not have).
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
drivers/staging/media/imx/Makefile | 1 +
.../staging/media/imx/imx-media-dev-common.c | 102 ++++++++++++++++++
drivers/staging/media/imx/imx-media-dev.c | 89 ++++-----------
.../staging/media/imx/imx-media-internal-sd.c | 3 +
drivers/staging/media/imx/imx-media-of.c | 6 +-
drivers/staging/media/imx/imx-media.h | 18 ++++
6 files changed, 150 insertions(+), 69 deletions(-)
create mode 100644 drivers/staging/media/imx/imx-media-dev-common.c
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index 698a4210316e..a30b3033f9a3 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
imx-media-objs := imx-media-dev.o imx-media-internal-sd.o imx-media-of.o
+imx-media-objs += imx-media-dev-common.o
imx-media-common-objs := imx-media-utils.o imx-media-fim.o
imx-media-ic-objs := imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o
diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c
new file mode 100644
index 000000000000..7e9613ca5b5f
--- /dev/null
+++ b/drivers/staging/media/imx/imx-media-dev-common.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL
+/*
+ * V4L2 Media Controller Driver for Freescale common i.MX5/6/7 SOC
+ *
+ * Copyright (c) 2018 Linaro Ltd
+ * Copyright (c) 2016 Mentor Graphics Inc.
+ */
+
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include "imx-media.h"
+
+static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
+ .bound = imx_media_subdev_bound,
+ .complete = imx_media_probe_complete,
+};
+
+static const struct media_device_ops imx_media_md_ops = {
+ .link_notify = imx_media_link_notify,
+};
+
+struct imx_media_dev *imx_media_dev_init(struct device *dev, bool ipu_present)
+{
+ struct imx_media_dev *imxmd;
+ int ret;
+
+ imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
+ if (!imxmd)
+ return ERR_PTR(-ENOMEM);
+
+ dev_set_drvdata(dev, imxmd);
+
+ strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
+ imxmd->md.ops = &imx_media_md_ops;
+ imxmd->md.dev = dev;
+
+ imxmd->ipu_present = ipu_present;
+
+ mutex_init(&imxmd->mutex);
+
+ imxmd->v4l2_dev.mdev = &imxmd->md;
+ strlcpy(imxmd->v4l2_dev.name, "imx-media",
+ sizeof(imxmd->v4l2_dev.name));
+
+ media_device_init(&imxmd->md);
+
+ ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
+ if (ret < 0) {
+ v4l2_err(&imxmd->v4l2_dev,
+ "Failed to register v4l2_device: %d\n", ret);
+ goto cleanup;
+ }
+
+ dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
+
+ INIT_LIST_HEAD(&imxmd->vdev_list);
+
+ return imxmd;
+
+cleanup:
+ media_device_cleanup(&imxmd->md);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_init);
+
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd)
+{
+ int ret;
+
+ /* no subdevs? just bail */
+ if (imxmd->notifier.num_subdevs == 0) {
+ v4l2_err(&imxmd->v4l2_dev, "no subdevs\n");
+ return -ENODEV;
+ }
+
+ /* prepare the async subdev notifier and register it */
+ imxmd->notifier.ops = &imx_media_subdev_ops;
+ ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
+ &imxmd->notifier);
+ if (ret) {
+ v4l2_err(&imxmd->v4l2_dev,
+ "v4l2_async_notifier_register failed with %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_notifier_register);
+
+void imx_media_dev_cleanup(struct imx_media_dev *imxmd)
+{
+ v4l2_device_unregister(&imxmd->v4l2_dev);
+ media_device_cleanup(&imxmd->md);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_cleanup);
+
+void imx_media_dev_notifier_unregister(struct imx_media_dev *imxmd)
+{
+ v4l2_async_notifier_cleanup(&imxmd->notifier);
+}
+EXPORT_SYMBOL_GPL(imx_media_dev_notifier_unregister);
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 7e7bd1c6c81b..6160070b72fb 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -87,6 +87,9 @@ static int imx_media_get_ipu(struct imx_media_dev *imxmd,
struct ipu_soc *ipu;
int ipu_id;
+ if (!imxmd->ipu_present)
+ return 0;
+
ipu = dev_get_drvdata(csi_sd->dev->parent);
if (!ipu) {
v4l2_err(&imxmd->v4l2_dev,
@@ -107,9 +110,9 @@ static int imx_media_get_ipu(struct imx_media_dev *imxmd,
}
/* async subdev bound notifier */
-static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd)
+int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
int ret = 0;
@@ -293,7 +296,7 @@ static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
}
/* async subdev complete notifier */
-static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
{
struct imx_media_dev *imxmd = notifier2dev(notifier);
int ret;
@@ -317,11 +320,6 @@ static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
return media_device_register(&imxmd->md);
}
-static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
- .bound = imx_media_subdev_bound,
- .complete = imx_media_probe_complete,
-};
-
/*
* adds controls to a video device from an entity subdevice.
* Continues upstream from the entity's sink pads.
@@ -365,8 +363,8 @@ static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
return ret;
}
-static int imx_media_link_notify(struct media_link *link, u32 flags,
- unsigned int notification)
+int imx_media_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification)
{
struct media_entity *source = link->source->entity;
struct imx_media_pad_vdev *pad_vdev;
@@ -429,10 +427,6 @@ static int imx_media_link_notify(struct media_link *link, u32 flags,
return ret;
}
-static const struct media_device_ops imx_media_md_ops = {
- .link_notify = imx_media_link_notify,
-};
-
static int imx_media_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -440,74 +434,36 @@ static int imx_media_probe(struct platform_device *pdev)
struct imx_media_dev *imxmd;
int ret;
- imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
- if (!imxmd)
- return -ENOMEM;
-
- dev_set_drvdata(dev, imxmd);
-
- strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
- imxmd->md.ops = &imx_media_md_ops;
- imxmd->md.dev = dev;
-
- mutex_init(&imxmd->mutex);
-
- imxmd->v4l2_dev.mdev = &imxmd->md;
- strlcpy(imxmd->v4l2_dev.name, "imx-media",
- sizeof(imxmd->v4l2_dev.name));
-
- media_device_init(&imxmd->md);
-
- ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
- if (ret < 0) {
- v4l2_err(&imxmd->v4l2_dev,
- "Failed to register v4l2_device: %d\n", ret);
- goto cleanup;
- }
-
- dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
-
- INIT_LIST_HEAD(&imxmd->vdev_list);
+ imxmd = imx_media_dev_init(dev, true);
+ if (IS_ERR(imxmd))
+ return PTR_ERR(imxmd);
ret = imx_media_add_of_subdevs(imxmd, node);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"add_of_subdevs failed with %d\n", ret);
- goto notifier_cleanup;
+ goto dev_cleanup;
}
ret = imx_media_add_internal_subdevs(imxmd);
if (ret) {
v4l2_err(&imxmd->v4l2_dev,
"add_internal_subdevs failed with %d\n", ret);
- goto notifier_cleanup;
- }
-
- /* no subdevs? just bail */
- if (imxmd->notifier.num_subdevs == 0) {
- ret = -ENODEV;
- goto notifier_cleanup;
+ goto dev_cleanup;
}
- /* prepare the async subdev notifier and register it */
- imxmd->notifier.ops = &imx_media_subdev_ops;
- ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
- &imxmd->notifier);
- if (ret) {
- v4l2_err(&imxmd->v4l2_dev,
- "v4l2_async_notifier_register failed with %d\n", ret);
+ ret = imx_media_dev_notifier_register(imxmd);
+ if (ret < 0)
goto del_int;
- }
return 0;
del_int:
imx_media_remove_internal_subdevs(imxmd);
-notifier_cleanup:
- v4l2_async_notifier_cleanup(&imxmd->notifier);
- v4l2_device_unregister(&imxmd->v4l2_dev);
-cleanup:
- media_device_cleanup(&imxmd->md);
+
+dev_cleanup:
+ imx_media_dev_cleanup(imxmd);
+
return ret;
}
@@ -520,10 +476,9 @@ static int imx_media_remove(struct platform_device *pdev)
v4l2_async_notifier_unregister(&imxmd->notifier);
imx_media_remove_internal_subdevs(imxmd);
- v4l2_async_notifier_cleanup(&imxmd->notifier);
- v4l2_device_unregister(&imxmd->v4l2_dev);
+ imx_media_dev_notifier_unregister(imxmd);
media_device_unregister(&imxmd->md);
- media_device_cleanup(&imxmd->md);
+ imx_media_dev_cleanup(imxmd);
return 0;
}
diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c
index 0fdc45dbfb76..2bcdc232369a 100644
--- a/drivers/staging/media/imx/imx-media-internal-sd.c
+++ b/drivers/staging/media/imx/imx-media-internal-sd.c
@@ -238,6 +238,9 @@ int imx_media_create_internal_links(struct imx_media_dev *imxmd,
struct media_pad *pad;
int i, j, ret;
+ if (!imxmd->ipu_present)
+ return 0;
+
intsd = find_intsd_by_grp_id(sd->grp_id);
if (!intsd)
return -ENODEV;
diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c
index 1c9175433ba6..a0020cc7b3f3 100644
--- a/drivers/staging/media/imx/imx-media-of.c
+++ b/drivers/staging/media/imx/imx-media-of.c
@@ -20,7 +20,8 @@
#include <video/imx-ipu-v3.h>
#include "imx-media.h"
-static int of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np)
+int imx_media_of_add_csi(struct imx_media_dev *imxmd,
+ struct device_node *csi_np)
{
int ret;
@@ -45,6 +46,7 @@ static int of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np)
return 0;
}
+EXPORT_SYMBOL_GPL(imx_media_of_add_csi);
int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
struct device_node *np)
@@ -57,7 +59,7 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd,
if (!csi_np)
break;
- ret = of_add_csi(imxmd, csi_np);
+ ret = imx_media_of_add_csi(imxmd, csi_np);
of_node_put(csi_np);
if (ret)
return ret;
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 44532cd5b812..6fb0f9f68169 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -147,6 +147,9 @@ struct imx_media_dev {
/* for async subdev registration */
struct v4l2_async_notifier notifier;
+
+ /* indicator to if the system has IPU */
+ bool ipu_present;
};
enum codespace_sel {
@@ -224,6 +227,19 @@ int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
struct fwnode_handle *fwnode,
struct platform_device *pdev);
+int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd);
+int imx_media_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification);
+int imx_media_probe_complete(struct v4l2_async_notifier *notifier);
+
+struct imx_media_dev *imx_media_dev_init(struct device *dev, bool ipu_present);
+int imx_media_dev_notifier_register(struct imx_media_dev *imxmd);
+
+void imx_media_dev_cleanup(struct imx_media_dev *imxmd);
+void imx_media_dev_notifier_unregister(struct imx_media_dev *imxmd);
+
/* imx-media-fim.c */
struct imx_media_fim;
void imx_media_fim_eof_monitor(struct imx_media_fim *fim, ktime_t timestamp);
@@ -247,6 +263,8 @@ int imx_media_create_of_links(struct imx_media_dev *imxmd,
struct v4l2_subdev *sd);
int imx_media_create_csi_of_links(struct imx_media_dev *imxmd,
struct v4l2_subdev *csi);
+int imx_media_of_add_csi(struct imx_media_dev *imxmd,
+ struct device_node *csi_np);
/* imx-media-capture.c */
struct imx_media_video_dev *
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 04/24] arm64/dts: add switch-delay for meson mali
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Andrei Paulau <7134956@gmail.com>
Meson mali GPU operate in high clock frequency, need
this value be high to work in a stable state.
Signed-off-by: Andrei Paulau <7134956@gmail.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 562c26a0ba33..00cd2fc1aa95 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -241,6 +241,7 @@
"pp2", "ppmmu2";
clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
clock-names = "bus", "core";
+ switch-delay = <0xffff>;
/*
* Mali clocking is provided by two identical clock paths
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 02/12] media: staging/imx7: add imx7 CSI subdev driver
From: Rui Miguel Silva @ 2018-05-18 9:27 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
This add the media entity subdevice and control driver for the i.MX7
CMOS Sensor Interface.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
drivers/staging/media/imx/Kconfig | 9 +-
drivers/staging/media/imx/Makefile | 2 +
drivers/staging/media/imx/imx7-media-csi.c | 1352 ++++++++++++++++++++
3 files changed, 1362 insertions(+), 1 deletion(-)
create mode 100644 drivers/staging/media/imx/imx7-media-csi.c
diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig
index bfc17de56b17..40a11f988fc6 100644
--- a/drivers/staging/media/imx/Kconfig
+++ b/drivers/staging/media/imx/Kconfig
@@ -11,7 +11,7 @@ config VIDEO_IMX_MEDIA
driver for the i.MX5/6 SOC.
if VIDEO_IMX_MEDIA
-menu "i.MX5/6 Media Sub devices"
+menu "i.MX5/6/7 Media Sub devices"
config VIDEO_IMX_CSI
tristate "i.MX5/6 Camera Sensor Interface driver"
@@ -20,5 +20,12 @@ config VIDEO_IMX_CSI
---help---
A video4linux camera sensor interface driver for i.MX5/6.
+config VIDEO_IMX7_CSI
+ tristate "i.MX7 Camera Sensor Interface driver"
+ depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C
+ default y
+ ---help---
+ A video4linux camera sensor interface driver for i.MX7.
+
endmenu
endif
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index a30b3033f9a3..074f016d3519 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -12,3 +12,5 @@ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx-media-ic.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx-media-csi.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
+
+obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c
new file mode 100644
index 000000000000..d739eb8be402
--- /dev/null
+++ b/drivers/staging/media/imx/imx7-media-csi.c
@@ -0,0 +1,1352 @@
+// SPDX-License-Identifier: GPL
+/*
+ * V4L2 Capture CSI Subdev for Freescale i.MX7 SOC
+ *
+ * Copyright (c) 2018 Linaro Ltd
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gcd.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <media/imx.h>
+#include "imx-media.h"
+
+#define IMX7_CSI_PAD_SINK 0
+#define IMX7_CSI_PAD_SRC 1
+#define IMX7_CSI_PADS_NUM 2
+
+/* reset values */
+#define CSICR1_RESET_VAL 0x40000800
+#define CSICR2_RESET_VAL 0x0
+#define CSICR3_RESET_VAL 0x0
+
+/* csi control reg 1 */
+#define BIT_SWAP16_EN BIT(31)
+#define BIT_EXT_VSYNC BIT(30)
+#define BIT_EOF_INT_EN BIT(29)
+#define BIT_PRP_IF_EN BIT(28)
+#define BIT_CCIR_MODE BIT(27)
+#define BIT_COF_INT_EN BIT(26)
+#define BIT_SF_OR_INTEN BIT(25)
+#define BIT_RF_OR_INTEN BIT(24)
+#define BIT_SFF_DMA_DONE_INTEN BIT(22)
+#define BIT_STATFF_INTEN BIT(21)
+#define BIT_FB2_DMA_DONE_INTEN BIT(20)
+#define BIT_FB1_DMA_DONE_INTEN BIT(19)
+#define BIT_RXFF_INTEN BIT(18)
+#define BIT_SOF_POL BIT(17)
+#define BIT_SOF_INTEN BIT(16)
+#define BIT_MCLKDIV (0xF << 12)
+#define BIT_HSYNC_POL BIT(11)
+#define BIT_CCIR_EN BIT(10)
+#define BIT_MCLKEN BIT(9)
+#define BIT_FCC BIT(8)
+#define BIT_PACK_DIR BIT(7)
+#define BIT_CLR_STATFIFO BIT(6)
+#define BIT_CLR_RXFIFO BIT(5)
+#define BIT_GCLK_MODE BIT(4)
+#define BIT_INV_DATA BIT(3)
+#define BIT_INV_PCLK BIT(2)
+#define BIT_REDGE BIT(1)
+#define BIT_PIXEL_BIT BIT(0)
+
+#define SHIFT_MCLKDIV 12
+
+/* control reg 3 */
+#define BIT_FRMCNT (0xFFFF << 16)
+#define BIT_FRMCNT_RST BIT(15)
+#define BIT_DMA_REFLASH_RFF BIT(14)
+#define BIT_DMA_REFLASH_SFF BIT(13)
+#define BIT_DMA_REQ_EN_RFF BIT(12)
+#define BIT_DMA_REQ_EN_SFF BIT(11)
+#define BIT_STATFF_LEVEL (0x7 << 8)
+#define BIT_HRESP_ERR_EN BIT(7)
+#define BIT_RXFF_LEVEL (0x7 << 4)
+#define BIT_TWO_8BIT_SENSOR BIT(3)
+#define BIT_ZERO_PACK_EN BIT(2)
+#define BIT_ECC_INT_EN BIT(1)
+#define BIT_ECC_AUTO_EN BIT(0)
+
+#define SHIFT_FRMCNT 16
+#define SHIFT_RXFIFO_LEVEL 4
+
+/* csi status reg */
+#define BIT_ADDR_CH_ERR_INT BIT(28)
+#define BIT_FIELD0_INT BIT(27)
+#define BIT_FIELD1_INT BIT(26)
+#define BIT_SFF_OR_INT BIT(25)
+#define BIT_RFF_OR_INT BIT(24)
+#define BIT_DMA_TSF_DONE_SFF BIT(22)
+#define BIT_STATFF_INT BIT(21)
+#define BIT_DMA_TSF_DONE_FB2 BIT(20)
+#define BIT_DMA_TSF_DONE_FB1 BIT(19)
+#define BIT_RXFF_INT BIT(18)
+#define BIT_EOF_INT BIT(17)
+#define BIT_SOF_INT BIT(16)
+#define BIT_F2_INT BIT(15)
+#define BIT_F1_INT BIT(14)
+#define BIT_COF_INT BIT(13)
+#define BIT_HRESP_ERR_INT BIT(7)
+#define BIT_ECC_INT BIT(1)
+#define BIT_DRDY BIT(0)
+
+/* csi control reg 18 */
+#define BIT_CSI_HW_ENABLE BIT(31)
+#define BIT_MIPI_DATA_FORMAT_RAW8 (0x2a << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW10 (0x2b << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW12 (0x2c << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW14 (0x2d << 25)
+#define BIT_MIPI_DATA_FORMAT_YUV422_8B (0x1e << 25)
+#define BIT_MIPI_DATA_FORMAT_MASK (0x3F << 25)
+#define BIT_MIPI_DATA_FORMAT_OFFSET 25
+#define BIT_DATA_FROM_MIPI BIT(22)
+#define BIT_MIPI_YU_SWAP BIT(21)
+#define BIT_MIPI_DOUBLE_CMPNT BIT(20)
+#define BIT_BASEADDR_CHG_ERR_EN BIT(9)
+#define BIT_BASEADDR_SWITCH_SEL BIT(5)
+#define BIT_BASEADDR_SWITCH_EN BIT(4)
+#define BIT_PARALLEL24_EN BIT(3)
+#define BIT_DEINTERLACE_EN BIT(2)
+#define BIT_TVDECODER_IN_EN BIT(1)
+#define BIT_NTSC_EN BIT(0)
+
+#define CSI_MCLK_VF 1
+#define CSI_MCLK_ENC 2
+#define CSI_MCLK_RAW 4
+#define CSI_MCLK_I2C 8
+
+#define CSI_CSICR1 0x0
+#define CSI_CSICR2 0x4
+#define CSI_CSICR3 0x8
+#define CSI_STATFIFO 0xC
+#define CSI_CSIRXFIFO 0x10
+#define CSI_CSIRXCNT 0x14
+#define CSI_CSISR 0x18
+
+#define CSI_CSIDBG 0x1C
+#define CSI_CSIDMASA_STATFIFO 0x20
+#define CSI_CSIDMATS_STATFIFO 0x24
+#define CSI_CSIDMASA_FB1 0x28
+#define CSI_CSIDMASA_FB2 0x2C
+#define CSI_CSIFBUF_PARA 0x30
+#define CSI_CSIIMAG_PARA 0x34
+
+#define CSI_CSICR18 0x48
+#define CSI_CSICR19 0x4c
+
+struct imx7_csi {
+ struct device *dev;
+ struct imx_media_dev *md;
+ struct v4l2_subdev sd;
+ struct imx_media_video_dev *vdev;
+ struct imx_media_dev *imxmd;
+ struct media_pad pad[IMX7_CSI_PADS_NUM];
+
+ struct mutex lock;
+ spinlock_t irqlock;
+
+ struct v4l2_subdev *src_sd;
+
+ struct media_entity *sink;
+
+ struct v4l2_fwnode_endpoint upstream_ep;
+
+ struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM];
+ const struct imx_media_pixfmt *cc[IMX7_CSI_PADS_NUM];
+ struct v4l2_fract frame_interval[IMX7_CSI_PADS_NUM];
+
+ struct v4l2_ctrl_handler ctrl_hdlr;
+
+ void __iomem *regbase;
+ int irq;
+
+ struct clk *clk_disp_axi;
+ struct clk *clk_disp_dcic;
+ struct clk *clk_csi_mclk;
+
+ /* active vb2 buffers to send to video dev sink */
+ struct imx_media_buffer *active_vb2_buf[2];
+ struct imx_media_dma_buf underrun_buf;
+
+ int buf_num;
+ u32 frame_sequence;
+
+ bool last_eof;
+ bool is_init;
+ bool is_streaming;
+ bool is_csi2;
+
+ struct completion last_eof_completion;
+};
+
+#define imx7_csi_reg_read(_csi, _offset) __raw_readl(_csi->regbase + _offset)
+#define imx7_csi_reg_write(_csi, _val, _offset) \
+ __raw_writel(_val, _csi->regbase + _offset)
+
+static void imx7_csi_clk_enable(struct imx7_csi *csi)
+{
+ clk_prepare_enable(csi->clk_disp_axi);
+ clk_prepare_enable(csi->clk_disp_dcic);
+ clk_prepare_enable(csi->clk_csi_mclk);
+}
+
+static void imx7_csi_clk_disable(struct imx7_csi *csi)
+{
+ clk_disable_unprepare(csi->clk_csi_mclk);
+ clk_disable_unprepare(csi->clk_disp_dcic);
+ clk_disable_unprepare(csi->clk_disp_axi);
+}
+
+static void imx7_csi_hw_reset(struct imx7_csi *csi)
+{
+ imx7_csi_reg_write(csi,
+ imx7_csi_reg_read(csi, CSI_CSICR3) | BIT_FRMCNT_RST,
+ CSI_CSICR3);
+
+ imx7_csi_reg_write(csi, CSICR1_RESET_VAL, CSI_CSICR1);
+ imx7_csi_reg_write(csi, CSICR2_RESET_VAL, CSI_CSICR2);
+ imx7_csi_reg_write(csi, CSICR3_RESET_VAL, CSI_CSICR3);
+}
+
+static unsigned long imx7_csi_irq_clear(struct imx7_csi *csi)
+{
+ unsigned long isr;
+
+ isr = imx7_csi_reg_read(csi, CSI_CSISR);
+ imx7_csi_reg_write(csi, isr, CSI_CSISR);
+
+ return isr;
+}
+
+static void imx7_csi_init_interface(struct imx7_csi *csi)
+{
+ unsigned int val = 0;
+ unsigned int imag_para;
+
+ val = BIT_SOF_POL | BIT_REDGE | BIT_GCLK_MODE | BIT_HSYNC_POL |
+ BIT_FCC | 1 << SHIFT_MCLKDIV | BIT_MCLKEN;
+ imx7_csi_reg_write(csi, val, CSI_CSICR1);
+
+ imag_para = (800 << 16) | 600;
+ imx7_csi_reg_write(csi, imag_para, CSI_CSIIMAG_PARA);
+
+ val = BIT_DMA_REFLASH_RFF;
+ imx7_csi_reg_write(csi, val, CSI_CSICR3);
+}
+
+static void imx7_csi_hw_enable_irq(struct imx7_csi *csi)
+{
+ unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+
+ cr1 |= BIT_SOF_INTEN;
+ cr1 |= BIT_RFF_OR_INT;
+
+ /* still capture needs DMA interrupt */
+ cr1 |= BIT_FB1_DMA_DONE_INTEN;
+ cr1 |= BIT_FB2_DMA_DONE_INTEN;
+
+ cr1 |= BIT_EOF_INT_EN;
+
+ imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
+}
+
+static void imx7_csi_hw_disable_irq(struct imx7_csi *csi)
+{
+ unsigned long cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+
+ cr1 &= ~BIT_SOF_INTEN;
+ cr1 &= ~BIT_RFF_OR_INT;
+ cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
+ cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
+ cr1 &= ~BIT_EOF_INT_EN;
+
+ imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
+}
+
+static void imx7_csi_hw_enable(struct imx7_csi *csi)
+{
+ unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+ cr |= BIT_CSI_HW_ENABLE;
+
+ imx7_csi_reg_write(csi, cr, CSI_CSICR18);
+}
+
+static void imx7_csi_hw_disable(struct imx7_csi *csi)
+{
+ unsigned long cr = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+ cr &= ~BIT_CSI_HW_ENABLE;
+
+ imx7_csi_reg_write(csi, cr, CSI_CSICR18);
+}
+
+static void imx7_csi_dma_reflash(struct imx7_csi *csi)
+{
+ unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+ cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF;
+ imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
+}
+
+static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi)
+{
+ unsigned long cr1;
+
+ cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+ imx7_csi_reg_write(csi, cr1 & ~BIT_FCC, CSI_CSICR1);
+ cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+ imx7_csi_reg_write(csi, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+ cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+ imx7_csi_reg_write(csi, cr1 | BIT_FCC, CSI_CSICR1);
+}
+
+static void imx7_csi_buf_stride_set(struct imx7_csi *csi, u32 stride)
+{
+ imx7_csi_reg_write(csi, stride, CSI_CSIFBUF_PARA);
+}
+
+static void imx7_csi_deinterlace_enable(struct imx7_csi *csi, bool enable)
+{
+ unsigned long cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
+
+ if (enable)
+ cr18 |= BIT_DEINTERLACE_EN;
+ else
+ cr18 &= ~BIT_DEINTERLACE_EN;
+
+ imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
+}
+
+static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi)
+{
+ unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+ unsigned long cr2 = imx7_csi_reg_read(csi, CSI_CSICR2);
+
+ /* Burst Type of DMA Transfer from RxFIFO. INCR16 */
+ cr2 |= 0xC0000000;
+
+ cr3 |= BIT_DMA_REQ_EN_RFF;
+ cr3 |= BIT_HRESP_ERR_EN;
+ cr3 &= ~BIT_RXFF_LEVEL;
+ cr3 |= 0x2 << 4;
+
+ imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
+ imx7_csi_reg_write(csi, cr2, CSI_CSICR2);
+}
+
+static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi)
+{
+ unsigned long cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
+
+ cr3 &= ~BIT_DMA_REQ_EN_RFF;
+ cr3 &= ~BIT_HRESP_ERR_EN;
+ imx7_csi_reg_write(csi, cr3, CSI_CSICR3);
+}
+
+static void imx7_csi_set_imagpara(struct imx7_csi *csi, int width, int height)
+{
+ int imag_para;
+ int rx_count;
+
+ rx_count = (width * height) >> 2;
+ imx7_csi_reg_write(csi, rx_count, CSI_CSIRXCNT);
+
+ imag_para = (width << 16) | height;
+ imx7_csi_reg_write(csi, imag_para, CSI_CSIIMAG_PARA);
+
+ /* reflash the embedded DMA controller */
+ imx7_csi_dma_reflash(csi);
+}
+
+static void imx7_csi_sw_reset(struct imx7_csi *csi)
+{
+ imx7_csi_hw_disable(csi);
+
+ imx7_csi_rx_fifo_clear(csi);
+
+ imx7_csi_dma_reflash(csi);
+
+ usleep_range(2000, 3000);
+
+ imx7_csi_irq_clear(csi);
+
+ imx7_csi_hw_enable(csi);
+}
+
+static void imx7_csi_error_recovery(struct imx7_csi *csi)
+{
+ imx7_csi_hw_disable(csi);
+
+ imx7_csi_rx_fifo_clear(csi);
+
+ imx7_csi_dma_reflash(csi);
+
+ imx7_csi_hw_enable(csi);
+}
+
+static void imx7_csi_init(struct imx7_csi *csi)
+{
+ if (csi->is_init)
+ return;
+
+ imx7_csi_clk_enable(csi);
+ imx7_csi_hw_reset(csi);
+ imx7_csi_init_interface(csi);
+ imx7_csi_dmareq_rff_enable(csi);
+
+ csi->is_init = true;
+}
+
+static void imx7_csi_deinit(struct imx7_csi *csi)
+{
+ if (!csi->is_init)
+ return;
+
+ imx7_csi_hw_reset(csi);
+ imx7_csi_init_interface(csi);
+ imx7_csi_dmareq_rff_disable(csi);
+ imx7_csi_clk_disable(csi);
+
+ csi->is_init = false;
+}
+
+static int imx7_csi_get_upstream_endpoint(struct imx7_csi *csi,
+ struct v4l2_fwnode_endpoint *ep,
+ bool skip_mux)
+{
+ struct device_node *endpoint, *port;
+ struct media_entity *src;
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+
+ if (!csi->src_sd)
+ return -EPIPE;
+
+ src = &csi->src_sd->entity;
+
+skip_video_mux:
+ /* get source pad of entity directly upstream from src */
+ pad = imx_media_find_upstream_pad(csi->md, src, 0);
+ if (IS_ERR(pad))
+ return PTR_ERR(pad);
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ /* To get bus type we may need to skip video mux */
+ if (skip_mux && src->function == MEDIA_ENT_F_VID_MUX) {
+ src = &sd->entity;
+ goto skip_video_mux;
+ }
+
+ /*
+ * NOTE: this assumes an OF-graph port id is the same as a
+ * media pad index.
+ */
+ port = of_graph_get_port_by_id(sd->dev->of_node, pad->index);
+ if (!port)
+ return -ENODEV;
+
+ endpoint = of_get_next_child(port, NULL);
+ of_node_put(port);
+ if (!endpoint)
+ return -ENODEV;
+
+ v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), ep);
+ of_node_put(endpoint);
+
+ return 0;
+}
+
+static int imx7_csi_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev *remote_sd;
+ int ret = 0;
+
+ dev_dbg(csi->dev, "link setup %s -> %s\n", remote->entity->name,
+ local->entity->name);
+
+ mutex_lock(&csi->lock);
+
+ if (local->flags & MEDIA_PAD_FL_SINK) {
+ if (!is_media_entity_v4l2_subdev(remote->entity)) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ remote_sd = media_entity_to_v4l2_subdev(remote->entity);
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (csi->src_sd) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ csi->src_sd = remote_sd;
+ } else {
+ csi->src_sd = NULL;
+ }
+
+ goto init;
+ }
+
+ /* source pad */
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (csi->sink) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ csi->sink = remote->entity;
+ } else {
+ v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
+ v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0);
+ csi->sink = NULL;
+ }
+
+init:
+ if (csi->sink || csi->src_sd)
+ imx7_csi_init(csi);
+ else
+ imx7_csi_deinit(csi);
+
+unlock:
+ mutex_unlock(&csi->lock);
+
+ return ret;
+}
+
+static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
+ struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct v4l2_fwnode_endpoint upstream_ep;
+ int ret;
+
+ ret = v4l2_subdev_link_validate_default(sd, link, source_fmt, sink_fmt);
+ if (ret)
+ return ret;
+
+ ret = imx7_csi_get_upstream_endpoint(csi, &upstream_ep, true);
+ if (ret) {
+ v4l2_err(&csi->sd, "failed to find upstream endpoint\n");
+ return ret;
+ }
+
+ mutex_lock(&csi->lock);
+
+ csi->upstream_ep = upstream_ep;
+ csi->is_csi2 = (upstream_ep.bus_type == V4L2_MBUS_CSI2);
+
+ mutex_unlock(&csi->lock);
+
+ return 0;
+}
+
+static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys,
+ int buf_num)
+{
+ if (buf_num == 1)
+ imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB2);
+ else
+ imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1);
+}
+
+static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
+{
+ struct imx_media_video_dev *vdev = csi->vdev;
+ struct imx_media_buffer *buf;
+ struct vb2_buffer *vb2_buf;
+ dma_addr_t phys[2];
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ buf = imx_media_capture_device_next_buf(vdev);
+ if (buf) {
+ csi->active_vb2_buf[i] = buf;
+ vb2_buf = &buf->vbuf.vb2_buf;
+ phys[i] = vb2_dma_contig_plane_dma_addr(vb2_buf, 0);
+ } else {
+ csi->active_vb2_buf[i] = NULL;
+ phys[i] = csi->underrun_buf.phys;
+ }
+
+ imx7_csi_update_buf(csi, phys[i], i);
+ }
+}
+
+static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi,
+ enum vb2_buffer_state return_status)
+{
+ struct imx_media_buffer *buf;
+ int i;
+
+ /* return any remaining active frames with return_status */
+ for (i = 0; i < 2; i++) {
+ buf = csi->active_vb2_buf[i];
+ if (buf) {
+ struct vb2_buffer *vb = &buf->vbuf.vb2_buf;
+
+ vb->timestamp = ktime_get_ns();
+ vb2_buffer_done(vb, return_status);
+ }
+ }
+}
+
+static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
+{
+ struct imx_media_video_dev *vdev = csi->vdev;
+ struct imx_media_buffer *done, *next;
+ struct vb2_buffer *vb;
+ dma_addr_t phys;
+
+ done = csi->active_vb2_buf[csi->buf_num];
+ if (done) {
+ done->vbuf.field = vdev->fmt.fmt.pix.field;
+ done->vbuf.sequence = csi->frame_sequence;
+ vb = &done->vbuf.vb2_buf;
+ vb->timestamp = ktime_get_ns();
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+ csi->frame_sequence++;
+
+ /* get next queued buffer */
+ next = imx_media_capture_device_next_buf(vdev);
+ if (next) {
+ phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
+ csi->active_vb2_buf[csi->buf_num] = next;
+ } else {
+ phys = csi->underrun_buf.phys;
+ csi->active_vb2_buf[csi->buf_num] = NULL;
+ }
+
+ imx7_csi_update_buf(csi, phys, csi->buf_num);
+}
+
+static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
+{
+ struct imx7_csi *csi = data;
+ unsigned long status;
+
+ spin_lock(&csi->irqlock);
+
+ status = imx7_csi_irq_clear(csi);
+
+ if (status & BIT_RFF_OR_INT) {
+ dev_warn(csi->dev, "Rx fifo overflow\n");
+ imx7_csi_error_recovery(csi);
+ }
+
+ if (status & BIT_HRESP_ERR_INT) {
+ dev_warn(csi->dev, "Hresponse error detected\n");
+ imx7_csi_error_recovery(csi);
+ }
+
+ if (status & BIT_ADDR_CH_ERR_INT) {
+ imx7_csi_hw_disable(csi);
+
+ imx7_csi_dma_reflash(csi);
+
+ imx7_csi_hw_enable(csi);
+ }
+
+ if ((status & BIT_DMA_TSF_DONE_FB1) &&
+ (status & BIT_DMA_TSF_DONE_FB2)) {
+ /*
+ * For both FB1 and FB2 interrupter bits set case,
+ * CSI DMA is work in one of FB1 and FB2 buffer,
+ * but software can not know the state.
+ * Skip it to avoid base address updated
+ * when csi work in field0 and field1 will write to
+ * new base address.
+ */
+ } else if (status & BIT_DMA_TSF_DONE_FB1) {
+ csi->buf_num = 0;
+ } else if (status & BIT_DMA_TSF_DONE_FB2) {
+ csi->buf_num = 1;
+ }
+
+ if ((status & BIT_DMA_TSF_DONE_FB1) ||
+ (status & BIT_DMA_TSF_DONE_FB2)) {
+ imx7_csi_vb2_buf_done(csi);
+
+ if (csi->last_eof) {
+ complete(&csi->last_eof_completion);
+ csi->last_eof = false;
+ }
+ }
+
+
+ spin_unlock(&csi->irqlock);
+
+ return IRQ_HANDLED;
+}
+
+static int imx7_csi_dma_start(struct imx7_csi *csi)
+{
+ struct imx_media_video_dev *vdev = csi->vdev;
+ struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
+ int ret;
+
+ ret = imx_media_alloc_dma_buf(csi->md, &csi->underrun_buf,
+ out_pix->sizeimage);
+ if (ret < 0) {
+ v4l2_warn(&csi->sd, "consider increasing the CMA area\n");
+ return ret;
+ }
+
+ csi->frame_sequence = 0;
+ csi->last_eof = false;
+ init_completion(&csi->last_eof_completion);
+
+ imx7_csi_setup_vb2_buf(csi);
+
+ return 0;
+}
+
+static void imx7_csi_dma_stop(struct imx7_csi *csi)
+{
+ unsigned long flags;
+ int ret;
+
+ /* mark next EOF interrupt as the last before stream off */
+ spin_lock_irqsave(&csi->irqlock, flags);
+ csi->last_eof = true;
+ spin_unlock_irqrestore(&csi->irqlock, flags);
+
+ /*
+ * and then wait for interrupt handler to mark completion.
+ */
+ ret = wait_for_completion_timeout(&csi->last_eof_completion,
+ msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT));
+ if (ret == 0)
+ v4l2_warn(&csi->sd, "wait last EOF timeout\n");
+
+ imx7_csi_hw_disable_irq(csi);
+
+ imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR);
+
+ imx_media_free_dma_buf(csi->md, &csi->underrun_buf);
+}
+
+static int imx7_csi_configure(struct imx7_csi *csi)
+{
+ struct imx_media_video_dev *vdev = csi->vdev;
+ struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix;
+ __u32 in_code = csi->format_mbus[IMX7_CSI_PAD_SINK].code;
+ u32 cr1, cr18;
+
+ if (out_pix->field == V4L2_FIELD_INTERLACED) {
+ imx7_csi_deinterlace_enable(csi, true);
+ imx7_csi_buf_stride_set(csi, out_pix->width);
+ } else {
+ imx7_csi_deinterlace_enable(csi, false);
+ imx7_csi_buf_stride_set(csi, 0);
+ }
+
+ imx7_csi_set_imagpara(csi, out_pix->width, out_pix->height);
+
+ if (!csi->is_csi2)
+ return 0;
+
+ cr1 = imx7_csi_reg_read(csi, CSI_CSICR1);
+ cr1 &= ~BIT_GCLK_MODE;
+
+ cr18 = imx7_csi_reg_read(csi, CSI_CSICR18);
+ cr18 &= BIT_MIPI_DATA_FORMAT_MASK;
+ cr18 |= BIT_DATA_FROM_MIPI;
+
+ switch (out_pix->pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B;
+ break;
+ case V4L2_PIX_FMT_SBGGR8:
+ cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
+ break;
+ case V4L2_PIX_FMT_SBGGR16:
+ if (in_code == MEDIA_BUS_FMT_SBGGR10_1X10)
+ cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
+ else if (in_code == MEDIA_BUS_FMT_SBGGR12_1X12)
+ cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
+ else if (in_code == MEDIA_BUS_FMT_SBGGR14_1X14)
+ cr18 |= BIT_MIPI_DATA_FORMAT_RAW14;
+ cr1 |= BIT_PIXEL_BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ imx7_csi_reg_write(csi, cr1, CSI_CSICR1);
+ imx7_csi_reg_write(csi, cr18, CSI_CSICR18);
+
+ return 0;
+}
+
+static int imx7_csi_enable(struct imx7_csi *csi)
+{
+ imx7_csi_sw_reset(csi);
+
+ if (csi->is_csi2) {
+ imx7_csi_dmareq_rff_enable(csi);
+ imx7_csi_hw_enable_irq(csi);
+ imx7_csi_hw_enable(csi);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void imx7_csi_disable(struct imx7_csi *csi)
+{
+ imx7_csi_dmareq_rff_disable(csi);
+
+ imx7_csi_hw_disable_irq(csi);
+
+ imx7_csi_buf_stride_set(csi, 0);
+
+ imx7_csi_hw_disable(csi);
+}
+
+static int imx7_csi_streaming_start(struct imx7_csi *csi)
+{
+ int ret;
+
+ ret = imx7_csi_dma_start(csi);
+ if (ret < 0)
+ return ret;
+
+ ret = imx7_csi_configure(csi);
+ if (ret < 0)
+ goto dma_stop;
+
+ imx7_csi_enable(csi);
+
+ return 0;
+
+dma_stop:
+ imx7_csi_dma_stop(csi);
+
+ return ret;
+}
+
+static int imx7_csi_streaming_stop(struct imx7_csi *csi)
+{
+ imx7_csi_dma_stop(csi);
+
+ imx7_csi_disable(csi);
+
+ return 0;
+}
+
+static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&csi->lock);
+
+ if (!csi->src_sd || !csi->sink) {
+ ret = -EPIPE;
+ goto out_unlock;
+ }
+
+ if (csi->is_streaming == !!enable)
+ goto out_unlock;
+
+ if (enable) {
+ ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1);
+ if (ret < 0)
+ goto out_unlock;
+
+ ret = imx7_csi_streaming_start(csi);
+ if (ret < 0) {
+ v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
+ goto out_unlock;
+ }
+ } else {
+ imx7_csi_streaming_stop(csi);
+
+ v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
+ }
+
+ csi->is_streaming = !!enable;
+
+out_unlock:
+ mutex_unlock(&csi->lock);
+
+ return ret;
+}
+
+static struct v4l2_mbus_framefmt *imx7_csi_get_format(struct imx7_csi *csi,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(&csi->sd, cfg, pad);
+
+ return &csi->format_mbus[pad];
+}
+
+static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ const struct imx_media_pixfmt *in_cc;
+ struct v4l2_mbus_framefmt *in_fmt;
+ int ret = 0;
+
+ mutex_lock(&csi->lock);
+
+ in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, code->which);
+
+ in_cc = imx_media_find_mbus_format(in_fmt->code, CS_SEL_ANY, true);
+
+ switch (code->pad) {
+ case IMX7_CSI_PAD_SINK:
+ ret = imx_media_enum_mbus_format(&code->code, code->index,
+ CS_SEL_ANY, true);
+ break;
+ case IMX7_CSI_PAD_SRC:
+ if (code->index != 0) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ code->code = in_fmt->code;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+out_unlock:
+ mutex_unlock(&csi->lock);
+
+ return ret;
+}
+
+static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ int ret = 0;
+
+ if (sdformat->pad >= IMX7_CSI_PADS_NUM)
+ return -EINVAL;
+
+ mutex_lock(&csi->lock);
+
+ fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ sdformat->format = *fmt;
+
+out_unlock:
+ mutex_unlock(&csi->lock);
+
+ return ret;
+}
+
+static void imx7_csi_try_fmt(struct imx7_csi *csi,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat,
+ const struct imx_media_pixfmt **cc)
+{
+ const struct imx_media_pixfmt *in_cc;
+ struct v4l2_mbus_framefmt *in_fmt;
+ u32 code;
+
+ in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK,
+ sdformat->which);
+ if (!in_fmt)
+ return;
+
+ switch (sdformat->pad) {
+ case IMX7_CSI_PAD_SRC:
+ in_cc = imx_media_find_mbus_format(in_fmt->code, CS_SEL_ANY,
+ true);
+
+ sdformat->format.width = in_fmt->width;
+ sdformat->format.height = in_fmt->height;
+ sdformat->format.code = in_fmt->code;
+ *cc = in_cc;
+
+ sdformat->format.colorspace = in_fmt->colorspace;
+ sdformat->format.xfer_func = in_fmt->xfer_func;
+ sdformat->format.quantization = in_fmt->quantization;
+ sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
+ break;
+ case IMX7_CSI_PAD_SINK:
+ *cc = imx_media_find_mbus_format(sdformat->format.code,
+ CS_SEL_ANY, true);
+ if (!*cc) {
+ imx_media_enum_mbus_format(&code, 0, CS_SEL_ANY, false);
+ *cc = imx_media_find_mbus_format(code, CS_SEL_ANY,
+ false);
+ sdformat->format.code = (*cc)->codes[0];
+ }
+
+ imx_media_fill_default_mbus_fields(&sdformat->format, in_fmt,
+ false);
+ break;
+ default:
+ break;
+ }
+}
+
+static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct imx_media_video_dev *vdev = csi->vdev;
+ const struct imx_media_pixfmt *outcc;
+ struct v4l2_mbus_framefmt *outfmt;
+ struct v4l2_pix_format vdev_fmt;
+ const struct imx_media_pixfmt *cc;
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_subdev_format format;
+ int ret = 0;
+
+ if (sdformat->pad >= IMX7_CSI_PADS_NUM)
+ return -EINVAL;
+
+ mutex_lock(&csi->lock);
+
+ if (csi->is_streaming) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
+ imx7_csi_try_fmt(csi, cfg, sdformat, &cc);
+
+ fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ *fmt = sdformat->format;
+
+ if (sdformat->pad == IMX7_CSI_PAD_SINK) {
+ /* propagate format to source pads */
+ format.pad = IMX7_CSI_PAD_SRC;
+ format.which = sdformat->which;
+ format.format = sdformat->format;
+ imx7_csi_try_fmt(csi, cfg, &format, &outcc);
+
+ outfmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SRC,
+ sdformat->which);
+ *outfmt = format.format;
+
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ csi->cc[IMX7_CSI_PAD_SRC] = outcc;
+ }
+
+ if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY)
+ goto out_unlock;
+
+ csi->cc[sdformat->pad] = cc;
+
+ /* propagate output pad format to capture device */
+ imx_media_mbus_fmt_to_pix_fmt(&vdev_fmt,
+ &csi->format_mbus[IMX7_CSI_PAD_SRC],
+ csi->cc[IMX7_CSI_PAD_SRC]);
+ mutex_unlock(&csi->lock);
+ imx_media_capture_device_set_format(vdev, &vdev_fmt);
+
+ return 0;
+
+out_unlock:
+ mutex_unlock(&csi->lock);
+
+ return ret;
+}
+
+static int imx7_csi_registered(struct v4l2_subdev *sd)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ int ret;
+ int i;
+
+ csi->md = dev_get_drvdata(sd->v4l2_dev->dev);
+
+ for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
+ csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+ /* set a default mbus format */
+ ret = imx_media_init_mbus_fmt(&csi->format_mbus[i],
+ 800, 600, 0, V4L2_FIELD_NONE,
+ &csi->cc[i]);
+ if (ret < 0)
+ return ret;
+
+ /* init default frame interval */
+ csi->frame_interval[i].numerator = 1;
+ csi->frame_interval[i].denominator = 30;
+ }
+
+ ret = media_entity_pads_init(&sd->entity, IMX7_CSI_PADS_NUM, csi->pad);
+ if (ret < 0)
+ return ret;
+
+ ret = imx_media_capture_device_register(csi->vdev);
+ if (ret < 0)
+ return ret;
+
+ ret = imx_media_add_video_device(csi->md, csi->vdev);
+ if (ret < 0) {
+ imx_media_capture_device_unregister(csi->vdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void imx7_csi_unregistered(struct v4l2_subdev *sd)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+
+ imx_media_capture_device_unregister(csi->vdev);
+}
+
+static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg)
+{
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+ int ret;
+ int i;
+
+ for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
+ mf = v4l2_subdev_get_try_format(sd, cfg, i);
+
+ ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE,
+ &csi->cc[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations imx7_csi_entity_ops = {
+ .link_setup = imx7_csi_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
+ .s_stream = imx7_csi_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = {
+ .init_cfg = imx7_csi_init_cfg,
+ .enum_mbus_code = imx7_csi_enum_mbus_code,
+ .get_fmt = imx7_csi_get_fmt,
+ .set_fmt = imx7_csi_set_fmt,
+ .link_validate = imx7_csi_pad_link_validate,
+};
+
+static const struct v4l2_subdev_ops imx7_csi_subdev_ops = {
+ .video = &imx7_csi_video_ops,
+ .pad = &imx7_csi_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx7_csi_internal_ops = {
+ .registered = imx7_csi_registered,
+ .unregistered = imx7_csi_unregistered,
+};
+
+static int imx7_csi_parse_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct v4l2_async_subdev *asd)
+{
+ return fwnode_device_is_available(asd->match.fwnode) ? 0 : -EINVAL;
+}
+
+static int imx7_csi_parse_dt(struct imx7_csi *csi)
+{
+ struct device *dev = csi->dev;
+
+ csi->clk_disp_axi = devm_clk_get(dev, "axi");
+ if (IS_ERR(csi->clk_disp_axi)) {
+ dev_err(dev, "Could not get csi axi clock\n");
+ return -ENODEV;
+ }
+
+ csi->clk_disp_dcic = devm_clk_get(dev, "dcic");
+ if (IS_ERR(csi->clk_disp_dcic)) {
+ dev_err(dev, "Could not get disp dcic clock\n");
+ return -ENODEV;
+ }
+
+ csi->clk_csi_mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(csi->clk_csi_mclk)) {
+ dev_err(dev, "Could not get csi mclk clock\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int imx7_csi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct imx7_csi *csi;
+ struct resource *res;
+ int ret;
+
+ csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
+ if (!csi)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, &csi->sd);
+ csi->dev = dev;
+
+ ret = imx7_csi_parse_dt(csi);
+ if (ret < 0)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi->irq = platform_get_irq(pdev, 0);
+ if (!res || csi->irq < 0) {
+ dev_err(dev, "Missing platform resources data\n");
+ return -ENODEV;
+ }
+
+ csi->regbase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(csi->regbase)) {
+ dev_err(dev, "Failed platform resources map\n");
+ return -ENODEV;
+ }
+
+ spin_lock_init(&csi->irqlock);
+ mutex_init(&csi->lock);
+
+ /* install interrupt handler */
+ ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
+ (void *)csi);
+ if (ret < 0) {
+ dev_err(dev, "Request CSI IRQ failed.\n");
+ return -ENODEV;
+ }
+
+ /* add media device */
+ csi->imxmd = imx_media_dev_init(dev, false);
+ if (IS_ERR(csi->imxmd))
+ return PTR_ERR(csi->imxmd);
+
+ ret = imx_media_of_add_csi(csi->imxmd, node);
+ if (ret < 0)
+ goto media_cleanup;
+
+ ret = imx_media_dev_notifier_register(csi->imxmd);
+ if (ret < 0)
+ goto media_cleanup;
+
+ v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops);
+ v4l2_set_subdevdata(&csi->sd, csi);
+ csi->sd.internal_ops = &imx7_csi_internal_ops;
+ csi->sd.entity.ops = &imx7_csi_entity_ops;
+ csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ csi->sd.dev = &pdev->dev;
+ csi->sd.owner = THIS_MODULE;
+ csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI0;
+ snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
+
+ csi->vdev = imx_media_capture_device_init(&csi->sd, IMX7_CSI_PAD_SRC);
+ if (IS_ERR(csi->vdev))
+ return PTR_ERR(csi->vdev);
+
+ v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0);
+ csi->sd.ctrl_handler = &csi->ctrl_hdlr;
+
+ ret = v4l2_async_register_fwnode_subdev(&csi->sd,
+ sizeof(struct v4l2_async_subdev),
+ NULL, 0, imx7_csi_parse_endpoint);
+ if (ret)
+ goto free;
+
+ return 0;
+
+free:
+ v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
+ mutex_destroy(&csi->lock);
+ imx_media_capture_device_remove(csi->vdev);
+
+media_cleanup:
+ imx_media_dev_cleanup(csi->imxmd);
+
+ return ret;
+}
+
+static int imx7_csi_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+
+ v4l2_ctrl_handler_free(&csi->ctrl_hdlr);
+ mutex_destroy(&csi->lock);
+ imx_media_capture_device_remove(csi->vdev);
+ imx_media_dev_notifier_unregister(csi->imxmd);
+ imx_media_dev_cleanup(csi->imxmd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_async_unregister_subdev(sd);
+
+ return 0;
+}
+
+static const struct of_device_id imx7_csi_of_match[] = {
+ { .compatible = "fsl,imx7-csi" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, imx7_csi_of_match);
+
+static struct platform_driver imx7_csi_driver = {
+ .probe = imx7_csi_probe,
+ .remove = imx7_csi_remove,
+ .driver = {
+ .of_match_table = imx7_csi_of_match,
+ .name = "imx7-csi",
+ },
+};
+module_platform_driver(imx7_csi_driver);
+
+MODULE_DESCRIPTION("i.MX7 CSI subdev driver");
+MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx7-csi");
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 05/24] Revert "drm: Nerf the preclose callback for modern drivers"
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
This reverts commit 45c3d213a400c952ab7119f394c5293bb6877e6b.
lima driver need preclose to wait all task in the context
created within closing file to finish before free all the
buffer object. Otherwise pending tesk may fail and get
noisy MMU fault message.
Move this wait to each buffer object free function can
achieve the same result but some buffer object is shared
with other file context, but we only want to wait the
closing file context's tasks. So the implementation is
not that straight forword compared to the preclose one.
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
drivers/gpu/drm/drm_file.c | 8 ++++----
include/drm/drm_drv.h | 23 +++++++++++++++++++++--
2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index e394799979a6..0a43107396b9 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -361,8 +361,9 @@ void drm_lastclose(struct drm_device * dev)
*
* This function must be used by drivers as their &file_operations.release
* method. It frees any resources associated with the open file, and calls the
- * &drm_driver.postclose driver callback. If this is the last open file for the
- * DRM device also proceeds to call the &drm_driver.lastclose driver callback.
+ * &drm_driver.preclose and &drm_driver.lastclose driver callbacks. If this is
+ * the last open file for the DRM device also proceeds to call the
+ * &drm_driver.lastclose driver callback.
*
* RETURNS:
*
@@ -382,8 +383,7 @@ int drm_release(struct inode *inode, struct file *filp)
list_del(&file_priv->lhead);
mutex_unlock(&dev->filelist_mutex);
- if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
- dev->driver->preclose)
+ if (dev->driver->preclose)
dev->driver->preclose(dev, file_priv);
/* ========================================================
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index d23dcdd1bd95..8d6080f97ed4 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -107,6 +107,23 @@ struct drm_driver {
*/
int (*open) (struct drm_device *, struct drm_file *);
+ /**
+ * @preclose:
+ *
+ * One of the driver callbacks when a new &struct drm_file is closed.
+ * Useful for tearing down driver-private data structures allocated in
+ * @open like buffer allocators, execution contexts or similar things.
+ *
+ * Since the display/modeset side of DRM can only be owned by exactly
+ * one &struct drm_file (see &drm_file.is_master and &drm_device.master)
+ * there should never be a need to tear down any modeset related
+ * resources in this callback. Doing so would be a driver design bug.
+ *
+ * FIXME: It is not really clear why there's both @preclose and
+ * @postclose. Without a really good reason, use @postclose only.
+ */
+ void (*preclose) (struct drm_device *, struct drm_file *file_priv);
+
/**
* @postclose:
*
@@ -118,6 +135,9 @@ struct drm_driver {
* one &struct drm_file (see &drm_file.is_master and &drm_device.master)
* there should never be a need to tear down any modeset related
* resources in this callback. Doing so would be a driver design bug.
+ *
+ * FIXME: It is not really clear why there's both @preclose and
+ * @postclose. Without a really good reason, use @postclose only.
*/
void (*postclose) (struct drm_device *, struct drm_file *);
@@ -134,7 +154,7 @@ struct drm_driver {
* state changes, e.g. in conjunction with the :ref:`vga_switcheroo`
* infrastructure.
*
- * This is called after @postclose hook has been called.
+ * This is called after @preclose and @postclose have been called.
*
* NOTE:
*
@@ -601,7 +621,6 @@ struct drm_driver {
/* List of devices hanging off this driver with stealth attach. */
struct list_head legacy_dev_list;
int (*firstopen) (struct drm_device *);
- void (*preclose) (struct drm_device *, struct drm_file *file_priv);
int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
int (*dma_quiescent) (struct drm_device *);
int (*context_dtor) (struct drm_device *dev, int context);
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 03/12] clk: imx7d: fix mipi dphy div parent
From: Rui Miguel Silva @ 2018-05-18 9:27 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
Fix the mipi dphy root divider to mipi_dphy_pre_div, this would remove a orphan
clock and set the correct parent.
before:
cat clk_orphan_summary
enable prepare protect
clock count count count rate accuracy phase
----------------------------------------------------------------------------------------
mipi_dphy_post_div 1 1 0 0 0 0
mipi_dphy_root_clk 1 1 0 0 0 0
cat clk_dump | grep mipi_dphy
mipi_dphy_post_div 1 1 0 0 0 0
mipi_dphy_root_clk 1 1 0 0 0 0
after:
cat clk_dump | grep mipi_dphy
mipi_dphy_src 1 1 0 24000000 0 0
mipi_dphy_cg 1 1 0 24000000 0 0
mipi_dphy_pre_div 1 1 0 24000000 0 0
mipi_dphy_post_div 1 1 0 24000000 0 0
mipi_dphy_root_clk 1 1 0 24000000 0 0
Fixes: 8f6d8094b215 ("ARM: imx: add imx7d clk tree support")
Acked-by: Dong Aisheng <Aisheng.dong@nxp.com>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
drivers/clk/imx/clk-imx7d.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 975a20d3cc94..f7f4db2e6fa6 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -729,7 +729,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
- clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_csi_dphy_div", base + 0xa480, 0, 6);
+ clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 06/24] drm/lima: add lima uapi header
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
include/uapi/drm/lima_drm.h | 195 ++++++++++++++++++++++++++++++++++++
1 file changed, 195 insertions(+)
create mode 100644 include/uapi/drm/lima_drm.h
diff --git a/include/uapi/drm/lima_drm.h b/include/uapi/drm/lima_drm.h
new file mode 100644
index 000000000000..9df95e46fb2c
--- /dev/null
+++ b/include/uapi/drm/lima_drm.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_DRM_H__
+#define __LIMA_DRM_H__
+
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define LIMA_INFO_GPU_MALI400 0x00
+#define LIMA_INFO_GPU_MALI450 0x01
+
+struct drm_lima_info {
+ __u32 gpu_id; /* out */
+ __u32 num_pp; /* out */
+ __u64 va_start; /* out */
+ __u64 va_end; /* out */
+};
+
+struct drm_lima_gem_create {
+ __u32 size; /* in */
+ __u32 flags; /* in */
+ __u32 handle; /* out */
+ __u32 pad;
+};
+
+struct drm_lima_gem_info {
+ __u32 handle; /* in */
+ __u32 pad;
+ __u64 offset; /* out */
+};
+
+#define LIMA_VA_OP_MAP 1
+#define LIMA_VA_OP_UNMAP 2
+
+struct drm_lima_gem_va {
+ __u32 handle; /* in */
+ __u32 op; /* in */
+ __u32 flags; /* in */
+ __u32 va; /* in */
+};
+
+#define LIMA_SUBMIT_BO_READ 0x01
+#define LIMA_SUBMIT_BO_WRITE 0x02
+
+struct drm_lima_gem_submit_bo {
+ __u32 handle; /* in */
+ __u32 flags; /* in */
+};
+
+#define LIMA_SUBMIT_DEP_FENCE 0x00
+#define LIMA_SUBMIT_DEP_SYNC_FD 0x01
+
+struct drm_lima_gem_submit_dep_fence {
+ __u32 type;
+ __u32 ctx;
+ __u32 pipe;
+ __u32 seq;
+};
+
+struct drm_lima_gem_submit_dep_sync_fd {
+ __u32 type;
+ __u32 fd;
+};
+
+union drm_lima_gem_submit_dep {
+ __u32 type;
+ struct drm_lima_gem_submit_dep_fence fence;
+ struct drm_lima_gem_submit_dep_sync_fd sync_fd;
+};
+
+#define LIMA_GP_FRAME_REG_NUM 6
+
+struct drm_lima_gp_frame {
+ __u32 frame[LIMA_GP_FRAME_REG_NUM];
+};
+
+#define LIMA_PP_FRAME_REG_NUM 23
+#define LIMA_PP_WB_REG_NUM 12
+
+struct drm_lima_m400_pp_frame {
+ __u32 frame[LIMA_PP_FRAME_REG_NUM];
+ __u32 num_pp;
+ __u32 wb[3 * LIMA_PP_WB_REG_NUM];
+ __u32 plbu_array_address[4];
+ __u32 fragment_stack_address[4];
+};
+
+struct drm_lima_m450_pp_frame {
+ __u32 frame[LIMA_PP_FRAME_REG_NUM];
+ __u32 _pad;
+ __u32 wb[3 * LIMA_PP_WB_REG_NUM];
+ __u32 dlbu_regs[4];
+ __u32 fragment_stack_address[8];
+};
+
+#define LIMA_PIPE_GP 0x00
+#define LIMA_PIPE_PP 0x01
+
+#define LIMA_SUBMIT_FLAG_EXPLICIT_FENCE (1 << 0)
+#define LIMA_SUBMIT_FLAG_SYNC_FD_OUT (1 << 1)
+
+struct drm_lima_gem_submit_in {
+ __u32 ctx;
+ __u32 pipe;
+ __u32 nr_bos;
+ __u32 frame_size;
+ __u64 bos;
+ __u64 frame;
+ __u64 deps;
+ __u32 nr_deps;
+ __u32 flags;
+};
+
+struct drm_lima_gem_submit_out {
+ __u32 fence;
+ __u32 done;
+ __u32 sync_fd;
+ __u32 _pad;
+};
+
+union drm_lima_gem_submit {
+ struct drm_lima_gem_submit_in in;
+ struct drm_lima_gem_submit_out out;
+};
+
+struct drm_lima_wait_fence {
+ __u32 ctx; /* in */
+ __u32 pipe; /* in */
+ __u64 timeout_ns; /* in */
+ __u32 seq; /* in */
+ __u32 _pad;
+};
+
+#define LIMA_GEM_WAIT_READ 0x01
+#define LIMA_GEM_WAIT_WRITE 0x02
+
+struct drm_lima_gem_wait {
+ __u32 handle; /* in */
+ __u32 op; /* in */
+ __u64 timeout_ns; /* in */
+};
+
+#define LIMA_CTX_OP_CREATE 1
+#define LIMA_CTX_OP_FREE 2
+
+struct drm_lima_ctx {
+ __u32 op; /* in */
+ __u32 id; /* in/out */
+};
+
+#define DRM_LIMA_INFO 0x00
+#define DRM_LIMA_GEM_CREATE 0x01
+#define DRM_LIMA_GEM_INFO 0x02
+#define DRM_LIMA_GEM_VA 0x03
+#define DRM_LIMA_GEM_SUBMIT 0x04
+#define DRM_LIMA_WAIT_FENCE 0x05
+#define DRM_LIMA_GEM_WAIT 0x06
+#define DRM_LIMA_CTX 0x07
+
+#define DRM_IOCTL_LIMA_INFO DRM_IOR(DRM_COMMAND_BASE + DRM_LIMA_INFO, struct drm_lima_info)
+#define DRM_IOCTL_LIMA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_CREATE, struct drm_lima_gem_create)
+#define DRM_IOCTL_LIMA_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_INFO, struct drm_lima_gem_info)
+#define DRM_IOCTL_LIMA_GEM_VA DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_GEM_VA, struct drm_lima_gem_va)
+#define DRM_IOCTL_LIMA_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_SUBMIT, union drm_lima_gem_submit)
+#define DRM_IOCTL_LIMA_WAIT_FENCE DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_WAIT_FENCE, struct drm_lima_wait_fence)
+#define DRM_IOCTL_LIMA_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_GEM_WAIT, struct drm_lima_gem_wait)
+#define DRM_IOCTL_LIMA_CTX DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_CTX, struct drm_lima_ctx)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __LIMA_DRM_H__ */
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 04/12] clk: imx7d: reset parent for mipi csi root
From: Rui Miguel Silva @ 2018-05-18 9:27 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
To guarantee that we do not get Overflow in image FIFO the outer bandwidth has
to be faster than inputer bandwidth. For that it must be possible to set a
faster frequency clock. So set new parent to sys_pfd3 clock for the mipi csi
block.
Acked-by: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
drivers/clk/imx/clk-imx7d.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index f7f4db2e6fa6..27877d05faa2 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -891,6 +891,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
+ clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
+
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 07/24] drm/lima: add mali 4xx GPU hardware regs
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Lima Project Developers <dri-devel@lists.freedesktop.org>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/gpu/drm/lima/lima_regs.h | 304 +++++++++++++++++++++++++++++++
1 file changed, 304 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_regs.h
diff --git a/drivers/gpu/drm/lima/lima_regs.h b/drivers/gpu/drm/lima/lima_regs.h
new file mode 100644
index 000000000000..ea4a37d69b98
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_regs.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2010-2017 ARM Limited. All rights reserved.
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * This program is free software and is provided to you under
+ * the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, and any use by
+ * you of this program is subject to the terms of such GNU
+ * licence.
+ *
+ * A copy of the licence is included with the program, and
+ * can also be obtained from Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __LIMA_REGS_H__
+#define __LIMA_REGS_H__
+
+/* PMU regs */
+#define LIMA_PMU_POWER_UP 0x00
+#define LIMA_PMU_POWER_DOWN 0x04
+#define LIMA_PMU_POWER_GP0_MASK (1 << 0)
+#define LIMA_PMU_POWER_L2_MASK (1 << 1)
+#define LIMA_PMU_POWER_PP_MASK(i) (1 << (2 + i))
+
+/*
+ * On Mali450 each block automatically starts up its corresponding L2
+ * and the PPs are not fully independent controllable.
+ * Instead PP0, PP1-3 and PP4-7 can be turned on or off.
+ */
+#define LIMA450_PMU_POWER_PP0_MASK BIT(1)
+#define LIMA450_PMU_POWER_PP13_MASK BIT(2)
+#define LIMA450_PMU_POWER_PP47_MASK BIT(3)
+
+#define LIMA_PMU_STATUS 0x08
+#define LIMA_PMU_INT_MASK 0x0C
+#define LIMA_PMU_INT_RAWSTAT 0x10
+#define LIMA_PMU_INT_CLEAR 0x18
+#define LIMA_PMU_INT_CMD_MASK (1 << 0)
+#define LIMA_PMU_SW_DELAY 0x1C
+
+/* L2 cache regs */
+#define LIMA_L2_CACHE_SIZE 0x0004
+#define LIMA_L2_CACHE_STATUS 0x0008
+#define LIMA_L2_CACHE_STATUS_COMMAND_BUSY (1 << 0)
+#define LIMA_L2_CACHE_STATUS_DATA_BUSY (1 << 1)
+#define LIMA_L2_CACHE_COMMAND 0x0010
+#define LIMA_L2_CACHE_COMMAND_CLEAR_ALL (1 << 0)
+#define LIMA_L2_CACHE_CLEAR_PAGE 0x0014
+#define LIMA_L2_CACHE_MAX_READS 0x0018
+#define LIMA_L2_CACHE_ENABLE 0x001C
+#define LIMA_L2_CACHE_ENABLE_ACCESS (1 << 0)
+#define LIMA_L2_CACHE_ENABLE_READ_ALLOCATE (1 << 1)
+#define LIMA_L2_CACHE_PERFCNT_SRC0 0x0020
+#define LIMA_L2_CACHE_PERFCNT_VAL0 0x0024
+#define LIMA_L2_CACHE_PERFCNT_SRC1 0x0028
+#define LIMA_L2_CACHE_ERFCNT_VAL1 0x002C
+
+/* GP regs */
+#define LIMA_GP_VSCL_START_ADDR 0x00
+#define LIMA_GP_VSCL_END_ADDR 0x04
+#define LIMA_GP_PLBUCL_START_ADDR 0x08
+#define LIMA_GP_PLBUCL_END_ADDR 0x0c
+#define LIMA_GP_PLBU_ALLOC_START_ADDR 0x10
+#define LIMA_GP_PLBU_ALLOC_END_ADDR 0x14
+#define LIMA_GP_CMD 0x20
+#define LIMA_GP_CMD_START_VS (1 << 0)
+#define LIMA_GP_CMD_START_PLBU (1 << 1)
+#define LIMA_GP_CMD_UPDATE_PLBU_ALLOC (1 << 4)
+#define LIMA_GP_CMD_RESET (1 << 5)
+#define LIMA_GP_CMD_FORCE_HANG (1 << 6)
+#define LIMA_GP_CMD_STOP_BUS (1 << 9)
+#define LIMA_GP_CMD_SOFT_RESET (1 << 10)
+#define LIMA_GP_INT_RAWSTAT 0x24
+#define LIMA_GP_INT_CLEAR 0x28
+#define LIMA_GP_INT_MASK 0x2C
+#define LIMA_GP_INT_STAT 0x30
+#define LIMA_GP_IRQ_VS_END_CMD_LST (1 << 0)
+#define LIMA_GP_IRQ_PLBU_END_CMD_LST (1 << 1)
+#define LIMA_GP_IRQ_PLBU_OUT_OF_MEM (1 << 2)
+#define LIMA_GP_IRQ_VS_SEM_IRQ (1 << 3)
+#define LIMA_GP_IRQ_PLBU_SEM_IRQ (1 << 4)
+#define LIMA_GP_IRQ_HANG (1 << 5)
+#define LIMA_GP_IRQ_FORCE_HANG (1 << 6)
+#define LIMA_GP_IRQ_PERF_CNT_0_LIMIT (1 << 7)
+#define LIMA_GP_IRQ_PERF_CNT_1_LIMIT (1 << 8)
+#define LIMA_GP_IRQ_WRITE_BOUND_ERR (1 << 9)
+#define LIMA_GP_IRQ_SYNC_ERROR (1 << 10)
+#define LIMA_GP_IRQ_AXI_BUS_ERROR (1 << 11)
+#define LIMA_GP_IRQ_AXI_BUS_STOPPED (1 << 12)
+#define LIMA_GP_IRQ_VS_INVALID_CMD (1 << 13)
+#define LIMA_GP_IRQ_PLB_INVALID_CMD (1 << 14)
+#define LIMA_GP_IRQ_RESET_COMPLETED (1 << 19)
+#define LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW (1 << 20)
+#define LIMA_GP_IRQ_SEMAPHORE_OVERFLOW (1 << 21)
+#define LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS (1 << 22)
+#define LIMA_GP_WRITE_BOUND_LOW 0x34
+#define LIMA_GP_PERF_CNT_0_ENABLE 0x3C
+#define LIMA_GP_PERF_CNT_1_ENABLE 0x40
+#define LIMA_GP_PERF_CNT_0_SRC 0x44
+#define LIMA_GP_PERF_CNT_1_SRC 0x48
+#define LIMA_GP_PERF_CNT_0_VALUE 0x4C
+#define LIMA_GP_PERF_CNT_1_VALUE 0x50
+#define LIMA_GP_PERF_CNT_0_LIMIT 0x54
+#define LIMA_GP_STATUS 0x68
+#define LIMA_GP_STATUS_VS_ACTIVE (1 << 1)
+#define LIMA_GP_STATUS_BUS_STOPPED (1 << 2)
+#define LIMA_GP_STATUS_PLBU_ACTIVE (1 << 3)
+#define LIMA_GP_STATUS_BUS_ERROR (1 << 6)
+#define LIMA_GP_STATUS_WRITE_BOUND_ERR (1 << 8)
+#define LIMA_GP_VERSION 0x6C
+#define LIMA_GP_VSCL_START_ADDR_READ 0x80
+#define LIMA_GP_PLBCL_START_ADDR_READ 0x84
+#define LIMA_GP_CONTR_AXI_BUS_ERROR_STAT 0x94
+
+#define LIMA_GP_IRQ_MASK_ALL \
+ ( \
+ LIMA_GP_IRQ_VS_END_CMD_LST | \
+ LIMA_GP_IRQ_PLBU_END_CMD_LST | \
+ LIMA_GP_IRQ_PLBU_OUT_OF_MEM | \
+ LIMA_GP_IRQ_VS_SEM_IRQ | \
+ LIMA_GP_IRQ_PLBU_SEM_IRQ | \
+ LIMA_GP_IRQ_HANG | \
+ LIMA_GP_IRQ_FORCE_HANG | \
+ LIMA_GP_IRQ_PERF_CNT_0_LIMIT | \
+ LIMA_GP_IRQ_PERF_CNT_1_LIMIT | \
+ LIMA_GP_IRQ_WRITE_BOUND_ERR | \
+ LIMA_GP_IRQ_SYNC_ERROR | \
+ LIMA_GP_IRQ_AXI_BUS_ERROR | \
+ LIMA_GP_IRQ_AXI_BUS_STOPPED | \
+ LIMA_GP_IRQ_VS_INVALID_CMD | \
+ LIMA_GP_IRQ_PLB_INVALID_CMD | \
+ LIMA_GP_IRQ_RESET_COMPLETED | \
+ LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW | \
+ LIMA_GP_IRQ_SEMAPHORE_OVERFLOW | \
+ LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS)
+
+#define LIMA_GP_IRQ_MASK_ERROR \
+ ( \
+ LIMA_GP_IRQ_PLBU_OUT_OF_MEM | \
+ LIMA_GP_IRQ_FORCE_HANG | \
+ LIMA_GP_IRQ_WRITE_BOUND_ERR | \
+ LIMA_GP_IRQ_SYNC_ERROR | \
+ LIMA_GP_IRQ_AXI_BUS_ERROR | \
+ LIMA_GP_IRQ_VS_INVALID_CMD | \
+ LIMA_GP_IRQ_PLB_INVALID_CMD | \
+ LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW | \
+ LIMA_GP_IRQ_SEMAPHORE_OVERFLOW | \
+ LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS)
+
+#define LIMA_GP_IRQ_MASK_USED \
+ ( \
+ LIMA_GP_IRQ_VS_END_CMD_LST | \
+ LIMA_GP_IRQ_PLBU_END_CMD_LST | \
+ LIMA_GP_IRQ_MASK_ERROR)
+
+/* PP regs */
+#define LIMA_PP_FRAME 0x0000
+#define LIMA_PP_RSW 0x0004
+#define LIMA_PP_STACK 0x0030
+#define LIMA_PP_STACK_SIZE 0x0034
+#define LIMA_PP_ORIGIN_OFFSET_X 0x0040
+#define LIMA_PP_WB(i) (0x0100 * (i + 1))
+#define LIMA_PP_WB_SOURCE_SELECT 0x0000
+#define LIMA_PP_WB_SOURCE_ADDR 0x0004
+
+#define LIMA_PP_VERSION 0x1000
+#define LIMA_PP_CURRENT_REND_LIST_ADDR 0x1004
+#define LIMA_PP_STATUS 0x1008
+#define LIMA_PP_STATUS_RENDERING_ACTIVE (1 << 0)
+#define LIMA_PP_STATUS_BUS_STOPPED (1 << 4)
+#define LIMA_PP_CTRL 0x100c
+#define LIMA_PP_CTRL_STOP_BUS (1 << 0)
+#define LIMA_PP_CTRL_FLUSH_CACHES (1 << 3)
+#define LIMA_PP_CTRL_FORCE_RESET (1 << 5)
+#define LIMA_PP_CTRL_START_RENDERING (1 << 6)
+#define LIMA_PP_CTRL_SOFT_RESET (1 << 7)
+#define LIMA_PP_INT_RAWSTAT 0x1020
+#define LIMA_PP_INT_CLEAR 0x1024
+#define LIMA_PP_INT_MASK 0x1028
+#define LIMA_PP_INT_STATUS 0x102c
+#define LIMA_PP_IRQ_END_OF_FRAME (1 << 0)
+#define LIMA_PP_IRQ_END_OF_TILE (1 << 1)
+#define LIMA_PP_IRQ_HANG (1 << 2)
+#define LIMA_PP_IRQ_FORCE_HANG (1 << 3)
+#define LIMA_PP_IRQ_BUS_ERROR (1 << 4)
+#define LIMA_PP_IRQ_BUS_STOP (1 << 5)
+#define LIMA_PP_IRQ_CNT_0_LIMIT (1 << 6)
+#define LIMA_PP_IRQ_CNT_1_LIMIT (1 << 7)
+#define LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR (1 << 8)
+#define LIMA_PP_IRQ_INVALID_PLIST_COMMAND (1 << 9)
+#define LIMA_PP_IRQ_CALL_STACK_UNDERFLOW (1 << 10)
+#define LIMA_PP_IRQ_CALL_STACK_OVERFLOW (1 << 11)
+#define LIMA_PP_IRQ_RESET_COMPLETED (1 << 12)
+#define LIMA_PP_WRITE_BOUNDARY_LOW 0x1044
+#define LIMA_PP_BUS_ERROR_STATUS 0x1050
+#define LIMA_PP_PERF_CNT_0_ENABLE 0x1080
+#define LIMA_PP_PERF_CNT_0_SRC 0x1084
+#define LIMA_PP_PERF_CNT_0_LIMIT 0x1088
+#define LIMA_PP_PERF_CNT_0_VALUE 0x108c
+#define LIMA_PP_PERF_CNT_1_ENABLE 0x10a0
+#define LIMA_PP_PERF_CNT_1_SRC 0x10a4
+#define LIMA_PP_PERF_CNT_1_LIMIT 0x10a8
+#define LIMA_PP_PERF_CNT_1_VALUE 0x10ac
+#define LIMA_PP_PERFMON_CONTR 0x10b0
+#define LIMA_PP_PERFMON_BASE 0x10b4
+
+#define LIMA_PP_IRQ_MASK_ALL \
+ ( \
+ LIMA_PP_IRQ_END_OF_FRAME | \
+ LIMA_PP_IRQ_END_OF_TILE | \
+ LIMA_PP_IRQ_HANG | \
+ LIMA_PP_IRQ_FORCE_HANG | \
+ LIMA_PP_IRQ_BUS_ERROR | \
+ LIMA_PP_IRQ_BUS_STOP | \
+ LIMA_PP_IRQ_CNT_0_LIMIT | \
+ LIMA_PP_IRQ_CNT_1_LIMIT | \
+ LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR | \
+ LIMA_PP_IRQ_INVALID_PLIST_COMMAND | \
+ LIMA_PP_IRQ_CALL_STACK_UNDERFLOW | \
+ LIMA_PP_IRQ_CALL_STACK_OVERFLOW | \
+ LIMA_PP_IRQ_RESET_COMPLETED)
+
+#define LIMA_PP_IRQ_MASK_ERROR \
+ ( \
+ LIMA_PP_IRQ_FORCE_HANG | \
+ LIMA_PP_IRQ_BUS_ERROR | \
+ LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR | \
+ LIMA_PP_IRQ_INVALID_PLIST_COMMAND | \
+ LIMA_PP_IRQ_CALL_STACK_UNDERFLOW | \
+ LIMA_PP_IRQ_CALL_STACK_OVERFLOW)
+
+#define LIMA_PP_IRQ_MASK_USED \
+ ( \
+ LIMA_PP_IRQ_END_OF_FRAME | \
+ LIMA_PP_IRQ_MASK_ERROR)
+
+/* MMU regs */
+#define LIMA_MMU_DTE_ADDR 0x0000
+#define LIMA_MMU_STATUS 0x0004
+#define LIMA_MMU_STATUS_PAGING_ENABLED (1 << 0)
+#define LIMA_MMU_STATUS_PAGE_FAULT_ACTIVE (1 << 1)
+#define LIMA_MMU_STATUS_STALL_ACTIVE (1 << 2)
+#define LIMA_MMU_STATUS_IDLE (1 << 3)
+#define LIMA_MMU_STATUS_REPLAY_BUFFER_EMPTY (1 << 4)
+#define LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE (1 << 5)
+#define LIMA_MMU_STATUS_BUS_ID(x) ((x >> 6) & 0x1F)
+#define LIMA_MMU_COMMAND 0x0008
+#define LIMA_MMU_COMMAND_ENABLE_PAGING 0x00
+#define LIMA_MMU_COMMAND_DISABLE_PAGING 0x01
+#define LIMA_MMU_COMMAND_ENABLE_STALL 0x02
+#define LIMA_MMU_COMMAND_DISABLE_STALL 0x03
+#define LIMA_MMU_COMMAND_ZAP_CACHE 0x04
+#define LIMA_MMU_COMMAND_PAGE_FAULT_DONE 0x05
+#define LIMA_MMU_COMMAND_HARD_RESET 0x06
+#define LIMA_MMU_PAGE_FAULT_ADDR 0x000C
+#define LIMA_MMU_ZAP_ONE_LINE 0x0010
+#define LIMA_MMU_INT_RAWSTAT 0x0014
+#define LIMA_MMU_INT_CLEAR 0x0018
+#define LIMA_MMU_INT_MASK 0x001C
+#define LIMA_MMU_INT_PAGE_FAULT 0x01
+#define LIMA_MMU_INT_READ_BUS_ERROR 0x02
+#define LIMA_MMU_INT_STATUS 0x0020
+
+#define LIMA_VM_FLAG_PRESENT (1 << 0)
+#define LIMA_VM_FLAG_READ_PERMISSION (1 << 1)
+#define LIMA_VM_FLAG_WRITE_PERMISSION (1 << 2)
+#define LIMA_VM_FLAG_OVERRIDE_CACHE (1 << 3)
+#define LIMA_VM_FLAG_WRITE_CACHEABLE (1 << 4)
+#define LIMA_VM_FLAG_WRITE_ALLOCATE (1 << 5)
+#define LIMA_VM_FLAG_WRITE_BUFFERABLE (1 << 6)
+#define LIMA_VM_FLAG_READ_CACHEABLE (1 << 7)
+#define LIMA_VM_FLAG_READ_ALLOCATE (1 << 8)
+#define LIMA_VM_FLAG_MASK 0x1FF
+
+#define LIMA_VM_FLAGS_CACHE ( \
+ LIMA_VM_FLAG_PRESENT | \
+ LIMA_VM_FLAG_READ_PERMISSION | \
+ LIMA_VM_FLAG_WRITE_PERMISSION | \
+ LIMA_VM_FLAG_OVERRIDE_CACHE | \
+ LIMA_VM_FLAG_WRITE_CACHEABLE | \
+ LIMA_VM_FLAG_WRITE_BUFFERABLE | \
+ LIMA_VM_FLAG_READ_CACHEABLE | \
+ LIMA_VM_FLAG_READ_ALLOCATE )
+
+#define LIMA_VM_FLAGS_UNCACHE ( \
+ LIMA_VM_FLAG_PRESENT | \
+ LIMA_VM_FLAG_READ_PERMISSION | \
+ LIMA_VM_FLAG_WRITE_PERMISSION )
+
+/* DLBU regs */
+#define LIMA_DLBU_MASTER_TLLIST_PHYS_ADDR 0x0000
+#define LIMA_DLBU_MASTER_TLLIST_VADDR 0x0004
+#define LIMA_DLBU_TLLIST_VBASEADDR 0x0008
+#define LIMA_DLBU_FB_DIM 0x000C
+#define LIMA_DLBU_TLLIST_CONF 0x0010
+#define LIMA_DLBU_START_TILE_POS 0x0014
+#define LIMA_DLBU_PP_ENABLE_MASK 0x0018
+
+/* BCAST regs */
+#define LIMA_BCAST_BROADCAST_MASK 0x0
+#define LIMA_BCAST_INTERRUPT_MASK 0x4
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 05/12] media: staging/imx7: add MIPI CSI-2 receiver subdev for i.MX7
From: Rui Miguel Silva @ 2018-05-18 9:27 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
Adds MIPI CSI-2 subdev for i.MX7 to connect with sensors with a MIPI CSI-2
interface.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
drivers/staging/media/imx/Makefile | 1 +
drivers/staging/media/imx/imx7-mipi-csis.c | 1154 ++++++++++++++++++++
2 files changed, 1155 insertions(+)
create mode 100644 drivers/staging/media/imx/imx7-mipi-csis.c
diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile
index 074f016d3519..d2d909a36239 100644
--- a/drivers/staging/media/imx/Makefile
+++ b/drivers/staging/media/imx/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_VIDEO_IMX_CSI) += imx-media-csi.o
obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o
obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
+obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-mipi-csis.o
diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c
new file mode 100644
index 000000000000..e56facea36ba
--- /dev/null
+++ b/drivers/staging/media/imx/imx7-mipi-csis.c
@@ -0,0 +1,1154 @@
+// SPDX-License-Identifier: GPL
+/*
+ * Freescale i.MX7 SoC series MIPI-CSI V3.3 receiver driver
+ *
+ * Copyright (C) 2018 Linaro Ltd
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#include "imx-media.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define CSIS_DRIVER_NAME "imx7-mipi-csis"
+#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME
+
+#define CSIS_PAD_SINK 0
+#define CSIS_PAD_SOURCE 1
+#define CSIS_PADS_NUM 2
+
+#define MIPI_CSIS_DEF_PIX_WIDTH 640
+#define MIPI_CSIS_DEF_PIX_HEIGHT 480
+
+/* Register map definition */
+
+/* CSIS common control */
+#define MIPI_CSIS_CMN_CTRL 0x04
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16)
+#define MIPI_CSIS_CMN_CTRL_INTER_MODE BIT(10)
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2)
+#define MIPI_CSIS_CMN_CTRL_RESET BIT(1)
+#define MIPI_CSIS_CMN_CTRL_ENABLE BIT(0)
+
+#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8
+#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8)
+
+/* CSIS clock control */
+#define MIPI_CSIS_CLK_CTRL 0x08
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) (x << 28)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) (x << 24)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) (x << 20)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) (x << 16)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4)
+#define MIPI_CSIS_CLK_CTRL_WCLK_SRC BIT(0)
+
+/* CSIS Interrupt mask */
+#define MIPI_CSIS_INTMSK 0x10
+#define MIPI_CSIS_INTMSK_EVEN_BEFORE BIT(31)
+#define MIPI_CSIS_INTMSK_EVEN_AFTER BIT(30)
+#define MIPI_CSIS_INTMSK_ODD_BEFORE BIT(29)
+#define MIPI_CSIS_INTMSK_ODD_AFTER BIT(28)
+#define MIPI_CSIS_INTMSK_FRAME_START BIT(24)
+#define MIPI_CSIS_INTMSK_FRAME_END BIT(20)
+#define MIPI_CSIS_INTMSK_ERR_SOT_HS BIT(16)
+#define MIPI_CSIS_INTMSK_ERR_LOST_FS BIT(12)
+#define MIPI_CSIS_INTMSK_ERR_LOST_FE BIT(8)
+#define MIPI_CSIS_INTMSK_ERR_OVER BIT(4)
+#define MIPI_CSIS_INTMSK_ERR_WRONG_CFG BIT(3)
+#define MIPI_CSIS_INTMSK_ERR_ECC BIT(2)
+#define MIPI_CSIS_INTMSK_ERR_CRC BIT(1)
+#define MIPI_CSIS_INTMSK_ERR_UNKNOWN BIT(0)
+
+/* CSIS Interrupt source */
+#define MIPI_CSIS_INTSRC 0x14
+#define MIPI_CSIS_INTSRC_EVEN_BEFORE BIT(31)
+#define MIPI_CSIS_INTSRC_EVEN_AFTER BIT(30)
+#define MIPI_CSIS_INTSRC_EVEN BIT(30)
+#define MIPI_CSIS_INTSRC_ODD_BEFORE BIT(29)
+#define MIPI_CSIS_INTSRC_ODD_AFTER BIT(28)
+#define MIPI_CSIS_INTSRC_ODD (0x3 << 28)
+#define MIPI_CSIS_INTSRC_NON_IMAGE_DATA (0xf << 28)
+#define MIPI_CSIS_INTSRC_FRAME_START BIT(24)
+#define MIPI_CSIS_INTSRC_FRAME_END BIT(20)
+#define MIPI_CSIS_INTSRC_ERR_SOT_HS BIT(16)
+#define MIPI_CSIS_INTSRC_ERR_LOST_FS BIT(12)
+#define MIPI_CSIS_INTSRC_ERR_LOST_FE BIT(8)
+#define MIPI_CSIS_INTSRC_ERR_OVER BIT(4)
+#define MIPI_CSIS_INTSRC_ERR_WRONG_CFG BIT(3)
+#define MIPI_CSIS_INTSRC_ERR_ECC BIT(2)
+#define MIPI_CSIS_INTSRC_ERR_CRC BIT(1)
+#define MIPI_CSIS_INTSRC_ERR_UNKNOWN BIT(0)
+#define MIPI_CSIS_INTSRC_ERRORS 0xfffff
+
+/* D-PHY status control */
+#define MIPI_CSIS_DPHYSTATUS 0x20
+#define MIPI_CSIS_DPHYSTATUS_ULPS_DAT BIT(8)
+#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_DAT BIT(4)
+#define MIPI_CSIS_DPHYSTATUS_ULPS_CLK BIT(1)
+#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_CLK BIT(0)
+
+/* D-PHY common control */
+#define MIPI_CSIS_DPHYCTRL 0x24
+#define MIPI_CSIS_DPHYCTRL_HSS_MASK (0xff << 24)
+#define MIPI_CSIS_DPHYCTRL_HSS_OFFSET 24
+#define MIPI_CSIS_DPHYCTRL_SCLKS_MASK (0x3 << 22)
+#define MIPI_CSIS_DPHYCTRL_SCLKS_OFFSET 22
+#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_CLK BIT(6)
+#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_DAT BIT(5)
+#define MIPI_CSIS_DPHYCTRL_ENABLE_DAT BIT(1)
+#define MIPI_CSIS_DPHYCTRL_ENABLE_CLK BIT(0)
+#define MIPI_CSIS_DPHYCTRL_ENABLE (0x1f << 0)
+
+/* D-PHY Master and Slave Control register Low */
+#define MIPI_CSIS_DPHYBCTRL_L 0x30
+/* D-PHY Master and Slave Control register High */
+#define MIPI_CSIS_DPHYBCTRL_H 0x34
+/* D-PHY Slave Control register Low */
+#define MIPI_CSIS_DPHYSCTRL_L 0x38
+/* D-PHY Slave Control register High */
+#define MIPI_CSIS_DPHYSCTRL_H 0x3c
+
+/* ISP Configuration register */
+#define MIPI_CSIS_ISPCONFIG_CH0 0x40
+#define MIPI_CSIS_ISPCONFIG_CH1 0x50
+#define MIPI_CSIS_ISPCONFIG_CH2 0x60
+#define MIPI_CSIS_ISPCONFIG_CH3 0x70
+
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24)
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) (x << 24)
+#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT BIT(12)
+#define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11)
+#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW8 (0x2a << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW10 (0x2b << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW12 (0x2c << 2)
+
+/* User defined formats, x = 1...4 */
+#define MIPI_CSIS_ISPCFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2)
+
+/* ISP Image Resolution register */
+#define MIPI_CSIS_ISPRESOL_CH0 0x44
+#define MIPI_CSIS_ISPRESOL_CH1 0x54
+#define MIPI_CSIS_ISPRESOL_CH2 0x64
+#define MIPI_CSIS_ISPRESOL_CH3 0x74
+#define CSIS_MAX_PIX_WIDTH 0xffff
+#define CSIS_MAX_PIX_HEIGHT 0xffff
+
+/* ISP SYNC register */
+#define MIPI_CSIS_ISPSYNC_CH0 0x48
+#define MIPI_CSIS_ISPSYNC_CH1 0x58
+#define MIPI_CSIS_ISPSYNC_CH2 0x68
+#define MIPI_CSIS_ISPSYNC_CH3 0x78
+
+#define MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET 18
+#define MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET 12
+#define MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET 0
+
+/* Non-image packet data buffers */
+#define MIPI_CSIS_PKTDATA_ODD 0x2000
+#define MIPI_CSIS_PKTDATA_EVEN 0x3000
+#define MIPI_CSIS_PKTDATA_SIZE SZ_4K
+
+#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
+
+enum {
+ ST_POWERED = 1,
+ ST_STREAMING = 2,
+ ST_SUSPENDED = 4,
+};
+
+struct mipi_csis_event {
+ u32 mask;
+ const char * const name;
+ unsigned int counter;
+};
+
+static const struct mipi_csis_event mipi_csis_events[] = {
+ /* Errors */
+ { MIPI_CSIS_INTSRC_ERR_SOT_HS, "SOT Error" },
+ { MIPI_CSIS_INTSRC_ERR_LOST_FS, "Lost Frame Start Error" },
+ { MIPI_CSIS_INTSRC_ERR_LOST_FE, "Lost Frame End Error" },
+ { MIPI_CSIS_INTSRC_ERR_OVER, "FIFO Overflow Error" },
+ { MIPI_CSIS_INTSRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
+ { MIPI_CSIS_INTSRC_ERR_ECC, "ECC Error" },
+ { MIPI_CSIS_INTSRC_ERR_CRC, "CRC Error" },
+ { MIPI_CSIS_INTSRC_ERR_UNKNOWN, "Unknown Error" },
+ /* Non-image data receive events */
+ { MIPI_CSIS_INTSRC_EVEN_BEFORE, "Non-image data before even frame" },
+ { MIPI_CSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" },
+ { MIPI_CSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" },
+ { MIPI_CSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" },
+ /* Frame start/end */
+ { MIPI_CSIS_INTSRC_FRAME_START, "Frame Start" },
+ { MIPI_CSIS_INTSRC_FRAME_END, "Frame End" },
+};
+
+#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
+
+struct csis_hw_reset {
+ struct regmap *src;
+ u8 req_src;
+ u8 rst_bit;
+};
+
+struct csi_state {
+ struct mutex lock;
+ spinlock_t slock;
+ struct device *dev;
+ struct media_pad pads[CSIS_PADS_NUM];
+ struct v4l2_subdev mipi_sd;
+ struct v4l2_subdev *src_sd;
+
+ u8 index;
+ struct platform_device *pdev;
+ struct phy *phy;
+ void __iomem *regs;
+ struct clk *pclk_clk;
+ struct clk *wrap_clk;
+ struct clk *phy_clk;
+ int irq;
+ u32 flags;
+
+ u32 clk_frequency;
+ u32 hs_settle;
+ u32 num_lanes;
+ u32 max_num_lanes;
+
+ struct reset_control *mrst;
+
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_mbus_framefmt format_mbus;
+
+ struct v4l2_fwnode_bus_mipi_csi2 bus;
+
+ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
+
+ struct v4l2_async_notifier subdev_notifier;
+
+ struct csis_hw_reset hw_reset;
+ struct regulator *mipi_phy_regulator;
+ bool sink_linked;
+};
+
+struct csis_pix_format {
+ unsigned int pix_width_alignment;
+ u32 code;
+ u32 fmt_reg;
+ u8 data_alignment;
+};
+
+static const struct csis_pix_format mipi_csis_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+ .data_alignment = 16,
+ }, {
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+ .data_alignment = 16,
+ }, {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_alignment = 8,
+ }, {
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+ .data_alignment = 16,
+ }
+};
+
+#define mipi_csis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define mipi_csis_read(__csis, __r) readl(__csis->regs + __r)
+
+static void dump_regs(struct csi_state *state, const char *label)
+{
+ u32 cfg;
+ u32 i;
+ struct {
+ u32 offset;
+ const char * const name;
+ } registers[] = {
+ { 0x04, "CTRL" },
+ { 0x24, "DPHYCTRL" },
+ { 0x08, "CLKCTRL" },
+ { 0x20, "DPHYSTS" },
+ { 0x10, "INTMSK" },
+ { 0x40, "CONFIG_CH0" },
+ { 0xC0, "DBG_CONFIG" },
+ { 0x38, "DPHYSLAVE_L" },
+ { 0x3C, "DPHYSLAVE_H" },
+ };
+
+ v4l2_info(&state->mipi_sd, "--- %s ---\n", label);
+
+ for (i = 0; i < ARRAY_SIZE(registers); i++) {
+ cfg = mipi_csis_read(state, registers[i].offset);
+ v4l2_info(&state->mipi_sd, "%12s: 0x%08x 0x%p\n",
+ registers[i].name, cfg, state->regs);
+ }
+}
+
+static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct csi_state, mipi_sd);
+}
+
+static const struct csis_pix_format *find_csis_format(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
+ if (code == mipi_csis_formats[i].code)
+ return &mipi_csis_formats[i];
+ return NULL;
+}
+
+static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
+{
+ u32 val = mipi_csis_read(state, MIPI_CSIS_INTMSK);
+
+ if (on)
+ val |= 0xffffffff;
+ else
+ val &= ~0xffffffff;
+ mipi_csis_write(state, MIPI_CSIS_INTMSK, val);
+}
+
+static void mipi_csis_sw_reset(struct csi_state *state)
+{
+ u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL,
+ val | MIPI_CSIS_CMN_CTRL_RESET);
+ usleep_range(10, 20);
+}
+
+static int mipi_csis_phy_init(struct csi_state *state)
+{
+ state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy");
+
+ return regulator_set_voltage(state->mipi_phy_regulator, 1000000,
+ 1000000);
+}
+
+static void mipi_csis_phy_reset(struct csi_state *state)
+{
+ reset_control_assert(state->mrst);
+
+ msleep(20);
+
+ reset_control_deassert(state->mrst);
+}
+
+static void mipi_csis_system_enable(struct csi_state *state, int on)
+{
+ u32 val, mask;
+
+ val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ if (on)
+ val |= MIPI_CSIS_CMN_CTRL_ENABLE;
+ else
+ val &= ~MIPI_CSIS_CMN_CTRL_ENABLE;
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+
+ val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
+ val &= ~MIPI_CSIS_DPHYCTRL_ENABLE;
+ if (on) {
+ mask = (1 << (state->num_lanes + 1)) - 1;
+ val |= (mask & MIPI_CSIS_DPHYCTRL_ENABLE);
+ }
+ mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __mipi_csis_set_format(struct csi_state *state)
+{
+ struct v4l2_mbus_framefmt *mf = &state->format_mbus;
+ u32 val;
+
+ /* Color format */
+ val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0);
+ val = (val & ~MIPI_CSIS_ISPCFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+ mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val);
+
+ /* Pixel resolution */
+ val = mf->width | (mf->height << 16);
+ mipi_csis_write(state, MIPI_CSIS_ISPRESOL_CH0, val);
+}
+
+static void mipi_csis_set_hsync_settle(struct csi_state *state, int hs_settle)
+{
+ u32 val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
+
+ val = ((val & ~MIPI_CSIS_DPHYCTRL_HSS_MASK) | (hs_settle << 24));
+
+ mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
+}
+
+static void mipi_csis_set_params(struct csi_state *state)
+{
+ u32 val;
+
+ val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
+ val |= (state->num_lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+
+ __mipi_csis_set_format(state);
+
+ mipi_csis_set_hsync_settle(state, state->hs_settle);
+
+ val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0);
+ if (state->csis_fmt->data_alignment == 32)
+ val |= MIPI_CSIS_ISPCFG_ALIGN_32BIT;
+ else
+ val &= ~MIPI_CSIS_ISPCFG_ALIGN_32BIT;
+ mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val);
+
+ val = (0 << MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET) |
+ (0 << MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET) |
+ (0 << MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET);
+ mipi_csis_write(state, MIPI_CSIS_ISPSYNC_CH0, val);
+
+ val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL);
+ val &= ~MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+ if (state->wrap_clk)
+ val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+ else
+ val &= ~MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+
+ val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15);
+ val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK;
+ mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val);
+
+ mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_L, 0x1f4);
+ mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_H, 0);
+
+ /* Update the shadow register. */
+ val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL,
+ val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW |
+ MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL);
+}
+
+static void mipi_csis_clk_enable(struct csi_state *state)
+{
+ clk_prepare_enable(state->pclk_clk);
+ clk_prepare_enable(state->wrap_clk);
+ clk_prepare_enable(state->phy_clk);
+}
+
+static void mipi_csis_clk_disable(struct csi_state *state)
+{
+ clk_disable_unprepare(state->pclk_clk);
+ clk_disable_unprepare(state->wrap_clk);
+ clk_disable_unprepare(state->phy_clk);
+}
+
+static int mipi_csis_clk_get(struct csi_state *state)
+{
+ struct device *dev = &state->pdev->dev;
+ int ret;
+
+ state->pclk_clk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(state->pclk_clk)) {
+ dev_err(dev, "Could not get pclk clock\n");
+ return -ENODEV;
+ }
+
+ state->wrap_clk = devm_clk_get(dev, "wrap");
+ if (IS_ERR(state->wrap_clk)) {
+ dev_info(dev, "Could not get wrap clock, using pclk\n");
+ state->wrap_clk = NULL;
+ }
+
+ state->phy_clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(state->phy_clk)) {
+ dev_err(dev, "Could not get mipi phy clock\n");
+ return -ENODEV;
+ }
+
+ /* Set clock rate */
+ ret = clk_set_rate(state->wrap_clk, state->clk_frequency);
+ if (ret < 0)
+ dev_err(dev, "set rate=%d failed: %d\n", state->clk_frequency,
+ ret);
+
+ return ret;
+}
+
+static void mipi_csis_start_stream(struct csi_state *state)
+{
+ mipi_csis_sw_reset(state);
+ mipi_csis_set_params(state);
+ mipi_csis_system_enable(state, true);
+ mipi_csis_enable_interrupts(state, true);
+}
+
+static void mipi_csis_stop_stream(struct csi_state *state)
+{
+ mipi_csis_enable_interrupts(state, false);
+ mipi_csis_system_enable(state, false);
+}
+
+static void mipi_csis_clear_counters(struct csi_state *state)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&state->slock, flags);
+ for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++)
+ state->events[i].counter = 0;
+ spin_unlock_irqrestore(&state->slock, flags);
+}
+
+static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
+{
+ int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->slock, flags);
+
+ for (i--; i >= 0; i--) {
+ if (state->events[i].counter > 0 || debug)
+ v4l2_info(&state->mipi_sd, "%s events: %d\n",
+ state->events[i].name,
+ state->events[i].counter);
+ }
+ spin_unlock_irqrestore(&state->slock, flags);
+}
+
+/*
+ * V4L2 subdev operations
+ */
+static int mipi_csis_s_power(struct v4l2_subdev *mipi_sd, int on)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct device *dev = &state->pdev->dev;
+
+ v4l2_subdev_call(state->src_sd, core, s_power, on);
+
+ if (on)
+ return pm_runtime_get_sync(dev);
+
+ return pm_runtime_put_sync(dev);
+}
+
+static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ int ret = 0;
+
+ if (enable) {
+ mipi_csis_clear_counters(state);
+ ret = pm_runtime_get_sync(&state->pdev->dev);
+ if (ret && ret != 1)
+ return ret;
+ }
+
+ mutex_lock(&state->lock);
+ if (enable) {
+ if (state->flags & ST_SUSPENDED) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ mipi_csis_start_stream(state);
+ ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1);
+ if (ret < 0)
+ goto unlock;
+
+ mipi_csis_log_counters(state, true);
+
+ state->flags |= ST_STREAMING;
+ } else {
+ v4l2_subdev_call(state->src_sd, video, s_stream, 0);
+ mipi_csis_stop_stream(state);
+ state->flags &= ~ST_STREAMING;
+ if (debug > 0)
+ mipi_csis_log_counters(state, true);
+ }
+
+unlock:
+ mutex_unlock(&state->lock);
+ if (!enable)
+ pm_runtime_put(&state->pdev->dev);
+
+ return ret;
+}
+
+static int mipi_csis_link_setup(struct media_entity *entity,
+ const struct media_pad *local_pad,
+ const struct media_pad *remote_pad, u32 flags)
+{
+ struct v4l2_subdev *mipi_sd = media_entity_to_v4l2_subdev(entity);
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct v4l2_subdev *remote_sd;
+ int ret = 0;
+
+ dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
+ local_pad->entity->name);
+
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ mutex_lock(&state->lock);
+
+ if (local_pad->flags & MEDIA_PAD_FL_SOURCE) {
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (state->sink_linked) {
+ ret = -EBUSY;
+ goto out;
+ }
+ state->sink_linked = true;
+ } else {
+ state->sink_linked = false;
+ }
+ } else {
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (state->src_sd) {
+ ret = -EBUSY;
+ goto out;
+ }
+ state->src_sd = remote_sd;
+ } else {
+ state->src_sd = NULL;
+ }
+ }
+
+out:
+ mutex_unlock(&state->lock);
+ return ret;
+}
+
+static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg)
+{
+ struct v4l2_mbus_framefmt *mf;
+ int ret;
+ int i;
+
+ for (i = 0; i < CSIS_PADS_NUM; i++) {
+ mf = v4l2_subdev_get_try_format(mipi_sd, cfg, i);
+
+ ret = imx_media_init_mbus_fmt(mf, MIPI_CSIS_DEF_PIX_HEIGHT,
+ MIPI_CSIS_DEF_PIX_WIDTH, 0,
+ V4L2_FIELD_NONE, NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct csis_pix_format const *mipi_csis_try_format(
+ struct v4l2_subdev *mipi_sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csis_pix_format const *csis_fmt;
+
+ csis_fmt = find_csis_format(mf->code);
+ if (!csis_fmt)
+ csis_fmt = &mipi_csis_formats[0];
+
+ v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+ csis_fmt->pix_width_alignment,
+ &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+ 0);
+
+ state->format_mbus.code = csis_fmt->code;
+ state->format_mbus.width = mf->width;
+ state->format_mbus.height = mf->height;
+
+ return csis_fmt;
+}
+
+static struct v4l2_mbus_framefmt *mipi_csis_get_format(struct csi_state *state,
+ struct v4l2_subdev_pad_config *cfg,
+ enum v4l2_subdev_format_whence which,
+ unsigned int pad)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(&state->mipi_sd, cfg, pad);
+
+ return &state->format_mbus;
+}
+
+static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct csis_pix_format const *csis_fmt;
+ struct v4l2_mbus_framefmt *fmt;
+
+ if (sdformat->pad >= CSIS_PADS_NUM)
+ return -EINVAL;
+
+ fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
+
+ mutex_lock(&state->lock);
+ if (fmt && sdformat->pad == CSIS_PAD_SOURCE) {
+ sdformat->format = *fmt;
+ goto unlock;
+ }
+
+ csis_fmt = mipi_csis_try_format(mipi_sd, &sdformat->format);
+
+ sdformat->format = *fmt;
+
+ if (csis_fmt && sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ state->csis_fmt = csis_fmt;
+ else
+ cfg->try_fmt = sdformat->format;
+
+unlock:
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ struct v4l2_mbus_framefmt *fmt;
+
+ mutex_lock(&state->lock);
+
+ fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad);
+
+ sdformat->format = *fmt;
+
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+
+ mutex_lock(&state->lock);
+ mipi_csis_log_counters(state, true);
+ if (debug && (state->flags & ST_POWERED))
+ dump_regs(state, __func__);
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
+{
+ struct csi_state *state = dev_id;
+ unsigned long flags;
+ u32 status;
+ int i;
+
+ status = mipi_csis_read(state, MIPI_CSIS_INTSRC);
+
+ spin_lock_irqsave(&state->slock, flags);
+
+ /* Update the event/error counters */
+ if ((status & MIPI_CSIS_INTSRC_ERRORS) || debug) {
+ for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
+ if (!(status & state->events[i].mask))
+ continue;
+ state->events[i].counter++;
+ }
+ }
+ spin_unlock_irqrestore(&state->slock, flags);
+
+ mipi_csis_write(state, MIPI_CSIS_INTSRC, status);
+
+ return IRQ_HANDLED;
+}
+
+static int mipi_csi_registered(struct v4l2_subdev *mipi_sd)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ int i, ret;
+
+ for (i = 0; i < CSIS_PADS_NUM; i++) {
+ state->pads[i].flags = (i == CSIS_PAD_SINK) ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+ }
+
+ /* set a default mbus format */
+ ret = imx_media_init_mbus_fmt(&state->format_mbus,
+ MIPI_CSIS_DEF_PIX_HEIGHT,
+ MIPI_CSIS_DEF_PIX_WIDTH, 0,
+ V4L2_FIELD_NONE, NULL);
+ if (ret)
+ return ret;
+
+ return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
+ state->pads);
+}
+
+static struct v4l2_subdev_core_ops mipi_csis_core_ops = {
+ .s_power = mipi_csis_s_power,
+ .log_status = mipi_csis_log_status,
+};
+
+static const struct media_entity_operations mipi_csis_entity_ops = {
+ .link_setup = mipi_csis_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static struct v4l2_subdev_video_ops mipi_csis_video_ops = {
+ .s_stream = mipi_csis_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
+ .init_cfg = mipi_csis_init_cfg,
+ .get_fmt = mipi_csis_get_fmt,
+ .set_fmt = mipi_csis_set_fmt,
+};
+
+static struct v4l2_subdev_ops mipi_csis_subdev_ops = {
+ .core = &mipi_csis_core_ops,
+ .video = &mipi_csis_video_ops,
+ .pad = &mipi_csis_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mipi_csis_internal_ops = {
+ .registered = mipi_csi_registered,
+};
+
+static int mipi_csis_parse_dt(struct platform_device *pdev,
+ struct csi_state *state)
+{
+ struct device_node *node = pdev->dev.of_node;
+
+ if (of_property_read_u32(node, "clock-frequency",
+ &state->clk_frequency))
+ state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+
+ if (of_property_read_u32(node, "bus-width", &state->max_num_lanes))
+ return -EINVAL;
+
+ node = of_graph_get_next_endpoint(node, NULL);
+ if (!node) {
+ dev_err(&pdev->dev, "No port node at %s\n",
+ pdev->dev.of_node->full_name);
+ return -EINVAL;
+ }
+
+ /* Get MIPI PHY resets */
+ state->mrst = devm_reset_control_get_exclusive(&pdev->dev, "mrst");
+ if (IS_ERR(state->mrst))
+ return PTR_ERR(state->mrst);
+
+ /* Get MIPI CSI-2 bus configration from the endpoint node. */
+ of_property_read_u32(node, "fsl,csis-hs-settle", &state->hs_settle);
+
+ of_property_read_u32(node, "data-lanes", &state->num_lanes);
+ of_node_put(node);
+
+ if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) {
+ dev_err(&pdev->dev, "Unsupported number of data lanes: %d (max. %d)\n",
+ state->num_lanes, state->max_num_lanes);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mipi_csis_pm_resume(struct device *dev, bool runtime);
+
+static int mipi_csis_parse_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *ep,
+ struct v4l2_async_subdev *asd)
+{
+ struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+
+ if (!fwnode_device_is_available(asd->match.fwnode)) {
+ v4l2_err(mipi_sd, "remote is not available\n");
+ return -EINVAL;
+ }
+
+ if (ep->bus_type != V4L2_MBUS_CSI2)
+ v4l2_err(mipi_sd, "invalid bus type, must be MIPI CSI2\n");
+
+ state->bus = ep->bus.mipi_csi2;
+
+ dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes);
+ dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags);
+
+ return 0;
+}
+
+static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
+ struct platform_device *pdev,
+ const struct v4l2_subdev_ops *ops)
+{
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ unsigned int sink_port = 0;
+ int ret;
+
+ v4l2_subdev_init(mipi_sd, ops);
+ mipi_sd->owner = THIS_MODULE;
+ snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
+ CSIS_SUBDEV_NAME, state->index);
+
+ mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ mipi_sd->ctrl_handler = NULL;
+
+ mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ mipi_sd->entity.ops = &mipi_csis_entity_ops;
+
+ mipi_sd->dev = &pdev->dev;
+
+ state->csis_fmt = &mipi_csis_formats[0];
+ state->format_mbus.code = mipi_csis_formats[0].code;
+ state->format_mbus.width = MIPI_CSIS_DEF_PIX_WIDTH;
+ state->format_mbus.height = MIPI_CSIS_DEF_PIX_HEIGHT;
+ state->format_mbus.field = V4L2_FIELD_NONE;
+
+ v4l2_set_subdevdata(mipi_sd, &pdev->dev);
+
+ ret = v4l2_async_register_fwnode_subdev(mipi_sd,
+ sizeof(struct v4l2_async_subdev), &sink_port, 1,
+ mipi_csis_parse_endpoint);
+ if (ret < 0)
+ dev_err(&pdev->dev, "async fwnode register failed: %d\n", ret);
+
+ return ret;
+}
+
+static int mipi_csis_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *mem_res;
+ struct csi_state *state;
+ int ret = -ENOMEM;
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ mutex_init(&state->lock);
+ spin_lock_init(&state->slock);
+
+ state->pdev = pdev;
+ state->dev = dev;
+
+ ret = mipi_csis_parse_dt(pdev, state);
+ if (ret < 0) {
+ dev_err(dev, "Failed to parse device tree: %d\n", ret);
+ return ret;
+ }
+
+ mipi_csis_phy_init(state);
+ mipi_csis_phy_reset(state);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ state->regs = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(state->regs))
+ return PTR_ERR(state->regs);
+
+ state->irq = platform_get_irq(pdev, 0);
+ if (state->irq < 0) {
+ dev_err(dev, "Failed to get irq\n");
+ return state->irq;
+ }
+
+ ret = mipi_csis_clk_get(state);
+ if (ret < 0)
+ return ret;
+
+ mipi_csis_clk_enable(state);
+
+ ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler,
+ 0, dev_name(dev), state);
+ if (ret) {
+ dev_err(dev, "Interrupt request failed\n");
+ goto disable_clock;
+ }
+
+ platform_set_drvdata(pdev, &state->mipi_sd);
+
+ ret = mipi_csis_subdev_init(&state->mipi_sd, pdev,
+ &mipi_csis_subdev_ops);
+ if (ret < 0)
+ goto disable_clock;
+
+ state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&state->mipi_sd.entity, CSIS_PADS_NUM,
+ state->pads);
+ if (ret < 0)
+ goto unregister_subdev;
+
+ memcpy(state->events, mipi_csis_events, sizeof(state->events));
+
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = mipi_csis_pm_resume(dev, true);
+ if (ret < 0)
+ goto unregister_all;
+ }
+
+ dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n",
+ state->num_lanes, state->hs_settle,
+ state->wrap_clk ? 1 : 0, state->clk_frequency);
+ return 0;
+
+unregister_all:
+ media_entity_cleanup(&state->mipi_sd.entity);
+unregister_subdev:
+ v4l2_async_unregister_subdev(&state->mipi_sd);
+disable_clock:
+ mipi_csis_clk_disable(state);
+
+ return ret;
+}
+
+static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev);
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ int ret = 0;
+
+ mutex_lock(&state->lock);
+ if (state->flags & ST_POWERED) {
+ mipi_csis_stop_stream(state);
+ ret = regulator_disable(state->mipi_phy_regulator);
+ if (ret)
+ goto unlock;
+ mipi_csis_clk_disable(state);
+ state->flags &= ~ST_POWERED;
+ if (!runtime)
+ state->flags |= ST_SUSPENDED;
+ }
+
+ unlock:
+ mutex_unlock(&state->lock);
+
+ return ret ? -EAGAIN : 0;
+}
+
+static int mipi_csis_pm_resume(struct device *dev, bool runtime)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev);
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+ int ret = 0;
+
+ mutex_lock(&state->lock);
+ if (!runtime && !(state->flags & ST_SUSPENDED))
+ goto unlock;
+
+ if (!(state->flags & ST_POWERED)) {
+ ret = regulator_enable(state->mipi_phy_regulator);
+ if (ret)
+ goto unlock;
+
+ state->flags |= ST_POWERED;
+ mipi_csis_clk_enable(state);
+ }
+ if (state->flags & ST_STREAMING)
+ mipi_csis_start_stream(state);
+
+ state->flags &= ~ST_SUSPENDED;
+
+ unlock:
+ mutex_unlock(&state->lock);
+
+ return ret ? -EAGAIN : 0;
+}
+
+static int mipi_csis_suspend(struct device *dev)
+{
+ return mipi_csis_pm_suspend(dev, false);
+}
+
+static int mipi_csis_resume(struct device *dev)
+{
+ return mipi_csis_pm_resume(dev, false);
+}
+
+static int mipi_csis_runtime_suspend(struct device *dev)
+{
+ return mipi_csis_pm_suspend(dev, true);
+}
+
+static int mipi_csis_runtime_resume(struct device *dev)
+{
+ return mipi_csis_pm_resume(dev, true);
+}
+
+static int mipi_csis_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev);
+ struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
+
+ v4l2_async_unregister_subdev(&state->mipi_sd);
+ v4l2_async_notifier_unregister(&state->subdev_notifier);
+
+ pm_runtime_disable(&pdev->dev);
+ mipi_csis_pm_suspend(&pdev->dev, true);
+ mipi_csis_clk_disable(state);
+ media_entity_cleanup(&state->mipi_sd.entity);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_csis_pm_ops = {
+ SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
+};
+
+static const struct of_device_id mipi_csis_of_match[] = {
+ { .compatible = "fsl,imx7-mipi-csi2", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
+
+static struct platform_driver mipi_csis_driver = {
+ .probe = mipi_csis_probe,
+ .remove = mipi_csis_remove,
+ .driver = {
+ .of_match_table = mipi_csis_of_match,
+ .name = CSIS_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &mipi_csis_pm_ops,
+ },
+};
+
+module_platform_driver(mipi_csis_driver);
+
+MODULE_DESCRIPTION("i.MX7 MIPI CSI-2 Receiver driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx7-mipi-csi2");
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 08/24] drm/lima: add lima core driver
From: Qiang Yu @ 2018-05-18 9:27 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Lima Project Developers <dri-devel@lists.freedesktop.org>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Erico Nunes <nunes.erico@gmail.com>
---
drivers/gpu/drm/lima/lima_drv.c | 466 ++++++++++++++++++++++++++++++++
drivers/gpu/drm/lima/lima_drv.h | 77 ++++++
2 files changed, 543 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_drv.c
create mode 100644 drivers/gpu/drm/lima/lima_drv.h
diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c
new file mode 100644
index 000000000000..4df24a6cfff3
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_drv.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/log2.h>
+#include <drm/drm_prime.h>
+#include <drm/lima_drm.h>
+
+#include "lima_drv.h"
+#include "lima_gem.h"
+#include "lima_gem_prime.h"
+#include "lima_vm.h"
+
+int lima_sched_timeout_ms = 0;
+int lima_sched_max_tasks = 32;
+int lima_max_mem = -1;
+
+MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms (0 = no timeout (default))");
+module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444);
+
+MODULE_PARM_DESC(sched_max_tasks, "max queued task num in a context (default 32)");
+module_param_named(sched_max_tasks, lima_sched_max_tasks, int, 0444);
+
+MODULE_PARM_DESC(max_mem, "Max memory size in MB can be used (<0 = auto)");
+module_param_named(max_mem, lima_max_mem, int, 0444);
+
+static int lima_ioctl_info(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_info *info = data;
+ struct lima_device *ldev = to_lima_dev(dev);
+
+ switch (ldev->id) {
+ case lima_gpu_mali400:
+ info->gpu_id = LIMA_INFO_GPU_MALI400;
+ break;
+ case lima_gpu_mali450:
+ info->gpu_id = LIMA_INFO_GPU_MALI450;
+ break;
+ default:
+ return -ENODEV;
+ }
+ info->num_pp = ldev->pipe[lima_pipe_pp].num_processor;
+ info->va_start = ldev->va_start;
+ info->va_end = ldev->va_end;
+ return 0;
+}
+
+static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_gem_create *args = data;
+
+ if (args->flags)
+ return -EINVAL;
+
+ if (args->size == 0)
+ return -EINVAL;
+
+ return lima_gem_create_handle(dev, file, args->size, args->flags, &args->handle);
+}
+
+static int lima_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_gem_info *args = data;
+
+ return lima_gem_mmap_offset(file, args->handle, &args->offset);
+}
+
+static int lima_ioctl_gem_va(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_gem_va *args = data;
+
+ switch (args->op) {
+ case LIMA_VA_OP_MAP:
+ return lima_gem_va_map(file, args->handle, args->flags, args->va);
+ case LIMA_VA_OP_UNMAP:
+ return lima_gem_va_unmap(file, args->handle, args->va);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lima_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_gem_submit_in *args = data;
+ struct lima_device *ldev = to_lima_dev(dev);
+ struct lima_drm_priv *priv = file->driver_priv;
+ struct drm_lima_gem_submit_bo *bos;
+ struct ttm_validate_buffer *vbs;
+ union drm_lima_gem_submit_dep *deps = NULL;
+ struct lima_sched_pipe *pipe;
+ struct lima_sched_task *task;
+ struct lima_ctx *ctx;
+ struct lima_submit submit = {0};
+ int err = 0, size;
+
+ if (args->pipe >= lima_pipe_num || args->nr_bos == 0)
+ return -EINVAL;
+
+ if (args->flags & ~(LIMA_SUBMIT_FLAG_EXPLICIT_FENCE |
+ LIMA_SUBMIT_FLAG_SYNC_FD_OUT))
+ return -EINVAL;
+
+ pipe = ldev->pipe + args->pipe;
+ if (args->frame_size != pipe->frame_size)
+ return -EINVAL;
+
+ size = args->nr_bos * (sizeof(*submit.bos) + sizeof(*submit.vbs)) +
+ args->nr_deps * sizeof(*submit.deps);
+ bos = kzalloc(size, GFP_KERNEL);
+ if (!bos)
+ return -ENOMEM;
+
+ size = args->nr_bos * sizeof(*submit.bos);
+ if (copy_from_user(bos, u64_to_user_ptr(args->bos), size)) {
+ err = -EFAULT;
+ goto out0;
+ }
+
+ vbs = (void *)bos + size;
+
+ if (args->nr_deps) {
+ deps = (void *)vbs + args->nr_bos * sizeof(*submit.vbs);
+ size = args->nr_deps * sizeof(*submit.deps);
+ if (copy_from_user(deps, u64_to_user_ptr(args->deps), size)) {
+ err = -EFAULT;
+ goto out0;
+ }
+ }
+
+ task = kmem_cache_zalloc(pipe->task_slab, GFP_KERNEL);
+ if (!task) {
+ err = -ENOMEM;
+ goto out0;
+ }
+
+ task->frame = task + 1;
+ if (copy_from_user(task->frame, u64_to_user_ptr(args->frame), args->frame_size)) {
+ err = -EFAULT;
+ goto out1;
+ }
+
+ err = pipe->task_validate(pipe, task);
+ if (err)
+ goto out1;
+
+ ctx = lima_ctx_get(&priv->ctx_mgr, args->ctx);
+ if (!ctx) {
+ err = -ENOENT;
+ goto out1;
+ }
+
+ submit.pipe = args->pipe;
+ submit.bos = bos;
+ submit.vbs = vbs;
+ submit.nr_bos = args->nr_bos;
+ submit.task = task;
+ submit.ctx = ctx;
+ submit.deps = deps;
+ submit.nr_deps = args->nr_deps;
+ submit.flags = args->flags;
+
+ err = lima_gem_submit(file, &submit);
+ if (!err) {
+ struct drm_lima_gem_submit_out *out = data;
+ out->fence = submit.fence;
+ out->done = submit.done;
+ out->sync_fd = submit.sync_fd;
+ }
+
+ lima_ctx_put(ctx);
+out1:
+ if (err)
+ kmem_cache_free(pipe->task_slab, task);
+out0:
+ kfree(bos);
+ return err;
+}
+
+static int lima_wait_fence(struct dma_fence *fence, u64 timeout_ns)
+{
+ signed long ret;
+
+ if (!timeout_ns)
+ ret = dma_fence_is_signaled(fence) ? 0 : -EBUSY;
+ else {
+ unsigned long timeout = lima_timeout_to_jiffies(timeout_ns);
+
+ /* must use long for result check because in 64bit arch int
+ * will overflow if timeout is too large and get <0 result
+ */
+ ret = dma_fence_wait_timeout(fence, true, timeout);
+ if (ret == 0)
+ ret = timeout ? -ETIMEDOUT : -EBUSY;
+ else if (ret > 0)
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int lima_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_wait_fence *args = data;
+ struct lima_drm_priv *priv = file->driver_priv;
+ struct dma_fence *fence;
+ int err = 0;
+
+ fence = lima_ctx_get_native_fence(&priv->ctx_mgr, args->ctx,
+ args->pipe, args->seq);
+ if (IS_ERR(fence))
+ return PTR_ERR(fence);
+
+ if (fence) {
+ err = lima_wait_fence(fence, args->timeout_ns);
+ dma_fence_put(fence);
+ }
+
+ return err;
+}
+
+static int lima_ioctl_gem_wait(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_gem_wait *args = data;
+
+ if (!(args->op & (LIMA_GEM_WAIT_READ|LIMA_GEM_WAIT_WRITE)))
+ return -EINVAL;
+
+ return lima_gem_wait(file, args->handle, args->op, args->timeout_ns);
+}
+
+static int lima_ioctl_ctx(struct drm_device *dev, void *data, struct drm_file *file)
+{
+ struct drm_lima_ctx *args = data;
+ struct lima_drm_priv *priv = file->driver_priv;
+ struct lima_device *ldev = to_lima_dev(dev);
+
+ if (args->op == LIMA_CTX_OP_CREATE)
+ return lima_ctx_create(ldev, &priv->ctx_mgr, &args->id);
+ else if (args->op == LIMA_CTX_OP_FREE)
+ return lima_ctx_free(&priv->ctx_mgr, args->id);
+
+ return -EINVAL;
+}
+
+static int lima_drm_driver_open(struct drm_device *dev, struct drm_file *file)
+{
+ int err;
+ struct lima_drm_priv *priv;
+ struct lima_device *ldev = to_lima_dev(dev);
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->vm = lima_vm_create(ldev);
+ if (!priv->vm) {
+ err = -ENOMEM;
+ goto err_out0;
+ }
+
+ lima_ctx_mgr_init(&priv->ctx_mgr);
+
+ file->driver_priv = priv;
+ return 0;
+
+err_out0:
+ kfree(priv);
+ return err;
+}
+
+static void lima_drm_driver_preclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct lima_drm_priv *priv = file->driver_priv;
+
+ lima_ctx_mgr_fini(&priv->ctx_mgr);
+}
+
+static void lima_drm_driver_postclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct lima_drm_priv *priv = file->driver_priv;
+
+ lima_vm_put(priv->vm);
+ kfree(priv);
+}
+
+static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = {
+ DRM_IOCTL_DEF_DRV(LIMA_INFO, lima_ioctl_info, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_GEM_CREATE, lima_ioctl_gem_create, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_GEM_INFO, lima_ioctl_gem_info, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_GEM_VA, lima_ioctl_gem_va, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_GEM_SUBMIT, lima_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_WAIT_FENCE, lima_ioctl_wait_fence, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_GEM_WAIT, lima_ioctl_gem_wait, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(LIMA_CTX, lima_ioctl_ctx, DRM_AUTH|DRM_RENDER_ALLOW),
+};
+
+static const struct file_operations lima_drm_driver_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .mmap = lima_gem_mmap,
+};
+
+static struct drm_driver lima_drm_driver = {
+ .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_PRIME,
+ .open = lima_drm_driver_open,
+ .preclose = lima_drm_driver_preclose,
+ .postclose = lima_drm_driver_postclose,
+ .ioctls = lima_drm_driver_ioctls,
+ .num_ioctls = ARRAY_SIZE(lima_drm_driver_ioctls),
+ .fops = &lima_drm_driver_fops,
+ .gem_free_object_unlocked = lima_gem_free_object,
+ .gem_open_object = lima_gem_object_open,
+ .gem_close_object = lima_gem_object_close,
+ .name = "lima",
+ .desc = "lima DRM",
+ .date = "20170325",
+ .major = 1,
+ .minor = 0,
+ .patchlevel = 0,
+
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_import_sg_table = lima_gem_prime_import_sg_table,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_res_obj = lima_gem_prime_res_obj,
+ .gem_prime_get_sg_table = lima_gem_prime_get_sg_table,
+};
+
+static int lima_pdev_probe(struct platform_device *pdev)
+{
+ struct lima_device *ldev;
+ struct drm_device *ddev;
+ int err;
+
+ ldev = devm_kzalloc(&pdev->dev, sizeof(*ldev), GFP_KERNEL);
+ if (!ldev)
+ return -ENOMEM;
+
+ ldev->pdev = pdev;
+ ldev->dev = &pdev->dev;
+ ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev);
+
+ platform_set_drvdata(pdev, ldev);
+
+ /* Allocate and initialize the DRM device. */
+ ddev = drm_dev_alloc(&lima_drm_driver, &pdev->dev);
+ if (IS_ERR(ddev))
+ return PTR_ERR(ddev);
+
+ ddev->dev_private = ldev;
+ ldev->ddev = ddev;
+
+ err = lima_device_init(ldev);
+ if (err) {
+ dev_err(&pdev->dev, "Fatal error during GPU init\n");
+ goto err_out0;
+ }
+
+ /*
+ * Register the DRM device with the core and the connectors with
+ * sysfs.
+ */
+ err = drm_dev_register(ddev, 0);
+ if (err < 0)
+ goto err_out1;
+
+ return 0;
+
+err_out1:
+ lima_device_fini(ldev);
+err_out0:
+ drm_dev_unref(ddev);
+ return err;
+}
+
+static int lima_pdev_remove(struct platform_device *pdev)
+{
+ struct lima_device *ldev = platform_get_drvdata(pdev);
+ struct drm_device *ddev = ldev->ddev;
+
+ drm_dev_unregister(ddev);
+ lima_device_fini(ldev);
+ drm_dev_unref(ddev);
+ return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+ { .compatible = "arm,mali-400", .data = (void *)lima_gpu_mali400 },
+ { .compatible = "arm,mali-450", .data = (void *)lima_gpu_mali450 },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
+static struct platform_driver lima_platform_driver = {
+ .probe = lima_pdev_probe,
+ .remove = lima_pdev_remove,
+ .driver = {
+ .name = "lima",
+ .of_match_table = dt_match,
+ },
+};
+
+static void lima_check_module_param(void)
+{
+ if (lima_sched_max_tasks < 4)
+ lima_sched_max_tasks = 4;
+ else
+ lima_sched_max_tasks = roundup_pow_of_two(lima_sched_max_tasks);
+
+ if (lima_max_mem < 32)
+ lima_max_mem = -1;
+}
+
+static int __init lima_init(void)
+{
+ int ret;
+
+ lima_check_module_param();
+ ret = lima_sched_slab_init();
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&lima_platform_driver);
+ if (ret)
+ lima_sched_slab_fini();
+
+ return ret;
+}
+module_init(lima_init);
+
+static void __exit lima_exit(void)
+{
+ platform_driver_unregister(&lima_platform_driver);
+ lima_sched_slab_fini();
+}
+module_exit(lima_exit);
+
+MODULE_AUTHOR("Lima Project Developers");
+MODULE_DESCRIPTION("Lima DRM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h
new file mode 100644
index 000000000000..2f5f51da21db
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_drv.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_DRV_H__
+#define __LIMA_DRV_H__
+
+#include <drm/drmP.h>
+#include <drm/ttm/ttm_execbuf_util.h>
+
+#include "lima_ctx.h"
+
+extern int lima_sched_timeout_ms;
+extern int lima_sched_max_tasks;
+extern int lima_max_mem;
+
+struct lima_vm;
+struct lima_bo;
+struct lima_sched_task;
+
+struct drm_lima_gem_submit_bo;
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+struct lima_drm_priv {
+ struct lima_vm *vm;
+ struct lima_ctx_mgr ctx_mgr;
+};
+
+struct lima_submit {
+ struct lima_ctx *ctx;
+ int pipe;
+ u32 flags;
+
+ struct drm_lima_gem_submit_bo *bos;
+ struct ttm_validate_buffer *vbs;
+ u32 nr_bos;
+
+ struct ttm_validate_buffer vm_pd_vb;
+ struct ww_acquire_ctx ticket;
+ struct list_head duplicates;
+ struct list_head validated;
+
+ union drm_lima_gem_submit_dep *deps;
+ u32 nr_deps;
+
+ struct lima_sched_task *task;
+
+ uint32_t fence;
+ uint32_t done;
+ int sync_fd;
+};
+
+static inline struct lima_drm_priv *
+to_lima_drm_priv(struct drm_file *file)
+{
+ return file->driver_priv;
+}
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 06/12] media: dt-bindings: add bindings for i.MX7 media driver
From: Rui Miguel Silva @ 2018-05-18 9:28 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
Add bindings documentation for i.MX7 media drivers.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
.../devicetree/bindings/media/imx7.txt | 125 ++++++++++++++++++
1 file changed, 125 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/imx7.txt
diff --git a/Documentation/devicetree/bindings/media/imx7.txt b/Documentation/devicetree/bindings/media/imx7.txt
new file mode 100644
index 000000000000..a26372630377
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/imx7.txt
@@ -0,0 +1,125 @@
+Freescale i.MX7 Media Video Device
+==================================
+
+mipi_csi2 node
+--------------
+
+This is the device node for the MIPI CSI-2 receiver core in i.MX7 SoC. It is
+compatible with previous version of Samsung D-phy.
+
+Required properties:
+
+- compatible : "fsl,imx7-mipi-csi2";
+- reg : base address and length of the register set for the device;
+- interrupts : should contain MIPI CSIS interrupt;
+- clocks : list of clock specifiers, see
+ Documentation/devicetree/bindings/clock/clock-bindings.txt for details;
+- clock-names : must contain "pclk", "wrap" and "phy" entries, matching
+ entries in the clock property;
+- power-domains : a phandle to the power domain, see
+ Documentation/devicetree/bindings/power/power_domain.txt for details.
+- reset-names : should include following entry "mrst";
+- resets : a list of phandle, should contain reset entry of
+ reset-names;
+- phy-supply : from the generic phy bindings, a phandle to a regulator that
+ provides power to MIPI CSIS core;
+- bus-width : maximum number of data lanes supported (SoC specific);
+
+Optional properties:
+
+- clock-frequency : The IP's main (system bus) clock frequency in Hz, default
+ value when this property is not specified is 166 MHz;
+
+port node
+---------
+
+- reg : (required) can take the values 0 or 1, where 0 is the
+ related sink port and port 1 should be the source one;
+
+endpoint node
+-------------
+
+- data-lanes : (required) an array specifying active physical MIPI-CSI2
+ data input lanes and their mapping to logical lanes; the
+ array's content is unused, only its length is meaningful;
+
+- fsl,csis-hs-settle : (optional) differential receiver (HS-RX) settle time;
+
+example:
+
+ mipi_csi: mipi-csi@30750000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "fsl,imx7-mipi-csi2";
+ reg = <0x30750000 0x10000>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_IPG_ROOT_CLK>,
+ <&clks IMX7D_MIPI_CSI_ROOT_CLK>,
+ <&clks IMX7D_MIPI_DPHY_ROOT_CLK>;
+ clock-names = "pclk", "wrap", "phy";
+ clock-names = "mipi", "phy";
+ clock-frequency = <166000000>;
+ power-domains = <&pgc_mipi_phy>;
+ phy-supply = <®_1p0d>;
+ resets = <&src IMX7_RESET_MIPI_PHY_MRST>;
+ reset-names = "mrst";
+ bus-width = <4>;
+ fsl,csis-hs-settle = <3>;
+ fsl,csis-clk-settle = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mipi_from_sensor: endpoint {
+ remote-endpoint = <&ov2680_to_mipi>;
+ data-lanes = <1>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mipi_vc0_to_csi_mux: endpoint {
+ remote-endpoint = <&csi_mux_from_mipi_vc0>;
+ };
+ };
+ };
+
+
+csi node
+--------
+
+This is device node for the CMOS Sensor Interface (CSI) which enables the chip
+to connect directly to external CMOS image sensors.
+
+Required properties:
+
+- compatible : "fsl,imx7-csi";
+- reg : base address and length of the register set for the device;
+- interrupts : should contain CSI interrupt;
+- clocks : list of clock specifiers, see
+ Documentation/devicetree/bindings/clock/clock-bindings.txt for details;
+- clock-names : must contain "axi", "mclk" and "dcic" entries, matching
+ entries in the clock property;
+
+example:
+
+ csi: csi@30710000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "fsl,imx7-csi";
+ reg = <0x30710000 0x10000>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CSI_MCLK_ROOT_CLK>,
+ <&clks IMX7D_CLK_DUMMY>;
+ clock-names = "axi", "mclk", "dcic";
+
+ port {
+ csi_from_csi_mux: endpoint {
+ remote-endpoint = <&csi_mux_to_csi>;
+ };
+ };
+ };
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 09/24] drm/lima: add GPU device functions
From: Qiang Yu @ 2018-05-18 9:28 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Lima Project Developers <dri-devel@lists.freedesktop.org>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Signed-off-by: Simon Shields <simon@lineageos.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/gpu/drm/lima/lima_device.c | 407 +++++++++++++++++++++++++++++
drivers/gpu/drm/lima/lima_device.h | 136 ++++++++++
2 files changed, 543 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_device.c
create mode 100644 drivers/gpu/drm/lima/lima_device.h
diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c
new file mode 100644
index 000000000000..a6c3905a0c85
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_device.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include "lima_device.h"
+#include "lima_gp.h"
+#include "lima_pp.h"
+#include "lima_mmu.h"
+#include "lima_pmu.h"
+#include "lima_l2_cache.h"
+#include "lima_dlbu.h"
+#include "lima_bcast.h"
+#include "lima_vm.h"
+
+struct lima_ip_desc {
+ char *name;
+ char *irq_name;
+ bool must_have[lima_gpu_num];
+ int offset[lima_gpu_num];
+
+ int (*init)(struct lima_ip *);
+ void (*fini)(struct lima_ip *);
+};
+
+#define LIMA_IP_DESC(ipname, mst0, mst1, off0, off1, func, irq) \
+ [lima_ip_##ipname] = { \
+ .name = #ipname, \
+ .irq_name = irq, \
+ .must_have = { \
+ [lima_gpu_mali400] = mst0, \
+ [lima_gpu_mali450] = mst1, \
+ }, \
+ .offset = { \
+ [lima_gpu_mali400] = off0, \
+ [lima_gpu_mali450] = off1, \
+ }, \
+ .init = lima_##func##_init, \
+ .fini = lima_##func##_fini, \
+ }
+
+static struct lima_ip_desc lima_ip_desc[lima_ip_num] = {
+ LIMA_IP_DESC(pmu, false, false, 0x02000, 0x02000, pmu, "pmu"),
+ LIMA_IP_DESC(l2_cache0, true, true, 0x01000, 0x10000, l2_cache, NULL),
+ LIMA_IP_DESC(l2_cache1, false, true, -1, 0x01000, l2_cache, NULL),
+ LIMA_IP_DESC(l2_cache2, false, false, -1, 0x11000, l2_cache, NULL),
+ LIMA_IP_DESC(gp, true, true, 0x00000, 0x00000, gp, "gp"),
+ LIMA_IP_DESC(pp0, true, true, 0x08000, 0x08000, pp, "pp0"),
+ LIMA_IP_DESC(pp1, false, false, 0x0A000, 0x0A000, pp, "pp1"),
+ LIMA_IP_DESC(pp2, false, false, 0x0C000, 0x0C000, pp, "pp2"),
+ LIMA_IP_DESC(pp3, false, false, 0x0E000, 0x0E000, pp, "pp3"),
+ LIMA_IP_DESC(pp4, false, false, -1, 0x28000, pp, "pp4"),
+ LIMA_IP_DESC(pp5, false, false, -1, 0x2A000, pp, "pp5"),
+ LIMA_IP_DESC(pp6, false, false, -1, 0x2C000, pp, "pp6"),
+ LIMA_IP_DESC(pp7, false, false, -1, 0x2E000, pp, "pp7"),
+ LIMA_IP_DESC(gpmmu, true, true, 0x03000, 0x03000, mmu, "gpmmu"),
+ LIMA_IP_DESC(ppmmu0, true, true, 0x04000, 0x04000, mmu, "ppmmu0"),
+ LIMA_IP_DESC(ppmmu1, false, false, 0x05000, 0x05000, mmu, "ppmmu1"),
+ LIMA_IP_DESC(ppmmu2, false, false, 0x06000, 0x06000, mmu, "ppmmu2"),
+ LIMA_IP_DESC(ppmmu3, false, false, 0x07000, 0x07000, mmu, "ppmmu3"),
+ LIMA_IP_DESC(ppmmu4, false, false, -1, 0x1C000, mmu, "ppmmu4"),
+ LIMA_IP_DESC(ppmmu5, false, false, -1, 0x1D000, mmu, "ppmmu5"),
+ LIMA_IP_DESC(ppmmu6, false, false, -1, 0x1E000, mmu, "ppmmu6"),
+ LIMA_IP_DESC(ppmmu7, false, false, -1, 0x1F000, mmu, "ppmmu7"),
+ LIMA_IP_DESC(dlbu, false, true, -1, 0x14000, dlbu, NULL),
+ LIMA_IP_DESC(bcast, false, true, -1, 0x13000, bcast, NULL),
+ LIMA_IP_DESC(pp_bcast, false, true, -1, 0x16000, pp_bcast, "pp"),
+ LIMA_IP_DESC(ppmmu_bcast, false, true, -1, 0x15000, mmu, NULL),
+};
+
+const char *lima_ip_name(struct lima_ip *ip)
+{
+ return lima_ip_desc[ip->id].name;
+}
+
+static int lima_clk_init(struct lima_device *dev)
+{
+ int err;
+ unsigned long bus_rate, gpu_rate;
+
+ dev->clk_bus = devm_clk_get(dev->dev, "bus");
+ if (IS_ERR(dev->clk_bus)) {
+ dev_err(dev->dev, "get bus clk failed %ld\n", PTR_ERR(dev->clk_bus));
+ return PTR_ERR(dev->clk_bus);
+ }
+
+ dev->clk_gpu = devm_clk_get(dev->dev, "core");
+ if (IS_ERR(dev->clk_gpu)) {
+ dev_err(dev->dev, "get core clk failed %ld\n", PTR_ERR(dev->clk_gpu));
+ return PTR_ERR(dev->clk_gpu);
+ }
+
+ bus_rate = clk_get_rate(dev->clk_bus);
+ dev_info(dev->dev, "bus rate = %lu\n", bus_rate);
+
+ gpu_rate = clk_get_rate(dev->clk_gpu);
+ dev_info(dev->dev, "mod rate = %lu", gpu_rate);
+
+ if ((err = clk_prepare_enable(dev->clk_bus)))
+ return err;
+ if ((err = clk_prepare_enable(dev->clk_gpu)))
+ goto error_out0;
+
+ dev->reset = devm_reset_control_get_optional(dev->dev, NULL);
+ if (IS_ERR(dev->reset)) {
+ err = PTR_ERR(dev->reset);
+ goto error_out1;
+ } else if (dev->reset != NULL) {
+ if ((err = reset_control_deassert(dev->reset)))
+ goto error_out1;
+ }
+
+ return 0;
+
+error_out1:
+ clk_disable_unprepare(dev->clk_gpu);
+error_out0:
+ clk_disable_unprepare(dev->clk_bus);
+ return err;
+}
+
+static void lima_clk_fini(struct lima_device *dev)
+{
+ if (dev->reset != NULL)
+ reset_control_assert(dev->reset);
+ clk_disable_unprepare(dev->clk_gpu);
+ clk_disable_unprepare(dev->clk_bus);
+}
+
+static int lima_regulator_init(struct lima_device *dev)
+{
+ int ret;
+ dev->regulator = devm_regulator_get_optional(dev->dev, "mali");
+ if (IS_ERR(dev->regulator)) {
+ ret = PTR_ERR(dev->regulator);
+ dev->regulator = NULL;
+ if (ret == -ENODEV)
+ return 0;
+ dev_err(dev->dev, "failed to get regulator: %ld\n", PTR_ERR(dev->regulator));
+ return ret;
+ }
+
+ ret = regulator_enable(dev->regulator);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void lima_regulator_fini(struct lima_device *dev)
+{
+ if (dev->regulator)
+ regulator_disable(dev->regulator);
+}
+
+static int lima_init_ip(struct lima_device *dev, int index)
+{
+ struct lima_ip_desc *desc = lima_ip_desc + index;
+ struct lima_ip *ip = dev->ip + index;
+ int offset = desc->offset[dev->id];
+ bool must = desc->must_have[dev->id];
+ int err;
+
+ if (offset < 0)
+ return 0;
+
+ ip->dev = dev;
+ ip->id = index;
+ ip->iomem = dev->iomem + offset;
+ if (desc->irq_name) {
+ err = platform_get_irq_byname(dev->pdev, desc->irq_name);
+ if (err < 0)
+ goto out;
+ ip->irq = err;
+ }
+
+ err = desc->init(ip);
+ if (!err) {
+ ip->present = true;
+ return 0;
+ }
+
+out:
+ return must ? err : 0;
+}
+
+static void lima_fini_ip(struct lima_device *ldev, int index)
+{
+ struct lima_ip_desc *desc = lima_ip_desc + index;
+ struct lima_ip *ip = ldev->ip + index;
+
+ if (ip->present)
+ desc->fini(ip);
+}
+
+static int lima_init_gp_pipe(struct lima_device *dev)
+{
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
+ int err;
+
+ if ((err = lima_sched_pipe_init(pipe, "gp")))
+ return err;
+
+ pipe->l2_cache[pipe->num_l2_cache++] = dev->ip + lima_ip_l2_cache0;
+ pipe->mmu[pipe->num_mmu++] = dev->ip + lima_ip_gpmmu;
+ pipe->processor[pipe->num_processor++] = dev->ip + lima_ip_gp;
+
+ if ((err = lima_gp_pipe_init(dev))) {
+ lima_sched_pipe_fini(pipe);
+ return err;
+ }
+
+ return 0;
+}
+
+static void lima_fini_gp_pipe(struct lima_device *dev)
+{
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
+
+ lima_gp_pipe_fini(dev);
+ lima_sched_pipe_fini(pipe);
+}
+
+static int lima_init_pp_pipe(struct lima_device *dev)
+{
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+ int err, i;
+
+ if ((err = lima_sched_pipe_init(pipe, "pp")))
+ return err;
+
+ for (i = 0; i < LIMA_SCHED_PIPE_MAX_PROCESSOR; i++) {
+ struct lima_ip *pp = dev->ip + lima_ip_pp0 + i;
+ struct lima_ip *ppmmu = dev->ip + lima_ip_ppmmu0 + i;
+ struct lima_ip *l2_cache;
+
+ if (dev->id == lima_gpu_mali400)
+ l2_cache = dev->ip + lima_ip_l2_cache0;
+ else
+ l2_cache = dev->ip + lima_ip_l2_cache1 + (i >> 2);
+
+ if (pp->present && ppmmu->present && l2_cache->present) {
+ pipe->mmu[pipe->num_mmu++] = ppmmu;
+ pipe->processor[pipe->num_processor++] = pp;
+ if (!pipe->l2_cache[i >> 2])
+ pipe->l2_cache[pipe->num_l2_cache++] = l2_cache;
+ }
+ }
+
+ if (dev->ip[lima_ip_bcast].present) {
+ pipe->bcast_processor = dev->ip + lima_ip_pp_bcast;
+ pipe->bcast_mmu = dev->ip + lima_ip_ppmmu_bcast;
+ }
+
+ if ((err = lima_pp_pipe_init(dev))) {
+ lima_sched_pipe_fini(pipe);
+ return err;
+ }
+
+ return 0;
+}
+
+static void lima_fini_pp_pipe(struct lima_device *dev)
+{
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+
+ lima_pp_pipe_fini(dev);
+ lima_sched_pipe_fini(pipe);
+}
+
+int lima_device_init(struct lima_device *ldev)
+{
+ int err, i;
+ struct resource *res;
+
+ dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32));
+
+ err = lima_clk_init(ldev);
+ if (err) {
+ dev_err(ldev->dev, "clk init fail %d\n", err);
+ return err;
+ }
+
+ if ((err = lima_regulator_init(ldev))) {
+ dev_err(ldev->dev, "regulator init fail %d\n", err);
+ goto err_out0;
+ }
+
+ err = lima_ttm_init(ldev);
+ if (err)
+ goto err_out1;
+
+ ldev->empty_vm = lima_vm_create(ldev);
+ if (!ldev->empty_vm) {
+ err = -ENOMEM;
+ goto err_out2;
+ }
+
+ ldev->va_start = 0;
+ if (ldev->id == lima_gpu_mali450) {
+ ldev->va_end = LIMA_VA_RESERVE_START;
+ ldev->dlbu_cpu = dma_alloc_wc(
+ ldev->dev, LIMA_PAGE_SIZE,
+ &ldev->dlbu_dma, GFP_KERNEL);
+ if (!ldev->dlbu_cpu) {
+ err = -ENOMEM;
+ goto err_out3;
+ }
+ }
+ else
+ ldev->va_end = LIMA_VA_RESERVE_END;
+
+ res = platform_get_resource(ldev->pdev, IORESOURCE_MEM, 0);
+ ldev->iomem = devm_ioremap_resource(ldev->dev, res);
+ if (IS_ERR(ldev->iomem)) {
+ dev_err(ldev->dev, "fail to ioremap iomem\n");
+ err = PTR_ERR(ldev->iomem);
+ goto err_out4;
+ }
+
+ for (i = 0; i < lima_ip_num; i++) {
+ err = lima_init_ip(ldev, i);
+ if (err)
+ goto err_out5;
+ }
+
+ err = lima_init_gp_pipe(ldev);
+ if (err)
+ goto err_out5;
+
+ err = lima_init_pp_pipe(ldev);
+ if (err)
+ goto err_out6;
+
+ if (ldev->id == lima_gpu_mali450) {
+ lima_dlbu_enable(ldev);
+ lima_bcast_enable(ldev);
+ }
+
+ return 0;
+
+err_out6:
+ lima_fini_gp_pipe(ldev);
+err_out5:
+ while (--i >= 0)
+ lima_fini_ip(ldev, i);
+err_out4:
+ if (ldev->dlbu_cpu)
+ dma_free_wc(ldev->dev, LIMA_PAGE_SIZE,
+ ldev->dlbu_cpu, ldev->dlbu_dma);
+err_out3:
+ lima_vm_put(ldev->empty_vm);
+err_out2:
+ lima_ttm_fini(ldev);
+err_out1:
+ lima_regulator_fini(ldev);
+err_out0:
+ lima_clk_fini(ldev);
+ return err;
+}
+
+void lima_device_fini(struct lima_device *ldev)
+{
+ int i;
+
+ lima_fini_pp_pipe(ldev);
+ lima_fini_gp_pipe(ldev);
+
+ for (i = lima_ip_num - 1; i >= 0; i--)
+ lima_fini_ip(ldev, i);
+
+ if (ldev->dlbu_cpu)
+ dma_free_wc(ldev->dev, LIMA_PAGE_SIZE,
+ ldev->dlbu_cpu, ldev->dlbu_dma);
+
+ lima_vm_put(ldev->empty_vm);
+
+ lima_ttm_fini(ldev);
+
+ lima_regulator_fini(ldev);
+
+ lima_clk_fini(ldev);
+}
diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h
new file mode 100644
index 000000000000..6c9c26b9e122
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_device.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_DEVICE_H__
+#define __LIMA_DEVICE_H__
+
+#include <drm/drm_device.h>
+
+#include "lima_sched.h"
+#include "lima_ttm.h"
+
+enum lima_gpu_id {
+ lima_gpu_mali400 = 0,
+ lima_gpu_mali450,
+ lima_gpu_num,
+};
+
+enum lima_ip_id {
+ lima_ip_pmu,
+ lima_ip_gpmmu,
+ lima_ip_ppmmu0,
+ lima_ip_ppmmu1,
+ lima_ip_ppmmu2,
+ lima_ip_ppmmu3,
+ lima_ip_ppmmu4,
+ lima_ip_ppmmu5,
+ lima_ip_ppmmu6,
+ lima_ip_ppmmu7,
+ lima_ip_gp,
+ lima_ip_pp0,
+ lima_ip_pp1,
+ lima_ip_pp2,
+ lima_ip_pp3,
+ lima_ip_pp4,
+ lima_ip_pp5,
+ lima_ip_pp6,
+ lima_ip_pp7,
+ lima_ip_l2_cache0,
+ lima_ip_l2_cache1,
+ lima_ip_l2_cache2,
+ lima_ip_dlbu,
+ lima_ip_bcast,
+ lima_ip_pp_bcast,
+ lima_ip_ppmmu_bcast,
+ lima_ip_num,
+};
+
+struct lima_device;
+
+struct lima_ip {
+ struct lima_device *dev;
+ enum lima_ip_id id;
+ bool present;
+
+ void __iomem *iomem;
+ int irq;
+
+ union {
+ /* pmu */
+ unsigned switch_delay;
+ /* gp/pp */
+ bool async_reset;
+ /* l2 cache */
+ spinlock_t lock;
+ } data;
+};
+
+enum lima_pipe_id {
+ lima_pipe_gp,
+ lima_pipe_pp,
+ lima_pipe_num,
+};
+
+struct lima_device {
+ struct device *dev;
+ struct drm_device *ddev;
+ struct platform_device *pdev;
+
+ enum lima_gpu_id id;
+ int num_pp;
+
+ void __iomem *iomem;
+ struct clk *clk_bus;
+ struct clk *clk_gpu;
+ struct reset_control *reset;
+ struct regulator *regulator;
+
+ struct lima_ip ip[lima_ip_num];
+ struct lima_sched_pipe pipe[lima_pipe_num];
+
+ struct lima_mman mman;
+
+ struct lima_vm *empty_vm;
+ uint64_t va_start;
+ uint64_t va_end;
+
+ u32 *dlbu_cpu;
+ dma_addr_t dlbu_dma;
+};
+
+static inline struct lima_device *
+to_lima_dev(struct drm_device *dev)
+{
+ return dev->dev_private;
+}
+
+static inline struct lima_device *
+ttm_to_lima_dev(struct ttm_bo_device *dev)
+{
+ return container_of(dev, struct lima_device, mman.bdev);
+}
+
+int lima_device_init(struct lima_device *ldev);
+void lima_device_fini(struct lima_device *ldev);
+
+const char *lima_ip_name(struct lima_ip *ip);
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 07/12] ARM: dts: imx7s: add mipi phy power domain
From: Rui Miguel Silva @ 2018-05-18 9:28 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
Add power domain index 0 related with mipi-phy to imx7s.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
arch/arm/boot/dts/imx7s.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 4d42335c0dee..67450ad89940 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -636,6 +636,12 @@
#address-cells = <1>;
#size-cells = <0>;
+ pgc_mipi_phy: pgc-power-domain@0 {
+ #power-domain-cells = <0>;
+ reg = <0>;
+ power-supply = <®_1p0d>;
+ };
+
pgc_pcie_phy: pgc-power-domain@1 {
#power-domain-cells = <0>;
reg = <1>;
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 10/24] drm/lima: add PMU related functions
From: Qiang Yu @ 2018-05-18 9:28 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Lima Project Developers <dri-devel@lists.freedesktop.org>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/gpu/drm/lima/lima_pmu.c | 85 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/lima/lima_pmu.h | 30 ++++++++++++
2 files changed, 115 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_pmu.c
create mode 100644 drivers/gpu/drm/lima/lima_pmu.h
diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c
new file mode 100644
index 000000000000..255a64e9f265
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_pmu.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/device.h>
+
+#include "lima_device.h"
+#include "lima_pmu.h"
+#include "lima_regs.h"
+
+#define pmu_write(reg, data) writel(data, ip->iomem + LIMA_PMU_##reg)
+#define pmu_read(reg) readl(ip->iomem + LIMA_PMU_##reg)
+
+static int lima_pmu_wait_cmd(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ u32 stat, timeout;
+
+ for (timeout = 1000000; timeout > 0; timeout--) {
+ stat = pmu_read(INT_RAWSTAT);
+ if (stat & LIMA_PMU_INT_CMD_MASK)
+ break;
+ }
+
+ if (!timeout) {
+ dev_err(dev->dev, "timeout wait pmd cmd\n");
+ return -ETIMEDOUT;
+ }
+
+ pmu_write(INT_CLEAR, LIMA_PMU_INT_CMD_MASK);
+ return 0;
+}
+
+int lima_pmu_init(struct lima_ip *ip)
+{
+ int err;
+ u32 stat;
+ struct lima_device *dev = ip->dev;
+ struct device_node *np = dev->dev->of_node;
+
+ /* If this value is too low, when in high GPU clk freq,
+ * GPU will be in unstable state. */
+ if (of_property_read_u32(np, "switch-delay", &ip->data.switch_delay))
+ ip->data.switch_delay = 0xff;
+
+ pmu_write(INT_MASK, 0);
+ pmu_write(SW_DELAY, ip->data.switch_delay);
+
+ /* status reg 1=off 0=on */
+ stat = pmu_read(STATUS);
+
+ /* power up all ip */
+ if (stat) {
+ pmu_write(POWER_UP, stat);
+ err = lima_pmu_wait_cmd(ip);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+void lima_pmu_fini(struct lima_ip *ip)
+{
+
+}
diff --git a/drivers/gpu/drm/lima/lima_pmu.h b/drivers/gpu/drm/lima/lima_pmu.h
new file mode 100644
index 000000000000..fb68a7059a37
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_pmu.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_PMU_H__
+#define __LIMA_PMU_H__
+
+struct lima_ip;
+
+int lima_pmu_init(struct lima_ip *ip);
+void lima_pmu_fini(struct lima_ip *ip);
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 08/12] ARM: dts: imx7s: add multiplexer controls
From: Rui Miguel Silva @ 2018-05-18 9:28 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
The IOMUXC General Purpose Register has bitfield to control video bus
multiplexer to control the CSI input between the MIPI-CSI2 and parallel
interface. Add that register and mask.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
---
arch/arm/boot/dts/imx7s.dtsi | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 67450ad89940..3590dab529f9 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -520,8 +520,14 @@
gpr: iomuxc-gpr@30340000 {
compatible = "fsl,imx7d-iomuxc-gpr",
- "fsl,imx6q-iomuxc-gpr", "syscon";
+ "fsl,imx6q-iomuxc-gpr", "syscon", "simple-mfd";
reg = <0x30340000 0x10000>;
+
+ mux: mux-controller {
+ compatible = "mmio-mux";
+ #mux-control-cells = <1>;
+ mux-reg-masks = <0x14 0x00000010>;
+ };
};
ocotp: ocotp-ctrl@30350000 {
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 11/24] drm/lima: add L2 cache functions
From: Qiang Yu @ 2018-05-18 9:28 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
drivers/gpu/drm/lima/lima_l2_cache.c | 98 ++++++++++++++++++++++++++++
drivers/gpu/drm/lima/lima_l2_cache.h | 32 +++++++++
2 files changed, 130 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.c
create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.h
diff --git a/drivers/gpu/drm/lima/lima_l2_cache.c b/drivers/gpu/drm/lima/lima_l2_cache.c
new file mode 100644
index 000000000000..a9b85de5c51a
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_l2_cache.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/io.h>
+#include <linux/device.h>
+
+#include "lima_device.h"
+#include "lima_l2_cache.h"
+#include "lima_regs.h"
+
+#define l2_cache_write(reg, data) writel(data, ip->iomem + LIMA_L2_CACHE_##reg)
+#define l2_cache_read(reg) readl(ip->iomem + LIMA_L2_CACHE_##reg)
+
+static int lima_l2_cache_wait_idle(struct lima_ip *ip)
+{
+ int timeout;
+ struct lima_device *dev = ip->dev;
+
+ for (timeout = 100000; timeout > 0; timeout--) {
+ if (!(l2_cache_read(STATUS) & LIMA_L2_CACHE_STATUS_COMMAND_BUSY))
+ break;
+ }
+ if (!timeout) {
+ dev_err(dev->dev, "l2 cache wait command timeout\n");
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+int lima_l2_cache_flush(struct lima_ip *ip)
+{
+ int ret;
+
+ spin_lock(&ip->data.lock);
+ l2_cache_write(COMMAND, LIMA_L2_CACHE_COMMAND_CLEAR_ALL);
+ ret = lima_l2_cache_wait_idle(ip);
+ spin_unlock(&ip->data.lock);
+ return ret;
+}
+
+int lima_l2_cache_init(struct lima_ip *ip)
+{
+ int i, err;
+ u32 size;
+ struct lima_device *dev = ip->dev;
+
+ /* l2_cache2 only exists when one of PP4-7 present */
+ if (ip->id == lima_ip_l2_cache2) {
+ for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) {
+ if (dev->ip[i].present)
+ break;
+ }
+ if (i > lima_ip_pp7)
+ return -ENODEV;
+ }
+
+ spin_lock_init(&ip->data.lock);
+
+ size = l2_cache_read(SIZE);
+ dev_info(dev->dev, "l2 cache %uK, %u-way, %ubyte cache line, %ubit external bus\n",
+ 1 << (((size >> 16) & 0xff) - 10),
+ 1 << ((size >> 8) & 0xff),
+ 1 << (size & 0xff),
+ 1 << ((size >> 24) & 0xff));
+
+ err = lima_l2_cache_flush(ip);
+ if (err)
+ return err;
+
+ l2_cache_write(ENABLE, LIMA_L2_CACHE_ENABLE_ACCESS | LIMA_L2_CACHE_ENABLE_READ_ALLOCATE);
+ l2_cache_write(MAX_READS, 0x1c);
+
+ return 0;
+}
+
+void lima_l2_cache_fini(struct lima_ip *ip)
+{
+
+}
diff --git a/drivers/gpu/drm/lima/lima_l2_cache.h b/drivers/gpu/drm/lima/lima_l2_cache.h
new file mode 100644
index 000000000000..4a35725bf38d
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_l2_cache.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_L2_CACHE_H__
+#define __LIMA_L2_CACHE_H__
+
+struct lima_ip;
+
+int lima_l2_cache_init(struct lima_ip *ip);
+void lima_l2_cache_fini(struct lima_ip *ip);
+
+int lima_l2_cache_flush(struct lima_ip *ip);
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 09/12] ARM: dts: imx7: Add video mux, csi and mipi_csi and connections
From: Rui Miguel Silva @ 2018-05-18 9:28 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
This patch adds the device tree nodes for csi, video multiplexer and mipi-csi
besides the graph connecting the necessary endpoints to make the media capture
entities to work in imx7 Warp board.
Also add the pin control related with the mipi_csi in that board.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
arch/arm/boot/dts/imx7s-warp.dts | 51 ++++++++++++++++++++++++++++++++
arch/arm/boot/dts/imx7s.dtsi | 28 ++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-warp.dts
index 8a30b148534d..cb175ee2fc9d 100644
--- a/arch/arm/boot/dts/imx7s-warp.dts
+++ b/arch/arm/boot/dts/imx7s-warp.dts
@@ -310,6 +310,57 @@
status = "okay";
};
+&gpr {
+ csi_mux {
+ compatible = "video-mux";
+ mux-controls = <&mux 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+
+ csi_mux_from_mipi_vc0: endpoint {
+ remote-endpoint = <&mipi_vc0_to_csi_mux>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+
+ csi_mux_to_csi: endpoint {
+ remote-endpoint = <&csi_from_csi_mux>;
+ };
+ };
+ };
+};
+
+&csi {
+ status = "okay";
+
+ port {
+ csi_from_csi_mux: endpoint {
+ remote-endpoint = <&csi_mux_to_csi>;
+ };
+ };
+};
+
+&mipi_csi {
+ clock-frequency = <166000000>;
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ fsl,csis-hs-settle = <3>;
+
+ port@1 {
+ reg = <1>;
+
+ mipi_vc0_to_csi_mux: endpoint {
+ remote-endpoint = <&csi_mux_from_mipi_vc0>;
+ };
+ };
+};
+
&wdog1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_wdog>;
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index 3590dab529f9..0bae41f2944c 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -46,6 +46,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/imx7-reset.h>
#include "imx7d-pinfunc.h"
/ {
@@ -738,6 +739,17 @@
status = "disabled";
};
+ csi: csi@30710000 {
+ compatible = "fsl,imx7-csi";
+ reg = <0x30710000 0x10000>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_CLK_DUMMY>,
+ <&clks IMX7D_CSI_MCLK_ROOT_CLK>,
+ <&clks IMX7D_CLK_DUMMY>;
+ clock-names = "axi", "mclk", "dcic";
+ status = "disabled";
+ };
+
lcdif: lcdif@30730000 {
compatible = "fsl,imx7d-lcdif", "fsl,imx28-lcdif";
reg = <0x30730000 0x10000>;
@@ -747,6 +759,22 @@
clock-names = "pix", "axi";
status = "disabled";
};
+
+ mipi_csi: mipi-csi@30750000 {
+ compatible = "fsl,imx7-mipi-csi2";
+ reg = <0x30750000 0x10000>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_IPG_ROOT_CLK>,
+ <&clks IMX7D_MIPI_CSI_ROOT_CLK>,
+ <&clks IMX7D_MIPI_DPHY_ROOT_CLK>;
+ clock-names = "pclk", "wrap", "phy";
+ power-domains = <&pgc_mipi_phy>;
+ phy-supply = <®_1p0d>;
+ resets = <&src IMX7_RESET_MIPI_PHY_MRST>;
+ reset-names = "mrst";
+ bus-width = <2>;
+ status = "disabled";
+ };
};
aips3: aips-bus@30800000 {
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 12/24] drm/lima: add GP related functions
From: Qiang Yu @ 2018-05-18 9:28 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
GP is a processor for OpenGL vertex shader
processing.
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
drivers/gpu/drm/lima/lima_gp.c | 293 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/lima/lima_gp.h | 34 ++++
2 files changed, 327 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_gp.c
create mode 100644 drivers/gpu/drm/lima/lima_gp.h
diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c
new file mode 100644
index 000000000000..8fb49986418a
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_gp.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include <drm/lima_drm.h>
+
+#include "lima_device.h"
+#include "lima_gp.h"
+#include "lima_regs.h"
+
+#define gp_write(reg, data) writel(data, ip->iomem + LIMA_GP_##reg)
+#define gp_read(reg) readl(ip->iomem + LIMA_GP_##reg)
+
+static irqreturn_t lima_gp_irq_handler(int irq, void *data)
+{
+ struct lima_ip *ip = data;
+ struct lima_device *dev = ip->dev;
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
+ u32 state = gp_read(INT_STAT);
+ u32 status = gp_read(STATUS);
+ bool done = false;
+
+ /* for shared irq case */
+ if (!state)
+ return IRQ_NONE;
+
+ if (state & LIMA_GP_IRQ_MASK_ERROR) {
+ dev_err(dev->dev, "gp error irq state=%x status=%x\n",
+ state, status);
+
+ /* mask all interrupts before hard reset */
+ gp_write(INT_MASK, 0);
+
+ pipe->error = true;
+ done = true;
+ }
+ else {
+ bool valid = state & (LIMA_GP_IRQ_VS_END_CMD_LST |
+ LIMA_GP_IRQ_PLBU_END_CMD_LST);
+ bool active = status & (LIMA_GP_STATUS_VS_ACTIVE |
+ LIMA_GP_STATUS_PLBU_ACTIVE);
+ done = valid && !active;
+ }
+
+ gp_write(INT_CLEAR, state);
+
+ if (done)
+ lima_sched_pipe_task_done(pipe);
+
+ return IRQ_HANDLED;
+}
+
+static void lima_gp_soft_reset_async(struct lima_ip *ip)
+{
+ if (ip->data.async_reset)
+ return;
+
+ gp_write(INT_MASK, 0);
+ gp_write(INT_CLEAR, LIMA_GP_IRQ_RESET_COMPLETED);
+ gp_write(CMD, LIMA_GP_CMD_SOFT_RESET);
+ ip->data.async_reset = true;
+}
+
+static int lima_gp_soft_reset_async_wait(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int timeout;
+
+ if (!ip->data.async_reset)
+ return 0;
+
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (gp_read(INT_RAWSTAT) & LIMA_GP_IRQ_RESET_COMPLETED)
+ break;
+ }
+ if (!timeout) {
+ dev_err(dev->dev, "gp soft reset time out\n");
+ return -ETIMEDOUT;
+ }
+
+ gp_write(INT_CLEAR, LIMA_GP_IRQ_MASK_ALL);
+ gp_write(INT_MASK, LIMA_GP_IRQ_MASK_USED);
+
+ ip->data.async_reset = false;
+ return 0;
+}
+
+static int lima_gp_task_validate(struct lima_sched_pipe *pipe,
+ struct lima_sched_task *task)
+{
+ struct drm_lima_gp_frame *frame = task->frame;
+ u32 *f = frame->frame;
+ (void)pipe;
+
+ if (f[LIMA_GP_VSCL_START_ADDR >> 2] >
+ f[LIMA_GP_VSCL_END_ADDR >> 2] ||
+ f[LIMA_GP_PLBUCL_START_ADDR >> 2] >
+ f[LIMA_GP_PLBUCL_END_ADDR >> 2] ||
+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] >
+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2])
+ return -EINVAL;
+
+ if (f[LIMA_GP_VSCL_START_ADDR >> 2] ==
+ f[LIMA_GP_VSCL_END_ADDR >> 2] &&
+ f[LIMA_GP_PLBUCL_START_ADDR >> 2] ==
+ f[LIMA_GP_PLBUCL_END_ADDR >> 2])
+ return -EINVAL;
+
+ return 0;
+}
+
+static void lima_gp_task_run(struct lima_sched_pipe *pipe,
+ struct lima_sched_task *task)
+{
+ struct lima_ip *ip = pipe->processor[0];
+ struct drm_lima_gp_frame *frame = task->frame;
+ u32 *f = frame->frame;
+ u32 cmd = 0;
+ int i;
+
+ if (f[LIMA_GP_VSCL_START_ADDR >> 2] !=
+ f[LIMA_GP_VSCL_END_ADDR >> 2])
+ cmd |= LIMA_GP_CMD_START_VS;
+ if (f[LIMA_GP_PLBUCL_START_ADDR >> 2] !=
+ f[LIMA_GP_PLBUCL_END_ADDR >> 2])
+ cmd |= LIMA_GP_CMD_START_PLBU;
+
+ /* before any hw ops, wait last success task async soft reset */
+ lima_gp_soft_reset_async_wait(ip);
+
+ for (i = 0; i < LIMA_GP_FRAME_REG_NUM; i++)
+ writel(f[i], ip->iomem + LIMA_GP_VSCL_START_ADDR + i * 4);
+
+ gp_write(CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
+ gp_write(CMD, cmd);
+}
+
+static int lima_gp_hard_reset(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int timeout;
+
+ gp_write(PERF_CNT_0_LIMIT, 0xC0FFE000);
+ gp_write(INT_MASK, 0);
+ gp_write(CMD, LIMA_GP_CMD_RESET);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ gp_write(PERF_CNT_0_LIMIT, 0xC01A0000);
+ if (gp_read(PERF_CNT_0_LIMIT) == 0xC01A0000)
+ break;
+ }
+ if (!timeout) {
+ dev_err(dev->dev, "gp hard reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ gp_write(PERF_CNT_0_LIMIT, 0);
+ gp_write(INT_CLEAR, LIMA_GP_IRQ_MASK_ALL);
+ gp_write(INT_MASK, LIMA_GP_IRQ_MASK_USED);
+ return 0;
+}
+
+static void lima_gp_task_fini(struct lima_sched_pipe *pipe)
+{
+ lima_gp_soft_reset_async(pipe->processor[0]);
+}
+
+static void lima_gp_task_error(struct lima_sched_pipe *pipe)
+{
+ lima_gp_hard_reset(pipe->processor[0]);
+}
+
+static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe)
+{
+ lima_sched_pipe_task_done(pipe);
+}
+
+static void lima_gp_print_version(struct lima_ip *ip)
+{
+ u32 version, major, minor;
+ char *name;
+
+ version = gp_read(VERSION);
+ major = (version >> 8) & 0xFF;
+ minor = version & 0xFF;
+ switch (version >> 16) {
+ case 0xA07:
+ name = "mali200";
+ break;
+ case 0xC07:
+ name = "mali300";
+ break;
+ case 0xB07:
+ name = "mali400";
+ break;
+ case 0xD07:
+ name = "mali450";
+ break;
+ default:
+ name = "unknow";
+ break;
+ }
+ dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n",
+ lima_ip_name(ip), name, major, minor);
+}
+
+static struct kmem_cache *lima_gp_task_slab = NULL;
+static int lima_gp_task_slab_refcnt = 0;
+
+int lima_gp_init(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int err;
+
+ lima_gp_print_version(ip);
+
+ ip->data.async_reset = false;
+ lima_gp_soft_reset_async(ip);
+ err = lima_gp_soft_reset_async_wait(ip);
+ if (err)
+ return err;
+
+ err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler, 0,
+ lima_ip_name(ip), ip);
+ if (err) {
+ dev_err(dev->dev, "gp %s fail to request irq\n",
+ lima_ip_name(ip));
+ return err;
+ }
+
+ return 0;
+}
+
+void lima_gp_fini(struct lima_ip *ip)
+{
+
+}
+
+int lima_gp_pipe_init(struct lima_device *dev)
+{
+ int frame_size = sizeof(struct drm_lima_gp_frame);
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
+
+ if (!lima_gp_task_slab) {
+ lima_gp_task_slab = kmem_cache_create(
+ "lima_gp_task", sizeof(struct lima_sched_task) + frame_size,
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!lima_gp_task_slab)
+ return -ENOMEM;
+ }
+ lima_gp_task_slab_refcnt++;
+
+ pipe->frame_size = frame_size;
+ pipe->task_slab = lima_gp_task_slab;
+
+ pipe->task_validate = lima_gp_task_validate;
+ pipe->task_run = lima_gp_task_run;
+ pipe->task_fini = lima_gp_task_fini;
+ pipe->task_error = lima_gp_task_error;
+ pipe->task_mmu_error = lima_gp_task_mmu_error;
+
+ return 0;
+}
+
+void lima_gp_pipe_fini(struct lima_device *dev)
+{
+ if (!--lima_gp_task_slab_refcnt) {
+ kmem_cache_destroy(lima_gp_task_slab);
+ lima_gp_task_slab = NULL;
+ }
+}
diff --git a/drivers/gpu/drm/lima/lima_gp.h b/drivers/gpu/drm/lima/lima_gp.h
new file mode 100644
index 000000000000..8354911e50ce
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_gp.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_GP_H__
+#define __LIMA_GP_H__
+
+struct lima_ip;
+struct lima_device;
+
+int lima_gp_init(struct lima_ip *ip);
+void lima_gp_fini(struct lima_ip *ip);
+
+int lima_gp_pipe_init(struct lima_device *dev);
+void lima_gp_pipe_fini(struct lima_device *dev);
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v5 10/12] ARM: dts: imx7s-warp: add ov2680 sensor node
From: Rui Miguel Silva @ 2018-05-18 9:28 UTC (permalink / raw)
To: mchehab, sakari.ailus, Steve Longerbeam, Philipp Zabel,
Rob Herring
Cc: devel, devicetree, Greg Kroah-Hartman, Ryan Harkin,
Rui Miguel Silva, Fabio Estevam, Shawn Guo, linux-clk,
linux-media
In-Reply-To: <20180518092806.3829-1-rui.silva@linaro.org>
Warp7 comes with a Omnivision OV2680 sensor, add the node here to make complete
the camera data path for this system. Add the needed regulator to the analog
voltage supply, the port and endpoints in mipi_csi node and the pinctrl for the
reset gpio.
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
arch/arm/boot/dts/imx7s-warp.dts | 44 ++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/arch/arm/boot/dts/imx7s-warp.dts b/arch/arm/boot/dts/imx7s-warp.dts
index cb175ee2fc9d..bf04e13afd02 100644
--- a/arch/arm/boot/dts/imx7s-warp.dts
+++ b/arch/arm/boot/dts/imx7s-warp.dts
@@ -91,6 +91,14 @@
regulator-always-on;
};
+ reg_peri_3p15v: regulator-peri-3p15v {
+ compatible = "regulator-fixed";
+ regulator-name = "peri_3p15v_reg";
+ regulator-min-microvolt = <3150000>;
+ regulator-max-microvolt = <3150000>;
+ regulator-always-on;
+ };
+
sound {
compatible = "simple-audio-card";
simple-audio-card,name = "imx7-sgtl5000";
@@ -218,6 +226,27 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
+
+ ov2680: camera@36 {
+ compatible = "ovti,ov2680";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ov2680>;
+ reg = <0x36>;
+ clocks = <&osc>;
+ clock-names = "xvclk";
+ reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
+ DOVDD-supply = <&sw2_reg>;
+ DVDD-supply = <&sw2_reg>;
+ AVDD-supply = <®_peri_3p15v>;
+
+ port {
+ ov2680_to_mipi: endpoint {
+ remote-endpoint = <&mipi_from_sensor>;
+ clock-lanes = <0>;
+ data-lanes = <1>;
+ };
+ };
+ };
};
&i2c4 {
@@ -352,6 +381,15 @@
#size-cells = <0>;
fsl,csis-hs-settle = <3>;
+ port@0 {
+ reg = <0>;
+
+ mipi_from_sensor: endpoint {
+ remote-endpoint = <&ov2680_to_mipi>;
+ data-lanes = <1>;
+ };
+ };
+
port@1 {
reg = <1>;
@@ -408,6 +446,12 @@
>;
};
+ pinctrl_ov2680: ov2660grp {
+ fsl,pins = <
+ MX7D_PAD_LPSR_GPIO1_IO03__GPIO1_IO3 0x14
+ >;
+ };
+
pinctrl_sai1: sai1grp {
fsl,pins = <
MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0 0x1f
--
2.17.0
^ permalink raw reply related
* [PATCH RFC 13/24] drm/lima: add PP related functions
From: Qiang Yu @ 2018-05-18 9:28 UTC (permalink / raw)
To: dri-devel, devicetree
Cc: Simon Shields, Marek Vasut, Connor Abbott, Neil Armstrong,
Andrei Paulau, Vasily Khoruzhick, Qiang Yu, Erico Nunes
In-Reply-To: <20180518092815.25280-1-yuq825@gmail.com>
From: Lima Project Developers <dri-devel@lists.freedesktop.org>
PP is a processor used for OpenGL fragment shader
processing.
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/gpu/drm/lima/lima_pp.c | 418 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/lima/lima_pp.h | 37 +++
2 files changed, 455 insertions(+)
create mode 100644 drivers/gpu/drm/lima/lima_pp.c
create mode 100644 drivers/gpu/drm/lima/lima_pp.h
diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c
new file mode 100644
index 000000000000..371d6b70c271
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_pp.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include <drm/lima_drm.h>
+
+#include "lima_device.h"
+#include "lima_pp.h"
+#include "lima_dlbu.h"
+#include "lima_bcast.h"
+#include "lima_vm.h"
+#include "lima_regs.h"
+
+#define pp_write(reg, data) writel(data, ip->iomem + LIMA_PP_##reg)
+#define pp_read(reg) readl(ip->iomem + LIMA_PP_##reg)
+
+static void lima_pp_handle_irq(struct lima_ip *ip, u32 state)
+{
+ struct lima_device *dev = ip->dev;
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+
+ if (state & LIMA_PP_IRQ_MASK_ERROR) {
+ u32 status = pp_read(STATUS);
+
+ dev_err(dev->dev, "pp error irq state=%x status=%x\n",
+ state, status);
+
+ pipe->error = true;
+
+ /* mask all interrupts before hard reset */
+ pp_write(INT_MASK, 0);
+ }
+
+ pp_write(INT_CLEAR, state);
+}
+
+static irqreturn_t lima_pp_irq_handler(int irq, void *data)
+{
+ struct lima_ip *ip = data;
+ struct lima_device *dev = ip->dev;
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+ u32 state = pp_read(INT_STATUS);
+
+ /* for shared irq case */
+ if (!state)
+ return IRQ_NONE;
+
+ lima_pp_handle_irq(ip, state);
+
+ if (atomic_dec_and_test(&pipe->task))
+ lima_sched_pipe_task_done(pipe);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t lima_pp_bcast_irq_handler(int irq, void *data)
+{
+ int i;
+ irqreturn_t ret = IRQ_NONE;
+ struct lima_ip *pp_bcast = data;
+ struct lima_device *dev = pp_bcast->dev;
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+
+ for (i = 0; i < pipe->num_processor; i++) {
+ struct lima_ip *ip = pipe->processor[i];
+ u32 status, state;
+
+ if (pipe->done & (1 << i))
+ continue;
+
+ /* status read first in case int state change in the middle
+ * which may miss the interrupt handling */
+ status = pp_read(STATUS);
+ state = pp_read(INT_STATUS);
+
+ if (state) {
+ lima_pp_handle_irq(ip, state);
+ ret = IRQ_HANDLED;
+ }
+ else {
+ if (status & LIMA_PP_STATUS_RENDERING_ACTIVE)
+ continue;
+ }
+
+ pipe->done |= (1 << i);
+ if (atomic_dec_and_test(&pipe->task))
+ lima_sched_pipe_task_done(pipe);
+ }
+
+ return ret;
+}
+
+static void lima_pp_soft_reset_async(struct lima_ip *ip)
+{
+ if (ip->data.async_reset)
+ return;
+
+ pp_write(INT_MASK, 0);
+ pp_write(INT_RAWSTAT, LIMA_PP_IRQ_MASK_ALL);
+ pp_write(CTRL, LIMA_PP_CTRL_SOFT_RESET);
+ ip->data.async_reset = true;
+}
+
+static int lima_pp_soft_reset_async_wait_one(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int timeout;
+
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (!(pp_read(STATUS) & LIMA_PP_STATUS_RENDERING_ACTIVE) &&
+ pp_read(INT_RAWSTAT) == LIMA_PP_IRQ_RESET_COMPLETED)
+ break;
+ }
+ if (!timeout) {
+ dev_err(dev->dev, "pp %s reset time out\n", lima_ip_name(ip));
+ return -ETIMEDOUT;
+ }
+
+ pp_write(INT_CLEAR, LIMA_PP_IRQ_MASK_ALL);
+ pp_write(INT_MASK, LIMA_PP_IRQ_MASK_USED);
+ return 0;
+}
+
+static int lima_pp_soft_reset_async_wait(struct lima_ip *ip)
+{
+ int i, err = 0;
+
+ if (!ip->data.async_reset)
+ return 0;
+
+ if (ip->id == lima_ip_pp_bcast) {
+ struct lima_device *dev = ip->dev;
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+ for (i = 0; i < pipe->num_processor; i++)
+ err |= lima_pp_soft_reset_async_wait_one(pipe->processor[i]);
+ }
+ else
+ err = lima_pp_soft_reset_async_wait_one(ip);
+
+ ip->data.async_reset = false;
+ return err;
+}
+
+static void lima_pp_start_task(struct lima_ip *ip, u32 *frame, u32 *wb,
+ bool skip_stack_addr)
+{
+ int i, j, n = 0;
+
+ for (i = 0; i < LIMA_PP_FRAME_REG_NUM; i++) {
+ if (skip_stack_addr && i * 4 == LIMA_PP_STACK)
+ continue;
+
+ writel(frame[i], ip->iomem + LIMA_PP_FRAME + i * 4);
+ }
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < LIMA_PP_WB_REG_NUM; j++)
+ writel(wb[n++], ip->iomem + LIMA_PP_WB(i) + j * 4);
+ }
+
+ pp_write(CTRL, LIMA_PP_CTRL_START_RENDERING);
+}
+
+static int lima_pp_hard_reset(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int timeout;
+
+ pp_write(PERF_CNT_0_LIMIT, 0xC0FFE000);
+ pp_write(INT_MASK, 0);
+ pp_write(CTRL, LIMA_PP_CTRL_FORCE_RESET);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ pp_write(PERF_CNT_0_LIMIT, 0xC01A0000);
+ if (pp_read(PERF_CNT_0_LIMIT) == 0xC01A0000)
+ break;
+ }
+ if (!timeout) {
+ dev_err(dev->dev, "pp hard reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ pp_write(PERF_CNT_0_LIMIT, 0);
+ pp_write(INT_CLEAR, LIMA_PP_IRQ_MASK_ALL);
+ pp_write(INT_MASK, LIMA_PP_IRQ_MASK_USED);
+ return 0;
+}
+
+static void lima_pp_print_version(struct lima_ip *ip)
+{
+ u32 version, major, minor;
+ char *name;
+
+ version = pp_read(VERSION);
+ major = (version >> 8) & 0xFF;
+ minor = version & 0xFF;
+ switch (version >> 16) {
+ case 0xC807:
+ name = "mali200";
+ break;
+ case 0xCE07:
+ name = "mali300";
+ break;
+ case 0xCD07:
+ name = "mali400";
+ break;
+ case 0xCF07:
+ name = "mali450";
+ break;
+ default:
+ name = "unknow";
+ break;
+ }
+ dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n",
+ lima_ip_name(ip), name, major, minor);
+}
+
+int lima_pp_init(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int err;
+
+ lima_pp_print_version(ip);
+
+ ip->data.async_reset = false;
+ lima_pp_soft_reset_async(ip);
+ err = lima_pp_soft_reset_async_wait(ip);
+ if (err)
+ return err;
+
+ err = devm_request_irq(dev->dev, ip->irq, lima_pp_irq_handler,
+ IRQF_SHARED, lima_ip_name(ip), ip);
+ if (err) {
+ dev_err(dev->dev, "pp %s fail to request irq\n",
+ lima_ip_name(ip));
+ return err;
+ }
+
+ return 0;
+}
+
+void lima_pp_fini(struct lima_ip *ip)
+{
+
+}
+
+int lima_pp_bcast_init(struct lima_ip *ip)
+{
+ struct lima_device *dev = ip->dev;
+ int err;
+
+ err = devm_request_irq(dev->dev, ip->irq, lima_pp_bcast_irq_handler,
+ IRQF_SHARED, lima_ip_name(ip), ip);
+ if (err) {
+ dev_err(dev->dev, "pp %s fail to request irq\n",
+ lima_ip_name(ip));
+ return err;
+ }
+
+ return 0;
+}
+
+void lima_pp_bcast_fini(struct lima_ip *ip)
+{
+
+}
+
+static int lima_pp_task_validate(struct lima_sched_pipe *pipe,
+ struct lima_sched_task *task)
+{
+ if (!pipe->bcast_processor) {
+ struct drm_lima_m400_pp_frame *f = task->frame;
+
+ if (f->num_pp > pipe->num_processor)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void lima_pp_task_run(struct lima_sched_pipe *pipe,
+ struct lima_sched_task *task)
+{
+ if (pipe->bcast_processor) {
+ struct drm_lima_m450_pp_frame *frame = task->frame;
+ struct lima_device *dev = pipe->bcast_processor->dev;
+ int i;
+
+ pipe->done = 0;
+ atomic_set(&pipe->task, pipe->num_processor);
+
+ frame->frame[LIMA_PP_FRAME >> 2] = LIMA_VA_RESERVE_DLBU;
+ lima_dlbu_set_reg(dev->ip + lima_ip_dlbu, frame->dlbu_regs);
+
+ lima_pp_soft_reset_async_wait(pipe->bcast_processor);
+
+ for (i = 0; i < pipe->num_processor; i++) {
+ struct lima_ip *ip = pipe->processor[i];
+ pp_write(STACK, frame->fragment_stack_address[i]);
+ }
+
+ lima_pp_start_task(pipe->bcast_processor, frame->frame,
+ frame->wb, true);
+ }
+ else {
+ struct drm_lima_m400_pp_frame *frame = task->frame;
+ int i;
+
+ atomic_set(&pipe->task, frame->num_pp);
+
+ for (i = 0; i < frame->num_pp; i++) {
+ frame->frame[LIMA_PP_FRAME >> 2] =
+ frame->plbu_array_address[i];
+ frame->frame[LIMA_PP_STACK >> 2] =
+ frame->fragment_stack_address[i];
+
+ lima_pp_soft_reset_async_wait(pipe->processor[i]);
+
+ lima_pp_start_task(pipe->processor[i], frame->frame,
+ frame->wb, false);
+ }
+ }
+}
+
+static void lima_pp_task_fini(struct lima_sched_pipe *pipe)
+{
+ if (pipe->bcast_processor)
+ lima_pp_soft_reset_async(pipe->bcast_processor);
+ else {
+ int i;
+ for (i = 0; i < pipe->num_processor; i++)
+ lima_pp_soft_reset_async(pipe->processor[i]);
+ }
+}
+
+static void lima_pp_task_error(struct lima_sched_pipe *pipe)
+{
+ int i;
+
+ if (pipe->bcast_processor)
+ lima_bcast_disable(pipe->bcast_processor->dev);
+
+ for (i = 0; i < pipe->num_processor; i++)
+ lima_pp_hard_reset(pipe->processor[i]);
+
+ if (pipe->bcast_processor)
+ lima_bcast_enable(pipe->bcast_processor->dev);
+}
+
+static void lima_pp_task_mmu_error(struct lima_sched_pipe *pipe)
+{
+ if (atomic_dec_and_test(&pipe->task))
+ lima_sched_pipe_task_done(pipe);
+}
+
+static struct kmem_cache *lima_pp_task_slab = NULL;
+static int lima_pp_task_slab_refcnt = 0;
+
+int lima_pp_pipe_init(struct lima_device *dev)
+{
+ int frame_size;
+ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp;
+
+ if (dev->id == lima_gpu_mali400)
+ frame_size = sizeof(struct drm_lima_m400_pp_frame);
+ else
+ frame_size = sizeof(struct drm_lima_m450_pp_frame);
+
+ if (!lima_pp_task_slab) {
+ lima_pp_task_slab = kmem_cache_create(
+ "lima_pp_task", sizeof(struct lima_sched_task) + frame_size,
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!lima_pp_task_slab)
+ return -ENOMEM;
+ }
+ lima_pp_task_slab_refcnt++;
+
+ pipe->frame_size = frame_size;
+ pipe->task_slab = lima_pp_task_slab;
+
+ pipe->task_validate = lima_pp_task_validate;
+ pipe->task_run = lima_pp_task_run;
+ pipe->task_fini = lima_pp_task_fini;
+ pipe->task_error = lima_pp_task_error;
+ pipe->task_mmu_error = lima_pp_task_mmu_error;
+
+ return 0;
+}
+
+void lima_pp_pipe_fini(struct lima_device *dev)
+{
+ if (!--lima_pp_task_slab_refcnt) {
+ kmem_cache_destroy(lima_pp_task_slab);
+ lima_pp_task_slab = NULL;
+ }
+}
diff --git a/drivers/gpu/drm/lima/lima_pp.h b/drivers/gpu/drm/lima/lima_pp.h
new file mode 100644
index 000000000000..4bd1d9fcbcdf
--- /dev/null
+++ b/drivers/gpu/drm/lima/lima_pp.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017-2018 Lima Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIMA_PP_H__
+#define __LIMA_PP_H__
+
+struct lima_ip;
+struct lima_device;
+
+int lima_pp_init(struct lima_ip *ip);
+void lima_pp_fini(struct lima_ip *ip);
+
+int lima_pp_bcast_init(struct lima_ip *ip);
+void lima_pp_bcast_fini(struct lima_ip *ip);
+
+int lima_pp_pipe_init(struct lima_device *dev);
+void lima_pp_pipe_fini(struct lima_device *dev);
+
+#endif
--
2.17.0
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox