diff options
223 files changed, 5062 insertions, 3844 deletions
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt deleted file mode 100644 index 3a50a7862cf3..000000000000 --- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +++ /dev/null @@ -1,119 +0,0 @@ -Amlogic specific extensions to the Synopsys Designware HDMI Controller -====================================================================== - -The Amlogic Meson Synopsys Designware Integration is composed of : -- A Synopsys DesignWare HDMI Controller IP -- A TOP control block controlling the Clocks and PHY -- A custom HDMI PHY in order to convert video to TMDS signal - ___________________________________ -| HDMI TOP |<= HPD -|___________________________________| -| | | -| Synopsys HDMI | HDMI PHY |=> TMDS -| Controller |________________| -|___________________________________|<=> DDC - -The HDMI TOP block only supports HPD sensing. -The Synopsys HDMI Controller interrupt is routed through the -TOP Block interrupt. -Communication to the TOP Block and the Synopsys HDMI Controller is done -via a pair of dedicated addr+read/write registers. -The HDMI PHY is configured by registers in the HHI register block. - -Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux -selects either the ENCI encoder for the 576i or 480i formats or the ENCP -encoder for all the other formats including interlaced HD formats. - -The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate -DVI timings for the HDMI controller. - -Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare -HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF -audio source interfaces. - -Required properties: -- compatible: value should be different for each SoC family as : - - GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi" - - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" - - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" - followed by the common "amlogic,meson-gx-dw-hdmi" - - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-dw-hdmi" -- reg: Physical base address and length of the controller's registers. -- interrupts: The HDMI interrupt number -- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, - and the Amlogic Meson venci clocks as described in - Documentation/devicetree/bindings/clock/clock-bindings.txt, - the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci" -- resets, resets-names: must have the phandles to the HDMI apb, glue and phy - resets as described in : - Documentation/devicetree/bindings/reset/reset.txt, - the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy" - -Optional properties: -- hdmi-supply: Optional phandle to an external 5V regulator to power the HDMI - logic, as described in the file ../regulator/regulator.txt - -Required nodes: - -The connections to the HDMI ports are modeled using the OF graph -bindings specified in Documentation/devicetree/bindings/graph.txt. - -The following table lists for each supported model the port number -corresponding to each HDMI output and input. - - Port 0 Port 1 ------------------------------------------ - S905 (GXBB) VENC Input TMDS Output - S905X (GXL) VENC Input TMDS Output - S905D (GXL) VENC Input TMDS Output - S912 (GXM) VENC Input TMDS Output - S905X2 (G12A) VENC Input TMDS Output - S905Y2 (G12A) VENC Input TMDS Output - S905D2 (G12A) VENC Input TMDS Output - -Example: - -hdmi-connector { - compatible = "hdmi-connector"; - type = "a"; - - port { - hdmi_connector_in: endpoint { - remote-endpoint = <&hdmi_tx_tmds_out>; - }; - }; -}; - -hdmi_tx: hdmi-tx@c883a000 { - compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; - reg = <0x0 0xc883a000 0x0 0x1c>; - interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>; - resets = <&reset RESET_HDMITX_CAPB3>, - <&reset RESET_HDMI_SYSTEM_RESET>, - <&reset RESET_HDMI_TX>; - reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; - clocks = <&clkc CLKID_HDMI_PCLK>, - <&clkc CLKID_CLK81>, - <&clkc CLKID_GCLK_VENCI_INT0>; - clock-names = "isfr", "iahb", "venci"; - #address-cells = <1>; - #size-cells = <0>; - - /* VPU VENC Input */ - hdmi_tx_venc_port: port@0 { - reg = <0>; - - hdmi_tx_in: endpoint { - remote-endpoint = <&hdmi_tx_out>; - }; - }; - - /* TMDS Output */ - hdmi_tx_tmds_port: port@1 { - reg = <1>; - - hdmi_tx_tmds_out: endpoint { - remote-endpoint = <&hdmi_connector_in>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml new file mode 100644 index 000000000000..fb747682006d --- /dev/null +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 BayLibre, SAS +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/display/amlogic,meson-dw-hdmi.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic specific extensions to the Synopsys Designware HDMI Controller + +maintainers: + - Neil Armstrong <narmstrong@baylibre.com> + +description: | + The Amlogic Meson Synopsys Designware Integration is composed of + - A Synopsys DesignWare HDMI Controller IP + - A TOP control block controlling the Clocks and PHY + - A custom HDMI PHY in order to convert video to TMDS signal + ___________________________________ + | HDMI TOP |<= HPD + |___________________________________| + | | | + | Synopsys HDMI | HDMI PHY |=> TMDS + | Controller |________________| + |___________________________________|<=> DDC + + The HDMI TOP block only supports HPD sensing. + The Synopsys HDMI Controller interrupt is routed through the + TOP Block interrupt. + Communication to the TOP Block and the Synopsys HDMI Controller is done + via a pair of dedicated addr+read/write registers. + The HDMI PHY is configured by registers in the HHI register block. + + Pixel data arrives in "4:4:4" format from the VENC block and the VPU HDMI mux + selects either the ENCI encoder for the 576i or 480i formats or the ENCP + encoder for all the other formats including interlaced HD formats. + + The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate + DVI timings for the HDMI controller. + + Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare + HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF + audio source interfaces. + +properties: + compatible: + oneOf: + - items: + - enum: + - amlogic,meson-gxbb-dw-hdmi # GXBB (S905) + - amlogic,meson-gxl-dw-hdmi # GXL (S905X, S905D) + - amlogic,meson-gxm-dw-hdmi # GXM (S912) + - const: amlogic,meson-gx-dw-hdmi + - enum: + - amlogic,meson-g12a-dw-hdmi # G12A (S905X2, S905Y2, S905D2) + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 3 + + clock-names: + items: + - const: isfr + - const: iahb + - const: venci + + resets: + minItems: 3 + + reset-names: + items: + - const: hdmitx_apb + - const: hdmitx + - const: hdmitx_phy + + hdmi-supply: + description: phandle to an external 5V regulator to power the HDMI logic + allOf: + - $ref: /schemas/types.yaml#/definitions/phandle + + port@0: + type: object + description: + A port node pointing to the VENC Input port node. + + port@1: + type: object + description: + A port node pointing to the TMDS Output port node. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + - reset-names + - port@0 + - port@1 + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + hdmi_tx: hdmi-tx@c883a000 { + compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; + reg = <0xc883a000 0x1c>; + interrupts = <57>; + resets = <&reset_apb>, <&reset_hdmitx>, <&reset_hdmitx_phy>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clk_isfr>, <&clk_iahb>, <&clk_venci>; + clock-names = "isfr", "iahb", "venci"; + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; + + hdmi_tx_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + + /* TMDS Output */ + hdmi_tx_tmds_port: port@1 { + reg = <1>; + + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt deleted file mode 100644 index be40a780501c..000000000000 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +++ /dev/null @@ -1,121 +0,0 @@ -Amlogic Meson Display Controller -================================ - -The Amlogic Meson Display controller is composed of several components -that are going to be documented below: - -DMC|---------------VPU (Video Processing Unit)----------------|------HHI------| - | vd1 _______ _____________ _________________ | | -D |-------| |----| | | | | HDMI PLL | -D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK | -R |-------| |----| Processing | | | | | - | osd2 | | | |---| Enci ----------|----|-----VDAC------| -R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----| -A | osd1 | | | Blenders | | Encl ----------|----|---------------| -M |-------|______|----|____________| |________________| | | -___|__________________________________________________________|_______________| - - -VIU: Video Input Unit ---------------------- - -The Video Input Unit is in charge of the pixel scanout from the DDR memory. -It fetches the frames addresses, stride and parameters from the "Canvas" memory. -This part is also in charge of the CSC (Colorspace Conversion). -It can handle 2 OSD Planes and 2 Video Planes. - -VPP: Video Post Processing --------------------------- - -The Video Post Processing is in charge of the scaling and blending of the -various planes into a single pixel stream. -There is a special "pre-blending" used by the video planes with a dedicated -scaler and a "post-blending" to merge with the OSD Planes. -The OSD planes also have a dedicated scaler for one of the OSD. - -VENC: Video Encoders --------------------- - -The VENC is composed of the multiple pixel encoders : - - ENCI : Interlace Video encoder for CVBS and Interlace HDMI - - ENCP : Progressive Video Encoder for HDMI - - ENCL : LCD LVDS Encoder -The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock -tree and provides the scanout clock to the VPP and VIU. -The ENCI is connected to a single VDAC for Composite Output. -The ENCI and ENCP are connected to an on-chip HDMI Transceiver. - -Device Tree Bindings: ---------------------- - -VPU: Video Processing Unit --------------------------- - -Required properties: -- compatible: value should be different for each SoC family as : - - GXBB (S905) : "amlogic,meson-gxbb-vpu" - - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" - - GXM (S912) : "amlogic,meson-gxm-vpu" - followed by the common "amlogic,meson-gx-vpu" - - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-vpu" -- reg: base address and size of he following memory-mapped regions : - - vpu - - hhi -- reg-names: should contain the names of the previous memory regions -- interrupts: should contain the VENC Vsync interrupt number -- amlogic,canvas: phandle to canvas provider node as described in the file - ../soc/amlogic/amlogic,canvas.txt - -Optional properties: -- power-domains: Optional phandle to associated power domain as described in - the file ../power/power_domain.txt - -Required nodes: - -The connections to the VPU output video ports are modeled using the OF graph -bindings specified in Documentation/devicetree/bindings/graph.txt. - -The following table lists for each supported model the port number -corresponding to each VPU output. - - Port 0 Port 1 ------------------------------------------ - S905 (GXBB) CVBS VDAC HDMI-TX - S905X (GXL) CVBS VDAC HDMI-TX - S905D (GXL) CVBS VDAC HDMI-TX - S912 (GXM) CVBS VDAC HDMI-TX - S905X2 (G12A) CVBS VDAC HDMI-TX - S905Y2 (G12A) CVBS VDAC HDMI-TX - S905D2 (G12A) CVBS VDAC HDMI-TX - -Example: - -tv-connector { - compatible = "composite-video-connector"; - - port { - tv_connector_in: endpoint { - remote-endpoint = <&cvbs_vdac_out>; - }; - }; -}; - -vpu: vpu@d0100000 { - compatible = "amlogic,meson-gxbb-vpu"; - reg = <0x0 0xd0100000 0x0 0x100000>, - <0x0 0xc883c000 0x0 0x1000>, - <0x0 0xc8838000 0x0 0x1000>; - reg-names = "vpu", "hhi", "dmc"; - interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>; - #address-cells = <1>; - #size-cells = <0>; - - /* CVBS VDAC output port */ - port@0 { - reg = <0>; - - cvbs_vdac_out: endpoint { - remote-endpoint = <&tv_connector_in>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml new file mode 100644 index 000000000000..d1205a6697a0 --- /dev/null +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 BayLibre, SAS +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/display/amlogic,meson-vpu.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic Meson Display Controller + +maintainers: + - Neil Armstrong <narmstrong@baylibre.com> + +description: | + The Amlogic Meson Display controller is composed of several components + that are going to be documented below + + DMC|---------------VPU (Video Processing Unit)----------------|------HHI------| + | vd1 _______ _____________ _________________ | | + D |-------| |----| | | | | HDMI PLL | + D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK | + R |-------| |----| Processing | | | | | + | osd2 | | | |---| Enci ----------|----|-----VDAC------| + R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----| + A | osd1 | | | Blenders | | Encl ----------|----|---------------| + M |-------|______|----|____________| |________________| | | + ___|__________________________________________________________|_______________| + + + VIU: Video Input Unit + --------------------- + + The Video Input Unit is in charge of the pixel scanout from the DDR memory. + It fetches the frames addresses, stride and parameters from the "Canvas" memory. + This part is also in charge of the CSC (Colorspace Conversion). + It can handle 2 OSD Planes and 2 Video Planes. + + VPP: Video Post Processing + -------------------------- + + The Video Post Processing is in charge of the scaling and blending of the + various planes into a single pixel stream. + There is a special "pre-blending" used by the video planes with a dedicated + scaler and a "post-blending" to merge with the OSD Planes. + The OSD planes also have a dedicated scaler for one of the OSD. + + VENC: Video Encoders + -------------------- + + The VENC is composed of the multiple pixel encoders + - ENCI : Interlace Video encoder for CVBS and Interlace HDMI + - ENCP : Progressive Video Encoder for HDMI + - ENCL : LCD LVDS Encoder + The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock + tree and provides the scanout clock to the VPP and VIU. + The ENCI is connected to a single VDAC for Composite Output. + The ENCI and ENCP are connected to an on-chip HDMI Transceiver. + +properties: + compatible: + oneOf: + - items: + - enum: + - amlogic,meson-gxbb-vpu # GXBB (S905) + - amlogic,meson-gxl-vpu # GXL (S905X, S905D) + - amlogic,meson-gxm-vpu # GXM (S912) + - const: amlogic,meson-gx-vpu + - enum: + - amlogic,meson-g12a-vpu # G12A (S905X2, S905Y2, S905D2) + + reg: + maxItems: 2 + + reg-names: + items: + - const: vpu + - const: hhi + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + description: phandle to the associated power domain + + port@0: + type: object + description: + A port node pointing to the CVBS VDAC port node. + + port@1: + type: object + description: + A port node pointing to the HDMI-TX port node. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +required: + - compatible + - reg + - interrupts + - port@0 + - port@1 + - "#address-cells" + - "#size-cells" + +examples: + - | + vpu: vpu@d0100000 { + compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; + reg = <0xd0100000 0x100000>, <0xc883c000 0x1000>; + reg-names = "vpu", "hhi"; + interrupts = <3>; + #address-cells = <1>; + #size-cells = <0>; + + /* CVBS VDAC output port */ + port@0 { + reg = <0>; + + cvbs_vdac_out: endpoint { + remote-endpoint = <&tv_connector_in>; + }; + }; + + /* HDMI TX output port */ + port@1 { + reg = <1>; + + hdmi_tx_out: endpoint { + remote-endpoint = <&hdmi_tx_in>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/connector/hdmi-connector.txt b/Documentation/devicetree/bindings/display/connector/hdmi-connector.txt index 508aee461e0d..aeb07c4bd703 100644 --- a/Documentation/devicetree/bindings/display/connector/hdmi-connector.txt +++ b/Documentation/devicetree/bindings/display/connector/hdmi-connector.txt @@ -9,6 +9,7 @@ Optional properties: - label: a symbolic name for the connector - hpd-gpios: HPD GPIO number - ddc-i2c-bus: phandle link to the I2C controller used for DDC EDID probing +- ddc-en-gpios: signal to enable DDC bus Required nodes: - Video port for HDMI input diff --git a/Documentation/devicetree/bindings/display/panel/nec,nl8048hl11.yaml b/Documentation/devicetree/bindings/display/panel/nec,nl8048hl11.yaml new file mode 100644 index 000000000000..aa788eaa2f71 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/nec,nl8048hl11.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/nec,nl8048hl11.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NEC NL8048HL11 4.1" WVGA TFT LCD panel + +description: + The NEC NL8048HL11 is a 4.1" WVGA TFT LCD panel with a 24-bit RGB parallel + data interface and an SPI control interface. + +maintainers: + - Laurent Pinchart <laurent.pinchart@ideasonboard.com> + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: nec,nl8048hl11 + + label: true + port: true + reg: true + reset-gpios: true + + spi-max-frequency: + maximum: 10000000 + +required: + - compatible + - reg + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + lcd_panel: panel@0 { + compatible = "nec,nl8048hl11"; + reg = <0>; + spi-max-frequency = <10000000>; + + reset-gpios = <&gpio7 7 GPIO_ACTIVE_LOW>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/ti,nspire.yaml b/Documentation/devicetree/bindings/display/panel/ti,nspire.yaml new file mode 100644 index 000000000000..5c5a3b519e31 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/ti,nspire.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/ti,nspire.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments NSPIRE Display Panels + +maintainers: + - Linus Walleij <linus.walleij@linaro.org> + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + enum: + - ti,nspire-cx-lcd-panel + - ti,nspire-classic-lcd-panel + port: true + +required: + - compatible + +additionalProperties: false + +examples: + - | + panel { + compatible = "ti,nspire-cx-lcd-panel"; + port { + panel_in: endpoint { + remote-endpoint = <&pads>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6992bbbbffab..29dcc6f8a64a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -511,6 +511,8 @@ patternProperties: description: Lenovo Group Ltd. "^lg,.*": description: LG Corporation + "^lgphilips,.*": + description: LG Display "^libretech,.*": description: Shenzhen Libre Technology Co., Ltd "^licheepi,.*": @@ -933,6 +935,9 @@ patternProperties: description: Tecon Microprocessor Technologies, LLC. "^topeet,.*": description: Topeet + "^toppoly,.*": + description: TPO (deprecated, use tpo) + deprecated: true "^toradex,.*": description: Toradex AG "^toshiba,.*": diff --git a/MAINTAINERS b/MAINTAINERS index 1bd7b9c2d146..c2d975da561f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5334,8 +5334,8 @@ L: linux-amlogic@lists.infradead.org W: http://linux-meson.com/ S: Supported F: drivers/gpu/drm/meson/ -F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt -F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml +F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml F: Documentation/gpu/meson.rst T: git git://anongit.freedesktop.org/drm/drm-misc diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index e8c7310cb800..dcfb01e7c6f4 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ - reservation.o seqno-fence.o + dma-resv.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/dma-buf.c b/drivers/dma-buf/dma-buf.c index f45bfb29ef96..433d91d710e4 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -21,7 +21,7 @@ #include <linux/module.h> #include <linux/seq_file.h> #include <linux/poll.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/mm.h> #include <linux/mount.h> #include <linux/pseudo_fs.h> @@ -104,8 +104,8 @@ static int dma_buf_release(struct inode *inode, struct file *file) list_del(&dmabuf->list_node); mutex_unlock(&db_list.lock); - if (dmabuf->resv == (struct reservation_object *)&dmabuf[1]) - reservation_object_fini(dmabuf->resv); + if (dmabuf->resv == (struct dma_resv *)&dmabuf[1]) + dma_resv_fini(dmabuf->resv); module_put(dmabuf->owner); kfree(dmabuf); @@ -165,7 +165,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) * To support cross-device and cross-driver synchronization of buffer access * implicit fences (represented internally in the kernel with &struct fence) can * be attached to a &dma_buf. The glue for that and a few related things are - * provided in the &reservation_object structure. + * provided in the &dma_resv structure. * * Userspace can query the state of these implicitly tracked fences using poll() * and related system calls: @@ -195,8 +195,8 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) static __poll_t dma_buf_poll(struct file *file, poll_table *poll) { struct dma_buf *dmabuf; - struct reservation_object *resv; - struct reservation_object_list *fobj; + struct dma_resv *resv; + struct dma_resv_list *fobj; struct dma_fence *fence_excl; __poll_t events; unsigned shared_count, seq; @@ -506,13 +506,13 @@ err_alloc_file: struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) { struct dma_buf *dmabuf; - struct reservation_object *resv = exp_info->resv; + struct dma_resv *resv = exp_info->resv; struct file *file; size_t alloc_size = sizeof(struct dma_buf); int ret; if (!exp_info->resv) - alloc_size += sizeof(struct reservation_object); + alloc_size += sizeof(struct dma_resv); else /* prevent &dma_buf[1] == dma_buf->resv */ alloc_size += 1; @@ -544,8 +544,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0; if (!resv) { - resv = (struct reservation_object *)&dmabuf[1]; - reservation_object_init(resv); + resv = (struct dma_resv *)&dmabuf[1]; + dma_resv_init(resv); } dmabuf->resv = resv; @@ -909,11 +909,11 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf, { bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE); - struct reservation_object *resv = dmabuf->resv; + struct dma_resv *resv = dmabuf->resv; long ret; /* Wait on any implicit rendering fences */ - ret = reservation_object_wait_timeout_rcu(resv, write, true, + ret = dma_resv_wait_timeout_rcu(resv, write, true, MAX_SCHEDULE_TIMEOUT); if (ret < 0) return ret; @@ -1154,8 +1154,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) int ret; struct dma_buf *buf_obj; struct dma_buf_attachment *attach_obj; - struct reservation_object *robj; - struct reservation_object_list *fobj; + struct dma_resv *robj; + struct dma_resv_list *fobj; struct dma_fence *fence; unsigned seq; int count = 0, attach_count, shared_count, i; diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 12c6f64c0bc2..d3fbd950be94 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -13,6 +13,8 @@ #include <linux/slab.h> #include <linux/dma-fence-array.h> +#define PENDING_ERROR 1 + static const char *dma_fence_array_get_driver_name(struct dma_fence *fence) { return "dma_fence_array"; @@ -23,10 +25,29 @@ static const char *dma_fence_array_get_timeline_name(struct dma_fence *fence) return "unbound"; } +static void dma_fence_array_set_pending_error(struct dma_fence_array *array, + int error) +{ + /* + * Propagate the first error reported by any of our fences, but only + * before we ourselves are signaled. + */ + if (error) + cmpxchg(&array->base.error, PENDING_ERROR, error); +} + +static void dma_fence_array_clear_pending_error(struct dma_fence_array *array) +{ + /* Clear the error flag if not actually set. */ + cmpxchg(&array->base.error, PENDING_ERROR, 0); +} + static void irq_dma_fence_array_work(struct irq_work *wrk) { struct dma_fence_array *array = container_of(wrk, typeof(*array), work); + dma_fence_array_clear_pending_error(array); + dma_fence_signal(&array->base); dma_fence_put(&array->base); } @@ -38,6 +59,8 @@ static void dma_fence_array_cb_func(struct dma_fence *f, container_of(cb, struct dma_fence_array_cb, cb); struct dma_fence_array *array = array_cb->array; + dma_fence_array_set_pending_error(array, f->error); + if (atomic_dec_and_test(&array->num_pending)) irq_work_queue(&array->work); else @@ -63,9 +86,14 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence) dma_fence_get(&array->base); if (dma_fence_add_callback(array->fences[i], &cb[i].cb, dma_fence_array_cb_func)) { + int error = array->fences[i]->error; + + dma_fence_array_set_pending_error(array, error); dma_fence_put(&array->base); - if (atomic_dec_and_test(&array->num_pending)) + if (atomic_dec_and_test(&array->num_pending)) { + dma_fence_array_clear_pending_error(array); return false; + } } } @@ -142,6 +170,8 @@ struct dma_fence_array *dma_fence_array_create(int num_fences, atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences); array->fences = fences; + array->base.error = PENDING_ERROR; + return array; } EXPORT_SYMBOL(dma_fence_array_create); diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 59ac96ec7ba8..2c136aee3e79 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -60,7 +60,7 @@ static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(1); * * - Then there's also implicit fencing, where the synchronization points are * implicitly passed around as part of shared &dma_buf instances. Such - * implicit fences are stored in &struct reservation_object through the + * implicit fences are stored in &struct dma_resv through the * &dma_buf.resv pointer. */ @@ -129,31 +129,27 @@ EXPORT_SYMBOL(dma_fence_context_alloc); int dma_fence_signal_locked(struct dma_fence *fence) { struct dma_fence_cb *cur, *tmp; - int ret = 0; + struct list_head cb_list; lockdep_assert_held(fence->lock); - if (WARN_ON(!fence)) + if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, + &fence->flags))) return -EINVAL; - if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { - ret = -EINVAL; + /* Stash the cb_list before replacing it with the timestamp */ + list_replace(&fence->cb_list, &cb_list); - /* - * we might have raced with the unlocked dma_fence_signal, - * still run through all callbacks - */ - } else { - fence->timestamp = ktime_get(); - set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); - trace_dma_fence_signaled(fence); - } + fence->timestamp = ktime_get(); + set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); + trace_dma_fence_signaled(fence); - list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { - list_del_init(&cur->node); + list_for_each_entry_safe(cur, tmp, &cb_list, node) { + INIT_LIST_HEAD(&cur->node); cur->func(fence, cur); } - return ret; + + return 0; } EXPORT_SYMBOL(dma_fence_signal_locked); @@ -173,28 +169,16 @@ EXPORT_SYMBOL(dma_fence_signal_locked); int dma_fence_signal(struct dma_fence *fence) { unsigned long flags; + int ret; if (!fence) return -EINVAL; - if (test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - return -EINVAL; - - fence->timestamp = ktime_get(); - set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags); - trace_dma_fence_signaled(fence); - - if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &fence->flags)) { - struct dma_fence_cb *cur, *tmp; + spin_lock_irqsave(fence->lock, flags); + ret = dma_fence_signal_locked(fence); + spin_unlock_irqrestore(fence->lock, flags); - spin_lock_irqsave(fence->lock, flags); - list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { - list_del_init(&cur->node); - cur->func(fence, cur); - } - spin_unlock_irqrestore(fence->lock, flags); - } - return 0; + return ret; } EXPORT_SYMBOL(dma_fence_signal); @@ -248,7 +232,8 @@ void dma_fence_release(struct kref *kref) trace_dma_fence_destroy(fence); - if (WARN(!list_empty(&fence->cb_list), + if (WARN(!list_empty(&fence->cb_list) && + !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags), "Fence %s:%s:%llx:%llx released with pending signals!\n", fence->ops->get_driver_name(fence), fence->ops->get_timeline_name(fence), diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/dma-resv.c index ad6775b32a73..42a8f3f11681 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/dma-resv.c @@ -32,7 +32,7 @@ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> */ -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/export.h> /** @@ -56,16 +56,15 @@ const char reservation_seqcount_string[] = "reservation_seqcount"; EXPORT_SYMBOL(reservation_seqcount_string); /** - * reservation_object_list_alloc - allocate fence list + * dma_resv_list_alloc - allocate fence list * @shared_max: number of fences we need space for * - * Allocate a new reservation_object_list and make sure to correctly initialize + * Allocate a new dma_resv_list and make sure to correctly initialize * shared_max. */ -static struct reservation_object_list * -reservation_object_list_alloc(unsigned int shared_max) +static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max) { - struct reservation_object_list *list; + struct dma_resv_list *list; list = kmalloc(offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL); if (!list) @@ -78,12 +77,12 @@ reservation_object_list_alloc(unsigned int shared_max) } /** - * reservation_object_list_free - free fence list + * dma_resv_list_free - free fence list * @list: list to free * - * Free a reservation_object_list and make sure to drop all references. + * Free a dma_resv_list and make sure to drop all references. */ -static void reservation_object_list_free(struct reservation_object_list *list) +static void dma_resv_list_free(struct dma_resv_list *list) { unsigned int i; @@ -97,10 +96,10 @@ static void reservation_object_list_free(struct reservation_object_list *list) } /** - * reservation_object_init - initialize a reservation object + * dma_resv_init - initialize a reservation object * @obj: the reservation object */ -void reservation_object_init(struct reservation_object *obj) +void dma_resv_init(struct dma_resv *obj) { ww_mutex_init(&obj->lock, &reservation_ww_class); @@ -109,15 +108,15 @@ void reservation_object_init(struct reservation_object *obj) RCU_INIT_POINTER(obj->fence, NULL); RCU_INIT_POINTER(obj->fence_excl, NULL); } -EXPORT_SYMBOL(reservation_object_init); +EXPORT_SYMBOL(dma_resv_init); /** - * reservation_object_fini - destroys a reservation object + * dma_resv_fini - destroys a reservation object * @obj: the reservation object */ -void reservation_object_fini(struct reservation_object *obj) +void dma_resv_fini(struct dma_resv *obj) { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; struct dma_fence *excl; /* @@ -129,32 +128,31 @@ void reservation_object_fini(struct reservation_object *obj) dma_fence_put(excl); fobj = rcu_dereference_protected(obj->fence, 1); - reservation_object_list_free(fobj); + dma_resv_list_free(fobj); ww_mutex_destroy(&obj->lock); } -EXPORT_SYMBOL(reservation_object_fini); +EXPORT_SYMBOL(dma_resv_fini); /** - * reservation_object_reserve_shared - Reserve space to add shared fences to - * a reservation_object. + * dma_resv_reserve_shared - Reserve space to add shared fences to + * a dma_resv. * @obj: reservation object * @num_fences: number of fences we want to add * - * Should be called before reservation_object_add_shared_fence(). Must + * Should be called before dma_resv_add_shared_fence(). Must * be called with obj->lock held. * * RETURNS * Zero for success, or -errno */ -int reservation_object_reserve_shared(struct reservation_object *obj, - unsigned int num_fences) +int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences) { - struct reservation_object_list *old, *new; + struct dma_resv_list *old, *new; unsigned int i, j, k, max; - reservation_object_assert_held(obj); + dma_resv_assert_held(obj); - old = reservation_object_get_list(obj); + old = dma_resv_get_list(obj); if (old && old->shared_max) { if ((old->shared_count + num_fences) <= old->shared_max) @@ -166,7 +164,7 @@ int reservation_object_reserve_shared(struct reservation_object *obj, max = 4; } - new = reservation_object_list_alloc(max); + new = dma_resv_list_alloc(max); if (!new) return -ENOMEM; @@ -180,7 +178,7 @@ int reservation_object_reserve_shared(struct reservation_object *obj, struct dma_fence *fence; fence = rcu_dereference_protected(old->shared[i], - reservation_object_held(obj)); + dma_resv_held(obj)); if (dma_fence_is_signaled(fence)) RCU_INIT_POINTER(new->shared[--k], fence); else @@ -206,35 +204,34 @@ int reservation_object_reserve_shared(struct reservation_object *obj, struct dma_fence *fence; fence = rcu_dereference_protected(new->shared[i], - reservation_object_held(obj)); + dma_resv_held(obj)); dma_fence_put(fence); } kfree_rcu(old, rcu); return 0; } -EXPORT_SYMBOL(reservation_object_reserve_shared); +EXPORT_SYMBOL(dma_resv_reserve_shared); /** - * reservation_object_add_shared_fence - Add a fence to a shared slot + * dma_resv_add_shared_fence - Add a fence to a shared slot * @obj: the reservation object * @fence: the shared fence to add * * Add a fence to a shared slot, obj->lock must be held, and - * reservation_object_reserve_shared() has been called. + * dma_resv_reserve_shared() has been called. */ -void reservation_object_add_shared_fence(struct reservation_object *obj, - struct dma_fence *fence) +void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence) { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; struct dma_fence *old; unsigned int i, count; dma_fence_get(fence); - reservation_object_assert_held(obj); + dma_resv_assert_held(obj); - fobj = reservation_object_get_list(obj); + fobj = dma_resv_get_list(obj); count = fobj->shared_count; preempt_disable(); @@ -243,7 +240,7 @@ void reservation_object_add_shared_fence(struct reservation_object *obj, for (i = 0; i < count; ++i) { old = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(obj)); + dma_resv_held(obj)); if (old->context == fence->context || dma_fence_is_signaled(old)) goto replace; @@ -262,25 +259,24 @@ replace: preempt_enable(); dma_fence_put(old); } -EXPORT_SYMBOL(reservation_object_add_shared_fence); +EXPORT_SYMBOL(dma_resv_add_shared_fence); /** - * reservation_object_add_excl_fence - Add an exclusive fence. + * dma_resv_add_excl_fence - Add an exclusive fence. * @obj: the reservation object * @fence: the shared fence to add * * Add a fence to the exclusive slot. The obj->lock must be held. */ -void reservation_object_add_excl_fence(struct reservation_object *obj, - struct dma_fence *fence) +void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence) { - struct dma_fence *old_fence = reservation_object_get_excl(obj); - struct reservation_object_list *old; + struct dma_fence *old_fence = dma_resv_get_excl(obj); + struct dma_resv_list *old; u32 i = 0; - reservation_object_assert_held(obj); + dma_resv_assert_held(obj); - old = reservation_object_get_list(obj); + old = dma_resv_get_list(obj); if (old) i = old->shared_count; @@ -299,27 +295,26 @@ void reservation_object_add_excl_fence(struct reservation_object *obj, /* inplace update, no shared fences */ while (i--) dma_fence_put(rcu_dereference_protected(old->shared[i], - reservation_object_held(obj))); + dma_resv_held(obj))); dma_fence_put(old_fence); } -EXPORT_SYMBOL(reservation_object_add_excl_fence); +EXPORT_SYMBOL(dma_resv_add_excl_fence); /** -* reservation_object_copy_fences - Copy all fences from src to dst. +* dma_resv_copy_fences - Copy all fences from src to dst. * @dst: the destination reservation object * @src: the source reservation object * * Copy all fences from src to dst. dst-lock must be held. */ -int reservation_object_copy_fences(struct reservation_object *dst, - struct reservation_object *src) +int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src) { - struct reservation_object_list *src_list, *dst_list; + struct dma_resv_list *src_list, *dst_list; struct dma_fence *old, *new; unsigned i; - reservation_object_assert_held(dst); + dma_resv_assert_held(dst); rcu_read_lock(); src_list = rcu_dereference(src->fence); @@ -330,7 +325,7 @@ retry: rcu_read_unlock(); - dst_list = reservation_object_list_alloc(shared_count); + dst_list = dma_resv_list_alloc(shared_count); if (!dst_list) return -ENOMEM; @@ -351,7 +346,7 @@ retry: continue; if (!dma_fence_get_rcu(fence)) { - reservation_object_list_free(dst_list); + dma_resv_list_free(dst_list); src_list = rcu_dereference(src->fence); goto retry; } @@ -370,8 +365,8 @@ retry: new = dma_fence_get_rcu_safe(&src->fence_excl); rcu_read_unlock(); - src_list = reservation_object_get_list(dst); - old = reservation_object_get_excl(dst); + src_list = dma_resv_get_list(dst); + old = dma_resv_get_excl(dst); preempt_disable(); write_seqcount_begin(&dst->seq); @@ -381,15 +376,15 @@ retry: write_seqcount_end(&dst->seq); preempt_enable(); - reservation_object_list_free(src_list); + dma_resv_list_free(src_list); dma_fence_put(old); return 0; } -EXPORT_SYMBOL(reservation_object_copy_fences); +EXPORT_SYMBOL(dma_resv_copy_fences); /** - * reservation_object_get_fences_rcu - Get an object's shared and exclusive + * dma_resv_get_fences_rcu - Get an object's shared and exclusive * fences without update side lock held * @obj: the reservation object * @pfence_excl: the returned exclusive fence (or NULL) @@ -401,10 +396,10 @@ EXPORT_SYMBOL(reservation_object_copy_fences); * exclusive fence is not specified the fence is put into the array of the * shared fences as well. Returns either zero or -ENOMEM. */ -int reservation_object_get_fences_rcu(struct reservation_object *obj, - struct dma_fence **pfence_excl, - unsigned *pshared_count, - struct dma_fence ***pshared) +int dma_resv_get_fences_rcu(struct dma_resv *obj, + struct dma_fence **pfence_excl, + unsigned *pshared_count, + struct dma_fence ***pshared) { struct dma_fence **shared = NULL; struct dma_fence *fence_excl; @@ -412,7 +407,7 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, int ret = 1; do { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; unsigned int i, seq; size_t sz = 0; @@ -487,10 +482,10 @@ unlock: *pshared = shared; return ret; } -EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu); +EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu); /** - * reservation_object_wait_timeout_rcu - Wait on reservation's objects + * dma_resv_wait_timeout_rcu - Wait on reservation's objects * shared and/or exclusive fences. * @obj: the reservation object * @wait_all: if true, wait on all fences, else wait on just exclusive fence @@ -501,9 +496,9 @@ EXPORT_SYMBOL_GPL(reservation_object_get_fences_rcu); * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or * greater than zer on success. */ -long reservation_object_wait_timeout_rcu(struct reservation_object *obj, - bool wait_all, bool intr, - unsigned long timeout) +long dma_resv_wait_timeout_rcu(struct dma_resv *obj, + bool wait_all, bool intr, + unsigned long timeout) { struct dma_fence *fence; unsigned seq, shared_count; @@ -531,8 +526,7 @@ retry: } if (wait_all) { - struct reservation_object_list *fobj = - rcu_dereference(obj->fence); + struct dma_resv_list *fobj = rcu_dereference(obj->fence); if (fobj) shared_count = fobj->shared_count; @@ -575,11 +569,10 @@ unlock_retry: rcu_read_unlock(); goto retry; } -EXPORT_SYMBOL_GPL(reservation_object_wait_timeout_rcu); +EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu); -static inline int -reservation_object_test_signaled_single(struct dma_fence *passed_fence) +static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) { struct dma_fence *fence, *lfence = passed_fence; int ret = 1; @@ -596,7 +589,7 @@ reservation_object_test_signaled_single(struct dma_fence *passed_fence) } /** - * reservation_object_test_signaled_rcu - Test if a reservation object's + * dma_resv_test_signaled_rcu - Test if a reservation object's * fences have been signaled. * @obj: the reservation object * @test_all: if true, test all fences, otherwise only test the exclusive @@ -605,8 +598,7 @@ reservation_object_test_signaled_single(struct dma_fence *passed_fence) * RETURNS * true if all fences signaled, else false */ -bool reservation_object_test_signaled_rcu(struct reservation_object *obj, - bool test_all) +bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all) { unsigned seq, shared_count; int ret; @@ -620,8 +612,7 @@ retry: if (test_all) { unsigned i; - struct reservation_object_list *fobj = - rcu_dereference(obj->fence); + struct dma_resv_list *fobj = rcu_dereference(obj->fence); if (fobj) shared_count = fobj->shared_count; @@ -629,7 +620,7 @@ retry: for (i = 0; i < shared_count; ++i) { struct dma_fence *fence = rcu_dereference(fobj->shared[i]); - ret = reservation_object_test_signaled_single(fence); + ret = dma_resv_test_signaled_single(fence); if (ret < 0) goto retry; else if (!ret) @@ -644,8 +635,7 @@ retry: struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl); if (fence_excl) { - ret = reservation_object_test_signaled_single( - fence_excl); + ret = dma_resv_test_signaled_single(fence_excl); if (ret < 0) goto retry; @@ -657,4 +647,4 @@ retry: rcu_read_unlock(); return ret; } -EXPORT_SYMBOL_GPL(reservation_object_test_signaled_rcu); +EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu); diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index 051f6c2873c7..6713cfb1995c 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -132,17 +132,14 @@ static void timeline_fence_release(struct dma_fence *fence) { struct sync_pt *pt = dma_fence_to_sync_pt(fence); struct sync_timeline *parent = dma_fence_parent(fence); + unsigned long flags; + spin_lock_irqsave(fence->lock, flags); if (!list_empty(&pt->link)) { - unsigned long flags; - - spin_lock_irqsave(fence->lock, flags); - if (!list_empty(&pt->link)) { - list_del(&pt->link); - rb_erase(&pt->node, &parent->pt_tree); - } - spin_unlock_irqrestore(fence->lock, flags); + list_del(&pt->link); + rb_erase(&pt->node, &parent->pt_tree); } + spin_unlock_irqrestore(fence->lock, flags); sync_timeline_put(parent); dma_fence_free(fence); @@ -265,7 +262,8 @@ static struct sync_pt *sync_pt_create(struct sync_timeline *obj, p = &parent->rb_left; } else { if (dma_fence_get_rcu(&other->base)) { - dma_fence_put(&pt->base); + sync_timeline_put(obj); + kfree(pt); pt = other; goto unlock; } diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index ee4d1a96d779..25c5c071645b 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -419,7 +419,7 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, * info->num_fences. */ if (!info.num_fences) { - info.status = dma_fence_is_signaled(sync_file->fence); + info.status = dma_fence_get_status(sync_file->fence); goto no_fences; } else { info.status = 1; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index e0c47ae52fc1..42b936b6bbf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -218,14 +218,14 @@ void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo) static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, struct amdgpu_amdkfd_fence *ef) { - struct reservation_object *resv = bo->tbo.base.resv; - struct reservation_object_list *old, *new; + struct dma_resv *resv = bo->tbo.base.resv; + struct dma_resv_list *old, *new; unsigned int i, j, k; if (!ef) return -EINVAL; - old = reservation_object_get_list(resv); + old = dma_resv_get_list(resv); if (!old) return 0; @@ -241,7 +241,7 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, struct dma_fence *f; f = rcu_dereference_protected(old->shared[i], - reservation_object_held(resv)); + dma_resv_held(resv)); if (f->context == ef->base.context) RCU_INIT_POINTER(new->shared[--j], f); @@ -263,7 +263,7 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, struct dma_fence *f; f = rcu_dereference_protected(new->shared[i], - reservation_object_held(resv)); + dma_resv_held(resv)); dma_fence_put(f); } kfree_rcu(old, rcu); @@ -887,7 +887,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, AMDGPU_FENCE_OWNER_KFD, false); if (ret) goto wait_pd_fail; - ret = reservation_object_reserve_shared(vm->root.base.bo->tbo.base.resv, 1); + ret = dma_resv_reserve_shared(vm->root.base.bo->tbo.base.resv, 1); if (ret) goto reserve_shared_fail; amdgpu_bo_fence(vm->root.base.bo, @@ -2133,7 +2133,7 @@ int amdgpu_amdkfd_add_gws_to_process(void *info, void *gws, struct kgd_mem **mem * Add process eviction fence to bo so they can * evict each other. */ - ret = reservation_object_reserve_shared(gws_bo->tbo.base.resv, 1); + ret = dma_resv_reserve_shared(gws_bo->tbo.base.resv, 1); if (ret) goto reserve_shared_fail; amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 9ccf32c5456a..8c50be56f458 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -730,7 +730,7 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) list_for_each_entry(e, &p->validated, tv.head) { struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo); - struct reservation_object *resv = bo->tbo.base.resv; + struct dma_resv *resv = bo->tbo.base.resv; r = amdgpu_sync_resv(p->adev, &p->job->sync, resv, p->filp, amdgpu_bo_explicit_sync(bo)); @@ -1727,7 +1727,7 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, *map = mapping; /* Double check that the BO is reserved by this CS */ - if (reservation_object_locking_ctx((*bo)->tbo.base.resv) != &parser->ticket) + if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->ticket) return -EINVAL; if (!((*bo)->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index f453e277ed24..1d4aaa9580f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -205,7 +205,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, goto unpin; } - r = reservation_object_get_fences_rcu(new_abo->tbo.base.resv, &work->excl, + r = dma_resv_get_fences_rcu(new_abo->tbo.base.resv, &work->excl, &work->shared_count, &work->shared); if (unlikely(r != 0)) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index f0db7ddcb61b..61f108ec2b5c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -137,23 +137,23 @@ int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, } static int -__reservation_object_make_exclusive(struct reservation_object *obj) +__dma_resv_make_exclusive(struct dma_resv *obj) { struct dma_fence **fences; unsigned int count; int r; - if (!reservation_object_get_list(obj)) /* no shared fences to convert */ + if (!dma_resv_get_list(obj)) /* no shared fences to convert */ return 0; - r = reservation_object_get_fences_rcu(obj, NULL, &count, &fences); + r = dma_resv_get_fences_rcu(obj, NULL, &count, &fences); if (r) return r; if (count == 0) { /* Now that was unexpected. */ } else if (count == 1) { - reservation_object_add_excl_fence(obj, fences[0]); + dma_resv_add_excl_fence(obj, fences[0]); dma_fence_put(fences[0]); kfree(fences); } else { @@ -165,7 +165,7 @@ __reservation_object_make_exclusive(struct reservation_object *obj) if (!array) goto err_fences_put; - reservation_object_add_excl_fence(obj, &array->base); + dma_resv_add_excl_fence(obj, &array->base); dma_fence_put(&array->base); } @@ -216,7 +216,7 @@ static int amdgpu_dma_buf_map_attach(struct dma_buf *dma_buf, * fences on the reservation object into a single exclusive * fence. */ - r = __reservation_object_make_exclusive(bo->tbo.base.resv); + r = __dma_resv_make_exclusive(bo->tbo.base.resv); if (r) goto error_unreserve; } @@ -367,7 +367,7 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg) { - struct reservation_object *resv = attach->dmabuf->resv; + struct dma_resv *resv = attach->dmabuf->resv; struct amdgpu_device *adev = dev->dev_private; struct amdgpu_bo *bo; struct amdgpu_bo_param bp; @@ -380,7 +380,7 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, bp.flags = 0; bp.type = ttm_bo_type_sg; bp.resv = resv; - reservation_object_lock(resv, NULL); + dma_resv_lock(resv, NULL); ret = amdgpu_bo_create(adev, &bp, &bo); if (ret) goto error; @@ -392,11 +392,11 @@ amdgpu_gem_prime_import_sg_table(struct drm_device *dev, if (attach->dmabuf->ops != &amdgpu_dmabuf_ops) bo->prime_shared_count = 1; - reservation_object_unlock(resv); + dma_resv_unlock(resv); return &bo->tbo.base; error: - reservation_object_unlock(resv); + dma_resv_unlock(resv); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index d532e3d647ca..b174bd5eb38e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -50,7 +50,7 @@ void amdgpu_gem_object_free(struct drm_gem_object *gobj) int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, int alignment, u32 initial_domain, u64 flags, enum ttm_bo_type type, - struct reservation_object *resv, + struct dma_resv *resv, struct drm_gem_object **obj) { struct amdgpu_bo *bo; @@ -215,7 +215,7 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, union drm_amdgpu_gem_create *args = data; uint64_t flags = args->in.domain_flags; uint64_t size = args->in.bo_size; - struct reservation_object *resv = NULL; + struct dma_resv *resv = NULL; struct drm_gem_object *gobj; uint32_t handle; int r; @@ -433,7 +433,7 @@ int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data, return -ENOENT; } robj = gem_to_amdgpu_bo(gobj); - ret = reservation_object_wait_timeout_rcu(robj->tbo.base.resv, true, true, + ret = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true, timeout); /* ret == 0 means not signaled, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h index 2f17150e26e1..0b66d2e6b5d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.h @@ -47,7 +47,7 @@ void amdgpu_gem_force_release(struct amdgpu_device *adev); int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, int alignment, u32 initial_domain, u64 flags, enum ttm_bo_type type, - struct reservation_object *resv, + struct dma_resv *resv, struct drm_gem_object **obj); int amdgpu_mode_dumb_create(struct drm_file *file_priv, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 529065b83885..53734da1c2df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -104,7 +104,7 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence, * * Free the pasid only after all the fences in resv are signaled. */ -void amdgpu_pasid_free_delayed(struct reservation_object *resv, +void amdgpu_pasid_free_delayed(struct dma_resv *resv, unsigned int pasid) { struct dma_fence *fence, **fences; @@ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct reservation_object *resv, unsigned count; int r; - r = reservation_object_get_fences_rcu(resv, NULL, &count, &fences); + r = dma_resv_get_fences_rcu(resv, NULL, &count, &fences); if (r) goto fallback; @@ -156,7 +156,7 @@ fallback: /* Not enough memory for the delayed delete, as last resort * block for all the fences to complete. */ - reservation_object_wait_timeout_rcu(resv, true, false, + dma_resv_wait_timeout_rcu(resv, true, false, MAX_SCHEDULE_TIMEOUT); amdgpu_pasid_free(pasid); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index 7625419f0fc2..8e58325bbca2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -72,7 +72,7 @@ struct amdgpu_vmid_mgr { int amdgpu_pasid_alloc(unsigned int bits); void amdgpu_pasid_free(unsigned int pasid); -void amdgpu_pasid_free_delayed(struct reservation_object *resv, +void amdgpu_pasid_free_delayed(struct dma_resv *resv, unsigned int pasid); bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index 50022acc8a81..f1f8cdd695d3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -179,7 +179,7 @@ static void amdgpu_mn_invalidate_node(struct amdgpu_mn_node *node, if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start, end)) continue; - r = reservation_object_wait_timeout_rcu(bo->tbo.base.resv, + r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false, MAX_SCHEDULE_TIMEOUT); if (r <= 0) DRM_ERROR("(%ld) failed to wait for user bo\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 2d07f16f1789..6ebe61e14f29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -550,7 +550,7 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, fail_unreserve: if (!bp->resv) - reservation_object_unlock(bo->tbo.base.resv); + dma_resv_unlock(bo->tbo.base.resv); amdgpu_bo_unref(&bo); return r; } @@ -612,13 +612,13 @@ int amdgpu_bo_create(struct amdgpu_device *adev, if ((flags & AMDGPU_GEM_CREATE_SHADOW) && !(adev->flags & AMD_IS_APU)) { if (!bp->resv) - WARN_ON(reservation_object_lock((*bo_ptr)->tbo.base.resv, + WARN_ON(dma_resv_lock((*bo_ptr)->tbo.base.resv, NULL)); r = amdgpu_bo_create_shadow(adev, bp->size, *bo_ptr); if (!bp->resv) - reservation_object_unlock((*bo_ptr)->tbo.base.resv); + dma_resv_unlock((*bo_ptr)->tbo.base.resv); if (r) amdgpu_bo_unref(bo_ptr); @@ -715,7 +715,7 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) return 0; } - r = reservation_object_wait_timeout_rcu(bo->tbo.base.resv, false, false, + r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, false, false, MAX_SCHEDULE_TIMEOUT); if (r < 0) return r; @@ -1093,7 +1093,7 @@ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) */ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) { - reservation_object_assert_held(bo->tbo.base.resv); + dma_resv_assert_held(bo->tbo.base.resv); if (tiling_flags) *tiling_flags = bo->tiling_flags; @@ -1242,7 +1242,7 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) return; - reservation_object_lock(bo->base.resv, NULL); + dma_resv_lock(bo->base.resv, NULL); r = amdgpu_fill_buffer(abo, AMDGPU_POISON, bo->base.resv, &fence); if (!WARN_ON(r)) { @@ -1250,7 +1250,7 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) dma_fence_put(fence); } - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } /** @@ -1325,12 +1325,12 @@ int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, bool shared) { - struct reservation_object *resv = bo->tbo.base.resv; + struct dma_resv *resv = bo->tbo.base.resv; if (shared) - reservation_object_add_shared_fence(resv, fence); + dma_resv_add_shared_fence(resv, fence); else - reservation_object_add_excl_fence(resv, fence); + dma_resv_add_excl_fence(resv, fence); } /** @@ -1370,7 +1370,7 @@ int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr) u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) { WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM); - WARN_ON_ONCE(!reservation_object_is_locked(bo->tbo.base.resv) && + WARN_ON_ONCE(!dma_resv_is_locked(bo->tbo.base.resv) && !bo->pin_count && bo->tbo.type != ttm_bo_type_kernel); WARN_ON_ONCE(bo->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET); WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_VRAM && diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 05dde0dd04ff..658f4c9779b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -41,7 +41,7 @@ struct amdgpu_bo_param { u32 preferred_domain; u64 flags; enum ttm_bo_type type; - struct reservation_object *resv; + struct dma_resv *resv; }; /* bo virtual addresses in a vm */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 9828f3c7c655..95e5e93edd18 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -190,10 +190,10 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, */ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync, - struct reservation_object *resv, + struct dma_resv *resv, void *owner, bool explicit_sync) { - struct reservation_object_list *flist; + struct dma_resv_list *flist; struct dma_fence *f; void *fence_owner; unsigned i; @@ -203,16 +203,16 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, return -EINVAL; /* always sync to the exclusive fence */ - f = reservation_object_get_excl(resv); + f = dma_resv_get_excl(resv); r = amdgpu_sync_fence(adev, sync, f, false); - flist = reservation_object_get_list(resv); + flist = dma_resv_get_list(resv); if (!flist || r) return r; for (i = 0; i < flist->shared_count; ++i) { f = rcu_dereference_protected(flist->shared[i], - reservation_object_held(resv)); + dma_resv_held(resv)); /* We only want to trigger KFD eviction fences on * evict or move jobs. Skip KFD fences otherwise. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h index 10cf23a57f17..b5f1778a2319 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.h @@ -27,7 +27,7 @@ #include <linux/hashtable.h> struct dma_fence; -struct reservation_object; +struct dma_resv; struct amdgpu_device; struct amdgpu_ring; @@ -44,7 +44,7 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct dma_fence *f, bool explicit); int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync, - struct reservation_object *resv, + struct dma_resv *resv, void *owner, bool explicit_sync); struct dma_fence *amdgpu_sync_peek_fence(struct amdgpu_sync *sync, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8f8b7a350b8b..3e8f9072561e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -303,7 +303,7 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, struct amdgpu_copy_mem *src, struct amdgpu_copy_mem *dst, uint64_t size, - struct reservation_object *resv, + struct dma_resv *resv, struct dma_fence **f) { struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; @@ -1486,7 +1486,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, { unsigned long num_pages = bo->mem.num_pages; struct drm_mm_node *node = bo->mem.mm_node; - struct reservation_object_list *flist; + struct dma_resv_list *flist; struct dma_fence *f; int i; @@ -1494,18 +1494,18 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, * cleanly handle page faults. */ if (bo->type == ttm_bo_type_kernel && - !reservation_object_test_signaled_rcu(bo->base.resv, true)) + !dma_resv_test_signaled_rcu(bo->base.resv, true)) return false; /* If bo is a KFD BO, check if the bo belongs to the current process. * If true, then return false as any KFD process needs all its BOs to * be resident to run successfully */ - flist = reservation_object_get_list(bo->base.resv); + flist = dma_resv_get_list(bo->base.resv); if (flist) { for (i = 0; i < flist->shared_count; ++i) { f = rcu_dereference_protected(flist->shared[i], - reservation_object_held(bo->base.resv)); + dma_resv_held(bo->base.resv)); if (amdkfd_fence_check_mm(f, current->mm)) return false; } @@ -2009,7 +2009,7 @@ error_free: int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count, - struct reservation_object *resv, + struct dma_resv *resv, struct dma_fence **fence, bool direct_submit, bool vm_needs_flush) { @@ -2083,7 +2083,7 @@ error_free: int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t src_data, - struct reservation_object *resv, + struct dma_resv *resv, struct dma_fence **fence) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index bccb8c49e597..0dddedc06ae3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -85,18 +85,18 @@ void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count, - struct reservation_object *resv, + struct dma_resv *resv, struct dma_fence **fence, bool direct_submit, bool vm_needs_flush); int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, struct amdgpu_copy_mem *src, struct amdgpu_copy_mem *dst, uint64_t size, - struct reservation_object *resv, + struct dma_resv *resv, struct dma_fence **f); int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t src_data, - struct reservation_object *resv, + struct dma_resv *resv, struct dma_fence **fence); int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index f858607b17a5..b2c364b8695f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -1073,7 +1073,7 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, ib->length_dw = 16; if (direct) { - r = reservation_object_wait_timeout_rcu(bo->tbo.base.resv, + r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false, msecs_to_jiffies(10)); if (r == 0) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index c8244ce184e8..b7665b31a2ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1702,7 +1702,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm); pages_addr = ttm->dma_address; } - exclusive = reservation_object_get_excl(bo->tbo.base.resv); + exclusive = dma_resv_get_excl(bo->tbo.base.resv); } if (bo) { @@ -1879,18 +1879,18 @@ static void amdgpu_vm_free_mapping(struct amdgpu_device *adev, */ static void amdgpu_vm_prt_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) { - struct reservation_object *resv = vm->root.base.bo->tbo.base.resv; + struct dma_resv *resv = vm->root.base.bo->tbo.base.resv; struct dma_fence *excl, **shared; unsigned i, shared_count; int r; - r = reservation_object_get_fences_rcu(resv, &excl, + r = dma_resv_get_fences_rcu(resv, &excl, &shared_count, &shared); if (r) { /* Not enough memory to grab the fence list, as last resort * block for all the fences to complete. */ - reservation_object_wait_timeout_rcu(resv, true, false, + dma_resv_wait_timeout_rcu(resv, true, false, MAX_SCHEDULE_TIMEOUT); return; } @@ -1978,7 +1978,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, struct amdgpu_vm *vm) { struct amdgpu_bo_va *bo_va, *tmp; - struct reservation_object *resv; + struct dma_resv *resv; bool clear; int r; @@ -1997,7 +1997,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, spin_unlock(&vm->invalidated_lock); /* Try to reserve the BO to avoid clearing its ptes */ - if (!amdgpu_vm_debug && reservation_object_trylock(resv)) + if (!amdgpu_vm_debug && dma_resv_trylock(resv)) clear = false; /* Somebody else is using the BO right now */ else @@ -2008,7 +2008,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, return r; if (!clear) - reservation_object_unlock(resv); + dma_resv_unlock(resv); spin_lock(&vm->invalidated_lock); } spin_unlock(&vm->invalidated_lock); @@ -2416,7 +2416,7 @@ void amdgpu_vm_bo_trace_cs(struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket) struct amdgpu_bo *bo; bo = mapping->bo_va->base.bo; - if (reservation_object_locking_ctx(bo->tbo.base.resv) != + if (dma_resv_locking_ctx(bo->tbo.base.resv) != ticket) continue; } @@ -2649,7 +2649,7 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size, */ long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout) { - return reservation_object_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv, + return dma_resv_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv, true, true, timeout); } @@ -2724,7 +2724,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm, if (r) goto error_free_root; - r = reservation_object_reserve_shared(root->tbo.base.resv, 1); + r = dma_resv_reserve_shared(root->tbo.base.resv, 1); if (r) goto error_unreserve; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 722c70d40d3b..67f8aee4cd1b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5695,7 +5695,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, * deadlock during GPU reset when this fence will not signal * but we hold reservation lock for the BO. */ - r = reservation_object_wait_timeout_rcu(abo->tbo.base.resv, true, + r = dma_resv_wait_timeout_rcu(abo->tbo.base.resv, true, false, msecs_to_jiffies(5000)); if (unlikely(r <= 0)) diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index fa9a4593bb37..624d257da20f 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -27,7 +27,7 @@ static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st) return; } - pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000; + pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000ULL; aclk = komeda_crtc_get_aclk(kcrtc_st); kcrtc_st->clock_ratio = div64_u64(aclk << 32, pxlclk); diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c index a3efa28436ea..af67fefed38d 100644 --- a/drivers/gpu/drm/arm/hdlcd_crtc.c +++ b/drivers/gpu/drm/arm/hdlcd_crtc.c @@ -9,7 +9,12 @@ * Implementation of a CRTC class for the HDLCD driver. */ -#include <drm/drmP.h> +#include <linux/clk.h> +#include <linux/of_graph.h> +#include <linux/platform_data/simplefb.h> + +#include <video/videomode.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> @@ -19,10 +24,7 @@ #include <drm/drm_of.h> #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> -#include <linux/clk.h> -#include <linux/of_graph.h> -#include <linux/platform_data/simplefb.h> -#include <video/videomode.h> +#include <drm/drm_vblank.h> #include "hdlcd_drv.h" #include "hdlcd_regs.h" diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 27c46a2838c5..2e053815b54a 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -14,21 +14,26 @@ #include <linux/clk.h> #include <linux/component.h> #include <linux/console.h> +#include <linux/dma-mapping.h> #include <linux/list.h> #include <linux/of_graph.h> #include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_irq.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "hdlcd_drv.h" #include "hdlcd_regs.h" diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index db4451260fff..587d94798f5c 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -6,14 +6,17 @@ * ARM Mali DP500/DP550/DP650 driver (crtc operations) */ -#include <drm/drmP.h> +#include <linux/clk.h> +#include <linux/pm_runtime.h> + +#include <video/videomode.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <linux/clk.h> -#include <linux/pm_runtime.h> -#include <video/videomode.h> +#include <drm/drm_vblank.h> #include "malidp_drv.h" #include "malidp_hw.h" diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index c27ff456eddc..333b88a5efb0 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -15,17 +15,19 @@ #include <linux/pm_runtime.h> #include <linux/debugfs.h> -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_fb_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_of.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "malidp_drv.h" #include "malidp_mw.h" diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h index 0a639af8337e..cdfddfabf2d1 100644 --- a/drivers/gpu/drm/arm/malidp_drv.h +++ b/drivers/gpu/drm/arm/malidp_drv.h @@ -9,12 +9,13 @@ #ifndef __MALIDP_DRV_H__ #define __MALIDP_DRV_H__ -#include <drm/drm_writeback.h> -#include <drm/drm_encoder.h> #include <linux/mutex.h> #include <linux/wait.h> #include <linux/spinlock.h> -#include <drm/drmP.h> + +#include <drm/drm_writeback.h> +#include <drm/drm_encoder.h> + #include "malidp_hw.h" #define MALIDP_CONFIG_VALID_INIT 0 diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 380be66d4c6e..bd8265f02e0b 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -9,12 +9,17 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/types.h> #include <linux/io.h> -#include <drm/drmP.h> + #include <video/videomode.h> #include <video/display_timing.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_vblank.h> +#include <drm/drm_print.h> + #include "malidp_drv.h" #include "malidp_hw.h" #include "malidp_mw.h" diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c index 2e812525025d..22c0847986df 100644 --- a/drivers/gpu/drm/arm/malidp_mw.c +++ b/drivers/gpu/drm/arm/malidp_mw.c @@ -5,13 +5,14 @@ * * ARM Mali DP Writeback connector implementation */ + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> -#include <drm/drm_probe_helper.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_cma_helper.h> -#include <drm/drmP.h> +#include <drm/drm_probe_helper.h> #include <drm/drm_writeback.h> #include "malidp_drv.h" diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 488375bd133d..3c70a53813bf 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -7,11 +7,13 @@ */ #include <linux/iommu.h> +#include <linux/platform_device.h> -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_plane_helper.h> diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index d44fca4e1655..c2b92acd1e9a 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -3,15 +3,19 @@ * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. */ + #include <linux/clk.h> #include <linux/component.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <drm/drmP.h> + #include <drm/drm_atomic.h> -#include <drm/drm_probe_helper.h> -#include <drm/drm_plane_helper.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c index dc3716dbb2c0..c6fc2f1d58e9 100644 --- a/drivers/gpu/drm/armada/armada_debugfs.c +++ b/drivers/gpu/drm/armada/armada_debugfs.c @@ -3,11 +3,15 @@ * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. */ + #include <linux/ctype.h> -#include <linux/debugfs.h> #include <linux/module.h> #include <linux/seq_file.h> -#include <drm/drmP.h> +#include <linux/uaccess.h> + +#include <drm/drm_debugfs.h> +#include <drm/drm_file.h> + #include "armada_crtc.h" #include "armada_drm.h" diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index c7794c8bdd90..a11bdaccbb33 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -8,11 +8,14 @@ #include <linux/kfifo.h> #include <linux/io.h> #include <linux/workqueue.h> -#include <drm/drmP.h> + +#include <drm/drm_device.h> +#include <drm/drm_mm.h> struct armada_crtc; struct armada_gem_object; struct clk; +struct drm_display_mode; struct drm_fb_helper; static inline void diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 055c92bc88bf..197dca3fc84c 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -2,14 +2,22 @@ /* * Copyright (C) 2012 Russell King */ + #include <linux/clk.h> #include <linux/component.h> #include <linux/module.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> + #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_prime.h> #include <drm/drm_probe_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_of.h> +#include <drm/drm_vblank.h> + #include "armada_crtc.h" #include "armada_drm.h" #include "armada_gem.h" diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index de030cb0aa90..426ca383d696 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -2,9 +2,12 @@ /* * Copyright (C) 2012 Russell King */ + #include <drm/drm_modeset_helper.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> + #include "armada_drm.h" #include "armada_fb.h" #include "armada_gem.h" diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 096aff530b01..090cc0d699ae 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -3,11 +3,14 @@ * Copyright (C) 2012 Russell King * Written from the i915 driver. */ + #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_fourcc.h> + #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 60c509784fa3..93cf8b8bfcff 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -2,12 +2,17 @@ /* * Copyright (C) 2012 Russell King */ + #include <linux/dma-buf.h> #include <linux/dma-mapping.h> +#include <linux/mman.h> #include <linux/shmem_fs.h> + +#include <drm/armada_drm.h> +#include <drm/drm_prime.h> + #include "armada_drm.h" #include "armada_gem.h" -#include <drm/armada_drm.h> #include "armada_ioctlP.h" static vm_fault_t armada_gem_vm_fault(struct vm_fault *vmf) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index e8060216b389..07f0da4d9ba1 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -3,12 +3,14 @@ * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. */ -#include <drm/drmP.h> + +#include <drm/armada_drm.h> #include <drm/drm_atomic.h> -#include <drm/drm_atomic_uapi.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic_uapi.h> +#include <drm/drm_fourcc.h> #include <drm/drm_plane_helper.h> -#include <drm/armada_drm.h> + #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" diff --git a/drivers/gpu/drm/armada/armada_plane.c b/drivers/gpu/drm/armada/armada_plane.c index f08b4f37816d..e7cc2b343bcb 100644 --- a/drivers/gpu/drm/armada/armada_plane.c +++ b/drivers/gpu/drm/armada/armada_plane.c @@ -3,10 +3,12 @@ * Copyright (C) 2012 Russell King * Rewritten from the dovefb driver, and Armada510 manuals. */ -#include <drm/drmP.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_plane_helper.h> + #include "armada_crtc.h" #include "armada_drm.h" #include "armada_fb.h" diff --git a/drivers/gpu/drm/armada/armada_trace.h b/drivers/gpu/drm/armada/armada_trace.h index f03a56bda596..528f20fe3147 100644 --- a/drivers/gpu/drm/armada/armada_trace.h +++ b/drivers/gpu/drm/armada/armada_trace.h @@ -3,7 +3,10 @@ #define ARMADA_TRACE_H #include <linux/tracepoint.h> -#include <drm/drmP.h> + +struct drm_crtc; +struct drm_framebuffer; +struct drm_plane; #undef TRACE_SYSTEM #define TRACE_SYSTEM armada diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c index 15db9e426ec4..2184b8be6fd4 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c @@ -215,7 +215,7 @@ static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1); } -static struct drm_simple_display_pipe_funcs aspeed_gfx_funcs = { +static const struct drm_simple_display_pipe_funcs aspeed_gfx_funcs = { .enable = aspeed_gfx_pipe_enable, .disable = aspeed_gfx_pipe_disable, .update = aspeed_gfx_pipe_update, diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index f2f7f69d6cc3..22885dceaa17 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1780,8 +1780,7 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) if (dp->plat_data->panel) { if (drm_panel_unprepare(dp->plat_data->panel)) DRM_ERROR("failed to turnoff the panel\n"); - if (drm_panel_detach(dp->plat_data->panel)) - DRM_ERROR("failed to detach the panel\n"); + drm_panel_detach(dp->plat_data->panel); } drm_dp_aux_unregister(&dp->aux); diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 8ef6539ae78a..7aa789c35882 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -42,7 +42,7 @@ static int dumb_vga_get_modes(struct drm_connector *connector) struct edid *edid; int ret; - if (IS_ERR(vga->ddc)) + if (!vga->ddc) goto fallback; edid = drm_get_edid(connector, vga->ddc); @@ -84,7 +84,7 @@ dumb_vga_connector_detect(struct drm_connector *connector, bool force) * wire the DDC pins, or the I2C bus might not be working at * all. */ - if (!IS_ERR(vga->ddc) && drm_probe_ddc(vga->ddc)) + if (vga->ddc && drm_probe_ddc(vga->ddc)) return connector_status_connected; return connector_status_unknown; @@ -197,6 +197,7 @@ static int dumb_vga_probe(struct platform_device *pdev) if (PTR_ERR(vga->ddc) == -ENODEV) { dev_dbg(&pdev->dev, "No i2c bus specified. Disabling EDID readout\n"); + vga->ddc = NULL; } else { dev_err(&pdev->dev, "Couldn't retrieve i2c bus\n"); return PTR_ERR(vga->ddc); @@ -218,7 +219,7 @@ static int dumb_vga_remove(struct platform_device *pdev) drm_bridge_remove(&vga->bridge); - if (!IS_ERR(vga->ddc)) + if (vga->ddc) i2c_put_adapter(vga->ddc); return 0; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index a494186ae6ce..2b7539701b42 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c @@ -63,10 +63,6 @@ enum { HDMI_REVISION_ID = 0x0001, HDMI_IH_AHBDMAAUD_STAT0 = 0x0109, HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189, - HDMI_FC_AUDICONF2 = 0x1027, - HDMI_FC_AUDSCONF = 0x1063, - HDMI_FC_AUDSCONF_LAYOUT1 = 1 << 0, - HDMI_FC_AUDSCONF_LAYOUT0 = 0 << 0, HDMI_AHB_DMA_CONF0 = 0x3600, HDMI_AHB_DMA_START = 0x3601, HDMI_AHB_DMA_STOP = 0x3602, @@ -403,7 +399,7 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dw_hdmi *dw = substream->private_data; - u8 threshold, conf0, conf1, layout, ca; + u8 threshold, conf0, conf1, ca; /* Setup as per 3.0.5 FSL 4.1.0 BSP */ switch (dw->revision) { @@ -434,20 +430,12 @@ static int dw_hdmi_prepare(struct snd_pcm_substream *substream) conf1 = default_hdmi_channel_config[runtime->channels - 2].conf1; ca = default_hdmi_channel_config[runtime->channels - 2].ca; - /* - * For >2 channel PCM audio, we need to select layout 1 - * and set an appropriate channel map. - */ - if (runtime->channels > 2) - layout = HDMI_FC_AUDSCONF_LAYOUT1; - else - layout = HDMI_FC_AUDSCONF_LAYOUT0; - writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD); writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0); writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1); - writeb_relaxed(layout, dw->data.base + HDMI_FC_AUDSCONF); - writeb_relaxed(ca, dw->data.base + HDMI_FC_AUDICONF2); + + dw_hdmi_set_channel_count(dw->data.hdmi, runtime->channels); + dw_hdmi_set_channel_allocation(dw->data.hdmi, ca); switch (runtime->format) { case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h index 63b5756f463b..cb07dc0da5a7 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h @@ -14,6 +14,7 @@ struct dw_hdmi_audio_data { struct dw_hdmi_i2s_audio_data { struct dw_hdmi *hdmi; + u8 *eld; void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read)(struct dw_hdmi *hdmi, int offset); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index 5cbb71a866d5..1d15cf9b6821 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <drm/bridge/dw_hdmi.h> +#include <drm/drm_crtc.h> #include <sound/hdmi-codec.h> @@ -44,14 +45,30 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, u8 inputclkfs = 0; /* it cares I2S only */ - if ((fmt->fmt != HDMI_I2S) || - (fmt->bit_clk_master | fmt->frame_clk_master)) { - dev_err(dev, "unsupported format/settings\n"); + if (fmt->bit_clk_master | fmt->frame_clk_master) { + dev_err(dev, "unsupported clock settings\n"); return -EINVAL; } + /* Reset the FIFOs before applying new params */ + hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); + hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); + inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; - conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; + conf0 = (HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_EN0); + + /* Enable the required i2s lanes */ + switch (hparms->channels) { + case 7 ... 8: + conf0 |= HDMI_AUD_CONF0_I2S_EN3; + /* Fall-thru */ + case 5 ... 6: + conf0 |= HDMI_AUD_CONF0_I2S_EN2; + /* Fall-thru */ + case 3 ... 4: + conf0 |= HDMI_AUD_CONF0_I2S_EN1; + /* Fall-thru */ + } switch (hparms->sample_width) { case 16: @@ -63,7 +80,30 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, break; } + switch (fmt->fmt) { + case HDMI_I2S: + conf1 |= HDMI_AUD_CONF1_MODE_I2S; + break; + case HDMI_RIGHT_J: + conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J; + break; + case HDMI_LEFT_J: + conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J; + break; + case HDMI_DSP_A: + conf1 |= HDMI_AUD_CONF1_MODE_BURST_1; + break; + case HDMI_DSP_B: + conf1 |= HDMI_AUD_CONF1_MODE_BURST_2; + break; + default: + dev_err(dev, "unsupported format\n"); + return -EINVAL; + } + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + dw_hdmi_set_channel_count(hdmi, hparms->channels); + dw_hdmi_set_channel_allocation(hdmi, hparms->cea.channel_allocation); hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); hdmi_write(audio, conf0, HDMI_AUD_CONF0); @@ -80,8 +120,15 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) struct dw_hdmi *hdmi = audio->hdmi; dw_hdmi_audio_disable(hdmi); +} - hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); +static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf, + size_t len) +{ + struct dw_hdmi_i2s_audio_data *audio = data; + + memcpy(buf, audio->eld, min_t(size_t, MAX_ELD_BYTES, len)); + return 0; } static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, @@ -107,6 +154,7 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, static struct hdmi_codec_ops dw_hdmi_i2s_ops = { .hw_params = dw_hdmi_i2s_hw_params, .audio_shutdown = dw_hdmi_i2s_audio_shutdown, + .get_eld = dw_hdmi_i2s_get_eld, .get_dai_id = dw_hdmi_i2s_get_dai_id, }; @@ -119,7 +167,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) pdata.ops = &dw_hdmi_i2s_ops; pdata.i2s = 1; - pdata.max_i2s_channels = 6; + pdata.max_i2s_channels = 8; pdata.data = audio; memset(&pdevinfo, 0, sizeof(pdevinfo)); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 83b94b66e464..4044071090c4 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -645,6 +645,42 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) } EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate); +void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt) +{ + u8 layout; + + mutex_lock(&hdmi->audio_mutex); + + /* + * For >2 channel PCM audio, we need to select layout 1 + * and set an appropriate channel map. + */ + if (cnt > 2) + layout = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1; + else + layout = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0; + + hdmi_modb(hdmi, layout, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, + HDMI_FC_AUDSCONF); + + /* Set the audio infoframes channel count */ + hdmi_modb(hdmi, (cnt - 1) << HDMI_FC_AUDICONF0_CC_OFFSET, + HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0); + + mutex_unlock(&hdmi->audio_mutex); +} +EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_count); + +void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca) +{ + mutex_lock(&hdmi->audio_mutex); + + hdmi_writeb(hdmi, ca, HDMI_FC_AUDICONF2); + + mutex_unlock(&hdmi->audio_mutex); +} +EXPORT_SYMBOL_GPL(dw_hdmi_set_channel_allocation); + static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) { if (enable) @@ -2763,6 +2799,7 @@ __dw_hdmi_probe(struct platform_device *pdev, struct dw_hdmi_i2s_audio_data audio; audio.hdmi = hdmi; + audio.eld = hdmi->connector.eld; audio.write = hdmi_writeb; audio.read = hdmi_readb; hdmi->enable_audio = dw_hdmi_i2s_audio_enable; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h index 4e3ec09d3ca4..6988f12d89d9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h @@ -865,12 +865,18 @@ enum { /* AUD_CONF0 field values */ HDMI_AUD_CONF0_SW_RESET = 0x80, - HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F, + HDMI_AUD_CONF0_I2S_SELECT = 0x20, + HDMI_AUD_CONF0_I2S_EN3 = 0x08, + HDMI_AUD_CONF0_I2S_EN2 = 0x04, + HDMI_AUD_CONF0_I2S_EN1 = 0x02, + HDMI_AUD_CONF0_I2S_EN0 = 0x01, /* AUD_CONF1 field values */ HDMI_AUD_CONF1_MODE_I2S = 0x00, - HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02, - HDMI_AUD_CONF1_MODE_LEFT_J = 0x04, + HDMI_AUD_CONF1_MODE_RIGHT_J = 0x20, + HDMI_AUD_CONF1_MODE_LEFT_J = 0x40, + HDMI_AUD_CONF1_MODE_BURST_1 = 0x60, + HDMI_AUD_CONF1_MODE_BURST_2 = 0x80, HDMI_AUD_CONF1_WIDTH_16 = 0x10, HDMI_AUD_CONF1_WIDTH_24 = 0x18, @@ -938,6 +944,7 @@ enum { HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1, /* MC_SWRSTZ field values */ + HDMI_MC_SWRSTZ_I2SSWRST_REQ = 0x08, HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02, /* MC_FLOWCTRL field values */ diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 42f03a985ac0..cebc8e620820 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1312,7 +1312,7 @@ static int tc_connector_get_modes(struct drm_connector *connector) { struct tc_data *tc = connector_to_tc(connector); struct edid *edid; - unsigned int count; + int count; int ret; ret = tc_get_display_props(tc); @@ -1321,11 +1321,9 @@ static int tc_connector_get_modes(struct drm_connector *connector) return 0; } - if (tc->panel && tc->panel->funcs && tc->panel->funcs->get_modes) { - count = tc->panel->funcs->get_modes(tc->panel); - if (count > 0) - return count; - } + count = drm_panel_get_modes(tc->panel); + if (count > 0) + return count; edid = drm_get_edid(connector, &tc->aux.ddc); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 19ae119f1a5d..5a5b42db6f2a 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1037,7 +1037,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state, * 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. + * a &struct dma_buf this is tracked in &struct dma_resv. * Implicit syncing is how Linux traditionally worked (e.g. DRI2/3 on X.org), * whereas explicit fencing is what Android wants. * diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 354798bad576..4c766624b20d 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -986,12 +986,14 @@ static const struct drm_prop_enum_list hdmi_colorspaces[] = { * - Kernel sends uevent with the connector id and property id through * @drm_hdcp_update_content_protection, upon below kernel triggered * scenarios: - * DESIRED -> ENABLED (authentication success) - * ENABLED -> DESIRED (termination of authentication) + * + * - DESIRED -> ENABLED (authentication success) + * - ENABLED -> DESIRED (termination of authentication) * - Please note no uevents for userspace triggered property state changes, * which can't fail such as - * DESIRED/ENABLED -> UNDESIRED - * UNDESIRED -> DESIRED + * + * - DESIRED/ENABLED -> UNDESIRED + * - UNDESIRED -> DESIRED * - Userspace is responsible for polling the property or listen to uevents * to determine when the value transitions from ENABLED to DESIRED. * This signifies the link is no longer protected and userspace should diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index afc38cece3f5..6854f5867d51 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -159,7 +159,7 @@ void drm_gem_private_object_init(struct drm_device *dev, kref_init(&obj->refcount); obj->handle_count = 0; obj->size = size; - reservation_object_init(&obj->_resv); + dma_resv_init(&obj->_resv); if (!obj->resv) obj->resv = &obj->_resv; @@ -633,6 +633,9 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, pagevec_init(&pvec); for (i = 0; i < npages; i++) { + if (!pages[i]) + continue; + if (dirty) set_page_dirty(pages[i]); @@ -752,7 +755,7 @@ drm_gem_object_lookup(struct drm_file *filp, u32 handle) EXPORT_SYMBOL(drm_gem_object_lookup); /** - * drm_gem_reservation_object_wait - Wait on GEM object's reservation's objects + * drm_gem_dma_resv_wait - Wait on GEM object's reservation's objects * shared and/or exclusive fences. * @filep: DRM file private date * @handle: userspace handle @@ -764,7 +767,7 @@ EXPORT_SYMBOL(drm_gem_object_lookup); * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or * greater than 0 on success. */ -long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, +long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, bool wait_all, unsigned long timeout) { long ret; @@ -776,7 +779,7 @@ long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, return -EINVAL; } - ret = reservation_object_wait_timeout_rcu(obj->resv, wait_all, + ret = dma_resv_wait_timeout_rcu(obj->resv, wait_all, true, timeout); if (ret == 0) ret = -ETIME; @@ -787,7 +790,7 @@ long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, return ret; } -EXPORT_SYMBOL(drm_gem_reservation_object_wait); +EXPORT_SYMBOL(drm_gem_dma_resv_wait); /** * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl @@ -953,7 +956,7 @@ drm_gem_object_release(struct drm_gem_object *obj) if (obj->filp) fput(obj->filp); - reservation_object_fini(&obj->_resv); + dma_resv_fini(&obj->_resv); drm_gem_free_mmap_offset(obj); } EXPORT_SYMBOL(drm_gem_object_release); @@ -1288,7 +1291,7 @@ retry: if (contended != -1) { struct drm_gem_object *obj = objs[contended]; - ret = reservation_object_lock_slow_interruptible(obj->resv, + ret = dma_resv_lock_slow_interruptible(obj->resv, acquire_ctx); if (ret) { ww_acquire_done(acquire_ctx); @@ -1300,16 +1303,16 @@ retry: if (i == contended) continue; - ret = reservation_object_lock_interruptible(objs[i]->resv, + ret = dma_resv_lock_interruptible(objs[i]->resv, acquire_ctx); if (ret) { int j; for (j = 0; j < i; j++) - reservation_object_unlock(objs[j]->resv); + dma_resv_unlock(objs[j]->resv); if (contended != -1 && contended >= i) - reservation_object_unlock(objs[contended]->resv); + dma_resv_unlock(objs[contended]->resv); if (ret == -EDEADLK) { contended = i; @@ -1334,7 +1337,7 @@ drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, int i; for (i = 0; i < count; i++) - reservation_object_unlock(objs[i]->resv); + dma_resv_unlock(objs[i]->resv); ww_acquire_fini(acquire_ctx); } @@ -1410,12 +1413,12 @@ int drm_gem_fence_array_add_implicit(struct xarray *fence_array, if (!write) { struct dma_fence *fence = - reservation_object_get_excl_rcu(obj->resv); + dma_resv_get_excl_rcu(obj->resv); return drm_gem_fence_array_add(fence_array, fence); } - ret = reservation_object_get_fences_rcu(obj->resv, NULL, + ret = dma_resv_get_fences_rcu(obj->resv, NULL, &fence_count, &fences); if (ret || !fence_count) return ret; diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index f61304054786..b9bcd310ca2d 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -7,7 +7,7 @@ #include <linux/dma-buf.h> #include <linux/dma-fence.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/slab.h> #include <drm/drm_atomic.h> @@ -294,7 +294,7 @@ int drm_gem_fb_prepare_fb(struct drm_plane *plane, return 0; obj = drm_gem_fb_get_obj(state->fb, 0); - fence = reservation_object_get_excl_rcu(obj->resv); + fence = dma_resv_get_excl_rcu(obj->resv); drm_atomic_set_fence_for_plane(state, fence); return 0; diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 2f64667ac805..df8f2c8adb2b 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -75,6 +75,7 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t shmem = to_drm_gem_shmem_obj(obj); mutex_init(&shmem->pages_lock); mutex_init(&shmem->vmap_lock); + INIT_LIST_HEAD(&shmem->madv_list); /* * Our buffers are kept pinned, so allocating them @@ -118,11 +119,11 @@ void drm_gem_shmem_free_object(struct drm_gem_object *obj) if (shmem->sgt) { dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl, shmem->sgt->nents, DMA_BIDIRECTIONAL); - - drm_gem_shmem_put_pages(shmem); sg_free_table(shmem->sgt); kfree(shmem->sgt); } + if (shmem->pages) + drm_gem_shmem_put_pages(shmem); } WARN_ON(shmem->pages_use_count); @@ -362,6 +363,62 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv, } EXPORT_SYMBOL(drm_gem_shmem_create_with_handle); +/* Update madvise status, returns true if not purged, else + * false or -errno. + */ +int drm_gem_shmem_madvise(struct drm_gem_object *obj, int madv) +{ + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + + mutex_lock(&shmem->pages_lock); + + if (shmem->madv >= 0) + shmem->madv = madv; + + madv = shmem->madv; + + mutex_unlock(&shmem->pages_lock); + + return (madv >= 0); +} +EXPORT_SYMBOL(drm_gem_shmem_madvise); + +void drm_gem_shmem_purge_locked(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + + WARN_ON(!drm_gem_shmem_is_purgeable(shmem)); + + drm_gem_shmem_put_pages_locked(shmem); + + shmem->madv = -1; + + drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); + drm_gem_free_mmap_offset(obj); + + /* Our goal here is to return as much of the memory as + * is possible back to the system as we are called from OOM. + * To do this we must instruct the shmfs to drop all of its + * backing pages, *now*. + */ + shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1); + + invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, + 0, (loff_t)-1); +} +EXPORT_SYMBOL(drm_gem_shmem_purge_locked); + +void drm_gem_shmem_purge(struct drm_gem_object *obj) +{ + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + + mutex_lock(&shmem->pages_lock); + drm_gem_shmem_purge_locked(obj); + mutex_unlock(&shmem->pages_lock); +} +EXPORT_SYMBOL(drm_gem_shmem_purge); + /** * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object * @file: DRM file structure to create the dumb buffer for diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index dbd5b873e8f2..6b0bf42039cf 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -123,18 +123,110 @@ EXPORT_SYMBOL(drm_panel_attach); * * This function should not be called by the panel device itself. It * is only for the drm device that called drm_panel_attach(). - * - * Return: 0 on success or a negative error code on failure. */ -int drm_panel_detach(struct drm_panel *panel) +void drm_panel_detach(struct drm_panel *panel) { panel->connector = NULL; panel->drm = NULL; - - return 0; } EXPORT_SYMBOL(drm_panel_detach); +/** + * drm_panel_prepare - power on a panel + * @panel: DRM panel + * + * Calling this function will enable power and deassert any reset signals to + * the panel. After this has completed it is possible to communicate with any + * integrated circuitry via a command bus. + * + * Return: 0 on success or a negative error code on failure. + */ +int drm_panel_prepare(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->prepare) + return panel->funcs->prepare(panel); + + return panel ? -ENOSYS : -EINVAL; +} +EXPORT_SYMBOL(drm_panel_prepare); + +/** + * drm_panel_unprepare - power off a panel + * @panel: DRM panel + * + * Calling this function will completely power off a panel (assert the panel's + * reset, turn off power supplies, ...). After this function has completed, it + * is usually no longer possible to communicate with the panel until another + * call to drm_panel_prepare(). + * + * Return: 0 on success or a negative error code on failure. + */ +int drm_panel_unprepare(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->unprepare) + return panel->funcs->unprepare(panel); + + return panel ? -ENOSYS : -EINVAL; +} +EXPORT_SYMBOL(drm_panel_unprepare); + +/** + * drm_panel_enable - enable a panel + * @panel: DRM panel + * + * Calling this function will cause the panel display drivers to be turned on + * and the backlight to be enabled. Content will be visible on screen after + * this call completes. + * + * Return: 0 on success or a negative error code on failure. + */ +int drm_panel_enable(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->enable) + return panel->funcs->enable(panel); + + return panel ? -ENOSYS : -EINVAL; +} +EXPORT_SYMBOL(drm_panel_enable); + +/** + * drm_panel_disable - disable a panel + * @panel: DRM panel + * + * This will typically turn off the panel's backlight or disable the display + * drivers. For smart panels it should still be possible to communicate with + * the integrated circuitry via any command bus after this call. + * + * Return: 0 on success or a negative error code on failure. + */ +int drm_panel_disable(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->disable) + return panel->funcs->disable(panel); + + return panel ? -ENOSYS : -EINVAL; +} +EXPORT_SYMBOL(drm_panel_disable); + +/** + * drm_panel_get_modes - probe the available display modes of a panel + * @panel: DRM panel + * + * The modes probed from the panel are automatically added to the connector + * that the panel is attached to. + * + * Return: The number of modes available from the panel on success or a + * negative error code on failure. + */ +int drm_panel_get_modes(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->get_modes) + return panel->funcs->get_modes(panel); + + return panel ? -ENOSYS : -EINVAL; +} +EXPORT_SYMBOL(drm_panel_get_modes); + #ifdef CONFIG_OF /** * of_drm_find_panel - look up a panel using a device tree node diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 1438dcb3ebb1..4b5c7b0ed714 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -29,21 +29,97 @@ /** * DOC: Overview * - * DRM synchronisation objects (syncobj, see struct &drm_syncobj) are - * persistent objects that contain an optional fence. The fence can be updated - * with a new fence, or be NULL. + * DRM synchronisation objects (syncobj, see struct &drm_syncobj) provide a + * container for a synchronization primitive which can be used by userspace + * to explicitly synchronize GPU commands, can be shared between userspace + * processes, and can be shared between different DRM drivers. + * Their primary use-case is to implement Vulkan fences and semaphores. + * The syncobj userspace API provides ioctls for several operations: * - * syncobj's can be waited upon, where it will wait for the underlying - * fence. + * - Creation and destruction of syncobjs + * - Import and export of syncobjs to/from a syncobj file descriptor + * - Import and export a syncobj's underlying fence to/from a sync file + * - Reset a syncobj (set its fence to NULL) + * - Signal a syncobj (set a trivially signaled fence) + * - Wait for a syncobj's fence to appear and be signaled * - * syncobj's can be export to fd's and back, these fd's are opaque and - * have no other use case, except passing the syncobj between processes. + * At it's core, a syncobj is simply a wrapper around a pointer to a struct + * &dma_fence which may be NULL. + * When a syncobj is first created, its pointer is either NULL or a pointer + * to an already signaled fence depending on whether the + * &DRM_SYNCOBJ_CREATE_SIGNALED flag is passed to + * &DRM_IOCTL_SYNCOBJ_CREATE. + * When GPU work which signals a syncobj is enqueued in a DRM driver, + * the syncobj fence is replaced with a fence which will be signaled by the + * completion of that work. + * When GPU work which waits on a syncobj is enqueued in a DRM driver, the + * driver retrieves syncobj's current fence at the time the work is enqueued + * waits on that fence before submitting the work to hardware. + * If the syncobj's fence is NULL, the enqueue operation is expected to fail. + * All manipulation of the syncobjs's fence happens in terms of the current + * fence at the time the ioctl is called by userspace regardless of whether + * that operation is an immediate host-side operation (signal or reset) or + * or an operation which is enqueued in some driver queue. + * &DRM_IOCTL_SYNCOBJ_RESET and &DRM_IOCTL_SYNCOBJ_SIGNAL can be used to + * manipulate a syncobj from the host by resetting its pointer to NULL or + * setting its pointer to a fence which is already signaled. * - * Their primary use-case is to implement Vulkan fences and semaphores. * - * syncobj have a kref reference count, but also have an optional file. - * The file is only created once the syncobj is exported. - * The file takes a reference on the kref. + * Host-side wait on syncobjs + * -------------------------- + * + * &DRM_IOCTL_SYNCOBJ_WAIT takes an array of syncobj handles and does a + * host-side wait on all of the syncobj fences simultaneously. + * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL is set, the wait ioctl will wait on + * all of the syncobj fences to be signaled before it returns. + * Otherwise, it returns once at least one syncobj fence has been signaled + * and the index of a signaled fence is written back to the client. + * + * Unlike the enqueued GPU work dependencies which fail if they see a NULL + * fence in a syncobj, if &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT is set, + * the host-side wait will first wait for the syncobj to receive a non-NULL + * fence and then wait on that fence. + * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT is not set and any one of the + * syncobjs in the array has a NULL fence, -EINVAL will be returned. + * Assuming the syncobj starts off with a NULL fence, this allows a client + * to do a host wait in one thread (or process) which waits on GPU work + * submitted in another thread (or process) without having to manually + * synchronize between the two. + * This requirement is inherited from the Vulkan fence API. + * + * + * Import/export of syncobjs + * ------------------------- + * + * &DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE and &DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD + * provide two mechanisms for import/export of syncobjs. + * + * The first lets the client import or export an entire syncobj to a file + * descriptor. + * These fd's are opaque and have no other use case, except passing the + * syncobj between processes. + * All exported file descriptors and any syncobj handles created as a + * result of importing those file descriptors own a reference to the + * same underlying struct &drm_syncobj and the syncobj can be used + * persistently across all the processes with which it is shared. + * The syncobj is freed only once the last reference is dropped. + * Unlike dma-buf, importing a syncobj creates a new handle (with its own + * reference) for every import instead of de-duplicating. + * The primary use-case of this persistent import/export is for shared + * Vulkan fences and semaphores. + * + * The second import/export mechanism, which is indicated by + * &DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE or + * &DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE lets the client + * import/export the syncobj's current fence from/to a &sync_file. + * When a syncobj is exported to a sync file, that sync file wraps the + * sycnobj's fence at the time of export and any later signal or reset + * operations on the syncobj will not affect the exported sync file. + * When a sync file is imported into a syncobj, the syncobj's fence is set + * to the fence wrapped by that sync file. + * Because sync files are immutable, resetting or signaling the syncobj + * will not affect any sync files whose fences have been imported into the + * syncobj. */ #include <linux/anon_inodes.h> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 17ca602db60a..7d83e04ec36e 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -397,13 +397,13 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op, } if (op & ETNA_PREP_NOSYNC) { - if (!reservation_object_test_signaled_rcu(obj->resv, + if (!dma_resv_test_signaled_rcu(obj->resv, write)) return -EBUSY; } else { unsigned long remain = etnaviv_timeout_to_jiffies(timeout); - ret = reservation_object_wait_timeout_rcu(obj->resv, + ret = dma_resv_wait_timeout_rcu(obj->resv, write, true, remain); if (ret <= 0) return ret == 0 ? -ETIMEDOUT : ret; @@ -459,8 +459,8 @@ static void etnaviv_gem_describe_fence(struct dma_fence *fence, static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct etnaviv_gem_object *etnaviv_obj = to_etnaviv_bo(obj); - struct reservation_object *robj = obj->resv; - struct reservation_object_list *fobj; + struct dma_resv *robj = obj->resv; + struct dma_resv_list *fobj; struct dma_fence *fence; unsigned long off = drm_vma_node_start(&obj->vma_node); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.h b/drivers/gpu/drm/etnaviv/etnaviv_gem.h index fcd5d71b502f..28379e4df253 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.h +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.h @@ -6,7 +6,7 @@ #ifndef __ETNAVIV_GEM_H__ #define __ETNAVIV_GEM_H__ -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "etnaviv_cmdbuf.h" #include "etnaviv_drv.h" diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 1a636469eeda..998c96b40d8a 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -4,7 +4,7 @@ */ #include <linux/dma-fence-array.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/sync_file.h> #include "etnaviv_cmdbuf.h" #include "etnaviv_drv.h" @@ -165,10 +165,10 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit) for (i = 0; i < submit->nr_bos; i++) { struct etnaviv_gem_submit_bo *bo = &submit->bos[i]; - struct reservation_object *robj = bo->obj->base.resv; + struct dma_resv *robj = bo->obj->base.resv; if (!(bo->flags & ETNA_SUBMIT_BO_WRITE)) { - ret = reservation_object_reserve_shared(robj, 1); + ret = dma_resv_reserve_shared(robj, 1); if (ret) return ret; } @@ -177,13 +177,13 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit) continue; if (bo->flags & ETNA_SUBMIT_BO_WRITE) { - ret = reservation_object_get_fences_rcu(robj, &bo->excl, + ret = dma_resv_get_fences_rcu(robj, &bo->excl, &bo->nr_shared, &bo->shared); if (ret) return ret; } else { - bo->excl = reservation_object_get_excl_rcu(robj); + bo->excl = dma_resv_get_excl_rcu(robj); } } @@ -199,10 +199,10 @@ static void submit_attach_object_fences(struct etnaviv_gem_submit *submit) struct drm_gem_object *obj = &submit->bos[i].obj->base; if (submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE) - reservation_object_add_excl_fence(obj->resv, + dma_resv_add_excl_fence(obj->resv, submit->out_fence); else - reservation_object_add_shared_fence(obj->resv, + dma_resv_add_shared_fence(obj->resv, submit->out_fence); submit_unlock_object(submit, i); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 279d83eaffc0..a92fd6c70b09 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -65,17 +65,9 @@ static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = { static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) { struct fsl_dcu_drm_connector *fsl_connector; - int (*get_modes)(struct drm_panel *panel); - int num_modes = 0; fsl_connector = to_fsl_dcu_connector(connector); - if (fsl_connector->panel && fsl_connector->panel->funcs && - fsl_connector->panel->funcs->get_modes) { - get_modes = fsl_connector->panel->funcs->get_modes; - num_modes = get_modes(fsl_connector->panel); - } - - return num_modes; + return drm_panel_get_modes(fsl_connector->panel); } static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 61e042918a7f..84c6d4c91c65 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -13,10 +13,10 @@ #include <sound/asoundef.h> #include <sound/hdmi-codec.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_edid.h> #include <drm/drm_of.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/i2c/tda998x.h> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 9e4ee29fd0fc..29a9ecf66efc 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -29,7 +29,7 @@ #include <linux/intel-iommu.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/slab.h> #include <linux/vgaarb.h> @@ -14431,7 +14431,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, if (ret < 0) return ret; - fence = reservation_object_get_excl_rcu(obj->base.resv); + fence = dma_resv_get_excl_rcu(obj->base.resv); if (fence) { add_rps_boost_after_vblank(new_state->crtc, fence); dma_fence_put(fence); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_busy.c b/drivers/gpu/drm/i915/gem/i915_gem_busy.c index 6ad93a09968c..3d4f5775a4ba 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_busy.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_busy.c @@ -82,7 +82,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_busy *args = data; struct drm_i915_gem_object *obj; - struct reservation_object_list *list; + struct dma_resv_list *list; unsigned int seq; int err; @@ -105,7 +105,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * Alternatively, we can trade that extra information on read/write * activity with * args->busy = - * !reservation_object_test_signaled_rcu(obj->resv, true); + * !dma_resv_test_signaled_rcu(obj->resv, true); * to report the overall busyness. This is what the wait-ioctl does. * */ diff --git a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c index 5295285d5843..88ee8ca7967f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_clflush.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_clflush.c @@ -147,7 +147,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, true, I915_FENCE_TIMEOUT, I915_FENCE_GFP); - reservation_object_add_excl_fence(obj->base.resv, + dma_resv_add_excl_fence(obj->base.resv, &clflush->dma); i915_sw_fence_commit(&clflush->wait); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c b/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c index 2312a0c6af89..4714047f77e1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_client_blt.c @@ -287,7 +287,7 @@ int i915_gem_schedule_fill_pages_blt(struct drm_i915_gem_object *obj, if (err < 0) { dma_fence_set_error(&work->dma, err); } else { - reservation_object_add_excl_fence(obj->base.resv, &work->dma); + dma_resv_add_excl_fence(obj->base.resv, &work->dma); err = 0; } i915_gem_object_unlock(obj); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c index 570b20ad9e58..96ce95c8ac5a 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c @@ -6,7 +6,7 @@ #include <linux/dma-buf.h> #include <linux/highmem.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "i915_drv.h" #include "i915_gem_object.h" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index cbd7c6e3a1f8..924e4a26f2b7 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -5,7 +5,7 @@ */ #include <linux/intel-iommu.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/sync_file.h> #include <linux/uaccess.h> @@ -1242,7 +1242,7 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, goto skip_request; i915_vma_lock(batch); - GEM_BUG_ON(!reservation_object_test_signaled_rcu(batch->resv, true)); + GEM_BUG_ON(!dma_resv_test_signaled_rcu(batch->resv, true)); err = i915_vma_move_to_active(batch, rq, 0); i915_vma_unlock(batch); if (err) @@ -1313,7 +1313,7 @@ relocate_entry(struct i915_vma *vma, if (!eb->reloc_cache.vaddr && (DBG_FORCE_RELOC == FORCE_GPU_RELOC || - !reservation_object_test_signaled_rcu(vma->resv, true))) { + !dma_resv_test_signaled_rcu(vma->resv, true))) { const unsigned int gen = eb->reloc_cache.gen; unsigned int len; u32 *batch; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_fence.c b/drivers/gpu/drm/i915/gem/i915_gem_fence.c index cf0439e6be83..5496f33a9064 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_fence.c @@ -78,7 +78,7 @@ i915_gem_object_lock_fence(struct drm_i915_gem_object *obj) I915_FENCE_GFP) < 0) goto err; - reservation_object_add_excl_fence(obj->base.resv, &stub->dma); + dma_resv_add_excl_fence(obj->base.resv, &stub->dma); return &stub->dma; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index d5197a2a106f..afd75b85da1d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -152,7 +152,7 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head) container_of(head, typeof(*obj), rcu); struct drm_i915_private *i915 = to_i915(obj->base.dev); - reservation_object_fini(&obj->base._resv); + dma_resv_fini(&obj->base._resv); i915_gem_object_free(obj); GEM_BUG_ON(!atomic_read(&i915->mm.free_count)); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 67aea07ea019..69ad38949141 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -99,22 +99,22 @@ i915_gem_object_put(struct drm_i915_gem_object *obj) __drm_gem_object_put(&obj->base); } -#define assert_object_held(obj) reservation_object_assert_held((obj)->base.resv) +#define assert_object_held(obj) dma_resv_assert_held((obj)->base.resv) static inline void i915_gem_object_lock(struct drm_i915_gem_object *obj) { - reservation_object_lock(obj->base.resv, NULL); + dma_resv_lock(obj->base.resv, NULL); } static inline int i915_gem_object_lock_interruptible(struct drm_i915_gem_object *obj) { - return reservation_object_lock_interruptible(obj->base.resv, NULL); + return dma_resv_lock_interruptible(obj->base.resv, NULL); } static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj) { - reservation_object_unlock(obj->base.resv); + dma_resv_unlock(obj->base.resv); } struct dma_fence * @@ -367,7 +367,7 @@ i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj) struct dma_fence *fence; rcu_read_lock(); - fence = reservation_object_get_excl_rcu(obj->base.resv); + fence = dma_resv_get_excl_rcu(obj->base.resv); rcu_read_unlock(); if (fence && dma_fence_is_i915(fence) && !dma_fence_is_signaled(fence)) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c index fa46a54bcbe7..8af55cd3e690 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c @@ -31,7 +31,7 @@ i915_gem_object_wait_fence(struct dma_fence *fence, } static long -i915_gem_object_wait_reservation(struct reservation_object *resv, +i915_gem_object_wait_reservation(struct dma_resv *resv, unsigned int flags, long timeout) { @@ -43,7 +43,7 @@ i915_gem_object_wait_reservation(struct reservation_object *resv, unsigned int count, i; int ret; - ret = reservation_object_get_fences_rcu(resv, + ret = dma_resv_get_fences_rcu(resv, &excl, &count, &shared); if (ret) return ret; @@ -72,7 +72,7 @@ i915_gem_object_wait_reservation(struct reservation_object *resv, */ prune_fences = count && timeout >= 0; } else { - excl = reservation_object_get_excl_rcu(resv); + excl = dma_resv_get_excl_rcu(resv); } if (excl && timeout >= 0) @@ -84,10 +84,10 @@ i915_gem_object_wait_reservation(struct reservation_object *resv, * Opportunistically prune the fences iff we know they have *all* been * signaled. */ - if (prune_fences && reservation_object_trylock(resv)) { - if (reservation_object_test_signaled_rcu(resv, true)) - reservation_object_add_excl_fence(resv, NULL); - reservation_object_unlock(resv); + if (prune_fences && dma_resv_trylock(resv)) { + if (dma_resv_test_signaled_rcu(resv, true)) + dma_resv_add_excl_fence(resv, NULL); + dma_resv_unlock(resv); } return timeout; @@ -140,7 +140,7 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object *obj, unsigned int count, i; int ret; - ret = reservation_object_get_fences_rcu(obj->base.resv, + ret = dma_resv_get_fences_rcu(obj->base.resv, &excl, &count, &shared); if (ret) return ret; @@ -152,7 +152,7 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object *obj, kfree(shared); } else { - excl = reservation_object_get_excl_rcu(obj->base.resv); + excl = dma_resv_get_excl_rcu(obj->base.resv); } if (excl) { diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c index c092bdf5f0bf..ea56b2cc6095 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -112,18 +112,18 @@ __dma_fence_signal__timestamp(struct dma_fence *fence, ktime_t timestamp) } static void -__dma_fence_signal__notify(struct dma_fence *fence) +__dma_fence_signal__notify(struct dma_fence *fence, + const struct list_head *list) { struct dma_fence_cb *cur, *tmp; lockdep_assert_held(fence->lock); lockdep_assert_irqs_disabled(); - list_for_each_entry_safe(cur, tmp, &fence->cb_list, node) { + list_for_each_entry_safe(cur, tmp, list, node) { INIT_LIST_HEAD(&cur->node); cur->func(fence, cur); } - INIT_LIST_HEAD(&fence->cb_list); } void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine) @@ -185,11 +185,12 @@ void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine) list_for_each_safe(pos, next, &signal) { struct i915_request *rq = list_entry(pos, typeof(*rq), signal_link); - - __dma_fence_signal__timestamp(&rq->fence, timestamp); + struct list_head cb_list; spin_lock(&rq->lock); - __dma_fence_signal__notify(&rq->fence); + list_replace(&rq->fence.cb_list, &cb_list); + __dma_fence_signal__timestamp(&rq->fence, timestamp); + __dma_fence_signal__notify(&rq->fence, &cb_list); spin_unlock(&rq->lock); i915_request_put(rq); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2e13ecc9cbb6..681ab0aea70e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -43,7 +43,7 @@ #include <linux/mm_types.h> #include <linux/perf_event.h> #include <linux/pm_qos.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/shmem_fs.h> #include <linux/stackdepot.h> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 65863e955f40..f6e66a7f4bf0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -29,7 +29,7 @@ #include <drm/i915_drm.h> #include <linux/dma-fence-array.h> #include <linux/kthread.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/shmem_fs.h> #include <linux/slab.h> #include <linux/stop_machine.h> diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c b/drivers/gpu/drm/i915/i915_gem_batch_pool.c index b17f23991253..8675a608a6fe 100644 --- a/drivers/gpu/drm/i915/i915_gem_batch_pool.c +++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c @@ -94,10 +94,10 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, list = &pool->cache_list[n]; list_for_each_entry(obj, list, batch_pool_link) { - struct reservation_object *resv = obj->base.resv; + struct dma_resv *resv = obj->base.resv; /* The batches are strictly LRU ordered */ - if (!reservation_object_test_signaled_rcu(resv, true)) + if (!dma_resv_test_signaled_rcu(resv, true)) break; /* @@ -109,9 +109,9 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, * than replace the existing fence. */ if (rcu_access_pointer(resv->fence)) { - reservation_object_lock(resv, NULL); - reservation_object_add_excl_fence(resv, NULL); - reservation_object_unlock(resv); + dma_resv_lock(resv, NULL); + dma_resv_add_excl_fence(resv, NULL); + dma_resv_unlock(resv); } if (obj->base.size >= size) diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 8ac7d14ec8c9..6d5d7eb25663 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -1038,7 +1038,7 @@ i915_request_await_object(struct i915_request *to, struct dma_fence **shared; unsigned int count, i; - ret = reservation_object_get_fences_rcu(obj->base.resv, + ret = dma_resv_get_fences_rcu(obj->base.resv, &excl, &count, &shared); if (ret) return ret; @@ -1055,7 +1055,7 @@ i915_request_await_object(struct i915_request *to, dma_fence_put(shared[i]); kfree(shared); } else { - excl = reservation_object_get_excl_rcu(obj->base.resv); + excl = dma_resv_get_excl_rcu(obj->base.resv); } if (excl) { diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index 5387aafd3424..362e4e00b4c6 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -7,7 +7,7 @@ #include <linux/slab.h> #include <linux/dma-fence.h> #include <linux/irq_work.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "i915_sw_fence.h" #include "i915_selftest.h" @@ -510,7 +510,7 @@ int __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, } int i915_sw_fence_await_reservation(struct i915_sw_fence *fence, - struct reservation_object *resv, + struct dma_resv *resv, const struct dma_fence_ops *exclude, bool write, unsigned long timeout, @@ -526,7 +526,7 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence, struct dma_fence **shared; unsigned int count, i; - ret = reservation_object_get_fences_rcu(resv, + ret = dma_resv_get_fences_rcu(resv, &excl, &count, &shared); if (ret) return ret; @@ -551,7 +551,7 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence, dma_fence_put(shared[i]); kfree(shared); } else { - excl = reservation_object_get_excl_rcu(resv); + excl = dma_resv_get_excl_rcu(resv); } if (ret >= 0 && excl && excl->ops != exclude) { diff --git a/drivers/gpu/drm/i915/i915_sw_fence.h b/drivers/gpu/drm/i915/i915_sw_fence.h index 9cb5c3b307a6..8cf353e8c3e0 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.h +++ b/drivers/gpu/drm/i915/i915_sw_fence.h @@ -16,7 +16,7 @@ #include <linux/wait.h> struct completion; -struct reservation_object; +struct dma_resv; struct i915_sw_fence { wait_queue_head_t wait; @@ -82,7 +82,7 @@ int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence, gfp_t gfp); int i915_sw_fence_await_reservation(struct i915_sw_fence *fence, - struct reservation_object *resv, + struct dma_resv *resv, const struct dma_fence_ops *exclude, bool write, unsigned long timeout, diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index eb16a1a93bbc..2645f4e850c2 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -890,7 +890,7 @@ static void export_fence(struct i915_vma *vma, struct i915_request *rq, unsigned int flags) { - struct reservation_object *resv = vma->resv; + struct dma_resv *resv = vma->resv; /* * Ignore errors from failing to allocate the new fence, we can't @@ -898,9 +898,9 @@ static void export_fence(struct i915_vma *vma, * synchronisation leading to rendering corruption. */ if (flags & EXEC_OBJECT_WRITE) - reservation_object_add_excl_fence(resv, &rq->fence); - else if (reservation_object_reserve_shared(resv, 1) == 0) - reservation_object_add_shared_fence(resv, &rq->fence); + dma_resv_add_excl_fence(resv, &rq->fence); + else if (dma_resv_reserve_shared(resv, 1) == 0) + dma_resv_add_shared_fence(resv, &rq->fence); } int i915_vma_move_to_active(struct i915_vma *vma, diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index 4b769db649bf..59a497561fc4 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -55,7 +55,7 @@ struct i915_vma { struct i915_address_space *vm; const struct i915_vma_ops *ops; struct i915_fence_reg *fence; - struct reservation_object *resv; /** Alias of obj->resv */ + struct dma_resv *resv; /** Alias of obj->resv */ struct sg_table *pages; void __iomem *iomap; void *private; /* owned by creator */ @@ -299,16 +299,16 @@ void i915_vma_close(struct i915_vma *vma); void i915_vma_reopen(struct i915_vma *vma); void i915_vma_destroy(struct i915_vma *vma); -#define assert_vma_held(vma) reservation_object_assert_held((vma)->resv) +#define assert_vma_held(vma) dma_resv_assert_held((vma)->resv) static inline void i915_vma_lock(struct i915_vma *vma) { - reservation_object_lock(vma->resv, NULL); + dma_resv_lock(vma->resv, NULL); } static inline void i915_vma_unlock(struct i915_vma *vma) { - reservation_object_unlock(vma->resv); + dma_resv_unlock(vma->resv); } int __i915_vma_do_pin(struct i915_vma *vma, diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index db461b6a257f..695f307f36b2 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -124,14 +124,11 @@ static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch, static int imx_ldb_connector_get_modes(struct drm_connector *connector) { struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); - int num_modes = 0; + int num_modes; - if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs && - imx_ldb_ch->panel->funcs->get_modes) { - num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel); - if (num_modes > 0) - return num_modes; - } + num_modes = drm_panel_get_modes(imx_ldb_ch->panel); + if (num_modes > 0) + return num_modes; if (!imx_ldb_ch->edid && imx_ldb_ch->ddc) imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 2e51b2fade75..e7ce17503ae1 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -47,14 +47,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) { struct imx_parallel_display *imxpd = con_to_imxpd(connector); struct device_node *np = imxpd->dev->of_node; - int num_modes = 0; + int num_modes; - if (imxpd->panel && imxpd->panel->funcs && - imxpd->panel->funcs->get_modes) { - num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); - if (num_modes > 0) - return num_modes; - } + num_modes = drm_panel_get_modes(imxpd->panel); + if (num_modes > 0) + return num_modes; if (imxpd->edid) { drm_connector_update_edid_property(connector, imxpd->edid); diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c index fd1a024703d2..ff3d9acc24fc 100644 --- a/drivers/gpu/drm/lima/lima_gem.c +++ b/drivers/gpu/drm/lima/lima_gem.c @@ -136,7 +136,7 @@ static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo, int err = 0; if (!write) { - err = reservation_object_reserve_shared(bo->gem.resv, 1); + err = dma_resv_reserve_shared(bo->gem.resv, 1); if (err) return err; } @@ -296,9 +296,9 @@ int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) for (i = 0; i < submit->nr_bos; i++) { if (submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE) - reservation_object_add_excl_fence(bos[i]->gem.resv, fence); + dma_resv_add_excl_fence(bos[i]->gem.resv, fence); else - reservation_object_add_shared_fence(bos[i]->gem.resv, fence); + dma_resv_add_shared_fence(bos[i]->gem.resv, fence); } lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); @@ -341,7 +341,7 @@ int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns) timeout = drm_timeout_abs_to_jiffies(timeout_ns); - ret = drm_gem_reservation_object_wait(file, handle, write, timeout); + ret = drm_gem_dma_resv_wait(file, handle, write, timeout); if (ret == 0) ret = timeout ? -ETIMEDOUT : -EBUSY; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_fb.c b/drivers/gpu/drm/mediatek/mtk_drm_fb.c index ae40b080ae47..3f230a28a2dc 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_fb.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_fb.c @@ -4,7 +4,7 @@ */ #include <linux/dma-buf.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <drm/drm_modeset_helper.h> #include <drm/drm_fb_helper.h> diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 3320a74e67fa..bba25325aa9c 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -265,11 +265,11 @@ static void meson_crtc_enable_vd1(struct meson_drm *priv) static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) { - writel_relaxed(((1 << 16) | /* post bld premult*/ - (1 << 8) | /* post src */ - (1 << 4) | /* pre bld premult*/ - (1 << 0)), - priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); + writel_relaxed(VD_BLEND_PREBLD_SRC_VD1 | + VD_BLEND_PREBLD_PREMULT_EN | + VD_BLEND_POSTBLD_SRC_VD1 | + VD_BLEND_POSTBLD_PREMULT_EN, + priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); } void meson_crtc_irq(struct meson_drm *priv) @@ -487,7 +487,12 @@ void meson_crtc_irq(struct meson_drm *priv) writel_relaxed(priv->viu.vd1_range_map_cr, priv->io_base + meson_crtc->viu_offset + _REG(VD1_IF0_RANGE_MAP_CR)); - writel_relaxed(0x78404, + writel_relaxed(VPP_VSC_BANK_LENGTH(4) | + VPP_HSC_BANK_LENGTH(4) | + VPP_SC_VD_EN_ENABLE | + VPP_SC_TOP_EN_ENABLE | + VPP_SC_HSC_EN_ENABLE | + VPP_SC_VSC_EN_ENABLE, priv->io_base + _REG(VPP_SC_MISC)); writel_relaxed(priv->viu.vpp_pic_in_height, priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 42af49afdd75..ae0166181606 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -140,10 +140,28 @@ static struct regmap_config meson_regmap_config = { static void meson_vpu_init(struct meson_drm *priv) { - writel_relaxed(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); - writel_relaxed(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); - writel_relaxed(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); - writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); + u32 value; + + /* + * Slave dc0 and dc5 connected to master port 1. + * By default other slaves are connected to master port 0. + */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) | + VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); + + /* Slave dc0 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); + + /* Slave dc4 and dc7 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) | + VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); + + /* Slave dc1 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } static void meson_remove_framebuffers(void) diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c index 9f0b08eaf003..f893ebd0b799 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c @@ -429,6 +429,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 0x3, 0x3); + + /* Enable cec_clk and hdcp22_tmdsclk_en */ dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, 0x3 << 4, 0x3 << 4); diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h index 1b2ef043eb5c..08e1c14e4ea0 100644 --- a/drivers/gpu/drm/meson/meson_dw_hdmi.h +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h @@ -100,7 +100,8 @@ #define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6) #define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7) -/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; +/* + * Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern * every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0. @@ -135,7 +136,8 @@ /* Bit 9: 0 RW tmds_clk_pttn[29:20]. Default 0. */ #define HDMITX_TOP_TMDS_CLK_PTTN_23 (0x00B) -/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, +/* + * Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern, * used when TMDS CLK rate = TMDS character rate /4. Default 0. * Bit 0 R Reserved. Default 0. * [ 1] shift_tmds_clk_pttn @@ -143,12 +145,14 @@ */ #define HDMITX_TOP_TMDS_CLK_PTTN_CNTL (0x00C) -/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM +/* + * Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM * failure, write 1 to clear the failure flag. Default 0. */ #define HDMITX_TOP_REVOCMEM_STAT (0x00D) -/* Bit 1 R filtered RxSense status +/* + * Bit 1 R filtered RxSense status * Bit 0 R filtered HPD status. */ #define HDMITX_TOP_STAT0 (0x00E) diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 80b8d70c4d75..b9e1e117fb85 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -328,7 +328,7 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, /* Disable OSD1 */ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) - writel_bits_relaxed(3 << 8, 0, + writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); else writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h index 057453ce027c..05fce48ceee0 100644 --- a/drivers/gpu/drm/meson/meson_registers.h +++ b/drivers/gpu/drm/meson/meson_registers.h @@ -12,7 +12,7 @@ #define _REG(reg) ((reg) << 2) #define writel_bits_relaxed(mask, val, addr) \ - writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) + writel_relaxed((readl_relaxed(addr) & ~(mask)) | ((val) & (mask)), addr) /* vpp2 */ #define VPP2_DUMMY_DATA 0x1900 @@ -138,11 +138,19 @@ #define VIU_ADDR_START 0x1a00 #define VIU_ADDR_END 0x1aff #define VIU_SW_RESET 0x1a01 +#define VIU_SW_RESET_OSD1 BIT(0) #define VIU_MISC_CTRL0 0x1a06 +#define VIU_CTRL0_VD1_AFBC_MASK 0x170000 #define VIU_MISC_CTRL1 0x1a07 #define D2D3_INTF_LENGTH 0x1a08 #define D2D3_INTF_CTRL0 0x1a09 #define VIU_OSD1_CTRL_STAT 0x1a10 +#define VIU_OSD1_OSD_BLK_ENABLE BIT(0) +#define VIU_OSD1_POSTBLD_SRC_VD1 (1 << 8) +#define VIU_OSD1_POSTBLD_SRC_VD2 (2 << 8) +#define VIU_OSD1_POSTBLD_SRC_OSD1 (3 << 8) +#define VIU_OSD1_POSTBLD_SRC_OSD2 (4 << 8) +#define VIU_OSD1_OSD_ENABLE BIT(21) #define VIU_OSD1_CTRL_STAT2 0x1a2d #define VIU_OSD1_COLOR_ADDR 0x1a11 #define VIU_OSD1_COLOR 0x1a12 @@ -232,6 +240,12 @@ #define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f #define VIU_OSD3_DIMM_CTRL 0x3da0 +#define VIU_OSD_DDR_PRIORITY_URGENT BIT(0) +#define VIU_OSD_HOLD_FIFO_LINES(lines) ((lines & 0x1f) << 5) +#define VIU_OSD_FIFO_DEPTH_VAL(val) ((val & 0x7f) << 12) +#define VIU_OSD_WORDS_PER_BURST(words) (((words & 0x4) >> 1) << 22) +#define VIU_OSD_FIFO_LIMITS(size) ((size & 0xf) << 24) + #define VD1_IF0_GEN_REG 0x1a50 #define VD1_IF0_CANVAS0 0x1a51 #define VD1_IF0_CANVAS1 0x1a52 @@ -341,6 +355,7 @@ #define VPP_LINE_IN_LENGTH 0x1d01 #define VPP_PIC_IN_HEIGHT 0x1d02 #define VPP_SCALE_COEF_IDX 0x1d03 +#define VPP_SCALE_HORIZONTAL_COEF BIT(8) #define VPP_SCALE_COEF 0x1d04 #define VPP_VSC_REGION12_STARTP 0x1d05 #define VPP_VSC_REGION34_STARTP 0x1d06 @@ -362,6 +377,12 @@ #define VPP_HSC_REGION4_PHASE_SLOPE 0x1d17 #define VPP_HSC_PHASE_CTRL 0x1d18 #define VPP_SC_MISC 0x1d19 +#define VPP_SC_VD_EN_ENABLE BIT(15) +#define VPP_SC_TOP_EN_ENABLE BIT(16) +#define VPP_SC_HSC_EN_ENABLE BIT(17) +#define VPP_SC_VSC_EN_ENABLE BIT(18) +#define VPP_VSC_BANK_LENGTH(length) (length & 0x7) +#define VPP_HSC_BANK_LENGTH(length) ((length & 0x7) << 8) #define VPP_PREBLEND_VD1_H_START_END 0x1d1a #define VPP_PREBLEND_VD1_V_START_END 0x1d1b #define VPP_POSTBLEND_VD1_H_START_END 0x1d1c @@ -371,24 +392,28 @@ #define VPP_PREBLEND_H_SIZE 0x1d20 #define VPP_POSTBLEND_H_SIZE 0x1d21 #define VPP_HOLD_LINES 0x1d22 +#define VPP_POSTBLEND_HOLD_LINES(lines) (lines & 0xf) +#define VPP_PREBLEND_HOLD_LINES(lines) ((lines & 0xf) << 8) #define VPP_BLEND_ONECOLOR_CTRL 0x1d23 #define VPP_PREBLEND_CURRENT_XY 0x1d24 #define VPP_POSTBLEND_CURRENT_XY 0x1d25 #define VPP_MISC 0x1d26 -#define VPP_PREBLEND_ENABLE BIT(6) -#define VPP_POSTBLEND_ENABLE BIT(7) -#define VPP_OSD2_ALPHA_PREMULT BIT(8) -#define VPP_OSD1_ALPHA_PREMULT BIT(9) -#define VPP_VD1_POSTBLEND BIT(10) -#define VPP_VD2_POSTBLEND BIT(11) -#define VPP_OSD1_POSTBLEND BIT(12) -#define VPP_OSD2_POSTBLEND BIT(13) -#define VPP_VD1_PREBLEND BIT(14) -#define VPP_VD2_PREBLEND BIT(15) -#define VPP_OSD1_PREBLEND BIT(16) -#define VPP_OSD2_PREBLEND BIT(17) -#define VPP_COLOR_MNG_ENABLE BIT(28) +#define VPP_PREBLEND_ENABLE BIT(6) +#define VPP_POSTBLEND_ENABLE BIT(7) +#define VPP_OSD2_ALPHA_PREMULT BIT(8) +#define VPP_OSD1_ALPHA_PREMULT BIT(9) +#define VPP_VD1_POSTBLEND BIT(10) +#define VPP_VD2_POSTBLEND BIT(11) +#define VPP_OSD1_POSTBLEND BIT(12) +#define VPP_OSD2_POSTBLEND BIT(13) +#define VPP_VD1_PREBLEND BIT(14) +#define VPP_VD2_PREBLEND BIT(15) +#define VPP_OSD1_PREBLEND BIT(16) +#define VPP_OSD2_PREBLEND BIT(17) +#define VPP_COLOR_MNG_ENABLE BIT(28) #define VPP_OFIFO_SIZE 0x1d27 +#define VPP_OFIFO_SIZE_MASK GENMASK(13, 0) +#define VPP_OFIFO_SIZE_DEFAULT (0xfff << 20 | 0x1000) #define VPP_FIFO_STATUS 0x1d28 #define VPP_SMOKE_CTRL 0x1d29 #define VPP_SMOKE1_VAL 0x1d2a @@ -404,6 +429,8 @@ #define VPP_HSC_PHASE_CTRL1 0x1d34 #define VPP_HSC_INI_PAT_CTRL 0x1d35 #define VPP_VADJ_CTRL 0x1d40 +#define VPP_MINUS_BLACK_LVL_VADJ1_ENABLE BIT(1) + #define VPP_VADJ1_Y 0x1d41 #define VPP_VADJ1_MA_MB 0x1d42 #define VPP_VADJ1_MC_MD 0x1d43 @@ -463,6 +490,7 @@ #define VPP_PEAKING_VGAIN 0x1d92 #define VPP_PEAKING_NLP_1 0x1d93 #define VPP_DOLBY_CTRL 0x1d93 +#define VPP_PPS_DUMMY_DATA_MODE (1 << 17) #define VPP_PEAKING_NLP_2 0x1d94 #define VPP_PEAKING_NLP_3 0x1d95 #define VPP_PEAKING_NLP_4 0x1d96 @@ -593,6 +621,7 @@ #define OSD34_SCI_WH_M1 0x3d29 #define OSD34_SCO_H_START_END 0x3d2a #define OSD34_SCO_V_START_END 0x3d2b + /* viu2 */ #define VIU2_ADDR_START 0x1e00 #define VIU2_ADDR_END 0x1eff @@ -706,6 +735,25 @@ #define VENC_UPSAMPLE_CTRL0 0x1b64 #define VENC_UPSAMPLE_CTRL1 0x1b65 #define VENC_UPSAMPLE_CTRL2 0x1b66 +#define VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO BIT(0) +#define VENC_UPSAMPLE_CTRL_F1_EN BIT(5) +#define VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN BIT(6) +#define VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA (0x0 << 12) +#define VENC_UPSAMPLE_CTRL_CVBS (0x1 << 12) +#define VENC_UPSAMPLE_CTRL_S_VIDEO_LUMA (0x2 << 12) +#define VENC_UPSAMPLE_CTRL_S_VIDEO_CHROMA (0x3 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_PB (0x4 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_PR (0x5 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_R (0x6 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_G (0x7 << 12) +#define VENC_UPSAMPLE_CTRL_INTERLACE_B (0x8 << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_Y (0x9 << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_PB (0xa << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_PR (0xb << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_R (0xc << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_G (0xd << 12) +#define VENC_UPSAMPLE_CTRL_PROGRESSIVE_B (0xe << 12) +#define VENC_UPSAMPLE_CTRL_VDAC_TEST_VALUE (0xf << 12) #define TCON_INVERT_CTL 0x1b67 #define VENC_VIDEO_PROG_MODE 0x1b68 #define VENC_ENCI_LINE 0x1b69 @@ -714,6 +762,7 @@ #define VENC_ENCP_PIXEL 0x1b6c #define VENC_STATA 0x1b6d #define VENC_INTCTRL 0x1b6e +#define VENC_INTCTRL_ENCI_LNRST_INT_EN BIT(1) #define VENC_INTFLAG 0x1b6f #define VENC_VIDEO_TST_EN 0x1b70 #define VENC_VIDEO_TST_MDSEL 0x1b71 @@ -724,6 +773,7 @@ #define VENC_VIDEO_TST_CLRBAR_WIDTH 0x1b76 #define VENC_VIDEO_TST_VDCNT_STSET 0x1b77 #define VENC_VDAC_DACSEL0 0x1b78 +#define VENC_VDAC_SEL_ATV_DMD BIT(5) #define VENC_VDAC_DACSEL1 0x1b79 #define VENC_VDAC_DACSEL2 0x1b7a #define VENC_VDAC_DACSEL3 0x1b7b @@ -744,6 +794,7 @@ #define VENC_VDAC_DAC5_GAINCTRL 0x1bfa #define VENC_VDAC_DAC5_OFFSET 0x1bfb #define VENC_VDAC_FIFO_CTRL 0x1bfc +#define VENC_VDAC_FIFO_EN_ENCI_ENABLE BIT(13) #define ENCL_TCON_INVERT_CTL 0x1bfd #define ENCP_VIDEO_EN 0x1b80 #define ENCP_VIDEO_SYNC_MODE 0x1b81 @@ -759,6 +810,7 @@ #define ENCP_VIDEO_SYNC_OFFST 0x1b8b #define ENCP_VIDEO_MACV_OFFST 0x1b8c #define ENCP_VIDEO_MODE 0x1b8d +#define ENCP_VIDEO_MODE_DE_V_HIGH BIT(14) #define ENCP_VIDEO_MODE_ADV 0x1b8e #define ENCP_DBG_PX_RST 0x1b90 #define ENCP_DBG_LN_RST 0x1b91 @@ -837,6 +889,11 @@ #define C656_FS_LNED 0x1be7 #define ENCI_VIDEO_MODE 0x1b00 #define ENCI_VIDEO_MODE_ADV 0x1b01 +#define ENCI_VIDEO_MODE_ADV_DMXMD(val) (val & 0x3) +#define ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 BIT(2) +#define ENCI_VIDEO_MODE_ADV_YBW_MEDIUM (0 << 4) +#define ENCI_VIDEO_MODE_ADV_YBW_LOW (0x1 << 4) +#define ENCI_VIDEO_MODE_ADV_YBW_HIGH (0x2 << 4) #define ENCI_VIDEO_FSC_ADJ 0x1b02 #define ENCI_VIDEO_BRIGHT 0x1b03 #define ENCI_VIDEO_CONT 0x1b04 @@ -907,13 +964,17 @@ #define ENCI_DBG_MAXPX 0x1b4c #define ENCI_DBG_MAXLN 0x1b4d #define ENCI_MACV_MAX_AMP 0x1b50 +#define ENCI_MACV_MAX_AMP_ENABLE_CHANGE BIT(15) +#define ENCI_MACV_MAX_AMP_VAL(val) (val & 0x83ff) #define ENCI_MACV_PULSE_LO 0x1b51 #define ENCI_MACV_PULSE_HI 0x1b52 #define ENCI_MACV_BKP_MAX 0x1b53 #define ENCI_CFILT_CTRL 0x1b54 +#define ENCI_CFILT_CMPT_SEL_HIGH BIT(1) #define ENCI_CFILT7 0x1b55 #define ENCI_YC_DELAY 0x1b56 #define ENCI_VIDEO_EN 0x1b57 +#define ENCI_VIDEO_EN_ENABLE BIT(0) #define ENCI_DVI_HSO_BEGIN 0x1c00 #define ENCI_DVI_HSO_END 0x1c01 #define ENCI_DVI_VSO_BLINE_EVN 0x1c02 @@ -925,6 +986,10 @@ #define ENCI_DVI_VSO_END_EVN 0x1c08 #define ENCI_DVI_VSO_END_ODD 0x1c09 #define ENCI_CFILT_CTRL2 0x1c0a +#define ENCI_CFILT_CMPT_CR_DLY(delay) (delay & 0xf) +#define ENCI_CFILT_CMPT_CB_DLY(delay) ((delay & 0xf) << 4) +#define ENCI_CFILT_CVBS_CR_DLY(delay) ((delay & 0xf) << 8) +#define ENCI_CFILT_CVBS_CB_DLY(delay) ((delay & 0xf) << 12) #define ENCI_DACSEL_0 0x1c0b #define ENCI_DACSEL_1 0x1c0c #define ENCP_DACSEL_0 0x1c0d @@ -939,6 +1004,8 @@ #define ENCI_TST_CLRBAR_WIDTH 0x1c16 #define ENCI_TST_VDCNT_STSET 0x1c17 #define ENCI_VFIFO2VD_CTL 0x1c18 +#define ENCI_VFIFO2VD_CTL_ENABLE BIT(0) +#define ENCI_VFIFO2VD_CTL_VD_SEL(val) ((val & 0xff) << 8) #define ENCI_VFIFO2VD_PIXEL_START 0x1c19 #define ENCI_VFIFO2VD_PIXEL_END 0x1c1a #define ENCI_VFIFO2VD_LINE_TOP_START 0x1c1b @@ -1001,6 +1068,7 @@ #define VENC_VDAC_DAC5_FILT_CTRL0 0x1c56 #define VENC_VDAC_DAC5_FILT_CTRL1 0x1c57 #define VENC_VDAC_DAC0_FILT_CTRL0 0x1c58 +#define VENC_VDAC_DAC0_FILT_CTRL0_EN BIT(0) #define VENC_VDAC_DAC0_FILT_CTRL1 0x1c59 #define VENC_VDAC_DAC1_FILT_CTRL0 0x1c5a #define VENC_VDAC_DAC1_FILT_CTRL1 0x1c5b @@ -1406,6 +1474,18 @@ #define VIU2_SEL_VENC_ENCP (2 << 2) #define VIU2_SEL_VENC_ENCT (3 << 2) #define VPU_HDMI_SETTING 0x271b +#define VPU_HDMI_ENCI_DATA_TO_HDMI BIT(0) +#define VPU_HDMI_ENCP_DATA_TO_HDMI BIT(1) +#define VPU_HDMI_INV_HSYNC BIT(2) +#define VPU_HDMI_INV_VSYNC BIT(3) +#define VPU_HDMI_OUTPUT_CRYCB (0 << 5) +#define VPU_HDMI_OUTPUT_YCBCR (1 << 5) +#define VPU_HDMI_OUTPUT_YCRCB (2 << 5) +#define VPU_HDMI_OUTPUT_CBCRY (3 << 5) +#define VPU_HDMI_OUTPUT_CBYCR (4 << 5) +#define VPU_HDMI_OUTPUT_CRCBY (5 << 5) +#define VPU_HDMI_WR_RATE(rate) (((rate & 0x1f) - 1) << 8) +#define VPU_HDMI_RD_RATE(rate) (((rate & 0x1f) - 1) << 12) #define ENCI_INFO_READ 0x271c #define ENCP_INFO_READ 0x271d #define ENCT_INFO_READ 0x271e @@ -1482,6 +1562,7 @@ #define VPU_RDARB_MODE_L1C2 0x2799 #define VPU_RDARB_MODE_L2C1 0x279d #define VPU_WRARB_MODE_L2C1 0x27a2 +#define VPU_RDARB_SLAVE_TO_MASTER_PORT(dc, port) (port << (16 + dc)) /* osd super scale */ #define OSDSR_HV_SIZEIN 0x3130 @@ -1523,7 +1604,6 @@ #define OSD1_AFBCD_STATUS 0x31a8 #define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 #define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa -#define VIU_MISC_CTRL1 0x1a07 /* add for gxm and 962e dv core2 */ #define DOLBY_CORE2A_SWAP_CTRL1 0x3434 @@ -1538,8 +1618,6 @@ #define VPU_MAFBC_COMMAND 0x3a05 #define VPU_MAFBC_STATUS 0x3a06 #define VPU_MAFBC_SURFACE_CFG 0x3a07 - -/* osd afbc on g12a */ #define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 #define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 #define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 @@ -1597,10 +1675,18 @@ #define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c #define DOLBY_PATH_CTRL 0x1a0c +#define DOLBY_BYPASS_EN(val) (val & 0xf) #define OSD_PATH_MISC_CTRL 0x1a0e #define MALI_AFBCD_TOP_CTRL 0x1a0f #define VIU_OSD_BLEND_CTRL 0x39b0 +#define VIU_OSD_BLEND_REORDER(dest, src) ((src) << (dest * 4)) +#define VIU_OSD_BLEND_DIN_EN(bits) ((bits & 0xf) << 20) +#define VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 BIT(24) +#define VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 BIT(25) +#define VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 BIT(26) +#define VIU_OSD_BLEND_BLEN2_PREMULT_EN(input) ((input & 0x3) << 27) +#define VIU_OSD_BLEND_HOLD_LINES(lines) ((lines & 0x7) << 29) #define VIU_OSD_BLEND_CTRL1 0x39c0 #define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1 #define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2 @@ -1630,13 +1716,27 @@ #define VPP_SLEEP_CTRL 0x1dfa #define VD1_BLEND_SRC_CTRL 0x1dfb #define VD2_BLEND_SRC_CTRL 0x1dfc +#define VD_BLEND_PREBLD_SRC_VD1 (1 << 0) +#define VD_BLEND_PREBLD_SRC_VD2 (2 << 0) +#define VD_BLEND_PREBLD_SRC_OSD1 (3 << 0) +#define VD_BLEND_PREBLD_SRC_OSD2 (4 << 0) +#define VD_BLEND_PREBLD_PREMULT_EN BIT(4) +#define VD_BLEND_POSTBLD_SRC_VD1 (1 << 8) +#define VD_BLEND_POSTBLD_SRC_VD2 (2 << 8) +#define VD_BLEND_POSTBLD_SRC_OSD1 (3 << 8) +#define VD_BLEND_POSTBLD_SRC_OSD2 (4 << 8) +#define VD_BLEND_POSTBLD_PREMULT_EN BIT(16) #define OSD1_BLEND_SRC_CTRL 0x1dfd #define OSD2_BLEND_SRC_CTRL 0x1dfe +#define OSD_BLEND_POSTBLD_SRC_VD1 (1 << 8) +#define OSD_BLEND_POSTBLD_SRC_VD2 (2 << 8) +#define OSD_BLEND_POSTBLD_SRC_OSD1 (3 << 8) +#define OSD_BLEND_POSTBLD_SRC_OSD2 (4 << 8) +#define OSD_BLEND_PATH_SEL_ENABLE BIT(20) #define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968 #define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 #define VPP_RDARB_MODE 0x3978 #define VPP_RDARB_REQEN_SLV 0x3979 -#define VPU_RDARB_MODE_L2C1 0x279d #endif /* __MESON_REGISTERS_H */ diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c index 8abff51f937d..869231c93617 100644 --- a/drivers/gpu/drm/meson/meson_vclk.c +++ b/drivers/gpu/drm/meson/meson_vclk.c @@ -97,6 +97,7 @@ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ #define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ +#define HHI_HDMI_PLL_CNTL_EN BIT(30) #define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ #define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ @@ -469,7 +470,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, /* Enable and unreset */ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, - 0x7 << 28, 0x4 << 28); + 0x7 << 28, HHI_HDMI_PLL_CNTL_EN); /* Poll for lock bit */ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, @@ -496,6 +497,7 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m); /* Enable and reset */ + /* TODO: add specific macro for g12a here */ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3 << 28, 0x3 << 28); @@ -970,7 +972,8 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, meson_venci_cvbs_clock_config(priv); return; } else if (target == MESON_VCLK_TARGET_DMT) { - /* The DMT clock path is fixed after the PLL: + /* + * The DMT clock path is fixed after the PLL: * - automatic PLL freq + OD management * - vid_pll_div = VID_PLL_DIV_5 * - vclk_div = 2 diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index 3d4791798ae0..679d2274531c 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -61,9 +61,9 @@ /* HHI Registers */ #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ -#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ +#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbb offset in data sheet */ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ -#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ +#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbc offset in data sheet */ #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { @@ -192,7 +192,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = { .hso_end = 129, .vso_even = 3, .vso_odd = 260, - .macv_max_amp = 0x810b, + .macv_max_amp = 0xb, .video_prog_mode = 0xf0, .video_mode = 0x8, .sch_adjust = 0x20, @@ -212,7 +212,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = { .hso_end = 129, .vso_even = 3, .vso_odd = 260, - .macv_max_amp = 8107, + .macv_max_amp = 0x7, .video_prog_mode = 0xff, .video_mode = 0x13, .sch_adjust = 0x28, @@ -976,6 +976,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int eof_lines; unsigned int sof_lines; unsigned int vsync_lines; + u32 reg; /* Use VENCI for 480i and 576i and double HDMI pixels */ if (mode->flags & DRM_MODE_FLAG_DBLCLK) { @@ -1048,8 +1049,11 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, unsigned int lines_f1; /* CVBS Filter settings */ - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); + writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0x10, + priv->io_base + _REG(ENCI_CFILT_CTRL)); + writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2) | + ENCI_CFILT_CMPT_CB_DLY(1), + priv->io_base + _REG(ENCI_CFILT_CTRL2)); /* Digital Video Select : Interlace, clk27 clk, external */ writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); @@ -1071,8 +1075,9 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); /* Macrovision max amplitude change */ - writel_relaxed(vmode->enci.macv_max_amp, - priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE | + ENCI_MACV_MAX_AMP_VAL(vmode->enci.macv_max_amp), + priv->io_base + _REG(ENCI_MACV_MAX_AMP)); /* Video mode */ writel_relaxed(vmode->enci.video_prog_mode, @@ -1080,7 +1085,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, writel_relaxed(vmode->enci.video_mode, priv->io_base + _REG(ENCI_VIDEO_MODE)); - /* Advanced Video Mode : + /* + * Advanced Video Mode : * Demux shifting 0x2 * Blank line end at line17/22 * High bandwidth Luma Filter @@ -1088,7 +1094,10 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, * Bypass luma low pass filter * No macrovision on CSYNC */ - writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + writel_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2) | + ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 | + ENCI_VIDEO_MODE_ADV_YBW_HIGH, + priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); writel(vmode->enci.sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH)); @@ -1104,8 +1113,17 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, /* UNreset Interlaced TV Encoder */ writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); - /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ - writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + /* + * Enable Vfifo2vd and set Y_Cb_Y_Cr: + * Corresponding value: + * Y => 00 or 10 + * Cb => 01 + * Cr => 11 + * Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y + */ + writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE | + ENCI_VFIFO2VD_CTL_VD_SEL(0x4e), + priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); /* Timings */ writel_relaxed(vmode->enci.pixel_start, @@ -1127,7 +1145,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); /* Interlace video enable */ - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(ENCI_VIDEO_EN_ENABLE, + priv->io_base + _REG(ENCI_VIDEO_EN)); lines_f0 = mode->vtotal >> 1; lines_f1 = lines_f0 + 1; @@ -1374,7 +1393,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); /* Set DE signal’s polarity is active high */ - writel_bits_relaxed(BIT(14), BIT(14), + writel_bits_relaxed(ENCP_VIDEO_MODE_DE_V_HIGH, + ENCP_VIDEO_MODE_DE_V_HIGH, priv->io_base + _REG(ENCP_VIDEO_MODE)); /* Program DE timing */ @@ -1493,13 +1513,39 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCP); } - writel_relaxed((use_enci ? 1 : 2) | - (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) | - (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) | - 4 << 5 | - (venc_repeat ? 1 << 8 : 0) | - (hdmi_repeat ? 1 << 12 : 0), - priv->io_base + _REG(VPU_HDMI_SETTING)); + /* Set VPU HDMI setting */ + /* Select ENCP or ENCI data to HDMI */ + if (use_enci) + reg = VPU_HDMI_ENCI_DATA_TO_HDMI; + else + reg = VPU_HDMI_ENCP_DATA_TO_HDMI; + + /* Invert polarity of HSYNC from VENC */ + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + reg |= VPU_HDMI_INV_HSYNC; + + /* Invert polarity of VSYNC from VENC */ + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + reg |= VPU_HDMI_INV_VSYNC; + + /* Output data format: CbYCr */ + reg |= VPU_HDMI_OUTPUT_CBYCR; + + /* + * Write rate to the async FIFO between VENC and HDMI. + * One write every 2 wr_clk. + */ + if (venc_repeat) + reg |= VPU_HDMI_WR_RATE(2); + + /* + * Read rate to the async FIFO between VENC and HDMI. + * One read every 2 wr_clk. + */ + if (hdmi_repeat) + reg |= VPU_HDMI_RD_RATE(2); + + writel_relaxed(reg, priv->io_base + _REG(VPU_HDMI_SETTING)); priv->venc.hdmi_repeat = hdmi_repeat; priv->venc.venc_repeat = venc_repeat; @@ -1512,12 +1558,17 @@ EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set); void meson_venci_cvbs_mode_set(struct meson_drm *priv, struct meson_cvbs_enci_mode *mode) { + u32 reg; + if (mode->mode_tag == priv->venc.current_mode) return; /* CVBS Filter settings */ - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); - writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); + writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0x10, + priv->io_base + _REG(ENCI_CFILT_CTRL)); + writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2) | + ENCI_CFILT_CMPT_CB_DLY(1), + priv->io_base + _REG(ENCI_CFILT_CTRL2)); /* Digital Video Select : Interlace, clk27 clk, external */ writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); @@ -1539,8 +1590,9 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); /* Macrovision max amplitude change */ - writel_relaxed(0x8100 + mode->macv_max_amp, - priv->io_base + _REG(ENCI_MACV_MAX_AMP)); + writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE | + ENCI_MACV_MAX_AMP_VAL(mode->macv_max_amp), + priv->io_base + _REG(ENCI_MACV_MAX_AMP)); /* Video mode */ writel_relaxed(mode->video_prog_mode, @@ -1548,7 +1600,8 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, writel_relaxed(mode->video_mode, priv->io_base + _REG(ENCI_VIDEO_MODE)); - /* Advanced Video Mode : + /* + * Advanced Video Mode : * Demux shifting 0x2 * Blank line end at line17/22 * High bandwidth Luma Filter @@ -1556,7 +1609,10 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, * Bypass luma low pass filter * No macrovision on CSYNC */ - writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); + writel_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2) | + ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 | + ENCI_VIDEO_MODE_ADV_YBW_HIGH, + priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); writel(mode->sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH)); @@ -1588,16 +1644,50 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, /* UNreset Interlaced TV Encoder */ writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); - /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ - writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); + /* + * Enable Vfifo2vd and set Y_Cb_Y_Cr: + * Corresponding value: + * Y => 00 or 10 + * Cb => 01 + * Cr => 11 + * Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y + */ + writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE | + ENCI_VFIFO2VD_CTL_VD_SEL(0x4e), + priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); /* Power UP Dacs */ writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_SETTING)); /* Video Upsampling */ - writel_relaxed(0x0061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); - writel_relaxed(0x4061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); - writel_relaxed(0x5061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); + /* + * CTRL0, CTRL1 and CTRL2: + * Filter0: input data sample every 2 cloks + * Filter1: filtering and upsample enable + */ + reg = VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO | VENC_UPSAMPLE_CTRL_F1_EN | + VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN; + + /* + * Upsample CTRL0: + * Interlace High Bandwidth Luma + */ + writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA | reg, + priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); + + /* + * Upsample CTRL1: + * Interlace Pb + */ + writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PB | reg, + priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); + + /* + * Upsample CTRL2: + * Interlace R + */ + writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PR | reg, + priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); /* Select Interlace Y DACs */ writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); @@ -1611,14 +1701,16 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); /* Enable ENCI FIFO */ - writel_relaxed(0x2000, priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); + writel_relaxed(VENC_VDAC_FIFO_EN_ENCI_ENABLE, + priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); /* Select ENCI DACs 0, 1, 4, and 5 */ writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_0)); writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_1)); /* Interlace video enable */ - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); + writel_relaxed(ENCI_VIDEO_EN_ENABLE, + priv->io_base + _REG(ENCI_VIDEO_EN)); /* Configure Video Saturation / Contrast / Brightness / Hue */ writel_relaxed(mode->video_saturation, @@ -1631,7 +1723,8 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv, priv->io_base + _REG(ENCI_VIDEO_HUE)); /* Enable DAC0 Filter */ - writel_relaxed(0x1, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); + writel_relaxed(VENC_VDAC_DAC0_FILT_CTRL0_EN, + priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); writel_relaxed(0xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1)); /* 0 in Macrovision register 0 */ @@ -1652,7 +1745,8 @@ unsigned int meson_venci_get_field(struct meson_drm *priv) void meson_venc_enable_vsync(struct meson_drm *priv) { - writel_relaxed(2, priv->io_base + _REG(VENC_INTCTRL)); + writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, + priv->io_base + _REG(VENC_INTCTRL)); regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25)); } @@ -1680,7 +1774,8 @@ void meson_venc_init(struct meson_drm *priv) regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); /* Disable HDMI */ - writel_bits_relaxed(0x3, 0, + writel_bits_relaxed(VPU_HDMI_ENCI_DATA_TO_HDMI | + VPU_HDMI_ENCP_DATA_TO_HDMI, 0, priv->io_base + _REG(VPU_HDMI_SETTING)); /* Disable all encoders */ diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index 45a467f10b9b..6dc130a24070 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -171,7 +171,8 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) struct meson_drm *priv = meson_venc_cvbs->priv; /* VDAC0 source is not from ATV */ - writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); + writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0, + priv->io_base + _REG(VENC_VDAC_DACSEL0)); if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c index 9f8a450d50d5..e70cd55d56c9 100644 --- a/drivers/gpu/drm/meson/meson_viu.c +++ b/drivers/gpu/drm/meson/meson_viu.c @@ -320,9 +320,9 @@ void meson_viu_osd1_reset(struct meson_drm *priv) priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); /* Reset OSD1 */ - writel_bits_relaxed(BIT(0), BIT(0), + writel_bits_relaxed(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1, priv->io_base + _REG(VIU_SW_RESET)); - writel_bits_relaxed(BIT(0), 0, + writel_bits_relaxed(VIU_SW_RESET_OSD1, 0, priv->io_base + _REG(VIU_SW_RESET)); /* Rewrite these registers state lost in the reset */ @@ -335,15 +335,22 @@ void meson_viu_osd1_reset(struct meson_drm *priv) meson_viu_load_matrix(priv); } +static inline uint32_t meson_viu_osd_burst_length_reg(uint32_t length) +{ + uint32_t val = (((length & 0x80) % 24) / 12); + + return (((val & 0x3) << 10) | (((val & 0x4) >> 2) << 31)); +} + void meson_viu_init(struct meson_drm *priv) { uint32_t reg; /* Disable OSDs */ - writel_bits_relaxed(BIT(0) | BIT(21), 0, - priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); - writel_bits_relaxed(BIT(0) | BIT(21), 0, - priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); + writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, + priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); + writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, + priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); /* On GXL/GXM, Use the 10bit HDR conversion matrix */ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || @@ -354,19 +361,17 @@ void meson_viu_init(struct meson_drm *priv) true); /* Initialize OSD1 fifo control register */ - reg = BIT(0) | /* Urgent DDR request priority */ - (4 << 5); /* hold_fifo_lines */ + reg = VIU_OSD_DDR_PRIORITY_URGENT | + VIU_OSD_HOLD_FIFO_LINES(4) | + VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ + VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ + VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ + if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) - reg |= (1 << 10) | /* burst length 32 */ - (32 << 12) | /* fifo_depth_val: 32*8=256 */ - (2 << 22) | /* 4 words in 1 burst */ - (2 << 24) | - (1 << 31); + reg |= meson_viu_osd_burst_length_reg(32); else - reg |= (3 << 10) | /* burst length 64 */ - (32 << 12) | /* fifo_depth_val: 32*8=256 */ - (2 << 22) | /* 4 words in 1 burst */ - (2 << 24); + reg |= meson_viu_osd_burst_length_reg(64); + writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); @@ -379,12 +384,9 @@ void meson_viu_init(struct meson_drm *priv) priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); /* Disable VD1 AFBC */ - /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */ - writel_bits_relaxed(0x7 << 16, 0, - priv->io_base + _REG(VIU_MISC_CTRL0)); - /* afbc vd1 set=0 */ - writel_bits_relaxed(BIT(20), 0, - priv->io_base + _REG(VIU_MISC_CTRL0)); + /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/ + writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0, + priv->io_base + _REG(VIU_MISC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); writel_relaxed(0x00FF00C0, @@ -393,27 +395,31 @@ void meson_viu_init(struct meson_drm *priv) priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { - writel_relaxed(4 << 29 | - 1 << 27 | - 1 << 26 | /* blend_din0 input to blend0 */ - 1 << 25 | /* blend1_dout to blend2 */ - 1 << 24 | /* blend1_din3 input to blend1 */ - 1 << 20 | - 0 << 16 | - 1, - priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); - writel_relaxed(1 << 20, - priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); - writel_relaxed(1 << 20, - priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); + writel_relaxed(VIU_OSD_BLEND_REORDER(0, 1) | + VIU_OSD_BLEND_REORDER(1, 0) | + VIU_OSD_BLEND_REORDER(2, 0) | + VIU_OSD_BLEND_REORDER(3, 0) | + VIU_OSD_BLEND_DIN_EN(1) | + VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 | + VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 | + VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 | + VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) | + VIU_OSD_BLEND_HOLD_LINES(4), + priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); + + writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); + writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, + priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); writel_relaxed(0, priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); writel_relaxed(0, priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); - writel_bits_relaxed(0x3 << 2, 0x3 << 2, - priv->io_base + _REG(DOLBY_PATH_CTRL)); + + writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc), + priv->io_base + _REG(DOLBY_PATH_CTRL)); } priv->viu.osd1_enabled = false; diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c index cbe6cf46e541..1429f3be6028 100644 --- a/drivers/gpu/drm/meson/meson_vpp.c +++ b/drivers/gpu/drm/meson/meson_vpp.c @@ -56,7 +56,7 @@ static void meson_vpp_write_scaling_filter_coefs(struct meson_drm *priv, { int i; - writel_relaxed(is_horizontal ? BIT(8) : 0, + writel_relaxed(is_horizontal ? VPP_SCALE_HORIZONTAL_COEF : 0, priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX)); for (i = 0; i < 33; i++) writel_relaxed(coefs[i], @@ -81,7 +81,7 @@ static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_drm *priv, { int i; - writel_relaxed(is_horizontal ? BIT(8) : 0, + writel_relaxed(is_horizontal ? VPP_SCALE_HORIZONTAL_COEF : 0, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); for (i = 0; i < 33; i++) writel_relaxed(coefs[i], @@ -96,7 +96,8 @@ void meson_vpp_init(struct meson_drm *priv) else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu")) { writel_bits_relaxed(0xff << 16, 0xff << 16, priv->io_base + _REG(VIU_MISC_CTRL1)); - writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); + writel_relaxed(VPP_PPS_DUMMY_DATA_MODE, + priv->io_base + _REG(VPP_DOLBY_CTRL)); writel_relaxed(0x1020080, priv->io_base + _REG(VPP_DUMMY_DATA1)); } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) @@ -104,12 +105,13 @@ void meson_vpp_init(struct meson_drm *priv) /* Initialize vpu fifo control registers */ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) - writel_relaxed(0xfff << 20 | 0x1000, + writel_relaxed(VPP_OFIFO_SIZE_DEFAULT, priv->io_base + _REG(VPP_OFIFO_SIZE)); else - writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | - 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); - writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); + writel_bits_relaxed(VPP_OFIFO_SIZE_MASK, 0x77f, + priv->io_base + _REG(VPP_OFIFO_SIZE)); + writel_relaxed(VPP_POSTBLEND_HOLD_LINES(4) | VPP_PREBLEND_HOLD_LINES(4), + priv->io_base + _REG(VPP_HOLD_LINES)); if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { /* Turn off preblend */ @@ -137,10 +139,15 @@ void meson_vpp_init(struct meson_drm *priv) writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); - writel_relaxed(4 | (4 << 8) | BIT(15), + + /* Set horizontal/vertical bank length and enable video scale out */ + writel_relaxed(VPP_VSC_BANK_LENGTH(4) | VPP_HSC_BANK_LENGTH(4) | + VPP_SC_VD_EN_ENABLE, priv->io_base + _REG(VPP_SC_MISC)); - writel_relaxed(1, priv->io_base + _REG(VPP_VADJ_CTRL)); + /* Enable minus black level for vadj1 */ + writel_relaxed(VPP_MINUS_BLACK_LVL_VADJ1_ENABLE, + priv->io_base + _REG(VPP_VADJ_CTRL)); /* Write in the proper filter coefficients. */ meson_vpp_write_scaling_filter_coefs(priv, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 8cc70026c358..0c2a1252c8be 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -700,13 +700,13 @@ void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass) int msm_gem_sync_object(struct drm_gem_object *obj, struct msm_fence_context *fctx, bool exclusive) { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; struct dma_fence *fence; int i, ret; - fobj = reservation_object_get_list(obj->resv); + fobj = dma_resv_get_list(obj->resv); if (!fobj || (fobj->shared_count == 0)) { - fence = reservation_object_get_excl(obj->resv); + fence = dma_resv_get_excl(obj->resv); /* don't need to wait on our own fences, since ring is fifo */ if (fence && (fence->context != fctx->context)) { ret = dma_fence_wait(fence, true); @@ -720,7 +720,7 @@ int msm_gem_sync_object(struct drm_gem_object *obj, for (i = 0; i < fobj->shared_count; i++) { fence = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(obj->resv)); + dma_resv_held(obj->resv)); if (fence->context != fctx->context) { ret = dma_fence_wait(fence, true); if (ret) @@ -738,9 +738,9 @@ void msm_gem_move_to_active(struct drm_gem_object *obj, WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED); msm_obj->gpu = gpu; if (exclusive) - reservation_object_add_excl_fence(obj->resv, fence); + dma_resv_add_excl_fence(obj->resv, fence); else - reservation_object_add_shared_fence(obj->resv, fence); + dma_resv_add_shared_fence(obj->resv, fence); list_del_init(&msm_obj->mm_list); list_add_tail(&msm_obj->mm_list, &gpu->active_list); } @@ -765,7 +765,7 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) op & MSM_PREP_NOSYNC ? 0 : timeout_to_jiffies(timeout); long ret; - ret = reservation_object_wait_timeout_rcu(obj->resv, write, + ret = dma_resv_wait_timeout_rcu(obj->resv, write, true, remain); if (ret == 0) return remain == 0 ? -EBUSY : -ETIMEDOUT; @@ -797,8 +797,8 @@ static void describe_fence(struct dma_fence *fence, const char *type, void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - struct reservation_object *robj = obj->resv; - struct reservation_object_list *fobj; + struct dma_resv *robj = obj->resv; + struct dma_resv_list *fobj; struct dma_fence *fence; struct msm_gem_vma *vma; uint64_t off = drm_vma_node_start(&obj->vma_node); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 8cfcf8f09e3e..9e0953c2b7ce 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -8,7 +8,7 @@ #define __MSM_GEM_H__ #include <linux/kref.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "msm_drv.h" /* Additional internal-use only BO flags: */ diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 348f8c2be806..2e1556b7af26 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -225,7 +225,7 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) * strange place to call it. OTOH this is a * convenient can-fail point to hook it in. */ - ret = reservation_object_reserve_shared(msm_obj->base.resv, + ret = dma_resv_reserve_shared(msm_obj->base.resv, 1); if (ret) return ret; diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 878ef6822812..e8506335cd15 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -17,7 +17,7 @@ #include <linux/of_graph.h> #include <linux/of_reserved_mem.h> #include <linux/pm_runtime.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <linux/spinlock.h> #include <drm/drm_atomic.h> diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c index 231d016c6f47..be36f4d6cc96 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_out.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c @@ -30,7 +30,7 @@ static int mxsfb_panel_get_modes(struct drm_connector *connector) drm_connector_to_mxsfb_drm_private(connector); if (mxsfb->panel) - return mxsfb->panel->funcs->get_modes(mxsfb->panel); + return drm_panel_get_modes(mxsfb->panel); return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 89f8e76a2d7d..027a01b97d1c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -457,7 +457,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) asyw->image.handle[0] = ctxdma->object.handle; } - asyw->state.fence = reservation_object_get_excl_rcu(fb->nvbo->bo.base.resv); + asyw->state.fence = dma_resv_get_excl_rcu(fb->nvbo->bo.base.resv); asyw->image.offset[0] = fb->nvbo->bo.offset; if (wndw->func->prepare) { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 99e391be9370..e0b1bbee936f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -188,7 +188,7 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, int nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align, uint32_t flags, uint32_t tile_mode, uint32_t tile_flags, - struct sg_table *sg, struct reservation_object *robj, + struct sg_table *sg, struct dma_resv *robj, struct nouveau_bo **pnvbo) { struct nouveau_drm *drm = cli->drm; @@ -1324,7 +1324,7 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo, { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct drm_device *dev = drm->dev; - struct dma_fence *fence = reservation_object_get_excl(bo->base.resv); + struct dma_fence *fence = dma_resv_get_excl(bo->base.resv); nv10_bo_put_tile_region(dev, *old_tile, fence); *old_tile = new_tile; @@ -1655,12 +1655,12 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) void nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive) { - struct reservation_object *resv = nvbo->bo.base.resv; + struct dma_resv *resv = nvbo->bo.base.resv; if (exclusive) - reservation_object_add_excl_fence(resv, &fence->base); + dma_resv_add_excl_fence(resv, &fence->base); else if (fence) - reservation_object_add_shared_fence(resv, &fence->base); + dma_resv_add_shared_fence(resv, &fence->base); } struct ttm_bo_driver nouveau_bo_driver = { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index d675efe8e7f9..3ae84834bd5c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -73,7 +73,7 @@ extern struct ttm_bo_driver nouveau_bo_driver; void nouveau_bo_move_init(struct nouveau_drm *); int nouveau_bo_new(struct nouveau_cli *, u64 size, int align, u32 flags, u32 tile_mode, u32 tile_flags, struct sg_table *sg, - struct reservation_object *robj, + struct dma_resv *robj, struct nouveau_bo **); int nouveau_bo_pin(struct nouveau_bo *, u32 flags, bool contig); int nouveau_bo_unpin(struct nouveau_bo *); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index e5f249ab216a..8df390078c85 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -335,20 +335,20 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e { struct nouveau_fence_chan *fctx = chan->fence; struct dma_fence *fence; - struct reservation_object *resv = nvbo->bo.base.resv; - struct reservation_object_list *fobj; + struct dma_resv *resv = nvbo->bo.base.resv; + struct dma_resv_list *fobj; struct nouveau_fence *f; int ret = 0, i; if (!exclusive) { - ret = reservation_object_reserve_shared(resv, 1); + ret = dma_resv_reserve_shared(resv, 1); if (ret) return ret; } - fobj = reservation_object_get_list(resv); - fence = reservation_object_get_excl(resv); + fobj = dma_resv_get_list(resv); + fence = dma_resv_get_excl(resv); if (fence && (!exclusive || !fobj || !fobj->shared_count)) { struct nouveau_channel *prev = NULL; @@ -377,7 +377,7 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e bool must_wait = true; fence = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(resv)); + dma_resv_held(resv)); f = nouveau_local_fence(fence, chan->drm); if (f) { diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index c7368aa0bdec..c77302f969e8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -887,7 +887,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, return -ENOENT; nvbo = nouveau_gem_object(gem); - lret = reservation_object_wait_timeout_rcu(nvbo->bo.base.resv, write, true, + lret = dma_resv_wait_timeout_rcu(nvbo->bo.base.resv, write, true, no_wait ? 0 : 30 * HZ); if (!lret) ret = -EBUSY; diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c index e86ad7ae622b..7262ced9688a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -62,16 +62,16 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev, { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_bo *nvbo; - struct reservation_object *robj = attach->dmabuf->resv; + struct dma_resv *robj = attach->dmabuf->resv; u32 flags = 0; int ret; flags = TTM_PL_FLAG_TT; - reservation_object_lock(robj, NULL); + dma_resv_lock(robj, NULL); ret = nouveau_bo_new(&drm->client, attach->dmabuf->size, 0, flags, 0, 0, sg, robj, &nvbo); - reservation_object_unlock(robj); + dma_resv_unlock(robj); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig index c2566da32ac4..240dda102845 100644 --- a/drivers/gpu/drm/omapdrm/displays/Kconfig +++ b/drivers/gpu/drm/omapdrm/displays/Kconfig @@ -29,42 +29,4 @@ config DRM_OMAP_PANEL_DSI_CM help Driver for generic DSI command mode panels. -config DRM_OMAP_PANEL_SONY_ACX565AKM - tristate "ACX565AKM Panel" - depends on SPI && BACKLIGHT_CLASS_DEVICE - help - This is the LCD panel used on Nokia N900 - -config DRM_OMAP_PANEL_LGPHILIPS_LB035Q02 - tristate "LG.Philips LB035Q02 LCD Panel" - depends on SPI - help - LCD Panel used on the Gumstix Overo Palo35 - -config DRM_OMAP_PANEL_SHARP_LS037V7DW01 - tristate "Sharp LS037V7DW01 LCD Panel" - depends on BACKLIGHT_CLASS_DEVICE - help - LCD Panel used in TI's SDP3430 and EVM boards - -config DRM_OMAP_PANEL_TPO_TD028TTEC1 - tristate "TPO TD028TTEC1 LCD Panel" - depends on SPI - help - LCD panel used in Openmoko. - -config DRM_OMAP_PANEL_TPO_TD043MTEA1 - tristate "TPO TD043MTEA1 LCD Panel" - depends on SPI - help - LCD Panel used in OMAP3 Pandora - -config DRM_OMAP_PANEL_NEC_NL8048HL11 - tristate "NEC NL8048HL11 Panel" - depends on SPI - depends on BACKLIGHT_CLASS_DEVICE - help - This NEC NL8048HL11 panel is TFT LCD used in the - Zoom2/3/3630 sdp boards. - endmenu diff --git a/drivers/gpu/drm/omapdrm/displays/Makefile b/drivers/gpu/drm/omapdrm/displays/Makefile index 1db34d4fed64..cb76859dc574 100644 --- a/drivers/gpu/drm/omapdrm/displays/Makefile +++ b/drivers/gpu/drm/omapdrm/displays/Makefile @@ -4,9 +4,3 @@ obj-$(CONFIG_DRM_OMAP_ENCODER_TPD12S015) += encoder-tpd12s015.o obj-$(CONFIG_DRM_OMAP_CONNECTOR_HDMI) += connector-hdmi.o obj-$(CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV) += connector-analog-tv.o obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o -obj-$(CONFIG_DRM_OMAP_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o -obj-$(CONFIG_DRM_OMAP_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o -obj-$(CONFIG_DRM_OMAP_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o -obj-$(CONFIG_DRM_OMAP_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o -obj-$(CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o -obj-$(CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c deleted file mode 100644 index 1fd0d84e6e38..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ /dev/null @@ -1,251 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * LG.Philips LB035Q02 LCD Panel driver - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * Based on a driver by: Steve Sakoman <steve@sakoman.com> - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/spi/spi.h> -#include <linux/mutex.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h> - -#include "../dss/omapdss.h" - -static const struct videomode lb035q02_vm = { - .hactive = 320, - .vactive = 240, - - .pixelclock = 6500000, - - .hsync_len = 2, - .hfront_porch = 20, - .hback_porch = 68, - - .vsync_len = 2, - .vfront_porch = 4, - .vback_porch = 18, - - .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, -}; - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct spi_device *spi; - - struct videomode vm; - - struct gpio_desc *enable_gpio; -}; - -#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) - -static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val) -{ - struct spi_message msg; - struct spi_transfer index_xfer = { - .len = 3, - .cs_change = 1, - }; - struct spi_transfer value_xfer = { - .len = 3, - }; - u8 buffer[16]; - - spi_message_init(&msg); - - /* register index */ - buffer[0] = 0x70; - buffer[1] = 0x00; - buffer[2] = reg & 0x7f; - index_xfer.tx_buf = buffer; - spi_message_add_tail(&index_xfer, &msg); - - /* register value */ - buffer[4] = 0x72; - buffer[5] = val >> 8; - buffer[6] = val; - value_xfer.tx_buf = buffer + 4; - spi_message_add_tail(&value_xfer, &msg); - - return spi_sync(spi, &msg); -} - -static void init_lb035q02_panel(struct spi_device *spi) -{ - /* Init sequence from page 28 of the lb035q02 spec */ - lb035q02_write_reg(spi, 0x01, 0x6300); - lb035q02_write_reg(spi, 0x02, 0x0200); - lb035q02_write_reg(spi, 0x03, 0x0177); - lb035q02_write_reg(spi, 0x04, 0x04c7); - lb035q02_write_reg(spi, 0x05, 0xffc0); - lb035q02_write_reg(spi, 0x06, 0xe806); - lb035q02_write_reg(spi, 0x0a, 0x4008); - lb035q02_write_reg(spi, 0x0b, 0x0000); - lb035q02_write_reg(spi, 0x0d, 0x0030); - lb035q02_write_reg(spi, 0x0e, 0x2800); - lb035q02_write_reg(spi, 0x0f, 0x0000); - lb035q02_write_reg(spi, 0x16, 0x9f80); - lb035q02_write_reg(spi, 0x17, 0x0a0f); - lb035q02_write_reg(spi, 0x1e, 0x00c1); - lb035q02_write_reg(spi, 0x30, 0x0300); - lb035q02_write_reg(spi, 0x31, 0x0007); - lb035q02_write_reg(spi, 0x32, 0x0000); - lb035q02_write_reg(spi, 0x33, 0x0000); - lb035q02_write_reg(spi, 0x34, 0x0707); - lb035q02_write_reg(spi, 0x35, 0x0004); - lb035q02_write_reg(spi, 0x36, 0x0302); - lb035q02_write_reg(spi, 0x37, 0x0202); - lb035q02_write_reg(spi, 0x3a, 0x0a0d); - lb035q02_write_reg(spi, 0x3b, 0x0806); -} - -static int lb035q02_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - struct panel_drv_data *ddata = to_panel_data(dst); - - init_lb035q02_panel(ddata->spi); - - return 0; -} - -static void lb035q02_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static void lb035q02_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (ddata->enable_gpio) - gpiod_set_value_cansleep(ddata->enable_gpio, 1); -} - -static void lb035q02_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (ddata->enable_gpio) - gpiod_set_value_cansleep(ddata->enable_gpio, 0); -} - -static int lb035q02_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return omapdss_display_get_modes(connector, &ddata->vm); -} - -static const struct omap_dss_device_ops lb035q02_ops = { - .connect = lb035q02_connect, - .disconnect = lb035q02_disconnect, - - .enable = lb035q02_enable, - .disable = lb035q02_disable, - - .get_modes = lb035q02_get_modes, -}; - -static int lb035q02_probe_of(struct spi_device *spi) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct gpio_desc *gpio; - - gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - dev_err(&spi->dev, "failed to parse enable gpio\n"); - return PTR_ERR(gpio); - } - - ddata->enable_gpio = gpio; - - return 0; -} - -static int lb035q02_panel_spi_probe(struct spi_device *spi) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - int r; - - ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); - if (ddata == NULL) - return -ENOMEM; - - dev_set_drvdata(&spi->dev, ddata); - - ddata->spi = spi; - - r = lb035q02_probe_of(spi); - if (r) - return r; - - ddata->vm = lb035q02_vm; - - dssdev = &ddata->dssdev; - dssdev->dev = &spi->dev; - dssdev->ops = &lb035q02_ops; - dssdev->type = OMAP_DISPLAY_TYPE_DPI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - - /* - * Note: According to the panel documentation: - * DE is active LOW - * DATA needs to be driven on the FALLING edge - */ - dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE - | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int lb035q02_panel_spi_remove(struct spi_device *spi) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - omapdss_device_unregister(dssdev); - - lb035q02_disable(dssdev); - - return 0; -} - -static const struct of_device_id lb035q02_of_match[] = { - { .compatible = "omapdss,lgphilips,lb035q02", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, lb035q02_of_match); - -static struct spi_driver lb035q02_spi_driver = { - .probe = lb035q02_panel_spi_probe, - .remove = lb035q02_panel_spi_remove, - .driver = { - .name = "panel_lgphilips_lb035q02", - .of_match_table = lb035q02_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_spi_driver(lb035q02_spi_driver); - -MODULE_ALIAS("spi:lgphilips,lb035q02"); -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); -MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c deleted file mode 100644 index eba5bd1d702f..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c +++ /dev/null @@ -1,271 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * NEC NL8048HL11 Panel driver - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Erik Gilling <konkers@android.com> - * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/delay.h> -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/spi/spi.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct videomode vm; - - struct gpio_desc *res_gpio; - - struct spi_device *spi; -}; - -#define LCD_XRES 800 -#define LCD_YRES 480 -/* - * NEC PIX Clock Ratings - * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz - */ -#define LCD_PIXEL_CLOCK 23800000 - -static const struct { - unsigned char addr; - unsigned char dat; -} nec_8048_init_seq[] = { - { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 }, - { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 }, - { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 }, - { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F }, - { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F }, - { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F }, - { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F }, - { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, - { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 }, - { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C }, - { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, - { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 }, - { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 }, - { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 }, - { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC }, - { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, - { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 }, - { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 }, -}; - -static const struct videomode nec_8048_panel_vm = { - .hactive = LCD_XRES, - .vactive = LCD_YRES, - .pixelclock = LCD_PIXEL_CLOCK, - .hfront_porch = 6, - .hsync_len = 1, - .hback_porch = 4, - .vfront_porch = 3, - .vsync_len = 1, - .vback_porch = 4, - - .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, -}; - -#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) - -static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr, - unsigned char reg_data) -{ - int ret = 0; - unsigned int cmd = 0, data = 0; - - cmd = 0x0000 | reg_addr; /* register address write */ - data = 0x0100 | reg_data; /* register data write */ - data = (cmd << 16) | data; - - ret = spi_write(spi, (unsigned char *)&data, 4); - if (ret) - pr_err("error in spi_write %x\n", data); - - return ret; -} - -static int init_nec_8048_wvga_lcd(struct spi_device *spi) -{ - unsigned int i; - /* Initialization Sequence */ - /* nec_8048_spi_send(spi, REG, VAL) */ - for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++) - nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, - nec_8048_init_seq[i].dat); - udelay(20); - nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, - nec_8048_init_seq[i].dat); - return 0; -} - -static int nec_8048_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void nec_8048_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static void nec_8048_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - gpiod_set_value_cansleep(ddata->res_gpio, 1); -} - -static void nec_8048_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - gpiod_set_value_cansleep(ddata->res_gpio, 0); -} - -static int nec_8048_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return omapdss_display_get_modes(connector, &ddata->vm); -} - -static const struct omap_dss_device_ops nec_8048_ops = { - .connect = nec_8048_connect, - .disconnect = nec_8048_disconnect, - - .enable = nec_8048_enable, - .disable = nec_8048_disable, - - .get_modes = nec_8048_get_modes, -}; - -static int nec_8048_probe(struct spi_device *spi) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - struct gpio_desc *gpio; - int r; - - dev_dbg(&spi->dev, "%s\n", __func__); - - spi->mode = SPI_MODE_0; - spi->bits_per_word = 32; - - r = spi_setup(spi); - if (r < 0) { - dev_err(&spi->dev, "spi_setup failed: %d\n", r); - return r; - } - - init_nec_8048_wvga_lcd(spi); - - ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); - if (ddata == NULL) - return -ENOMEM; - - dev_set_drvdata(&spi->dev, ddata); - - ddata->spi = spi; - - gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - dev_err(&spi->dev, "failed to get reset gpio\n"); - return PTR_ERR(gpio); - } - - ddata->res_gpio = gpio; - - ddata->vm = nec_8048_panel_vm; - - dssdev = &ddata->dssdev; - dssdev->dev = &spi->dev; - dssdev->ops = &nec_8048_ops; - dssdev->type = OMAP_DISPLAY_TYPE_DPI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE - | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int nec_8048_remove(struct spi_device *spi) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - dev_dbg(&ddata->spi->dev, "%s\n", __func__); - - omapdss_device_unregister(dssdev); - - nec_8048_disable(dssdev); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int nec_8048_suspend(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - - nec_8048_spi_send(spi, 2, 0x01); - mdelay(40); - - return 0; -} - -static int nec_8048_resume(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - - /* reinitialize the panel */ - spi_setup(spi); - nec_8048_spi_send(spi, 2, 0x00); - init_nec_8048_wvga_lcd(spi); - - return 0; -} -static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend, - nec_8048_resume); -#define NEC_8048_PM_OPS (&nec_8048_pm_ops) -#else -#define NEC_8048_PM_OPS NULL -#endif - -static const struct of_device_id nec_8048_of_match[] = { - { .compatible = "omapdss,nec,nl8048hl11", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, nec_8048_of_match); - -static struct spi_driver nec_8048_driver = { - .driver = { - .name = "panel-nec-nl8048hl11", - .pm = NEC_8048_PM_OPS, - .of_match_table = nec_8048_of_match, - .suppress_bind_attrs = true, - }, - .probe = nec_8048_probe, - .remove = nec_8048_remove, -}; - -module_spi_driver(nec_8048_driver); - -MODULE_ALIAS("spi:nec,nl8048hl11"); -MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); -MODULE_DESCRIPTION("NEC-NL8048HL11 Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c deleted file mode 100644 index 3ab50fd1f3f2..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ /dev/null @@ -1,262 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * LCD panel driver for Sharp LS037V7DW01 - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/delay.h> -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/regulator/consumer.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - struct regulator *vcc; - - struct videomode vm; - - struct gpio_desc *resb_gpio; /* low = reset active min 20 us */ - struct gpio_desc *ini_gpio; /* high = power on */ - struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */ - struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */ - struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */ -}; - -static const struct videomode sharp_ls_vm = { - .hactive = 480, - .vactive = 640, - - .pixelclock = 19200000, - - .hsync_len = 2, - .hfront_porch = 1, - .hback_porch = 28, - - .vsync_len = 1, - .vfront_porch = 1, - .vback_porch = 1, - - .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, -}; - -#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) - -static int sharp_ls_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void sharp_ls_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static void sharp_ls_pre_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - int r; - - if (ddata->vcc) { - r = regulator_enable(ddata->vcc); - if (r) - dev_err(dssdev->dev, "%s: failed to enable regulator\n", - __func__); - } -} - -static void sharp_ls_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - /* wait couple of vsyncs until enabling the LCD */ - msleep(50); - - if (ddata->resb_gpio) - gpiod_set_value_cansleep(ddata->resb_gpio, 1); - - if (ddata->ini_gpio) - gpiod_set_value_cansleep(ddata->ini_gpio, 1); -} - -static void sharp_ls_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (ddata->ini_gpio) - gpiod_set_value_cansleep(ddata->ini_gpio, 0); - - if (ddata->resb_gpio) - gpiod_set_value_cansleep(ddata->resb_gpio, 0); - - /* wait at least 5 vsyncs after disabling the LCD */ - msleep(100); -} - -static void sharp_ls_post_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (ddata->vcc) - regulator_disable(ddata->vcc); -} - -static int sharp_ls_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return omapdss_display_get_modes(connector, &ddata->vm); -} - -static const struct omap_dss_device_ops sharp_ls_ops = { - .connect = sharp_ls_connect, - .disconnect = sharp_ls_disconnect, - - .pre_enable = sharp_ls_pre_enable, - .enable = sharp_ls_enable, - .disable = sharp_ls_disable, - .post_disable = sharp_ls_post_disable, - - .get_modes = sharp_ls_get_modes, -}; - -static int sharp_ls_get_gpio_of(struct device *dev, int index, int val, - const char *desc, struct gpio_desc **gpiod) -{ - struct gpio_desc *gd; - - *gpiod = NULL; - - gd = devm_gpiod_get_index(dev, desc, index, GPIOD_OUT_LOW); - if (IS_ERR(gd)) - return PTR_ERR(gd); - - *gpiod = gd; - return 0; -} - -static int sharp_ls_probe_of(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - int r; - - ddata->vcc = devm_regulator_get(&pdev->dev, "envdd"); - if (IS_ERR(ddata->vcc)) { - dev_err(&pdev->dev, "failed to get regulator\n"); - return PTR_ERR(ddata->vcc); - } - - /* lcd INI */ - r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio); - if (r) - return r; - - /* lcd RESB */ - r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio); - if (r) - return r; - - /* lcd MO */ - r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio); - if (r) - return r; - - /* lcd LR */ - r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio); - if (r) - return r; - - /* lcd UD */ - r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio); - if (r) - return r; - - return 0; -} - -static int sharp_ls_probe(struct platform_device *pdev) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - int r; - - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (ddata == NULL) - return -ENOMEM; - - platform_set_drvdata(pdev, ddata); - - r = sharp_ls_probe_of(pdev); - if (r) - return r; - - ddata->vm = sharp_ls_vm; - - dssdev = &ddata->dssdev; - dssdev->dev = &pdev->dev; - dssdev->ops = &sharp_ls_ops; - dssdev->type = OMAP_DISPLAY_TYPE_DPI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - - /* - * Note: According to the panel documentation: - * DATA needs to be driven on the FALLING edge - */ - dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE - | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int __exit sharp_ls_remove(struct platform_device *pdev) -{ - struct panel_drv_data *ddata = platform_get_drvdata(pdev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - omapdss_device_unregister(dssdev); - - if (omapdss_device_is_enabled(dssdev)) { - sharp_ls_disable(dssdev); - sharp_ls_post_disable(dssdev); - } - - return 0; -} - -static const struct of_device_id sharp_ls_of_match[] = { - { .compatible = "omapdss,sharp,ls037v7dw01", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, sharp_ls_of_match); - -static struct platform_driver sharp_ls_driver = { - .probe = sharp_ls_probe, - .remove = __exit_p(sharp_ls_remove), - .driver = { - .name = "panel-sharp-ls037v7dw01", - .of_match_table = sharp_ls_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_platform_driver(sharp_ls_driver); - -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); -MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c deleted file mode 100644 index 588a1a6bbcc3..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ /dev/null @@ -1,755 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Sony ACX565AKM LCD Panel driver - * - * Copyright (C) 2010 Nokia Corporation - * - * Original Driver Author: Imre Deak <imre.deak@nokia.com> - * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@ti.com> - * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> - */ - -#include <linux/backlight.h> -#include <linux/delay.h> -#include <linux/gpio/consumer.h> -#include <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/sched.h> -#include <linux/spi/spi.h> - -#include "../dss/omapdss.h" - -#define MIPID_CMD_READ_DISP_ID 0x04 -#define MIPID_CMD_READ_RED 0x06 -#define MIPID_CMD_READ_GREEN 0x07 -#define MIPID_CMD_READ_BLUE 0x08 -#define MIPID_CMD_READ_DISP_STATUS 0x09 -#define MIPID_CMD_RDDSDR 0x0F -#define MIPID_CMD_SLEEP_IN 0x10 -#define MIPID_CMD_SLEEP_OUT 0x11 -#define MIPID_CMD_DISP_OFF 0x28 -#define MIPID_CMD_DISP_ON 0x29 -#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51 -#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52 -#define MIPID_CMD_WRITE_CTRL_DISP 0x53 - -#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5) -#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4) -#define CTRL_DISP_BACKLIGHT_ON (1 << 2) -#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1) - -#define MIPID_CMD_READ_CTRL_DISP 0x54 -#define MIPID_CMD_WRITE_CABC 0x55 -#define MIPID_CMD_READ_CABC 0x56 - -#define MIPID_VER_LPH8923 3 -#define MIPID_VER_LS041Y3 4 -#define MIPID_VER_L4F00311 8 -#define MIPID_VER_ACX565AKM 9 - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct gpio_desc *reset_gpio; - - struct videomode vm; - - char *name; - int enabled; - int model; - int revision; - u8 display_id[3]; - unsigned has_bc:1; - unsigned has_cabc:1; - unsigned cabc_mode; - unsigned long hw_guard_end; /* next value of jiffies - when we can issue the - next sleep in/out command */ - unsigned long hw_guard_wait; /* max guard time in jiffies */ - - struct spi_device *spi; - struct mutex mutex; - - struct backlight_device *bl_dev; -}; - -static const struct videomode acx565akm_panel_vm = { - .hactive = 800, - .vactive = 480, - .pixelclock = 24000000, - .hfront_porch = 28, - .hsync_len = 4, - .hback_porch = 24, - .vfront_porch = 3, - .vsync_len = 3, - .vback_porch = 4, - - .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, -}; - -#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) - -static void acx565akm_transfer(struct panel_drv_data *ddata, int cmd, - const u8 *wbuf, int wlen, u8 *rbuf, int rlen) -{ - struct spi_message m; - struct spi_transfer *x, xfer[5]; - int r; - - BUG_ON(ddata->spi == NULL); - - spi_message_init(&m); - - memset(xfer, 0, sizeof(xfer)); - x = &xfer[0]; - - cmd &= 0xff; - x->tx_buf = &cmd; - x->bits_per_word = 9; - x->len = 2; - - if (rlen > 1 && wlen == 0) { - /* - * Between the command and the response data there is a - * dummy clock cycle. Add an extra bit after the command - * word to account for this. - */ - x->bits_per_word = 10; - cmd <<= 1; - } - spi_message_add_tail(x, &m); - - if (wlen) { - x++; - x->tx_buf = wbuf; - x->len = wlen; - x->bits_per_word = 9; - spi_message_add_tail(x, &m); - } - - if (rlen) { - x++; - x->rx_buf = rbuf; - x->len = rlen; - spi_message_add_tail(x, &m); - } - - r = spi_sync(ddata->spi, &m); - if (r < 0) - dev_dbg(&ddata->spi->dev, "spi_sync %d\n", r); -} - -static inline void acx565akm_cmd(struct panel_drv_data *ddata, int cmd) -{ - acx565akm_transfer(ddata, cmd, NULL, 0, NULL, 0); -} - -static inline void acx565akm_write(struct panel_drv_data *ddata, - int reg, const u8 *buf, int len) -{ - acx565akm_transfer(ddata, reg, buf, len, NULL, 0); -} - -static inline void acx565akm_read(struct panel_drv_data *ddata, - int reg, u8 *buf, int len) -{ - acx565akm_transfer(ddata, reg, NULL, 0, buf, len); -} - -static void hw_guard_start(struct panel_drv_data *ddata, int guard_msec) -{ - ddata->hw_guard_wait = msecs_to_jiffies(guard_msec); - ddata->hw_guard_end = jiffies + ddata->hw_guard_wait; -} - -static void hw_guard_wait(struct panel_drv_data *ddata) -{ - unsigned long wait = ddata->hw_guard_end - jiffies; - - if ((long)wait > 0 && wait <= ddata->hw_guard_wait) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(wait); - } -} - -static void set_sleep_mode(struct panel_drv_data *ddata, int on) -{ - int cmd; - - if (on) - cmd = MIPID_CMD_SLEEP_IN; - else - cmd = MIPID_CMD_SLEEP_OUT; - /* - * We have to keep 120msec between sleep in/out commands. - * (8.2.15, 8.2.16). - */ - hw_guard_wait(ddata); - acx565akm_cmd(ddata, cmd); - hw_guard_start(ddata, 120); -} - -static void set_display_state(struct panel_drv_data *ddata, int enabled) -{ - int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF; - - acx565akm_cmd(ddata, cmd); -} - -static int panel_enabled(struct panel_drv_data *ddata) -{ - __be32 v; - u32 disp_status; - int enabled; - - acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, (u8 *)&v, 4); - disp_status = __be32_to_cpu(v); - enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); - dev_dbg(&ddata->spi->dev, - "LCD panel %senabled by bootloader (status 0x%04x)\n", - enabled ? "" : "not ", disp_status); - return enabled; -} - -static int panel_detect(struct panel_drv_data *ddata) -{ - acx565akm_read(ddata, MIPID_CMD_READ_DISP_ID, ddata->display_id, 3); - dev_dbg(&ddata->spi->dev, "MIPI display ID: %02x%02x%02x\n", - ddata->display_id[0], - ddata->display_id[1], - ddata->display_id[2]); - - switch (ddata->display_id[0]) { - case 0x10: - ddata->model = MIPID_VER_ACX565AKM; - ddata->name = "acx565akm"; - ddata->has_bc = 1; - ddata->has_cabc = 1; - break; - case 0x29: - ddata->model = MIPID_VER_L4F00311; - ddata->name = "l4f00311"; - break; - case 0x45: - ddata->model = MIPID_VER_LPH8923; - ddata->name = "lph8923"; - break; - case 0x83: - ddata->model = MIPID_VER_LS041Y3; - ddata->name = "ls041y3"; - break; - default: - ddata->name = "unknown"; - dev_err(&ddata->spi->dev, "invalid display ID\n"); - return -ENODEV; - } - - ddata->revision = ddata->display_id[1]; - - dev_info(&ddata->spi->dev, "omapfb: %s rev %02x LCD detected\n", - ddata->name, ddata->revision); - - return 0; -} - -/*----------------------Backlight Control-------------------------*/ - -static void enable_backlight_ctrl(struct panel_drv_data *ddata, int enable) -{ - u16 ctrl; - - acx565akm_read(ddata, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1); - if (enable) { - ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON | - CTRL_DISP_BACKLIGHT_ON; - } else { - ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON | - CTRL_DISP_BACKLIGHT_ON); - } - - ctrl |= 1 << 8; - acx565akm_write(ddata, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2); -} - -static void set_cabc_mode(struct panel_drv_data *ddata, unsigned int mode) -{ - u16 cabc_ctrl; - - ddata->cabc_mode = mode; - if (!ddata->enabled) - return; - cabc_ctrl = 0; - acx565akm_read(ddata, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1); - cabc_ctrl &= ~3; - cabc_ctrl |= (1 << 8) | (mode & 3); - acx565akm_write(ddata, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); -} - -static unsigned int get_cabc_mode(struct panel_drv_data *ddata) -{ - return ddata->cabc_mode; -} - -static unsigned int get_hw_cabc_mode(struct panel_drv_data *ddata) -{ - u8 cabc_ctrl; - - acx565akm_read(ddata, MIPID_CMD_READ_CABC, &cabc_ctrl, 1); - return cabc_ctrl & 3; -} - -static void acx565akm_set_brightness(struct panel_drv_data *ddata, int level) -{ - int bv; - - bv = level | (1 << 8); - acx565akm_write(ddata, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2); - - if (level) - enable_backlight_ctrl(ddata, 1); - else - enable_backlight_ctrl(ddata, 0); -} - -static int acx565akm_get_actual_brightness(struct panel_drv_data *ddata) -{ - u8 bv; - - acx565akm_read(ddata, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1); - - return bv; -} - - -static int acx565akm_bl_update_status(struct backlight_device *dev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); - int level; - - dev_dbg(&ddata->spi->dev, "%s\n", __func__); - - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) - level = dev->props.brightness; - else - level = 0; - - if (ddata->has_bc) - acx565akm_set_brightness(ddata, level); - else - return -ENODEV; - - return 0; -} - -static int acx565akm_bl_get_intensity(struct backlight_device *dev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); - - dev_dbg(&dev->dev, "%s\n", __func__); - - if (!ddata->has_bc) - return -ENODEV; - - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) { - if (ddata->has_bc) - return acx565akm_get_actual_brightness(ddata); - else - return dev->props.brightness; - } - - return 0; -} - -static int acx565akm_bl_update_status_locked(struct backlight_device *dev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); - int r; - - mutex_lock(&ddata->mutex); - r = acx565akm_bl_update_status(dev); - mutex_unlock(&ddata->mutex); - - return r; -} - -static int acx565akm_bl_get_intensity_locked(struct backlight_device *dev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev); - int r; - - mutex_lock(&ddata->mutex); - r = acx565akm_bl_get_intensity(dev); - mutex_unlock(&ddata->mutex); - - return r; -} - -static const struct backlight_ops acx565akm_bl_ops = { - .get_brightness = acx565akm_bl_get_intensity_locked, - .update_status = acx565akm_bl_update_status_locked, -}; - -/*--------------------Auto Brightness control via Sysfs---------------------*/ - -static const char * const cabc_modes[] = { - "off", /* always used when CABC is not supported */ - "ui", - "still-image", - "moving-image", -}; - -static ssize_t show_cabc_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - const char *mode_str; - int mode; - int len; - - if (!ddata->has_cabc) - mode = 0; - else - mode = get_cabc_mode(ddata); - mode_str = "unknown"; - if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes)) - mode_str = cabc_modes[mode]; - len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str); - - return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1; -} - -static ssize_t store_cabc_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - int i; - - for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) { - const char *mode_str = cabc_modes[i]; - int cmp_len = strlen(mode_str); - - if (count > 0 && buf[count - 1] == '\n') - count--; - if (count != cmp_len) - continue; - - if (strncmp(buf, mode_str, cmp_len) == 0) - break; - } - - if (i == ARRAY_SIZE(cabc_modes)) - return -EINVAL; - - if (!ddata->has_cabc && i != 0) - return -EINVAL; - - mutex_lock(&ddata->mutex); - set_cabc_mode(ddata, i); - mutex_unlock(&ddata->mutex); - - return count; -} - -static ssize_t show_cabc_available_modes(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - int len; - int i; - - if (!ddata->has_cabc) - return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]); - - for (i = 0, len = 0; - len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++) - len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s", - i ? " " : "", cabc_modes[i], - i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : ""); - - return len < PAGE_SIZE ? len : PAGE_SIZE - 1; -} - -static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR, - show_cabc_mode, store_cabc_mode); -static DEVICE_ATTR(cabc_available_modes, S_IRUGO, - show_cabc_available_modes, NULL); - -static struct attribute *bldev_attrs[] = { - &dev_attr_cabc_mode.attr, - &dev_attr_cabc_available_modes.attr, - NULL, -}; - -static const struct attribute_group bldev_attr_group = { - .attrs = bldev_attrs, -}; - -static int acx565akm_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void acx565akm_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - dev_dbg(&ddata->spi->dev, "%s\n", __func__); - - /*FIXME tweak me */ - msleep(50); - - if (ddata->reset_gpio) - gpiod_set_value(ddata->reset_gpio, 1); - - if (ddata->enabled) { - dev_dbg(&ddata->spi->dev, "panel already enabled\n"); - return 0; - } - - /* - * We have to meet all the following delay requirements: - * 1. tRW: reset pulse width 10usec (7.12.1) - * 2. tRT: reset cancel time 5msec (7.12.1) - * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst - * case (7.6.2) - * 4. 120msec before the sleep out command (7.12.1) - */ - msleep(120); - - set_sleep_mode(ddata, 0); - ddata->enabled = 1; - - /* 5msec between sleep out and the next command. (8.2.16) */ - usleep_range(5000, 10000); - set_display_state(ddata, 1); - set_cabc_mode(ddata, ddata->cabc_mode); - - return acx565akm_bl_update_status(ddata->bl_dev); -} - -static void acx565akm_panel_power_off(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - dev_dbg(dssdev->dev, "%s\n", __func__); - - if (!ddata->enabled) - return; - - set_display_state(ddata, 0); - set_sleep_mode(ddata, 1); - ddata->enabled = 0; - /* - * We have to provide PCLK,HS,VS signals for 2 frames (worst case - * ~50msec) after sending the sleep in command and asserting the - * reset signal. We probably could assert the reset w/o the delay - * but we still delay to avoid possible artifacts. (7.6.1) - */ - msleep(50); - - if (ddata->reset_gpio) - gpiod_set_value(ddata->reset_gpio, 0); - - /* FIXME need to tweak this delay */ - msleep(100); -} - -static void acx565akm_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - mutex_lock(&ddata->mutex); - acx565akm_panel_power_on(dssdev); - mutex_unlock(&ddata->mutex); -} - -static void acx565akm_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - mutex_lock(&ddata->mutex); - acx565akm_panel_power_off(dssdev); - mutex_unlock(&ddata->mutex); -} - -static int acx565akm_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return omapdss_display_get_modes(connector, &ddata->vm); -} - -static const struct omap_dss_device_ops acx565akm_ops = { - .connect = acx565akm_connect, - .disconnect = acx565akm_disconnect, - - .enable = acx565akm_enable, - .disable = acx565akm_disable, - - .get_modes = acx565akm_get_modes, -}; - -static int acx565akm_probe(struct spi_device *spi) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - struct backlight_device *bldev; - int max_brightness, brightness; - struct backlight_properties props; - struct gpio_desc *gpio; - int r; - - dev_dbg(&spi->dev, "%s\n", __func__); - - spi->mode = SPI_MODE_3; - - ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); - if (ddata == NULL) - return -ENOMEM; - - dev_set_drvdata(&spi->dev, ddata); - - ddata->spi = spi; - - mutex_init(&ddata->mutex); - - gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(gpio)) { - dev_err(&spi->dev, "failed to parse reset gpio\n"); - return PTR_ERR(gpio); - } - - ddata->reset_gpio = gpio; - - if (ddata->reset_gpio) - gpiod_set_value(ddata->reset_gpio, 1); - - /* - * After reset we have to wait 5 msec before the first - * command can be sent. - */ - usleep_range(5000, 10000); - - ddata->enabled = panel_enabled(ddata); - - r = panel_detect(ddata); - - if (!ddata->enabled && ddata->reset_gpio) - gpiod_set_value(ddata->reset_gpio, 0); - - if (r) { - dev_err(&spi->dev, "%s panel detect error\n", __func__); - return r; - } - - memset(&props, 0, sizeof(props)); - props.fb_blank = FB_BLANK_UNBLANK; - props.power = FB_BLANK_UNBLANK; - props.type = BACKLIGHT_RAW; - - bldev = backlight_device_register("acx565akm", &ddata->spi->dev, - ddata, &acx565akm_bl_ops, &props); - if (IS_ERR(bldev)) - return PTR_ERR(bldev); - ddata->bl_dev = bldev; - if (ddata->has_cabc) { - r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group); - if (r) { - dev_err(&bldev->dev, - "%s failed to create sysfs files\n", __func__); - goto err_backlight_unregister; - } - ddata->cabc_mode = get_hw_cabc_mode(ddata); - } - - max_brightness = 255; - - if (ddata->has_bc) - brightness = acx565akm_get_actual_brightness(ddata); - else - brightness = 0; - - bldev->props.max_brightness = max_brightness; - bldev->props.brightness = brightness; - - acx565akm_bl_update_status(bldev); - - - ddata->vm = acx565akm_panel_vm; - - dssdev = &ddata->dssdev; - dssdev->dev = &spi->dev; - dssdev->ops = &acx565akm_ops; - dssdev->type = OMAP_DISPLAY_TYPE_SDI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE - | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; - -err_backlight_unregister: - backlight_device_unregister(bldev); - return r; -} - -static int acx565akm_remove(struct spi_device *spi) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - dev_dbg(&ddata->spi->dev, "%s\n", __func__); - - sysfs_remove_group(&ddata->bl_dev->dev.kobj, &bldev_attr_group); - backlight_device_unregister(ddata->bl_dev); - - omapdss_device_unregister(dssdev); - - if (omapdss_device_is_enabled(dssdev)) - acx565akm_disable(dssdev); - - return 0; -} - -static const struct of_device_id acx565akm_of_match[] = { - { .compatible = "omapdss,sony,acx565akm", }, - {}, -}; -MODULE_DEVICE_TABLE(of, acx565akm_of_match); - -static struct spi_driver acx565akm_driver = { - .driver = { - .name = "acx565akm", - .of_match_table = acx565akm_of_match, - .suppress_bind_attrs = true, - }, - .probe = acx565akm_probe, - .remove = acx565akm_remove, -}; - -module_spi_driver(acx565akm_driver); - -MODULE_ALIAS("spi:sony,acx565akm"); -MODULE_AUTHOR("Nokia Corporation"); -MODULE_DESCRIPTION("acx565akm LCD Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c deleted file mode 100644 index c885018ac6ce..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ /dev/null @@ -1,390 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Toppoly TD028TTEC1 panel support - * - * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * Neo 1973 code (jbt6k74.c): - * Copyright (C) 2006-2007 by OpenMoko, Inc. - * Author: Harald Welte <laforge@openmoko.org> - * - * Ported and adapted from Neo 1973 U-Boot by: - * H. Nikolaus Schaller <hns@goldelico.com> - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/spi/spi.h> - -#include "../dss/omapdss.h" - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct videomode vm; - - struct backlight_device *backlight; - - struct spi_device *spi_dev; -}; - -static const struct videomode td028ttec1_panel_vm = { - .hactive = 480, - .vactive = 640, - .pixelclock = 22153000, - .hfront_porch = 24, - .hsync_len = 8, - .hback_porch = 8, - .vfront_porch = 4, - .vsync_len = 2, - .vback_porch = 2, - - .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, -}; - -#define JBT_COMMAND 0x000 -#define JBT_DATA 0x100 - -static int jbt_ret_write_0(struct panel_drv_data *ddata, u8 reg) -{ - int rc; - u16 tx_buf = JBT_COMMAND | reg; - - rc = spi_write(ddata->spi_dev, (u8 *)&tx_buf, - 1*sizeof(u16)); - if (rc != 0) - dev_err(&ddata->spi_dev->dev, - "jbt_ret_write_0 spi_write ret %d\n", rc); - - return rc; -} - -static int jbt_reg_write_1(struct panel_drv_data *ddata, u8 reg, u8 data) -{ - int rc; - u16 tx_buf[2]; - - tx_buf[0] = JBT_COMMAND | reg; - tx_buf[1] = JBT_DATA | data; - rc = spi_write(ddata->spi_dev, (u8 *)tx_buf, - 2*sizeof(u16)); - if (rc != 0) - dev_err(&ddata->spi_dev->dev, - "jbt_reg_write_1 spi_write ret %d\n", rc); - - return rc; -} - -static int jbt_reg_write_2(struct panel_drv_data *ddata, u8 reg, u16 data) -{ - int rc; - u16 tx_buf[3]; - - tx_buf[0] = JBT_COMMAND | reg; - tx_buf[1] = JBT_DATA | (data >> 8); - tx_buf[2] = JBT_DATA | (data & 0xff); - - rc = spi_write(ddata->spi_dev, (u8 *)tx_buf, - 3*sizeof(u16)); - - if (rc != 0) - dev_err(&ddata->spi_dev->dev, - "jbt_reg_write_2 spi_write ret %d\n", rc); - - return rc; -} - -enum jbt_register { - JBT_REG_SLEEP_IN = 0x10, - JBT_REG_SLEEP_OUT = 0x11, - - JBT_REG_DISPLAY_OFF = 0x28, - JBT_REG_DISPLAY_ON = 0x29, - - JBT_REG_RGB_FORMAT = 0x3a, - JBT_REG_QUAD_RATE = 0x3b, - - JBT_REG_POWER_ON_OFF = 0xb0, - JBT_REG_BOOSTER_OP = 0xb1, - JBT_REG_BOOSTER_MODE = 0xb2, - JBT_REG_BOOSTER_FREQ = 0xb3, - JBT_REG_OPAMP_SYSCLK = 0xb4, - JBT_REG_VSC_VOLTAGE = 0xb5, - JBT_REG_VCOM_VOLTAGE = 0xb6, - JBT_REG_EXT_DISPL = 0xb7, - JBT_REG_OUTPUT_CONTROL = 0xb8, - JBT_REG_DCCLK_DCEV = 0xb9, - JBT_REG_DISPLAY_MODE1 = 0xba, - JBT_REG_DISPLAY_MODE2 = 0xbb, - JBT_REG_DISPLAY_MODE = 0xbc, - JBT_REG_ASW_SLEW = 0xbd, - JBT_REG_DUMMY_DISPLAY = 0xbe, - JBT_REG_DRIVE_SYSTEM = 0xbf, - - JBT_REG_SLEEP_OUT_FR_A = 0xc0, - JBT_REG_SLEEP_OUT_FR_B = 0xc1, - JBT_REG_SLEEP_OUT_FR_C = 0xc2, - JBT_REG_SLEEP_IN_LCCNT_D = 0xc3, - JBT_REG_SLEEP_IN_LCCNT_E = 0xc4, - JBT_REG_SLEEP_IN_LCCNT_F = 0xc5, - JBT_REG_SLEEP_IN_LCCNT_G = 0xc6, - - JBT_REG_GAMMA1_FINE_1 = 0xc7, - JBT_REG_GAMMA1_FINE_2 = 0xc8, - JBT_REG_GAMMA1_INCLINATION = 0xc9, - JBT_REG_GAMMA1_BLUE_OFFSET = 0xca, - - JBT_REG_BLANK_CONTROL = 0xcf, - JBT_REG_BLANK_TH_TV = 0xd0, - JBT_REG_CKV_ON_OFF = 0xd1, - JBT_REG_CKV_1_2 = 0xd2, - JBT_REG_OEV_TIMING = 0xd3, - JBT_REG_ASW_TIMING_1 = 0xd4, - JBT_REG_ASW_TIMING_2 = 0xd5, - - JBT_REG_HCLOCK_VGA = 0xec, - JBT_REG_HCLOCK_QVGA = 0xed, -}; - -#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) - -static int td028ttec1_panel_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void td028ttec1_panel_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static void td028ttec1_panel_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - int r = 0; - - dev_dbg(dssdev->dev, "%s: state %d\n", __func__, dssdev->state); - - /* three times command zero */ - r |= jbt_ret_write_0(ddata, 0x00); - usleep_range(1000, 2000); - r |= jbt_ret_write_0(ddata, 0x00); - usleep_range(1000, 2000); - r |= jbt_ret_write_0(ddata, 0x00); - usleep_range(1000, 2000); - - if (r) { - dev_warn(dssdev->dev, "%s: transfer error\n", __func__); - return; - } - - /* deep standby out */ - r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x17); - - /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */ - r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE, 0x80); - - /* Quad mode off */ - r |= jbt_reg_write_1(ddata, JBT_REG_QUAD_RATE, 0x00); - - /* AVDD on, XVDD on */ - r |= jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x16); - - /* Output control */ - r |= jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0xfff9); - - /* Sleep mode off */ - r |= jbt_ret_write_0(ddata, JBT_REG_SLEEP_OUT); - - /* at this point we have like 50% grey */ - - /* initialize register set */ - r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE1, 0x01); - r |= jbt_reg_write_1(ddata, JBT_REG_DISPLAY_MODE2, 0x00); - r |= jbt_reg_write_1(ddata, JBT_REG_RGB_FORMAT, 0x60); - r |= jbt_reg_write_1(ddata, JBT_REG_DRIVE_SYSTEM, 0x10); - r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_OP, 0x56); - r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_MODE, 0x33); - r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11); - r |= jbt_reg_write_1(ddata, JBT_REG_BOOSTER_FREQ, 0x11); - r |= jbt_reg_write_1(ddata, JBT_REG_OPAMP_SYSCLK, 0x02); - r |= jbt_reg_write_1(ddata, JBT_REG_VSC_VOLTAGE, 0x2b); - r |= jbt_reg_write_1(ddata, JBT_REG_VCOM_VOLTAGE, 0x40); - r |= jbt_reg_write_1(ddata, JBT_REG_EXT_DISPL, 0x03); - r |= jbt_reg_write_1(ddata, JBT_REG_DCCLK_DCEV, 0x04); - /* - * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement - * to avoid red / blue flicker - */ - r |= jbt_reg_write_1(ddata, JBT_REG_ASW_SLEW, 0x04); - r |= jbt_reg_write_1(ddata, JBT_REG_DUMMY_DISPLAY, 0x00); - - r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_A, 0x11); - r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_B, 0x11); - r |= jbt_reg_write_1(ddata, JBT_REG_SLEEP_OUT_FR_C, 0x11); - r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040); - r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0); - r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020); - r |= jbt_reg_write_2(ddata, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0); - - r |= jbt_reg_write_2(ddata, JBT_REG_GAMMA1_FINE_1, 0x5533); - r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_FINE_2, 0x00); - r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_INCLINATION, 0x00); - r |= jbt_reg_write_1(ddata, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00); - - r |= jbt_reg_write_2(ddata, JBT_REG_HCLOCK_VGA, 0x1f0); - r |= jbt_reg_write_1(ddata, JBT_REG_BLANK_CONTROL, 0x02); - r |= jbt_reg_write_2(ddata, JBT_REG_BLANK_TH_TV, 0x0804); - - r |= jbt_reg_write_1(ddata, JBT_REG_CKV_ON_OFF, 0x01); - r |= jbt_reg_write_2(ddata, JBT_REG_CKV_1_2, 0x0000); - - r |= jbt_reg_write_2(ddata, JBT_REG_OEV_TIMING, 0x0d0e); - r |= jbt_reg_write_2(ddata, JBT_REG_ASW_TIMING_1, 0x11a4); - r |= jbt_reg_write_1(ddata, JBT_REG_ASW_TIMING_2, 0x0e); - - r |= jbt_ret_write_0(ddata, JBT_REG_DISPLAY_ON); - - if (r) - dev_err(dssdev->dev, "%s: write error\n", __func__); - - backlight_enable(ddata->backlight); -} - -static void td028ttec1_panel_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - backlight_disable(ddata->backlight); - - dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n"); - - jbt_ret_write_0(ddata, JBT_REG_DISPLAY_OFF); - jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002); - jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN); - jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00); -} - -static int td028ttec1_panel_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return omapdss_display_get_modes(connector, &ddata->vm); -} - -static const struct omap_dss_device_ops td028ttec1_ops = { - .connect = td028ttec1_panel_connect, - .disconnect = td028ttec1_panel_disconnect, - - .enable = td028ttec1_panel_enable, - .disable = td028ttec1_panel_disable, - - .get_modes = td028ttec1_panel_get_modes, -}; - -static int td028ttec1_panel_probe(struct spi_device *spi) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - int r; - - dev_dbg(&spi->dev, "%s\n", __func__); - - spi->bits_per_word = 9; - spi->mode = SPI_MODE_3; - - r = spi_setup(spi); - if (r < 0) { - dev_err(&spi->dev, "spi_setup failed: %d\n", r); - return r; - } - - ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); - if (ddata == NULL) - return -ENOMEM; - - ddata->backlight = devm_of_find_backlight(&spi->dev); - if (IS_ERR(ddata->backlight)) - return PTR_ERR(ddata->backlight); - - dev_set_drvdata(&spi->dev, ddata); - - ddata->spi_dev = spi; - - ddata->vm = td028ttec1_panel_vm; - - dssdev = &ddata->dssdev; - dssdev->dev = &spi->dev; - dssdev->ops = &td028ttec1_ops; - dssdev->type = OMAP_DISPLAY_TYPE_DPI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - - /* - * Note: According to the panel documentation: - * SYNC needs to be driven on the FALLING edge - */ - dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE - | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int td028ttec1_panel_remove(struct spi_device *spi) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - dev_dbg(&ddata->spi_dev->dev, "%s\n", __func__); - - omapdss_device_unregister(dssdev); - - td028ttec1_panel_disable(dssdev); - - return 0; -} - -static const struct of_device_id td028ttec1_of_match[] = { - { .compatible = "omapdss,tpo,td028ttec1", }, - /* keep to not break older DTB */ - { .compatible = "omapdss,toppoly,td028ttec1", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, td028ttec1_of_match); - -static const struct spi_device_id td028ttec1_ids[] = { - { "toppoly,td028ttec1", 0 }, - { "tpo,td028ttec1", 0}, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(spi, td028ttec1_ids); - - -static struct spi_driver td028ttec1_spi_driver = { - .probe = td028ttec1_panel_probe, - .remove = td028ttec1_panel_remove, - .id_table = td028ttec1_ids, - - .driver = { - .name = "panel-tpo-td028ttec1", - .of_match_table = td028ttec1_of_match, - .suppress_bind_attrs = true, - }, -}; - -module_spi_driver(td028ttec1_spi_driver); - -MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>"); -MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c deleted file mode 100644 index ce09217da597..000000000000 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c +++ /dev/null @@ -1,513 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * TPO TD043MTEA1 Panel driver - * - * Author: Gražvydas Ignotas <notasas@gmail.com> - * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com> - */ - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/gpio/consumer.h> -#include <linux/module.h> -#include <linux/regulator/consumer.h> -#include <linux/slab.h> -#include <linux/spi/spi.h> - -#include "../dss/omapdss.h" - -#define TPO_R02_MODE(x) ((x) & 7) -#define TPO_R02_MODE_800x480 7 -#define TPO_R02_NCLK_RISING BIT(3) -#define TPO_R02_HSYNC_HIGH BIT(4) -#define TPO_R02_VSYNC_HIGH BIT(5) - -#define TPO_R03_NSTANDBY BIT(0) -#define TPO_R03_EN_CP_CLK BIT(1) -#define TPO_R03_EN_VGL_PUMP BIT(2) -#define TPO_R03_EN_PWM BIT(3) -#define TPO_R03_DRIVING_CAP_100 BIT(4) -#define TPO_R03_EN_PRE_CHARGE BIT(6) -#define TPO_R03_SOFTWARE_CTL BIT(7) - -#define TPO_R04_NFLIP_H BIT(0) -#define TPO_R04_NFLIP_V BIT(1) -#define TPO_R04_CP_CLK_FREQ_1H BIT(2) -#define TPO_R04_VGL_FREQ_1H BIT(4) - -#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \ - TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \ - TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ - TPO_R03_SOFTWARE_CTL) - -#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \ - TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) - -static const u16 tpo_td043_def_gamma[12] = { - 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 -}; - -struct panel_drv_data { - struct omap_dss_device dssdev; - - struct videomode vm; - - struct spi_device *spi; - struct regulator *vcc_reg; - struct gpio_desc *reset_gpio; - u16 gamma[12]; - u32 mode; - u32 vmirror:1; - u32 powered_on:1; - u32 spi_suspended:1; - u32 power_on_resume:1; -}; - -static const struct videomode tpo_td043_vm = { - .hactive = 800, - .vactive = 480, - - .pixelclock = 36000000, - - .hsync_len = 1, - .hfront_porch = 68, - .hback_porch = 214, - - .vsync_len = 1, - .vfront_porch = 39, - .vback_porch = 34, - - .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, -}; - -#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) - -static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) -{ - struct spi_message m; - struct spi_transfer xfer; - u16 w; - int r; - - spi_message_init(&m); - - memset(&xfer, 0, sizeof(xfer)); - - w = ((u16)addr << 10) | (1 << 8) | data; - xfer.tx_buf = &w; - xfer.bits_per_word = 16; - xfer.len = 2; - spi_message_add_tail(&xfer, &m); - - r = spi_sync(spi, &m); - if (r < 0) - dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r); - return r; -} - -static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12]) -{ - u8 i, val; - - /* gamma bits [9:8] */ - for (val = i = 0; i < 4; i++) - val |= (gamma[i] & 0x300) >> ((i + 1) * 2); - tpo_td043_write(spi, 0x11, val); - - for (val = i = 0; i < 4; i++) - val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2); - tpo_td043_write(spi, 0x12, val); - - for (val = i = 0; i < 4; i++) - val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2); - tpo_td043_write(spi, 0x13, val); - - /* gamma bits [7:0] */ - for (val = i = 0; i < 12; i++) - tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff); -} - -static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v) -{ - u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | - TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H; - if (h) - reg4 &= ~TPO_R04_NFLIP_H; - if (v) - reg4 &= ~TPO_R04_NFLIP_V; - - return tpo_td043_write(spi, 4, reg4); -} - -static ssize_t tpo_td043_vmirror_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%d\n", ddata->vmirror); -} - -static ssize_t tpo_td043_vmirror_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - int val; - int ret; - - ret = kstrtoint(buf, 0, &val); - if (ret < 0) - return ret; - - val = !!val; - - ret = tpo_td043_write_mirror(ddata->spi, false, val); - if (ret < 0) - return ret; - - ddata->vmirror = val; - - return count; -} - -static ssize_t tpo_td043_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%d\n", ddata->mode); -} - -static ssize_t tpo_td043_mode_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - long val; - int ret; - - ret = kstrtol(buf, 0, &val); - if (ret != 0 || val & ~7) - return -EINVAL; - - ddata->mode = val; - - val |= TPO_R02_NCLK_RISING; - tpo_td043_write(ddata->spi, 2, val); - - return count; -} - -static ssize_t tpo_td043_gamma_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - ssize_t len = 0; - int ret; - int i; - - for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) { - ret = snprintf(buf + len, PAGE_SIZE - len, "%u ", - ddata->gamma[i]); - if (ret < 0) - return ret; - len += ret; - } - buf[len - 1] = '\n'; - - return len; -} - -static ssize_t tpo_td043_gamma_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - unsigned int g[12]; - int ret; - int i; - - ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u", - &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], - &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]); - - if (ret != 12) - return -EINVAL; - - for (i = 0; i < 12; i++) - ddata->gamma[i] = g[i]; - - tpo_td043_write_gamma(ddata->spi, ddata->gamma); - - return count; -} - -static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR, - tpo_td043_vmirror_show, tpo_td043_vmirror_store); -static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, - tpo_td043_mode_show, tpo_td043_mode_store); -static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR, - tpo_td043_gamma_show, tpo_td043_gamma_store); - -static struct attribute *tpo_td043_attrs[] = { - &dev_attr_vmirror.attr, - &dev_attr_mode.attr, - &dev_attr_gamma.attr, - NULL, -}; - -static const struct attribute_group tpo_td043_attr_group = { - .attrs = tpo_td043_attrs, -}; - -static int tpo_td043_power_on(struct panel_drv_data *ddata) -{ - int r; - - if (ddata->powered_on) - return 0; - - r = regulator_enable(ddata->vcc_reg); - if (r != 0) - return r; - - /* wait for panel to stabilize */ - msleep(160); - - gpiod_set_value(ddata->reset_gpio, 0); - - tpo_td043_write(ddata->spi, 2, - TPO_R02_MODE(ddata->mode) | TPO_R02_NCLK_RISING); - tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_NORMAL); - tpo_td043_write(ddata->spi, 0x20, 0xf0); - tpo_td043_write(ddata->spi, 0x21, 0xf0); - tpo_td043_write_mirror(ddata->spi, false, ddata->vmirror); - tpo_td043_write_gamma(ddata->spi, ddata->gamma); - - ddata->powered_on = 1; - return 0; -} - -static void tpo_td043_power_off(struct panel_drv_data *ddata) -{ - if (!ddata->powered_on) - return; - - tpo_td043_write(ddata->spi, 3, - TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); - - gpiod_set_value(ddata->reset_gpio, 1); - - /* wait for at least 2 vsyncs before cutting off power */ - msleep(50); - - tpo_td043_write(ddata->spi, 3, TPO_R03_VAL_STANDBY); - - regulator_disable(ddata->vcc_reg); - - ddata->powered_on = 0; -} - -static int tpo_td043_connect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ - return 0; -} - -static void tpo_td043_disconnect(struct omap_dss_device *src, - struct omap_dss_device *dst) -{ -} - -static void tpo_td043_enable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - int r; - - /* - * If we are resuming from system suspend, SPI clocks might not be - * enabled yet, so we'll program the LCD from SPI PM resume callback. - */ - if (!ddata->spi_suspended) { - r = tpo_td043_power_on(ddata); - if (r) { - dev_err(&ddata->spi->dev, "%s: power on failed (%d)\n", - __func__, r); - return; - } - } -} - -static void tpo_td043_disable(struct omap_dss_device *dssdev) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - if (!ddata->spi_suspended) - tpo_td043_power_off(ddata); -} - -static int tpo_td043_get_modes(struct omap_dss_device *dssdev, - struct drm_connector *connector) -{ - struct panel_drv_data *ddata = to_panel_data(dssdev); - - return omapdss_display_get_modes(connector, &ddata->vm); -} - -static const struct omap_dss_device_ops tpo_td043_ops = { - .connect = tpo_td043_connect, - .disconnect = tpo_td043_disconnect, - - .enable = tpo_td043_enable, - .disable = tpo_td043_disable, - - .get_modes = tpo_td043_get_modes, -}; - -static int tpo_td043_probe(struct spi_device *spi) -{ - struct panel_drv_data *ddata; - struct omap_dss_device *dssdev; - struct gpio_desc *gpio; - int r; - - dev_dbg(&spi->dev, "%s\n", __func__); - - spi->bits_per_word = 16; - spi->mode = SPI_MODE_0; - - r = spi_setup(spi); - if (r < 0) { - dev_err(&spi->dev, "spi_setup failed: %d\n", r); - return r; - } - - ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); - if (ddata == NULL) - return -ENOMEM; - - dev_set_drvdata(&spi->dev, ddata); - - ddata->spi = spi; - - ddata->mode = TPO_R02_MODE_800x480; - memcpy(ddata->gamma, tpo_td043_def_gamma, sizeof(ddata->gamma)); - - ddata->vcc_reg = devm_regulator_get(&spi->dev, "vcc"); - if (IS_ERR(ddata->vcc_reg)) { - dev_err(&spi->dev, "failed to get LCD VCC regulator\n"); - return PTR_ERR(ddata->vcc_reg); - } - - gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(gpio)) { - dev_err(&spi->dev, "failed to get reset gpio\n"); - return PTR_ERR(gpio); - } - - ddata->reset_gpio = gpio; - - r = sysfs_create_group(&spi->dev.kobj, &tpo_td043_attr_group); - if (r) { - dev_err(&spi->dev, "failed to create sysfs files\n"); - return r; - } - - ddata->vm = tpo_td043_vm; - - dssdev = &ddata->dssdev; - dssdev->dev = &spi->dev; - dssdev->ops = &tpo_td043_ops; - dssdev->type = OMAP_DISPLAY_TYPE_DPI; - dssdev->display = true; - dssdev->owner = THIS_MODULE; - dssdev->of_ports = BIT(0); - dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES; - - /* - * Note: According to the panel documentation: - * SYNC needs to be driven on the FALLING edge - */ - dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH - | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE - | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; - - omapdss_display_init(dssdev); - omapdss_device_register(dssdev); - - return 0; -} - -static int tpo_td043_remove(struct spi_device *spi) -{ - struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); - struct omap_dss_device *dssdev = &ddata->dssdev; - - dev_dbg(&ddata->spi->dev, "%s\n", __func__); - - omapdss_device_unregister(dssdev); - - if (omapdss_device_is_enabled(dssdev)) - tpo_td043_disable(dssdev); - - sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int tpo_td043_spi_suspend(struct device *dev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - - dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", ddata); - - ddata->power_on_resume = ddata->powered_on; - tpo_td043_power_off(ddata); - ddata->spi_suspended = 1; - - return 0; -} - -static int tpo_td043_spi_resume(struct device *dev) -{ - struct panel_drv_data *ddata = dev_get_drvdata(dev); - int ret; - - dev_dbg(dev, "tpo_td043_spi_resume\n"); - - if (ddata->power_on_resume) { - ret = tpo_td043_power_on(ddata); - if (ret) - return ret; - } - ddata->spi_suspended = 0; - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, - tpo_td043_spi_suspend, tpo_td043_spi_resume); - -static const struct of_device_id tpo_td043_of_match[] = { - { .compatible = "omapdss,tpo,td043mtea1", }, - {}, -}; - -MODULE_DEVICE_TABLE(of, tpo_td043_of_match); - -static struct spi_driver tpo_td043_spi_driver = { - .driver = { - .name = "panel-tpo-td043mtea1", - .pm = &tpo_td043_spi_pm, - .of_match_table = tpo_td043_of_match, - .suppress_bind_attrs = true, - }, - .probe = tpo_td043_probe, - .remove = tpo_td043_remove, -}; - -module_spi_driver(tpo_td043_spi_driver); - -MODULE_ALIAS("spi:tpo,td043mtea1"); -MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); -MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c index a140de79c50e..31502857f013 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c +++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c @@ -176,17 +176,10 @@ static const struct of_device_id omapdss_of_match[] __initconst = { static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = { { .compatible = "composite-video-connector" }, { .compatible = "hdmi-connector" }, - { .compatible = "lgphilips,lb035q02" }, - { .compatible = "nec,nl8048hl11" }, { .compatible = "panel-dsi-cm" }, - { .compatible = "sharp,ls037v7dw01" }, - { .compatible = "sony,acx565akm" }, { .compatible = "svideo-connector" }, { .compatible = "ti,opa362" }, { .compatible = "ti,tpd12s015" }, - { .compatible = "toppoly,td028ttec1" }, - { .compatible = "tpo,td028ttec1" }, - { .compatible = "tpo,td043mtea1" }, {}, }; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index eaecd40cc32e..f152bc4eeb53 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -103,6 +103,14 @@ config DRM_PANEL_SAMSUNG_LD9040 depends on OF && SPI select VIDEOMODE_HELPERS +config DRM_PANEL_LG_LB035Q02 + tristate "LG LB035Q024573 RGB panel" + depends on GPIOLIB && OF && SPI + help + Say Y here if you want to enable support for the LB035Q02 RGB panel + (found on the Gumstix Overo Palo35 board). To compile this driver as + a module, choose M here. + config DRM_PANEL_LG_LG4573 tristate "LG4573 RGB/SPI panel" depends on OF && SPI @@ -111,6 +119,14 @@ config DRM_PANEL_LG_LG4573 Say Y here if you want to enable support for LG4573 RGB panel. To compile this driver as a module, choose M here. +config DRM_PANEL_NEC_NL8048HL11 + tristate "NEC NL8048HL11 RGB panel" + depends on GPIOLIB && OF && SPI + help + Say Y here if you want to enable support for the NEC NL8048HL11 RGB + panel (found on the Zoom2/3/3630 SDP boards). To compile this driver + as a module, choose M here. + config DRM_PANEL_NOVATEK_NT39016 tristate "Novatek NT39016 RGB/SPI panel" depends on OF && SPI @@ -266,6 +282,13 @@ config DRM_PANEL_SHARP_LQ101R1SX01 To compile this driver as a module, choose M here: the module will be called panel-sharp-lq101r1sx01. +config DRM_PANEL_SHARP_LS037V7DW01 + tristate "Sharp LS037V7DW01 VGA LCD panel" + depends on GPIOLIB && OF && REGULATOR + help + Say Y here if you want to enable support for Sharp LS037V7DW01 VGA + (480x640) LCD panel (found on the TI SDP3430 board). + config DRM_PANEL_SHARP_LS043T1LE01 tristate "Sharp LS043T1LE01 qHD video mode panel" depends on OF @@ -293,6 +316,29 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels +config DRM_PANEL_SONY_ACX565AKM + tristate "Sony ACX565AKM panel" + depends on GPIOLIB && OF && SPI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Sony ACX565AKM + 800x600 3.5" panel (found on the Nokia N900). + +config DRM_PANEL_TPO_TD028TTEC1 + tristate "Toppoly (TPO) TD028TTEC1 panel driver" + depends on OF && SPI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for TPO TD028TTEC1 480x640 + 2.8" panel (found on the OpenMoko Neo FreeRunner and Neo 1973). + +config DRM_PANEL_TPO_TD043MTEA1 + tristate "Toppoly (TPO) TD043MTEA1 panel driver" + depends on GPIOLIB && OF && REGULATOR && SPI + help + Say Y here if you want to enable support for TPO TD043MTEA1 800x480 + 4.3" panel (found on the OMAP3 Pandora board). + config DRM_PANEL_TPO_TPG110 tristate "TPO TPG 800x400 panel" depends on OF && SPI && GPIOLIB diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 62dae45f8f74..b6cd39fe0f20 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -8,7 +8,9 @@ obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o +obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o +obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT39016) += panel-novatek-nt39016.o obj-$(CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO) += panel-olimex-lcd-olinuxino.o obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o @@ -27,8 +29,12 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o +obj-$(CONFIG_DRM_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o +obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o +obj-$(CONFIG_DRM_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o +obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 53dd1e128795..3c58f63adbf7 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -349,7 +349,6 @@ static const struct regmap_config ili9322_regmap_config = { static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili) { - struct drm_connector *connector = panel->connector; u8 reg; int ret; int i; @@ -407,23 +406,11 @@ static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili) * Polarity and inverted color order for RGB input. * None of this applies in the BT.656 mode. */ - if (ili->conf->dclk_active_high) { + reg = 0; + if (ili->conf->dclk_active_high) reg = ILI9322_POL_DCLK; - connector->display_info.bus_flags |= - DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; - } else { - reg = 0; - connector->display_info.bus_flags |= - DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; - } - if (ili->conf->de_active_high) { + if (ili->conf->de_active_high) reg |= ILI9322_POL_DE; - connector->display_info.bus_flags |= - DRM_BUS_FLAG_DE_HIGH; - } else { - connector->display_info.bus_flags |= - DRM_BUS_FLAG_DE_LOW; - } if (ili->conf->hsync_active_high) reg |= ILI9322_POL_HSYNC; if (ili->conf->vsync_active_high) @@ -659,9 +646,20 @@ static int ili9322_get_modes(struct drm_panel *panel) struct drm_connector *connector = panel->connector; struct ili9322 *ili = panel_to_ili9322(panel); struct drm_display_mode *mode; + struct drm_display_info *info; + + info = &connector->display_info; + info->width_mm = ili->conf->width_mm; + info->height_mm = ili->conf->height_mm; + if (ili->conf->dclk_active_high) + info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; + else + info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; - connector->display_info.width_mm = ili->conf->width_mm; - connector->display_info.height_mm = ili->conf->height_mm; + if (ili->conf->de_active_high) + info->bus_flags |= DRM_BUS_FLAG_DE_HIGH; + else + info->bus_flags |= DRM_BUS_FLAG_DE_LOW; switch (ili->input) { case ILI9322_INPUT_SRGB_DUMMY_320X240: diff --git a/drivers/gpu/drm/panel/panel-lg-lb035q02.c b/drivers/gpu/drm/panel/panel-lg-lb035q02.c new file mode 100644 index 000000000000..fc82a525b071 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-lg-lb035q02.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * LG.Philips LB035Q02 LCD Panel Driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific panel-lgphilips-lb035q02 driver + * + * Copyright (C) 2013 Texas Instruments Incorporated + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * Based on a driver by: Steve Sakoman <steve@sakoman.com> + */ + +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +struct lb035q02_device { + struct drm_panel panel; + + struct spi_device *spi; + struct gpio_desc *enable_gpio; +}; + +#define to_lb035q02_device(p) container_of(p, struct lb035q02_device, panel) + +static int lb035q02_write(struct lb035q02_device *lcd, u16 reg, u16 val) +{ + struct spi_message msg; + struct spi_transfer index_xfer = { + .len = 3, + .cs_change = 1, + }; + struct spi_transfer value_xfer = { + .len = 3, + }; + u8 buffer[16]; + + spi_message_init(&msg); + + /* register index */ + buffer[0] = 0x70; + buffer[1] = 0x00; + buffer[2] = reg & 0x7f; + index_xfer.tx_buf = buffer; + spi_message_add_tail(&index_xfer, &msg); + + /* register value */ + buffer[4] = 0x72; + buffer[5] = val >> 8; + buffer[6] = val; + value_xfer.tx_buf = buffer + 4; + spi_message_add_tail(&value_xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +static int lb035q02_init(struct lb035q02_device *lcd) +{ + /* Init sequence from page 28 of the lb035q02 spec. */ + static const struct { + u16 index; + u16 value; + } init_data[] = { + { 0x01, 0x6300 }, + { 0x02, 0x0200 }, + { 0x03, 0x0177 }, + { 0x04, 0x04c7 }, + { 0x05, 0xffc0 }, + { 0x06, 0xe806 }, + { 0x0a, 0x4008 }, + { 0x0b, 0x0000 }, + { 0x0d, 0x0030 }, + { 0x0e, 0x2800 }, + { 0x0f, 0x0000 }, + { 0x16, 0x9f80 }, + { 0x17, 0x0a0f }, + { 0x1e, 0x00c1 }, + { 0x30, 0x0300 }, + { 0x31, 0x0007 }, + { 0x32, 0x0000 }, + { 0x33, 0x0000 }, + { 0x34, 0x0707 }, + { 0x35, 0x0004 }, + { 0x36, 0x0302 }, + { 0x37, 0x0202 }, + { 0x3a, 0x0a0d }, + { 0x3b, 0x0806 }, + }; + + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(init_data); ++i) { + ret = lb035q02_write(lcd, init_data[i].index, + init_data[i].value); + if (ret < 0) + return ret; + } + + return 0; +} + +static int lb035q02_disable(struct drm_panel *panel) +{ + struct lb035q02_device *lcd = to_lb035q02_device(panel); + + gpiod_set_value_cansleep(lcd->enable_gpio, 0); + + return 0; +} + +static int lb035q02_enable(struct drm_panel *panel) +{ + struct lb035q02_device *lcd = to_lb035q02_device(panel); + + gpiod_set_value_cansleep(lcd->enable_gpio, 1); + + return 0; +} + +static const struct drm_display_mode lb035q02_mode = { + .clock = 6500, + .hdisplay = 320, + .hsync_start = 320 + 20, + .hsync_end = 320 + 20 + 2, + .htotal = 320 + 20 + 2 + 68, + .vdisplay = 240, + .vsync_start = 240 + 4, + .vsync_end = 240 + 4 + 2, + .vtotal = 240 + 4 + 2 + 18, + .vrefresh = 60, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 70, + .height_mm = 53, +}; + +static int lb035q02_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &lb035q02_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = lb035q02_mode.width_mm; + connector->display_info.height_mm = lb035q02_mode.height_mm; + /* + * FIXME: According to the datasheet pixel data is sampled on the + * rising edge of the clock, but the code running on the Gumstix Overo + * Palo35 indicates sampling on the negative edge. This should be + * tested on a real device. + */ + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH + | DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE; + + return 1; +} + +static const struct drm_panel_funcs lb035q02_funcs = { + .disable = lb035q02_disable, + .enable = lb035q02_enable, + .get_modes = lb035q02_get_modes, +}; + +static int lb035q02_probe(struct spi_device *spi) +{ + struct lb035q02_device *lcd; + int ret; + + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + spi_set_drvdata(spi, lcd); + lcd->spi = spi; + + lcd->enable_gpio = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(lcd->enable_gpio)) { + dev_err(&spi->dev, "failed to parse enable gpio\n"); + return PTR_ERR(lcd->enable_gpio); + } + + ret = lb035q02_init(lcd); + if (ret < 0) + return ret; + + drm_panel_init(&lcd->panel); + lcd->panel.dev = &lcd->spi->dev; + lcd->panel.funcs = &lb035q02_funcs; + + return drm_panel_add(&lcd->panel); +} + +static int lb035q02_remove(struct spi_device *spi) +{ + struct lb035q02_device *lcd = spi_get_drvdata(spi); + + drm_panel_remove(&lcd->panel); + drm_panel_disable(&lcd->panel); + + return 0; +} + +static const struct of_device_id lb035q02_of_match[] = { + { .compatible = "lgphilips,lb035q02", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, lb035q02_of_match); + +static struct spi_driver lb035q02_driver = { + .probe = lb035q02_probe, + .remove = lb035q02_remove, + .driver = { + .name = "panel-lg-lb035q02", + .of_match_table = lb035q02_of_match, + }, +}; + +module_spi_driver(lb035q02_driver); + +MODULE_ALIAS("spi:lgphilips,lb035q02"); +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); +MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c new file mode 100644 index 000000000000..299b217c83e1 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-nec-nl8048hl11.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NEC NL8048HL11 Panel Driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific panel-nec-nl8048hl11 driver + * + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Erik Gilling <konkers@android.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/spi/spi.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +struct nl8048_panel { + struct drm_panel panel; + + struct spi_device *spi; + struct gpio_desc *reset_gpio; +}; + +#define to_nl8048_device(p) container_of(p, struct nl8048_panel, panel) + +static int nl8048_write(struct nl8048_panel *lcd, unsigned char addr, + unsigned char value) +{ + u8 data[4] = { value, 0x01, addr, 0x00 }; + int ret; + + ret = spi_write(lcd->spi, data, sizeof(data)); + if (ret) + dev_err(&lcd->spi->dev, "SPI write to %u failed: %d\n", + addr, ret); + + return ret; +} + +static int nl8048_init(struct nl8048_panel *lcd) +{ + static const struct { + unsigned char addr; + unsigned char data; + } nl8048_init_seq[] = { + { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, + { 5, 0x14 }, { 6, 0x24 }, { 16, 0xd7 }, { 17, 0x00 }, + { 18, 0x00 }, { 19, 0x55 }, { 20, 0x01 }, { 21, 0x70 }, + { 22, 0x1e }, { 23, 0x25 }, { 24, 0x25 }, { 25, 0x02 }, + { 26, 0x02 }, { 27, 0xa0 }, { 32, 0x2f }, { 33, 0x0f }, + { 34, 0x0f }, { 35, 0x0f }, { 36, 0x0f }, { 37, 0x0f }, + { 38, 0x0f }, { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, + { 42, 0x02 }, { 43, 0x0f }, { 44, 0x0f }, { 45, 0x0f }, + { 46, 0x0f }, { 47, 0x0f }, { 48, 0x0f }, { 49, 0x0f }, + { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, + { 80, 0x0c }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, + { 86, 0x14 }, { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, + { 92, 0x02 }, { 93, 0x0c }, { 94, 0x1c }, { 95, 0x27 }, + { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, { 103, 0x27 }, + { 112, 0x01 }, { 113, 0x0e }, { 114, 0x02 }, { 115, 0x0c }, + { 118, 0x0c }, { 121, 0x30 }, { 130, 0x00 }, { 131, 0x00 }, + { 132, 0xfc }, { 134, 0x00 }, { 136, 0x00 }, { 138, 0x00 }, + { 139, 0x00 }, { 140, 0x00 }, { 141, 0xfc }, { 143, 0x00 }, + { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, { 149, 0x00 }, + { 150, 0xfc }, { 152, 0x00 }, { 154, 0x00 }, { 156, 0x00 }, + { 157, 0x00 }, + }; + + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(nl8048_init_seq); ++i) { + ret = nl8048_write(lcd, nl8048_init_seq[i].addr, + nl8048_init_seq[i].data); + if (ret < 0) + return ret; + } + + udelay(20); + + return nl8048_write(lcd, 2, 0x00); +} + +static int nl8048_disable(struct drm_panel *panel) +{ + struct nl8048_panel *lcd = to_nl8048_device(panel); + + gpiod_set_value_cansleep(lcd->reset_gpio, 0); + + return 0; +} + +static int nl8048_enable(struct drm_panel *panel) +{ + struct nl8048_panel *lcd = to_nl8048_device(panel); + + gpiod_set_value_cansleep(lcd->reset_gpio, 1); + + return 0; +} + +static const struct drm_display_mode nl8048_mode = { + /* NEC PIX Clock Ratings MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz */ + .clock = 23800, + .hdisplay = 800, + .hsync_start = 800 + 6, + .hsync_end = 800 + 6 + 1, + .htotal = 800 + 6 + 1 + 4, + .vdisplay = 480, + .vsync_start = 480 + 3, + .vsync_end = 480 + 3 + 1, + .vtotal = 480 + 3 + 1 + 4, + .vrefresh = 60, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 89, + .height_mm = 53, +}; + +static int nl8048_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &nl8048_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = nl8048_mode.width_mm; + connector->display_info.height_mm = nl8048_mode.height_mm; + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH + | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE; + + return 1; +} + +static const struct drm_panel_funcs nl8048_funcs = { + .disable = nl8048_disable, + .enable = nl8048_enable, + .get_modes = nl8048_get_modes, +}; + +static int __maybe_unused nl8048_suspend(struct device *dev) +{ + struct nl8048_panel *lcd = dev_get_drvdata(dev); + + nl8048_write(lcd, 2, 0x01); + msleep(40); + + return 0; +} + +static int __maybe_unused nl8048_resume(struct device *dev) +{ + struct nl8048_panel *lcd = dev_get_drvdata(dev); + + /* Reinitialize the panel. */ + spi_setup(lcd->spi); + nl8048_write(lcd, 2, 0x00); + nl8048_init(lcd); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(nl8048_pm_ops, nl8048_suspend, nl8048_resume); + +static int nl8048_probe(struct spi_device *spi) +{ + struct nl8048_panel *lcd; + int ret; + + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + spi_set_drvdata(spi, lcd); + lcd->spi = spi; + + lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(lcd->reset_gpio)) { + dev_err(&spi->dev, "failed to parse reset gpio\n"); + return PTR_ERR(lcd->reset_gpio); + } + + spi->mode = SPI_MODE_0; + spi->bits_per_word = 32; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "failed to setup SPI: %d\n", ret); + return ret; + } + + ret = nl8048_init(lcd); + if (ret < 0) + return ret; + + drm_panel_init(&lcd->panel); + lcd->panel.dev = &lcd->spi->dev; + lcd->panel.funcs = &nl8048_funcs; + + return drm_panel_add(&lcd->panel); +} + +static int nl8048_remove(struct spi_device *spi) +{ + struct nl8048_panel *lcd = spi_get_drvdata(spi); + + drm_panel_remove(&lcd->panel); + drm_panel_disable(&lcd->panel); + drm_panel_unprepare(&lcd->panel); + + return 0; +} + +static const struct of_device_id nl8048_of_match[] = { + { .compatible = "nec,nl8048hl11", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, nl8048_of_match); + +static struct spi_driver nl8048_driver = { + .probe = nl8048_probe, + .remove = nl8048_remove, + .driver = { + .name = "panel-nec-nl8048hl11", + .pm = &nl8048_pm_ops, + .of_match_table = nl8048_of_match, + }, +}; + +module_spi_driver(nl8048_driver); + +MODULE_ALIAS("spi:nec,nl8048hl11"); +MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); +MODULE_DESCRIPTION("NEC-NL8048HL11 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c new file mode 100644 index 000000000000..46cd9a250129 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sharp-ls037v7dw01.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sharp LS037V7DW01 LCD Panel Driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific panel-sharp-ls037v7dw01 driver + * + * Copyright (C) 2013 Texas Instruments Incorporated + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +struct ls037v7dw01_panel { + struct drm_panel panel; + struct platform_device *pdev; + + struct regulator *vdd; + struct gpio_desc *resb_gpio; /* low = reset active min 20 us */ + struct gpio_desc *ini_gpio; /* high = power on */ + struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */ + struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */ + struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */ +}; + +#define to_ls037v7dw01_device(p) \ + container_of(p, struct ls037v7dw01_panel, panel) + +static int ls037v7dw01_disable(struct drm_panel *panel) +{ + struct ls037v7dw01_panel *lcd = to_ls037v7dw01_device(panel); + + gpiod_set_value_cansleep(lcd->ini_gpio, 0); + gpiod_set_value_cansleep(lcd->resb_gpio, 0); + + /* Wait at least 5 vsyncs after disabling the LCD. */ + msleep(100); + + return 0; +} + +static int ls037v7dw01_unprepare(struct drm_panel *panel) +{ + struct ls037v7dw01_panel *lcd = to_ls037v7dw01_device(panel); + + regulator_disable(lcd->vdd); + return 0; +} + +static int ls037v7dw01_prepare(struct drm_panel *panel) +{ + struct ls037v7dw01_panel *lcd = to_ls037v7dw01_device(panel); + int ret; + + ret = regulator_enable(lcd->vdd); + if (ret < 0) + dev_err(&lcd->pdev->dev, "%s: failed to enable regulator\n", + __func__); + + return ret; +} + +static int ls037v7dw01_enable(struct drm_panel *panel) +{ + struct ls037v7dw01_panel *lcd = to_ls037v7dw01_device(panel); + + /* Wait couple of vsyncs before enabling the LCD. */ + msleep(50); + + gpiod_set_value_cansleep(lcd->resb_gpio, 1); + gpiod_set_value_cansleep(lcd->ini_gpio, 1); + + return 0; +} + +static const struct drm_display_mode ls037v7dw01_mode = { + .clock = 19200, + .hdisplay = 480, + .hsync_start = 480 + 1, + .hsync_end = 480 + 1 + 2, + .htotal = 480 + 1 + 2 + 28, + .vdisplay = 640, + .vsync_start = 640 + 1, + .vsync_end = 640 + 1 + 1, + .vtotal = 640 + 1 + 1 + 1, + .vrefresh = 58, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 56, + .height_mm = 75, +}; + +static int ls037v7dw01_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &ls037v7dw01_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = ls037v7dw01_mode.width_mm; + connector->display_info.height_mm = ls037v7dw01_mode.height_mm; + /* + * FIXME: According to the datasheet pixel data is sampled on the + * rising edge of the clock, but the code running on the SDP3430 + * indicates sampling on the negative edge. This should be tested on a + * real device. + */ + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH + | DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE; + + return 1; +} + +static const struct drm_panel_funcs ls037v7dw01_funcs = { + .disable = ls037v7dw01_disable, + .unprepare = ls037v7dw01_unprepare, + .prepare = ls037v7dw01_prepare, + .enable = ls037v7dw01_enable, + .get_modes = ls037v7dw01_get_modes, +}; + +static int ls037v7dw01_probe(struct platform_device *pdev) +{ + struct ls037v7dw01_panel *lcd; + + lcd = devm_kzalloc(&pdev->dev, sizeof(*lcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + platform_set_drvdata(pdev, lcd); + lcd->pdev = pdev; + + lcd->vdd = devm_regulator_get(&pdev->dev, "envdd"); + if (IS_ERR(lcd->vdd)) { + dev_err(&pdev->dev, "failed to get regulator\n"); + return PTR_ERR(lcd->vdd); + } + + lcd->ini_gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(lcd->ini_gpio)) { + dev_err(&pdev->dev, "failed to get enable gpio\n"); + return PTR_ERR(lcd->ini_gpio); + } + + lcd->resb_gpio = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(lcd->resb_gpio)) { + dev_err(&pdev->dev, "failed to get reset gpio\n"); + return PTR_ERR(lcd->resb_gpio); + } + + lcd->mo_gpio = devm_gpiod_get_index(&pdev->dev, "mode", 0, + GPIOD_OUT_LOW); + if (IS_ERR(lcd->mo_gpio)) { + dev_err(&pdev->dev, "failed to get mode[0] gpio\n"); + return PTR_ERR(lcd->mo_gpio); + } + + lcd->lr_gpio = devm_gpiod_get_index(&pdev->dev, "mode", 1, + GPIOD_OUT_LOW); + if (IS_ERR(lcd->lr_gpio)) { + dev_err(&pdev->dev, "failed to get mode[1] gpio\n"); + return PTR_ERR(lcd->lr_gpio); + } + + lcd->ud_gpio = devm_gpiod_get_index(&pdev->dev, "mode", 2, + GPIOD_OUT_LOW); + if (IS_ERR(lcd->ud_gpio)) { + dev_err(&pdev->dev, "failed to get mode[2] gpio\n"); + return PTR_ERR(lcd->ud_gpio); + } + + drm_panel_init(&lcd->panel); + lcd->panel.dev = &pdev->dev; + lcd->panel.funcs = &ls037v7dw01_funcs; + + return drm_panel_add(&lcd->panel); +} + +static int ls037v7dw01_remove(struct platform_device *pdev) +{ + struct ls037v7dw01_panel *lcd = platform_get_drvdata(pdev); + + drm_panel_remove(&lcd->panel); + drm_panel_disable(&lcd->panel); + drm_panel_unprepare(&lcd->panel); + + return 0; +} + +static const struct of_device_id ls037v7dw01_of_match[] = { + { .compatible = "sharp,ls037v7dw01", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, ls037v7dw01_of_match); + +static struct platform_driver ls037v7dw01_driver = { + .probe = ls037v7dw01_probe, + .remove = ls037v7dw01_remove, + .driver = { + .name = "panel-sharp-ls037v7dw01", + .of_match_table = ls037v7dw01_of_match, + }, +}; + +module_platform_driver(ls037v7dw01_driver); + +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); +MODULE_DESCRIPTION("Sharp LS037V7DW01 Panel Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index bff7578f84dd..28fa6ba7b767 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2833,6 +2833,64 @@ static const struct panel_desc tianma_tm070rvhg71 = { .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, }; +static const struct drm_display_mode ti_nspire_cx_lcd_mode[] = { + { + .clock = 10000, + .hdisplay = 320, + .hsync_start = 320 + 50, + .hsync_end = 320 + 50 + 6, + .htotal = 320 + 50 + 6 + 38, + .vdisplay = 240, + .vsync_start = 240 + 3, + .vsync_end = 240 + 3 + 1, + .vtotal = 240 + 3 + 1 + 17, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, + }, +}; + +static const struct panel_desc ti_nspire_cx_lcd_panel = { + .modes = ti_nspire_cx_lcd_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 65, + .height = 49, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, + .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, +}; + +static const struct drm_display_mode ti_nspire_classic_lcd_mode[] = { + { + .clock = 10000, + .hdisplay = 320, + .hsync_start = 320 + 6, + .hsync_end = 320 + 6 + 6, + .htotal = 320 + 6 + 6 + 6, + .vdisplay = 240, + .vsync_start = 240 + 0, + .vsync_end = 240 + 0 + 1, + .vtotal = 240 + 0 + 1 + 0, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + }, +}; + +static const struct panel_desc ti_nspire_classic_lcd_panel = { + .modes = ti_nspire_classic_lcd_mode, + .num_modes = 1, + /* The grayscale panel has 8 bit for the color .. Y (black) */ + .bpc = 8, + .size = { + .width = 71, + .height = 53, + }, + /* This is the grayscale bus format */ + .bus_format = MEDIA_BUS_FMT_Y8_1X8, + .bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE, +}; + static const struct drm_display_mode toshiba_lt089ac29000_mode = { .clock = 79500, .hdisplay = 1280, @@ -3303,6 +3361,12 @@ static const struct of_device_id platform_of_match[] = { .compatible = "tianma,tm070rvhg71", .data = &tianma_tm070rvhg71, }, { + .compatible = "ti,nspire-cx-lcd-panel", + .data = &ti_nspire_cx_lcd_panel, + }, { + .compatible = "ti,nspire-classic-lcd-panel", + .data = &ti_nspire_classic_lcd_panel, + }, { .compatible = "toshiba,lt089ac29000", .data = &toshiba_lt089ac29000, }, { diff --git a/drivers/gpu/drm/panel/panel-sony-acx565akm.c b/drivers/gpu/drm/panel/panel-sony-acx565akm.c new file mode 100644 index 000000000000..305259b58767 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-sony-acx565akm.c @@ -0,0 +1,701 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sony ACX565AKM LCD Panel driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific panel-sony-acx565akm driver + * + * Copyright (C) 2010 Nokia Corporation + * Author: Imre Deak <imre.deak@nokia.com> + */ + +/* + * TODO (to be addressed with hardware access to test the changes): + * + * - Update backlight support to use backlight_update_status() etc. + * - Use prepare/unprepare for the basic power on/off of the backligt + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/sched.h> +#include <linux/spi/spi.h> +#include <video/mipi_display.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#define CTRL_DISP_BRIGHTNESS_CTRL_ON BIT(5) +#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON BIT(4) +#define CTRL_DISP_BACKLIGHT_ON BIT(2) +#define CTRL_DISP_AUTO_BRIGHTNESS_ON BIT(1) + +#define MIPID_CMD_WRITE_CABC 0x55 +#define MIPID_CMD_READ_CABC 0x56 + +#define MIPID_VER_LPH8923 3 +#define MIPID_VER_LS041Y3 4 +#define MIPID_VER_L4F00311 8 +#define MIPID_VER_ACX565AKM 9 + +struct acx565akm_panel { + struct drm_panel panel; + + struct spi_device *spi; + struct gpio_desc *reset_gpio; + struct backlight_device *backlight; + + struct mutex mutex; + + const char *name; + u8 display_id[3]; + int model; + int revision; + bool has_bc; + bool has_cabc; + + bool enabled; + unsigned int cabc_mode; + /* + * Next value of jiffies when we can issue the next sleep in/out + * command. + */ + unsigned long hw_guard_end; + unsigned long hw_guard_wait; /* max guard time in jiffies */ +}; + +#define to_acx565akm_device(p) container_of(p, struct acx565akm_panel, panel) + +static void acx565akm_transfer(struct acx565akm_panel *lcd, int cmd, + const u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + struct spi_message m; + struct spi_transfer *x, xfer[5]; + int ret; + + spi_message_init(&m); + + memset(xfer, 0, sizeof(xfer)); + x = &xfer[0]; + + cmd &= 0xff; + x->tx_buf = &cmd; + x->bits_per_word = 9; + x->len = 2; + + if (rlen > 1 && wlen == 0) { + /* + * Between the command and the response data there is a + * dummy clock cycle. Add an extra bit after the command + * word to account for this. + */ + x->bits_per_word = 10; + cmd <<= 1; + } + spi_message_add_tail(x, &m); + + if (wlen) { + x++; + x->tx_buf = wbuf; + x->len = wlen; + x->bits_per_word = 9; + spi_message_add_tail(x, &m); + } + + if (rlen) { + x++; + x->rx_buf = rbuf; + x->len = rlen; + spi_message_add_tail(x, &m); + } + + ret = spi_sync(lcd->spi, &m); + if (ret < 0) + dev_dbg(&lcd->spi->dev, "spi_sync %d\n", ret); +} + +static inline void acx565akm_cmd(struct acx565akm_panel *lcd, int cmd) +{ + acx565akm_transfer(lcd, cmd, NULL, 0, NULL, 0); +} + +static inline void acx565akm_write(struct acx565akm_panel *lcd, + int reg, const u8 *buf, int len) +{ + acx565akm_transfer(lcd, reg, buf, len, NULL, 0); +} + +static inline void acx565akm_read(struct acx565akm_panel *lcd, + int reg, u8 *buf, int len) +{ + acx565akm_transfer(lcd, reg, NULL, 0, buf, len); +} + +/* ----------------------------------------------------------------------------- + * Auto Brightness Control Via sysfs + */ + +static unsigned int acx565akm_get_cabc_mode(struct acx565akm_panel *lcd) +{ + return lcd->cabc_mode; +} + +static void acx565akm_set_cabc_mode(struct acx565akm_panel *lcd, + unsigned int mode) +{ + u16 cabc_ctrl; + + lcd->cabc_mode = mode; + if (!lcd->enabled) + return; + cabc_ctrl = 0; + acx565akm_read(lcd, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1); + cabc_ctrl &= ~3; + cabc_ctrl |= (1 << 8) | (mode & 3); + acx565akm_write(lcd, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2); +} + +static unsigned int acx565akm_get_hw_cabc_mode(struct acx565akm_panel *lcd) +{ + u8 cabc_ctrl; + + acx565akm_read(lcd, MIPID_CMD_READ_CABC, &cabc_ctrl, 1); + return cabc_ctrl & 3; +} + +static const char * const acx565akm_cabc_modes[] = { + "off", /* always used when CABC is not supported */ + "ui", + "still-image", + "moving-image", +}; + +static ssize_t cabc_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acx565akm_panel *lcd = dev_get_drvdata(dev); + const char *mode_str; + int mode; + + if (!lcd->has_cabc) + mode = 0; + else + mode = acx565akm_get_cabc_mode(lcd); + + mode_str = "unknown"; + if (mode >= 0 && mode < ARRAY_SIZE(acx565akm_cabc_modes)) + mode_str = acx565akm_cabc_modes[mode]; + + return sprintf(buf, "%s\n", mode_str); +} + +static ssize_t cabc_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acx565akm_panel *lcd = dev_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(acx565akm_cabc_modes); i++) { + const char *mode_str = acx565akm_cabc_modes[i]; + int cmp_len = strlen(mode_str); + + if (count > 0 && buf[count - 1] == '\n') + count--; + if (count != cmp_len) + continue; + + if (strncmp(buf, mode_str, cmp_len) == 0) + break; + } + + if (i == ARRAY_SIZE(acx565akm_cabc_modes)) + return -EINVAL; + + if (!lcd->has_cabc && i != 0) + return -EINVAL; + + mutex_lock(&lcd->mutex); + acx565akm_set_cabc_mode(lcd, i); + mutex_unlock(&lcd->mutex); + + return count; +} + +static ssize_t cabc_available_modes_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acx565akm_panel *lcd = dev_get_drvdata(dev); + unsigned int i; + size_t len = 0; + + if (!lcd->has_cabc) + return sprintf(buf, "%s\n", acx565akm_cabc_modes[0]); + + for (i = 0; i < ARRAY_SIZE(acx565akm_cabc_modes); i++) + len += sprintf(&buf[len], "%s%s", i ? " " : "", + acx565akm_cabc_modes[i]); + + buf[len++] = '\n'; + + return len; +} + +static DEVICE_ATTR_RW(cabc_mode); +static DEVICE_ATTR_RO(cabc_available_modes); + +static struct attribute *acx565akm_cabc_attrs[] = { + &dev_attr_cabc_mode.attr, + &dev_attr_cabc_available_modes.attr, + NULL, +}; + +static const struct attribute_group acx565akm_cabc_attr_group = { + .attrs = acx565akm_cabc_attrs, +}; + +/* ----------------------------------------------------------------------------- + * Backlight Device + */ + +static int acx565akm_get_actual_brightness(struct acx565akm_panel *lcd) +{ + u8 bv; + + acx565akm_read(lcd, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, &bv, 1); + + return bv; +} + +static void acx565akm_set_brightness(struct acx565akm_panel *lcd, int level) +{ + u16 ctrl; + int bv; + + bv = level | (1 << 8); + acx565akm_write(lcd, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, (u8 *)&bv, 2); + + acx565akm_read(lcd, MIPI_DCS_GET_CONTROL_DISPLAY, (u8 *)&ctrl, 1); + if (level) + ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON | + CTRL_DISP_BACKLIGHT_ON; + else + ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON | + CTRL_DISP_BACKLIGHT_ON); + + ctrl |= 1 << 8; + acx565akm_write(lcd, MIPI_DCS_WRITE_CONTROL_DISPLAY, (u8 *)&ctrl, 2); +} + +static int acx565akm_bl_update_status_locked(struct backlight_device *dev) +{ + struct acx565akm_panel *lcd = dev_get_drvdata(&dev->dev); + int level; + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) + level = dev->props.brightness; + else + level = 0; + + acx565akm_set_brightness(lcd, level); + + return 0; +} + +static int acx565akm_bl_update_status(struct backlight_device *dev) +{ + struct acx565akm_panel *lcd = dev_get_drvdata(&dev->dev); + int ret; + + mutex_lock(&lcd->mutex); + ret = acx565akm_bl_update_status_locked(dev); + mutex_unlock(&lcd->mutex); + + return ret; +} + +static int acx565akm_bl_get_intensity(struct backlight_device *dev) +{ + struct acx565akm_panel *lcd = dev_get_drvdata(&dev->dev); + unsigned int intensity; + + mutex_lock(&lcd->mutex); + + if (dev->props.fb_blank == FB_BLANK_UNBLANK && + dev->props.power == FB_BLANK_UNBLANK) + intensity = acx565akm_get_actual_brightness(lcd); + else + intensity = 0; + + mutex_unlock(&lcd->mutex); + + return intensity; +} + +static const struct backlight_ops acx565akm_bl_ops = { + .get_brightness = acx565akm_bl_get_intensity, + .update_status = acx565akm_bl_update_status, +}; + +static int acx565akm_backlight_init(struct acx565akm_panel *lcd) +{ + struct backlight_properties props = { + .fb_blank = FB_BLANK_UNBLANK, + .power = FB_BLANK_UNBLANK, + .type = BACKLIGHT_RAW, + }; + int ret; + + lcd->backlight = backlight_device_register(lcd->name, &lcd->spi->dev, + lcd, &acx565akm_bl_ops, + &props); + if (IS_ERR(lcd->backlight)) { + ret = PTR_ERR(lcd->backlight); + lcd->backlight = NULL; + return ret; + } + + if (lcd->has_cabc) { + ret = sysfs_create_group(&lcd->backlight->dev.kobj, + &acx565akm_cabc_attr_group); + if (ret < 0) { + dev_err(&lcd->spi->dev, + "%s failed to create sysfs files\n", __func__); + backlight_device_unregister(lcd->backlight); + return ret; + } + + lcd->cabc_mode = acx565akm_get_hw_cabc_mode(lcd); + } + + lcd->backlight->props.max_brightness = 255; + lcd->backlight->props.brightness = acx565akm_get_actual_brightness(lcd); + + acx565akm_bl_update_status_locked(lcd->backlight); + + return 0; +} + +static void acx565akm_backlight_cleanup(struct acx565akm_panel *lcd) +{ + if (lcd->has_cabc) + sysfs_remove_group(&lcd->backlight->dev.kobj, + &acx565akm_cabc_attr_group); + + backlight_device_unregister(lcd->backlight); +} + +/* ----------------------------------------------------------------------------- + * DRM Bridge Operations + */ + +static void acx565akm_set_sleep_mode(struct acx565akm_panel *lcd, int on) +{ + int cmd = on ? MIPI_DCS_ENTER_SLEEP_MODE : MIPI_DCS_EXIT_SLEEP_MODE; + unsigned long wait; + + /* + * We have to keep 120msec between sleep in/out commands. + * (8.2.15, 8.2.16). + */ + wait = lcd->hw_guard_end - jiffies; + if ((long)wait > 0 && wait <= lcd->hw_guard_wait) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(wait); + } + + acx565akm_cmd(lcd, cmd); + + lcd->hw_guard_wait = msecs_to_jiffies(120); + lcd->hw_guard_end = jiffies + lcd->hw_guard_wait; +} + +static void acx565akm_set_display_state(struct acx565akm_panel *lcd, + int enabled) +{ + int cmd = enabled ? MIPI_DCS_SET_DISPLAY_ON : MIPI_DCS_SET_DISPLAY_OFF; + + acx565akm_cmd(lcd, cmd); +} + +static int acx565akm_power_on(struct acx565akm_panel *lcd) +{ + /*FIXME tweak me */ + msleep(50); + + gpiod_set_value(lcd->reset_gpio, 1); + + if (lcd->enabled) { + dev_dbg(&lcd->spi->dev, "panel already enabled\n"); + return 0; + } + + /* + * We have to meet all the following delay requirements: + * 1. tRW: reset pulse width 10usec (7.12.1) + * 2. tRT: reset cancel time 5msec (7.12.1) + * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst + * case (7.6.2) + * 4. 120msec before the sleep out command (7.12.1) + */ + msleep(120); + + acx565akm_set_sleep_mode(lcd, 0); + lcd->enabled = true; + + /* 5msec between sleep out and the next command. (8.2.16) */ + usleep_range(5000, 10000); + acx565akm_set_display_state(lcd, 1); + acx565akm_set_cabc_mode(lcd, lcd->cabc_mode); + + return acx565akm_bl_update_status_locked(lcd->backlight); +} + +static void acx565akm_power_off(struct acx565akm_panel *lcd) +{ + if (!lcd->enabled) + return; + + acx565akm_set_display_state(lcd, 0); + acx565akm_set_sleep_mode(lcd, 1); + lcd->enabled = false; + /* + * We have to provide PCLK,HS,VS signals for 2 frames (worst case + * ~50msec) after sending the sleep in command and asserting the + * reset signal. We probably could assert the reset w/o the delay + * but we still delay to avoid possible artifacts. (7.6.1) + */ + msleep(50); + + gpiod_set_value(lcd->reset_gpio, 0); + + /* FIXME need to tweak this delay */ + msleep(100); +} + +static int acx565akm_disable(struct drm_panel *panel) +{ + struct acx565akm_panel *lcd = to_acx565akm_device(panel); + + mutex_lock(&lcd->mutex); + acx565akm_power_off(lcd); + mutex_unlock(&lcd->mutex); + + return 0; +} + +static int acx565akm_enable(struct drm_panel *panel) +{ + struct acx565akm_panel *lcd = to_acx565akm_device(panel); + + mutex_lock(&lcd->mutex); + acx565akm_power_on(lcd); + mutex_unlock(&lcd->mutex); + + return 0; +} + +static const struct drm_display_mode acx565akm_mode = { + .clock = 24000, + .hdisplay = 800, + .hsync_start = 800 + 28, + .hsync_end = 800 + 28 + 4, + .htotal = 800 + 28 + 4 + 24, + .vdisplay = 480, + .vsync_start = 480 + 3, + .vsync_end = 480 + 3 + 3, + .vtotal = 480 + 3 + 3 + 4, + .vrefresh = 57, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 77, + .height_mm = 46, +}; + +static int acx565akm_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &acx565akm_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = acx565akm_mode.width_mm; + connector->display_info.height_mm = acx565akm_mode.height_mm; + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH + | DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE; + + return 1; +} + +static const struct drm_panel_funcs acx565akm_funcs = { + .disable = acx565akm_disable, + .enable = acx565akm_enable, + .get_modes = acx565akm_get_modes, +}; + +/* ----------------------------------------------------------------------------- + * Probe, Detect and Remove + */ + +static int acx565akm_detect(struct acx565akm_panel *lcd) +{ + __be32 value; + u32 status; + int ret = 0; + + /* + * After being taken out of reset the panel needs 5ms before the first + * command can be sent. + */ + gpiod_set_value(lcd->reset_gpio, 1); + usleep_range(5000, 10000); + + acx565akm_read(lcd, MIPI_DCS_GET_DISPLAY_STATUS, (u8 *)&value, 4); + status = __be32_to_cpu(value); + lcd->enabled = (status & (1 << 17)) && (status & (1 << 10)); + + dev_dbg(&lcd->spi->dev, + "LCD panel %s by bootloader (status 0x%04x)\n", + lcd->enabled ? "enabled" : "disabled ", status); + + acx565akm_read(lcd, MIPI_DCS_GET_DISPLAY_ID, lcd->display_id, 3); + dev_dbg(&lcd->spi->dev, "MIPI display ID: %02x%02x%02x\n", + lcd->display_id[0], lcd->display_id[1], lcd->display_id[2]); + + switch (lcd->display_id[0]) { + case 0x10: + lcd->model = MIPID_VER_ACX565AKM; + lcd->name = "acx565akm"; + lcd->has_bc = 1; + lcd->has_cabc = 1; + break; + case 0x29: + lcd->model = MIPID_VER_L4F00311; + lcd->name = "l4f00311"; + break; + case 0x45: + lcd->model = MIPID_VER_LPH8923; + lcd->name = "lph8923"; + break; + case 0x83: + lcd->model = MIPID_VER_LS041Y3; + lcd->name = "ls041y3"; + break; + default: + lcd->name = "unknown"; + dev_err(&lcd->spi->dev, "unknown display ID\n"); + ret = -ENODEV; + goto done; + } + + lcd->revision = lcd->display_id[1]; + + dev_info(&lcd->spi->dev, "%s rev %02x panel detected\n", + lcd->name, lcd->revision); + +done: + if (!lcd->enabled) + gpiod_set_value(lcd->reset_gpio, 0); + + return ret; +} + +static int acx565akm_probe(struct spi_device *spi) +{ + struct acx565akm_panel *lcd; + int ret; + + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + spi_set_drvdata(spi, lcd); + spi->mode = SPI_MODE_3; + + lcd->spi = spi; + mutex_init(&lcd->mutex); + + lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(lcd->reset_gpio)) { + dev_err(&spi->dev, "failed to get reset GPIO\n"); + return PTR_ERR(lcd->reset_gpio); + } + + ret = acx565akm_detect(lcd); + if (ret < 0) { + dev_err(&spi->dev, "panel detection failed\n"); + return ret; + } + + if (lcd->has_bc) { + ret = acx565akm_backlight_init(lcd); + if (ret < 0) + return ret; + } + + drm_panel_init(&lcd->panel); + lcd->panel.dev = &lcd->spi->dev; + lcd->panel.funcs = &acx565akm_funcs; + + ret = drm_panel_add(&lcd->panel); + if (ret < 0) { + if (lcd->has_bc) + acx565akm_backlight_cleanup(lcd); + return ret; + } + + return 0; +} + +static int acx565akm_remove(struct spi_device *spi) +{ + struct acx565akm_panel *lcd = spi_get_drvdata(spi); + + drm_panel_remove(&lcd->panel); + + if (lcd->has_bc) + acx565akm_backlight_cleanup(lcd); + + drm_panel_disable(&lcd->panel); + drm_panel_unprepare(&lcd->panel); + + return 0; +} + +static const struct of_device_id acx565akm_of_match[] = { + { .compatible = "sony,acx565akm", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, acx565akm_of_match); + +static struct spi_driver acx565akm_driver = { + .probe = acx565akm_probe, + .remove = acx565akm_remove, + .driver = { + .name = "panel-sony-acx565akm", + .of_match_table = acx565akm_of_match, + }, +}; + +module_spi_driver(acx565akm_driver); + +MODULE_ALIAS("spi:sony,acx565akm"); +MODULE_AUTHOR("Nokia Corporation"); +MODULE_DESCRIPTION("Sony ACX565AKM LCD Panel Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c new file mode 100644 index 000000000000..d7b2e34626ef --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tpo-td028ttec1.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Toppoly TD028TTEC1 Panel Driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific panel-tpo-td028ttec1 driver + * + * Copyright (C) 2008 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * Neo 1973 code (jbt6k74.c): + * Copyright (C) 2006-2007 OpenMoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * + * Ported and adapted from Neo 1973 U-Boot by: + * H. Nikolaus Schaller <hns@goldelico.com> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#define JBT_COMMAND 0x000 +#define JBT_DATA 0x100 + +#define JBT_REG_SLEEP_IN 0x10 +#define JBT_REG_SLEEP_OUT 0x11 + +#define JBT_REG_DISPLAY_OFF 0x28 +#define JBT_REG_DISPLAY_ON 0x29 + +#define JBT_REG_RGB_FORMAT 0x3a +#define JBT_REG_QUAD_RATE 0x3b + +#define JBT_REG_POWER_ON_OFF 0xb0 +#define JBT_REG_BOOSTER_OP 0xb1 +#define JBT_REG_BOOSTER_MODE 0xb2 +#define JBT_REG_BOOSTER_FREQ 0xb3 +#define JBT_REG_OPAMP_SYSCLK 0xb4 +#define JBT_REG_VSC_VOLTAGE 0xb5 +#define JBT_REG_VCOM_VOLTAGE 0xb6 +#define JBT_REG_EXT_DISPL 0xb7 +#define JBT_REG_OUTPUT_CONTROL 0xb8 +#define JBT_REG_DCCLK_DCEV 0xb9 +#define JBT_REG_DISPLAY_MODE1 0xba +#define JBT_REG_DISPLAY_MODE2 0xbb +#define JBT_REG_DISPLAY_MODE 0xbc +#define JBT_REG_ASW_SLEW 0xbd +#define JBT_REG_DUMMY_DISPLAY 0xbe +#define JBT_REG_DRIVE_SYSTEM 0xbf + +#define JBT_REG_SLEEP_OUT_FR_A 0xc0 +#define JBT_REG_SLEEP_OUT_FR_B 0xc1 +#define JBT_REG_SLEEP_OUT_FR_C 0xc2 +#define JBT_REG_SLEEP_IN_LCCNT_D 0xc3 +#define JBT_REG_SLEEP_IN_LCCNT_E 0xc4 +#define JBT_REG_SLEEP_IN_LCCNT_F 0xc5 +#define JBT_REG_SLEEP_IN_LCCNT_G 0xc6 + +#define JBT_REG_GAMMA1_FINE_1 0xc7 +#define JBT_REG_GAMMA1_FINE_2 0xc8 +#define JBT_REG_GAMMA1_INCLINATION 0xc9 +#define JBT_REG_GAMMA1_BLUE_OFFSET 0xca + +#define JBT_REG_BLANK_CONTROL 0xcf +#define JBT_REG_BLANK_TH_TV 0xd0 +#define JBT_REG_CKV_ON_OFF 0xd1 +#define JBT_REG_CKV_1_2 0xd2 +#define JBT_REG_OEV_TIMING 0xd3 +#define JBT_REG_ASW_TIMING_1 0xd4 +#define JBT_REG_ASW_TIMING_2 0xd5 + +#define JBT_REG_HCLOCK_VGA 0xec +#define JBT_REG_HCLOCK_QVGA 0xed + +struct td028ttec1_panel { + struct drm_panel panel; + + struct spi_device *spi; + struct backlight_device *backlight; +}; + +#define to_td028ttec1_device(p) container_of(p, struct td028ttec1_panel, panel) + +static int jbt_ret_write_0(struct td028ttec1_panel *lcd, u8 reg, int *err) +{ + struct spi_device *spi = lcd->spi; + u16 tx_buf = JBT_COMMAND | reg; + int ret; + + if (err && *err) + return *err; + + ret = spi_write(spi, (u8 *)&tx_buf, sizeof(tx_buf)); + if (ret < 0) { + dev_err(&spi->dev, "%s: SPI write failed: %d\n", __func__, ret); + if (err) + *err = ret; + } + + return ret; +} + +static int jbt_reg_write_1(struct td028ttec1_panel *lcd, + u8 reg, u8 data, int *err) +{ + struct spi_device *spi = lcd->spi; + u16 tx_buf[2]; + int ret; + + if (err && *err) + return *err; + + tx_buf[0] = JBT_COMMAND | reg; + tx_buf[1] = JBT_DATA | data; + + ret = spi_write(spi, (u8 *)tx_buf, sizeof(tx_buf)); + if (ret < 0) { + dev_err(&spi->dev, "%s: SPI write failed: %d\n", __func__, ret); + if (err) + *err = ret; + } + + return ret; +} + +static int jbt_reg_write_2(struct td028ttec1_panel *lcd, + u8 reg, u16 data, int *err) +{ + struct spi_device *spi = lcd->spi; + u16 tx_buf[3]; + int ret; + + if (err && *err) + return *err; + + tx_buf[0] = JBT_COMMAND | reg; + tx_buf[1] = JBT_DATA | (data >> 8); + tx_buf[2] = JBT_DATA | (data & 0xff); + + ret = spi_write(spi, (u8 *)tx_buf, sizeof(tx_buf)); + if (ret < 0) { + dev_err(&spi->dev, "%s: SPI write failed: %d\n", __func__, ret); + if (err) + *err = ret; + } + + return ret; +} + +static int td028ttec1_prepare(struct drm_panel *panel) +{ + struct td028ttec1_panel *lcd = to_td028ttec1_device(panel); + unsigned int i; + int ret = 0; + + /* Three times command zero */ + for (i = 0; i < 3; ++i) { + jbt_ret_write_0(lcd, 0x00, &ret); + usleep_range(1000, 2000); + } + + /* deep standby out */ + jbt_reg_write_1(lcd, JBT_REG_POWER_ON_OFF, 0x17, &ret); + + /* RGB I/F on, RAM write off, QVGA through, SIGCON enable */ + jbt_reg_write_1(lcd, JBT_REG_DISPLAY_MODE, 0x80, &ret); + + /* Quad mode off */ + jbt_reg_write_1(lcd, JBT_REG_QUAD_RATE, 0x00, &ret); + + /* AVDD on, XVDD on */ + jbt_reg_write_1(lcd, JBT_REG_POWER_ON_OFF, 0x16, &ret); + + /* Output control */ + jbt_reg_write_2(lcd, JBT_REG_OUTPUT_CONTROL, 0xfff9, &ret); + + /* Sleep mode off */ + jbt_ret_write_0(lcd, JBT_REG_SLEEP_OUT, &ret); + + /* at this point we have like 50% grey */ + + /* initialize register set */ + jbt_reg_write_1(lcd, JBT_REG_DISPLAY_MODE1, 0x01, &ret); + jbt_reg_write_1(lcd, JBT_REG_DISPLAY_MODE2, 0x00, &ret); + jbt_reg_write_1(lcd, JBT_REG_RGB_FORMAT, 0x60, &ret); + jbt_reg_write_1(lcd, JBT_REG_DRIVE_SYSTEM, 0x10, &ret); + jbt_reg_write_1(lcd, JBT_REG_BOOSTER_OP, 0x56, &ret); + jbt_reg_write_1(lcd, JBT_REG_BOOSTER_MODE, 0x33, &ret); + jbt_reg_write_1(lcd, JBT_REG_BOOSTER_FREQ, 0x11, &ret); + jbt_reg_write_1(lcd, JBT_REG_BOOSTER_FREQ, 0x11, &ret); + jbt_reg_write_1(lcd, JBT_REG_OPAMP_SYSCLK, 0x02, &ret); + jbt_reg_write_1(lcd, JBT_REG_VSC_VOLTAGE, 0x2b, &ret); + jbt_reg_write_1(lcd, JBT_REG_VCOM_VOLTAGE, 0x40, &ret); + jbt_reg_write_1(lcd, JBT_REG_EXT_DISPL, 0x03, &ret); + jbt_reg_write_1(lcd, JBT_REG_DCCLK_DCEV, 0x04, &ret); + /* + * default of 0x02 in JBT_REG_ASW_SLEW responsible for 72Hz requirement + * to avoid red / blue flicker + */ + jbt_reg_write_1(lcd, JBT_REG_ASW_SLEW, 0x04, &ret); + jbt_reg_write_1(lcd, JBT_REG_DUMMY_DISPLAY, 0x00, &ret); + + jbt_reg_write_1(lcd, JBT_REG_SLEEP_OUT_FR_A, 0x11, &ret); + jbt_reg_write_1(lcd, JBT_REG_SLEEP_OUT_FR_B, 0x11, &ret); + jbt_reg_write_1(lcd, JBT_REG_SLEEP_OUT_FR_C, 0x11, &ret); + jbt_reg_write_2(lcd, JBT_REG_SLEEP_IN_LCCNT_D, 0x2040, &ret); + jbt_reg_write_2(lcd, JBT_REG_SLEEP_IN_LCCNT_E, 0x60c0, &ret); + jbt_reg_write_2(lcd, JBT_REG_SLEEP_IN_LCCNT_F, 0x1020, &ret); + jbt_reg_write_2(lcd, JBT_REG_SLEEP_IN_LCCNT_G, 0x60c0, &ret); + + jbt_reg_write_2(lcd, JBT_REG_GAMMA1_FINE_1, 0x5533, &ret); + jbt_reg_write_1(lcd, JBT_REG_GAMMA1_FINE_2, 0x00, &ret); + jbt_reg_write_1(lcd, JBT_REG_GAMMA1_INCLINATION, 0x00, &ret); + jbt_reg_write_1(lcd, JBT_REG_GAMMA1_BLUE_OFFSET, 0x00, &ret); + + jbt_reg_write_2(lcd, JBT_REG_HCLOCK_VGA, 0x1f0, &ret); + jbt_reg_write_1(lcd, JBT_REG_BLANK_CONTROL, 0x02, &ret); + jbt_reg_write_2(lcd, JBT_REG_BLANK_TH_TV, 0x0804, &ret); + + jbt_reg_write_1(lcd, JBT_REG_CKV_ON_OFF, 0x01, &ret); + jbt_reg_write_2(lcd, JBT_REG_CKV_1_2, 0x0000, &ret); + + jbt_reg_write_2(lcd, JBT_REG_OEV_TIMING, 0x0d0e, &ret); + jbt_reg_write_2(lcd, JBT_REG_ASW_TIMING_1, 0x11a4, &ret); + jbt_reg_write_1(lcd, JBT_REG_ASW_TIMING_2, 0x0e, &ret); + + return ret; +} + +static int td028ttec1_enable(struct drm_panel *panel) +{ + struct td028ttec1_panel *lcd = to_td028ttec1_device(panel); + int ret; + + ret = jbt_ret_write_0(lcd, JBT_REG_DISPLAY_ON, NULL); + if (ret) + return ret; + + backlight_enable(lcd->backlight); + + return 0; +} + +static int td028ttec1_disable(struct drm_panel *panel) +{ + struct td028ttec1_panel *lcd = to_td028ttec1_device(panel); + + backlight_disable(lcd->backlight); + + jbt_ret_write_0(lcd, JBT_REG_DISPLAY_OFF, NULL); + + return 0; +} + +static int td028ttec1_unprepare(struct drm_panel *panel) +{ + struct td028ttec1_panel *lcd = to_td028ttec1_device(panel); + + jbt_reg_write_2(lcd, JBT_REG_OUTPUT_CONTROL, 0x8002, NULL); + jbt_ret_write_0(lcd, JBT_REG_SLEEP_IN, NULL); + jbt_reg_write_1(lcd, JBT_REG_POWER_ON_OFF, 0x00, NULL); + + return 0; +} + +static const struct drm_display_mode td028ttec1_mode = { + .clock = 22153, + .hdisplay = 480, + .hsync_start = 480 + 24, + .hsync_end = 480 + 24 + 8, + .htotal = 480 + 24 + 8 + 8, + .vdisplay = 640, + .vsync_start = 640 + 4, + .vsync_end = 640 + 4 + 2, + .vtotal = 640 + 4 + 2 + 2, + .vrefresh = 66, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 43, + .height_mm = 58, +}; + +static int td028ttec1_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &td028ttec1_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = td028ttec1_mode.width_mm; + connector->display_info.height_mm = td028ttec1_mode.height_mm; + /* + * FIXME: According to the datasheet sync signals are sampled on the + * rising edge of the clock, but the code running on the OpenMoko Neo + * FreeRunner and Neo 1973 indicates sampling on the falling edge. This + * should be tested on a real device. + */ + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH + | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE; + + return 1; +} + +static const struct drm_panel_funcs td028ttec1_funcs = { + .prepare = td028ttec1_prepare, + .enable = td028ttec1_enable, + .disable = td028ttec1_disable, + .unprepare = td028ttec1_unprepare, + .get_modes = td028ttec1_get_modes, +}; + +static int td028ttec1_probe(struct spi_device *spi) +{ + struct td028ttec1_panel *lcd; + int ret; + + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + spi_set_drvdata(spi, lcd); + lcd->spi = spi; + + lcd->backlight = devm_of_find_backlight(&spi->dev); + if (IS_ERR(lcd->backlight)) + return PTR_ERR(lcd->backlight); + + spi->mode = SPI_MODE_3; + spi->bits_per_word = 9; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "failed to setup SPI: %d\n", ret); + return ret; + } + + drm_panel_init(&lcd->panel); + lcd->panel.dev = &lcd->spi->dev; + lcd->panel.funcs = &td028ttec1_funcs; + + return drm_panel_add(&lcd->panel); +} + +static int td028ttec1_remove(struct spi_device *spi) +{ + struct td028ttec1_panel *lcd = spi_get_drvdata(spi); + + drm_panel_remove(&lcd->panel); + drm_panel_disable(&lcd->panel); + drm_panel_unprepare(&lcd->panel); + + return 0; +} + +static const struct of_device_id td028ttec1_of_match[] = { + { .compatible = "tpo,td028ttec1", }, + /* DT backward compatibility. */ + { .compatible = "toppoly,td028ttec1", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, td028ttec1_of_match); + +static const struct spi_device_id td028ttec1_ids[] = { + { "tpo,td028ttec1", 0}, + { "toppoly,td028ttec1", 0 }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(spi, td028ttec1_ids); + +static struct spi_driver td028ttec1_driver = { + .probe = td028ttec1_probe, + .remove = td028ttec1_remove, + .id_table = td028ttec1_ids, + .driver = { + .name = "panel-tpo-td028ttec1", + .of_match_table = td028ttec1_of_match, + }, +}; + +module_spi_driver(td028ttec1_driver); + +MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>"); +MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c new file mode 100644 index 000000000000..84370562910f --- /dev/null +++ b/drivers/gpu/drm/panel/panel-tpo-td043mtea1.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Toppoly TD043MTEA1 Panel Driver + * + * Copyright (C) 2019 Texas Instruments Incorporated + * + * Based on the omapdrm-specific panel-tpo-td043mtea1 driver + * + * Author: Gražvydas Ignotas <notasas@gmail.com> + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> + +#include <drm/drm_connector.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +#define TPO_R02_MODE(x) ((x) & 7) +#define TPO_R02_MODE_800x480 7 +#define TPO_R02_NCLK_RISING BIT(3) +#define TPO_R02_HSYNC_HIGH BIT(4) +#define TPO_R02_VSYNC_HIGH BIT(5) + +#define TPO_R03_NSTANDBY BIT(0) +#define TPO_R03_EN_CP_CLK BIT(1) +#define TPO_R03_EN_VGL_PUMP BIT(2) +#define TPO_R03_EN_PWM BIT(3) +#define TPO_R03_DRIVING_CAP_100 BIT(4) +#define TPO_R03_EN_PRE_CHARGE BIT(6) +#define TPO_R03_SOFTWARE_CTL BIT(7) + +#define TPO_R04_NFLIP_H BIT(0) +#define TPO_R04_NFLIP_V BIT(1) +#define TPO_R04_CP_CLK_FREQ_1H BIT(2) +#define TPO_R04_VGL_FREQ_1H BIT(4) + +#define TPO_R03_VAL_NORMAL \ + (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | TPO_R03_EN_VGL_PUMP | \ + TPO_R03_EN_PWM | TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ + TPO_R03_SOFTWARE_CTL) + +#define TPO_R03_VAL_STANDBY \ + (TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \ + TPO_R03_SOFTWARE_CTL) + +static const u16 td043mtea1_def_gamma[12] = { + 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 +}; + +struct td043mtea1_panel { + struct drm_panel panel; + + struct spi_device *spi; + struct regulator *vcc_reg; + struct gpio_desc *reset_gpio; + + unsigned int mode; + u16 gamma[12]; + bool vmirror; + bool powered_on; + bool spi_suspended; + bool power_on_resume; +}; + +#define to_td043mtea1_device(p) container_of(p, struct td043mtea1_panel, panel) + +/* ----------------------------------------------------------------------------- + * Hardware Access + */ + +static int td043mtea1_write(struct td043mtea1_panel *lcd, u8 addr, u8 value) +{ + struct spi_message msg; + struct spi_transfer xfer; + u16 data; + int ret; + + spi_message_init(&msg); + + memset(&xfer, 0, sizeof(xfer)); + + data = ((u16)addr << 10) | (1 << 8) | value; + xfer.tx_buf = &data; + xfer.bits_per_word = 16; + xfer.len = 2; + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(lcd->spi, &msg); + if (ret < 0) + dev_warn(&lcd->spi->dev, "failed to write to LCD reg (%d)\n", + ret); + + return ret; +} + +static void td043mtea1_write_gamma(struct td043mtea1_panel *lcd) +{ + const u16 *gamma = lcd->gamma; + unsigned int i; + u8 val; + + /* gamma bits [9:8] */ + for (val = i = 0; i < 4; i++) + val |= (gamma[i] & 0x300) >> ((i + 1) * 2); + td043mtea1_write(lcd, 0x11, val); + + for (val = i = 0; i < 4; i++) + val |= (gamma[i + 4] & 0x300) >> ((i + 1) * 2); + td043mtea1_write(lcd, 0x12, val); + + for (val = i = 0; i < 4; i++) + val |= (gamma[i + 8] & 0x300) >> ((i + 1) * 2); + td043mtea1_write(lcd, 0x13, val); + + /* gamma bits [7:0] */ + for (i = 0; i < 12; i++) + td043mtea1_write(lcd, 0x14 + i, gamma[i] & 0xff); +} + +static int td043mtea1_write_mirror(struct td043mtea1_panel *lcd) +{ + u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | + TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H; + if (lcd->vmirror) + reg4 &= ~TPO_R04_NFLIP_V; + + return td043mtea1_write(lcd, 4, reg4); +} + +static int td043mtea1_power_on(struct td043mtea1_panel *lcd) +{ + int ret; + + if (lcd->powered_on) + return 0; + + ret = regulator_enable(lcd->vcc_reg); + if (ret < 0) + return ret; + + /* Wait for the panel to stabilize. */ + msleep(160); + + gpiod_set_value(lcd->reset_gpio, 0); + + td043mtea1_write(lcd, 2, TPO_R02_MODE(lcd->mode) | TPO_R02_NCLK_RISING); + td043mtea1_write(lcd, 3, TPO_R03_VAL_NORMAL); + td043mtea1_write(lcd, 0x20, 0xf0); + td043mtea1_write(lcd, 0x21, 0xf0); + td043mtea1_write_mirror(lcd); + td043mtea1_write_gamma(lcd); + + lcd->powered_on = true; + + return 0; +} + +static void td043mtea1_power_off(struct td043mtea1_panel *lcd) +{ + if (!lcd->powered_on) + return; + + td043mtea1_write(lcd, 3, TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); + + gpiod_set_value(lcd->reset_gpio, 1); + + /* wait for at least 2 vsyncs before cutting off power */ + msleep(50); + + td043mtea1_write(lcd, 3, TPO_R03_VAL_STANDBY); + + regulator_disable(lcd->vcc_reg); + + lcd->powered_on = false; +} + +/* ----------------------------------------------------------------------------- + * sysfs + */ + +static ssize_t vmirror_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", lcd->vmirror); +} + +static ssize_t vmirror_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + int val; + int ret; + + ret = kstrtoint(buf, 0, &val); + if (ret < 0) + return ret; + + lcd->vmirror = !!val; + + ret = td043mtea1_write_mirror(lcd); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", lcd->mode); +} + +static ssize_t mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + if (ret != 0 || val & ~7) + return -EINVAL; + + lcd->mode = val; + + val |= TPO_R02_NCLK_RISING; + td043mtea1_write(lcd, 2, val); + + return count; +} + +static ssize_t gamma_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(lcd->gamma); i++) { + ret = snprintf(buf + len, PAGE_SIZE - len, "%u ", + lcd->gamma[i]); + if (ret < 0) + return ret; + len += ret; + } + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t gamma_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + unsigned int g[12]; + unsigned int i; + int ret; + + ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u", + &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], + &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]); + if (ret != 12) + return -EINVAL; + + for (i = 0; i < 12; i++) + lcd->gamma[i] = g[i]; + + td043mtea1_write_gamma(lcd); + + return count; +} + +static DEVICE_ATTR_RW(vmirror); +static DEVICE_ATTR_RW(mode); +static DEVICE_ATTR_RW(gamma); + +static struct attribute *td043mtea1_attrs[] = { + &dev_attr_vmirror.attr, + &dev_attr_mode.attr, + &dev_attr_gamma.attr, + NULL, +}; + +static const struct attribute_group td043mtea1_attr_group = { + .attrs = td043mtea1_attrs, +}; + +/* ----------------------------------------------------------------------------- + * Panel Operations + */ + +static int td043mtea1_unprepare(struct drm_panel *panel) +{ + struct td043mtea1_panel *lcd = to_td043mtea1_device(panel); + + if (!lcd->spi_suspended) + td043mtea1_power_off(lcd); + + return 0; +} + +static int td043mtea1_prepare(struct drm_panel *panel) +{ + struct td043mtea1_panel *lcd = to_td043mtea1_device(panel); + int ret; + + /* + * If we are resuming from system suspend, SPI might not be enabled + * yet, so we'll program the LCD from SPI PM resume callback. + */ + if (lcd->spi_suspended) + return 0; + + ret = td043mtea1_power_on(lcd); + if (ret) { + dev_err(&lcd->spi->dev, "%s: power on failed (%d)\n", + __func__, ret); + return ret; + } + + return 0; +} + +static const struct drm_display_mode td043mtea1_mode = { + .clock = 36000, + .hdisplay = 800, + .hsync_start = 800 + 68, + .hsync_end = 800 + 68 + 1, + .htotal = 800 + 68 + 1 + 214, + .vdisplay = 480, + .vsync_start = 480 + 39, + .vsync_end = 480 + 39 + 1, + .vtotal = 480 + 39 + 1 + 34, + .vrefresh = 60, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 94, + .height_mm = 56, +}; + +static int td043mtea1_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(panel->drm, &td043mtea1_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + connector->display_info.width_mm = td043mtea1_mode.width_mm; + connector->display_info.height_mm = td043mtea1_mode.height_mm; + /* + * FIXME: According to the datasheet sync signals are sampled on the + * rising edge of the clock, but the code running on the OMAP3 Pandora + * indicates sampling on the falling edge. This should be tested on a + * real device. + */ + connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH + | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE; + + return 1; +} + +static const struct drm_panel_funcs td043mtea1_funcs = { + .unprepare = td043mtea1_unprepare, + .prepare = td043mtea1_prepare, + .get_modes = td043mtea1_get_modes, +}; + +/* ----------------------------------------------------------------------------- + * Power Management, Probe and Remove + */ + +static int __maybe_unused td043mtea1_suspend(struct device *dev) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + + if (lcd->powered_on) { + td043mtea1_power_off(lcd); + lcd->powered_on = true; + } + + lcd->spi_suspended = true; + + return 0; +} + +static int __maybe_unused td043mtea1_resume(struct device *dev) +{ + struct td043mtea1_panel *lcd = dev_get_drvdata(dev); + int ret; + + lcd->spi_suspended = false; + + if (lcd->powered_on) { + lcd->powered_on = false; + ret = td043mtea1_power_on(lcd); + if (ret) + return ret; + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(td043mtea1_pm_ops, td043mtea1_suspend, + td043mtea1_resume); + +static int td043mtea1_probe(struct spi_device *spi) +{ + struct td043mtea1_panel *lcd; + int ret; + + lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); + if (lcd == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, lcd); + lcd->spi = spi; + lcd->mode = TPO_R02_MODE_800x480; + memcpy(lcd->gamma, td043mtea1_def_gamma, sizeof(lcd->gamma)); + + lcd->vcc_reg = devm_regulator_get(&spi->dev, "vcc"); + if (IS_ERR(lcd->vcc_reg)) { + dev_err(&spi->dev, "failed to get VCC regulator\n"); + return PTR_ERR(lcd->vcc_reg); + } + + lcd->reset_gpio = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(lcd->reset_gpio)) { + dev_err(&spi->dev, "failed to get reset GPIO\n"); + return PTR_ERR(lcd->reset_gpio); + } + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_0; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "failed to setup SPI: %d\n", ret); + return ret; + } + + ret = sysfs_create_group(&spi->dev.kobj, &td043mtea1_attr_group); + if (ret < 0) { + dev_err(&spi->dev, "failed to create sysfs files\n"); + return ret; + } + + drm_panel_init(&lcd->panel); + lcd->panel.dev = &lcd->spi->dev; + lcd->panel.funcs = &td043mtea1_funcs; + + ret = drm_panel_add(&lcd->panel); + if (ret < 0) { + sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group); + return ret; + } + + return 0; +} + +static int td043mtea1_remove(struct spi_device *spi) +{ + struct td043mtea1_panel *lcd = spi_get_drvdata(spi); + + drm_panel_remove(&lcd->panel); + drm_panel_disable(&lcd->panel); + drm_panel_unprepare(&lcd->panel); + + sysfs_remove_group(&spi->dev.kobj, &td043mtea1_attr_group); + + return 0; +} + +static const struct of_device_id td043mtea1_of_match[] = { + { .compatible = "tpo,td043mtea1", }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, td043mtea1_of_match); + +static struct spi_driver td043mtea1_driver = { + .probe = td043mtea1_probe, + .remove = td043mtea1_remove, + .driver = { + .name = "panel-tpo-td043mtea1", + .pm = &td043mtea1_pm_ops, + .of_match_table = td043mtea1_of_match, + }, +}; + +module_spi_driver(td043mtea1_driver); + +MODULE_ALIAS("spi:tpo,td043mtea1"); +MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); +MODULE_DESCRIPTION("TPO TD043MTEA1 Panel Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile index ecf0864cb515..b71935862417 100644 --- a/drivers/gpu/drm/panfrost/Makefile +++ b/drivers/gpu/drm/panfrost/Makefile @@ -5,6 +5,7 @@ panfrost-y := \ panfrost_device.o \ panfrost_devfreq.o \ panfrost_gem.o \ + panfrost_gem_shrinker.o \ panfrost_gpu.o \ panfrost_job.o \ panfrost_mmu.o \ diff --git a/drivers/gpu/drm/panfrost/TODO b/drivers/gpu/drm/panfrost/TODO index c2e44add37d8..e7727b292355 100644 --- a/drivers/gpu/drm/panfrost/TODO +++ b/drivers/gpu/drm/panfrost/TODO @@ -6,22 +6,11 @@ - Bifrost specific feature and issue handling - Coherent DMA support -- Support for 2MB pages. The io-pgtable code already supports this. Finishing - support involves either copying or adapting the iommu API to handle passing - aligned addresses and sizes to the io-pgtable code. - - Per FD address space support. The h/w supports multiple addresses spaces. The hard part is handling when more address spaces are needed than what the h/w provides. -- Support pinning pages on demand (GPU page faults). - - Support userspace controlled GPU virtual addresses. Needed for Vulkan. (Tomeu) -- Support for madvise and a shrinker. - - Compute job support. So called 'compute only' jobs need to be plumbed up to userspace. - -- Performance counter support. (Boris) - diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index 8a111d7c0200..9814f4ccbd26 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -254,18 +254,22 @@ const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception return "UNKNOWN"; } +void panfrost_device_reset(struct panfrost_device *pfdev) +{ + panfrost_gpu_soft_reset(pfdev); + + panfrost_gpu_power_on(pfdev); + panfrost_mmu_reset(pfdev); + panfrost_job_enable_interrupts(pfdev); +} + #ifdef CONFIG_PM int panfrost_device_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct panfrost_device *pfdev = platform_get_drvdata(pdev); - panfrost_gpu_soft_reset(pfdev); - - /* TODO: Re-enable all other address spaces */ - panfrost_gpu_power_on(pfdev); - panfrost_mmu_enable(pfdev, 0); - panfrost_job_enable_interrupts(pfdev); + panfrost_device_reset(pfdev); panfrost_devfreq_resume(pfdev); return 0; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index ea5948ff3647..4e5641db9c7e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -85,6 +85,10 @@ struct panfrost_device { struct mutex sched_lock; struct mutex reset_lock; + struct mutex shrinker_lock; + struct list_head shrinker_list; + struct shrinker shrinker; + struct { struct devfreq *devfreq; struct thermal_cooling_device *cooling; @@ -128,6 +132,7 @@ int panfrost_unstable_ioctl_check(void); int panfrost_device_init(struct panfrost_device *pfdev); void panfrost_device_fini(struct panfrost_device *pfdev); +void panfrost_device_reset(struct panfrost_device *pfdev); int panfrost_device_resume(struct device *dev); int panfrost_device_suspend(struct device *dev); diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index b187daa4da85..b41754658681 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -78,29 +78,26 @@ static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file *file) { - int ret; - struct drm_gem_shmem_object *shmem; + struct panfrost_gem_object *bo; struct drm_panfrost_create_bo *args = data; - if (!args->size || args->flags || args->pad) + if (!args->size || args->pad || + (args->flags & ~(PANFROST_BO_NOEXEC | PANFROST_BO_HEAP))) return -EINVAL; - shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, - &args->handle); - if (IS_ERR(shmem)) - return PTR_ERR(shmem); + /* Heaps should never be executable */ + if ((args->flags & PANFROST_BO_HEAP) && + !(args->flags & PANFROST_BO_NOEXEC)) + return -EINVAL; - ret = panfrost_mmu_map(to_panfrost_bo(&shmem->base)); - if (ret) - goto err_free; + bo = panfrost_gem_create_with_handle(file, dev, args->size, args->flags, + &args->handle); + if (IS_ERR(bo)) + return PTR_ERR(bo); - args->offset = to_panfrost_bo(&shmem->base)->node.start << PAGE_SHIFT; + args->offset = bo->node.start << PAGE_SHIFT; return 0; - -err_free: - drm_gem_handle_delete(file, args->handle); - return ret; } /** @@ -277,7 +274,7 @@ panfrost_ioctl_wait_bo(struct drm_device *dev, void *data, if (!gem_obj) return -ENOENT; - ret = reservation_object_wait_timeout_rcu(gem_obj->resv, true, + ret = dma_resv_wait_timeout_rcu(gem_obj->resv, true, true, timeout); if (!ret) ret = timeout ? -ETIMEDOUT : -EBUSY; @@ -305,6 +302,10 @@ static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data, return -ENOENT; } + /* Don't allow mmapping of heap objects as pages are not pinned. */ + if (to_panfrost_bo(gem_obj)->is_heap) + return -EINVAL; + ret = drm_gem_create_mmap_offset(gem_obj); if (ret == 0) args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); @@ -333,6 +334,38 @@ static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data, return 0; } +static int panfrost_ioctl_madvise(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_panfrost_madvise *args = data; + struct panfrost_device *pfdev = dev->dev_private; + struct drm_gem_object *gem_obj; + + gem_obj = drm_gem_object_lookup(file_priv, args->handle); + if (!gem_obj) { + DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); + return -ENOENT; + } + + args->retained = drm_gem_shmem_madvise(gem_obj, args->madv); + + if (args->retained) { + struct panfrost_gem_object *bo = to_panfrost_bo(gem_obj); + + mutex_lock(&pfdev->shrinker_lock); + + if (args->madv == PANFROST_MADV_DONTNEED) + list_add_tail(&bo->base.madv_list, &pfdev->shrinker_list); + else if (args->madv == PANFROST_MADV_WILLNEED) + list_del_init(&bo->base.madv_list); + + mutex_unlock(&pfdev->shrinker_lock); + } + + drm_gem_object_put_unlocked(gem_obj); + return 0; +} + int panfrost_unstable_ioctl_check(void) { if (!unstable_ioctls) @@ -341,6 +374,32 @@ int panfrost_unstable_ioctl_check(void) return 0; } +#define PFN_4G (SZ_4G >> PAGE_SHIFT) +#define PFN_4G_MASK (PFN_4G - 1) +#define PFN_16M (SZ_16M >> PAGE_SHIFT) + +static void panfrost_drm_mm_color_adjust(const struct drm_mm_node *node, + unsigned long color, + u64 *start, u64 *end) +{ + /* Executable buffers can't start or end on a 4GB boundary */ + if (!(color & PANFROST_BO_NOEXEC)) { + u64 next_seg; + + if ((*start & PFN_4G_MASK) == 0) + (*start)++; + + if ((*end & PFN_4G_MASK) == 0) + (*end)--; + + next_seg = ALIGN(*start, PFN_4G); + if (next_seg - *start <= PFN_16M) + *start = next_seg + 1; + + *end = min(*end, ALIGN(*start, PFN_4G) - 1); + } +} + static int panfrost_open(struct drm_device *dev, struct drm_file *file) { @@ -384,10 +443,16 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW), PANFROST_IOCTL(PERFCNT_ENABLE, perfcnt_enable, DRM_RENDER_ALLOW), PANFROST_IOCTL(PERFCNT_DUMP, perfcnt_dump, DRM_RENDER_ALLOW), + PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW), }; DEFINE_DRM_GEM_SHMEM_FOPS(panfrost_drm_driver_fops); +/* + * Panfrost driver version: + * - 1.0 - initial interface + * - 1.1 - adds HEAP and NOEXEC flags for CREATE_BO + */ static struct drm_driver panfrost_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, .open = panfrost_open, @@ -399,7 +464,7 @@ static struct drm_driver panfrost_drm_driver = { .desc = "panfrost DRM", .date = "20180908", .major = 1, - .minor = 0, + .minor = 1, .gem_create_object = panfrost_gem_create_object, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, @@ -432,9 +497,12 @@ static int panfrost_probe(struct platform_device *pdev) pfdev->ddev = ddev; spin_lock_init(&pfdev->mm_lock); + mutex_init(&pfdev->shrinker_lock); + INIT_LIST_HEAD(&pfdev->shrinker_list); /* 4G enough for now. can be 48-bit */ drm_mm_init(&pfdev->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT); + pfdev->mm.color_adjust = panfrost_drm_mm_color_adjust; pm_runtime_use_autosuspend(pfdev->dev); pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */ @@ -462,6 +530,8 @@ static int panfrost_probe(struct platform_device *pdev) if (err < 0) goto err_out1; + panfrost_gem_shrinker_init(ddev); + return 0; err_out1: @@ -478,6 +548,7 @@ static int panfrost_remove(struct platform_device *pdev) struct drm_device *ddev = pfdev->ddev; drm_dev_unregister(ddev); + panfrost_gem_shrinker_cleanup(ddev); pm_runtime_get_sync(pfdev->dev); pm_runtime_put_sync_autosuspend(pfdev->dev); pm_runtime_disable(pfdev->dev); diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index 543ab1b81bd5..e71f27c4041e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -19,20 +19,92 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj) struct panfrost_gem_object *bo = to_panfrost_bo(obj); struct panfrost_device *pfdev = obj->dev->dev_private; + if (bo->sgts) { + int i; + int n_sgt = bo->base.base.size / SZ_2M; + + for (i = 0; i < n_sgt; i++) { + if (bo->sgts[i].sgl) { + dma_unmap_sg(pfdev->dev, bo->sgts[i].sgl, + bo->sgts[i].nents, DMA_BIDIRECTIONAL); + sg_free_table(&bo->sgts[i]); + } + } + kfree(bo->sgts); + } + + mutex_lock(&pfdev->shrinker_lock); + if (!list_empty(&bo->base.madv_list)) + list_del(&bo->base.madv_list); + mutex_unlock(&pfdev->shrinker_lock); + + drm_gem_shmem_free_object(obj); +} + +static int panfrost_gem_open(struct drm_gem_object *obj, struct drm_file *file_priv) +{ + int ret; + size_t size = obj->size; + u64 align; + struct panfrost_gem_object *bo = to_panfrost_bo(obj); + struct panfrost_device *pfdev = obj->dev->dev_private; + unsigned long color = bo->noexec ? PANFROST_BO_NOEXEC : 0; + + /* + * Executable buffers cannot cross a 16MB boundary as the program + * counter is 24-bits. We assume executable buffers will be less than + * 16MB and aligning executable buffers to their size will avoid + * crossing a 16MB boundary. + */ + if (!bo->noexec) + align = size >> PAGE_SHIFT; + else + align = size >= SZ_2M ? SZ_2M >> PAGE_SHIFT : 0; + + spin_lock(&pfdev->mm_lock); + ret = drm_mm_insert_node_generic(&pfdev->mm, &bo->node, + size >> PAGE_SHIFT, align, color, 0); + if (ret) + goto out; + + if (!bo->is_heap) { + ret = panfrost_mmu_map(bo); + if (ret) + drm_mm_remove_node(&bo->node); + } +out: + spin_unlock(&pfdev->mm_lock); + return ret; +} + +static void panfrost_gem_close(struct drm_gem_object *obj, struct drm_file *file_priv) +{ + struct panfrost_gem_object *bo = to_panfrost_bo(obj); + struct panfrost_device *pfdev = obj->dev->dev_private; + if (bo->is_mapped) panfrost_mmu_unmap(bo); spin_lock(&pfdev->mm_lock); - drm_mm_remove_node(&bo->node); + if (drm_mm_node_allocated(&bo->node)) + drm_mm_remove_node(&bo->node); spin_unlock(&pfdev->mm_lock); +} - drm_gem_shmem_free_object(obj); +static int panfrost_gem_pin(struct drm_gem_object *obj) +{ + if (to_panfrost_bo(obj)->is_heap) + return -EINVAL; + + return drm_gem_shmem_pin(obj); } static const struct drm_gem_object_funcs panfrost_gem_funcs = { .free = panfrost_gem_free_object, + .open = panfrost_gem_open, + .close = panfrost_gem_close, .print_info = drm_gem_shmem_print_info, - .pin = drm_gem_shmem_pin, + .pin = panfrost_gem_pin, .unpin = drm_gem_shmem_unpin, .get_sg_table = drm_gem_shmem_get_sg_table, .vmap = drm_gem_shmem_vmap, @@ -50,10 +122,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = { */ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size) { - int ret; - struct panfrost_device *pfdev = dev->dev_private; struct panfrost_gem_object *obj; - u64 align; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) @@ -61,21 +130,42 @@ struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t obj->base.base.funcs = &panfrost_gem_funcs; - size = roundup(size, PAGE_SIZE); - align = size >= SZ_2M ? SZ_2M >> PAGE_SHIFT : 0; + return &obj->base.base; +} - spin_lock(&pfdev->mm_lock); - ret = drm_mm_insert_node_generic(&pfdev->mm, &obj->node, - size >> PAGE_SHIFT, align, 0, 0); - spin_unlock(&pfdev->mm_lock); +struct panfrost_gem_object * +panfrost_gem_create_with_handle(struct drm_file *file_priv, + struct drm_device *dev, size_t size, + u32 flags, + uint32_t *handle) +{ + int ret; + struct drm_gem_shmem_object *shmem; + struct panfrost_gem_object *bo; + + /* Round up heap allocations to 2MB to keep fault handling simple */ + if (flags & PANFROST_BO_HEAP) + size = roundup(size, SZ_2M); + + shmem = drm_gem_shmem_create(dev, size); + if (IS_ERR(shmem)) + return ERR_CAST(shmem); + + bo = to_panfrost_bo(&shmem->base); + bo->noexec = !!(flags & PANFROST_BO_NOEXEC); + bo->is_heap = !!(flags & PANFROST_BO_HEAP); + + /* + * Allocate an id of idr table where the obj is registered + * and handle has the id what user can see. + */ + ret = drm_gem_handle_create(file_priv, &shmem->base, handle); + /* drop reference from allocate - handle holds it now. */ + drm_gem_object_put_unlocked(&shmem->base); if (ret) - goto free_obj; - - return &obj->base.base; + return ERR_PTR(ret); -free_obj: - kfree(obj); - return ERR_PTR(ret); + return bo; } struct drm_gem_object * @@ -84,15 +174,14 @@ panfrost_gem_prime_import_sg_table(struct drm_device *dev, struct sg_table *sgt) { struct drm_gem_object *obj; - struct panfrost_gem_object *pobj; + struct panfrost_gem_object *bo; obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt); if (IS_ERR(obj)) return ERR_CAST(obj); - pobj = to_panfrost_bo(obj); - - panfrost_mmu_map(pobj); + bo = to_panfrost_bo(obj); + bo->noexec = true; return obj; } diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h index 6dbcaba020fc..e10f58316915 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.h +++ b/drivers/gpu/drm/panfrost/panfrost_gem.h @@ -9,9 +9,12 @@ struct panfrost_gem_object { struct drm_gem_shmem_object base; + struct sg_table *sgts; struct drm_mm_node node; - bool is_mapped; + bool is_mapped :1; + bool noexec :1; + bool is_heap :1; }; static inline @@ -20,6 +23,12 @@ struct panfrost_gem_object *to_panfrost_bo(struct drm_gem_object *obj) return container_of(to_drm_gem_shmem_obj(obj), struct panfrost_gem_object, base); } +static inline +struct panfrost_gem_object *drm_mm_node_to_panfrost_bo(struct drm_mm_node *node) +{ + return container_of(node, struct panfrost_gem_object, node); +} + struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size); struct drm_gem_object * @@ -27,4 +36,13 @@ panfrost_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sgt); +struct panfrost_gem_object * +panfrost_gem_create_with_handle(struct drm_file *file_priv, + struct drm_device *dev, size_t size, + u32 flags, + uint32_t *handle); + +void panfrost_gem_shrinker_init(struct drm_device *dev); +void panfrost_gem_shrinker_cleanup(struct drm_device *dev); + #endif /* __PANFROST_GEM_H__ */ diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c new file mode 100644 index 000000000000..d191632b6197 --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2019 Arm Ltd. + * + * Based on msm_gem_freedreno.c: + * Copyright (C) 2016 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + */ + +#include <linux/list.h> + +#include <drm/drm_device.h> +#include <drm/drm_gem_shmem_helper.h> + +#include "panfrost_device.h" +#include "panfrost_gem.h" +#include "panfrost_mmu.h" + +static unsigned long +panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct panfrost_device *pfdev = + container_of(shrinker, struct panfrost_device, shrinker); + struct drm_gem_shmem_object *shmem; + unsigned long count = 0; + + if (!mutex_trylock(&pfdev->shrinker_lock)) + return 0; + + list_for_each_entry(shmem, &pfdev->shrinker_list, madv_list) { + if (drm_gem_shmem_is_purgeable(shmem)) + count += shmem->base.size >> PAGE_SHIFT; + } + + mutex_unlock(&pfdev->shrinker_lock); + + return count; +} + +static void panfrost_gem_purge(struct drm_gem_object *obj) +{ + struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); + mutex_lock(&shmem->pages_lock); + + panfrost_mmu_unmap(to_panfrost_bo(obj)); + drm_gem_shmem_purge_locked(obj); + + mutex_unlock(&shmem->pages_lock); +} + +static unsigned long +panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) +{ + struct panfrost_device *pfdev = + container_of(shrinker, struct panfrost_device, shrinker); + struct drm_gem_shmem_object *shmem, *tmp; + unsigned long freed = 0; + + if (!mutex_trylock(&pfdev->shrinker_lock)) + return SHRINK_STOP; + + list_for_each_entry_safe(shmem, tmp, &pfdev->shrinker_list, madv_list) { + if (freed >= sc->nr_to_scan) + break; + if (drm_gem_shmem_is_purgeable(shmem)) { + panfrost_gem_purge(&shmem->base); + freed += shmem->base.size >> PAGE_SHIFT; + list_del_init(&shmem->madv_list); + } + } + + mutex_unlock(&pfdev->shrinker_lock); + + if (freed > 0) + pr_info_ratelimited("Purging %lu bytes\n", freed << PAGE_SHIFT); + + return freed; +} + +/** + * panfrost_gem_shrinker_init - Initialize panfrost shrinker + * @dev: DRM device + * + * This function registers and sets up the panfrost shrinker. + */ +void panfrost_gem_shrinker_init(struct drm_device *dev) +{ + struct panfrost_device *pfdev = dev->dev_private; + pfdev->shrinker.count_objects = panfrost_gem_shrinker_count; + pfdev->shrinker.scan_objects = panfrost_gem_shrinker_scan; + pfdev->shrinker.seeks = DEFAULT_SEEKS; + WARN_ON(register_shrinker(&pfdev->shrinker)); +} + +/** + * panfrost_gem_shrinker_cleanup - Clean up panfrost shrinker + * @dev: DRM device + * + * This function unregisters the panfrost shrinker. + */ +void panfrost_gem_shrinker_cleanup(struct drm_device *dev) +{ + struct panfrost_device *pfdev = dev->dev_private; + + if (pfdev->shrinker.nr_deferred) { + unregister_shrinker(&pfdev->shrinker); + } +} diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 9bb9260d9181..0fc4539fd08d 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -6,7 +6,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <drm/gpu_scheduler.h> #include <drm/panfrost_drm.h> @@ -199,7 +199,7 @@ static void panfrost_acquire_object_fences(struct drm_gem_object **bos, int i; for (i = 0; i < bo_count; i++) - implicit_fences[i] = reservation_object_get_excl_rcu(bos[i]->resv); + implicit_fences[i] = dma_resv_get_excl_rcu(bos[i]->resv); } static void panfrost_attach_object_fences(struct drm_gem_object **bos, @@ -209,7 +209,7 @@ static void panfrost_attach_object_fences(struct drm_gem_object **bos, int i; for (i = 0; i < bo_count; i++) - reservation_object_add_excl_fence(bos[i]->resv, fence); + dma_resv_add_excl_fence(bos[i]->resv, fence); } int panfrost_job_push(struct panfrost_job *job) @@ -395,12 +395,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) /* panfrost_core_dump(pfdev); */ panfrost_devfreq_record_transition(pfdev, js); - panfrost_gpu_soft_reset(pfdev); - - /* TODO: Re-enable all other address spaces */ - panfrost_mmu_enable(pfdev, 0); - panfrost_gpu_power_on(pfdev); - panfrost_job_enable_interrupts(pfdev); + panfrost_device_reset(pfdev); for (i = 0; i < NUM_JOB_SLOTS; i++) drm_sched_resubmit_jobs(&pfdev->js->queue[i].sched); diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 92ac995dd9c6..2ed411f09d80 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -2,6 +2,7 @@ /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ #include <linux/bitfield.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> @@ -9,6 +10,7 @@ #include <linux/iommu.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/shmem_fs.h> #include <linux/sizes.h> #include "panfrost_device.h" @@ -105,15 +107,12 @@ static int mmu_hw_do_operation(struct panfrost_device *pfdev, u32 as_nr, return ret; } -void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr) +static void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr) { struct io_pgtable_cfg *cfg = &pfdev->mmu->pgtbl_cfg; u64 transtab = cfg->arm_mali_lpae_cfg.transtab; u64 memattr = cfg->arm_mali_lpae_cfg.memattr; - mmu_write(pfdev, MMU_INT_CLEAR, ~0); - mmu_write(pfdev, MMU_INT_MASK, ~0); - mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), transtab & 0xffffffffUL); mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), transtab >> 32); @@ -137,6 +136,14 @@ static void mmu_disable(struct panfrost_device *pfdev, u32 as_nr) write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE); } +void panfrost_mmu_reset(struct panfrost_device *pfdev) +{ + panfrost_mmu_enable(pfdev, 0); + + mmu_write(pfdev, MMU_INT_CLEAR, ~0); + mmu_write(pfdev, MMU_INT_MASK, ~0); +} + static size_t get_pgsize(u64 addr, size_t size) { if (addr & (SZ_2M - 1) || size < SZ_2M) @@ -145,27 +152,13 @@ static size_t get_pgsize(u64 addr, size_t size) return SZ_2M; } -int panfrost_mmu_map(struct panfrost_gem_object *bo) +static int mmu_map_sg(struct panfrost_device *pfdev, u64 iova, + int prot, struct sg_table *sgt) { - struct drm_gem_object *obj = &bo->base.base; - struct panfrost_device *pfdev = to_panfrost_device(obj->dev); - struct io_pgtable_ops *ops = pfdev->mmu->pgtbl_ops; - u64 iova = bo->node.start << PAGE_SHIFT; unsigned int count; struct scatterlist *sgl; - struct sg_table *sgt; - int ret; - - if (WARN_ON(bo->is_mapped)) - return 0; - - sgt = drm_gem_shmem_get_pages_sgt(obj); - if (WARN_ON(IS_ERR(sgt))) - return PTR_ERR(sgt); - - ret = pm_runtime_get_sync(pfdev->dev); - if (ret < 0) - return ret; + struct io_pgtable_ops *ops = pfdev->mmu->pgtbl_ops; + u64 start_iova = iova; mutex_lock(&pfdev->mmu->lock); @@ -178,18 +171,45 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo) while (len) { size_t pgsize = get_pgsize(iova | paddr, len); - ops->map(ops, iova, paddr, pgsize, IOMMU_WRITE | IOMMU_READ); + ops->map(ops, iova, paddr, pgsize, prot); iova += pgsize; paddr += pgsize; len -= pgsize; } } - mmu_hw_do_operation(pfdev, 0, bo->node.start << PAGE_SHIFT, - bo->node.size << PAGE_SHIFT, AS_COMMAND_FLUSH_PT); + mmu_hw_do_operation(pfdev, 0, start_iova, iova - start_iova, + AS_COMMAND_FLUSH_PT); mutex_unlock(&pfdev->mmu->lock); + return 0; +} + +int panfrost_mmu_map(struct panfrost_gem_object *bo) +{ + struct drm_gem_object *obj = &bo->base.base; + struct panfrost_device *pfdev = to_panfrost_device(obj->dev); + struct sg_table *sgt; + int ret; + int prot = IOMMU_READ | IOMMU_WRITE; + + if (WARN_ON(bo->is_mapped)) + return 0; + + if (bo->noexec) + prot |= IOMMU_NOEXEC; + + sgt = drm_gem_shmem_get_pages_sgt(obj); + if (WARN_ON(IS_ERR(sgt))) + return PTR_ERR(sgt); + + ret = pm_runtime_get_sync(pfdev->dev); + if (ret < 0) + return ret; + + mmu_map_sg(pfdev, bo->node.start << PAGE_SHIFT, prot, sgt); + pm_runtime_mark_last_busy(pfdev->dev); pm_runtime_put_autosuspend(pfdev->dev); bo->is_mapped = true; @@ -222,12 +242,12 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo) size_t unmapped_page; size_t pgsize = get_pgsize(iova, len - unmapped_len); - unmapped_page = ops->unmap(ops, iova, pgsize); - if (!unmapped_page) - break; - - iova += unmapped_page; - unmapped_len += unmapped_page; + if (ops->iova_to_phys(ops, iova)) { + unmapped_page = ops->unmap(ops, iova, pgsize); + WARN_ON(unmapped_page != pgsize); + } + iova += pgsize; + unmapped_len += pgsize; } mmu_hw_do_operation(pfdev, 0, bo->node.start << PAGE_SHIFT, @@ -263,6 +283,105 @@ static const struct iommu_gather_ops mmu_tlb_ops = { .tlb_sync = mmu_tlb_sync_context, }; +static struct drm_mm_node *addr_to_drm_mm_node(struct panfrost_device *pfdev, int as, u64 addr) +{ + struct drm_mm_node *node; + u64 offset = addr >> PAGE_SHIFT; + + drm_mm_for_each_node(node, &pfdev->mm) { + if (offset >= node->start && offset < (node->start + node->size)) + return node; + } + return NULL; +} + +#define NUM_FAULT_PAGES (SZ_2M / PAGE_SIZE) + +int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, u64 addr) +{ + int ret, i; + struct drm_mm_node *node; + struct panfrost_gem_object *bo; + struct address_space *mapping; + pgoff_t page_offset; + struct sg_table *sgt; + struct page **pages; + + node = addr_to_drm_mm_node(pfdev, as, addr); + if (!node) + return -ENOENT; + + bo = drm_mm_node_to_panfrost_bo(node); + if (!bo->is_heap) { + dev_WARN(pfdev->dev, "matching BO is not heap type (GPU VA = %llx)", + node->start << PAGE_SHIFT); + return -EINVAL; + } + /* Assume 2MB alignment and size multiple */ + addr &= ~((u64)SZ_2M - 1); + page_offset = addr >> PAGE_SHIFT; + page_offset -= node->start; + + mutex_lock(&bo->base.pages_lock); + + if (!bo->base.pages) { + bo->sgts = kvmalloc_array(bo->base.base.size / SZ_2M, + sizeof(struct sg_table), GFP_KERNEL | __GFP_ZERO); + if (!bo->sgts) + return -ENOMEM; + + pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT, + sizeof(struct page *), GFP_KERNEL | __GFP_ZERO); + if (!pages) { + kfree(bo->sgts); + bo->sgts = NULL; + return -ENOMEM; + } + bo->base.pages = pages; + bo->base.pages_use_count = 1; + } else + pages = bo->base.pages; + + mapping = bo->base.base.filp->f_mapping; + mapping_set_unevictable(mapping); + + for (i = page_offset; i < page_offset + NUM_FAULT_PAGES; i++) { + pages[i] = shmem_read_mapping_page(mapping, i); + if (IS_ERR(pages[i])) { + mutex_unlock(&bo->base.pages_lock); + ret = PTR_ERR(pages[i]); + goto err_pages; + } + } + + mutex_unlock(&bo->base.pages_lock); + + sgt = &bo->sgts[page_offset / (SZ_2M / PAGE_SIZE)]; + ret = sg_alloc_table_from_pages(sgt, pages + page_offset, + NUM_FAULT_PAGES, 0, SZ_2M, GFP_KERNEL); + if (ret) + goto err_pages; + + if (!dma_map_sg(pfdev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL)) { + ret = -EINVAL; + goto err_map; + } + + mmu_map_sg(pfdev, addr, IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt); + + bo->is_mapped = true; + + dev_dbg(pfdev->dev, "mapped page fault @ %llx", addr); + + return 0; + +err_map: + sg_free_table(sgt); +err_pages: + drm_gem_shmem_put_pages(&bo->base); + return ret; +} + static const char *access_type_name(struct panfrost_device *pfdev, u32 fault_status) { @@ -287,13 +406,19 @@ static const char *access_type_name(struct panfrost_device *pfdev, static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data) { struct panfrost_device *pfdev = data; - u32 status = mmu_read(pfdev, MMU_INT_STAT); - int i; - if (!status) + if (!mmu_read(pfdev, MMU_INT_STAT)) return IRQ_NONE; - dev_err(pfdev->dev, "mmu irq status=%x\n", status); + mmu_write(pfdev, MMU_INT_MASK, 0); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data) +{ + struct panfrost_device *pfdev = data; + u32 status = mmu_read(pfdev, MMU_INT_RAWSTAT); + int i, ret; for (i = 0; status; i++) { u32 mask = BIT(i) | BIT(i + 16); @@ -315,6 +440,18 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data) access_type = (fault_status >> 8) & 0x3; source_id = (fault_status >> 16); + /* Page fault only */ + if ((status & mask) == BIT(i)) { + WARN_ON(exception_type < 0xC1 || exception_type > 0xC4); + + ret = panfrost_mmu_map_fault_addr(pfdev, i, addr); + if (!ret) { + mmu_write(pfdev, MMU_INT_CLEAR, BIT(i)); + status &= ~mask; + continue; + } + } + /* terminal fault, print info about the fault */ dev_err(pfdev->dev, "Unhandled Page fault in AS%d at VA 0x%016llX\n" @@ -337,6 +474,7 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data) status &= ~mask; } + mmu_write(pfdev, MMU_INT_MASK, ~0); return IRQ_HANDLED; }; @@ -355,16 +493,14 @@ int panfrost_mmu_init(struct panfrost_device *pfdev) if (irq <= 0) return -ENODEV; - err = devm_request_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, - IRQF_SHARED, "mmu", pfdev); + err = devm_request_threaded_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, + panfrost_mmu_irq_handler_thread, + IRQF_SHARED, "mmu", pfdev); if (err) { dev_err(pfdev->dev, "failed to request mmu irq"); return err; } - mmu_write(pfdev, MMU_INT_CLEAR, ~0); - mmu_write(pfdev, MMU_INT_MASK, ~0); - pfdev->mmu->pgtbl_cfg = (struct io_pgtable_cfg) { .pgsize_bitmap = SZ_4K | SZ_2M, .ias = FIELD_GET(0xff, pfdev->features.mmu_features), diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h index f5878d86a5ce..d5f9b24537db 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.h +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h @@ -11,7 +11,6 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo); int panfrost_mmu_init(struct panfrost_device *pfdev); void panfrost_mmu_fini(struct panfrost_device *pfdev); - -void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr); +void panfrost_mmu_reset(struct panfrost_device *pfdev); #endif diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index 9a153125e5d2..024771a4083e 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -128,6 +128,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, struct drm_framebuffer *fb = plane->state->fb; struct drm_connector *connector = priv->connector; struct drm_bridge *bridge = priv->bridge; + bool grayscale = false; u32 cntl; u32 ppl, hsw, hfp, hbp; u32 lpp, vsw, vfp, vbp; @@ -187,6 +188,20 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) tim2 |= TIM2_IPC; + + if (connector->display_info.num_bus_formats == 1 && + connector->display_info.bus_formats[0] == + MEDIA_BUS_FMT_Y8_1X8) + grayscale = true; + + /* + * The AC pin bias frequency is set to max count when using + * grayscale so at least once in a while we will reverse + * polarity and get rid of any DC built up that could + * damage the display. + */ + if (grayscale) + tim2 |= TIM2_ACB_MASK; } if (bridge) { @@ -218,8 +233,18 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, writel(0, priv->regs + CLCD_TIM3); - /* Hard-code TFT panel */ - cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDVCOMP(1); + /* + * Detect grayscale bus format. We do not support a grayscale mode + * toward userspace, instead we expose an RGB24 buffer and then the + * hardware will activate its grayscaler to convert to the grayscale + * format. + */ + if (grayscale) + cntl = CNTL_LCDEN | CNTL_LCDMONO8; + else + /* Else we assume TFT display */ + cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDVCOMP(1); + /* On the ST Micro variant, assume all 24 bits are connected */ if (priv->variant->st_bitmux_control) cntl |= CNTL_ST_CDWID_24; diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c index 94439212a5c5..a4f4175bbdbe 100644 --- a/drivers/gpu/drm/qxl/qxl_debugfs.c +++ b/drivers/gpu/drm/qxl/qxl_debugfs.c @@ -57,7 +57,7 @@ qxl_debugfs_buffers_info(struct seq_file *m, void *data) struct qxl_bo *bo; list_for_each_entry(bo, &qdev->gem.objects, list) { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; int rel; rcu_read_lock(); diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index df55b83e0a55..312216caeea2 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -238,7 +238,7 @@ static int qxl_release_validate_bo(struct qxl_bo *bo) return ret; } - ret = reservation_object_reserve_shared(bo->tbo.base.resv, 1); + ret = dma_resv_reserve_shared(bo->tbo.base.resv, 1); if (ret) return ret; @@ -458,9 +458,9 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) list_for_each_entry(entry, &release->bos, head) { bo = entry->bo; - reservation_object_add_shared_fence(bo->base.resv, &release->base); + dma_resv_add_shared_fence(bo->base.resv, &release->base); ttm_bo_add_to_lru(bo); - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } spin_unlock(&glob->lru_lock); ww_acquire_fini(&release->ticket); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 40f4d29edfe2..62eab82a64f9 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3659,7 +3659,7 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index 589217a7e435..35b9dc6ce46a 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -579,7 +579,7 @@ void cik_sdma_fini(struct radeon_device *rdev) struct radeon_fence *cik_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/radeon/evergreen_dma.c b/drivers/gpu/drm/radeon/evergreen_dma.c index 5505a04ca402..a46ee6c2099d 100644 --- a/drivers/gpu/drm/radeon/evergreen_dma.c +++ b/drivers/gpu/drm/radeon/evergreen_dma.c @@ -108,7 +108,7 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 5c05193da520..7089dfc8c2a9 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -891,7 +891,7 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; struct radeon_fence *fence; diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index 9ce6dd83d284..840401413c58 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -84,7 +84,7 @@ struct radeon_fence *r200_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; struct radeon_fence *fence; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 7d175a9e8330..e937cc01910d 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2963,7 +2963,7 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 35d92ef8a0d4..af6c0da45f28 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c @@ -444,7 +444,7 @@ void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) struct radeon_fence *r600_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3f7701321d21..de1d090df034 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -619,7 +619,7 @@ void radeon_sync_fence(struct radeon_sync *sync, struct radeon_fence *fence); int radeon_sync_resv(struct radeon_device *rdev, struct radeon_sync *sync, - struct reservation_object *resv, + struct dma_resv *resv, bool shared); int radeon_sync_rings(struct radeon_device *rdev, struct radeon_sync *sync, @@ -1912,20 +1912,20 @@ struct radeon_asic { uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); u32 blit_ring_index; struct radeon_fence *(*dma)(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); u32 dma_ring_index; /* method used for bo copy */ struct radeon_fence *(*copy)(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); /* ring used for bo copies */ u32 copy_ring_index; } copy; diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index e3f036c20d64..a74fa18cd27b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -86,7 +86,7 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); int r100_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, uint32_t offset, uint32_t obj_size); @@ -157,7 +157,7 @@ struct radeon_fence *r200_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); void r200_set_safe_registers(struct radeon_device *rdev); /* @@ -347,11 +347,11 @@ int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); struct radeon_fence *r600_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); void r600_hpd_init(struct radeon_device *rdev); void r600_hpd_fini(struct radeon_device *rdev); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); @@ -473,7 +473,7 @@ void r700_cp_fini(struct radeon_device *rdev); struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); u32 rv770_get_xclk(struct radeon_device *rdev); int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int rv770_get_temp(struct radeon_device *rdev); @@ -547,7 +547,7 @@ void evergreen_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); int evergreen_get_temp(struct radeon_device *rdev); int evergreen_get_allowed_info_register(struct radeon_device *rdev, u32 reg, u32 *val); @@ -725,7 +725,7 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); struct radeon_fence *si_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); void si_dma_vm_copy_pages(struct radeon_device *rdev, struct radeon_ib *ib, @@ -796,11 +796,11 @@ void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); struct radeon_fence *cik_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv); + struct dma_resv *resv); int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring); diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 1ea50ce16312..ac9a5ec481c3 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -35,7 +35,7 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size, uint64_t saddr, uint64_t daddr, int flag, int n, - struct reservation_object *resv) + struct dma_resv *resv) { unsigned long start_jiffies; unsigned long end_jiffies; diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index 7e5254a34e84..7b5460678382 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -255,7 +255,7 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p) int r; list_for_each_entry(reloc, &p->validated, tv.head) { - struct reservation_object *resv; + struct dma_resv *resv; resv = reloc->robj->tbo.base.resv; r = radeon_sync_resv(p->rdev, &p->ib.sync, resv, diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 7bf73230ac0b..e81b01f8db90 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -533,7 +533,7 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc, DRM_ERROR("failed to pin new rbo buffer before flip\n"); goto cleanup; } - work->fence = dma_fence_get(reservation_object_get_excl(new_rbo->tbo.base.resv)); + work->fence = dma_fence_get(dma_resv_get_excl(new_rbo->tbo.base.resv)); radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL); radeon_bo_unreserve(new_rbo); diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 03873f21a734..4cf58dbbe439 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -114,7 +114,7 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj, } if (domain == RADEON_GEM_DOMAIN_CPU) { /* Asking for cpu access wait for object idle */ - r = reservation_object_wait_timeout_rcu(robj->tbo.base.resv, true, true, 30 * HZ); + r = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true, 30 * HZ); if (!r) r = -EBUSY; @@ -449,7 +449,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, } robj = gem_to_radeon_bo(gobj); - r = reservation_object_test_signaled_rcu(robj->tbo.base.resv, true); + r = dma_resv_test_signaled_rcu(robj->tbo.base.resv, true); if (r == 0) r = -EBUSY; else @@ -478,7 +478,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, } robj = gem_to_radeon_bo(gobj); - ret = reservation_object_wait_timeout_rcu(robj->tbo.base.resv, true, true, 30 * HZ); + ret = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true, 30 * HZ); if (ret == 0) r = -EBUSY; else if (ret < 0) diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c index 0d64ace0e6c1..6902f998ede9 100644 --- a/drivers/gpu/drm/radeon/radeon_mn.c +++ b/drivers/gpu/drm/radeon/radeon_mn.c @@ -163,7 +163,7 @@ static int radeon_mn_invalidate_range_start(struct mmu_notifier *mn, continue; } - r = reservation_object_wait_timeout_rcu(bo->tbo.base.resv, + r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false, MAX_SCHEDULE_TIMEOUT); if (r <= 0) DRM_ERROR("(%ld) failed to wait for user bo\n", r); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 9db8ba29ef68..2abe1eab471f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -183,7 +183,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) int radeon_bo_create(struct radeon_device *rdev, unsigned long size, int byte_align, bool kernel, u32 domain, u32 flags, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, struct radeon_bo **bo_ptr) { struct radeon_bo *bo; @@ -610,7 +610,7 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo) int steal; int i; - reservation_object_assert_held(bo->tbo.base.resv); + dma_resv_assert_held(bo->tbo.base.resv); if (!bo->tiling_flags) return 0; @@ -736,7 +736,7 @@ void radeon_bo_get_tiling_flags(struct radeon_bo *bo, uint32_t *tiling_flags, uint32_t *pitch) { - reservation_object_assert_held(bo->tbo.base.resv); + dma_resv_assert_held(bo->tbo.base.resv); if (tiling_flags) *tiling_flags = bo->tiling_flags; @@ -748,7 +748,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved, bool force_drop) { if (!force_drop) - reservation_object_assert_held(bo->tbo.base.resv); + dma_resv_assert_held(bo->tbo.base.resv); if (!(bo->tiling_flags & RADEON_TILING_SURFACE)) return 0; @@ -870,10 +870,10 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait) void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence, bool shared) { - struct reservation_object *resv = bo->tbo.base.resv; + struct dma_resv *resv = bo->tbo.base.resv; if (shared) - reservation_object_add_shared_fence(resv, &fence->base); + dma_resv_add_shared_fence(resv, &fence->base); else - reservation_object_add_excl_fence(resv, &fence->base); + dma_resv_add_excl_fence(resv, &fence->base); } diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index e5554bf9140e..d23f2ed4126e 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -126,7 +126,7 @@ extern int radeon_bo_create(struct radeon_device *rdev, unsigned long size, int byte_align, bool kernel, u32 domain, u32 flags, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, struct radeon_bo **bo_ptr); extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr); extern void radeon_bo_kunmap(struct radeon_bo *bo); diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c index 52b0d0cd8cbe..b906e8fbd5f3 100644 --- a/drivers/gpu/drm/radeon/radeon_prime.c +++ b/drivers/gpu/drm/radeon/radeon_prime.c @@ -63,15 +63,15 @@ struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg) { - struct reservation_object *resv = attach->dmabuf->resv; + struct dma_resv *resv = attach->dmabuf->resv; struct radeon_device *rdev = dev->dev_private; struct radeon_bo *bo; int ret; - reservation_object_lock(resv, NULL); + dma_resv_lock(resv, NULL); ret = radeon_bo_create(rdev, attach->dmabuf->size, PAGE_SIZE, false, RADEON_GEM_DOMAIN_GTT, 0, sg, resv, &bo); - reservation_object_unlock(resv); + dma_resv_unlock(resv); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/radeon/radeon_sync.c b/drivers/gpu/drm/radeon/radeon_sync.c index 8c9780b5a884..55cc77a73c7b 100644 --- a/drivers/gpu/drm/radeon/radeon_sync.c +++ b/drivers/gpu/drm/radeon/radeon_sync.c @@ -87,30 +87,30 @@ void radeon_sync_fence(struct radeon_sync *sync, */ int radeon_sync_resv(struct radeon_device *rdev, struct radeon_sync *sync, - struct reservation_object *resv, + struct dma_resv *resv, bool shared) { - struct reservation_object_list *flist; + struct dma_resv_list *flist; struct dma_fence *f; struct radeon_fence *fence; unsigned i; int r = 0; /* always sync to the exclusive fence */ - f = reservation_object_get_excl(resv); + f = dma_resv_get_excl(resv); fence = f ? to_radeon_fence(f) : NULL; if (fence && fence->rdev == rdev) radeon_sync_fence(sync, fence); else if (f) r = dma_fence_wait(f, true); - flist = reservation_object_get_list(resv); + flist = dma_resv_get_list(resv); if (shared || !flist || r) return r; for (i = 0; i < flist->shared_count; ++i) { f = rcu_dereference_protected(flist->shared[i], - reservation_object_held(resv)); + dma_resv_held(resv)); fence = to_radeon_fence(f); if (fence && fence->rdev == rdev) radeon_sync_fence(sync, fence); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 311e69c2ed7f..1ad5c3b86b64 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -477,7 +477,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } - f = reservation_object_get_excl(bo->tbo.base.resv); + f = dma_resv_get_excl(bo->tbo.base.resv); if (f) { r = radeon_fence_wait((struct radeon_fence *)f, false); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index e48a05533126..e0ad547786e8 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -831,7 +831,7 @@ static int radeon_vm_update_ptes(struct radeon_device *rdev, int r; radeon_sync_resv(rdev, &ib->sync, pt->tbo.base.resv, true); - r = reservation_object_reserve_shared(pt->tbo.base.resv, 1); + r = dma_resv_reserve_shared(pt->tbo.base.resv, 1); if (r) return r; diff --git a/drivers/gpu/drm/radeon/rv770_dma.c b/drivers/gpu/drm/radeon/rv770_dma.c index 0866b38ef264..4c91614b5e70 100644 --- a/drivers/gpu/drm/radeon/rv770_dma.c +++ b/drivers/gpu/drm/radeon/rv770_dma.c @@ -42,7 +42,7 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index 4773bb7d947e..d2fa302a5be9 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -231,7 +231,7 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring, struct radeon_fence *si_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, unsigned num_gpu_pages, - struct reservation_object *resv) + struct dma_resv *resv) { struct radeon_fence *fence; struct radeon_sync sync; diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c index 8ca5af0c912f..a44dca4b0219 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c @@ -97,10 +97,34 @@ crtcs_exit: return crtcs; } +static int sun8i_dw_hdmi_find_connector_pdev(struct device *dev, + struct platform_device **pdev_out) +{ + struct platform_device *pdev; + struct device_node *remote; + + remote = of_graph_get_remote_node(dev->of_node, 1, -1); + if (!remote) + return -ENODEV; + + if (!of_device_is_compatible(remote, "hdmi-connector")) { + of_node_put(remote); + return -ENODEV; + } + + pdev = of_find_device_by_node(remote); + of_node_put(remote); + if (!pdev) + return -ENODEV; + + *pdev_out = pdev; + return 0; +} + static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = to_platform_device(dev), *connector_pdev; struct dw_hdmi_plat_data *plat_data; struct drm_device *drm = data; struct device_node *phy_node; @@ -150,16 +174,30 @@ static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master, return PTR_ERR(hdmi->regulator); } + ret = sun8i_dw_hdmi_find_connector_pdev(dev, &connector_pdev); + if (!ret) { + hdmi->ddc_en = gpiod_get_optional(&connector_pdev->dev, + "ddc-en", GPIOD_OUT_HIGH); + platform_device_put(connector_pdev); + + if (IS_ERR(hdmi->ddc_en)) { + dev_err(dev, "Couldn't get ddc-en gpio\n"); + return PTR_ERR(hdmi->ddc_en); + } + } + ret = regulator_enable(hdmi->regulator); if (ret) { dev_err(dev, "Failed to enable regulator\n"); - return ret; + goto err_unref_ddc_en; } + gpiod_set_value(hdmi->ddc_en, 1); + ret = reset_control_deassert(hdmi->rst_ctrl); if (ret) { dev_err(dev, "Could not deassert ctrl reset control\n"); - goto err_disable_regulator; + goto err_disable_ddc_en; } ret = clk_prepare_enable(hdmi->clk_tmds); @@ -212,8 +250,12 @@ err_disable_clk_tmds: clk_disable_unprepare(hdmi->clk_tmds); err_assert_ctrl_reset: reset_control_assert(hdmi->rst_ctrl); -err_disable_regulator: +err_disable_ddc_en: + gpiod_set_value(hdmi->ddc_en, 0); regulator_disable(hdmi->regulator); +err_unref_ddc_en: + if (hdmi->ddc_en) + gpiod_put(hdmi->ddc_en); return ret; } @@ -227,7 +269,11 @@ static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master, sun8i_hdmi_phy_remove(hdmi); clk_disable_unprepare(hdmi->clk_tmds); reset_control_assert(hdmi->rst_ctrl); + gpiod_set_value(hdmi->ddc_en, 0); regulator_disable(hdmi->regulator); + + if (hdmi->ddc_en) + gpiod_put(hdmi->ddc_en); } static const struct component_ops sun8i_dw_hdmi_ops = { diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 720c5aa8adc1..d707c9171824 100644 --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h @@ -9,6 +9,7 @@ #include <drm/bridge/dw_hdmi.h> #include <drm/drm_encoder.h> #include <linux/clk.h> +#include <linux/gpio/consumer.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> @@ -190,6 +191,7 @@ struct sun8i_dw_hdmi { struct regulator *regulator; const struct sun8i_dw_hdmi_quirks *quirks; struct reset_control *rst_ctrl; + struct gpio_desc *ddc_en; }; static inline struct sun8i_dw_hdmi * diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 4a75d149e368..fbf57bc3cdab 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -6,23 +6,28 @@ #include <linux/clk.h> #include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/iommu.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> #include <soc/tegra/pmc.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_vblank.h> + #include "dc.h" #include "drm.h" #include "gem.h" #include "hub.h" #include "plane.h" -#include <drm/drm_atomic.h> -#include <drm/drm_atomic_helper.h> -#include <drm/drm_plane_helper.h> - static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 2d94da225e51..a0f6f9b0d258 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -8,14 +8,15 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/of_gpio.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> -#include <linux/pm_runtime.h> #include <linux/platform_device.h> -#include <linux/reset.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/workqueue.h> #include <drm/drm_dp_helper.h> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 870904bfad78..6fb7d74ff553 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -8,9 +8,17 @@ #include <linux/host1x.h> #include <linux/idr.h> #include <linux/iommu.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_drv.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_ioctl.h> +#include <drm/drm_prime.h> +#include <drm/drm_vblank.h> #if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) #include <asm/dma-iommu.h> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 86daa19fcf24..29911eff9ceb 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -7,18 +7,17 @@ #ifndef HOST1X_DRM_H #define HOST1X_DRM_H 1 -#include <uapi/drm/tegra_drm.h> #include <linux/host1x.h> #include <linux/iova.h> #include <linux/of_gpio.h> -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fixed.h> #include <drm/drm_probe_helper.h> +#include <uapi/drm/tegra_drm.h> #include "gem.h" #include "hub.h" diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 2fbfefe9cb42..a5d47e301c5f 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -5,22 +5,24 @@ #include <linux/clk.h> #include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/host1x.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <linux/reset.h> -#include <linux/regulator/consumer.h> +#include <video/mipi_display.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_file.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> -#include <video/mipi_display.h> - #include "dc.h" #include "drm.h" #include "dsi.h" diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 888ed0d74ccd..e34325c83d28 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -9,11 +9,13 @@ #include <linux/console.h> -#include "drm.h" -#include "gem.h" +#include <drm/drm_fourcc.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_modeset_helper.h> +#include "drm.h" +#include "gem.h" + #ifdef CONFIG_DRM_FBDEV_EMULATION static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) { diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 0a3d925d5284..fb7667c8dd4c 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -12,6 +12,9 @@ #include <linux/dma-buf.h> #include <linux/iommu.h> + +#include <drm/drm_drv.h> +#include <drm/drm_prime.h> #include <drm/tegra_drm.h> #include "drm.h" diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index f1f758b25886..83ffb1e14ca3 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -11,7 +11,6 @@ #include <linux/host1x.h> #include <drm/drm.h> -#include <drm/drmP.h> #include <drm/drm_gem.h> #define TEGRA_BO_BOTTOM_UP (1 << 0) diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 8dbfb30344e7..641299cc85b8 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -5,6 +5,7 @@ #include <linux/clk.h> #include <linux/iommu.h> +#include <linux/module.h> #include <linux/of_device.h> #include "drm.h" diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 334c4d7d238b..50269ffbcb6b 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -6,9 +6,11 @@ #include <linux/clk.h> #include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/gpio.h> #include <linux/hdmi.h> #include <linux/math64.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> @@ -16,6 +18,9 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> +#include <drm/drm_debugfs.h> +#include <drm/drm_file.h> +#include <drm/drm_fourcc.h> #include <drm/drm_probe_helper.h> #include "hda.h" diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 92f202ec0577..839b49c40e51 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -4,6 +4,7 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/host1x.h> #include <linux/module.h> #include <linux/of.h> @@ -13,9 +14,9 @@ #include <linux/pm_runtime.h> #include <linux/reset.h> -#include <drm/drmP.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_probe_helper.h> #include "drm.h" diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 41541e261c91..767a60d9313c 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h @@ -6,7 +6,6 @@ #ifndef TEGRA_HUB_H #define TEGRA_HUB_H 1 -#include <drm/drmP.h> #include <drm/drm_plane.h> #include "plane.h" diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index df80ca07e46e..6bab71d6e81d 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -5,6 +5,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_plane_helper.h> #include "dc.h" diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 4ffe3794e6d3..e1669ada0a40 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -8,6 +8,7 @@ #include <linux/debugfs.h> #include <linux/gpio.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -17,7 +18,9 @@ #include <soc/tegra/pmc.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_debugfs.h> #include <drm/drm_dp_helper.h> +#include <drm/drm_file.h> #include <drm/drm_panel.h> #include <drm/drm_scdc_helper.h> diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 958548ef69e7..cd0399fd8c63 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -4,6 +4,7 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/host1x.h> #include <linux/iommu.h> #include <linux/module.h> diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index b6f47b8cf240..03d0e2df6774 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -33,7 +33,6 @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); #define DRIVER_DATE "2019" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 1 /* * The DLP has an actual width of 854 pixels, but that is not a multiple @@ -45,6 +44,9 @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); #define GM12U320_BLOCK_COUNT 20 +#define GM12U320_ERR(fmt, ...) \ + DRM_DEV_ERROR(&gm12u320->udev->dev, fmt, ##__VA_ARGS__) + #define MISC_RCV_EPT 1 #define DATA_RCV_EPT 2 #define DATA_SND_EPT 3 @@ -220,7 +222,7 @@ static int gm12u320_misc_request(struct gm12u320_device *gm12u320, usb_sndbulkpipe(gm12u320->udev, MISC_SND_EPT), gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT); if (ret || len != CMD_SIZE) { - dev_err(&gm12u320->udev->dev, "Misc. req. error %d\n", ret); + GM12U320_ERR("Misc. req. error %d\n", ret); return -EIO; } @@ -230,7 +232,7 @@ static int gm12u320_misc_request(struct gm12u320_device *gm12u320, gm12u320->cmd_buf, MISC_VALUE_SIZE, &len, DATA_TIMEOUT); if (ret || len != MISC_VALUE_SIZE) { - dev_err(&gm12u320->udev->dev, "Misc. value error %d\n", ret); + GM12U320_ERR("Misc. value error %d\n", ret); return -EIO; } /* cmd_buf[0] now contains the read value, which we don't use */ @@ -241,7 +243,7 @@ static int gm12u320_misc_request(struct gm12u320_device *gm12u320, gm12u320->cmd_buf, READ_STATUS_SIZE, &len, CMD_TIMEOUT); if (ret || len != READ_STATUS_SIZE) { - dev_err(&gm12u320->udev->dev, "Misc. status error %d\n", ret); + GM12U320_ERR("Misc. status error %d\n", ret); return -EIO; } @@ -278,7 +280,7 @@ static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320) vaddr = drm_gem_shmem_vmap(fb->obj[0]); if (IS_ERR(vaddr)) { - DRM_ERROR("failed to vmap fb: %ld\n", PTR_ERR(vaddr)); + GM12U320_ERR("failed to vmap fb: %ld\n", PTR_ERR(vaddr)); goto put_fb; } @@ -286,7 +288,7 @@ static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320) ret = dma_buf_begin_cpu_access( fb->obj[0]->import_attach->dmabuf, DMA_FROM_DEVICE); if (ret) { - DRM_ERROR("dma_buf_begin_cpu_access err: %d\n", ret); + GM12U320_ERR("dma_buf_begin_cpu_access err: %d\n", ret); goto vunmap; } } @@ -329,7 +331,7 @@ static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320) ret = dma_buf_end_cpu_access(fb->obj[0]->import_attach->dmabuf, DMA_FROM_DEVICE); if (ret) - DRM_ERROR("dma_buf_end_cpu_access err: %d\n", ret); + GM12U320_ERR("dma_buf_end_cpu_access err: %d\n", ret); } vunmap: drm_gem_shmem_vunmap(fb->obj[0], vaddr); @@ -340,17 +342,6 @@ unlock: mutex_unlock(&gm12u320->fb_update.lock); } -static int gm12u320_fb_update_ready(struct gm12u320_device *gm12u320) -{ - int ret; - - mutex_lock(&gm12u320->fb_update.lock); - ret = !gm12u320->fb_update.run || gm12u320->fb_update.fb != NULL; - mutex_unlock(&gm12u320->fb_update.lock); - - return ret; -} - static void gm12u320_fb_update_work(struct work_struct *work) { struct gm12u320_device *gm12u320 = @@ -424,14 +415,15 @@ static void gm12u320_fb_update_work(struct work_struct *work) * switches back to showing its logo. */ wait_event_timeout(gm12u320->fb_update.waitq, - gm12u320_fb_update_ready(gm12u320), + !gm12u320->fb_update.run || + gm12u320->fb_update.fb != NULL, IDLE_TIMEOUT); } return; err: /* Do not log errors caused by module unload or device unplug */ - if (ret != -ECONNRESET && ret != -ESHUTDOWN) - dev_err(&gm12u320->udev->dev, "Frame update error: %d\n", ret); + if (ret != -ENODEV && ret != -ECONNRESET && ret != -ESHUTDOWN) + GM12U320_ERR("Frame update error: %d\n", ret); } static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb, @@ -746,7 +738,7 @@ static int gm12u320_usb_probe(struct usb_interface *interface, if (ret) goto err_put; - drm_fbdev_generic_setup(dev, dev->mode_config.preferred_depth); + drm_fbdev_generic_setup(dev, 0); return 0; @@ -765,9 +757,8 @@ static void gm12u320_usb_disconnect(struct usb_interface *interface) drm_dev_put(dev); } -#ifdef CONFIG_PM -static int gm12u320_suspend(struct usb_interface *interface, - pm_message_t message) +static __maybe_unused int gm12u320_suspend(struct usb_interface *interface, + pm_message_t message) { struct drm_device *dev = usb_get_intfdata(interface); struct gm12u320_device *gm12u320 = dev->dev_private; @@ -778,7 +769,7 @@ static int gm12u320_suspend(struct usb_interface *interface, return 0; } -static int gm12u320_resume(struct usb_interface *interface) +static __maybe_unused int gm12u320_resume(struct usb_interface *interface) { struct drm_device *dev = usb_get_intfdata(interface); struct gm12u320_device *gm12u320 = dev->dev_private; @@ -789,7 +780,6 @@ static int gm12u320_resume(struct usb_interface *interface) return 0; } -#endif static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1de1, 0xc102) }, diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 9157dcc897a2..20ff56f27aa4 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -41,7 +41,7 @@ #include <linux/file.h> #include <linux/module.h> #include <linux/atomic.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> static void ttm_bo_global_kobj_release(struct kobject *kobj); @@ -161,7 +161,7 @@ static void ttm_bo_release_list(struct kref *list_kref) atomic_dec(&bo->bdev->glob->bo_count); dma_fence_put(bo->moving); if (!ttm_bo_uses_embedded_gem_object(bo)) - reservation_object_fini(&bo->base._resv); + dma_resv_fini(&bo->base._resv); mutex_destroy(&bo->wu_mutex); bo->destroy(bo); ttm_mem_global_free(bdev->glob->mem_glob, acc_size); @@ -173,7 +173,7 @@ static void ttm_bo_add_mem_to_lru(struct ttm_buffer_object *bo, struct ttm_bo_device *bdev = bo->bdev; struct ttm_mem_type_manager *man; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); if (!list_empty(&bo->lru)) return; @@ -244,7 +244,7 @@ static void ttm_bo_bulk_move_set_pos(struct ttm_lru_bulk_move_pos *pos, void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo, struct ttm_lru_bulk_move *bulk) { - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); ttm_bo_del_from_lru(bo); ttm_bo_add_to_lru(bo); @@ -277,8 +277,8 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) if (!pos->first) continue; - reservation_object_assert_held(pos->first->base.resv); - reservation_object_assert_held(pos->last->base.resv); + dma_resv_assert_held(pos->first->base.resv); + dma_resv_assert_held(pos->last->base.resv); man = &pos->first->bdev->man[TTM_PL_TT]; list_bulk_move_tail(&man->lru[i], &pos->first->lru, @@ -292,8 +292,8 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) if (!pos->first) continue; - reservation_object_assert_held(pos->first->base.resv); - reservation_object_assert_held(pos->last->base.resv); + dma_resv_assert_held(pos->first->base.resv); + dma_resv_assert_held(pos->last->base.resv); man = &pos->first->bdev->man[TTM_PL_VRAM]; list_bulk_move_tail(&man->lru[i], &pos->first->lru, @@ -307,8 +307,8 @@ void ttm_bo_bulk_move_lru_tail(struct ttm_lru_bulk_move *bulk) if (!pos->first) continue; - reservation_object_assert_held(pos->first->base.resv); - reservation_object_assert_held(pos->last->base.resv); + dma_resv_assert_held(pos->first->base.resv); + dma_resv_assert_held(pos->last->base.resv); lru = &pos->first->bdev->glob->swap_lru[i]; list_bulk_move_tail(lru, &pos->first->swap, &pos->last->swap); @@ -442,29 +442,29 @@ static int ttm_bo_individualize_resv(struct ttm_buffer_object *bo) if (bo->base.resv == &bo->base._resv) return 0; - BUG_ON(!reservation_object_trylock(&bo->base._resv)); + BUG_ON(!dma_resv_trylock(&bo->base._resv)); - r = reservation_object_copy_fences(&bo->base._resv, bo->base.resv); + r = dma_resv_copy_fences(&bo->base._resv, bo->base.resv); if (r) - reservation_object_unlock(&bo->base._resv); + dma_resv_unlock(&bo->base._resv); return r; } static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo) { - struct reservation_object_list *fobj; + struct dma_resv_list *fobj; struct dma_fence *fence; int i; - fobj = reservation_object_get_list(&bo->base._resv); - fence = reservation_object_get_excl(&bo->base._resv); + fobj = dma_resv_get_list(&bo->base._resv); + fence = dma_resv_get_excl(&bo->base._resv); if (fence && !fence->ops->signaled) dma_fence_enable_sw_signaling(fence); for (i = 0; fobj && i < fobj->shared_count; ++i) { fence = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(bo->base.resv)); + dma_resv_held(bo->base.resv)); if (!fence->ops->signaled) dma_fence_enable_sw_signaling(fence); @@ -482,23 +482,23 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) /* Last resort, if we fail to allocate memory for the * fences block for the BO to become idle */ - reservation_object_wait_timeout_rcu(bo->base.resv, true, false, + dma_resv_wait_timeout_rcu(bo->base.resv, true, false, 30 * HZ); spin_lock(&glob->lru_lock); goto error; } spin_lock(&glob->lru_lock); - ret = reservation_object_trylock(bo->base.resv) ? 0 : -EBUSY; + ret = dma_resv_trylock(bo->base.resv) ? 0 : -EBUSY; if (!ret) { - if (reservation_object_test_signaled_rcu(&bo->base._resv, true)) { + if (dma_resv_test_signaled_rcu(&bo->base._resv, true)) { ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); if (bo->base.resv != &bo->base._resv) - reservation_object_unlock(&bo->base._resv); + dma_resv_unlock(&bo->base._resv); ttm_bo_cleanup_memtype_use(bo); - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); return; } @@ -514,10 +514,10 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) ttm_bo_add_to_lru(bo); } - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } if (bo->base.resv != &bo->base._resv) - reservation_object_unlock(&bo->base._resv); + dma_resv_unlock(&bo->base._resv); error: kref_get(&bo->list_kref); @@ -546,7 +546,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool unlock_resv) { struct ttm_bo_global *glob = bo->bdev->glob; - struct reservation_object *resv; + struct dma_resv *resv; int ret; if (unlikely(list_empty(&bo->ddestroy))) @@ -554,7 +554,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, else resv = &bo->base._resv; - if (reservation_object_test_signaled_rcu(resv, true)) + if (dma_resv_test_signaled_rcu(resv, true)) ret = 0; else ret = -EBUSY; @@ -563,10 +563,10 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, long lret; if (unlock_resv) - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); spin_unlock(&glob->lru_lock); - lret = reservation_object_wait_timeout_rcu(resv, true, + lret = dma_resv_wait_timeout_rcu(resv, true, interruptible, 30 * HZ); @@ -576,7 +576,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, return -EBUSY; spin_lock(&glob->lru_lock); - if (unlock_resv && !reservation_object_trylock(bo->base.resv)) { + if (unlock_resv && !dma_resv_trylock(bo->base.resv)) { /* * We raced, and lost, someone else holds the reservation now, * and is probably busy in ttm_bo_cleanup_memtype_use. @@ -593,7 +593,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, if (ret || unlikely(list_empty(&bo->ddestroy))) { if (unlock_resv) - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); spin_unlock(&glob->lru_lock); return ret; } @@ -606,7 +606,7 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, ttm_bo_cleanup_memtype_use(bo); if (unlock_resv) - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); return 0; } @@ -634,12 +634,12 @@ static bool ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all) if (remove_all || bo->base.resv != &bo->base._resv) { spin_unlock(&glob->lru_lock); - reservation_object_lock(bo->base.resv, NULL); + dma_resv_lock(bo->base.resv, NULL); spin_lock(&glob->lru_lock); ttm_bo_cleanup_refs(bo, false, !remove_all, true); - } else if (reservation_object_trylock(bo->base.resv)) { + } else if (dma_resv_trylock(bo->base.resv)) { ttm_bo_cleanup_refs(bo, false, !remove_all, true); } else { spin_unlock(&glob->lru_lock); @@ -711,7 +711,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, struct ttm_placement placement; int ret = 0; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); placement.num_placement = 0; placement.num_busy_placement = 0; @@ -782,7 +782,7 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo, bool ret = false; if (bo->base.resv == ctx->resv) { - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); if (ctx->flags & TTM_OPT_FLAG_ALLOW_RES_EVICT || !list_empty(&bo->ddestroy)) ret = true; @@ -790,7 +790,7 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo, if (busy) *busy = false; } else { - ret = reservation_object_trylock(bo->base.resv); + ret = dma_resv_trylock(bo->base.resv); *locked = ret; if (busy) *busy = !ret; @@ -818,10 +818,10 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo, return -EBUSY; if (ctx->interruptible) - r = reservation_object_lock_interruptible(busy_bo->base.resv, + r = dma_resv_lock_interruptible(busy_bo->base.resv, ticket); else - r = reservation_object_lock(busy_bo->base.resv, ticket); + r = dma_resv_lock(busy_bo->base.resv, ticket); /* * TODO: It would be better to keep the BO locked until allocation is at @@ -829,7 +829,7 @@ static int ttm_mem_evict_wait_busy(struct ttm_buffer_object *busy_bo, * of TTM. */ if (!r) - reservation_object_unlock(busy_bo->base.resv); + dma_resv_unlock(busy_bo->base.resv); return r == -EDEADLK ? -EBUSY : r; } @@ -855,7 +855,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked, &busy)) { if (busy && !busy_bo && ticket != - reservation_object_locking_ctx(bo->base.resv)) + dma_resv_locking_ctx(bo->base.resv)) busy_bo = bo; continue; } @@ -863,7 +863,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, if (place && !bdev->driver->eviction_valuable(bo, place)) { if (locked) - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); continue; } break; @@ -935,9 +935,9 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo, spin_unlock(&man->move_lock); if (fence) { - reservation_object_add_shared_fence(bo->base.resv, fence); + dma_resv_add_shared_fence(bo->base.resv, fence); - ret = reservation_object_reserve_shared(bo->base.resv, 1); + ret = dma_resv_reserve_shared(bo->base.resv, 1); if (unlikely(ret)) { dma_fence_put(fence); return ret; @@ -964,7 +964,7 @@ static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, struct ww_acquire_ctx *ticket; int ret; - ticket = reservation_object_locking_ctx(bo->base.resv); + ticket = dma_resv_locking_ctx(bo->base.resv); do { ret = (*man->func->get_node)(man, bo, place, mem); if (unlikely(ret != 0)) @@ -1094,7 +1094,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, bool type_found = false; int i, ret; - ret = reservation_object_reserve_shared(bo->base.resv, 1); + ret = dma_resv_reserve_shared(bo->base.resv, 1); if (unlikely(ret)) return ret; @@ -1175,7 +1175,7 @@ static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, int ret = 0; struct ttm_mem_reg mem; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); mem.num_pages = bo->num_pages; mem.size = mem.num_pages << PAGE_SHIFT; @@ -1245,7 +1245,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo, int ret; uint32_t new_flags; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); /* * Check whether we need to move buffer. */ @@ -1282,7 +1282,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, struct ttm_operation_ctx *ctx, size_t acc_size, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)) { int ret = 0; @@ -1336,7 +1336,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, bo->sg = sg; if (resv) { bo->base.resv = resv; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); } else { bo->base.resv = &bo->base._resv; } @@ -1345,7 +1345,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, * bo.gem is not initialized, so we have to setup the * struct elements we want use regardless. */ - reservation_object_init(&bo->base._resv); + dma_resv_init(&bo->base._resv); drm_vma_node_reset(&bo->base.vma_node); } atomic_inc(&bo->bdev->glob->bo_count); @@ -1363,7 +1363,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, * since otherwise lockdep will be angered in radeon. */ if (!resv) { - locked = reservation_object_trylock(bo->base.resv); + locked = dma_resv_trylock(bo->base.resv); WARN_ON(!locked); } @@ -1397,7 +1397,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, bool interruptible, size_t acc_size, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)) { struct ttm_operation_ctx ctx = { interruptible, false }; @@ -1807,13 +1807,13 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, long timeout = 15 * HZ; if (no_wait) { - if (reservation_object_test_signaled_rcu(bo->base.resv, true)) + if (dma_resv_test_signaled_rcu(bo->base.resv, true)) return 0; else return -EBUSY; } - timeout = reservation_object_wait_timeout_rcu(bo->base.resv, true, + timeout = dma_resv_wait_timeout_rcu(bo->base.resv, true, interruptible, timeout); if (timeout < 0) return timeout; @@ -1821,7 +1821,7 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, if (timeout == 0) return -EBUSY; - reservation_object_add_excl_fence(bo->base.resv, NULL); + dma_resv_add_excl_fence(bo->base.resv, NULL); return 0; } EXPORT_SYMBOL(ttm_bo_wait); @@ -1937,7 +1937,7 @@ out: * already swapped buffer. */ if (locked) - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); kref_put(&bo->list_kref, ttm_bo_release_list); return ret; } @@ -1975,14 +1975,14 @@ int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo) ret = mutex_lock_interruptible(&bo->wu_mutex); if (unlikely(ret != 0)) return -ERESTARTSYS; - if (!reservation_object_is_locked(bo->base.resv)) + if (!dma_resv_is_locked(bo->base.resv)) goto out_unlock; - ret = reservation_object_lock_interruptible(bo->base.resv, NULL); + ret = dma_resv_lock_interruptible(bo->base.resv, NULL); if (ret == -EINTR) ret = -ERESTARTSYS; if (unlikely(ret != 0)) goto out_unlock; - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); out_unlock: mutex_unlock(&bo->wu_mutex); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 425a6d627b30..fe81c565e7ef 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -38,7 +38,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/module.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> struct ttm_transfer_obj { struct ttm_buffer_object base; @@ -518,8 +518,8 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, fbo->base.destroy = &ttm_transfered_destroy; fbo->base.acc_size = 0; fbo->base.base.resv = &fbo->base.base._resv; - reservation_object_init(fbo->base.base.resv); - ret = reservation_object_trylock(fbo->base.base.resv); + dma_resv_init(fbo->base.base.resv); + ret = dma_resv_trylock(fbo->base.base.resv); WARN_ON(!ret); *new_obj = &fbo->base; @@ -689,7 +689,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, int ret; struct ttm_buffer_object *ghost_obj; - reservation_object_add_excl_fence(bo->base.resv, fence); + dma_resv_add_excl_fence(bo->base.resv, fence); if (evict) { ret = ttm_bo_wait(bo, false, false); if (ret) @@ -716,7 +716,7 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo, if (ret) return ret; - reservation_object_add_excl_fence(ghost_obj->base.resv, fence); + dma_resv_add_excl_fence(ghost_obj->base.resv, fence); /** * If we're not moving to fixed memory, the TTM object @@ -752,7 +752,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, int ret; - reservation_object_add_excl_fence(bo->base.resv, fence); + dma_resv_add_excl_fence(bo->base.resv, fence); if (!evict) { struct ttm_buffer_object *ghost_obj; @@ -772,7 +772,7 @@ int ttm_bo_pipeline_move(struct ttm_buffer_object *bo, if (ret) return ret; - reservation_object_add_excl_fence(ghost_obj->base.resv, fence); + dma_resv_add_excl_fence(ghost_obj->base.resv, fence); /** * If we're not moving to fixed memory, the TTM object @@ -841,7 +841,7 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) if (ret) return ret; - ret = reservation_object_copy_fences(ghost->base.resv, bo->base.resv); + ret = dma_resv_copy_fences(ghost->base.resv, bo->base.resv); /* Last resort, wait for the BO to be idle when we are OOM */ if (ret) ttm_bo_wait(bo, false, false); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 85f5bcbe0c76..76eedb963693 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -71,7 +71,7 @@ static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo, ttm_bo_get(bo); up_read(&vmf->vma->vm_mm->mmap_sem); (void) dma_fence_wait(bo->moving, true); - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); ttm_bo_put(bo); goto out_unlock; } @@ -131,7 +131,7 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) * for reserve, and if it fails, retry the fault after waiting * for the buffer to become unreserved. */ - if (unlikely(!reservation_object_trylock(bo->base.resv))) { + if (unlikely(!dma_resv_trylock(bo->base.resv))) { if (vmf->flags & FAULT_FLAG_ALLOW_RETRY) { if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { ttm_bo_get(bo); @@ -296,7 +296,7 @@ static vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf) out_io_unlock: ttm_mem_io_unlock(man); out_unlock: - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); return ret; } diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 3aefe72fb5cb..131dae8f4170 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -39,7 +39,7 @@ static void ttm_eu_backoff_reservation_reverse(struct list_head *list, list_for_each_entry_continue_reverse(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } } @@ -71,7 +71,7 @@ void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket, if (list_empty(&bo->lru)) ttm_bo_add_to_lru(bo); - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } spin_unlock(&glob->lru_lock); @@ -114,7 +114,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), ticket); if (!ret && unlikely(atomic_read(&bo->cpu_writers) > 0)) { - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); ret = -EBUSY; @@ -130,7 +130,7 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, if (!entry->num_shared) continue; - ret = reservation_object_reserve_shared(bo->base.resv, + ret = dma_resv_reserve_shared(bo->base.resv, entry->num_shared); if (!ret) continue; @@ -144,16 +144,16 @@ int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket, if (ret == -EDEADLK) { if (intr) { - ret = reservation_object_lock_slow_interruptible(bo->base.resv, + ret = dma_resv_lock_slow_interruptible(bo->base.resv, ticket); } else { - reservation_object_lock_slow(bo->base.resv, ticket); + dma_resv_lock_slow(bo->base.resv, ticket); ret = 0; } } if (!ret && entry->num_shared) - ret = reservation_object_reserve_shared(bo->base.resv, + ret = dma_resv_reserve_shared(bo->base.resv, entry->num_shared); if (unlikely(ret != 0)) { @@ -201,14 +201,14 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket, list_for_each_entry(entry, list, head) { bo = entry->bo; if (entry->num_shared) - reservation_object_add_shared_fence(bo->base.resv, fence); + dma_resv_add_shared_fence(bo->base.resv, fence); else - reservation_object_add_excl_fence(bo->base.resv, fence); + dma_resv_add_excl_fence(bo->base.resv, fence); if (list_empty(&bo->lru)) ttm_bo_add_to_lru(bo); else ttm_bo_move_to_lru_tail(bo, NULL); - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } spin_unlock(&glob->lru_lock); if (ticket) diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 00b4a3337840..e0e9b4f69db6 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -48,7 +48,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) struct ttm_bo_device *bdev = bo->bdev; uint32_t page_flags = 0; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); if (bdev->need_dma32) page_flags |= TTM_PAGE_FLAG_DMA32; diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c index 79744137d89f..5d80507b539b 100644 --- a/drivers/gpu/drm/v3d/v3d_gem.c +++ b/drivers/gpu/drm/v3d/v3d_gem.c @@ -409,7 +409,7 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data, if (args->pad != 0) return -EINVAL; - ret = drm_gem_reservation_object_wait(file_priv, args->handle, + ret = drm_gem_dma_resv_wait(file_priv, args->handle, true, timeout_jiffies); /* Decrement the user's timeout, in case we got interrupted @@ -495,7 +495,7 @@ v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv, for (i = 0; i < job->bo_count; i++) { /* XXX: Use shared fences for read-only objects. */ - reservation_object_add_excl_fence(job->bo[i]->resv, + dma_resv_add_excl_fence(job->bo[i]->resv, job->done_fence); } diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c b/drivers/gpu/drm/vboxvideo/vbox_drv.c index 6189ea89bb71..862db495d111 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_drv.c +++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c @@ -32,7 +32,7 @@ static const struct pci_device_id pciidlist[] = { }; MODULE_DEVICE_TABLE(pci, pciidlist); -static struct drm_fb_helper_funcs vbox_fb_helper_funcs = { +static const struct drm_fb_helper_funcs vbox_fb_helper_funcs = { .fb_probe = vboxfb_create, }; diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index b72b760e3018..7a06cb6e31c5 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -543,7 +543,7 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) bo = to_vc4_bo(&exec->bo[i]->base); bo->seqno = seqno; - reservation_object_add_shared_fence(bo->base.base.resv, exec->fence); + dma_resv_add_shared_fence(bo->base.base.resv, exec->fence); } list_for_each_entry(bo, &exec->unref_list, unref_head) { @@ -554,7 +554,7 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno) bo = to_vc4_bo(&exec->rcl_write_bo[i]->base); bo->write_seqno = seqno; - reservation_object_add_excl_fence(bo->base.base.resv, exec->fence); + dma_resv_add_excl_fence(bo->base.base.resv, exec->fence); } } @@ -642,7 +642,7 @@ retry: for (i = 0; i < exec->bo_count; i++) { bo = &exec->bo[i]->base; - ret = reservation_object_reserve_shared(bo->resv, 1); + ret = dma_resv_reserve_shared(bo->resv, 1); if (ret) { vc4_unlock_bo_reservations(dev, exec, acquire_ctx); return ret; diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c index d8630467549c..9268f6fc3f66 100644 --- a/drivers/gpu/drm/vgem/vgem_fence.c +++ b/drivers/gpu/drm/vgem/vgem_fence.c @@ -21,7 +21,7 @@ */ #include <linux/dma-buf.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <drm/drm_file.h> @@ -128,7 +128,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev, { struct drm_vgem_fence_attach *arg = data; struct vgem_file *vfile = file->driver_priv; - struct reservation_object *resv; + struct dma_resv *resv; struct drm_gem_object *obj; struct dma_fence *fence; int ret; @@ -151,7 +151,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev, /* Check for a conflicting fence */ resv = obj->resv; - if (!reservation_object_test_signaled_rcu(resv, + if (!dma_resv_test_signaled_rcu(resv, arg->flags & VGEM_FENCE_WRITE)) { ret = -EBUSY; goto err_fence; @@ -159,12 +159,12 @@ int vgem_fence_attach_ioctl(struct drm_device *dev, /* Expose the fence via the dma-buf */ ret = 0; - reservation_object_lock(resv, NULL); + dma_resv_lock(resv, NULL); if (arg->flags & VGEM_FENCE_WRITE) - reservation_object_add_excl_fence(resv, fence); - else if ((ret = reservation_object_reserve_shared(resv, 1)) == 0) - reservation_object_add_shared_fence(resv, fence); - reservation_object_unlock(resv); + dma_resv_add_excl_fence(resv, fence); + else if ((ret = dma_resv_reserve_shared(resv, 1)) == 0) + dma_resv_add_shared_fence(resv, fence); + dma_resv_unlock(resv); /* Record the fence in our idr for later signaling */ if (ret == 0) { diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 3c430dd65f67..0a88ef11b9d3 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -396,7 +396,7 @@ static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev, (vgdev, qobj->hw_res_handle, vfpriv->ctx_id, offset, args->level, &box, fence); - reservation_object_add_excl_fence(qobj->tbo.base.resv, + dma_resv_add_excl_fence(qobj->tbo.base.resv, &fence->f); dma_fence_put(&fence->f); @@ -450,7 +450,7 @@ static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data, (vgdev, qobj, vfpriv ? vfpriv->ctx_id : 0, offset, args->level, &box, fence); - reservation_object_add_excl_fence(qobj->tbo.base.resv, + dma_resv_add_excl_fence(qobj->tbo.base.resv, &fence->f); dma_fence_put(&fence->f); } diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 3dc08f991a8d..a492ac3f4a7e 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -212,7 +212,7 @@ static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, 0, 0, vgfb->fence); ret = virtio_gpu_object_reserve(bo, false); if (!ret) { - reservation_object_add_excl_fence(bo->tbo.base.resv, + dma_resv_add_excl_fence(bo->tbo.base.resv, &vgfb->fence->f); dma_fence_put(&vgfb->fence->f); vgfb->fence = NULL; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c index 6c01ad2785dd..bb46ca0c458f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c @@ -459,9 +459,9 @@ int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, /* Buffer objects need to be either pinned or reserved: */ if (!(dst->mem.placement & TTM_PL_FLAG_NO_EVICT)) - reservation_object_assert_held(dst->base.resv); + dma_resv_assert_held(dst->base.resv); if (!(src->mem.placement & TTM_PL_FLAG_NO_EVICT)) - reservation_object_assert_held(src->base.resv); + dma_resv_assert_held(src->base.resv); if (dst->ttm->state == tt_unpopulated) { ret = dst->ttm->bdev->driver->ttm_tt_populate(dst->ttm, &ctx); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 0d9a1d454cd4..aad8d8140259 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -341,7 +341,7 @@ void vmw_bo_pin_reserved(struct vmw_buffer_object *vbo, bool pin) uint32_t old_mem_type = bo->mem.mem_type; int ret; - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); if (pin) { if (vbo->pin_count++ > 0) @@ -690,7 +690,7 @@ static int vmw_user_bo_synccpu_grab(struct vmw_user_buffer_object *user_bo, bool nonblock = !!(flags & drm_vmw_synccpu_dontblock); long lret; - lret = reservation_object_wait_timeout_rcu + lret = dma_resv_wait_timeout_rcu (bo->base.resv, true, true, nonblock ? 0 : MAX_SCHEDULE_TIMEOUT); if (!lret) @@ -1008,10 +1008,10 @@ void vmw_bo_fence_single(struct ttm_buffer_object *bo, if (fence == NULL) { vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); - reservation_object_add_excl_fence(bo->base.resv, &fence->base); + dma_resv_add_excl_fence(bo->base.resv, &fence->base); dma_fence_put(&fence->base); } else - reservation_object_add_excl_fence(bo->base.resv, &fence->base); + dma_resv_add_excl_fence(bo->base.resv, &fence->base); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c index 4e8df76681c4..3ca5cf375b01 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cotable.c @@ -171,7 +171,7 @@ static int vmw_cotable_unscrub(struct vmw_resource *res) } *cmd; WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB); - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); if (!cmd) @@ -313,7 +313,7 @@ static int vmw_cotable_unbind(struct vmw_resource *res, return 0; WARN_ON_ONCE(bo->mem.mem_type != VMW_PL_MOB); - reservation_object_assert_held(bo->base.resv); + dma_resv_assert_held(bo->base.resv); mutex_lock(&dev_priv->binding_mutex); if (!vcotbl->scrubbed) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 434dfadb0e52..178a6cd1a06f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -185,6 +185,9 @@ static long vmw_fence_wait(struct dma_fence *f, bool intr, signed long timeout) spin_lock(f->lock); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags)) + goto out; + if (intr && signal_pending(current)) { ret = -ERESTARTSYS; goto out; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 2eb3532e3291..5581a7826b4c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -41,7 +41,7 @@ void vmw_resource_mob_attach(struct vmw_resource *res) { struct vmw_buffer_object *backup = res->backup; - reservation_object_assert_held(backup->base.base.resv); + dma_resv_assert_held(res->backup->base.base.resv); res->used_prio = (res->res_dirty) ? res->func->dirty_prio : res->func->prio; list_add_tail(&res->mob_head, &backup->res_list); @@ -56,7 +56,7 @@ void vmw_resource_mob_detach(struct vmw_resource *res) { struct vmw_buffer_object *backup = res->backup; - reservation_object_assert_held(backup->base.base.resv); + dma_resv_assert_held(backup->base.base.resv); if (vmw_resource_mob_attached(res)) { list_del_init(&res->mob_head); vmw_bo_prio_del(backup, res->used_prio); @@ -719,7 +719,7 @@ void vmw_resource_unbind_list(struct vmw_buffer_object *vbo) .num_shared = 0 }; - reservation_object_assert_held(vbo->base.base.resv); + dma_resv_assert_held(vbo->base.base.resv); list_for_each_entry_safe(res, next, &vbo->res_list, mob_head) { if (!res->func->unbind) continue; diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c b/drivers/gpu/drm/xen/xen_drm_front_kms.c index de990036199d..21ad1c359b61 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_kms.c +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c @@ -46,7 +46,7 @@ static void fb_destroy(struct drm_framebuffer *fb) drm_gem_fb_destroy(fb); } -static struct drm_framebuffer_funcs fb_funcs = { +static const struct drm_framebuffer_funcs fb_funcs = { .destroy = fb_destroy, }; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/Kconfig b/drivers/video/fbdev/omap2/omapfb/displays/Kconfig index 8c1c5a4cfe18..744416dc530e 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/Kconfig +++ b/drivers/video/fbdev/omap2/omapfb/displays/Kconfig @@ -49,6 +49,7 @@ config FB_OMAP2_PANEL_DSI_CM config FB_OMAP2_PANEL_SONY_ACX565AKM tristate "ACX565AKM Panel" depends on SPI && BACKLIGHT_CLASS_DEVICE + depends on DRM_PANEL_SONY_ACX565AKM = n help This is the LCD panel used on Nokia N900 @@ -61,18 +62,21 @@ config FB_OMAP2_PANEL_LGPHILIPS_LB035Q02 config FB_OMAP2_PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on BACKLIGHT_CLASS_DEVICE + depends on DRM_PANEL_SHARP_LS037V7DW01 = n help LCD Panel used in TI's SDP3430 and EVM boards config FB_OMAP2_PANEL_TPO_TD028TTEC1 tristate "TPO TD028TTEC1 LCD Panel" depends on SPI + depends on DRM_PANEL_TPO_TD028TTEC1 = n help LCD panel used in Openmoko. config FB_OMAP2_PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" depends on SPI + depends on DRM_PANEL_TPO_TD043MTEA1 = n help LCD Panel used in OMAP3 Pandora @@ -80,6 +84,7 @@ config FB_OMAP2_PANEL_NEC_NL8048HL11 tristate "NEC NL8048HL11 Panel" depends on SPI depends on BACKLIGHT_CLASS_DEVICE + depends on DRM_PANEL_NEC_NL8048HL11 = n help This NEC NL8048HL11 panel is TFT LCD used in the Zoom2/3/3630 sdp boards. diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index c402364aec0d..cf528c289857 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -155,6 +155,8 @@ void dw_hdmi_resume(struct dw_hdmi *hdmi); void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); +void dw_hdmi_set_channel_count(struct dw_hdmi *hdmi, unsigned int cnt); +void dw_hdmi_set_channel_allocation(struct dw_hdmi *hdmi, unsigned int ca); void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 94aae87b1138..037b1f7a87a5 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -87,7 +87,7 @@ struct module; struct device_node; struct videomode; -struct reservation_object; +struct dma_resv; struct dma_buf_attachment; struct pci_dev; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 0b9997e27689..681cb590f952 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -543,8 +543,8 @@ struct drm_connector_state { * * This is also used in the atomic helpers to map encoders to their * current and previous connectors, see - * &drm_atomic_get_old_connector_for_encoder() and - * &drm_atomic_get_new_connector_for_encoder(). + * drm_atomic_get_old_connector_for_encoder() and + * drm_atomic_get_new_connector_for_encoder(). * * NOTE: Atomic drivers must fill this out (either themselves or through * helpers), for otherwise the GETCONNECTOR and GETENCODER IOCTLs will diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index ae693c0666cd..6aaba14f5972 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -35,7 +35,7 @@ */ #include <linux/kref.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include <drm/drm_vma_manager.h> @@ -276,7 +276,7 @@ struct drm_gem_object { * * Normally (@resv == &@_resv) except for imported GEM objects. */ - struct reservation_object *resv; + struct dma_resv *resv; /** * @_resv: @@ -285,7 +285,7 @@ struct drm_gem_object { * * This is unused for imported GEM objects. */ - struct reservation_object _resv; + struct dma_resv _resv; /** * @funcs: @@ -390,7 +390,7 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, int count, struct drm_gem_object ***objs_out); struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); -long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, +long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, bool wait_all, unsigned long timeout); int drm_gem_lock_reservations(struct drm_gem_object **objs, int count, struct ww_acquire_ctx *acquire_ctx); diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h index 038b6d313447..ce1600fdfc3e 100644 --- a/include/drm/drm_gem_shmem_helper.h +++ b/include/drm/drm_gem_shmem_helper.h @@ -44,6 +44,9 @@ struct drm_gem_shmem_object { */ unsigned int pages_use_count; + int madv; + struct list_head madv_list; + /** * @pages_mark_dirty_on_put: * @@ -121,6 +124,18 @@ void drm_gem_shmem_unpin(struct drm_gem_object *obj); void *drm_gem_shmem_vmap(struct drm_gem_object *obj); void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr); +int drm_gem_shmem_madvise(struct drm_gem_object *obj, int madv); + +static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem) +{ + return (shmem->madv > 0) && + !shmem->vmap_use_count && shmem->sgt && + !shmem->base.dma_buf && !shmem->base.import_attach; +} + +void drm_gem_shmem_purge_locked(struct drm_gem_object *obj); +void drm_gem_shmem_purge(struct drm_gem_object *obj); + struct drm_gem_shmem_object * drm_gem_shmem_create_with_handle(struct drm_file *file_priv, struct drm_device *dev, size_t size, diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 26377836141c..624bd15ecfab 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -36,14 +36,6 @@ struct display_timing; /** * struct drm_panel_funcs - perform operations on a given panel - * @disable: disable panel (turn off back light, etc.) - * @unprepare: turn off panel - * @prepare: turn on panel and perform set up - * @enable: enable panel (turn on back light, etc.) - * @get_modes: add modes to the connector that the panel is attached to and - * return the number of modes added - * @get_timings: copy display timings into the provided array and return - * the number of display timings available * * The .prepare() function is typically called before the display controller * starts to transmit video data. Panel drivers can use this to turn the panel @@ -69,132 +61,107 @@ struct display_timing; * the panel. This is the job of the .unprepare() function. */ struct drm_panel_funcs { - int (*disable)(struct drm_panel *panel); - int (*unprepare)(struct drm_panel *panel); + /** + * @prepare: + * + * Turn on panel and perform set up. + */ int (*prepare)(struct drm_panel *panel); + + /** + * @enable: + * + * Enable panel (turn on back light, etc.). + */ int (*enable)(struct drm_panel *panel); + + /** + * @disable: + * + * Disable panel (turn off back light, etc.). + */ + int (*disable)(struct drm_panel *panel); + + /** + * @unprepare: + * + * Turn off panel. + */ + int (*unprepare)(struct drm_panel *panel); + + /** + * @get_modes: + * + * Add modes to the connector that the panel is attached to and + * return the number of modes added. + */ int (*get_modes)(struct drm_panel *panel); + + /** + * @get_timings: + * + * Copy display timings into the provided array and return + * the number of display timings available. + */ int (*get_timings)(struct drm_panel *panel, unsigned int num_timings, struct display_timing *timings); }; /** * struct drm_panel - DRM panel object - * @drm: DRM device owning the panel - * @connector: DRM connector that the panel is attached to - * @dev: parent device of the panel - * @link: link from panel device (supplier) to DRM device (consumer) - * @funcs: operations that can be performed on the panel - * @list: panel entry in registry */ struct drm_panel { + /** + * @drm: + * + * DRM device owning the panel. + */ struct drm_device *drm; + + /** + * @connector: + * + * DRM connector that the panel is attached to. + */ struct drm_connector *connector; + + /** + * @dev: + * + * Parent device of the panel. + */ struct device *dev; + /** + * @funcs: + * + * Operations that can be performed on the panel. + */ const struct drm_panel_funcs *funcs; + /** + * @list: + * + * Panel entry in registry. + */ struct list_head list; }; -/** - * drm_disable_unprepare - power off a panel - * @panel: DRM panel - * - * Calling this function will completely power off a panel (assert the panel's - * reset, turn off power supplies, ...). After this function has completed, it - * is usually no longer possible to communicate with the panel until another - * call to drm_panel_prepare(). - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_unprepare(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->unprepare) - return panel->funcs->unprepare(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_disable - disable a panel - * @panel: DRM panel - * - * This will typically turn off the panel's backlight or disable the display - * drivers. For smart panels it should still be possible to communicate with - * the integrated circuitry via any command bus after this call. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_disable(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->disable) - return panel->funcs->disable(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_prepare - power on a panel - * @panel: DRM panel - * - * Calling this function will enable power and deassert any reset signals to - * the panel. After this has completed it is possible to communicate with any - * integrated circuitry via a command bus. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_prepare(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->prepare) - return panel->funcs->prepare(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_enable - enable a panel - * @panel: DRM panel - * - * Calling this function will cause the panel display drivers to be turned on - * and the backlight to be enabled. Content will be visible on screen after - * this call completes. - * - * Return: 0 on success or a negative error code on failure. - */ -static inline int drm_panel_enable(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->enable) - return panel->funcs->enable(panel); - - return panel ? -ENOSYS : -EINVAL; -} - -/** - * drm_panel_get_modes - probe the available display modes of a panel - * @panel: DRM panel - * - * The modes probed from the panel are automatically added to the connector - * that the panel is attached to. - * - * Return: The number of modes available from the panel on success or a - * negative error code on failure. - */ -static inline int drm_panel_get_modes(struct drm_panel *panel) -{ - if (panel && panel->funcs && panel->funcs->get_modes) - return panel->funcs->get_modes(panel); - - return panel ? -ENOSYS : -EINVAL; -} - void drm_panel_init(struct drm_panel *panel); int drm_panel_add(struct drm_panel *panel); void drm_panel_remove(struct drm_panel *panel); int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector); -int drm_panel_detach(struct drm_panel *panel); +void drm_panel_detach(struct drm_panel *panel); + +int drm_panel_prepare(struct drm_panel *panel); +int drm_panel_unprepare(struct drm_panel *panel); + +int drm_panel_enable(struct drm_panel *panel); +int drm_panel_disable(struct drm_panel *panel); + +int drm_panel_get_modes(struct drm_panel *panel); #if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL) struct drm_panel *of_drm_find_panel(const struct device_node *np); diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 65ef5376de59..43c4929a2171 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h @@ -40,7 +40,7 @@ #include <linux/mutex.h> #include <linux/mm.h> #include <linux/bitmap.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> struct ttm_bo_global; @@ -273,7 +273,7 @@ struct ttm_bo_kmap_obj { struct ttm_operation_ctx { bool interruptible; bool no_wait_gpu; - struct reservation_object *resv; + struct dma_resv *resv; uint64_t bytes_moved; uint32_t flags; }; @@ -493,7 +493,7 @@ size_t ttm_bo_dma_acc_size(struct ttm_bo_device *bdev, * @page_alignment: Data alignment in pages. * @ctx: TTM operation context for memory allocation. * @acc_size: Accounted size for this object. - * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. * @destroy: Destroy function. Use NULL for kfree(). * * This function initializes a pre-allocated struct ttm_buffer_object. @@ -526,7 +526,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, struct ttm_operation_ctx *ctx, size_t acc_size, struct sg_table *sg, - struct reservation_object *resv, + struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)); /** @@ -545,7 +545,7 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, * point to the shmem object backing a GEM object if TTM is used to back a * GEM user interface. * @acc_size: Accounted size for this object. - * @resv: Pointer to a reservation_object, or NULL to let ttm allocate one. + * @resv: Pointer to a dma_resv, or NULL to let ttm allocate one. * @destroy: Destroy function. Use NULL for kfree(). * * This function initializes a pre-allocated struct ttm_buffer_object. @@ -570,7 +570,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, struct ttm_buffer_object *bo, unsigned long size, enum ttm_bo_type type, struct ttm_placement *placement, uint32_t page_alignment, bool interrubtible, size_t acc_size, - struct sg_table *sg, struct reservation_object *resv, + struct sg_table *sg, struct dma_resv *resv, void (*destroy) (struct ttm_buffer_object *)); /** diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 076d7ca0f8b6..6f536caea368 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -35,7 +35,7 @@ #include <linux/workqueue.h> #include <linux/fs.h> #include <linux/spinlock.h> -#include <linux/reservation.h> +#include <linux/dma-resv.h> #include "ttm_bo_api.h" #include "ttm_memory.h" @@ -664,14 +664,14 @@ static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, if (WARN_ON(ticket)) return -EBUSY; - success = reservation_object_trylock(bo->base.resv); + success = dma_resv_trylock(bo->base.resv); return success ? 0 : -EBUSY; } if (interruptible) - ret = reservation_object_lock_interruptible(bo->base.resv, ticket); + ret = dma_resv_lock_interruptible(bo->base.resv, ticket); else - ret = reservation_object_lock(bo->base.resv, ticket); + ret = dma_resv_lock(bo->base.resv, ticket); if (ret == -EINTR) return -ERESTARTSYS; return ret; @@ -755,10 +755,10 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, WARN_ON(!kref_read(&bo->kref)); if (interruptible) - ret = reservation_object_lock_slow_interruptible(bo->base.resv, + ret = dma_resv_lock_slow_interruptible(bo->base.resv, ticket); else - reservation_object_lock_slow(bo->base.resv, ticket); + dma_resv_lock_slow(bo->base.resv, ticket); if (likely(ret == 0)) ttm_bo_del_sub_from_lru(bo); @@ -783,7 +783,7 @@ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) else ttm_bo_move_to_lru_tail(bo, NULL); spin_unlock(&bo->bdev->glob->lru_lock); - reservation_object_unlock(bo->base.resv); + dma_resv_unlock(bo->base.resv); } /* diff --git a/include/linux/amba/clcd-regs.h b/include/linux/amba/clcd-regs.h index 516a6fda83c5..421b0fa90d6a 100644 --- a/include/linux/amba/clcd-regs.h +++ b/include/linux/amba/clcd-regs.h @@ -42,6 +42,7 @@ #define TIM2_PCD_LO_MASK GENMASK(4, 0) #define TIM2_PCD_LO_BITS 5 #define TIM2_CLKSEL (1 << 5) +#define TIM2_ACB_MASK GENMASK(10, 6) #define TIM2_IVS (1 << 11) #define TIM2_IHS (1 << 12) #define TIM2_IPC (1 << 13) diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index bae060fae862..ec212cb27fdc 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -306,7 +306,7 @@ struct dma_buf { struct module *owner; struct list_head list_node; void *priv; - struct reservation_object *resv; + struct dma_resv *resv; /* poll support */ wait_queue_head_t poll; @@ -365,7 +365,7 @@ struct dma_buf_export_info { const struct dma_buf_ops *ops; size_t size; int flags; - struct reservation_object *resv; + struct dma_resv *resv; void *priv; }; diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 05d29dbc7e62..3347c54f3a87 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -63,15 +63,35 @@ struct dma_fence_cb; * been completed, or never called at all. */ struct dma_fence { - struct kref refcount; - const struct dma_fence_ops *ops; - struct rcu_head rcu; - struct list_head cb_list; spinlock_t *lock; + const struct dma_fence_ops *ops; + /* + * We clear the callback list on kref_put so that by the time we + * release the fence it is unused. No one should be adding to the + * cb_list that they don't themselves hold a reference for. + * + * The lifetime of the timestamp is similarly tied to both the + * rcu freelist and the cb_list. The timestamp is only set upon + * signaling while simultaneously notifying the cb_list. Ergo, we + * only use either the cb_list of timestamp. Upon destruction, + * neither are accessible, and so we can use the rcu. This means + * that the cb_list is *only* valid until the signal bit is set, + * and to read either you *must* hold a reference to the fence, + * and not just the rcu_read_lock. + * + * Listed in chronological order. + */ + union { + struct list_head cb_list; + /* @cb_list replaced by @timestamp on dma_fence_signal() */ + ktime_t timestamp; + /* @timestamp replaced by @rcu on dma_fence_release() */ + struct rcu_head rcu; + }; u64 context; u64 seqno; unsigned long flags; - ktime_t timestamp; + struct kref refcount; int error; }; @@ -273,7 +293,7 @@ static inline struct dma_fence *dma_fence_get(struct dma_fence *fence) } /** - * dma_fence_get_rcu - get a fence from a reservation_object_list with + * dma_fence_get_rcu - get a fence from a dma_resv_list with * rcu read lock * @fence: fence to increase refcount of * @@ -297,7 +317,7 @@ static inline struct dma_fence *dma_fence_get_rcu(struct dma_fence *fence) * so long as the caller is using RCU on the pointer to the fence. * * An alternative mechanism is to employ a seqlock to protect a bunch of - * fences, such as used by struct reservation_object. When using a seqlock, + * fences, such as used by struct dma_resv. When using a seqlock, * the seqlock must be taken before and checked after a reference to the * fence is acquired (as shown here). * diff --git a/include/linux/reservation.h b/include/linux/dma-resv.h index 56b782fec49b..ee50d10f052b 100644 --- a/include/linux/reservation.h +++ b/include/linux/dma-resv.h @@ -50,54 +50,52 @@ extern struct lock_class_key reservation_seqcount_class; extern const char reservation_seqcount_string[]; /** - * struct reservation_object_list - a list of shared fences + * struct dma_resv_list - a list of shared fences * @rcu: for internal use * @shared_count: table of shared fences * @shared_max: for growing shared fence table * @shared: shared fence table */ -struct reservation_object_list { +struct dma_resv_list { struct rcu_head rcu; u32 shared_count, shared_max; struct dma_fence __rcu *shared[]; }; /** - * struct reservation_object - a reservation object manages fences for a buffer + * struct dma_resv - a reservation object manages fences for a buffer * @lock: update side lock * @seq: sequence count for managing RCU read-side synchronization * @fence_excl: the exclusive fence, if there is one currently * @fence: list of current shared fences */ -struct reservation_object { +struct dma_resv { struct ww_mutex lock; seqcount_t seq; struct dma_fence __rcu *fence_excl; - struct reservation_object_list __rcu *fence; + struct dma_resv_list __rcu *fence; }; -#define reservation_object_held(obj) lockdep_is_held(&(obj)->lock.base) -#define reservation_object_assert_held(obj) \ - lockdep_assert_held(&(obj)->lock.base) +#define dma_resv_held(obj) lockdep_is_held(&(obj)->lock.base) +#define dma_resv_assert_held(obj) lockdep_assert_held(&(obj)->lock.base) /** - * reservation_object_get_list - get the reservation object's + * dma_resv_get_list - get the reservation object's * shared fence list, with update-side lock held * @obj: the reservation object * * Returns the shared fence list. Does NOT take references to * the fence. The obj->lock must be held. */ -static inline struct reservation_object_list * -reservation_object_get_list(struct reservation_object *obj) +static inline struct dma_resv_list *dma_resv_get_list(struct dma_resv *obj) { return rcu_dereference_protected(obj->fence, - reservation_object_held(obj)); + dma_resv_held(obj)); } /** - * reservation_object_lock - lock the reservation object + * dma_resv_lock - lock the reservation object * @obj: the reservation object * @ctx: the locking context * @@ -111,15 +109,14 @@ reservation_object_get_list(struct reservation_object *obj) * is detected. See ww_mutex_lock() and ww_acquire_init(). A reservation * object may be locked by itself by passing NULL as @ctx. */ -static inline int -reservation_object_lock(struct reservation_object *obj, - struct ww_acquire_ctx *ctx) +static inline int dma_resv_lock(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) { return ww_mutex_lock(&obj->lock, ctx); } /** - * reservation_object_lock_interruptible - lock the reservation object + * dma_resv_lock_interruptible - lock the reservation object * @obj: the reservation object * @ctx: the locking context * @@ -133,48 +130,45 @@ reservation_object_lock(struct reservation_object *obj, * is detected. See ww_mutex_lock() and ww_acquire_init(). A reservation * object may be locked by itself by passing NULL as @ctx. */ -static inline int -reservation_object_lock_interruptible(struct reservation_object *obj, - struct ww_acquire_ctx *ctx) +static inline int dma_resv_lock_interruptible(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) { return ww_mutex_lock_interruptible(&obj->lock, ctx); } /** - * reservation_object_lock_slow - slowpath lock the reservation object + * dma_resv_lock_slow - slowpath lock the reservation object * @obj: the reservation object * @ctx: the locking context * * Acquires the reservation object after a die case. This function - * will sleep until the lock becomes available. See reservation_object_lock() as + * will sleep until the lock becomes available. See dma_resv_lock() as * well. */ -static inline void -reservation_object_lock_slow(struct reservation_object *obj, - struct ww_acquire_ctx *ctx) +static inline void dma_resv_lock_slow(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) { ww_mutex_lock_slow(&obj->lock, ctx); } /** - * reservation_object_lock_slow_interruptible - slowpath lock the reservation + * dma_resv_lock_slow_interruptible - slowpath lock the reservation * object, interruptible * @obj: the reservation object * @ctx: the locking context * * Acquires the reservation object interruptible after a die case. This function * will sleep until the lock becomes available. See - * reservation_object_lock_interruptible() as well. + * dma_resv_lock_interruptible() as well. */ -static inline int -reservation_object_lock_slow_interruptible(struct reservation_object *obj, - struct ww_acquire_ctx *ctx) +static inline int dma_resv_lock_slow_interruptible(struct dma_resv *obj, + struct ww_acquire_ctx *ctx) { return ww_mutex_lock_slow_interruptible(&obj->lock, ctx); } /** - * reservation_object_trylock - trylock the reservation object + * dma_resv_trylock - trylock the reservation object * @obj: the reservation object * * Tries to lock the reservation object for exclusive access and modification. @@ -187,51 +181,46 @@ reservation_object_lock_slow_interruptible(struct reservation_object *obj, * * Returns true if the lock was acquired, false otherwise. */ -static inline bool __must_check -reservation_object_trylock(struct reservation_object *obj) +static inline bool __must_check dma_resv_trylock(struct dma_resv *obj) { return ww_mutex_trylock(&obj->lock); } /** - * reservation_object_is_locked - is the reservation object locked + * dma_resv_is_locked - is the reservation object locked * @obj: the reservation object * * Returns true if the mutex is locked, false if unlocked. */ -static inline bool -reservation_object_is_locked(struct reservation_object *obj) +static inline bool dma_resv_is_locked(struct dma_resv *obj) { return ww_mutex_is_locked(&obj->lock); } /** - * reservation_object_locking_ctx - returns the context used to lock the object + * dma_resv_locking_ctx - returns the context used to lock the object * @obj: the reservation object * * Returns the context used to lock a reservation object or NULL if no context * was used or the object is not locked at all. */ -static inline struct ww_acquire_ctx * -reservation_object_locking_ctx(struct reservation_object *obj) +static inline struct ww_acquire_ctx *dma_resv_locking_ctx(struct dma_resv *obj) { return READ_ONCE(obj->lock.ctx); } /** - * reservation_object_unlock - unlock the reservation object + * dma_resv_unlock - unlock the reservation object * @obj: the reservation object * * Unlocks the reservation object following exclusive access. */ -static inline void -reservation_object_unlock(struct reservation_object *obj) +static inline void dma_resv_unlock(struct dma_resv *obj) { #ifdef CONFIG_DEBUG_MUTEXES /* Test shared fence slot reservation */ if (rcu_access_pointer(obj->fence)) { - struct reservation_object_list *fence = - reservation_object_get_list(obj); + struct dma_resv_list *fence = dma_resv_get_list(obj); fence->shared_max = fence->shared_count; } @@ -240,7 +229,7 @@ reservation_object_unlock(struct reservation_object *obj) } /** - * reservation_object_get_excl - get the reservation object's + * dma_resv_get_excl - get the reservation object's * exclusive fence, with update-side lock held * @obj: the reservation object * @@ -252,14 +241,14 @@ reservation_object_unlock(struct reservation_object *obj) * The exclusive fence or NULL */ static inline struct dma_fence * -reservation_object_get_excl(struct reservation_object *obj) +dma_resv_get_excl(struct dma_resv *obj) { return rcu_dereference_protected(obj->fence_excl, - reservation_object_held(obj)); + dma_resv_held(obj)); } /** - * reservation_object_get_excl_rcu - get the reservation object's + * dma_resv_get_excl_rcu - get the reservation object's * exclusive fence, without lock held. * @obj: the reservation object * @@ -270,7 +259,7 @@ reservation_object_get_excl(struct reservation_object *obj) * The exclusive fence or NULL if none */ static inline struct dma_fence * -reservation_object_get_excl_rcu(struct reservation_object *obj) +dma_resv_get_excl_rcu(struct dma_resv *obj) { struct dma_fence *fence; @@ -284,29 +273,23 @@ reservation_object_get_excl_rcu(struct reservation_object *obj) return fence; } -void reservation_object_init(struct reservation_object *obj); -void reservation_object_fini(struct reservation_object *obj); -int reservation_object_reserve_shared(struct reservation_object *obj, - unsigned int num_fences); -void reservation_object_add_shared_fence(struct reservation_object *obj, - struct dma_fence *fence); +void dma_resv_init(struct dma_resv *obj); +void dma_resv_fini(struct dma_resv *obj); +int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences); +void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence); -void reservation_object_add_excl_fence(struct reservation_object *obj, - struct dma_fence *fence); +void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); -int reservation_object_get_fences_rcu(struct reservation_object *obj, - struct dma_fence **pfence_excl, - unsigned *pshared_count, - struct dma_fence ***pshared); +int dma_resv_get_fences_rcu(struct dma_resv *obj, + struct dma_fence **pfence_excl, + unsigned *pshared_count, + struct dma_fence ***pshared); -int reservation_object_copy_fences(struct reservation_object *dst, - struct reservation_object *src); +int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); -long reservation_object_wait_timeout_rcu(struct reservation_object *obj, - bool wait_all, bool intr, - unsigned long timeout); +long dma_resv_wait_timeout_rcu(struct dma_resv *obj, bool wait_all, bool intr, + unsigned long timeout); -bool reservation_object_test_signaled_rcu(struct reservation_object *obj, - bool test_all); +bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all); #endif /* _LINUX_RESERVATION_H */ diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h index cb577fb96b38..ec19db1eead8 100644 --- a/include/uapi/drm/panfrost_drm.h +++ b/include/uapi/drm/panfrost_drm.h @@ -20,6 +20,7 @@ extern "C" { #define DRM_PANFROST_GET_BO_OFFSET 0x05 #define DRM_PANFROST_PERFCNT_ENABLE 0x06 #define DRM_PANFROST_PERFCNT_DUMP 0x07 +#define DRM_PANFROST_MADVISE 0x08 #define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) #define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) @@ -27,6 +28,7 @@ extern "C" { #define DRM_IOCTL_PANFROST_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MMAP_BO, struct drm_panfrost_mmap_bo) #define DRM_IOCTL_PANFROST_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_PARAM, struct drm_panfrost_get_param) #define DRM_IOCTL_PANFROST_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_BO_OFFSET, struct drm_panfrost_get_bo_offset) +#define DRM_IOCTL_PANFROST_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MADVISE, struct drm_panfrost_madvise) /* * Unstable ioctl(s): only exposed when the unsafe unstable_ioctls module @@ -82,6 +84,9 @@ struct drm_panfrost_wait_bo { __s64 timeout_ns; /* absolute */ }; +#define PANFROST_BO_NOEXEC 1 +#define PANFROST_BO_HEAP 2 + /** * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. * @@ -198,6 +203,26 @@ struct drm_panfrost_perfcnt_dump { __u64 buf_ptr; }; +/* madvise provides a way to tell the kernel in case a buffers contents + * can be discarded under memory pressure, which is useful for userspace + * bo cache where we want to optimistically hold on to buffer allocate + * and potential mmap, but allow the pages to be discarded under memory + * pressure. + * + * Typical usage would involve madvise(DONTNEED) when buffer enters BO + * cache, and madvise(WILLNEED) if trying to recycle buffer from BO cache. + * In the WILLNEED case, 'retained' indicates to userspace whether the + * backing pages still exist. + */ +#define PANFROST_MADV_WILLNEED 0 /* backing pages are needed, status returned in 'retained' */ +#define PANFROST_MADV_DONTNEED 1 /* backing pages not needed */ + +struct drm_panfrost_madvise { + __u32 handle; /* in, GEM handle */ + __u32 madv; /* in, PANFROST_MADV_x */ + __u32 retained; /* out, whether backing store still exists */ +}; + #if defined(__cplusplus) } #endif |