Merge branch 'imx-drm-staging' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into staging-next
Russell writes:
This set of changes reorganises imx-drm's DT bindings by re-using the OF
graph parsing code which was located in drivers/media, removing the
temporary bindings.
The result is that more TODO entries are now removed. While we're not
quite done with this yet as there's a few straggling updates to imx-ldb
to come, but leaving these out is not detrimental at this point in time
- they are more an enhancement.
However, this pull has the additional complication that we're sharing
seven commits with Mauro's V4L git tree, which move the OF graph parsing
code out of drivers/media into drivers/of. Philipp's imx-drm changes
depend on these and my previously committed round of imx-drm commits.
Hence, the diffstat below is from a test merge with your tree head
(17b02809cf
).
Mauro merged those seven commits earlier today as a git pull, so both
trees will be sharing exactly the same commit IDs.
I've given these changes a spin here on both my Hummingboard and Cubox-i4
(one is iMX6Solo, the other is iMX6Quad based), which includes Xorg using
the DRM device directly, and I find nothing wrong.
The diffstat does look a little scarey - this is because we're having to
update the ARM DT files along with this change, and obviously the
dependency on the OF graph parsing code.
This commit is contained in:
commit
bfe24b9cbe
35 changed files with 1087 additions and 336 deletions
129
Documentation/devicetree/bindings/graph.txt
Normal file
129
Documentation/devicetree/bindings/graph.txt
Normal file
|
@ -0,0 +1,129 @@
|
|||
Common bindings for device graphs
|
||||
|
||||
General concept
|
||||
---------------
|
||||
|
||||
The hierarchical organisation of the device tree is well suited to describe
|
||||
control flow to devices, but there can be more complex connections between
|
||||
devices that work together to form a logical compound device, following an
|
||||
arbitrarily complex graph.
|
||||
There already is a simple directed graph between devices tree nodes using
|
||||
phandle properties pointing to other nodes to describe connections that
|
||||
can not be inferred from device tree parent-child relationships. The device
|
||||
tree graph bindings described herein abstract more complex devices that can
|
||||
have multiple specifiable ports, each of which can be linked to one or more
|
||||
ports of other devices.
|
||||
|
||||
These common bindings do not contain any information about the direction or
|
||||
type of the connections, they just map their existence. Specific properties
|
||||
may be described by specialized bindings depending on the type of connection.
|
||||
|
||||
To see how this binding applies to video pipelines, for example, see
|
||||
Documentation/device-tree/bindings/media/video-interfaces.txt.
|
||||
Here the ports describe data interfaces, and the links between them are
|
||||
the connecting data buses. A single port with multiple connections can
|
||||
correspond to multiple devices being connected to the same physical bus.
|
||||
|
||||
Organisation of ports and endpoints
|
||||
-----------------------------------
|
||||
|
||||
Ports are described by child 'port' nodes contained in the device node.
|
||||
Each port node contains an 'endpoint' subnode for each remote device port
|
||||
connected to this port. If a single port is connected to more than one
|
||||
remote device, an 'endpoint' child node must be provided for each link.
|
||||
If more than one port is present in a device node or there is more than one
|
||||
endpoint at a port, or a port node needs to be associated with a selected
|
||||
hardware interface, a common scheme using '#address-cells', '#size-cells'
|
||||
and 'reg' properties is used number the nodes.
|
||||
|
||||
device {
|
||||
...
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
endpoint@0 {
|
||||
reg = <0>;
|
||||
...
|
||||
};
|
||||
endpoint@1 {
|
||||
reg = <1>;
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
endpoint { ... };
|
||||
};
|
||||
};
|
||||
|
||||
All 'port' nodes can be grouped under an optional 'ports' node, which
|
||||
allows to specify #address-cells, #size-cells properties for the 'port'
|
||||
nodes independently from any other child device nodes a device might
|
||||
have.
|
||||
|
||||
device {
|
||||
...
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
...
|
||||
endpoint@0 { ... };
|
||||
endpoint@1 { ... };
|
||||
};
|
||||
|
||||
port@1 { ... };
|
||||
};
|
||||
};
|
||||
|
||||
Links between endpoints
|
||||
-----------------------
|
||||
|
||||
Each endpoint should contain a 'remote-endpoint' phandle property that points
|
||||
to the corresponding endpoint in the port of the remote device. In turn, the
|
||||
remote endpoint should contain a 'remote-endpoint' property. If it has one,
|
||||
it must not point to another than the local endpoint. Two endpoints with their
|
||||
'remote-endpoint' phandles pointing at each other form a link between the
|
||||
containing ports.
|
||||
|
||||
device-1 {
|
||||
port {
|
||||
device_1_output: endpoint {
|
||||
remote-endpoint = <&device_2_input>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
device-2 {
|
||||
port {
|
||||
device_2_input: endpoint {
|
||||
remote-endpoint = <&device_1_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
|
||||
If there is more than one 'port' or more than one 'endpoint' node or 'reg'
|
||||
property is present in port and/or endpoint nodes the following properties
|
||||
are required in a relevant parent node:
|
||||
|
||||
- #address-cells : number of cells required to define port/endpoint
|
||||
identifier, should be 1.
|
||||
- #size-cells : should be zero.
|
||||
|
||||
Optional endpoint properties
|
||||
----------------------------
|
||||
|
||||
- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node.
|
||||
|
|
@ -1,3 +1,22 @@
|
|||
Freescale i.MX DRM master device
|
||||
================================
|
||||
|
||||
The freescale i.MX DRM master device is a virtual device needed to list all
|
||||
IPU or other display interface nodes that comprise the graphics subsystem.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx-display-subsystem"
|
||||
- ports: Should contain a list of phandles pointing to display interface ports
|
||||
of IPU devices
|
||||
|
||||
example:
|
||||
|
||||
display-subsystem {
|
||||
compatible = "fsl,display-subsystem";
|
||||
ports = <&ipu_di0>;
|
||||
};
|
||||
|
||||
|
||||
Freescale i.MX IPUv3
|
||||
====================
|
||||
|
||||
|
@ -7,18 +26,31 @@ Required properties:
|
|||
datasheet
|
||||
- interrupts: Should contain sync interrupt and error interrupt,
|
||||
in this order.
|
||||
- #crtc-cells: 1, See below
|
||||
- resets: phandle pointing to the system reset controller and
|
||||
reset line index, see reset/fsl,imx-src.txt for details
|
||||
Optional properties:
|
||||
- port@[0-3]: Port nodes with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
Ports 0 and 1 should correspond to CSI0 and CSI1,
|
||||
ports 2 and 3 should correspond to DI0 and DI1, respectively.
|
||||
|
||||
example:
|
||||
|
||||
ipu: ipu@18000000 {
|
||||
#crtc-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx53-ipu";
|
||||
reg = <0x18000000 0x080000000>;
|
||||
interrupts = <11 10>;
|
||||
resets = <&src 2>;
|
||||
|
||||
ipu_di0: port@2 {
|
||||
reg = <2>;
|
||||
|
||||
ipu_di0_disp0: endpoint {
|
||||
remote-endpoint = <&display_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Parallel display support
|
||||
|
@ -26,19 +58,25 @@ Parallel display support
|
|||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx-parallel-display"
|
||||
- crtc: the crtc this display is connected to, see below
|
||||
Optional properties:
|
||||
- interface_pix_fmt: How this display is connected to the
|
||||
crtc. Currently supported types: "rgb24", "rgb565", "bgr666"
|
||||
display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
|
||||
- edid: verbatim EDID data block describing attached display.
|
||||
- ddc: phandle describing the i2c bus handling the display data
|
||||
channel
|
||||
- port: A port node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
example:
|
||||
|
||||
display@di0 {
|
||||
compatible = "fsl,imx-parallel-display";
|
||||
edid = [edid-data];
|
||||
crtc = <&ipu 0>;
|
||||
interface-pix-fmt = "rgb24";
|
||||
|
||||
port {
|
||||
display_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_disp0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
58
Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
Normal file
58
Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
Device-Tree bindings for HDMI Transmitter
|
||||
|
||||
HDMI Transmitter
|
||||
================
|
||||
|
||||
The HDMI Transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with accompanying PHY IP.
|
||||
|
||||
Required properties:
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
- compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
|
||||
- gpr : should be <&gpr>.
|
||||
The phandle points to the iomuxc-gpr region containing the HDMI
|
||||
multiplexer control register.
|
||||
- clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
|
||||
in Documentation/devicetree/bindings/clock/clock-bindings.txt and
|
||||
Documentation/devicetree/bindings/clock/imx6q-clock.txt.
|
||||
- port@[0-4]: Up to four port nodes with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt,
|
||||
corresponding to the four inputs to the HDMI multiplexer.
|
||||
|
||||
Optional properties:
|
||||
- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
|
||||
|
||||
example:
|
||||
|
||||
gpr: iomuxc-gpr@020e0000 {
|
||||
/* ... */
|
||||
};
|
||||
|
||||
hdmi: hdmi@0120000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx6q-hdmi";
|
||||
reg = <0x00120000 0x9000>;
|
||||
interrupts = <0 115 0x04>;
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks 123>, <&clks 124>;
|
||||
clock-names = "iahb", "isfr";
|
||||
ddc-i2c-bus = <&i2c2>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -50,12 +50,14 @@ have a look at Documentation/devicetree/bindings/video/display-timing.txt.
|
|||
|
||||
Required properties:
|
||||
- reg : should be <0> or <1>
|
||||
- crtcs : a list of phandles with index pointing to the IPU display interfaces
|
||||
that can be used as video source for this channel.
|
||||
- fsl,data-mapping : should be "spwg" or "jeida"
|
||||
This describes how the color bits are laid out in the
|
||||
serialized LVDS signal.
|
||||
- fsl,data-width : should be <18> or <24>
|
||||
- port: A port node with endpoint definitions as defined in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
On i.MX6, there should be four ports (port@[0-3]) that correspond
|
||||
to the four LVDS multiplexer inputs.
|
||||
|
||||
example:
|
||||
|
||||
|
@ -77,23 +79,33 @@ ldb: ldb@53fa8008 {
|
|||
|
||||
lvds-channel@0 {
|
||||
reg = <0>;
|
||||
crtcs = <&ipu 0>;
|
||||
fsl,data-mapping = "spwg";
|
||||
fsl,data-width = <24>;
|
||||
|
||||
display-timings {
|
||||
/* ... */
|
||||
};
|
||||
|
||||
port {
|
||||
lvds0_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_lvds0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
lvds-channel@1 {
|
||||
reg = <1>;
|
||||
crtcs = <&ipu 1>;
|
||||
fsl,data-mapping = "spwg";
|
||||
fsl,data-width = <24>;
|
||||
|
||||
display-timings {
|
||||
/* ... */
|
||||
};
|
||||
|
||||
port {
|
||||
lvds1_in: endpoint {
|
||||
remote-endpoint = <&ipu_di1_lvds1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
display@di1 {
|
||||
compatible = "fsl,imx-parallel-display";
|
||||
crtcs = <&ipu 0>;
|
||||
interface-pix-fmt = "bgr666";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ipu_disp1_1>;
|
||||
|
@ -41,6 +40,12 @@
|
|||
pixelclk-active = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
port {
|
||||
display_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_disp0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
|
@ -122,3 +127,7 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ipu_di0_disp0 {
|
||||
remote-endpoint = <&display_in>;
|
||||
};
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
display0: display@di0 {
|
||||
compatible = "fsl,imx-parallel-display";
|
||||
crtcs = <&ipu 0>;
|
||||
interface-pix-fmt = "rgb24";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ipu_disp1_1>;
|
||||
|
@ -41,11 +40,16 @@
|
|||
vsync-len = <10>;
|
||||
};
|
||||
};
|
||||
|
||||
port {
|
||||
display0_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_disp0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
display1: display@di1 {
|
||||
compatible = "fsl,imx-parallel-display";
|
||||
crtcs = <&ipu 1>;
|
||||
interface-pix-fmt = "rgb565";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ipu_disp2_1>;
|
||||
|
@ -68,6 +72,12 @@
|
|||
pixelclk-active = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
port {
|
||||
display1_in: endpoint {
|
||||
remote-endpoint = <&ipu_di1_disp1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
|
@ -81,12 +91,6 @@
|
|||
};
|
||||
};
|
||||
|
||||
imx-drm {
|
||||
compatible = "fsl,imx-drm";
|
||||
crtcs = <&ipu 0>, <&ipu 1>;
|
||||
connectors = <&display0>, <&display1>;
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "fsl,imx51-babbage-sgtl5000",
|
||||
"fsl,imx-audio-sgtl5000";
|
||||
|
@ -264,6 +268,14 @@
|
|||
};
|
||||
};
|
||||
|
||||
&ipu_di0_disp0 {
|
||||
remote-endpoint = <&display0_in>;
|
||||
};
|
||||
|
||||
&ipu_di1_disp1 {
|
||||
remote-endpoint = <&display1_in>;
|
||||
};
|
||||
|
||||
&ssi2 {
|
||||
fsl,mode = "i2s-slave";
|
||||
status = "okay";
|
||||
|
|
|
@ -79,6 +79,11 @@
|
|||
};
|
||||
};
|
||||
|
||||
display-subsystem {
|
||||
compatible = "fsl,imx-display-subsystem";
|
||||
ports = <&ipu_di0>, <&ipu_di1>;
|
||||
};
|
||||
|
||||
soc {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
@ -92,13 +97,28 @@
|
|||
};
|
||||
|
||||
ipu: ipu@40000000 {
|
||||
#crtc-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx51-ipu";
|
||||
reg = <0x40000000 0x20000000>;
|
||||
interrupts = <11 10>;
|
||||
clocks = <&clks 59>, <&clks 110>, <&clks 61>;
|
||||
clock-names = "bus", "di0", "di1";
|
||||
resets = <&src 2>;
|
||||
|
||||
ipu_di0: port@2 {
|
||||
reg = <2>;
|
||||
|
||||
ipu_di0_disp0: endpoint {
|
||||
};
|
||||
};
|
||||
|
||||
ipu_di1: port@3 {
|
||||
reg = <3>;
|
||||
|
||||
ipu_di1_disp1: endpoint {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
aips@70000000 { /* AIPS1 */
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
soc {
|
||||
display1: display@di1 {
|
||||
compatible = "fsl,imx-parallel-display";
|
||||
crtcs = <&ipu 1>;
|
||||
interface-pix-fmt = "bgr666";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ipu_disp2_1>;
|
||||
|
@ -44,6 +43,12 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
port {
|
||||
display1_in: endpoint {
|
||||
remote-endpoint = <&ipu_di1_disp1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
backlight {
|
||||
|
@ -53,12 +58,6 @@
|
|||
default-brightness-level = <6>;
|
||||
};
|
||||
|
||||
imx-drm {
|
||||
compatible = "fsl,imx-drm";
|
||||
crtcs = <&ipu 1>;
|
||||
connectors = <&display1>;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
pinctrl-names = "default";
|
||||
|
@ -227,6 +226,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
&ipu_di1_disp1 {
|
||||
remote-endpoint = <&display1_in>;
|
||||
};
|
||||
|
||||
&nfc {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_nand_1>;
|
||||
|
|
|
@ -38,15 +38,14 @@
|
|||
compatible = "fsl,imx-parallel-display";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_disp1_1>;
|
||||
crtcs = <&ipu 1>;
|
||||
interface-pix-fmt = "rgb24";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
imx-drm {
|
||||
compatible = "fsl,imx-drm";
|
||||
crtcs = <&ipu 1>;
|
||||
connectors = <&disp1>, <&tve>;
|
||||
port {
|
||||
display1_in: endpoint {
|
||||
remote-endpoint = <&ipu_di1_disp1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
reg_3p2v: 3p2v {
|
||||
|
@ -147,6 +146,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
&ipu_di1_disp1 {
|
||||
remote-endpoint = <&display1_in>;
|
||||
};
|
||||
|
||||
&cspi {
|
||||
status = "okay";
|
||||
};
|
||||
|
@ -234,7 +237,7 @@
|
|||
&tve {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_vga_sync_1>;
|
||||
ddc = <&i2c3>;
|
||||
i2c-ddc-bus = <&i2c3>;
|
||||
fsl,tve-mode = "vga";
|
||||
fsl,hsync-pin = <4>;
|
||||
fsl,vsync-pin = <6>;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
display0: display@di0 {
|
||||
compatible = "fsl,imx-parallel-display";
|
||||
crtcs = <&ipu 0>;
|
||||
interface-pix-fmt = "rgb565";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ipu_disp0_1>;
|
||||
|
@ -46,6 +45,12 @@
|
|||
pixelclk-active = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
port {
|
||||
display0_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_disp0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
|
@ -72,12 +77,6 @@
|
|||
};
|
||||
};
|
||||
|
||||
imx-drm {
|
||||
compatible = "fsl,imx-drm";
|
||||
crtcs = <&ipu 0>;
|
||||
connectors = <&display0>;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
pinctrl-names = "default";
|
||||
|
@ -132,6 +131,10 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&ipu_di0_disp0 {
|
||||
remote-endpoint = <&display0_in>;
|
||||
};
|
||||
|
||||
&ssi2 {
|
||||
fsl,mode = "i2s-slave";
|
||||
status = "okay";
|
||||
|
|
|
@ -45,6 +45,11 @@
|
|||
};
|
||||
};
|
||||
|
||||
display-subsystem {
|
||||
compatible = "fsl,imx-display-subsystem";
|
||||
ports = <&ipu_di0>, <&ipu_di1>;
|
||||
};
|
||||
|
||||
tzic: tz-interrupt-controller@0fffc000 {
|
||||
compatible = "fsl,imx53-tzic", "fsl,tzic";
|
||||
interrupt-controller;
|
||||
|
@ -85,13 +90,49 @@
|
|||
ranges;
|
||||
|
||||
ipu: ipu@18000000 {
|
||||
#crtc-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx53-ipu";
|
||||
reg = <0x18000000 0x080000000>;
|
||||
interrupts = <11 10>;
|
||||
clocks = <&clks 59>, <&clks 110>, <&clks 61>;
|
||||
clock-names = "bus", "di0", "di1";
|
||||
resets = <&src 2>;
|
||||
|
||||
ipu_di0: port@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
|
||||
ipu_di0_disp0: endpoint@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
ipu_di0_lvds0: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&lvds0_in>;
|
||||
};
|
||||
};
|
||||
|
||||
ipu_di1: port@3 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <3>;
|
||||
|
||||
ipu_di1_disp1: endpoint@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
ipu_di1_lvds1: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&lvds1_in>;
|
||||
};
|
||||
|
||||
ipu_di1_tve: endpoint@2 {
|
||||
reg = <2>;
|
||||
remote-endpoint = <&tve_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
aips@50000000 { /* AIPS1 */
|
||||
|
@ -838,14 +879,24 @@
|
|||
|
||||
lvds-channel@0 {
|
||||
reg = <0>;
|
||||
crtcs = <&ipu 0>;
|
||||
status = "disabled";
|
||||
|
||||
port {
|
||||
lvds0_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_lvds0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
lvds-channel@1 {
|
||||
reg = <1>;
|
||||
crtcs = <&ipu 1>;
|
||||
status = "disabled";
|
||||
|
||||
port {
|
||||
lvds1_in: endpoint {
|
||||
remote-endpoint = <&ipu_di0_lvds0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1103,8 +1154,13 @@
|
|||
interrupts = <92>;
|
||||
clocks = <&clks 69>, <&clks 116>;
|
||||
clock-names = "tve", "di_sel";
|
||||
crtcs = <&ipu 1>;
|
||||
status = "disabled";
|
||||
|
||||
port {
|
||||
tve_in: endpoint {
|
||||
remote-endpoint = <&ipu_di1_tve>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
vpu: vpu@63ff4000 {
|
||||
|
|
|
@ -70,6 +70,15 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
display-subsystem {
|
||||
compatible = "fsl,imx-display-subsystem";
|
||||
ports = <&ipu1_di0>, <&ipu1_di1>;
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi {
|
||||
compatible = "fsl,imx6dl-hdmi";
|
||||
};
|
||||
|
||||
&ldb {
|
||||
|
@ -79,17 +88,4 @@
|
|||
clock-names = "di0_pll", "di1_pll",
|
||||
"di0_sel", "di1_sel",
|
||||
"di0", "di1";
|
||||
|
||||
lvds-channel@0 {
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>;
|
||||
};
|
||||
|
||||
lvds-channel@1 {
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>;
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi {
|
||||
compatible = "fsl,imx6dl-hdmi";
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>;
|
||||
};
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
compatible = "fsl,imx6q-sabresd", "fsl,imx6q";
|
||||
};
|
||||
|
||||
&imx_drm {
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
|
||||
};
|
||||
|
||||
&sata {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -132,13 +132,84 @@
|
|||
};
|
||||
|
||||
ipu2: ipu@02800000 {
|
||||
#crtc-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx6q-ipu";
|
||||
reg = <0x02800000 0x400000>;
|
||||
interrupts = <0 8 0x4 0 7 0x4>;
|
||||
clocks = <&clks 133>, <&clks 134>, <&clks 137>;
|
||||
clock-names = "bus", "di0", "di1";
|
||||
resets = <&src 4>;
|
||||
|
||||
ipu2_di0: port@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
|
||||
ipu2_di0_disp0: endpoint@0 {
|
||||
};
|
||||
|
||||
ipu2_di0_hdmi: endpoint@1 {
|
||||
remote-endpoint = <&hdmi_mux_2>;
|
||||
};
|
||||
|
||||
ipu2_di0_mipi: endpoint@2 {
|
||||
};
|
||||
|
||||
ipu2_di0_lvds0: endpoint@3 {
|
||||
remote-endpoint = <&lvds0_mux_2>;
|
||||
};
|
||||
|
||||
ipu2_di0_lvds1: endpoint@4 {
|
||||
remote-endpoint = <&lvds1_mux_2>;
|
||||
};
|
||||
};
|
||||
|
||||
ipu2_di1: port@3 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <3>;
|
||||
|
||||
ipu2_di1_hdmi: endpoint@1 {
|
||||
remote-endpoint = <&hdmi_mux_3>;
|
||||
};
|
||||
|
||||
ipu2_di1_mipi: endpoint@2 {
|
||||
};
|
||||
|
||||
ipu2_di1_lvds0: endpoint@3 {
|
||||
remote-endpoint = <&lvds0_mux_3>;
|
||||
};
|
||||
|
||||
ipu2_di1_lvds1: endpoint@4 {
|
||||
remote-endpoint = <&lvds1_mux_3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
display-subsystem {
|
||||
compatible = "fsl,imx-display-subsystem";
|
||||
ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>;
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi {
|
||||
compatible = "fsl,imx6q-hdmi";
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
hdmi_mux_2: endpoint {
|
||||
remote-endpoint = <&ipu2_di0_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
|
||||
hdmi_mux_3: endpoint {
|
||||
remote-endpoint = <&ipu2_di1_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -152,15 +223,56 @@
|
|||
"di0", "di1";
|
||||
|
||||
lvds-channel@0 {
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
lvds0_mux_2: endpoint {
|
||||
remote-endpoint = <&ipu2_di0_lvds0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
|
||||
lvds0_mux_3: endpoint {
|
||||
remote-endpoint = <&ipu2_di1_lvds0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
lvds-channel@1 {
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
lvds1_mux_2: endpoint {
|
||||
remote-endpoint = <&ipu2_di0_lvds1>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
|
||||
lvds1_mux_3: endpoint {
|
||||
remote-endpoint = <&ipu2_di1_lvds1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi {
|
||||
compatible = "fsl,imx6q-hdmi";
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
|
||||
&mipi_dsi {
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
mipi_mux_2: endpoint {
|
||||
remote-endpoint = <&ipu2_di0_mipi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
|
||||
mipi_mux_3: endpoint {
|
||||
remote-endpoint = <&ipu2_di1_mipi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -62,12 +62,6 @@
|
|||
};
|
||||
};
|
||||
|
||||
imx_drm: imx-drm {
|
||||
compatible = "fsl,imx-drm";
|
||||
crtcs = <&ipu1 0>, <&ipu1 1>;
|
||||
connectors = <&ldb>;
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "fsl,imx6q-sabresd-wm8962",
|
||||
"fsl,imx-audio-wm8962";
|
||||
|
|
|
@ -1358,23 +1358,77 @@
|
|||
status = "disabled";
|
||||
|
||||
lvds-channel@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
status = "disabled";
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds0_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_lvds0>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds0_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_lvds0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
lvds-channel@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <1>;
|
||||
status = "disabled";
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
lvds1_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_lvds1>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
lvds1_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_lvds1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hdmi: hdmi@0120000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x00120000 0x9000>;
|
||||
interrupts = <0 115 0x04>;
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks 123>, <&clks 124>;
|
||||
clock-names = "iahb", "isfr";
|
||||
status = "disabled";
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dcic1: dcic@020e4000 {
|
||||
|
@ -1588,8 +1642,27 @@
|
|||
reg = <0x021dc000 0x4000>;
|
||||
};
|
||||
|
||||
mipi@021e0000 { /* MIPI-DSI */
|
||||
mipi_dsi: mipi@021e0000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x021e0000 0x4000>;
|
||||
status = "disabled";
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
mipi_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_mipi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
mipi_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_mipi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
vdoa@021e4000 {
|
||||
|
@ -1643,13 +1716,64 @@
|
|||
};
|
||||
|
||||
ipu1: ipu@02400000 {
|
||||
#crtc-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx6q-ipu";
|
||||
reg = <0x02400000 0x400000>;
|
||||
interrupts = <0 6 0x4 0 5 0x4>;
|
||||
clocks = <&clks 130>, <&clks 131>, <&clks 132>;
|
||||
clock-names = "bus", "di0", "di1";
|
||||
resets = <&src 2>;
|
||||
|
||||
ipu1_di0: port@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
|
||||
ipu1_di0_disp0: endpoint@0 {
|
||||
};
|
||||
|
||||
ipu1_di0_hdmi: endpoint@1 {
|
||||
remote-endpoint = <&hdmi_mux_0>;
|
||||
};
|
||||
|
||||
ipu1_di0_mipi: endpoint@2 {
|
||||
remote-endpoint = <&mipi_mux_0>;
|
||||
};
|
||||
|
||||
ipu1_di0_lvds0: endpoint@3 {
|
||||
remote-endpoint = <&lvds0_mux_0>;
|
||||
};
|
||||
|
||||
ipu1_di0_lvds1: endpoint@4 {
|
||||
remote-endpoint = <&lvds1_mux_0>;
|
||||
};
|
||||
};
|
||||
|
||||
ipu1_di1: port@3 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <3>;
|
||||
|
||||
ipu1_di0_disp1: endpoint@0 {
|
||||
};
|
||||
|
||||
ipu1_di1_hdmi: endpoint@1 {
|
||||
remote-endpoint = <&hdmi_mux_1>;
|
||||
};
|
||||
|
||||
ipu1_di1_mipi: endpoint@2 {
|
||||
remote-endpoint = <&mipi_mux_1>;
|
||||
};
|
||||
|
||||
ipu1_di1_lvds0: endpoint@3 {
|
||||
remote-endpoint = <&lvds0_mux_1>;
|
||||
};
|
||||
|
||||
ipu1_di1_lvds1: endpoint@4 {
|
||||
remote-endpoint = <&lvds1_mux_1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <media/adv7343.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-of.h>
|
||||
|
||||
#include "adv7343_regs.h"
|
||||
|
||||
|
@ -410,7 +410,7 @@ adv7343_get_pdata(struct i2c_client *client)
|
|||
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
||||
return client->dev.platform_data;
|
||||
|
||||
np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
|
||||
np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -29,7 +30,6 @@
|
|||
#include <media/mt9p031.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-of.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "aptina-pll.h"
|
||||
|
@ -943,7 +943,7 @@ mt9p031_get_pdata(struct i2c_client *client)
|
|||
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
||||
return client->dev.platform_data;
|
||||
|
||||
np = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
|
||||
np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/media.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -1855,7 +1856,7 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
node_ep = v4l2_of_get_next_endpoint(node, NULL);
|
||||
node_ep = of_graph_get_next_endpoint(node, NULL);
|
||||
if (!node_ep) {
|
||||
dev_err(dev, "no endpoint defined at node %s\n",
|
||||
node->full_name);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/v4l2-mediabus.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
@ -1068,7 +1069,7 @@ tvp514x_get_pdata(struct i2c_client *client)
|
|||
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
||||
return client->dev.platform_data;
|
||||
|
||||
endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
|
||||
endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
|
||||
if (!endpoint)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
#include <media/tvp7002.h>
|
||||
#include <media/v4l2-async.h>
|
||||
|
@ -957,7 +958,7 @@ tvp7002_get_pdata(struct i2c_client *client)
|
|||
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
|
||||
return client->dev.platform_data;
|
||||
|
||||
endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
|
||||
endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
|
||||
if (!endpoint)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-of.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
|
||||
#include "media-dev.h"
|
||||
|
@ -167,10 +167,10 @@ static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor,
|
|||
u32 tmp = 0;
|
||||
int ret;
|
||||
|
||||
np = v4l2_of_get_next_endpoint(np, NULL);
|
||||
np = of_graph_get_next_endpoint(np, NULL);
|
||||
if (!np)
|
||||
return -ENXIO;
|
||||
np = v4l2_of_get_remote_port(np);
|
||||
np = of_graph_get_remote_port(np);
|
||||
if (!np)
|
||||
return -ENXIO;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -468,12 +469,12 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
|
|||
return 0;
|
||||
|
||||
v4l2_of_parse_endpoint(ep, &endpoint);
|
||||
if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS)
|
||||
if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS)
|
||||
return -EINVAL;
|
||||
|
||||
pd->mux_id = (endpoint.port - 1) & 0x1;
|
||||
pd->mux_id = (endpoint.base.port - 1) & 0x1;
|
||||
|
||||
rem = v4l2_of_get_remote_port_parent(ep);
|
||||
rem = of_graph_get_remote_port_parent(ep);
|
||||
of_node_put(ep);
|
||||
if (rem == NULL) {
|
||||
v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n",
|
||||
|
@ -493,13 +494,13 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fimc_input_is_parallel(endpoint.port)) {
|
||||
if (fimc_input_is_parallel(endpoint.base.port)) {
|
||||
if (endpoint.bus_type == V4L2_MBUS_PARALLEL)
|
||||
pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601;
|
||||
else
|
||||
pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656;
|
||||
pd->flags = endpoint.bus.parallel.flags;
|
||||
} else if (fimc_input_is_mipi_csi(endpoint.port)) {
|
||||
} else if (fimc_input_is_mipi_csi(endpoint.base.port)) {
|
||||
/*
|
||||
* MIPI CSI-2: only input mux selection and
|
||||
* the sensor's clock frequency is needed.
|
||||
|
@ -507,7 +508,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
|
|||
pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2;
|
||||
} else {
|
||||
v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n",
|
||||
endpoint.port, rem->full_name);
|
||||
endpoint.base.port, rem->full_name);
|
||||
}
|
||||
/*
|
||||
* For FIMC-IS handled sensors, that are placed under i2c-isp device
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/memory.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_data/mipi-csis.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -762,7 +763,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
|
|||
&state->max_num_lanes))
|
||||
return -EINVAL;
|
||||
|
||||
node = v4l2_of_get_next_endpoint(node, NULL);
|
||||
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);
|
||||
|
@ -771,7 +772,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
|
|||
/* Get port node and validate MIPI-CSI channel id. */
|
||||
v4l2_of_parse_endpoint(node, &endpoint);
|
||||
|
||||
state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0;
|
||||
state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
|
||||
if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
|
||||
return -ENXIO;
|
||||
|
||||
|
|
|
@ -127,17 +127,9 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
|
|||
int v4l2_of_parse_endpoint(const struct device_node *node,
|
||||
struct v4l2_of_endpoint *endpoint)
|
||||
{
|
||||
struct device_node *port_node = of_get_parent(node);
|
||||
|
||||
memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head));
|
||||
|
||||
endpoint->local_node = node;
|
||||
/*
|
||||
* It doesn't matter whether the two calls below succeed.
|
||||
* If they don't then the default value 0 is used.
|
||||
*/
|
||||
of_property_read_u32(port_node, "reg", &endpoint->port);
|
||||
of_property_read_u32(node, "reg", &endpoint->id);
|
||||
of_graph_parse_endpoint(node, &endpoint->base);
|
||||
endpoint->bus_type = 0;
|
||||
memset(&endpoint->bus, 0, sizeof(endpoint->bus));
|
||||
|
||||
v4l2_of_parse_csi_bus(node, endpoint);
|
||||
/*
|
||||
|
@ -147,125 +139,6 @@ int v4l2_of_parse_endpoint(const struct device_node *node,
|
|||
if (endpoint->bus.mipi_csi2.flags == 0)
|
||||
v4l2_of_parse_parallel_bus(node, endpoint);
|
||||
|
||||
of_node_put(port_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(v4l2_of_parse_endpoint);
|
||||
|
||||
/**
|
||||
* v4l2_of_get_next_endpoint() - get next endpoint node
|
||||
* @parent: pointer to the parent device node
|
||||
* @prev: previous endpoint node, or NULL to get first
|
||||
*
|
||||
* Return: An 'endpoint' node pointer with refcount incremented. Refcount
|
||||
* of the passed @prev node is not decremented, the caller have to use
|
||||
* of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *endpoint;
|
||||
struct device_node *port = NULL;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
if (!prev) {
|
||||
struct device_node *node;
|
||||
/*
|
||||
* It's the first call, we have to find a port subnode
|
||||
* within this node or within an optional 'ports' node.
|
||||
*/
|
||||
node = of_get_child_by_name(parent, "ports");
|
||||
if (node)
|
||||
parent = node;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
|
||||
if (port) {
|
||||
/* Found a port, get an endpoint. */
|
||||
endpoint = of_get_next_child(port, NULL);
|
||||
of_node_put(port);
|
||||
} else {
|
||||
endpoint = NULL;
|
||||
}
|
||||
|
||||
if (!endpoint)
|
||||
pr_err("%s(): no endpoint nodes specified for %s\n",
|
||||
__func__, parent->full_name);
|
||||
of_node_put(node);
|
||||
} else {
|
||||
port = of_get_parent(prev);
|
||||
if (!port)
|
||||
/* Hm, has someone given us the root node ?... */
|
||||
return NULL;
|
||||
|
||||
/* Avoid dropping prev node refcount to 0. */
|
||||
of_node_get(prev);
|
||||
endpoint = of_get_next_child(port, prev);
|
||||
if (endpoint) {
|
||||
of_node_put(port);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/* No more endpoints under this port, try the next one. */
|
||||
do {
|
||||
port = of_get_next_child(parent, port);
|
||||
if (!port)
|
||||
return NULL;
|
||||
} while (of_node_cmp(port->name, "port"));
|
||||
|
||||
/* Pick up the first endpoint in this port. */
|
||||
endpoint = of_get_next_child(port, NULL);
|
||||
of_node_put(port);
|
||||
}
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
EXPORT_SYMBOL(v4l2_of_get_next_endpoint);
|
||||
|
||||
/**
|
||||
* v4l2_of_get_remote_port_parent() - get remote port's parent node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote device node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *v4l2_of_get_remote_port_parent(
|
||||
const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
unsigned int depth;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
|
||||
/* Walk 3 levels up only if there is 'ports' node. */
|
||||
for (depth = 3; depth && np; depth--) {
|
||||
np = of_get_next_parent(np);
|
||||
if (depth == 2 && of_node_cmp(np->name, "ports"))
|
||||
break;
|
||||
}
|
||||
return np;
|
||||
}
|
||||
EXPORT_SYMBOL(v4l2_of_get_remote_port_parent);
|
||||
|
||||
/**
|
||||
* v4l2_of_get_remote_port() - get remote port node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote port node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *v4l2_of_get_remote_port(const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
if (!np)
|
||||
return NULL;
|
||||
return of_get_next_parent(np);
|
||||
}
|
||||
EXPORT_SYMBOL(v4l2_of_get_remote_port);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/cpu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
@ -1982,3 +1983,153 @@ struct device_node *of_find_next_cache_node(const struct device_node *np)
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_graph_parse_endpoint() - parse common endpoint node properties
|
||||
* @node: pointer to endpoint device_node
|
||||
* @endpoint: pointer to the OF endpoint data structure
|
||||
*
|
||||
* The caller should hold a reference to @node.
|
||||
*/
|
||||
int of_graph_parse_endpoint(const struct device_node *node,
|
||||
struct of_endpoint *endpoint)
|
||||
{
|
||||
struct device_node *port_node = of_get_parent(node);
|
||||
|
||||
WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n",
|
||||
__func__, node->full_name);
|
||||
|
||||
memset(endpoint, 0, sizeof(*endpoint));
|
||||
|
||||
endpoint->local_node = node;
|
||||
/*
|
||||
* It doesn't matter whether the two calls below succeed.
|
||||
* If they don't then the default value 0 is used.
|
||||
*/
|
||||
of_property_read_u32(port_node, "reg", &endpoint->port);
|
||||
of_property_read_u32(node, "reg", &endpoint->id);
|
||||
|
||||
of_node_put(port_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_parse_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_next_endpoint() - get next endpoint node
|
||||
* @parent: pointer to the parent device node
|
||||
* @prev: previous endpoint node, or NULL to get first
|
||||
*
|
||||
* Return: An 'endpoint' node pointer with refcount incremented. Refcount
|
||||
* of the passed @prev node is not decremented, the caller have to use
|
||||
* of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
{
|
||||
struct device_node *endpoint;
|
||||
struct device_node *port = NULL;
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
if (!prev) {
|
||||
struct device_node *node;
|
||||
/*
|
||||
* It's the first call, we have to find a port subnode
|
||||
* within this node or within an optional 'ports' node.
|
||||
*/
|
||||
node = of_get_child_by_name(parent, "ports");
|
||||
if (node)
|
||||
parent = node;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
|
||||
if (port) {
|
||||
/* Found a port, get an endpoint. */
|
||||
endpoint = of_get_next_child(port, NULL);
|
||||
of_node_put(port);
|
||||
} else {
|
||||
endpoint = NULL;
|
||||
}
|
||||
|
||||
if (!endpoint)
|
||||
pr_err("%s(): no endpoint nodes specified for %s\n",
|
||||
__func__, parent->full_name);
|
||||
of_node_put(node);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
port = of_get_parent(prev);
|
||||
if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n",
|
||||
__func__, prev->full_name))
|
||||
return NULL;
|
||||
|
||||
/* Avoid dropping prev node refcount to 0. */
|
||||
of_node_get(prev);
|
||||
endpoint = of_get_next_child(port, prev);
|
||||
if (endpoint) {
|
||||
of_node_put(port);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/* No more endpoints under this port, try the next one. */
|
||||
do {
|
||||
port = of_get_next_child(parent, port);
|
||||
if (!port)
|
||||
return NULL;
|
||||
} while (of_node_cmp(port->name, "port"));
|
||||
|
||||
/* Pick up the first endpoint in this port. */
|
||||
endpoint = of_get_next_child(port, NULL);
|
||||
of_node_put(port);
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_next_endpoint);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_port_parent() - get remote port's parent node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote device node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_port_parent(
|
||||
const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
unsigned int depth;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
|
||||
/* Walk 3 levels up only if there is 'ports' node. */
|
||||
for (depth = 3; depth && np; depth--) {
|
||||
np = of_get_next_parent(np);
|
||||
if (depth == 2 && of_node_cmp(np->name, "ports"))
|
||||
break;
|
||||
}
|
||||
return np;
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_port_parent);
|
||||
|
||||
/**
|
||||
* of_graph_get_remote_port() - get remote port node
|
||||
* @node: pointer to a local endpoint device_node
|
||||
*
|
||||
* Return: Remote port node associated with remote endpoint node linked
|
||||
* to @node. Use of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_graph_get_remote_port(const struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
/* Get remote endpoint node. */
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
if (!np)
|
||||
return NULL;
|
||||
return of_get_next_parent(np);
|
||||
}
|
||||
EXPORT_SYMBOL(of_graph_get_remote_port);
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
TODO:
|
||||
- get DRM Maintainer review for this code
|
||||
- Wait for common display framework to hit mainline and update the IPU
|
||||
driver to use it. This will most probably make changes to the devicetree
|
||||
bindings necessary.
|
||||
- Factor out more code to common helper functions
|
||||
- decide where to put the base driver. It is not specific to a subsystem
|
||||
and would be used by DRM/KMS and media/V4L2
|
||||
|
||||
Missing features (not necessarily for moving out of staging):
|
||||
|
||||
- Add i.MX6 HDMI support
|
||||
- Add support for IC (Image converter)
|
||||
- Add support for CSI (CMOS Sensor interface)
|
||||
- Add support for VDIC (Video Deinterlacer)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
|
@ -30,6 +31,11 @@
|
|||
|
||||
struct imx_drm_crtc;
|
||||
|
||||
struct imx_drm_component {
|
||||
struct device_node *of_node;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct imx_drm_device {
|
||||
struct drm_device *drm;
|
||||
struct imx_drm_crtc *crtc[MAX_CRTC];
|
||||
|
@ -41,9 +47,7 @@ struct imx_drm_crtc {
|
|||
struct drm_crtc *crtc;
|
||||
int pipe;
|
||||
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
|
||||
void *cookie;
|
||||
int id;
|
||||
int mux_id;
|
||||
struct device_node *port;
|
||||
};
|
||||
|
||||
static int legacyfb_depth = 16;
|
||||
|
@ -341,14 +345,11 @@ err_kms:
|
|||
|
||||
/*
|
||||
* imx_drm_add_crtc - add a new crtc
|
||||
*
|
||||
* The return value if !NULL is a cookie for the caller to pass to
|
||||
* imx_drm_remove_crtc later.
|
||||
*/
|
||||
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
|
||||
struct imx_drm_crtc **new_crtc,
|
||||
const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
|
||||
void *cookie, int id)
|
||||
struct device_node *port)
|
||||
{
|
||||
struct imx_drm_device *imxdrm = drm->dev_private;
|
||||
struct imx_drm_crtc *imx_drm_crtc;
|
||||
|
@ -370,9 +371,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
|
|||
|
||||
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
|
||||
imx_drm_crtc->pipe = imxdrm->pipes++;
|
||||
imx_drm_crtc->cookie = cookie;
|
||||
imx_drm_crtc->id = id;
|
||||
imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
|
||||
imx_drm_crtc->port = port;
|
||||
imx_drm_crtc->crtc = crtc;
|
||||
|
||||
imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
|
||||
|
@ -416,49 +415,56 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
|
|||
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
|
||||
|
||||
/*
|
||||
* Find the DRM CRTC possible mask for the device node cookie/id.
|
||||
* Find the DRM CRTC possible mask for the connected endpoint.
|
||||
*
|
||||
* The encoder possible masks are defined by their position in the
|
||||
* mode_config crtc_list. This means that CRTCs must not be added
|
||||
* or removed once the DRM device has been fully initialised.
|
||||
*/
|
||||
static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
|
||||
void *cookie, int id)
|
||||
struct device_node *endpoint)
|
||||
{
|
||||
struct device_node *port;
|
||||
unsigned i;
|
||||
|
||||
port = of_graph_get_remote_port(endpoint);
|
||||
if (!port)
|
||||
return 0;
|
||||
of_node_put(port);
|
||||
|
||||
for (i = 0; i < MAX_CRTC; i++) {
|
||||
struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
|
||||
if (imx_drm_crtc && imx_drm_crtc->id == id &&
|
||||
imx_drm_crtc->cookie == cookie)
|
||||
if (imx_drm_crtc && imx_drm_crtc->port == port)
|
||||
return drm_crtc_mask(imx_drm_crtc->crtc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_node *imx_drm_of_get_next_endpoint(
|
||||
const struct device_node *parent, struct device_node *prev)
|
||||
{
|
||||
struct device_node *node = of_graph_get_next_endpoint(parent, prev);
|
||||
of_node_put(prev);
|
||||
return node;
|
||||
}
|
||||
|
||||
int imx_drm_encoder_parse_of(struct drm_device *drm,
|
||||
struct drm_encoder *encoder, struct device_node *np)
|
||||
{
|
||||
struct imx_drm_device *imxdrm = drm->dev_private;
|
||||
struct device_node *ep = NULL;
|
||||
uint32_t crtc_mask = 0;
|
||||
int i, ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; !ret; i++) {
|
||||
struct of_phandle_args args;
|
||||
uint32_t mask;
|
||||
int id;
|
||||
for (i = 0; ; i++) {
|
||||
u32 mask;
|
||||
|
||||
ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
|
||||
&args);
|
||||
if (ret == -ENOENT)
|
||||
ep = imx_drm_of_get_next_endpoint(np, ep);
|
||||
if (!ep)
|
||||
break;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
id = args.args_count > 0 ? args.args[0] : 0;
|
||||
mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
|
||||
of_node_put(args.np);
|
||||
mask = imx_drm_find_crtc_mask(imxdrm, ep);
|
||||
|
||||
/*
|
||||
* If we failed to find the CRTC(s) which this encoder is
|
||||
|
@ -472,6 +478,11 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
|
|||
crtc_mask |= mask;
|
||||
}
|
||||
|
||||
if (ep)
|
||||
of_node_put(ep);
|
||||
if (i == 0)
|
||||
return -ENOENT;
|
||||
|
||||
encoder->possible_crtcs = crtc_mask;
|
||||
|
||||
/* FIXME: this is the mask of outputs which can clone this output. */
|
||||
|
@ -481,11 +492,36 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
|
||||
|
||||
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
|
||||
/*
|
||||
* @node: device tree node containing encoder input ports
|
||||
* @encoder: drm_encoder
|
||||
*/
|
||||
int imx_drm_encoder_get_mux_id(struct device_node *node,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
|
||||
struct device_node *ep = NULL;
|
||||
struct of_endpoint endpoint;
|
||||
struct device_node *port;
|
||||
int ret;
|
||||
|
||||
return imx_crtc ? imx_crtc->mux_id : -EINVAL;
|
||||
if (!node || !imx_crtc)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
ep = imx_drm_of_get_next_endpoint(node, ep);
|
||||
if (!ep)
|
||||
break;
|
||||
|
||||
port = of_graph_get_remote_port(ep);
|
||||
of_node_put(port);
|
||||
if (port == imx_crtc->port) {
|
||||
ret = of_graph_parse_endpoint(ep, &endpoint);
|
||||
return ret ? ret : endpoint.id;
|
||||
}
|
||||
} while (ep);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
|
||||
|
||||
|
@ -528,48 +564,29 @@ static struct drm_driver imx_drm_driver = {
|
|||
.patchlevel = 0,
|
||||
};
|
||||
|
||||
static int compare_parent_of(struct device *dev, void *data)
|
||||
{
|
||||
struct of_phandle_args *args = data;
|
||||
return dev->parent && dev->parent->of_node == args->np;
|
||||
}
|
||||
|
||||
static int compare_of(struct device *dev, void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
struct device_node *np = data;
|
||||
|
||||
/* Special case for LDB, one device for two channels */
|
||||
if (of_node_cmp(np->name, "lvds-channel") == 0) {
|
||||
np = of_get_parent(np);
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
return dev->of_node == np;
|
||||
}
|
||||
|
||||
static LIST_HEAD(imx_drm_components);
|
||||
|
||||
static int imx_drm_add_components(struct device *master, struct master *m)
|
||||
{
|
||||
struct device_node *np = master->of_node;
|
||||
unsigned i;
|
||||
struct imx_drm_component *component;
|
||||
int ret;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
struct of_phandle_args args;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1,
|
||||
i, &args);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = component_master_add_child(m, compare_parent_of, &args);
|
||||
of_node_put(args.np);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
struct device_node *node;
|
||||
|
||||
node = of_parse_phandle(np, "connectors", i);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
ret = component_master_add_child(m, compare_of, node);
|
||||
of_node_put(node);
|
||||
|
||||
list_for_each_entry(component, &imx_drm_components, list) {
|
||||
ret = component_master_add_child(m, compare_of,
|
||||
component->of_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -592,9 +609,81 @@ static const struct component_master_ops imx_drm_ops = {
|
|||
.unbind = imx_drm_unbind,
|
||||
};
|
||||
|
||||
static struct imx_drm_component *imx_drm_find_component(struct device *dev,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct imx_drm_component *component;
|
||||
|
||||
list_for_each_entry(component, &imx_drm_components, list)
|
||||
if (component->of_node == node)
|
||||
return component;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int imx_drm_add_component(struct device *dev, struct device_node *node)
|
||||
{
|
||||
struct imx_drm_component *component;
|
||||
|
||||
if (imx_drm_find_component(dev, node))
|
||||
return 0;
|
||||
|
||||
component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
|
||||
if (!component)
|
||||
return -ENOMEM;
|
||||
|
||||
component->of_node = node;
|
||||
list_add_tail(&component->list, &imx_drm_components);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_drm_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *ep, *port, *remote;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Bind the IPU display interface ports first, so that
|
||||
* imx_drm_encoder_parse_of called from encoder .bind callbacks
|
||||
* works as expected.
|
||||
*/
|
||||
for (i = 0; ; i++) {
|
||||
port = of_parse_phandle(pdev->dev.of_node, "ports", i);
|
||||
if (!port)
|
||||
break;
|
||||
|
||||
ret = imx_drm_add_component(&pdev->dev, port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
dev_err(&pdev->dev, "missing 'ports' property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Then bind all encoders */
|
||||
for (i = 0; ; i++) {
|
||||
port = of_parse_phandle(pdev->dev.of_node, "ports", i);
|
||||
if (!port)
|
||||
break;
|
||||
|
||||
for_each_child_of_node(port, ep) {
|
||||
remote = of_graph_get_remote_port_parent(ep);
|
||||
if (!remote || !of_device_is_available(remote)) {
|
||||
of_node_put(remote);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = imx_drm_add_component(&pdev->dev, remote);
|
||||
of_node_put(remote);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
of_node_put(port);
|
||||
}
|
||||
|
||||
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
|
@ -610,7 +699,7 @@ static int imx_drm_platform_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id imx_drm_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx-drm", },
|
||||
{ .compatible = "fsl,imx-display-subsystem", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
|
||||
|
|
|
@ -26,7 +26,7 @@ struct imx_drm_crtc_helper_funcs {
|
|||
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
|
||||
struct imx_drm_crtc **new_crtc,
|
||||
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
|
||||
void *cookie, int id);
|
||||
struct device_node *port);
|
||||
int imx_drm_remove_crtc(struct imx_drm_crtc *);
|
||||
int imx_drm_init_drm(struct platform_device *pdev,
|
||||
int preferred_bpp);
|
||||
|
@ -45,7 +45,8 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
|
|||
int imx_drm_panel_format(struct drm_encoder *encoder,
|
||||
u32 interface_pix_fmt);
|
||||
|
||||
int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
|
||||
int imx_drm_encoder_get_mux_id(struct device_node *node,
|
||||
struct drm_encoder *encoder);
|
||||
int imx_drm_encoder_parse_of(struct drm_device *drm,
|
||||
struct drm_encoder *encoder, struct device_node *np);
|
||||
|
||||
|
|
|
@ -1459,7 +1459,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
|
|||
static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
|
||||
int mux = imx_drm_encoder_get_mux_id(encoder);
|
||||
int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
|
||||
|
||||
imx_hdmi_set_ipu_di_mux(hdmi, mux);
|
||||
|
||||
|
@ -1610,7 +1610,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
|
|||
hdmi->dev_type = device_id->driver_data;
|
||||
}
|
||||
|
||||
ddc_node = of_parse_phandle(np, "ddc", 0);
|
||||
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
|
||||
if (ddc_node) {
|
||||
hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
|
||||
if (!hdmi->ddc)
|
||||
|
|
|
@ -170,7 +170,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
|
|||
u32 pixel_fmt;
|
||||
unsigned long serial_clk;
|
||||
unsigned long di_clk = mode->clock * 1000;
|
||||
int mux = imx_drm_encoder_get_mux_id(encoder);
|
||||
int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
|
||||
|
||||
if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
|
||||
/* dual channel LVDS mode */
|
||||
|
@ -205,7 +205,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
|
|||
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
|
||||
struct imx_ldb *ldb = imx_ldb_ch->ldb;
|
||||
int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
|
||||
int mux = imx_drm_encoder_get_mux_id(encoder);
|
||||
int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
|
||||
|
||||
if (dual) {
|
||||
clk_prepare_enable(ldb->clk[0]);
|
||||
|
|
|
@ -582,7 +582,7 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
|
|||
tve->dev = dev;
|
||||
spin_lock_init(&tve->lock);
|
||||
|
||||
ddc_node = of_parse_phandle(np, "ddc", 0);
|
||||
ddc_node = of_parse_phandle(np, "i2c-ddc-bus", 0);
|
||||
if (ddc_node) {
|
||||
tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
|
||||
of_node_put(ddc_node);
|
||||
|
|
|
@ -350,10 +350,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = imx_drm_add_crtc(drm, &ipu_crtc->base,
|
||||
&ipu_crtc->imx_crtc,
|
||||
&ipu_crtc_helper_funcs,
|
||||
ipu_crtc->dev->parent->of_node, pdata->di);
|
||||
ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
|
||||
&ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
|
||||
if (ret) {
|
||||
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
|
||||
goto err_put_resources;
|
||||
|
@ -401,6 +399,28 @@ err_put_resources:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
|
||||
int port_id)
|
||||
{
|
||||
struct device_node *port;
|
||||
int id, ret;
|
||||
|
||||
port = of_get_child_by_name(parent, "port");
|
||||
while (port) {
|
||||
ret = of_property_read_u32(port, "reg", &id);
|
||||
if (!ret && id == port_id)
|
||||
return port;
|
||||
|
||||
do {
|
||||
port = of_get_next_child(parent, port);
|
||||
if (!port)
|
||||
return NULL;
|
||||
} while (of_node_cmp(port->name, "port"));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct ipu_client_platformdata *pdata = dev->platform_data;
|
||||
|
@ -441,16 +461,29 @@ static const struct component_ops ipu_crtc_ops = {
|
|||
|
||||
static int ipu_drm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ipu_client_platformdata *pdata = dev->platform_data;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.platform_data)
|
||||
if (!dev->platform_data)
|
||||
return -EINVAL;
|
||||
|
||||
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (!dev->of_node) {
|
||||
/* Associate crtc device with the corresponding DI port node */
|
||||
dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
|
||||
pdata->di + 2);
|
||||
if (!dev->of_node) {
|
||||
dev_err(dev, "missing port@%d node in %s\n",
|
||||
pdata->di + 2, dev->parent->of_node->full_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return component_add(&pdev->dev, &ipu_crtc_ops);
|
||||
return component_add(dev, &ipu_crtc_ops);
|
||||
}
|
||||
|
||||
static int ipu_drm_remove(struct platform_device *pdev)
|
||||
|
|
66
include/linux/of_graph.h
Normal file
66
include/linux/of_graph.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* OF graph binding parsing helpers
|
||||
*
|
||||
* Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
|
||||
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
*
|
||||
* Copyright (C) 2012 Renesas Electronics Corp.
|
||||
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef __LINUX_OF_GRAPH_H
|
||||
#define __LINUX_OF_GRAPH_H
|
||||
|
||||
/**
|
||||
* struct of_endpoint - the OF graph endpoint data structure
|
||||
* @port: identifier (value of reg property) of a port this endpoint belongs to
|
||||
* @id: identifier (value of reg property) of this endpoint
|
||||
* @local_node: pointer to device_node of this endpoint
|
||||
*/
|
||||
struct of_endpoint {
|
||||
unsigned int port;
|
||||
unsigned int id;
|
||||
const struct device_node *local_node;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
int of_graph_parse_endpoint(const struct device_node *node,
|
||||
struct of_endpoint *endpoint);
|
||||
struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *previous);
|
||||
struct device_node *of_graph_get_remote_port_parent(
|
||||
const struct device_node *node);
|
||||
struct device_node *of_graph_get_remote_port(const struct device_node *node);
|
||||
#else
|
||||
|
||||
static inline int of_graph_parse_endpoint(const struct device_node *node,
|
||||
struct of_endpoint *endpoint)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline struct device_node *of_graph_get_next_endpoint(
|
||||
const struct device_node *parent,
|
||||
struct device_node *previous)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct device_node *of_graph_get_remote_port_parent(
|
||||
const struct device_node *node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct device_node *of_graph_get_remote_port(
|
||||
const struct device_node *node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#endif /* __LINUX_OF_GRAPH_H */
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <media/v4l2-mediabus.h>
|
||||
|
||||
|
@ -50,17 +51,13 @@ struct v4l2_of_bus_parallel {
|
|||
|
||||
/**
|
||||
* struct v4l2_of_endpoint - the endpoint data structure
|
||||
* @port: identifier (value of reg property) of a port this endpoint belongs to
|
||||
* @id: identifier (value of reg property) of this endpoint
|
||||
* @local_node: pointer to device_node of this endpoint
|
||||
* @base: struct of_endpoint containing port, id, and local of_node
|
||||
* @bus_type: bus type
|
||||
* @bus: bus configuration data structure
|
||||
* @head: list head for this structure
|
||||
*/
|
||||
struct v4l2_of_endpoint {
|
||||
unsigned int port;
|
||||
unsigned int id;
|
||||
const struct device_node *local_node;
|
||||
struct of_endpoint base;
|
||||
enum v4l2_mbus_type bus_type;
|
||||
union {
|
||||
struct v4l2_of_bus_parallel parallel;
|
||||
|
@ -72,11 +69,6 @@ struct v4l2_of_endpoint {
|
|||
#ifdef CONFIG_OF
|
||||
int v4l2_of_parse_endpoint(const struct device_node *node,
|
||||
struct v4l2_of_endpoint *endpoint);
|
||||
struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
|
||||
struct device_node *previous);
|
||||
struct device_node *v4l2_of_get_remote_port_parent(
|
||||
const struct device_node *node);
|
||||
struct device_node *v4l2_of_get_remote_port(const struct device_node *node);
|
||||
#else /* CONFIG_OF */
|
||||
|
||||
static inline int v4l2_of_parse_endpoint(const struct device_node *node,
|
||||
|
@ -85,25 +77,6 @@ static inline int v4l2_of_parse_endpoint(const struct device_node *node,
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline struct device_node *v4l2_of_get_next_endpoint(
|
||||
const struct device_node *parent,
|
||||
struct device_node *previous)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct device_node *v4l2_of_get_remote_port_parent(
|
||||
const struct device_node *node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct device_node *v4l2_of_get_remote_port(
|
||||
const struct device_node *node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#endif /* _V4L2_OF_H */
|
||||
|
|
Loading…
Reference in a new issue