From 9b32f8951f0f3f8e07c0682d853f5aaf77603aef Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 9 Jul 2018 14:37:50 +0530 Subject: dt-bindings: mipi-dsi: Add info about peripherals with non-DSI control bus Add a section that describes dt-bindings for peripherals that support MIPI DSI, but have a different bus as the primary control bus, or no control bus at all. Add an example for a peripheral with a non-DSI control bus. Reviewed-by: Rob Herring Reviewed-by: Boris Brezillon Reviewed-by: Philippe Cornu Reviewed-by: Sean Paul Signed-off-by: Archit Taneja Link: https://patchwork.freedesktop.org/patch/msgid/20180709090751.10221-2-architt@codeaurora.org --- .../devicetree/bindings/display/mipi-dsi-bus.txt | 71 +++++++++++++++++++--- 1 file changed, 64 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt index 973c27273772..b7c5bf47403c 100644 --- a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt +++ b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt @@ -16,7 +16,7 @@ The following assumes that only a single peripheral is connected to a DSI host. Experience shows that this is true for the large majority of setups. DSI host --------- +======== In addition to the standard properties and those defined by the parent bus of a DSI host, the following properties apply to a node representing a DSI host. @@ -30,11 +30,16 @@ Required properties: different value here. See below. DSI peripheral --------------- +============== -Peripherals are represented as child nodes of the DSI host's node. Properties -described here apply to all DSI peripherals, but individual bindings may want -to define additional, device-specific properties. +Peripherals with DSI as control bus, or no control bus +------------------------------------------------------ + +Peripherals with the DSI bus as the primary control bus, or peripherals with +no control bus but use the DSI bus to transmit pixel data are represented +as child nodes of the DSI host's node. Properties described here apply to all +DSI peripherals, but individual bindings may want to define additional, +device-specific properties. Required properties: - reg: The virtual channel number of a DSI peripheral. Must be in the range @@ -49,9 +54,25 @@ case two alternative representations can be chosen: property is the number of the first virtual channel and the second cell is the number of consecutive virtual channels. -Example -------- +Peripherals with a different control bus +---------------------------------------- + +There are peripherals that have I2C/SPI (or some other non-DSI bus) as the +primary control bus, but are also connected to a DSI bus (mostly for the data +path). Connections between such peripherals and a DSI host can be represented +using the graph bindings [1], [2]. + +[1] Documentation/devicetree/bindings/graph.txt +[2] Documentation/devicetree/bindings/media/video-interfaces.txt +Examples +======== +- (1), (2) and (3) are examples of a DSI host and peripheral on the DSI bus + with different virtual channel configurations. +- (4) is an example of a peripheral on a I2C control bus connected to a + DSI host using of-graph bindings. + +1) dsi-host { ... @@ -67,6 +88,7 @@ Example ... }; +2) dsi-host { ... @@ -82,6 +104,7 @@ Example ... }; +3) dsi-host { ... @@ -96,3 +119,37 @@ Example ... }; + +4) + i2c-host { + ... + + dsi-bridge@35 { + compatible = "..."; + reg = <0x35>; + + ports { + ... + + port { + bridge_mipi_in: endpoint { + remote-endpoint = <&host_mipi_out>; + }; + }; + }; + }; + }; + + dsi-host { + ... + + ports { + ... + + port { + host_mipi_out: endpoint { + remote-endpoint = <&bridge_mipi_in>; + }; + }; + }; + }; -- cgit v1.2.3 From 5e03f02cb58d1cee5d98f323da9abe2e7073b2b4 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 9 Jul 2018 14:37:51 +0530 Subject: dt-bindings: mipi-dsi: Add dual-channel DSI related info Add binding info for peripherals that support dual-channel DSI. Add corresponding optional bindings for DSI host controllers that may be configured in this mode. Add an example of an I2C controlled device operating in dual-channel DSI mode. Reviewed-by: Rob Herring Reviewed-by: Philippe Cornu Reviewed-by: Sean Paul Reviewed-by: Heiko Stuebner Signed-off-by: Archit Taneja Link: https://patchwork.freedesktop.org/patch/msgid/20180709090751.10221-3-architt@codeaurora.org --- .../devicetree/bindings/display/mipi-dsi-bus.txt | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt index b7c5bf47403c..a336599f6c03 100644 --- a/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt +++ b/Documentation/devicetree/bindings/display/mipi-dsi-bus.txt @@ -29,6 +29,13 @@ Required properties: - #size-cells: Should be 0. There are cases where it makes sense to use a different value here. See below. +Optional properties: +- clock-master: boolean. Should be enabled if the host is being used in + conjunction with another DSI host to drive the same peripheral. Hardware + supporting such a configuration generally requires the data on both the busses + to be driven by the same clock. Only the DSI host instance controlling this + clock should contain this property. + DSI peripheral ============== @@ -62,6 +69,16 @@ primary control bus, but are also connected to a DSI bus (mostly for the data path). Connections between such peripherals and a DSI host can be represented using the graph bindings [1], [2]. +Peripherals that support dual channel DSI +----------------------------------------- + +Peripherals with higher bandwidth requirements can be connected to 2 DSI +busses. Each DSI bus/channel drives some portion of the pixel data (generally +left/right half of each line of the display, or even/odd lines of the display). +The graph bindings should be used to represent the multiple DSI busses that are +connected to this peripheral. Each DSI host's output endpoint can be linked to +an input endpoint of the DSI peripheral. + [1] Documentation/devicetree/bindings/graph.txt [2] Documentation/devicetree/bindings/media/video-interfaces.txt @@ -71,6 +88,8 @@ Examples with different virtual channel configurations. - (4) is an example of a peripheral on a I2C control bus connected to a DSI host using of-graph bindings. +- (5) is an example of 2 DSI hosts driving a dual-channel DSI peripheral, + which uses I2C as its primary control bus. 1) dsi-host { @@ -153,3 +172,64 @@ Examples }; }; }; + +5) + i2c-host { + dsi-bridge@35 { + compatible = "..."; + reg = <0x35>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_in: endpoint { + remote-endpoint = <&dsi1_out>; + }; + }; + }; + }; + }; + + dsi0-host { + ... + + /* + * this DSI instance drives the clock for both the host + * controllers + */ + clock-master; + + ports { + ... + + port { + dsi0_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; + + dsi1-host { + ... + + ports { + ... + + port { + dsi1_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; -- cgit v1.2.3 From e3896e6dddf0b821dc3214b623a922aa7ee2c2d5 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 16 Jul 2018 14:13:30 +0530 Subject: dt-bindings: drm/bridge: Document sn65dsi86 bridge bindings Document the bindings used for the sn65dsi86 DSI to eDP bridge. Changes in v1: - Rephrase the dt-binding descriptions to be more inline with existing bindings (Andrzej Hajda). - Add missing dt-binding that are parsed by corresponding driver (Andrzej Hajda). Changes in v2: - Remove edp panel specific dt-binding entries. Only keep bridge specific entries (Sean Paul). - Remove custom-modes dt entry since its usage is removed from driver also (Sean Paul). - Remove is-pluggable dt entry since this will not be needed anymore (Sean Paul). Changes in v3: - Remove irq-gpio dt entry and instead populate is an interrupt property (Rob Herring). Changes in v4: - Add link to bridge chip datasheet (Stephen Boyd) - Add vpll and vcc regulator supply bindings (Stephen Boyd) - Add ref clk optional dt binding (Stephen Boyd) - Add gpio-controller optional dt binding (Stephen Boyd) Changes in v5: - Use clock property to specify the input refclk (Stephen Boyd). - Update gpio cell and pwm cell numbers (Stephen Boyd). Changes in v6: - Add property to mention the lane mapping scheme and polarity inversion (Stephen Boyd). Changes in v7: - Detail description of lane mapping scheme dt property (Andrzej Hajda/ Rob Herring). - Removed HDP gpio binding, since the bridge uses IRQ signal to determine HPD, and IRQ property is already documented in binding. Changes in v8: - Removed unnecessary explanation of lane mapping and polarity dt property, since these are already explained in media/video-interface dt binidng (Rob Herring). Changes in v9: - Avoid putting re-definition of lane mapping and polarity dt binding (Rob Herring). Changes in v10: - Use interrupts-extended property instead of interrupts to specify interrupt line (Andrzej Hajda). - Move data-lanes and lane-polarity property example to proper place (Andrzej Hajda). Changes in v11: - Add a property for suspend gpio function of GPIO1 pin on bridge chip (Stephen Boyd). Changes in v12: - Remove binding for dedicated DDC line (Andrzej Hajda). Signed-off-by: Sandeep Panda Reviewed-by: Stephen Boyd Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20180716084330.26698-3-spanda@codeaurora.org --- .../bindings/display/bridge/ti,sn65dsi86.txt | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt new file mode 100644 index 000000000000..0a3fbb53a16e --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.txt @@ -0,0 +1,87 @@ +SN65DSI86 DSI to eDP bridge chip +-------------------------------- + +This is the binding for Texas Instruments SN65DSI86 bridge. +http://www.ti.com/general/docs/lit/getliterature.tsp?genericPartNumber=sn65dsi86&fileType=pdf + +Required properties: +- compatible: Must be "ti,sn65dsi86" +- reg: i2c address of the chip, 0x2d as per datasheet +- enable-gpios: gpio specification for bridge_en pin (active high) + +- vccio-supply: A 1.8V supply that powers up the digital IOs. +- vpll-supply: A 1.8V supply that powers up the displayport PLL. +- vcca-supply: A 1.2V supply that powers up the analog circuits. +- vcc-supply: A 1.2V supply that powers up the digital core. + +Optional properties: +- interrupts-extended: Specifier for the SN65DSI86 interrupt line. + +- gpio-controller: Marks the device has a GPIO controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../../gpio/gpio.txt for more information. +- #pwm-cells : Should be one. See ../../pwm/pwm.txt for description of + the cell formats. + +- clock-names: should be "refclk" +- clocks: Specification for input reference clock. The reference + clock rate must be 12 MHz, 19.2 MHz, 26 MHz, 27 MHz or 38.4 MHz. + +- data-lanes: See ../../media/video-interface.txt +- lane-polarities: See ../../media/video-interface.txt + +- suspend-gpios: specification for GPIO1 pin on bridge (active low) + +Required nodes: +This device has two video ports. Their connections are modelled using the +OF graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for DSI input +- Video port 1 for eDP output + +Example +------- + +edp-bridge@2d { + compatible = "ti,sn65dsi86"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2d>; + + enable-gpios = <&msmgpio 33 GPIO_ACTIVE_HIGH>; + suspend-gpios = <&msmgpio 34 GPIO_ACTIVE_LOW>; + + interrupts-extended = <&gpio3 4 IRQ_TYPE_EDGE_FALLING>; + + vccio-supply = <&pm8916_l17>; + vcca-supply = <&pm8916_l6>; + vpll-supply = <&pm8916_l17>; + vcc-supply = <&pm8916_l6>; + + clock-names = "refclk"; + clocks = <&input_refclk>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + edp_bridge_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + edp_bridge_out: endpoint { + data-lanes = <2 1 3 0>; + lane-polarities = <0 1 0 1>; + remote-endpoint = <&edp_panel_in>; + }; + }; + }; +} -- cgit v1.2.3 From eb91cde094f523c06adf463aad0e41ae35765d71 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 25 Jul 2018 17:46:39 +0200 Subject: dt-bindings: tc358754: add DT bindings The patch adds bindings to Toshiba DSI/LVDS bridge TC358764. Bindings describe power supplies, reset gpio and video interfaces. Signed-off-by: Andrzej Hajda Signed-off-by: Maciej Purski Reviewed-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20180725154644.25412-5-a.hajda@samsung.com --- .../bindings/display/bridge/toshiba,tc358764.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt new file mode 100644 index 000000000000..8f9abf28a8fa --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt @@ -0,0 +1,35 @@ +TC358764 MIPI-DSI to LVDS panel bridge + +Required properties: + - compatible: "toshiba,tc358764" + - reg: the virtual channel number of a DSI peripheral + - vddc-supply: core voltage supply, 1.2V + - vddio-supply: I/O voltage supply, 1.8V or 3.3V + - vddlvds-supply: LVDS1/2 voltage supply, 3.3V + - reset-gpios: a GPIO spec for the reset pin + +The device node can contain following 'port' child nodes, +according to the OF graph bindings defined in [1]: + 0: DSI Input, not required, if the bridge is DSI controlled + 1: LVDS Output, mandatory + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + bridge@0 { + reg = <0>; + compatible = "toshiba,tc358764"; + vddc-supply = <&vcc_1v2_reg>; + vddio-supply = <&vcc_1v8_reg>; + vddlvds-supply = <&vcc_3v3_reg>; + reset-gpios = <&gpd1 6 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + port@1 { + reg = <1>; + lvds_ep: endpoint { + remote-endpoint = <&panel_ep>; + }; + }; + }; -- cgit v1.2.3 From d5890d5ff4b93bb4ccb0fb2085fc2da77c89790a Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Tue, 26 Jun 2018 16:53:34 +0800 Subject: dt-bindings: display: rockchip: add document for px30 vop Add the compatible values for the px30 display controllers. Signed-off-by: Sandy Huang Acked-by: Rob Herring [added commit message] Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/1530003215-46593-2-git-send-email-hjc@rock-chips.com --- Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index eeda3597011e..5de2a0f0d1f4 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -8,6 +8,8 @@ Required properties: - compatible: value should be one of the following "rockchip,rk3036-vop"; "rockchip,rk3126-vop"; + "rockchip,px30-vop-lit"; + "rockchip,px30-vop-big"; "rockchip,rk3288-vop"; "rockchip,rk3368-vop"; "rockchip,rk3366-vop"; -- cgit v1.2.3 From 7e7b68ef0076691f05b85a3ecd604a6160015fe9 Mon Sep 17 00:00:00 2001 From: Brian Starkey Date: Tue, 21 Aug 2018 17:16:11 +0100 Subject: drm/fourcc: Add DOC: overview comment There's a number of things which haven't previously been documented around the usage of format modifiers. Capture the current understanding in an overview comment and add it to the rst documentation. Ideally, the generated documentation would also include documentation of all of the #defines, but the kernel-doc system doesn't currently support kernel-doc comments on #define constants. Suggested-by: Daniel Vetter Signed-off-by: Brian Starkey Reviewed-by: Daniel Vetter Signed-off-by: Alexandru Gheorghe Link: https://patchwork.freedesktop.org/patch/msgid/20180821161611.10424-1-brian.starkey@arm.com --- Documentation/gpu/drm-kms.rst | 6 ++++++ include/uapi/drm/drm_fourcc.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'Documentation') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 5dee6b8a4c12..f8f5bf11a6ca 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -323,6 +323,12 @@ Frame Buffer Functions Reference DRM Format Handling =================== +.. kernel-doc:: include/uapi/drm/drm_fourcc.h + :doc: overview + +Format Functions Reference +-------------------------- + .. kernel-doc:: include/drm/drm_fourcc.h :internal: diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index d43949b5bb3e..21c50b39596f 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -30,6 +30,42 @@ extern "C" { #endif +/** + * DOC: overview + * + * In the DRM subsystem, framebuffer pixel formats are described using the + * fourcc codes defined in `include/uapi/drm/drm_fourcc.h`. In addition to the + * fourcc code, a Format Modifier may optionally be provided, in order to + * further describe the buffer's format - for example tiling or compression. + * + * Format Modifiers + * ---------------- + * + * Format modifiers are used in conjunction with a fourcc code, forming a + * unique fourcc:modifier pair. This format:modifier pair must fully define the + * format and data layout of the buffer, and should be the only way to describe + * that particular buffer. + * + * Having multiple fourcc:modifier pairs which describe the same layout should + * be avoided, as such aliases run the risk of different drivers exposing + * different names for the same data format, forcing userspace to understand + * that they are aliases. + * + * Format modifiers may change any property of the buffer, including the number + * of planes and/or the required allocation size. Format modifiers are + * vendor-namespaced, and as such the relationship between a fourcc code and a + * modifier is specific to the modifer being used. For example, some modifiers + * may preserve meaning - such as number of planes - from the fourcc code, + * whereas others may not. + * + * Vendors should document their modifier usage in as much detail as + * possible, to ensure maximum compatibility across devices, drivers and + * applications. + * + * The authoritative list of format modifier codes is found in + * `include/uapi/drm/drm_fourcc.h` + */ + #define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ ((__u32)(c) << 16) | ((__u32)(d) << 24)) -- cgit v1.2.3 From 851c2509aef6ee2374d8192130f33e1166c1c2a3 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Wed, 15 Aug 2018 12:58:13 +0200 Subject: drm/doc: Adapt GPU scheduler references for renamed C file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: "drm/scheduler: rename gpu_scheduler.c to sched_main.c" Reviewed-by: Christian König Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- Documentation/gpu/drm-mm.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 21b6b72a9ba8..d3acb4949e2d 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -505,7 +505,7 @@ GPU Scheduler Overview -------- -.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c +.. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c :doc: Overview Scheduler Function References @@ -514,5 +514,5 @@ Scheduler Function References .. kernel-doc:: include/drm/gpu_scheduler.h :internal: -.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler.c +.. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c :export: -- cgit v1.2.3 From 7473b9aff963007fed591a76b9df0335635c8bcd Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Sat, 25 Aug 2018 10:56:17 +0200 Subject: dt-bindings: display: bridge: lvds-transmitter: add ti, ds90c185 Start list of actual chips compatible with "lvds-encoder". Reviewed-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Peter Rosin Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20180825085620.10566-2-peda@axentia.se --- .../devicetree/bindings/display/bridge/lvds-transmitter.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt index fd39ad34c383..50220190c203 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -22,7 +22,13 @@ among others. Required properties: -- compatible: Must be "lvds-encoder" +- compatible: Must be one or more of the following + - "ti,ds90c185" for the TI DS90C185 FPD-Link Serializer + - "lvds-encoder" for a generic LVDS encoder device + + When compatible with the generic version, nodes must list the + device-specific version corresponding to the device first + followed by the generic version. Required nodes: -- cgit v1.2.3 From 2e7c04aec86758e0adfcad4a24c86593b45807a3 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Sat, 25 Aug 2018 10:56:18 +0200 Subject: dt-bindings: display: atmel: optional video-interface of endpoints With bus-type/bus-width properties in the endpoint nodes, the video- interface of the connection can be specified for cases where the heuristic fails to select the correct output mode. This can happen e.g. if not all RGB pins are routed on the PCB; the driver has no way of knowing this, and needs to be told explicitly. This is critical for the devices that have the "conflicting output formats" issue (SAM9N12, SAM9X5, SAMA5D3), since the most significant RGB bits move around depending on the selected output mode. For devices that do not have the "conflicting output formats" issue (SAMA5D2, SAMA5D4), this is completely irrelevant. Acked-by: Boris Brezillon Reviewed-by: Rob Herring Reviewed-by: Jacopo Mondi Signed-off-by: Peter Rosin Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20180825085620.10566-3-peda@axentia.se --- .../devicetree/bindings/display/atmel/hlcdc-dc.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt index 82f2acb3d374..0398aec488ac 100644 --- a/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt +++ b/Documentation/devicetree/bindings/display/atmel/hlcdc-dc.txt @@ -15,6 +15,13 @@ Required children nodes: to external devices using the OF graph reprensentation (see ../graph.txt). At least one port node is required. +Optional properties in grandchild nodes: + Any endpoint grandchild node may specify a desired video interface + according to ../../media/video-interfaces.txt, specifically + - bus-width: recognized values are <12>, <16>, <18> and <24>, and + override any output mode selection heuristic, forcing "rgb444", + "rgb565", "rgb666" and "rgb888" respectively. + Example: hlcdc: hlcdc@f0030000 { @@ -50,3 +57,19 @@ Example: #pwm-cells = <3>; }; }; + +Example 2: With a video interface override to force rgb565; as above +but with these changes/additions: + + &hlcdc { + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb565>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + bus-width = <16>; + }; + }; + }; + }; -- cgit v1.2.3 From fbb0de795078190a9834b3409e4b009cfb18a6d4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 27 Aug 2018 11:34:44 +0200 Subject: Add udmabuf misc device A driver to let userspace turn memfd regions into dma-bufs. Use case: Allows qemu create dmabufs for the vga framebuffer or virtio-gpu ressources. Then they can be passed around to display those guest things on the host. To spice client for classic full framebuffer display, and hopefully some day to wayland server for seamless guest window display. qemu test branch: https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf Cc: David Airlie Cc: Tomeu Vizoso Cc: Laurent Pinchart Cc: Daniel Vetter Signed-off-by: Gerd Hoffmann Acked-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20180827093444.23623-1-kraxel@redhat.com --- Documentation/ioctl/ioctl-number.txt | 1 + MAINTAINERS | 8 + drivers/dma-buf/Kconfig | 8 + drivers/dma-buf/Makefile | 1 + drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ include/uapi/linux/udmabuf.h | 33 +++ tools/testing/selftests/drivers/dma-buf/Makefile | 5 + tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ 8 files changed, 439 insertions(+) create mode 100644 drivers/dma-buf/udmabuf.c create mode 100644 include/uapi/linux/udmabuf.h create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c (limited to 'Documentation') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 13a7c999c04a..f2ac672eb766 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -272,6 +272,7 @@ Code Seq#(hex) Include File Comments 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 'u' 00-1F linux/smb_fs.h gone 'u' 20-3F linux/uvcvideo.h USB video class host driver +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device 'v' 00-1F linux/ext2_fs.h conflict! 'v' 00-1F linux/fs.h conflict! 'v' 00-0F linux/sonypi.h conflict! diff --git a/MAINTAINERS b/MAINTAINERS index a5b256b25905..9d9068ed4ee5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15343,6 +15343,14 @@ F: arch/x86/um/ F: fs/hostfs/ F: fs/hppfs/ +USERSPACE DMA BUFFER DRIVER +M: Gerd Hoffmann +S: Maintained +L: dri-devel@lists.freedesktop.org +F: drivers/dma-buf/udmabuf.c +F: include/uapi/linux/udmabuf.h +T: git git://anongit.freedesktop.org/drm/drm-misc + USERSPACE I/O (UIO) M: Greg Kroah-Hartman S: Maintained diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index ed3b785bae37..338129eb126f 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -30,4 +30,12 @@ config SW_SYNC WARNING: improper use of this can result in deadlocking kernel drivers from userspace. Intended for test and debug only. +config UDMABUF + bool "userspace dmabuf misc driver" + default n + depends on DMA_SHARED_BUFFER + help + A driver to let userspace turn memfd regions into dma-bufs. + Qemu can use this to create host dmabufs for guest framebuffers. + endmenu diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index c33bf8863147..0913a6ccab5a 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,3 +1,4 @@ obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o obj-$(CONFIG_SYNC_FILE) += sync_file.o obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +obj-$(CONFIG_UDMABUF) += udmabuf.o diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c new file mode 100644 index 000000000000..8e24204526cc --- /dev/null +++ b/drivers/dma-buf/udmabuf.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct udmabuf { + u32 pagecount; + struct page **pages; +}; + +static int udmabuf_vm_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct udmabuf *ubuf = vma->vm_private_data; + + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) + return VM_FAULT_SIGBUS; + + vmf->page = ubuf->pages[vmf->pgoff]; + get_page(vmf->page); + return 0; +} + +static const struct vm_operations_struct udmabuf_vm_ops = { + .fault = udmabuf_vm_fault, +}; + +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) +{ + struct udmabuf *ubuf = buf->priv; + + if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0) + return -EINVAL; + + vma->vm_ops = &udmabuf_vm_ops; + vma->vm_private_data = ubuf; + return 0; +} + +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, + enum dma_data_direction direction) +{ + struct udmabuf *ubuf = at->dmabuf->priv; + struct sg_table *sg; + + sg = kzalloc(sizeof(*sg), GFP_KERNEL); + if (!sg) + goto err1; + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, + 0, ubuf->pagecount << PAGE_SHIFT, + GFP_KERNEL) < 0) + goto err2; + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) + goto err3; + + return sg; + +err3: + sg_free_table(sg); +err2: + kfree(sg); +err1: + return ERR_PTR(-ENOMEM); +} + +static void unmap_udmabuf(struct dma_buf_attachment *at, + struct sg_table *sg, + enum dma_data_direction direction) +{ + sg_free_table(sg); + kfree(sg); +} + +static void release_udmabuf(struct dma_buf *buf) +{ + struct udmabuf *ubuf = buf->priv; + pgoff_t pg; + + for (pg = 0; pg < ubuf->pagecount; pg++) + put_page(ubuf->pages[pg]); + kfree(ubuf->pages); + kfree(ubuf); +} + +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) +{ + struct udmabuf *ubuf = buf->priv; + struct page *page = ubuf->pages[page_num]; + + return kmap(page); +} + +static void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, + void *vaddr) +{ + kunmap(vaddr); +} + +static struct dma_buf_ops udmabuf_ops = { + .map_dma_buf = map_udmabuf, + .unmap_dma_buf = unmap_udmabuf, + .release = release_udmabuf, + .map = kmap_udmabuf, + .unmap = kunmap_udmabuf, + .mmap = mmap_udmabuf, +}; + +#define SEALS_WANTED (F_SEAL_SHRINK) +#define SEALS_DENIED (F_SEAL_WRITE) + +static long udmabuf_create(struct udmabuf_create_list *head, + struct udmabuf_create_item *list) +{ + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct file *memfd = NULL; + struct udmabuf *ubuf; + struct dma_buf *buf; + pgoff_t pgoff, pgcnt, pgidx, pgbuf; + struct page *page; + int seals, ret = -EINVAL; + u32 i, flags; + + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); + if (!ubuf) + return -ENOMEM; + + for (i = 0; i < head->count; i++) { + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) + goto err_free_ubuf; + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) + goto err_free_ubuf; + ubuf->pagecount += list[i].size >> PAGE_SHIFT; + } + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), + GFP_KERNEL); + if (!ubuf->pages) { + ret = -ENOMEM; + goto err_free_ubuf; + } + + pgbuf = 0; + for (i = 0; i < head->count; i++) { + memfd = fget(list[i].memfd); + if (!memfd) + goto err_put_pages; + if (!shmem_mapping(file_inode(memfd)->i_mapping)) + goto err_put_pages; + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); + if (seals == -EINVAL || + (seals & SEALS_WANTED) != SEALS_WANTED || + (seals & SEALS_DENIED) != 0) + goto err_put_pages; + pgoff = list[i].offset >> PAGE_SHIFT; + pgcnt = list[i].size >> PAGE_SHIFT; + for (pgidx = 0; pgidx < pgcnt; pgidx++) { + page = shmem_read_mapping_page( + file_inode(memfd)->i_mapping, pgoff + pgidx); + if (IS_ERR(page)) { + ret = PTR_ERR(page); + goto err_put_pages; + } + ubuf->pages[pgbuf++] = page; + } + fput(memfd); + } + memfd = NULL; + + exp_info.ops = &udmabuf_ops; + exp_info.size = ubuf->pagecount << PAGE_SHIFT; + exp_info.priv = ubuf; + + buf = dma_buf_export(&exp_info); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto err_put_pages; + } + + flags = 0; + if (head->flags & UDMABUF_FLAGS_CLOEXEC) + flags |= O_CLOEXEC; + return dma_buf_fd(buf, flags); + +err_put_pages: + while (pgbuf > 0) + put_page(ubuf->pages[--pgbuf]); +err_free_ubuf: + fput(memfd); + kfree(ubuf->pages); + kfree(ubuf); + return ret; +} + +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) +{ + struct udmabuf_create create; + struct udmabuf_create_list head; + struct udmabuf_create_item list; + + if (copy_from_user(&create, (void __user *)arg, + sizeof(struct udmabuf_create))) + return -EFAULT; + + head.flags = create.flags; + head.count = 1; + list.memfd = create.memfd; + list.offset = create.offset; + list.size = create.size; + + return udmabuf_create(&head, &list); +} + +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) +{ + struct udmabuf_create_list head; + struct udmabuf_create_item *list; + int ret = -EINVAL; + u32 lsize; + + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) + return -EFAULT; + if (head.count > 1024) + return -EINVAL; + lsize = sizeof(struct udmabuf_create_item) * head.count; + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); + if (IS_ERR(list)) + return PTR_ERR(list); + + ret = udmabuf_create(&head, list); + kfree(list); + return ret; +} + +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg) +{ + long ret; + + switch (ioctl) { + case UDMABUF_CREATE: + ret = udmabuf_ioctl_create(filp, arg); + break; + case UDMABUF_CREATE_LIST: + ret = udmabuf_ioctl_create_list(filp, arg); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static const struct file_operations udmabuf_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = udmabuf_ioctl, +}; + +static struct miscdevice udmabuf_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "udmabuf", + .fops = &udmabuf_fops, +}; + +static int __init udmabuf_dev_init(void) +{ + return misc_register(&udmabuf_misc); +} + +static void __exit udmabuf_dev_exit(void) +{ + misc_deregister(&udmabuf_misc); +} + +module_init(udmabuf_dev_init) +module_exit(udmabuf_dev_exit) + +MODULE_AUTHOR("Gerd Hoffmann "); +MODULE_LICENSE("GPL v2"); diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h new file mode 100644 index 000000000000..46b6532ed855 --- /dev/null +++ b/include/uapi/linux/udmabuf.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_UDMABUF_H +#define _UAPI_LINUX_UDMABUF_H + +#include +#include + +#define UDMABUF_FLAGS_CLOEXEC 0x01 + +struct udmabuf_create { + __u32 memfd; + __u32 flags; + __u64 offset; + __u64 size; +}; + +struct udmabuf_create_item { + __u32 memfd; + __u32 __pad; + __u64 offset; + __u64 size; +}; + +struct udmabuf_create_list { + __u32 flags; + __u32 count; + struct udmabuf_create_item list[]; +}; + +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) + +#endif /* _UAPI_LINUX_UDMABUF_H */ diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile new file mode 100644 index 000000000000..4154c3d7aa58 --- /dev/null +++ b/tools/testing/selftests/drivers/dma-buf/Makefile @@ -0,0 +1,5 @@ +CFLAGS += -I../../../../../usr/include/ + +TEST_GEN_PROGS := udmabuf + +include ../../lib.mk diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c new file mode 100644 index 000000000000..376b1d6730bd --- /dev/null +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TEST_PREFIX "drivers/dma-buf/udmabuf" +#define NUM_PAGES 4 + +static int memfd_create(const char *name, unsigned int flags) +{ + return syscall(__NR_memfd_create, name, flags); +} + +int main(int argc, char *argv[]) +{ + struct udmabuf_create create; + int devfd, memfd, buf, ret; + off_t size; + void *mem; + + devfd = open("/dev/udmabuf", O_RDWR); + if (devfd < 0) { + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); + exit(77); + } + + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); + if (memfd < 0) { + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); + exit(77); + } + + size = getpagesize() * NUM_PAGES; + ret = ftruncate(memfd, size); + if (ret == -1) { + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); + exit(1); + } + + memset(&create, 0, sizeof(create)); + + /* should fail (offset not page aligned) */ + create.memfd = memfd; + create.offset = getpagesize()/2; + create.size = getpagesize(); + buf = ioctl(devfd, UDMABUF_CREATE, &create); + if (buf >= 0) { + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); + exit(1); + } + + /* should fail (size not multiple of page) */ + create.memfd = memfd; + create.offset = 0; + create.size = getpagesize()/2; + buf = ioctl(devfd, UDMABUF_CREATE, &create); + if (buf >= 0) { + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); + exit(1); + } + + /* should fail (not memfd) */ + create.memfd = 0; /* stdin */ + create.offset = 0; + create.size = size; + buf = ioctl(devfd, UDMABUF_CREATE, &create); + if (buf >= 0) { + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); + exit(1); + } + + /* should work */ + create.memfd = memfd; + create.offset = 0; + create.size = size; + buf = ioctl(devfd, UDMABUF_CREATE, &create); + if (buf < 0) { + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); + exit(1); + } + + fprintf(stderr, "%s: ok\n", TEST_PREFIX); + close(buf); + close(memfd); + close(devfd); + return 0; +} -- cgit v1.2.3 From b9a40816fef79a6053b9d601f50e852acdaafebd Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Tue, 4 Sep 2018 09:45:05 +0530 Subject: Document/gpu: Use new vm_fault_t type We have introduce new return type vm_fault_t for fault handler. Update the document for the same. Signed-off-by: Souptick Joarder Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180904041505.GA2712@jordon-HP-15-Notebook-PC --- Documentation/gpu/drm-mm.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 21b6b72a9ba8..c3ae888b92ef 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -297,7 +297,7 @@ made up of several fields, the more interesting ones being: struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); - int (*fault)(struct vm_fault *vmf); + vm_fault_t (*fault)(struct vm_fault *vmf); }; -- cgit v1.2.3 From 69517c1798f31232f91d9b4f3d07540f9aea6a07 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 4 Sep 2018 12:40:45 +0800 Subject: dt-bindings: display: Add compatible for A64 DE2 display pipeline Allwinner A64 has a DE2 display pipeline. The TCONs are similar to the ones in A83T, but the mixers are new (similar to the later R40 SoC). This patch adds dt-binding documentation for A64 DE2 display pipeline. Signed-off-by: Jagan Teki Reviewed-by: Rob Herring [Icenowy: Refactor and also cover TCON1] Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180904044053.15425-4-icenowy@aosc.io --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index f8773ecb7525..7b79c5e3dffc 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -151,6 +151,8 @@ Required properties: * allwinner,sun8i-v3s-tcon * allwinner,sun9i-a80-tcon-lcd * allwinner,sun9i-a80-tcon-tv + * "allwinner,sun50i-a64-tcon-lcd", "allwinner,sun8i-a83t-tcon-lcd" + * "allwinner,sun50i-a64-tcon-tv", "allwinner,sun8i-a83t-tcon-tv" - reg: base address and size of memory-mapped region - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the TCON. @@ -370,6 +372,8 @@ Required properties: * allwinner,sun8i-a83t-de2-mixer-1 * allwinner,sun8i-h3-de2-mixer-0 * allwinner,sun8i-v3s-de2-mixer + * allwinner,sun50i-a64-de2-mixer-0 + * allwinner,sun50i-a64-de2-mixer-1 - reg: base address and size of the memory-mapped region. - clocks: phandles to the clocks feeding the mixer * bus: the mixer interface clock @@ -403,6 +407,7 @@ Required properties: * allwinner,sun8i-r40-display-engine * allwinner,sun8i-v3s-display-engine * allwinner,sun9i-a80-display-engine + * allwinner,sun50i-a64-display-engine - allwinner,pipelines: list of phandle to the display engine frontends (DE 1.0) or mixers (DE 2.0) available. -- cgit v1.2.3 From d9ac59978d0dab5c4e2141cd7d62edcbd79434ce Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 4 Sep 2018 12:40:48 +0800 Subject: dt-bindings: display: Add compatible for A64 HDMI The HDMI controller on Allwinner A64 is similar on the one on H3/H5/A83T (although the PHY is different with A83T). Add A64 compatible and append A83T compatible as fallback. Signed-off-by: Jagan Teki Reviewed-by: Rob Herring [Icenowy: refactor commit log] Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180904044053.15425-7-icenowy@aosc.io --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 7b79c5e3dffc..fdb8fb29033f 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -78,6 +78,7 @@ Required properties: - compatible: value must be one of: * "allwinner,sun8i-a83t-dw-hdmi" + * "allwinner,sun50i-a64-dw-hdmi", "allwinner,sun8i-a83t-dw-hdmi" - reg: base address and size of memory-mapped region - reg-io-width: See dw_hdmi.txt. Shall be 1. - interrupts: HDMI interrupt number -- cgit v1.2.3 From 50414b954ba647693db655fb753811dc895e8cbe Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 4 Sep 2018 12:40:51 +0800 Subject: dt-bindings: sun4i-drm: add HDMI VCC supply property for sun8i-dw-hdmi Allwiner SoCs with DesignWare HDMI controller all come with a "HVCC" pin, which is the VCC of HDMI part. Add a supply property to specify HVCC's regulator in the device tree. Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180904044053.15425-10-icenowy@aosc.io --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index fdb8fb29033f..0bbb5d47f228 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -97,6 +97,9 @@ Required properties: first port should be the input endpoint. The second should be the output, usually to an HDMI connector. +Optional properties: + - hvcc-supply: the VCC power supply of the controller + DWC HDMI PHY ------------ -- cgit v1.2.3 From 428e15cc41e3603942edd4a1aa991127ce9eccea Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 30 Aug 2018 13:09:37 +0200 Subject: drm/rockchip: vop: add rk3188 vop definitions The rk3188 has 2 vops not using iommus which only output directly to a rgb interface per vop. So all other output modes like hdmi are provided by external brige chips. Signed-off-by: Heiko Stuebner Reviewed-by: Sandy Huang Acked-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20180830110937.1739-1-heiko@sntech.de --- .../bindings/display/rockchip/rockchip-vop.txt | 1 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 89 ++++++++++++++++++++++ drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 25 ++++++ 3 files changed, 115 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt index 5de2a0f0d1f4..b79e5769f0ae 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt @@ -10,6 +10,7 @@ Required properties: "rockchip,rk3126-vop"; "rockchip,px30-vop-lit"; "rockchip,px30-vop-big"; + "rockchip,rk3188-vop"; "rockchip,rk3288-vop"; "rockchip,rk3368-vop"; "rockchip,rk3366-vop"; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 09910d3b01ce..a6db3cd5544b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -299,6 +299,93 @@ static const struct vop_data px30_vop_lit = { .win_size = ARRAY_SIZE(px30_vop_lit_win_data), }; +static const struct vop_scl_regs rk3188_win_scl = { + .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy rk3188_win0_data = { + .scl = &rk3188_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0), + .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3), + .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15), + .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0), +}; + +static const struct vop_win_phy rk3188_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1), + .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6), + .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19), + /* no act_info on window1 */ + .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0), + .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16), +}; + +static const struct vop_modeset rk3188_modeset = { + .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output rk3188_output = { + .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4), +}; + +static const struct vop_common rk3188_common = { + .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31), + .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30), + .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0), + .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24), +}; + +static const struct vop_win_data rk3188_vop_win_data[] = { + { .base = 0x00, .phy = &rk3188_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3188_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const int rk3188_vop_intrs[] = { + 0, + FS_INTR, + LINE_FLAG_INTR, + BUS_ERROR_INTR, +}; + +static const struct vop_intr rk3188_vop_intr = { + .intrs = rk3188_vop_intrs, + .nintrs = ARRAY_SIZE(rk3188_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12), + .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0), + .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4), + .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8), +}; + +static const struct vop_data rk3188_vop = { + .intr = &rk3188_vop_intr, + .common = &rk3188_common, + .modeset = &rk3188_modeset, + .output = &rk3188_output, + .win = rk3188_vop_win_data, + .win_size = ARRAY_SIZE(rk3188_vop_win_data), + .feature = VOP_FEATURE_INTERNAL_RGB, +}; + static const struct vop_scl_extension rk3288_win_full_scl_ext = { .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), @@ -667,6 +754,8 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &px30_vop_big }, { .compatible = "rockchip,px30-vop-lit", .data = &px30_vop_lit }, + { .compatible = "rockchip,rk3188-vop", + .data = &rk3188_vop }, { .compatible = "rockchip,rk3288-vop", .data = &rk3288_vop }, { .compatible = "rockchip,rk3368-vop", diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 71527cb73295..7348c68352ed 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -958,4 +958,29 @@ #define PX30_GAMMA_LUT_ADDR 0x00a00 /* px30 register definition end */ +/* rk3188 register definition */ +#define RK3188_SYS_CTRL 0x00 +#define RK3188_DSP_CTRL0 0x04 +#define RK3188_DSP_CTRL1 0x08 +#define RK3188_INT_STATUS 0x10 +#define RK3188_WIN0_YRGB_MST0 0x20 +#define RK3188_WIN0_CBR_MST0 0x24 +#define RK3188_WIN0_YRGB_MST1 0x28 +#define RK3188_WIN0_CBR_MST1 0x2c +#define RK3188_WIN_VIR 0x30 +#define RK3188_WIN0_ACT_INFO 0x34 +#define RK3188_WIN0_DSP_INFO 0x38 +#define RK3188_WIN0_DSP_ST 0x3c +#define RK3188_WIN0_SCL_FACTOR_YRGB 0x40 +#define RK3188_WIN0_SCL_FACTOR_CBR 0x44 +#define RK3188_WIN1_MST 0x4c +#define RK3188_WIN1_DSP_INFO 0x50 +#define RK3188_WIN1_DSP_ST 0x54 +#define RK3188_DSP_HTOTAL_HS_END 0x6c +#define RK3188_DSP_HACT_ST_END 0x70 +#define RK3188_DSP_VTOTAL_VS_END 0x74 +#define RK3188_DSP_VACT_ST_END 0x78 +#define RK3188_REG_CFG_DONE 0x90 +/* rk3188 register definition end */ + #endif /* _ROCKCHIP_VOP_REG_H */ -- cgit v1.2.3 From d86552efe10a321a78ab3d093bbe9b8ecf778c4e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Sep 2018 15:57:09 +0200 Subject: drm/atomic: trim driver interface/docs Remove the kerneldoc and EXPORT_SYMBOL which aren't used and really shouldn't ever be used by drivers directly. Unfortunately this means we need to move the set_writeback_fb function around to avoid a forward decl. Acked-by: Heiko Stuebner Signed-off-by: Daniel Vetter Cc: David Airlie Cc: Gustavo Padovan Cc: Maarten Lankhorst Cc: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20180905135711.28370-5-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 3 - drivers/gpu/drm/drm_atomic.c | 219 +++++++----------------------------------- include/drm/drm_atomic.h | 6 -- 3 files changed, 34 insertions(+), 194 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index f8f5bf11a6ca..3a9dd68b97c9 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -287,9 +287,6 @@ Atomic Mode Setting Function Reference .. kernel-doc:: drivers/gpu/drm/drm_atomic.c :export: -.. kernel-doc:: drivers/gpu/drm/drm_atomic.c - :internal: - CRTC Abstraction ================ diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index d0478abc01bd..f2c505d8ea57 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -464,30 +464,6 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, } EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); -/** - * drm_atomic_replace_property_blob_from_id - lookup the new blob and replace the old one with it - * @dev: DRM device - * @blob: a pointer to the member blob to be replaced - * @blob_id: ID of the new blob - * @expected_size: total expected size of the blob data (in bytes) - * @expected_elem_size: expected element size of the blob data (in bytes) - * @replaced: did the blob get replaced? - * - * Replace @blob with another blob with the ID @blob_id. If @blob_id is zero - * @blob becomes NULL. - * - * If @expected_size is positive the new blob length is expected to be equal - * to @expected_size bytes. If @expected_elem_size is positive the new blob - * length is expected to be a multiple of @expected_elem_size bytes. Otherwise - * an error is returned. - * - * @replaced will indicate to the caller whether the blob was replaced or not. - * If the old and new blobs were in fact the same blob @replaced will be false - * otherwise it will be true. - * - * RETURNS: - * Zero on success, error code on failure. - */ static int drm_atomic_replace_property_blob_from_id(struct drm_device *dev, struct drm_property_blob **blob, @@ -521,22 +497,7 @@ drm_atomic_replace_property_blob_from_id(struct drm_device *dev, return 0; } -/** - * drm_atomic_crtc_set_property - set property on CRTC - * @crtc: the drm CRTC to set a property on - * @state: the state object to update with the new property value - * @property: the property to set - * @val: the new property value - * - * This function handles generic/core properties and calls out to driver's - * &drm_crtc_funcs.atomic_set_property for driver properties. To ensure - * consistent behavior you must call this function rather than the driver hook - * directly. - * - * RETURNS: - * Zero on success, error code on failure - */ -int drm_atomic_crtc_set_property(struct drm_crtc *crtc, +static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { @@ -598,23 +559,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, return 0; } -EXPORT_SYMBOL(drm_atomic_crtc_set_property); -/** - * drm_atomic_crtc_get_property - get property value from CRTC state - * @crtc: the drm CRTC to set a property on - * @state: the state object to get the property value from - * @property: the property to set - * @val: return location for the property value - * - * This function handles generic/core properties and calls out to driver's - * &drm_crtc_funcs.atomic_get_property for driver properties. To ensure - * consistent behavior you must call this function rather than the driver hook - * directly. - * - * RETURNS: - * Zero on success, error code on failure - */ static int drm_atomic_crtc_get_property(struct drm_crtc *crtc, const struct drm_crtc_state *state, @@ -643,16 +588,6 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, return 0; } -/** - * drm_atomic_crtc_check - check crtc state - * @crtc: crtc to check - * @state: crtc state to check - * - * Provides core sanity checks for crtc state. - * - * RETURNS: - * Zero on success, error code on failure - */ static int drm_atomic_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -728,16 +663,6 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p, crtc->funcs->atomic_print_state(p, state); } -/** - * drm_atomic_connector_check - check connector state - * @connector: connector to check - * @state: connector state to check - * - * Provides core sanity checks for connector state. - * - * RETURNS: - * Zero on success, error code on failure - */ static int drm_atomic_connector_check(struct drm_connector *connector, struct drm_connector_state *state) { @@ -923,21 +848,6 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, return 0; } -/** - * drm_atomic_plane_get_property - get property value from plane state - * @plane: the drm plane to set a property on - * @state: the state object to get the property value from - * @property: the property to set - * @val: return location for the property value - * - * This function handles generic/core properties and calls out to driver's - * &drm_plane_funcs.atomic_get_property for driver properties. To ensure - * consistent behavior you must call this function rather than the driver hook - * directly. - * - * RETURNS: - * Zero on success, error code on failure - */ static int drm_atomic_plane_get_property(struct drm_plane *plane, const struct drm_plane_state *state, @@ -1328,21 +1238,39 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_connector_state); -/** - * drm_atomic_connector_set_property - set property on connector. - * @connector: the drm connector to set a property on - * @state: the state object to update with the new property value - * @property: the property to set - * @val: the new property value - * - * This function handles generic/core properties and calls out to driver's - * &drm_connector_funcs.atomic_set_property for driver properties. To ensure - * consistent behavior you must call this function rather than the driver hook - * directly. - * - * RETURNS: - * Zero on success, error code on failure - */ +static struct drm_writeback_job * +drm_atomic_get_writeback_job(struct drm_connector_state *conn_state) +{ + WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); + + if (!conn_state->writeback_job) + conn_state->writeback_job = + kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); + + return conn_state->writeback_job; +} + +static int drm_atomic_set_writeback_fb_for_connector( + struct drm_connector_state *conn_state, + struct drm_framebuffer *fb) +{ + struct drm_writeback_job *job = + drm_atomic_get_writeback_job(conn_state); + if (!job) + return -ENOMEM; + + drm_framebuffer_assign(&job->fb, fb); + + if (fb) + DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", + fb->base.id, conn_state); + else + DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n", + conn_state); + + return 0; +} + static int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, uint64_t val) @@ -1449,21 +1377,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } -/** - * drm_atomic_connector_get_property - get property value from connector state - * @connector: the drm connector to set a property on - * @state: the state object to get the property value from - * @property: the property to set - * @val: return location for the property value - * - * This function handles generic/core properties and calls out to driver's - * &drm_connector_funcs.atomic_get_property for driver properties. To ensure - * consistent behavior you must call this function rather than the driver hook - * directly. - * - * RETURNS: - * Zero on success, error code on failure - */ static int drm_atomic_connector_get_property(struct drm_connector *connector, const struct drm_connector_state *state, @@ -1739,70 +1652,6 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, } EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); -/* - * drm_atomic_get_writeback_job - return or allocate a writeback job - * @conn_state: Connector state to get the job for - * - * Writeback jobs have a different lifetime to the atomic state they are - * associated with. This convenience function takes care of allocating a job - * if there isn't yet one associated with the connector state, otherwise - * it just returns the existing job. - * - * Returns: The writeback job for the given connector state - */ -static struct drm_writeback_job * -drm_atomic_get_writeback_job(struct drm_connector_state *conn_state) -{ - WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); - - if (!conn_state->writeback_job) - conn_state->writeback_job = - kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); - - return conn_state->writeback_job; -} - -/** - * drm_atomic_set_writeback_fb_for_connector - set writeback framebuffer - * @conn_state: atomic state object for the connector - * @fb: fb to use for the connector - * - * This is used to set the framebuffer for a writeback connector, which outputs - * to a buffer instead of an actual physical connector. - * Changing the assigned framebuffer requires us to grab a reference to the new - * fb and drop the reference to the old fb, if there is one. This function - * takes care of all these details besides updating the pointer in the - * state object itself. - * - * Note: The only way conn_state can already have an fb set is if the commit - * sets the property more than once. - * - * See also: drm_writeback_connector_init() - * - * Returns: 0 on success - */ -int drm_atomic_set_writeback_fb_for_connector( - struct drm_connector_state *conn_state, - struct drm_framebuffer *fb) -{ - struct drm_writeback_job *job = - drm_atomic_get_writeback_job(conn_state); - if (!job) - return -ENOMEM; - - drm_framebuffer_assign(&job->fb, fb); - - if (fb) - DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", - fb->base.id, conn_state); - else - DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n", - conn_state); - - return 0; -} -EXPORT_SYMBOL(drm_atomic_set_writeback_fb_for_connector); - /** * drm_atomic_add_affected_connectors - add connectors for crtc * @state: atomic state diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index d621232a469a..93d29af34024 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -374,9 +374,6 @@ void drm_atomic_state_default_release(struct drm_atomic_state *state); struct drm_crtc_state * __must_check drm_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc *crtc); -int drm_atomic_crtc_set_property(struct drm_crtc *crtc, - struct drm_crtc_state *state, struct drm_property *property, - uint64_t val); struct drm_plane_state * __must_check drm_atomic_get_plane_state(struct drm_atomic_state *state, struct drm_plane *plane); @@ -603,9 +600,6 @@ void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, int __must_check drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, struct drm_crtc *crtc); -int drm_atomic_set_writeback_fb_for_connector( - struct drm_connector_state *conn_state, - struct drm_framebuffer *fb); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); -- cgit v1.2.3 From 2ec04b33a96fe954701ceecfd0b489978f667b34 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Sep 2018 20:15:09 +0200 Subject: drm: Update todo.rst - drmP.h is now fully split up. - vkms is happening (and will gain its own todo and docs under a new vkms.rst file real soon) - legacy cruft is completely hidden now, drm_vblank.c is split out from drm_irq.c now. I've decided to drop the task to split out drm_legacy.ko, partially because Dave already rejected a patch to hide the old dri1 drivers better. Current state feels good enough to me. - best_encoder atomic cleanup is done (it's now the default, not even exported anymore) - bunch of smaller things v2: - Explain why the drm_legacy.ko task is dropped (Emil). - typos (Sam). v3: Fix typo (Ilia) Reviewed-by: Emil Velikov Reviewed-by: Heiko Stuebner Cc: Ilia Mirkin Cc: Sam Ravnborg Cc: Emil Velikov Signed-off-by: Daniel Vetter Cc: Gustavo Padovan Cc: Maarten Lankhorst Cc: Sean Paul Cc: David Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20180905181509.19530-1-daniel.vetter@ffwll.ch --- Documentation/gpu/todo.rst | 68 +++++++--------------------------------------- 1 file changed, 10 insertions(+), 58 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index a7c150d6b63f..4c7c3ab60089 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -127,7 +127,8 @@ interfaces to fix these issues: the acquire context explicitly on stack and then also pass it down into drivers explicitly so that the legacy-on-atomic functions can use them. - Except for some driver code this is done. + Except for some driver code this is done. This task should be finished by + adding WARN_ON(!drm_drv_uses_atomic_modeset) in drm_modeset_lock_all(). * A bunch of the vtable hooks are now in the wrong place: DRM has a split between core vfunc tables (named ``drm_foo_funcs``), which are used to @@ -137,13 +138,6 @@ interfaces to fix these issues: ``_helper_funcs`` since they are not part of the core ABI. There's a ``FIXME`` comment in the kerneldoc for each such case in ``drm_crtc.h``. -* There's a new helper ``drm_atomic_helper_best_encoder()`` which could be - used by all atomic drivers which don't select the encoder for a given - connector at runtime. That's almost all of them, and would allow us to get - rid of a lot of ``best_encoder`` boilerplate in drivers. - - This was almost done, but new drivers added a few more cases again. - Contact: Daniel Vetter Get rid of dev->struct_mutex from GEM drivers @@ -164,9 +158,8 @@ private lock. The tricky part is the BO free functions, since those can't reliably take that lock any more. Instead state needs to be protected with suitable subordinate locks or some cleanup work pushed to a worker thread. For performance-critical drivers it might also be better to go with a more -fine-grained per-buffer object and per-context lockings scheme. Currently the -following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and -``udl``. +fine-grained per-buffer object and per-context lockings scheme. Currently only the +``msm`` driver still use ``struct_mutex``. Contact: Daniel Vetter, respective driver maintainers @@ -190,7 +183,8 @@ Convert drivers to use simple modeset suspend/resume Most drivers (except i915 and nouveau) that use drm_atomic_helper_suspend/resume() can probably be converted to use -drm_mode_config_helper_suspend/resume(). +drm_mode_config_helper_suspend/resume(). Also there's still open-coded version +of the atomic suspend/resume code in older atomic modeset drivers. Contact: Maintainer of the driver you plan to convert @@ -246,20 +240,10 @@ Core refactorings Clean up the DRM header mess ---------------------------- -Currently the DRM subsystem has only one global header, ``drmP.h``. This is -used both for functions exported to helper libraries and drivers and functions -only used internally in the ``drm.ko`` module. The goal would be to move all -header declarations not needed outside of ``drm.ko`` into -``drivers/gpu/drm/drm_*_internal.h`` header files. ``EXPORT_SYMBOL`` also -needs to be dropped for these functions. - -This would nicely tie in with the below task to create kerneldoc after the API -is cleaned up. Or with the "hide legacy cruft better" task. - -Note that this is well in progress, but ``drmP.h`` is still huge. The updated -plan is to switch to per-file driver API headers, which will also structure -the kerneldoc better. This should also allow more fine-grained ``#include`` -directives. +The DRM subsystem originally had only one huge global header, ``drmP.h``. This +is now split up, but many source files still include it. The remaining part of +the cleanup work here is to replace any ``#include `` by only the +headers needed (and fixing up any missing pre-declarations in the headers). In the end no .c file should need to include ``drmP.h`` anymore. @@ -278,26 +262,6 @@ See https://dri.freedesktop.org/docs/drm/ for what's there already. Contact: Daniel Vetter -Hide legacy cruft better ------------------------- - -Way back DRM supported only drivers which shadow-attached to PCI devices with -userspace or fbdev drivers setting up outputs. Modern DRM drivers take charge -of the entire device, you can spot them with the DRIVER_MODESET flag. - -Unfortunately there's still large piles of legacy code around which needs to -be hidden so that driver writers don't accidentally end up using it. And to -prevent security issues in those legacy IOCTLs from being exploited on modern -drivers. This has multiple possible subtasks: - -* Extract support code for legacy features into a ``drm-legacy.ko`` kernel - module and compile it only when one of the legacy drivers is enabled. - -This is mostly done, the only thing left is to split up ``drm_irq.c`` into -legacy cruft and the parts needed by modern KMS drivers. - -Contact: Daniel Vetter - Make panic handling work ------------------------ @@ -398,18 +362,6 @@ the non-i915 specific modeset tests. Contact: Daniel Vetter -Create a virtual KMS driver for testing (vkms) ----------------------------------------------- - -With all the latest helpers it should be fairly simple to create a virtual KMS -driver useful for testing, or for running X or similar on headless machines -(to be able to still use the GPU). This would be similar to vgem, but aimed at -the modeset side. - -Once the basics are there there's tons of possibilities to extend it. - -Contact: Daniel Vetter - Driver Specific =============== -- cgit v1.2.3 From 72fdb40c1a4b48f5fa6f6083ea7419b94639ed57 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Sep 2018 15:57:11 +0200 Subject: drm: extract drm_atomic_uapi.c This leaves all the commit/check and state handling in drm_atomic.c, while pulling all the uapi glue and the huge ioctl itself into a seprate file. This seems to almost perfectly split the rather big drm_atomic.c file into 2 equal sizes. Also adjust the kerneldoc and type a very terse overview text. v2: Rebase. v3: Fix tiny typo. v4: - Fixup armada, newly converted atomic driver hooray! - Fixup msm/dpu1, newly added too. Signed-off-by: Daniel Vetter Cc: David Airlie Cc: Gustavo Padovan Cc: Maarten Lankhorst Cc: Sean Paul Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Rob Clark Cc: Eric Anholt Cc: intel-gfx@lists.freedesktop.org Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Acked-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20180905135711.28370-7-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 11 +- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/armada/armada_overlay.c | 1 + drivers/gpu/drm/drm_atomic.c | 1359 +------------------------ drivers/gpu/drm/drm_atomic_helper.c | 1 + drivers/gpu/drm/drm_atomic_uapi.c | 1393 ++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc_helper.c | 1 + drivers/gpu/drm/drm_crtc_internal.h | 5 + drivers/gpu/drm/drm_framebuffer.c | 1 + drivers/gpu/drm/drm_gem_framebuffer_helper.c | 1 + drivers/gpu/drm/drm_plane_helper.c | 1 + drivers/gpu/drm/i915/intel_display.c | 1 + drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 2 + drivers/gpu/drm/msm/msm_atomic.c | 2 + drivers/gpu/drm/vc4/vc4_crtc.c | 1 + drivers/gpu/drm/vc4/vc4_plane.c | 1 + include/drm/drm_atomic.h | 16 - include/drm/drm_atomic_uapi.h | 58 ++ 18 files changed, 1483 insertions(+), 1375 deletions(-) create mode 100644 drivers/gpu/drm/drm_atomic_uapi.c create mode 100644 include/drm/drm_atomic_uapi.h (limited to 'Documentation') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 3a9dd68b97c9..4b1501b4835b 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -287,6 +287,15 @@ Atomic Mode Setting Function Reference .. kernel-doc:: drivers/gpu/drm/drm_atomic.c :export: +Atomic Mode Setting IOCTL and UAPI Functions +-------------------------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c + :doc: overview + +.. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c + :export: + CRTC Abstraction ================ @@ -563,7 +572,7 @@ Tile Group Property Explicit Fencing Properties --------------------------- -.. kernel-doc:: drivers/gpu/drm/drm_atomic.c +.. kernel-doc:: drivers/gpu/drm/drm_atomic_uapi.c :doc: explicit fencing properties Existing KMS Properties diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index a6771cef85e2..bc6a16a3c36e 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -18,7 +18,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_encoder.o drm_mode_object.o drm_property.o \ drm_plane.o drm_color_mgmt.o drm_print.o \ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ - drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o + drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ + drm_atomic_uapi.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_DRM_VM) += drm_vm.o diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index eb7dfb65ef47..8d770641fcc4 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f2c505d8ea57..7ada75919756 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -309,285 +310,6 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_crtc_state); -static void set_out_fence_for_crtc(struct drm_atomic_state *state, - struct drm_crtc *crtc, s32 __user *fence_ptr) -{ - state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr; -} - -static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, - struct drm_crtc *crtc) -{ - s32 __user *fence_ptr; - - fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr; - state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL; - - return fence_ptr; -} - -static int set_out_fence_for_connector(struct drm_atomic_state *state, - struct drm_connector *connector, - s32 __user *fence_ptr) -{ - unsigned int index = drm_connector_index(connector); - - if (!fence_ptr) - return 0; - - if (put_user(-1, fence_ptr)) - return -EFAULT; - - state->connectors[index].out_fence_ptr = fence_ptr; - - return 0; -} - -static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, - struct drm_connector *connector) -{ - unsigned int index = drm_connector_index(connector); - s32 __user *fence_ptr; - - fence_ptr = state->connectors[index].out_fence_ptr; - state->connectors[index].out_fence_ptr = NULL; - - return fence_ptr; -} - -/** - * drm_atomic_set_mode_for_crtc - set mode for CRTC - * @state: the CRTC whose incoming state to update - * @mode: kernel-internal mode to use for the CRTC, or NULL to disable - * - * Set a mode (originating from the kernel) on the desired CRTC state and update - * the enable property. - * - * RETURNS: - * Zero on success, error code on failure. Cannot return -EDEADLK. - */ -int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, - const struct drm_display_mode *mode) -{ - struct drm_crtc *crtc = state->crtc; - struct drm_mode_modeinfo umode; - - /* Early return for no change. */ - if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) - return 0; - - drm_property_blob_put(state->mode_blob); - state->mode_blob = NULL; - - if (mode) { - drm_mode_convert_to_umode(&umode, mode); - state->mode_blob = - drm_property_create_blob(state->crtc->dev, - sizeof(umode), - &umode); - if (IS_ERR(state->mode_blob)) - return PTR_ERR(state->mode_blob); - - drm_mode_copy(&state->mode, mode); - state->enable = true; - DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", - mode->name, crtc->base.id, crtc->name, state); - } else { - memset(&state->mode, 0, sizeof(state->mode)); - state->enable = false; - DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n", - crtc->base.id, crtc->name, state); - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); - -/** - * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC - * @state: the CRTC whose incoming state to update - * @blob: pointer to blob property to use for mode - * - * Set a mode (originating from a blob property) on the desired CRTC state. - * This function will take a reference on the blob property for the CRTC state, - * and release the reference held on the state's existing mode property, if any - * was set. - * - * RETURNS: - * Zero on success, error code on failure. Cannot return -EDEADLK. - */ -int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, - struct drm_property_blob *blob) -{ - struct drm_crtc *crtc = state->crtc; - - if (blob == state->mode_blob) - return 0; - - drm_property_blob_put(state->mode_blob); - state->mode_blob = NULL; - - memset(&state->mode, 0, sizeof(state->mode)); - - if (blob) { - int ret; - - if (blob->length != sizeof(struct drm_mode_modeinfo)) { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] bad mode blob length: %zu\n", - crtc->base.id, crtc->name, - blob->length); - return -EINVAL; - } - - ret = drm_mode_convert_umode(crtc->dev, - &state->mode, blob->data); - if (ret) { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n", - crtc->base.id, crtc->name, - ret, drm_get_mode_status_name(state->mode.status)); - drm_mode_debug_printmodeline(&state->mode); - return -EINVAL; - } - - state->mode_blob = drm_property_blob_get(blob); - state->enable = true; - DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", - state->mode.name, crtc->base.id, crtc->name, - state); - } else { - state->enable = false; - DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n", - crtc->base.id, crtc->name, state); - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); - -static int -drm_atomic_replace_property_blob_from_id(struct drm_device *dev, - struct drm_property_blob **blob, - uint64_t blob_id, - ssize_t expected_size, - ssize_t expected_elem_size, - bool *replaced) -{ - struct drm_property_blob *new_blob = NULL; - - if (blob_id != 0) { - new_blob = drm_property_lookup_blob(dev, blob_id); - if (new_blob == NULL) - return -EINVAL; - - if (expected_size > 0 && - new_blob->length != expected_size) { - drm_property_blob_put(new_blob); - return -EINVAL; - } - if (expected_elem_size > 0 && - new_blob->length % expected_elem_size != 0) { - drm_property_blob_put(new_blob); - return -EINVAL; - } - } - - *replaced |= drm_property_replace_blob(blob, new_blob); - drm_property_blob_put(new_blob); - - return 0; -} - -static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, - struct drm_crtc_state *state, struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = crtc->dev; - struct drm_mode_config *config = &dev->mode_config; - bool replaced = false; - int ret; - - if (property == config->prop_active) - state->active = val; - else if (property == config->prop_mode_id) { - struct drm_property_blob *mode = - drm_property_lookup_blob(dev, val); - ret = drm_atomic_set_mode_prop_for_crtc(state, mode); - drm_property_blob_put(mode); - return ret; - } else if (property == config->degamma_lut_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, - &state->degamma_lut, - val, - -1, sizeof(struct drm_color_lut), - &replaced); - state->color_mgmt_changed |= replaced; - return ret; - } else if (property == config->ctm_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, - &state->ctm, - val, - sizeof(struct drm_color_ctm), -1, - &replaced); - state->color_mgmt_changed |= replaced; - return ret; - } else if (property == config->gamma_lut_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, - &state->gamma_lut, - val, - -1, sizeof(struct drm_color_lut), - &replaced); - state->color_mgmt_changed |= replaced; - return ret; - } else if (property == config->prop_out_fence_ptr) { - s32 __user *fence_ptr = u64_to_user_ptr(val); - - if (!fence_ptr) - return 0; - - if (put_user(-1, fence_ptr)) - return -EFAULT; - - set_out_fence_for_crtc(state->state, crtc, fence_ptr); - } else if (crtc->funcs->atomic_set_property) { - return crtc->funcs->atomic_set_property(crtc, state, property, val); - } else { - DRM_DEBUG_ATOMIC("[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n", - crtc->base.id, crtc->name, - property->base.id, property->name); - return -EINVAL; - } - - return 0; -} - -static int -drm_atomic_crtc_get_property(struct drm_crtc *crtc, - const struct drm_crtc_state *state, - struct drm_property *property, uint64_t *val) -{ - struct drm_device *dev = crtc->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (property == config->prop_active) - *val = state->active; - else if (property == config->prop_mode_id) - *val = (state->mode_blob) ? state->mode_blob->base.id : 0; - else if (property == config->degamma_lut_property) - *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; - else if (property == config->ctm_property) - *val = (state->ctm) ? state->ctm->base.id : 0; - else if (property == config->gamma_lut_property) - *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; - else if (property == config->prop_out_fence_ptr) - *val = 0; - else if (crtc->funcs->atomic_get_property) - return crtc->funcs->atomic_get_property(crtc, state, property, val); - else - return -EINVAL; - - return 0; -} - static int drm_atomic_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -761,144 +483,6 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_plane_state); -/** - * drm_atomic_plane_set_property - set property on plane - * @plane: the drm plane to set a property on - * @state: the state object to update with the new property value - * @property: the property to set - * @val: the new property value - * - * This function handles generic/core properties and calls out to driver's - * &drm_plane_funcs.atomic_set_property for driver properties. To ensure - * consistent behavior you must call this function rather than the driver hook - * directly. - * - * RETURNS: - * Zero on success, error code on failure - */ -static int drm_atomic_plane_set_property(struct drm_plane *plane, - struct drm_plane_state *state, struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = plane->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (property == config->prop_fb_id) { - struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); - drm_atomic_set_fb_for_plane(state, fb); - if (fb) - drm_framebuffer_put(fb); - } else if (property == config->prop_in_fence_fd) { - if (state->fence) - return -EINVAL; - - if (U642I64(val) == -1) - return 0; - - state->fence = sync_file_get_fence(val); - if (!state->fence) - return -EINVAL; - - } else if (property == config->prop_crtc_id) { - struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val); - return drm_atomic_set_crtc_for_plane(state, crtc); - } else if (property == config->prop_crtc_x) { - state->crtc_x = U642I64(val); - } else if (property == config->prop_crtc_y) { - state->crtc_y = U642I64(val); - } else if (property == config->prop_crtc_w) { - state->crtc_w = val; - } else if (property == config->prop_crtc_h) { - state->crtc_h = val; - } else if (property == config->prop_src_x) { - state->src_x = val; - } else if (property == config->prop_src_y) { - state->src_y = val; - } else if (property == config->prop_src_w) { - state->src_w = val; - } else if (property == config->prop_src_h) { - state->src_h = val; - } else if (property == plane->alpha_property) { - state->alpha = val; - } else if (property == plane->blend_mode_property) { - state->pixel_blend_mode = val; - } else if (property == plane->rotation_property) { - if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) { - DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n", - plane->base.id, plane->name, val); - return -EINVAL; - } - state->rotation = val; - } else if (property == plane->zpos_property) { - state->zpos = val; - } else if (property == plane->color_encoding_property) { - state->color_encoding = val; - } else if (property == plane->color_range_property) { - state->color_range = val; - } else if (plane->funcs->atomic_set_property) { - return plane->funcs->atomic_set_property(plane, state, - property, val); - } else { - DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", - plane->base.id, plane->name, - property->base.id, property->name); - return -EINVAL; - } - - return 0; -} - -static int -drm_atomic_plane_get_property(struct drm_plane *plane, - const struct drm_plane_state *state, - struct drm_property *property, uint64_t *val) -{ - struct drm_device *dev = plane->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (property == config->prop_fb_id) { - *val = (state->fb) ? state->fb->base.id : 0; - } else if (property == config->prop_in_fence_fd) { - *val = -1; - } else if (property == config->prop_crtc_id) { - *val = (state->crtc) ? state->crtc->base.id : 0; - } else if (property == config->prop_crtc_x) { - *val = I642U64(state->crtc_x); - } else if (property == config->prop_crtc_y) { - *val = I642U64(state->crtc_y); - } else if (property == config->prop_crtc_w) { - *val = state->crtc_w; - } else if (property == config->prop_crtc_h) { - *val = state->crtc_h; - } else if (property == config->prop_src_x) { - *val = state->src_x; - } else if (property == config->prop_src_y) { - *val = state->src_y; - } else if (property == config->prop_src_w) { - *val = state->src_w; - } else if (property == config->prop_src_h) { - *val = state->src_h; - } else if (property == plane->alpha_property) { - *val = state->alpha; - } else if (property == plane->blend_mode_property) { - *val = state->pixel_blend_mode; - } else if (property == plane->rotation_property) { - *val = state->rotation; - } else if (property == plane->zpos_property) { - *val = state->zpos; - } else if (property == plane->color_encoding_property) { - *val = state->color_encoding; - } else if (property == plane->color_range_property) { - *val = state->color_range; - } else if (plane->funcs->atomic_get_property) { - return plane->funcs->atomic_get_property(plane, state, property, val); - } else { - return -EINVAL; - } - - return 0; -} - static bool plane_switching_crtc(struct drm_atomic_state *state, struct drm_plane *plane, @@ -1238,129 +822,6 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_connector_state); -static struct drm_writeback_job * -drm_atomic_get_writeback_job(struct drm_connector_state *conn_state) -{ - WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); - - if (!conn_state->writeback_job) - conn_state->writeback_job = - kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); - - return conn_state->writeback_job; -} - -static int drm_atomic_set_writeback_fb_for_connector( - struct drm_connector_state *conn_state, - struct drm_framebuffer *fb) -{ - struct drm_writeback_job *job = - drm_atomic_get_writeback_job(conn_state); - if (!job) - return -ENOMEM; - - drm_framebuffer_assign(&job->fb, fb); - - if (fb) - DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", - fb->base.id, conn_state); - else - DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n", - conn_state); - - return 0; -} - -static int drm_atomic_connector_set_property(struct drm_connector *connector, - struct drm_connector_state *state, struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = connector->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (property == config->prop_crtc_id) { - struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val); - return drm_atomic_set_crtc_for_connector(state, crtc); - } else if (property == config->dpms_property) { - /* setting DPMS property requires special handling, which - * is done in legacy setprop path for us. Disallow (for - * now?) atomic writes to DPMS property: - */ - return -EINVAL; - } else if (property == config->tv_select_subconnector_property) { - state->tv.subconnector = val; - } else if (property == config->tv_left_margin_property) { - state->tv.margins.left = val; - } else if (property == config->tv_right_margin_property) { - state->tv.margins.right = val; - } else if (property == config->tv_top_margin_property) { - state->tv.margins.top = val; - } else if (property == config->tv_bottom_margin_property) { - state->tv.margins.bottom = val; - } else if (property == config->tv_mode_property) { - state->tv.mode = val; - } else if (property == config->tv_brightness_property) { - state->tv.brightness = val; - } else if (property == config->tv_contrast_property) { - state->tv.contrast = val; - } else if (property == config->tv_flicker_reduction_property) { - state->tv.flicker_reduction = val; - } else if (property == config->tv_overscan_property) { - state->tv.overscan = val; - } else if (property == config->tv_saturation_property) { - state->tv.saturation = val; - } else if (property == config->tv_hue_property) { - state->tv.hue = val; - } else if (property == config->link_status_property) { - /* Never downgrade from GOOD to BAD on userspace's request here, - * only hw issues can do that. - * - * For an atomic property the userspace doesn't need to be able - * to understand all the properties, but needs to be able to - * restore the state it wants on VT switch. So if the userspace - * tries to change the link_status from GOOD to BAD, driver - * silently rejects it and returns a 0. This prevents userspace - * from accidently breaking the display when it restores the - * state. - */ - if (state->link_status != DRM_LINK_STATUS_GOOD) - state->link_status = val; - } else if (property == config->aspect_ratio_property) { - state->picture_aspect_ratio = val; - } else if (property == config->content_type_property) { - state->content_type = val; - } else if (property == connector->scaling_mode_property) { - state->scaling_mode = val; - } else if (property == connector->content_protection_property) { - if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) { - DRM_DEBUG_KMS("only drivers can set CP Enabled\n"); - return -EINVAL; - } - state->content_protection = val; - } else if (property == config->writeback_fb_id_property) { - struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); - int ret = drm_atomic_set_writeback_fb_for_connector(state, fb); - if (fb) - drm_framebuffer_put(fb); - return ret; - } else if (property == config->writeback_out_fence_ptr_property) { - s32 __user *fence_ptr = u64_to_user_ptr(val); - - return set_out_fence_for_connector(state->state, connector, - fence_ptr); - } else if (connector->funcs->atomic_set_property) { - return connector->funcs->atomic_set_property(connector, - state, property, val); - } else { - DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n", - connector->base.id, connector->name, - property->base.id, property->name); - return -EINVAL; - } - - return 0; -} - static void drm_atomic_connector_print_state(struct drm_printer *p, const struct drm_connector_state *state) { @@ -1377,281 +838,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } -static int -drm_atomic_connector_get_property(struct drm_connector *connector, - const struct drm_connector_state *state, - struct drm_property *property, uint64_t *val) -{ - struct drm_device *dev = connector->dev; - struct drm_mode_config *config = &dev->mode_config; - - if (property == config->prop_crtc_id) { - *val = (state->crtc) ? state->crtc->base.id : 0; - } else if (property == config->dpms_property) { - *val = connector->dpms; - } else if (property == config->tv_select_subconnector_property) { - *val = state->tv.subconnector; - } else if (property == config->tv_left_margin_property) { - *val = state->tv.margins.left; - } else if (property == config->tv_right_margin_property) { - *val = state->tv.margins.right; - } else if (property == config->tv_top_margin_property) { - *val = state->tv.margins.top; - } else if (property == config->tv_bottom_margin_property) { - *val = state->tv.margins.bottom; - } else if (property == config->tv_mode_property) { - *val = state->tv.mode; - } else if (property == config->tv_brightness_property) { - *val = state->tv.brightness; - } else if (property == config->tv_contrast_property) { - *val = state->tv.contrast; - } else if (property == config->tv_flicker_reduction_property) { - *val = state->tv.flicker_reduction; - } else if (property == config->tv_overscan_property) { - *val = state->tv.overscan; - } else if (property == config->tv_saturation_property) { - *val = state->tv.saturation; - } else if (property == config->tv_hue_property) { - *val = state->tv.hue; - } else if (property == config->link_status_property) { - *val = state->link_status; - } else if (property == config->aspect_ratio_property) { - *val = state->picture_aspect_ratio; - } else if (property == config->content_type_property) { - *val = state->content_type; - } else if (property == connector->scaling_mode_property) { - *val = state->scaling_mode; - } else if (property == connector->content_protection_property) { - *val = state->content_protection; - } else if (property == config->writeback_fb_id_property) { - /* Writeback framebuffer is one-shot, write and forget */ - *val = 0; - } else if (property == config->writeback_out_fence_ptr_property) { - *val = 0; - } else if (connector->funcs->atomic_get_property) { - return connector->funcs->atomic_get_property(connector, - state, property, val); - } else { - return -EINVAL; - } - - return 0; -} - -int drm_atomic_get_property(struct drm_mode_object *obj, - struct drm_property *property, uint64_t *val) -{ - struct drm_device *dev = property->dev; - int ret; - - switch (obj->type) { - case DRM_MODE_OBJECT_CONNECTOR: { - struct drm_connector *connector = obj_to_connector(obj); - WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - ret = drm_atomic_connector_get_property(connector, - connector->state, property, val); - break; - } - case DRM_MODE_OBJECT_CRTC: { - struct drm_crtc *crtc = obj_to_crtc(obj); - WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); - ret = drm_atomic_crtc_get_property(crtc, - crtc->state, property, val); - break; - } - case DRM_MODE_OBJECT_PLANE: { - struct drm_plane *plane = obj_to_plane(obj); - WARN_ON(!drm_modeset_is_locked(&plane->mutex)); - ret = drm_atomic_plane_get_property(plane, - plane->state, property, val); - break; - } - default: - ret = -EINVAL; - break; - } - - return ret; -} - -/** - * drm_atomic_set_crtc_for_plane - set crtc for plane - * @plane_state: the plane whose incoming state to update - * @crtc: crtc to use for the plane - * - * Changing the assigned crtc for a plane requires us to grab the lock and state - * for the new crtc, as needed. This function takes care of all these details - * besides updating the pointer in the state object itself. - * - * Returns: - * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK - * then the w/w mutex code has detected a deadlock and the entire atomic - * sequence must be restarted. All other errors are fatal. - */ -int -drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, - struct drm_crtc *crtc) -{ - struct drm_plane *plane = plane_state->plane; - struct drm_crtc_state *crtc_state; - /* Nothing to do for same crtc*/ - if (plane_state->crtc == crtc) - return 0; - if (plane_state->crtc) { - crtc_state = drm_atomic_get_crtc_state(plane_state->state, - plane_state->crtc); - if (WARN_ON(IS_ERR(crtc_state))) - return PTR_ERR(crtc_state); - - crtc_state->plane_mask &= ~drm_plane_mask(plane); - } - - plane_state->crtc = crtc; - - if (crtc) { - crtc_state = drm_atomic_get_crtc_state(plane_state->state, - crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - crtc_state->plane_mask |= drm_plane_mask(plane); - } - - if (crtc) - DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n", - plane->base.id, plane->name, plane_state, - crtc->base.id, crtc->name); - else - DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [NOCRTC]\n", - plane->base.id, plane->name, plane_state); - - return 0; -} -EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane); - -/** - * drm_atomic_set_fb_for_plane - set framebuffer for plane - * @plane_state: atomic state object for the plane - * @fb: fb to use for the plane - * - * Changing the assigned framebuffer for a plane requires us to grab a reference - * to the new fb and drop the reference to the old fb, if there is one. This - * function takes care of all these details besides updating the pointer in the - * state object itself. - */ -void -drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, - struct drm_framebuffer *fb) -{ - struct drm_plane *plane = plane_state->plane; - - if (fb) - DRM_DEBUG_ATOMIC("Set [FB:%d] for [PLANE:%d:%s] state %p\n", - fb->base.id, plane->base.id, plane->name, - plane_state); - else - DRM_DEBUG_ATOMIC("Set [NOFB] for [PLANE:%d:%s] state %p\n", - plane->base.id, plane->name, plane_state); - - drm_framebuffer_assign(&plane_state->fb, fb); -} -EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); - -/** - * drm_atomic_set_fence_for_plane - set fence for plane - * @plane_state: atomic state object for the plane - * @fence: dma_fence to use for the plane - * - * Helper to setup the plane_state fence in case it is not set yet. - * By using this drivers doesn't need to worry if the user choose - * implicit or explicit fencing. - * - * This function will not set the fence to the state if it was set - * via explicit fencing interfaces on the atomic ioctl. In that case it will - * drop the reference to the fence as we are not storing it anywhere. - * Otherwise, if &drm_plane_state.fence is not set this function we just set it - * with the received implicit fence. In both cases this function consumes a - * reference for @fence. - * - * This way explicit fencing can be used to overrule implicit fencing, which is - * important to make explicit fencing use-cases work: One example is using one - * buffer for 2 screens with different refresh rates. Implicit fencing will - * clamp rendering to the refresh rate of the slower screen, whereas explicit - * fence allows 2 independent render and display loops on a single buffer. If a - * driver allows obeys both implicit and explicit fences for plane updates, then - * it will break all the benefits of explicit fencing. - */ -void -drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, - struct dma_fence *fence) -{ - if (plane_state->fence) { - dma_fence_put(fence); - return; - } - - plane_state->fence = fence; -} -EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); - -/** - * drm_atomic_set_crtc_for_connector - set crtc for connector - * @conn_state: atomic state object for the connector - * @crtc: crtc to use for the connector - * - * Changing the assigned crtc for a connector requires us to grab the lock and - * state for the new crtc, as needed. This function takes care of all these - * details besides updating the pointer in the state object itself. - * - * Returns: - * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK - * then the w/w mutex code has detected a deadlock and the entire atomic - * sequence must be restarted. All other errors are fatal. - */ -int -drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, - struct drm_crtc *crtc) -{ - struct drm_connector *connector = conn_state->connector; - struct drm_crtc_state *crtc_state; - - if (conn_state->crtc == crtc) - return 0; - - if (conn_state->crtc) { - crtc_state = drm_atomic_get_new_crtc_state(conn_state->state, - conn_state->crtc); - - crtc_state->connector_mask &= - ~drm_connector_mask(conn_state->connector); - - drm_connector_put(conn_state->connector); - conn_state->crtc = NULL; - } - - if (crtc) { - crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - crtc_state->connector_mask |= - drm_connector_mask(conn_state->connector); - - drm_connector_get(conn_state->connector); - conn_state->crtc = crtc; - - DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n", - connector->base.id, connector->name, - conn_state, crtc->base.id, crtc->name); - } else { - DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n", - connector->base.id, connector->name, - conn_state); - } - - return 0; -} -EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); - /** * drm_atomic_add_affected_connectors - add connectors for crtc * @state: atomic state @@ -1888,7 +1074,7 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state) } EXPORT_SYMBOL(drm_atomic_nonblocking_commit); -static void drm_atomic_print_state(const struct drm_atomic_state *state) +void drm_atomic_print_state(const struct drm_atomic_state *state) { struct drm_printer p = drm_info_printer(state->dev->dev); struct drm_plane *plane; @@ -1995,544 +1181,3 @@ int drm_atomic_debugfs_init(struct drm_minor *minor) } #endif -/* - * The big monster ioctl - */ - -static struct drm_pending_vblank_event *create_vblank_event( - struct drm_crtc *crtc, uint64_t user_data) -{ - struct drm_pending_vblank_event *e = NULL; - - e = kzalloc(sizeof *e, GFP_KERNEL); - if (!e) - return NULL; - - e->event.base.type = DRM_EVENT_FLIP_COMPLETE; - e->event.base.length = sizeof(e->event); - e->event.vbl.crtc_id = crtc->base.id; - e->event.vbl.user_data = user_data; - - return e; -} - -int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, - struct drm_connector *connector, - int mode) -{ - struct drm_connector *tmp_connector; - struct drm_connector_state *new_conn_state; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i, ret, old_mode = connector->dpms; - bool active = false; - - ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, - state->acquire_ctx); - if (ret) - return ret; - - if (mode != DRM_MODE_DPMS_ON) - mode = DRM_MODE_DPMS_OFF; - connector->dpms = mode; - - crtc = connector->state->crtc; - if (!crtc) - goto out; - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - goto out; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - goto out; - } - - for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) { - if (new_conn_state->crtc != crtc) - continue; - if (tmp_connector->dpms == DRM_MODE_DPMS_ON) { - active = true; - break; - } - } - - crtc_state->active = active; - ret = drm_atomic_commit(state); -out: - if (ret != 0) - connector->dpms = old_mode; - return ret; -} - -int drm_atomic_set_property(struct drm_atomic_state *state, - struct drm_mode_object *obj, - struct drm_property *prop, - uint64_t prop_value) -{ - struct drm_mode_object *ref; - int ret; - - if (!drm_property_change_valid_get(prop, prop_value, &ref)) - return -EINVAL; - - switch (obj->type) { - case DRM_MODE_OBJECT_CONNECTOR: { - struct drm_connector *connector = obj_to_connector(obj); - struct drm_connector_state *connector_state; - - connector_state = drm_atomic_get_connector_state(state, connector); - if (IS_ERR(connector_state)) { - ret = PTR_ERR(connector_state); - break; - } - - ret = drm_atomic_connector_set_property(connector, - connector_state, prop, prop_value); - break; - } - case DRM_MODE_OBJECT_CRTC: { - struct drm_crtc *crtc = obj_to_crtc(obj); - struct drm_crtc_state *crtc_state; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - break; - } - - ret = drm_atomic_crtc_set_property(crtc, - crtc_state, prop, prop_value); - break; - } - case DRM_MODE_OBJECT_PLANE: { - struct drm_plane *plane = obj_to_plane(obj); - struct drm_plane_state *plane_state; - - plane_state = drm_atomic_get_plane_state(state, plane); - if (IS_ERR(plane_state)) { - ret = PTR_ERR(plane_state); - break; - } - - ret = drm_atomic_plane_set_property(plane, - plane_state, prop, prop_value); - break; - } - default: - ret = -EINVAL; - break; - } - - drm_property_change_valid_put(prop, ref); - return ret; -} - -/** - * DOC: explicit fencing properties - * - * Explicit fencing allows userspace to control the buffer synchronization - * between devices. A Fence or a group of fences are transfered to/from - * userspace using Sync File fds and there are two DRM properties for that. - * IN_FENCE_FD on each DRM Plane to send fences to the kernel and - * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel. - * - * As a contrast, with implicit fencing the kernel keeps track of any - * ongoing rendering, and automatically ensures that the atomic update waits - * for any pending rendering to complete. For shared buffers represented with - * a &struct dma_buf this is tracked in &struct reservation_object. - * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org), - * whereas explicit fencing is what Android wants. - * - * "IN_FENCE_FD”: - * Use this property to pass a fence that DRM should wait on before - * proceeding with the Atomic Commit request and show the framebuffer for - * the plane on the screen. The fence can be either a normal fence or a - * merged one, the sync_file framework will handle both cases and use a - * fence_array if a merged fence is received. Passing -1 here means no - * fences to wait on. - * - * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag - * it will only check if the Sync File is a valid one. - * - * On the driver side the fence is stored on the @fence parameter of - * &struct drm_plane_state. Drivers which also support implicit fencing - * should set the implicit fence using drm_atomic_set_fence_for_plane(), - * to make sure there's consistent behaviour between drivers in precedence - * of implicit vs. explicit fencing. - * - * "OUT_FENCE_PTR”: - * Use this property to pass a file descriptor pointer to DRM. Once the - * Atomic Commit request call returns OUT_FENCE_PTR will be filled with - * the file descriptor number of a Sync File. This Sync File contains the - * CRTC fence that will be signaled when all framebuffers present on the - * Atomic Commit * request for that given CRTC are scanned out on the - * screen. - * - * The Atomic Commit request fails if a invalid pointer is passed. If the - * Atomic Commit request fails for any other reason the out fence fd - * returned will be -1. On a Atomic Commit with the - * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1. - * - * Note that out-fences don't have a special interface to drivers and are - * internally represented by a &struct drm_pending_vblank_event in struct - * &drm_crtc_state, which is also used by the nonblocking atomic commit - * helpers and for the DRM event handling for existing userspace. - */ - -struct drm_out_fence_state { - s32 __user *out_fence_ptr; - struct sync_file *sync_file; - int fd; -}; - -static int setup_out_fence(struct drm_out_fence_state *fence_state, - struct dma_fence *fence) -{ - fence_state->fd = get_unused_fd_flags(O_CLOEXEC); - if (fence_state->fd < 0) - return fence_state->fd; - - if (put_user(fence_state->fd, fence_state->out_fence_ptr)) - return -EFAULT; - - fence_state->sync_file = sync_file_create(fence); - if (!fence_state->sync_file) - return -ENOMEM; - - return 0; -} - -static int prepare_signaling(struct drm_device *dev, - struct drm_atomic_state *state, - struct drm_mode_atomic *arg, - struct drm_file *file_priv, - struct drm_out_fence_state **fence_state, - unsigned int *num_fences) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - struct drm_connector *conn; - struct drm_connector_state *conn_state; - int i, c = 0, ret; - - if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) - return 0; - - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - s32 __user *fence_ptr; - - fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); - - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) { - struct drm_pending_vblank_event *e; - - e = create_vblank_event(crtc, arg->user_data); - if (!e) - return -ENOMEM; - - crtc_state->event = e; - } - - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - struct drm_pending_vblank_event *e = crtc_state->event; - - if (!file_priv) - continue; - - ret = drm_event_reserve_init(dev, file_priv, &e->base, - &e->event.base); - if (ret) { - kfree(e); - crtc_state->event = NULL; - return ret; - } - } - - if (fence_ptr) { - struct dma_fence *fence; - struct drm_out_fence_state *f; - - f = krealloc(*fence_state, sizeof(**fence_state) * - (*num_fences + 1), GFP_KERNEL); - if (!f) - return -ENOMEM; - - memset(&f[*num_fences], 0, sizeof(*f)); - - f[*num_fences].out_fence_ptr = fence_ptr; - *fence_state = f; - - fence = drm_crtc_create_fence(crtc); - if (!fence) - return -ENOMEM; - - ret = setup_out_fence(&f[(*num_fences)++], fence); - if (ret) { - dma_fence_put(fence); - return ret; - } - - crtc_state->event->base.fence = fence; - } - - c++; - } - - for_each_new_connector_in_state(state, conn, conn_state, i) { - struct drm_writeback_connector *wb_conn; - struct drm_writeback_job *job; - struct drm_out_fence_state *f; - struct dma_fence *fence; - s32 __user *fence_ptr; - - fence_ptr = get_out_fence_for_connector(state, conn); - if (!fence_ptr) - continue; - - job = drm_atomic_get_writeback_job(conn_state); - if (!job) - return -ENOMEM; - - f = krealloc(*fence_state, sizeof(**fence_state) * - (*num_fences + 1), GFP_KERNEL); - if (!f) - return -ENOMEM; - - memset(&f[*num_fences], 0, sizeof(*f)); - - f[*num_fences].out_fence_ptr = fence_ptr; - *fence_state = f; - - wb_conn = drm_connector_to_writeback(conn); - fence = drm_writeback_get_out_fence(wb_conn); - if (!fence) - return -ENOMEM; - - ret = setup_out_fence(&f[(*num_fences)++], fence); - if (ret) { - dma_fence_put(fence); - return ret; - } - - job->out_fence = fence; - } - - /* - * Having this flag means user mode pends on event which will never - * reach due to lack of at least one CRTC for signaling - */ - if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) - return -EINVAL; - - return 0; -} - -static void complete_signaling(struct drm_device *dev, - struct drm_atomic_state *state, - struct drm_out_fence_state *fence_state, - unsigned int num_fences, - bool install_fds) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i; - - if (install_fds) { - for (i = 0; i < num_fences; i++) - fd_install(fence_state[i].fd, - fence_state[i].sync_file->file); - - kfree(fence_state); - return; - } - - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - struct drm_pending_vblank_event *event = crtc_state->event; - /* - * Free the allocated event. drm_atomic_helper_setup_commit - * can allocate an event too, so only free it if it's ours - * to prevent a double free in drm_atomic_state_clear. - */ - if (event && (event->base.fence || event->base.file_priv)) { - drm_event_cancel_free(dev, &event->base); - crtc_state->event = NULL; - } - } - - if (!fence_state) - return; - - for (i = 0; i < num_fences; i++) { - if (fence_state[i].sync_file) - fput(fence_state[i].sync_file->file); - if (fence_state[i].fd >= 0) - put_unused_fd(fence_state[i].fd); - - /* If this fails log error to the user */ - if (fence_state[i].out_fence_ptr && - put_user(-1, fence_state[i].out_fence_ptr)) - DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n"); - } - - kfree(fence_state); -} - -int drm_mode_atomic_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_atomic *arg = data; - uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); - uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); - uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); - uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); - unsigned int copied_objs, copied_props; - struct drm_atomic_state *state; - struct drm_modeset_acquire_ctx ctx; - struct drm_out_fence_state *fence_state; - int ret = 0; - unsigned int i, j, num_fences; - - /* disallow for drivers not supporting atomic: */ - if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) - return -EINVAL; - - /* disallow for userspace that has not enabled atomic cap (even - * though this may be a bit overkill, since legacy userspace - * wouldn't know how to call this ioctl) - */ - if (!file_priv->atomic) - return -EINVAL; - - if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) - return -EINVAL; - - if (arg->reserved) - return -EINVAL; - - if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) && - !dev->mode_config.async_page_flip) - return -EINVAL; - - /* can't test and expect an event at the same time. */ - if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && - (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) - return -EINVAL; - - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); - - state = drm_atomic_state_alloc(dev); - if (!state) - return -ENOMEM; - - state->acquire_ctx = &ctx; - state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); - -retry: - copied_objs = 0; - copied_props = 0; - fence_state = NULL; - num_fences = 0; - - for (i = 0; i < arg->count_objs; i++) { - uint32_t obj_id, count_props; - struct drm_mode_object *obj; - - if (get_user(obj_id, objs_ptr + copied_objs)) { - ret = -EFAULT; - goto out; - } - - obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY); - if (!obj) { - ret = -ENOENT; - goto out; - } - - if (!obj->properties) { - drm_mode_object_put(obj); - ret = -ENOENT; - goto out; - } - - if (get_user(count_props, count_props_ptr + copied_objs)) { - drm_mode_object_put(obj); - ret = -EFAULT; - goto out; - } - - copied_objs++; - - for (j = 0; j < count_props; j++) { - uint32_t prop_id; - uint64_t prop_value; - struct drm_property *prop; - - if (get_user(prop_id, props_ptr + copied_props)) { - drm_mode_object_put(obj); - ret = -EFAULT; - goto out; - } - - prop = drm_mode_obj_find_prop_id(obj, prop_id); - if (!prop) { - drm_mode_object_put(obj); - ret = -ENOENT; - goto out; - } - - if (copy_from_user(&prop_value, - prop_values_ptr + copied_props, - sizeof(prop_value))) { - drm_mode_object_put(obj); - ret = -EFAULT; - goto out; - } - - ret = drm_atomic_set_property(state, obj, prop, - prop_value); - if (ret) { - drm_mode_object_put(obj); - goto out; - } - - copied_props++; - } - - drm_mode_object_put(obj); - } - - ret = prepare_signaling(dev, state, arg, file_priv, &fence_state, - &num_fences); - if (ret) - goto out; - - if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { - ret = drm_atomic_check_only(state); - } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { - ret = drm_atomic_nonblocking_commit(state); - } else { - if (unlikely(drm_debug & DRM_UT_STATE)) - drm_atomic_print_state(state); - - ret = drm_atomic_commit(state); - } - -out: - complete_signaling(dev, state, fence_state, num_fences, !ret); - - if (ret == -EDEADLK) { - drm_atomic_state_clear(state); - ret = drm_modeset_backoff(&ctx); - if (!ret) - goto retry; - } - - drm_atomic_state_put(state); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; -} diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 2c23a48482da..3cf1aa132778 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c new file mode 100644 index 000000000000..26690a664ec6 --- /dev/null +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -0,0 +1,1393 @@ +/* + * Copyright (C) 2014 Red Hat + * Copyright (C) 2014 Intel Corp. + * Copyright (C) 2018 Intel Corp. + * + * 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. + * + * Authors: + * Rob Clark + * Daniel Vetter + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "drm_crtc_internal.h" + +/** + * DOC: overview + * + * This file contains the marshalling and demarshalling glue for the atomic UAPI + * in all it's form: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and + * SET_PROPERTY IOCTls. Plus interface functions for compatibility helpers and + * drivers which have special needs to construct their own atomic updates, e.g. + * for load detect or similiar. + */ + +/** + * drm_atomic_set_mode_for_crtc - set mode for CRTC + * @state: the CRTC whose incoming state to update + * @mode: kernel-internal mode to use for the CRTC, or NULL to disable + * + * Set a mode (originating from the kernel) on the desired CRTC state and update + * the enable property. + * + * RETURNS: + * Zero on success, error code on failure. Cannot return -EDEADLK. + */ +int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + const struct drm_display_mode *mode) +{ + struct drm_crtc *crtc = state->crtc; + struct drm_mode_modeinfo umode; + + /* Early return for no change. */ + if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) + return 0; + + drm_property_blob_put(state->mode_blob); + state->mode_blob = NULL; + + if (mode) { + drm_mode_convert_to_umode(&umode, mode); + state->mode_blob = + drm_property_create_blob(state->crtc->dev, + sizeof(umode), + &umode); + if (IS_ERR(state->mode_blob)) + return PTR_ERR(state->mode_blob); + + drm_mode_copy(&state->mode, mode); + state->enable = true; + DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", + mode->name, crtc->base.id, crtc->name, state); + } else { + memset(&state->mode, 0, sizeof(state->mode)); + state->enable = false; + DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n", + crtc->base.id, crtc->name, state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); + +/** + * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC + * @state: the CRTC whose incoming state to update + * @blob: pointer to blob property to use for mode + * + * Set a mode (originating from a blob property) on the desired CRTC state. + * This function will take a reference on the blob property for the CRTC state, + * and release the reference held on the state's existing mode property, if any + * was set. + * + * RETURNS: + * Zero on success, error code on failure. Cannot return -EDEADLK. + */ +int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, + struct drm_property_blob *blob) +{ + struct drm_crtc *crtc = state->crtc; + + if (blob == state->mode_blob) + return 0; + + drm_property_blob_put(state->mode_blob); + state->mode_blob = NULL; + + memset(&state->mode, 0, sizeof(state->mode)); + + if (blob) { + int ret; + + if (blob->length != sizeof(struct drm_mode_modeinfo)) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] bad mode blob length: %zu\n", + crtc->base.id, crtc->name, + blob->length); + return -EINVAL; + } + + ret = drm_mode_convert_umode(crtc->dev, + &state->mode, blob->data); + if (ret) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n", + crtc->base.id, crtc->name, + ret, drm_get_mode_status_name(state->mode.status)); + drm_mode_debug_printmodeline(&state->mode); + return -EINVAL; + } + + state->mode_blob = drm_property_blob_get(blob); + state->enable = true; + DRM_DEBUG_ATOMIC("Set [MODE:%s] for [CRTC:%d:%s] state %p\n", + state->mode.name, crtc->base.id, crtc->name, + state); + } else { + state->enable = false; + DRM_DEBUG_ATOMIC("Set [NOMODE] for [CRTC:%d:%s] state %p\n", + crtc->base.id, crtc->name, state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); + +/** + * drm_atomic_set_crtc_for_plane - set crtc for plane + * @plane_state: the plane whose incoming state to update + * @crtc: crtc to use for the plane + * + * Changing the assigned crtc for a plane requires us to grab the lock and state + * for the new crtc, as needed. This function takes care of all these details + * besides updating the pointer in the state object itself. + * + * Returns: + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK + * then the w/w mutex code has detected a deadlock and the entire atomic + * sequence must be restarted. All other errors are fatal. + */ +int +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, + struct drm_crtc *crtc) +{ + struct drm_plane *plane = plane_state->plane; + struct drm_crtc_state *crtc_state; + /* Nothing to do for same crtc*/ + if (plane_state->crtc == crtc) + return 0; + if (plane_state->crtc) { + crtc_state = drm_atomic_get_crtc_state(plane_state->state, + plane_state->crtc); + if (WARN_ON(IS_ERR(crtc_state))) + return PTR_ERR(crtc_state); + + crtc_state->plane_mask &= ~drm_plane_mask(plane); + } + + plane_state->crtc = crtc; + + if (crtc) { + crtc_state = drm_atomic_get_crtc_state(plane_state->state, + crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + crtc_state->plane_mask |= drm_plane_mask(plane); + } + + if (crtc) + DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n", + plane->base.id, plane->name, plane_state, + crtc->base.id, crtc->name); + else + DRM_DEBUG_ATOMIC("Link [PLANE:%d:%s] state %p to [NOCRTC]\n", + plane->base.id, plane->name, plane_state); + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane); + +/** + * drm_atomic_set_fb_for_plane - set framebuffer for plane + * @plane_state: atomic state object for the plane + * @fb: fb to use for the plane + * + * Changing the assigned framebuffer for a plane requires us to grab a reference + * to the new fb and drop the reference to the old fb, if there is one. This + * function takes care of all these details besides updating the pointer in the + * state object itself. + */ +void +drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, + struct drm_framebuffer *fb) +{ + struct drm_plane *plane = plane_state->plane; + + if (fb) + DRM_DEBUG_ATOMIC("Set [FB:%d] for [PLANE:%d:%s] state %p\n", + fb->base.id, plane->base.id, plane->name, + plane_state); + else + DRM_DEBUG_ATOMIC("Set [NOFB] for [PLANE:%d:%s] state %p\n", + plane->base.id, plane->name, plane_state); + + drm_framebuffer_assign(&plane_state->fb, fb); +} +EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); + +/** + * drm_atomic_set_fence_for_plane - set fence for plane + * @plane_state: atomic state object for the plane + * @fence: dma_fence to use for the plane + * + * Helper to setup the plane_state fence in case it is not set yet. + * By using this drivers doesn't need to worry if the user choose + * implicit or explicit fencing. + * + * This function will not set the fence to the state if it was set + * via explicit fencing interfaces on the atomic ioctl. In that case it will + * drop the reference to the fence as we are not storing it anywhere. + * Otherwise, if &drm_plane_state.fence is not set this function we just set it + * with the received implicit fence. In both cases this function consumes a + * reference for @fence. + * + * This way explicit fencing can be used to overrule implicit fencing, which is + * important to make explicit fencing use-cases work: One example is using one + * buffer for 2 screens with different refresh rates. Implicit fencing will + * clamp rendering to the refresh rate of the slower screen, whereas explicit + * fence allows 2 independent render and display loops on a single buffer. If a + * driver allows obeys both implicit and explicit fences for plane updates, then + * it will break all the benefits of explicit fencing. + */ +void +drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, + struct dma_fence *fence) +{ + if (plane_state->fence) { + dma_fence_put(fence); + return; + } + + plane_state->fence = fence; +} +EXPORT_SYMBOL(drm_atomic_set_fence_for_plane); + +/** + * drm_atomic_set_crtc_for_connector - set crtc for connector + * @conn_state: atomic state object for the connector + * @crtc: crtc to use for the connector + * + * Changing the assigned crtc for a connector requires us to grab the lock and + * state for the new crtc, as needed. This function takes care of all these + * details besides updating the pointer in the state object itself. + * + * Returns: + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK + * then the w/w mutex code has detected a deadlock and the entire atomic + * sequence must be restarted. All other errors are fatal. + */ +int +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, + struct drm_crtc *crtc) +{ + struct drm_connector *connector = conn_state->connector; + struct drm_crtc_state *crtc_state; + + if (conn_state->crtc == crtc) + return 0; + + if (conn_state->crtc) { + crtc_state = drm_atomic_get_new_crtc_state(conn_state->state, + conn_state->crtc); + + crtc_state->connector_mask &= + ~drm_connector_mask(conn_state->connector); + + drm_connector_put(conn_state->connector); + conn_state->crtc = NULL; + } + + if (crtc) { + crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->connector_mask |= + drm_connector_mask(conn_state->connector); + + drm_connector_get(conn_state->connector); + conn_state->crtc = crtc; + + DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n", + connector->base.id, connector->name, + conn_state, crtc->base.id, crtc->name); + } else { + DRM_DEBUG_ATOMIC("Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n", + connector->base.id, connector->name, + conn_state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); + +static void set_out_fence_for_crtc(struct drm_atomic_state *state, + struct drm_crtc *crtc, s32 __user *fence_ptr) +{ + state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr; +} + +static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, + struct drm_crtc *crtc) +{ + s32 __user *fence_ptr; + + fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr; + state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL; + + return fence_ptr; +} + +static int set_out_fence_for_connector(struct drm_atomic_state *state, + struct drm_connector *connector, + s32 __user *fence_ptr) +{ + unsigned int index = drm_connector_index(connector); + + if (!fence_ptr) + return 0; + + if (put_user(-1, fence_ptr)) + return -EFAULT; + + state->connectors[index].out_fence_ptr = fence_ptr; + + return 0; +} + +static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, + struct drm_connector *connector) +{ + unsigned int index = drm_connector_index(connector); + s32 __user *fence_ptr; + + fence_ptr = state->connectors[index].out_fence_ptr; + state->connectors[index].out_fence_ptr = NULL; + + return fence_ptr; +} + +static int +drm_atomic_replace_property_blob_from_id(struct drm_device *dev, + struct drm_property_blob **blob, + uint64_t blob_id, + ssize_t expected_size, + ssize_t expected_elem_size, + bool *replaced) +{ + struct drm_property_blob *new_blob = NULL; + + if (blob_id != 0) { + new_blob = drm_property_lookup_blob(dev, blob_id); + if (new_blob == NULL) + return -EINVAL; + + if (expected_size > 0 && + new_blob->length != expected_size) { + drm_property_blob_put(new_blob); + return -EINVAL; + } + if (expected_elem_size > 0 && + new_blob->length % expected_elem_size != 0) { + drm_property_blob_put(new_blob); + return -EINVAL; + } + } + + *replaced |= drm_property_replace_blob(blob, new_blob); + drm_property_blob_put(new_blob); + + return 0; +} + +static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + bool replaced = false; + int ret; + + if (property == config->prop_active) + state->active = val; + else if (property == config->prop_mode_id) { + struct drm_property_blob *mode = + drm_property_lookup_blob(dev, val); + ret = drm_atomic_set_mode_prop_for_crtc(state, mode); + drm_property_blob_put(mode); + return ret; + } else if (property == config->degamma_lut_property) { + ret = drm_atomic_replace_property_blob_from_id(dev, + &state->degamma_lut, + val, + -1, sizeof(struct drm_color_lut), + &replaced); + state->color_mgmt_changed |= replaced; + return ret; + } else if (property == config->ctm_property) { + ret = drm_atomic_replace_property_blob_from_id(dev, + &state->ctm, + val, + sizeof(struct drm_color_ctm), -1, + &replaced); + state->color_mgmt_changed |= replaced; + return ret; + } else if (property == config->gamma_lut_property) { + ret = drm_atomic_replace_property_blob_from_id(dev, + &state->gamma_lut, + val, + -1, sizeof(struct drm_color_lut), + &replaced); + state->color_mgmt_changed |= replaced; + return ret; + } else if (property == config->prop_out_fence_ptr) { + s32 __user *fence_ptr = u64_to_user_ptr(val); + + if (!fence_ptr) + return 0; + + if (put_user(-1, fence_ptr)) + return -EFAULT; + + set_out_fence_for_crtc(state->state, crtc, fence_ptr); + } else if (crtc->funcs->atomic_set_property) { + return crtc->funcs->atomic_set_property(crtc, state, property, val); + } else { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n", + crtc->base.id, crtc->name, + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int +drm_atomic_crtc_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_active) + *val = state->active; + else if (property == config->prop_mode_id) + *val = (state->mode_blob) ? state->mode_blob->base.id : 0; + else if (property == config->degamma_lut_property) + *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; + else if (property == config->ctm_property) + *val = (state->ctm) ? state->ctm->base.id : 0; + else if (property == config->gamma_lut_property) + *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; + else if (property == config->prop_out_fence_ptr) + *val = 0; + else if (crtc->funcs->atomic_get_property) + return crtc->funcs->atomic_get_property(crtc, state, property, val); + else + return -EINVAL; + + return 0; +} + +static int drm_atomic_plane_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); + drm_atomic_set_fb_for_plane(state, fb); + if (fb) + drm_framebuffer_put(fb); + } else if (property == config->prop_in_fence_fd) { + if (state->fence) + return -EINVAL; + + if (U642I64(val) == -1) + return 0; + + state->fence = sync_file_get_fence(val); + if (!state->fence) + return -EINVAL; + + } else if (property == config->prop_crtc_id) { + struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val); + return drm_atomic_set_crtc_for_plane(state, crtc); + } else if (property == config->prop_crtc_x) { + state->crtc_x = U642I64(val); + } else if (property == config->prop_crtc_y) { + state->crtc_y = U642I64(val); + } else if (property == config->prop_crtc_w) { + state->crtc_w = val; + } else if (property == config->prop_crtc_h) { + state->crtc_h = val; + } else if (property == config->prop_src_x) { + state->src_x = val; + } else if (property == config->prop_src_y) { + state->src_y = val; + } else if (property == config->prop_src_w) { + state->src_w = val; + } else if (property == config->prop_src_h) { + state->src_h = val; + } else if (property == plane->alpha_property) { + state->alpha = val; + } else if (property == plane->blend_mode_property) { + state->pixel_blend_mode = val; + } else if (property == plane->rotation_property) { + if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) { + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n", + plane->base.id, plane->name, val); + return -EINVAL; + } + state->rotation = val; + } else if (property == plane->zpos_property) { + state->zpos = val; + } else if (property == plane->color_encoding_property) { + state->color_encoding = val; + } else if (property == plane->color_range_property) { + state->color_range = val; + } else if (plane->funcs->atomic_set_property) { + return plane->funcs->atomic_set_property(plane, state, + property, val); + } else { + DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", + plane->base.id, plane->name, + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int +drm_atomic_plane_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + *val = (state->fb) ? state->fb->base.id : 0; + } else if (property == config->prop_in_fence_fd) { + *val = -1; + } else if (property == config->prop_crtc_id) { + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->prop_crtc_x) { + *val = I642U64(state->crtc_x); + } else if (property == config->prop_crtc_y) { + *val = I642U64(state->crtc_y); + } else if (property == config->prop_crtc_w) { + *val = state->crtc_w; + } else if (property == config->prop_crtc_h) { + *val = state->crtc_h; + } else if (property == config->prop_src_x) { + *val = state->src_x; + } else if (property == config->prop_src_y) { + *val = state->src_y; + } else if (property == config->prop_src_w) { + *val = state->src_w; + } else if (property == config->prop_src_h) { + *val = state->src_h; + } else if (property == plane->alpha_property) { + *val = state->alpha; + } else if (property == plane->blend_mode_property) { + *val = state->pixel_blend_mode; + } else if (property == plane->rotation_property) { + *val = state->rotation; + } else if (property == plane->zpos_property) { + *val = state->zpos; + } else if (property == plane->color_encoding_property) { + *val = state->color_encoding; + } else if (property == plane->color_range_property) { + *val = state->color_range; + } else if (plane->funcs->atomic_get_property) { + return plane->funcs->atomic_get_property(plane, state, property, val); + } else { + return -EINVAL; + } + + return 0; +} + +static struct drm_writeback_job * +drm_atomic_get_writeback_job(struct drm_connector_state *conn_state) +{ + WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); + + if (!conn_state->writeback_job) + conn_state->writeback_job = + kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); + + return conn_state->writeback_job; +} + +static int drm_atomic_set_writeback_fb_for_connector( + struct drm_connector_state *conn_state, + struct drm_framebuffer *fb) +{ + struct drm_writeback_job *job = + drm_atomic_get_writeback_job(conn_state); + if (!job) + return -ENOMEM; + + drm_framebuffer_assign(&job->fb, fb); + + if (fb) + DRM_DEBUG_ATOMIC("Set [FB:%d] for connector state %p\n", + fb->base.id, conn_state); + else + DRM_DEBUG_ATOMIC("Set [NOFB] for connector state %p\n", + conn_state); + + return 0; +} + +static int drm_atomic_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_crtc_id) { + struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val); + return drm_atomic_set_crtc_for_connector(state, crtc); + } else if (property == config->dpms_property) { + /* setting DPMS property requires special handling, which + * is done in legacy setprop path for us. Disallow (for + * now?) atomic writes to DPMS property: + */ + return -EINVAL; + } else if (property == config->tv_select_subconnector_property) { + state->tv.subconnector = val; + } else if (property == config->tv_left_margin_property) { + state->tv.margins.left = val; + } else if (property == config->tv_right_margin_property) { + state->tv.margins.right = val; + } else if (property == config->tv_top_margin_property) { + state->tv.margins.top = val; + } else if (property == config->tv_bottom_margin_property) { + state->tv.margins.bottom = val; + } else if (property == config->tv_mode_property) { + state->tv.mode = val; + } else if (property == config->tv_brightness_property) { + state->tv.brightness = val; + } else if (property == config->tv_contrast_property) { + state->tv.contrast = val; + } else if (property == config->tv_flicker_reduction_property) { + state->tv.flicker_reduction = val; + } else if (property == config->tv_overscan_property) { + state->tv.overscan = val; + } else if (property == config->tv_saturation_property) { + state->tv.saturation = val; + } else if (property == config->tv_hue_property) { + state->tv.hue = val; + } else if (property == config->link_status_property) { + /* Never downgrade from GOOD to BAD on userspace's request here, + * only hw issues can do that. + * + * For an atomic property the userspace doesn't need to be able + * to understand all the properties, but needs to be able to + * restore the state it wants on VT switch. So if the userspace + * tries to change the link_status from GOOD to BAD, driver + * silently rejects it and returns a 0. This prevents userspace + * from accidently breaking the display when it restores the + * state. + */ + if (state->link_status != DRM_LINK_STATUS_GOOD) + state->link_status = val; + } else if (property == config->aspect_ratio_property) { + state->picture_aspect_ratio = val; + } else if (property == config->content_type_property) { + state->content_type = val; + } else if (property == connector->scaling_mode_property) { + state->scaling_mode = val; + } else if (property == connector->content_protection_property) { + if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) { + DRM_DEBUG_KMS("only drivers can set CP Enabled\n"); + return -EINVAL; + } + state->content_protection = val; + } else if (property == config->writeback_fb_id_property) { + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val); + int ret = drm_atomic_set_writeback_fb_for_connector(state, fb); + if (fb) + drm_framebuffer_put(fb); + return ret; + } else if (property == config->writeback_out_fence_ptr_property) { + s32 __user *fence_ptr = u64_to_user_ptr(val); + + return set_out_fence_for_connector(state->state, connector, + fence_ptr); + } else if (connector->funcs->atomic_set_property) { + return connector->funcs->atomic_set_property(connector, + state, property, val); + } else { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]]\n", + connector->base.id, connector->name, + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int +drm_atomic_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = connector->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_crtc_id) { + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->dpms_property) { + *val = connector->dpms; + } else if (property == config->tv_select_subconnector_property) { + *val = state->tv.subconnector; + } else if (property == config->tv_left_margin_property) { + *val = state->tv.margins.left; + } else if (property == config->tv_right_margin_property) { + *val = state->tv.margins.right; + } else if (property == config->tv_top_margin_property) { + *val = state->tv.margins.top; + } else if (property == config->tv_bottom_margin_property) { + *val = state->tv.margins.bottom; + } else if (property == config->tv_mode_property) { + *val = state->tv.mode; + } else if (property == config->tv_brightness_property) { + *val = state->tv.brightness; + } else if (property == config->tv_contrast_property) { + *val = state->tv.contrast; + } else if (property == config->tv_flicker_reduction_property) { + *val = state->tv.flicker_reduction; + } else if (property == config->tv_overscan_property) { + *val = state->tv.overscan; + } else if (property == config->tv_saturation_property) { + *val = state->tv.saturation; + } else if (property == config->tv_hue_property) { + *val = state->tv.hue; + } else if (property == config->link_status_property) { + *val = state->link_status; + } else if (property == config->aspect_ratio_property) { + *val = state->picture_aspect_ratio; + } else if (property == config->content_type_property) { + *val = state->content_type; + } else if (property == connector->scaling_mode_property) { + *val = state->scaling_mode; + } else if (property == connector->content_protection_property) { + *val = state->content_protection; + } else if (property == config->writeback_fb_id_property) { + /* Writeback framebuffer is one-shot, write and forget */ + *val = 0; + } else if (property == config->writeback_out_fence_ptr_property) { + *val = 0; + } else if (connector->funcs->atomic_get_property) { + return connector->funcs->atomic_get_property(connector, + state, property, val); + } else { + return -EINVAL; + } + + return 0; +} + +int drm_atomic_get_property(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = property->dev; + int ret; + + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: { + struct drm_connector *connector = obj_to_connector(obj); + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + ret = drm_atomic_connector_get_property(connector, + connector->state, property, val); + break; + } + case DRM_MODE_OBJECT_CRTC: { + struct drm_crtc *crtc = obj_to_crtc(obj); + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); + ret = drm_atomic_crtc_get_property(crtc, + crtc->state, property, val); + break; + } + case DRM_MODE_OBJECT_PLANE: { + struct drm_plane *plane = obj_to_plane(obj); + WARN_ON(!drm_modeset_is_locked(&plane->mutex)); + ret = drm_atomic_plane_get_property(plane, + plane->state, property, val); + break; + } + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/* + * The big monster ioctl + */ + +static struct drm_pending_vblank_event *create_vblank_event( + struct drm_crtc *crtc, uint64_t user_data) +{ + struct drm_pending_vblank_event *e = NULL; + + e = kzalloc(sizeof *e, GFP_KERNEL); + if (!e) + return NULL; + + e->event.base.type = DRM_EVENT_FLIP_COMPLETE; + e->event.base.length = sizeof(e->event); + e->event.vbl.crtc_id = crtc->base.id; + e->event.vbl.user_data = user_data; + + return e; +} + +int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, + struct drm_connector *connector, + int mode) +{ + struct drm_connector *tmp_connector; + struct drm_connector_state *new_conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, ret, old_mode = connector->dpms; + bool active = false; + + ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, + state->acquire_ctx); + if (ret) + return ret; + + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + connector->dpms = mode; + + crtc = connector->state->crtc; + if (!crtc) + goto out; + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + goto out; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto out; + } + + for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) { + if (new_conn_state->crtc != crtc) + continue; + if (tmp_connector->dpms == DRM_MODE_DPMS_ON) { + active = true; + break; + } + } + + crtc_state->active = active; + ret = drm_atomic_commit(state); +out: + if (ret != 0) + connector->dpms = old_mode; + return ret; +} + +int drm_atomic_set_property(struct drm_atomic_state *state, + struct drm_mode_object *obj, + struct drm_property *prop, + uint64_t prop_value) +{ + struct drm_mode_object *ref; + int ret; + + if (!drm_property_change_valid_get(prop, prop_value, &ref)) + return -EINVAL; + + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: { + struct drm_connector *connector = obj_to_connector(obj); + struct drm_connector_state *connector_state; + + connector_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(connector_state)) { + ret = PTR_ERR(connector_state); + break; + } + + ret = drm_atomic_connector_set_property(connector, + connector_state, prop, prop_value); + break; + } + case DRM_MODE_OBJECT_CRTC: { + struct drm_crtc *crtc = obj_to_crtc(obj); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + break; + } + + ret = drm_atomic_crtc_set_property(crtc, + crtc_state, prop, prop_value); + break; + } + case DRM_MODE_OBJECT_PLANE: { + struct drm_plane *plane = obj_to_plane(obj); + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + break; + } + + ret = drm_atomic_plane_set_property(plane, + plane_state, prop, prop_value); + break; + } + default: + ret = -EINVAL; + break; + } + + drm_property_change_valid_put(prop, ref); + return ret; +} + +/** + * DOC: explicit fencing properties + * + * Explicit fencing allows userspace to control the buffer synchronization + * between devices. A Fence or a group of fences are transfered to/from + * userspace using Sync File fds and there are two DRM properties for that. + * IN_FENCE_FD on each DRM Plane to send fences to the kernel and + * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel. + * + * As a contrast, with implicit fencing the kernel keeps track of any + * ongoing rendering, and automatically ensures that the atomic update waits + * for any pending rendering to complete. For shared buffers represented with + * a &struct dma_buf this is tracked in &struct reservation_object. + * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org), + * whereas explicit fencing is what Android wants. + * + * "IN_FENCE_FD”: + * Use this property to pass a fence that DRM should wait on before + * proceeding with the Atomic Commit request and show the framebuffer for + * the plane on the screen. The fence can be either a normal fence or a + * merged one, the sync_file framework will handle both cases and use a + * fence_array if a merged fence is received. Passing -1 here means no + * fences to wait on. + * + * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag + * it will only check if the Sync File is a valid one. + * + * On the driver side the fence is stored on the @fence parameter of + * &struct drm_plane_state. Drivers which also support implicit fencing + * should set the implicit fence using drm_atomic_set_fence_for_plane(), + * to make sure there's consistent behaviour between drivers in precedence + * of implicit vs. explicit fencing. + * + * "OUT_FENCE_PTR”: + * Use this property to pass a file descriptor pointer to DRM. Once the + * Atomic Commit request call returns OUT_FENCE_PTR will be filled with + * the file descriptor number of a Sync File. This Sync File contains the + * CRTC fence that will be signaled when all framebuffers present on the + * Atomic Commit * request for that given CRTC are scanned out on the + * screen. + * + * The Atomic Commit request fails if a invalid pointer is passed. If the + * Atomic Commit request fails for any other reason the out fence fd + * returned will be -1. On a Atomic Commit with the + * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1. + * + * Note that out-fences don't have a special interface to drivers and are + * internally represented by a &struct drm_pending_vblank_event in struct + * &drm_crtc_state, which is also used by the nonblocking atomic commit + * helpers and for the DRM event handling for existing userspace. + */ + +struct drm_out_fence_state { + s32 __user *out_fence_ptr; + struct sync_file *sync_file; + int fd; +}; + +static int setup_out_fence(struct drm_out_fence_state *fence_state, + struct dma_fence *fence) +{ + fence_state->fd = get_unused_fd_flags(O_CLOEXEC); + if (fence_state->fd < 0) + return fence_state->fd; + + if (put_user(fence_state->fd, fence_state->out_fence_ptr)) + return -EFAULT; + + fence_state->sync_file = sync_file_create(fence); + if (!fence_state->sync_file) + return -ENOMEM; + + return 0; +} + +static int prepare_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_mode_atomic *arg, + struct drm_file *file_priv, + struct drm_out_fence_state **fence_state, + unsigned int *num_fences) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + int i, c = 0, ret; + + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) + return 0; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + s32 __user *fence_ptr; + + fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) { + struct drm_pending_vblank_event *e; + + e = create_vblank_event(crtc, arg->user_data); + if (!e) + return -ENOMEM; + + crtc_state->event = e; + } + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + struct drm_pending_vblank_event *e = crtc_state->event; + + if (!file_priv) + continue; + + ret = drm_event_reserve_init(dev, file_priv, &e->base, + &e->event.base); + if (ret) { + kfree(e); + crtc_state->event = NULL; + return ret; + } + } + + if (fence_ptr) { + struct dma_fence *fence; + struct drm_out_fence_state *f; + + f = krealloc(*fence_state, sizeof(**fence_state) * + (*num_fences + 1), GFP_KERNEL); + if (!f) + return -ENOMEM; + + memset(&f[*num_fences], 0, sizeof(*f)); + + f[*num_fences].out_fence_ptr = fence_ptr; + *fence_state = f; + + fence = drm_crtc_create_fence(crtc); + if (!fence) + return -ENOMEM; + + ret = setup_out_fence(&f[(*num_fences)++], fence); + if (ret) { + dma_fence_put(fence); + return ret; + } + + crtc_state->event->base.fence = fence; + } + + c++; + } + + for_each_new_connector_in_state(state, conn, conn_state, i) { + struct drm_writeback_connector *wb_conn; + struct drm_writeback_job *job; + struct drm_out_fence_state *f; + struct dma_fence *fence; + s32 __user *fence_ptr; + + fence_ptr = get_out_fence_for_connector(state, conn); + if (!fence_ptr) + continue; + + job = drm_atomic_get_writeback_job(conn_state); + if (!job) + return -ENOMEM; + + f = krealloc(*fence_state, sizeof(**fence_state) * + (*num_fences + 1), GFP_KERNEL); + if (!f) + return -ENOMEM; + + memset(&f[*num_fences], 0, sizeof(*f)); + + f[*num_fences].out_fence_ptr = fence_ptr; + *fence_state = f; + + wb_conn = drm_connector_to_writeback(conn); + fence = drm_writeback_get_out_fence(wb_conn); + if (!fence) + return -ENOMEM; + + ret = setup_out_fence(&f[(*num_fences)++], fence); + if (ret) { + dma_fence_put(fence); + return ret; + } + + job->out_fence = fence; + } + + /* + * Having this flag means user mode pends on event which will never + * reach due to lack of at least one CRTC for signaling + */ + if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) + return -EINVAL; + + return 0; +} + +static void complete_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_out_fence_state *fence_state, + unsigned int num_fences, + bool install_fds) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + if (install_fds) { + for (i = 0; i < num_fences; i++) + fd_install(fence_state[i].fd, + fence_state[i].sync_file->file); + + kfree(fence_state); + return; + } + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + struct drm_pending_vblank_event *event = crtc_state->event; + /* + * Free the allocated event. drm_atomic_helper_setup_commit + * can allocate an event too, so only free it if it's ours + * to prevent a double free in drm_atomic_state_clear. + */ + if (event && (event->base.fence || event->base.file_priv)) { + drm_event_cancel_free(dev, &event->base); + crtc_state->event = NULL; + } + } + + if (!fence_state) + return; + + for (i = 0; i < num_fences; i++) { + if (fence_state[i].sync_file) + fput(fence_state[i].sync_file->file); + if (fence_state[i].fd >= 0) + put_unused_fd(fence_state[i].fd); + + /* If this fails log error to the user */ + if (fence_state[i].out_fence_ptr && + put_user(-1, fence_state[i].out_fence_ptr)) + DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n"); + } + + kfree(fence_state); +} + +int drm_mode_atomic_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_atomic *arg = data; + uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); + uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); + uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); + uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); + unsigned int copied_objs, copied_props; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; + struct drm_out_fence_state *fence_state; + int ret = 0; + unsigned int i, j, num_fences; + + /* disallow for drivers not supporting atomic: */ + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return -EINVAL; + + /* disallow for userspace that has not enabled atomic cap (even + * though this may be a bit overkill, since legacy userspace + * wouldn't know how to call this ioctl) + */ + if (!file_priv->atomic) + return -EINVAL; + + if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) + return -EINVAL; + + if (arg->reserved) + return -EINVAL; + + if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) && + !dev->mode_config.async_page_flip) + return -EINVAL; + + /* can't test and expect an event at the same time. */ + if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && + (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) + return -EINVAL; + + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = &ctx; + state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); + +retry: + copied_objs = 0; + copied_props = 0; + fence_state = NULL; + num_fences = 0; + + for (i = 0; i < arg->count_objs; i++) { + uint32_t obj_id, count_props; + struct drm_mode_object *obj; + + if (get_user(obj_id, objs_ptr + copied_objs)) { + ret = -EFAULT; + goto out; + } + + obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY); + if (!obj) { + ret = -ENOENT; + goto out; + } + + if (!obj->properties) { + drm_mode_object_put(obj); + ret = -ENOENT; + goto out; + } + + if (get_user(count_props, count_props_ptr + copied_objs)) { + drm_mode_object_put(obj); + ret = -EFAULT; + goto out; + } + + copied_objs++; + + for (j = 0; j < count_props; j++) { + uint32_t prop_id; + uint64_t prop_value; + struct drm_property *prop; + + if (get_user(prop_id, props_ptr + copied_props)) { + drm_mode_object_put(obj); + ret = -EFAULT; + goto out; + } + + prop = drm_mode_obj_find_prop_id(obj, prop_id); + if (!prop) { + drm_mode_object_put(obj); + ret = -ENOENT; + goto out; + } + + if (copy_from_user(&prop_value, + prop_values_ptr + copied_props, + sizeof(prop_value))) { + drm_mode_object_put(obj); + ret = -EFAULT; + goto out; + } + + ret = drm_atomic_set_property(state, obj, prop, + prop_value); + if (ret) { + drm_mode_object_put(obj); + goto out; + } + + copied_props++; + } + + drm_mode_object_put(obj); + } + + ret = prepare_signaling(dev, state, arg, file_priv, &fence_state, + &num_fences); + if (ret) + goto out; + + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { + ret = drm_atomic_check_only(state); + } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { + ret = drm_atomic_nonblocking_commit(state); + } else { + if (unlikely(drm_debug & DRM_UT_STATE)) + drm_atomic_print_state(state); + + ret = drm_atomic_commit(state); + } + +out: + complete_signaling(dev, state, fence_state, num_fences, !ret); + + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry; + } + + drm_atomic_state_put(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 5a84c3bc915d..ce75e9506e85 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index ff5e0d521c21..ede20b55d50c 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -204,6 +204,9 @@ struct drm_minor; int drm_atomic_debugfs_init(struct drm_minor *minor); #endif +void drm_atomic_print_state(const struct drm_atomic_state *state); + +/* drm_atomic_uapi.c */ int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, struct drm_connector *connector, int mode); @@ -213,6 +216,8 @@ int drm_atomic_set_property(struct drm_atomic_state *state, uint64_t prop_value); int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); + +/* IOCTL */ int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index c8a7829d73d6..227f52e55d05 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "drm_internal.h" diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 2810d4131411..7607f9cd6f77 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 621f17643bb0..a393756b664e 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9382375d33b2..c24bc848ac6c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index b640e39ebaca..015341e2dd4c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -21,6 +21,8 @@ #include #include +#include + #include "msm_drv.h" #include "dpu_kms.h" #include "dpu_formats.h" diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index c1f1779c980f..4bcdeca7479d 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -15,6 +15,8 @@ * this program. If not, see . */ +#include + #include "msm_drv.h" #include "msm_gem.h" #include "msm_kms.h" diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 0e6a121858d1..3ce136ba8791 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index cf78f74bb87f..f39ee212412d 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "uapi/drm/vc4_drm.h" #include "vc4_drv.h" diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 93d29af34024..d6adebcd6ea4 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -584,22 +584,6 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, return plane->state; } -int __must_check -drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, - const struct drm_display_mode *mode); -int __must_check -drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, - struct drm_property_blob *blob); -int __must_check -drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, - struct drm_crtc *crtc); -void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, - struct drm_framebuffer *fb); -void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, - struct dma_fence *fence); -int __must_check -drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, - struct drm_crtc *crtc); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/include/drm/drm_atomic_uapi.h b/include/drm/drm_atomic_uapi.h new file mode 100644 index 000000000000..8cec52ad1277 --- /dev/null +++ b/include/drm/drm_atomic_uapi.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 Red Hat + * Copyright (C) 2014 Intel Corp. + * Copyright (C) 2018 Intel Corp. + * + * 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. + * + * Authors: + * Rob Clark + * Daniel Vetter + */ + +#ifndef DRM_ATOMIC_UAPI_H_ +#define DRM_ATOMIC_UAPI_H_ + +struct drm_crtc_state; +struct drm_display_mode; +struct drm_property_blob; +struct drm_plane_state; +struct drm_crtc; +struct drm_connector_state; +struct dma_fence; +struct drm_framebuffer; + +int __must_check +drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, + const struct drm_display_mode *mode); +int __must_check +drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, + struct drm_property_blob *blob); +int __must_check +drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, + struct drm_crtc *crtc); +void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, + struct drm_framebuffer *fb); +void drm_atomic_set_fence_for_plane(struct drm_plane_state *plane_state, + struct dma_fence *fence); +int __must_check +drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, + struct drm_crtc *crtc); + +#endif -- cgit v1.2.3 From ad9ff96f65383f8296082158f7e44e466caaf71d Mon Sep 17 00:00:00 2001 From: Haneen Mohammed Date: Fri, 7 Sep 2018 20:41:36 +0300 Subject: drm/vkms: Add kerneldoc entry Add an initial kerneldoc entry for vkms with a todo list. Signed-off-by: Haneen Mohammed [danvet: Keep the todo.rst entry to point at the vkms docs instead.] Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180907174136.GA2648@haneenDRM --- Documentation/gpu/drivers.rst | 1 + Documentation/gpu/todo.rst | 7 +++++++ Documentation/gpu/vkms.rst | 24 ++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_drv.c | 9 +++++++++ 4 files changed, 41 insertions(+) create mode 100644 Documentation/gpu/vkms.rst (limited to 'Documentation') diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index 65be325bf282..7d2d3875ff1a 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -13,6 +13,7 @@ GPU Driver Documentation tve200 v3d vc4 + vkms bridge/dw-hdmi xen-front diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 4c7c3ab60089..77c2b3c25565 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -360,6 +360,13 @@ converting things over. For modeset tests we also first need a bit of infrastructure to use dumb buffers for untiled buffers, to be able to run all the non-i915 specific modeset tests. +Extend virtual test driver (VKMS) +--------------------------------- + +See the documentation of :ref:`VKMS ` for more details. This is an ideal +internship task, since it only requires a virtual machine and can be sized to +fit the available time. + Contact: Daniel Vetter Driver Specific diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst new file mode 100644 index 000000000000..0a6ea6216e41 --- /dev/null +++ b/Documentation/gpu/vkms.rst @@ -0,0 +1,24 @@ +.. _vkms: + +========================================== + drm/vkms Virtual Kernel Modesetting +========================================== + +.. kernel-doc:: drivers/gpu/drm/vkms/vkms_drv.c + :doc: vkms (Virtual Kernel Modesetting) + +TODO +==== + +CRC API +------- + +- Optimize CRC computation ``compute_crc()`` and plane blending ``blend()`` + +- Use the alpha value to blend vaddr_src with vaddr_dst instead of + overwriting it in ``blend()``. + +- Add igt test to check cleared alpha value for XRGB plane format. + +- Add igt test to check extreme alpha values i.e. fully opaque and fully + transparent (intermediate values are affected by hw-specific rounding modes). diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index 2d49ad31ad0b..07cfde1b4132 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -5,6 +5,15 @@ * (at your option) any later version. */ +/** + * DOC: vkms (Virtual Kernel Modesetting) + * + * vkms is a software-only model of a kms driver that is useful for testing, + * or for running X (or similar) on headless machines and be able to still + * use the GPU. vkms aims to enable a virtual display without the need for + * a hardware display capability. + */ + #include #include #include -- cgit v1.2.3 From 4ffe5aa53791ac5ab2c29e99f23c07cb85922dd5 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Mon, 4 Jun 2018 22:04:59 +0300 Subject: dt-bindings: display: renesas: du: document R8A77980 bindings Document the R-Car V3H (R8A77980) SoC in the R-Car DU bindings; the DU hardware has the same topology as in the R-Car V3M (R8A77970). Signed-off-by: Sergei Shtylyov Reviewed-by: Simon Horman Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- Documentation/devicetree/bindings/display/renesas,du.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index ec9d34be2ff7..caae2348a292 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -15,6 +15,7 @@ Required Properties: - "renesas,du-r8a7796" for R8A7796 (R-Car M3-W) compatible DU - "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU - "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU + - "renesas,du-r8a77980" for R8A77980 (R-Car V3H) compatible DU - "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU - reg: the memory-mapped I/O registers base address and length @@ -61,6 +62,7 @@ corresponding to each DU output. R8A7796 (R-Car M3-W) DPAD 0 HDMI 0 LVDS 0 - R8A77965 (R-Car M3-N) DPAD 0 HDMI 0 LVDS 0 - R8A77970 (R-Car V3M) DPAD 0 LVDS 0 - - + R8A77980 (R-Car V3H) DPAD 0 LVDS 0 - - R8A77995 (R-Car D3) DPAD 0 LVDS 0 LVDS 1 - -- cgit v1.2.3 From ab77eb4c4de77a3095abbc213b8f191c58ebdca1 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 5 Jun 2018 23:28:58 +0300 Subject: dt-bindings: display: renesas: lvds: document R8A77980 bindings Document the R-Car V3H (R8A77980) SoC in the R-Car LVDS bindings. Signed-off-by: Sergei Shtylyov Acked-by: Rob Herring Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt index 4f0ab3ed3b6f..5a4e379bb414 100644 --- a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt +++ b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt @@ -14,6 +14,7 @@ Required properties: - "renesas,r8a7795-lvds" for R8A7795 (R-Car H3) compatible LVDS encoders - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders + - "renesas,r8a77980-lvds" for R8A77980 (R-Car V3H) compatible LVDS encoders - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders - reg: Base address and length for the memory-mapped registers -- cgit v1.2.3 From 5c5b3b0ebe6d78cad645cc010d7e8fb81ccd099b Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sun, 16 Sep 2018 12:34:07 +0800 Subject: dt-bindings: sun4i-drm: add compatible for R40 HDMI PHY The Allwinner R40 HDMI PHY is currently the only one that seems to be able to select between two PLL inputs. Add a compatible string for it, and the pll-1 clock input definition. Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20180916043409.62374-3-icenowy@aosc.io --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 0bbb5d47f228..22d6dda587c5 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -107,6 +107,7 @@ Required properties: - compatible: value must be one of: * allwinner,sun8i-a83t-hdmi-phy * allwinner,sun8i-h3-hdmi-phy + * allwinner,sun8i-r40-hdmi-phy * allwinner,sun50i-a64-hdmi-phy - reg: base address and size of memory-mapped region - clocks: phandles to the clocks feeding the HDMI PHY @@ -116,9 +117,9 @@ Required properties: - resets: phandle to the reset controller driving the PHY - reset-names: must be "phy" -H3 and A64 HDMI PHY require additional clocks: +H3, A64 and R40 HDMI PHY require additional clocks: - pll-0: parent of phy clock - - pll-1: second possible phy clock parent (A64 only) + - pll-1: second possible phy clock parent (A64/R40 only) TV Encoder ---------- -- cgit v1.2.3 From 91e28030fd5deb56b5f14b870bc2e2c856435cca Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 25 Jul 2018 17:46:44 +0200 Subject: dt-bindings: exynos_dsim: update of graph bindings Of-graph bindings should describe ports present in the device, not the devices it can be connected to. The patch replaces verbose description with shorter but more precise one. While at it clock related properties are moved to the main node as it is their actual location. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae --- .../bindings/display/exynos/exynos_dsim.txt | 25 ++++++---------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt index 2fff8b406f4c..be377786e8cd 100644 --- a/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt +++ b/Documentation/devicetree/bindings/display/exynos/exynos_dsim.txt @@ -21,6 +21,9 @@ Required properties: - samsung,pll-clock-frequency: specifies frequency of the oscillator clock - #address-cells, #size-cells: should be set respectively to <1> and <0> according to DSI host bindings (see MIPI DSI bindings [1]) + - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst + mode + - samsung,esc-clock-frequency: specifies DSI frequency in escape mode Optional properties: - power-domains: a phandle to DSIM power domain node @@ -29,25 +32,9 @@ Child nodes: Should contain DSI peripheral nodes (see MIPI DSI bindings [1]). Video interfaces: - Device node can contain video interface port nodes according to [2]. - The following are properties specific to those nodes: - - port node inbound: - - reg: (required) must be 0. - port node outbound: - - reg: (required) must be 1. - - endpoint node connected from mic node (reg = 0): - - remote-endpoint: specifies the endpoint in mic node. This node is required - for Exynos5433 mipi dsi. So mic can access to panel node - throughout this dsi node. - endpoint node connected to panel node (reg = 1): - - remote-endpoint: specifies the endpoint in panel node. This node is - required in all kinds of exynos mipi dsi to represent - the connection between mipi dsi and panel. - - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst - mode - - samsung,esc-clock-frequency: specifies DSI frequency in escape mode + Device node can contain following video interface port nodes according to [2]: + 0: RGB input, + 1: DSI output [1]: Documentation/devicetree/bindings/display/mipi-dsi-bus.txt [2]: Documentation/devicetree/bindings/media/video-interfaces.txt -- cgit v1.2.3 From f48097d294d6f76a38bf1a1cb579aa99ede44297 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 20 Aug 2018 17:07:25 +0300 Subject: dt-bindings: display: renesas: du: Document r8a77990 bindings Document the E3 (r8a77990) SoC in the R-Car DU bindings. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Rob Herring Reviewed-by: Ulrich Hecht --- Documentation/devicetree/bindings/display/renesas,du.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/renesas,du.txt b/Documentation/devicetree/bindings/display/renesas,du.txt index caae2348a292..9de67be632d1 100644 --- a/Documentation/devicetree/bindings/display/renesas,du.txt +++ b/Documentation/devicetree/bindings/display/renesas,du.txt @@ -16,6 +16,7 @@ Required Properties: - "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU - "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU - "renesas,du-r8a77980" for R8A77980 (R-Car V3H) compatible DU + - "renesas,du-r8a77990" for R8A77990 (R-Car E3) compatible DU - "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU - reg: the memory-mapped I/O registers base address and length @@ -63,6 +64,7 @@ corresponding to each DU output. R8A77965 (R-Car M3-N) DPAD 0 HDMI 0 LVDS 0 - R8A77970 (R-Car V3M) DPAD 0 LVDS 0 - - R8A77980 (R-Car V3H) DPAD 0 LVDS 0 - - + R8A77990 (R-Car E3) DPAD 0 LVDS 0 LVDS 1 - R8A77995 (R-Car D3) DPAD 0 LVDS 0 LVDS 1 - -- cgit v1.2.3 From f9c32db12e2439ec9553a1a4c43d0ee308387790 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 20 Aug 2018 17:12:49 +0300 Subject: dt-bindings: display: renesas: lvds: Document r8a77990 bindings The E3 (r8a77990) supports two LVDS channels. Extend the binding to support them. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Rob Herring Reviewed-by: Ulrich Hecht Reviewed-by: Kieran Bingham --- Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt index 5a4e379bb414..13af7e2ac7e8 100644 --- a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt +++ b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt @@ -15,6 +15,7 @@ Required properties: - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders - "renesas,r8a77980-lvds" for R8A77980 (R-Car V3H) compatible LVDS encoders + - "renesas,r8a77990-lvds" for R8A77990 (R-Car E3) compatible LVDS encoders - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders - reg: Base address and length for the memory-mapped registers -- cgit v1.2.3 From 9734a7009de62c05e9b08fa65efb7c5214ab3f30 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 22 Aug 2018 15:27:16 +0300 Subject: dt-bindings: display: renesas: lvds: Add EXTAL and DU_DOTCLKIN clocks On the D3 and E3 SoCs, the LVDS encoder can derive its internal pixel clock from an externally supplied clock, either through the EXTAL pin or through one of the DU_DOTCLKINx pins. Add corresponding clocks to the DT bindings. To retain backward compatibility with DT that don't specify the clock-names property, the functional clock must always be specified first, and the clock-names property is optional when only the functional clock is specified. Signed-off-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Ulrich Hecht Reviewed-by: Kieran Bingham --- .../devicetree/bindings/display/bridge/renesas,lvds.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt index 13af7e2ac7e8..3aeb0ec06fd0 100644 --- a/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt +++ b/Documentation/devicetree/bindings/display/bridge/renesas,lvds.txt @@ -19,7 +19,17 @@ Required properties: - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders - reg: Base address and length for the memory-mapped registers -- clocks: A phandle + clock-specifier pair for the functional clock +- clocks: A list of phandles + clock-specifier pairs, one for each entry in + the clock-names property. +- clock-names: Name of the clocks. This property is model-dependent. + - The functional clock, which mandatory for all models, shall be listed + first, and shall be named "fck". + - On R8A77990 and R8A77995, the LVDS encoder can use the EXTAL or + DU_DOTCLKINx clocks. Those clocks are optional. When supplied they must be + named "extal" and "dclkin.x" respectively, with "x" being the DU_DOTCLKIN + numerical index. + - When the clocks property only contains the functional clock, the + clock-names property may be omitted. - resets: A phandle + reset specifier for the module reset Required nodes: -- cgit v1.2.3 From c2b70ffcd34eca60013d90bd6cd56e60b07adef8 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 25 Jun 2018 14:02:53 +0200 Subject: dt-bindings: display: sun4i-drm: Add R40 mixer compatibles R40 DE2 mixers are similar to those found in A83T, except it needs different clock settings. Add a compatibles for them. Reviewed-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Jernej Skrabec Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20180625120304.7543-14-jernej.skrabec@siol.net --- Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 22d6dda587c5..7854fff4fc16 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -376,6 +376,8 @@ Required properties: * allwinner,sun8i-a83t-de2-mixer-0 * allwinner,sun8i-a83t-de2-mixer-1 * allwinner,sun8i-h3-de2-mixer-0 + * allwinner,sun8i-r40-de2-mixer-0 + * allwinner,sun8i-r40-de2-mixer-1 * allwinner,sun8i-v3s-de2-mixer * allwinner,sun50i-a64-de2-mixer-0 * allwinner,sun50i-a64-de2-mixer-1 -- cgit v1.2.3