diff options
81 files changed, 2444 insertions, 1188 deletions
| diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt new file mode 100644 index 000000000000..fd39ad34c383 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -0,0 +1,64 @@ +Parallel to LVDS Encoder +------------------------ + +This binding supports the parallel to LVDS encoders that don't require any +configuration. + +LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple +incompatible data link layers have been used over time to transmit image data +to LVDS panels. This binding targets devices compatible with the following +specifications only. + +[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February +1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) +[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National +Semiconductor +[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video +Electronics Standards Association (VESA) + +Those devices have been marketed under the FPD-Link and FlatLink brand names +among others. + + +Required properties: + +- compatible: Must be "lvds-encoder" + +Required nodes: + +This device has two video ports. Their connections are modeled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for parallel input +- Video port 1 for LVDS output + + +Example +------- + +lvds-encoder { +	compatible = "lvds-encoder"; +	#address-cells = <1>; +	#size-cells = <0>; + +	ports { +		#address-cells = <1>; +		#size-cells = <0>; + +		port@0 { +			reg = <0>; + +			lvds_enc_in: endpoint { +				remote-endpoint = <&display_out_rgb>; +			}; +		}; + +		port@1 { +			reg = <1>; + +			lvds_enc_out: endpoint { +				remote-endpoint = <&lvds_panel_in>; +			}; +		}; +	}; +}; diff --git a/Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt b/Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt new file mode 100644 index 000000000000..7baa6582517e --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt @@ -0,0 +1,94 @@ +Drivers for the second video output of the GE B850v3: +   STDP4028-ge-b850v3-fw bridges (LVDS-DP) +   STDP2690-ge-b850v3-fw bridges (DP-DP++) + +The video processing pipeline on the second output on the GE B850v3: + +   Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output + +Each bridge has a dedicated flash containing firmware for supporting the custom +design. The result is that, in this design, neither the STDP4028 nor the +STDP2690 behave as the stock bridges would. The compatible strings include the +suffix "-ge-b850v3-fw" to make it clear that the driver is for the bridges with +the firmware specific for the GE B850v3. + +The hardware do not provide control over the video processing pipeline, as the +two bridges behaves as a single one. The only interfaces exposed by the +hardware are EDID, HPD, and interrupts. + +stdp4028-ge-b850v3-fw required properties: +  - compatible : "megachips,stdp4028-ge-b850v3-fw" +  - reg : I2C bus address +  - interrupt-parent : phandle of the interrupt controller that services +    interrupts to the device +  - interrupts : one interrupt should be described here, as in +    <0 IRQ_TYPE_LEVEL_HIGH> +  - ports : One input port(reg = <0>) and one output port(reg = <1>) + +stdp2690-ge-b850v3-fw required properties: +    compatible : "megachips,stdp2690-ge-b850v3-fw" +  - reg : I2C bus address +  - ports : One input port(reg = <0>) and one output port(reg = <1>) + +Example: + +&mux2_i2c2 { +	status = "okay"; +	clock-frequency = <100000>; + +	stdp4028@73 { +		compatible = "megachips,stdp4028-ge-b850v3-fw"; +		#address-cells = <1>; +		#size-cells = <0>; + +		reg = <0x73>; + +		interrupt-parent = <&gpio2>; +		interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + +		ports { +			#address-cells = <1>; +			#size-cells = <0>; + +			port@0 { +				reg = <0>; +				stdp4028_in: endpoint { +					remote-endpoint = <&lvds0_out>; +				}; +			}; +			port@1 { +				reg = <1>; +				stdp4028_out: endpoint { +					remote-endpoint = <&stdp2690_in>; +				}; +			}; +		}; +	}; + +	stdp2690@72 { +		compatible = "megachips,stdp2690-ge-b850v3-fw"; +		#address-cells = <1>; +		#size-cells = <0>; + +		reg = <0x72>; + +		ports { +			#address-cells = <1>; +			#size-cells = <0>; + +			port@0 { +				reg = <0>; +				stdp2690_in: endpoint { +					remote-endpoint = <&stdp4028_out>; +				}; +			}; + +			port@1 { +				reg = <1>; +				stdp2690_out: endpoint { +					/* Connector for external display */ +				}; +			}; +		}; +	}; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ec0bfb9bbebd..4686f4bdaca0 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -178,6 +178,7 @@ maxim	Maxim Integrated Products  mcube	mCube  meas	Measurement Specialties  mediatek	MediaTek Inc. +megachips	MegaChips  melexis	Melexis N.V.  melfas	MELFAS Inc.  memsic	MEMSIC Inc. diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index e35920db1f4c..3bb4d937cdfe 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -240,9 +240,6 @@ drivers.  .. kernel-doc:: drivers/gpu/drm/drm_pci.c     :export: -.. kernel-doc:: drivers/gpu/drm/drm_platform.c -   :export: -  Open/Close, File Operations and IOCTLs  ====================================== @@ -298,10 +295,10 @@ over.  File Operations  --------------- -.. kernel-doc:: drivers/gpu/drm/drm_fops.c +.. kernel-doc:: drivers/gpu/drm/drm_file.c     :doc: file operations -.. kernel-doc:: drivers/gpu/drm/drm_fops.c +.. kernel-doc:: drivers/gpu/drm/drm_file.c     :export:  IOCTLs diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index fd35998acefc..d7a29d41789f 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -449,6 +449,9 @@ PRIME Helper Functions  PRIME Function References  ------------------------- +.. kernel-doc:: include/drm/drm_prime.h +   :internal: +  .. kernel-doc:: drivers/gpu/drm/drm_prime.c     :export: diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index ce0f1a588e7f..64e9d16170ce 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -153,6 +153,19 @@ following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and  Contact: Daniel Vetter +Switch to drm_connector_list_iter for any connector_list walking +---------------------------------------------------------------- + +Connectors can be hotplugged, and we now have a special list of helpers to walk +the connector_list in a race-free fashion, without incurring deadlocks on +mutexes and other fun stuff. + +Unfortunately most drivers are not converted yet. At least all those supporting +DP MST hotplug should be converted, since for those drivers the difference +matters. See drm_for_each_connector_iter() vs. drm_for_each_connector(). + +Contact: Daniel Vetter +  Core refactorings  ================= diff --git a/MAINTAINERS b/MAINTAINERS index 4084e2fa39c9..e88154f2226c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8123,6 +8123,14 @@ L:	linux-wireless@vger.kernel.org  S:	Maintained  F:	drivers/net/wireless/mediatek/mt7601u/ +MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES +M:	Peter Senna Tschudin <peter.senna@collabora.com> +M:	Martin Donnelly <martin.donnelly@ge.com> +M:	Martyn Welch <martyn.welch@collabora.co.uk> +S:	Maintained +F:	drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +F:	Documentation/devicetree/bindings/video/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt +  MEGARAID SCSI/SAS DRIVERS  M:	Kashyap Desai <kashyap.desai@broadcom.com>  M:	Sumit Saxena <sumit.saxena@broadcom.com> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 3ee95793d122..59aae43005ee 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -4,10 +4,10 @@  drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \  		drm_context.o drm_dma.o \ -		drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ +		drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \  		drm_lock.o drm_memory.o drm_drv.o \  		drm_scatter.o drm_pci.o \ -		drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ +		drm_sysfs.o drm_hashtab.o drm_mm.o \  		drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \  		drm_info.o drm_encoder_slave.o \  		drm_trace_points.o drm_global.o drm_prime.o \ diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 1952e8748fea..408e00b64cf6 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -137,10 +137,9 @@ static int armada_drm_bind(struct device *dev)  		return ret;  	} -	priv->drm.platformdev = to_platform_device(dev);  	priv->drm.dev_private = priv; -	platform_set_drvdata(priv->drm.platformdev, &priv->drm); +	dev_set_drvdata(dev, &priv->drm);  	INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);  	INIT_KFIFO(priv->fb_unref); diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index eb8688ec6f18..f6968d3b4b41 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -24,29 +24,25 @@ config DRM_DUMB_VGA_DAC  	help  	  Support for RGB to VGA DAC based bridges -config DRM_DW_HDMI -	tristate +config DRM_LVDS_ENCODER +	tristate "Transparent parallel to LVDS encoder support" +	depends on OF  	select DRM_KMS_HELPER - -config DRM_DW_HDMI_AHB_AUDIO -	tristate "Synopsis Designware AHB Audio interface" -	depends on DRM_DW_HDMI && SND -	select SND_PCM -	select SND_PCM_ELD -	select SND_PCM_IEC958 +	select DRM_PANEL  	help -	  Support the AHB Audio interface which is part of the Synopsis -	  Designware HDMI block.  This is used in conjunction with -	  the i.MX6 HDMI driver. +	  Support for transparent parallel to LVDS encoders that don't require +	  any configuration. -config DRM_DW_HDMI_I2S_AUDIO -	tristate "Synopsis Designware I2S Audio interface" -	depends on SND_SOC -	depends on DRM_DW_HDMI -	select SND_SOC_HDMI_CODEC -	help -	  Support the I2S Audio interface which is part of the Synopsis -	  Designware HDMI block. +config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW +	tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw" +	depends on OF +	select DRM_KMS_HELPER +	select DRM_PANEL +	---help--- +          This is a driver for the display bridges of +          GE B850v3 that convert dual channel LVDS +          to DP++. This is used with the i.MX6 imx-ldb +          driver. You are likely to say N here.  config DRM_NXP_PTN3460  	tristate "NXP PTN3460 DP/LVDS bridge" @@ -101,4 +97,6 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig"  source "drivers/gpu/drm/bridge/adv7511/Kconfig" +source "drivers/gpu/drm/bridge/synopsys/Kconfig" +  endmenu diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 2e83a7855399..3fe2226ee2f2 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -2,9 +2,8 @@ ccflags-y := -Iinclude/drm  obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o  obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o -obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o -obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o -obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o +obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o +obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o  obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o  obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o  obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o @@ -13,3 +12,4 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o  obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/  obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/  obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o +obj-y += synopsys/ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index e7cd1056ff2d..c26997afd3cf 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1488,6 +1488,28 @@ int analogix_dp_resume(struct device *dev)  EXPORT_SYMBOL_GPL(analogix_dp_resume);  #endif +int analogix_dp_start_crc(struct drm_connector *connector) +{ +	struct analogix_dp_device *dp = to_dp(connector); + +	if (!connector->state->crtc) { +		DRM_ERROR("Connector %s doesn't currently have a CRTC.\n", +			  connector->name); +		return -EINVAL; +	} + +	return drm_dp_start_crc(&dp->aux, connector->state->crtc); +} +EXPORT_SYMBOL_GPL(analogix_dp_start_crc); + +int analogix_dp_stop_crc(struct drm_connector *connector) +{ +	struct analogix_dp_device *dp = to_dp(connector); + +	return drm_dp_stop_crc(&dp->aux); +} +EXPORT_SYMBOL_GPL(analogix_dp_stop_crc); +  MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");  MODULE_DESCRIPTION("Analogix DP Core Driver");  MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c index 86e9f9c7b59c..63e113bd21d2 100644 --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -237,6 +237,7 @@ static int dumb_vga_remove(struct platform_device *pdev)  static const struct of_device_id dumb_vga_match[] = {  	{ .compatible = "dumb-vga-dac" }, +	{ .compatible = "adi,adv7123" },  	{ .compatible = "ti,ths8135" },  	{},  }; diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c new file mode 100644 index 000000000000..f1f67a279426 --- /dev/null +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_connector.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_encoder.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_panel.h> + +#include <linux/of_graph.h> + +struct lvds_encoder { +	struct device *dev; + +	struct drm_bridge bridge; +	struct drm_connector connector; +	struct drm_panel *panel; +}; + +static inline struct lvds_encoder * +drm_bridge_to_lvds_encoder(struct drm_bridge *bridge) +{ +	return container_of(bridge, struct lvds_encoder, bridge); +} + +static inline struct lvds_encoder * +drm_connector_to_lvds_encoder(struct drm_connector *connector) +{ +	return container_of(connector, struct lvds_encoder, connector); +} + +static int lvds_connector_get_modes(struct drm_connector *connector) +{ +	struct lvds_encoder *lvds = drm_connector_to_lvds_encoder(connector); + +	return drm_panel_get_modes(lvds->panel); +} + +static const struct drm_connector_helper_funcs lvds_connector_helper_funcs = { +	.get_modes = lvds_connector_get_modes, +}; + +static const struct drm_connector_funcs lvds_connector_funcs = { +	.dpms = drm_atomic_helper_connector_dpms, +	.reset = drm_atomic_helper_connector_reset, +	.fill_modes = drm_helper_probe_single_connector_modes, +	.destroy = drm_connector_cleanup, +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int lvds_encoder_attach(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge); +	struct drm_connector *connector = &lvds->connector; +	int ret; + +	if (!bridge->encoder) { +		DRM_ERROR("Missing encoder\n"); +		return -ENODEV; +	} + +	drm_connector_helper_add(connector, &lvds_connector_helper_funcs); + +	ret = drm_connector_init(bridge->dev, connector, &lvds_connector_funcs, +				 DRM_MODE_CONNECTOR_LVDS); +	if (ret) { +		DRM_ERROR("Failed to initialize connector\n"); +		return ret; +	} + +	drm_mode_connector_attach_encoder(&lvds->connector, bridge->encoder); + +	ret = drm_panel_attach(lvds->panel, &lvds->connector); +	if (ret < 0) +		return ret; + +	return 0; +} + +static void lvds_encoder_detach(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge); + +	drm_panel_detach(lvds->panel); +} + +static void lvds_encoder_pre_enable(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge); + +	drm_panel_prepare(lvds->panel); +} + +static void lvds_encoder_enable(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge); + +	drm_panel_enable(lvds->panel); +} + +static void lvds_encoder_disable(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge); + +	drm_panel_disable(lvds->panel); +} + +static void lvds_encoder_post_disable(struct drm_bridge *bridge) +{ +	struct lvds_encoder *lvds = drm_bridge_to_lvds_encoder(bridge); + +	drm_panel_unprepare(lvds->panel); +} + +static const struct drm_bridge_funcs lvds_encoder_bridge_funcs = { +	.attach = lvds_encoder_attach, +	.detach = lvds_encoder_detach, +	.pre_enable = lvds_encoder_pre_enable, +	.enable = lvds_encoder_enable, +	.disable = lvds_encoder_disable, +	.post_disable = lvds_encoder_post_disable, +}; + +static int lvds_encoder_probe(struct platform_device *pdev) +{ +	struct lvds_encoder *lvds; +	struct device_node *port; +	struct device_node *endpoint; +	struct device_node *panel; + +	lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); +	if (!lvds) +		return -ENOMEM; + +	lvds->dev = &pdev->dev; +	platform_set_drvdata(pdev, lvds); + +	lvds->bridge.funcs = &lvds_encoder_bridge_funcs; +	lvds->bridge.of_node = pdev->dev.of_node; + +	/* Locate the panel DT node. */ +	port = of_graph_get_port_by_id(pdev->dev.of_node, 1); +	if (!port) { +		dev_dbg(&pdev->dev, "port 1 not found\n"); +		return -ENXIO; +	} + +	endpoint = of_get_child_by_name(port, "endpoint"); +	of_node_put(port); +	if (!endpoint) { +		dev_dbg(&pdev->dev, "no endpoint for port 1\n"); +		return -ENXIO; +	} + +	panel = of_graph_get_remote_port_parent(endpoint); +	of_node_put(endpoint); +	if (!panel) { +		dev_dbg(&pdev->dev, "no remote endpoint for port 1\n"); +		return -ENXIO; +	} + +	lvds->panel = of_drm_find_panel(panel); +	of_node_put(panel); +	if (!lvds->panel) { +		dev_dbg(&pdev->dev, "panel not found, deferring probe\n"); +		return -EPROBE_DEFER; +	} + +	/* Register the bridge. */ +	return drm_bridge_add(&lvds->bridge); +} + +static int lvds_encoder_remove(struct platform_device *pdev) +{ +	struct lvds_encoder *encoder = platform_get_drvdata(pdev); + +	drm_bridge_remove(&encoder->bridge); + +	return 0; +} + +static const struct of_device_id lvds_encoder_match[] = { +	{ .compatible = "lvds-encoder" }, +	{ .compatible = "thine,thc63lvdm83d" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, lvds_encoder_match); + +static struct platform_driver lvds_encoder_driver = { +	.probe	= lvds_encoder_probe, +	.remove	= lvds_encoder_remove, +	.driver		= { +		.name		= "lvds-encoder", +		.of_match_table	= lvds_encoder_match, +	}, +}; +module_platform_driver(lvds_encoder_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Transparent parallel to LVDS encoder"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c new file mode 100644 index 000000000000..cfc606a13a6d --- /dev/null +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -0,0 +1,428 @@ +/* + * Driver for MegaChips STDP4028 with GE B850v3 firmware (LVDS-DP) + * Driver for MegaChips STDP2690 with GE B850v3 firmware (DP-DP++) + + * Copyright (c) 2017, Collabora Ltd. + * Copyright (c) 2017, General Electric Company + + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + + * This driver creates a drm_bridge and a drm_connector for the LVDS to DP++ + * display bridge of the GE B850v3. There are two physical bridges on the video + * signal pipeline: a STDP4028(LVDS to DP) and a STDP2690(DP to DP++). The + * physical bridges are automatically configured by the input video signal, and + * the driver has no access to the video processing pipeline. The driver is + * only needed to read EDID from the STDP2690 and to handle HPD events from the + * STDP4028. The driver communicates with both bridges over i2c. The video + * signal pipeline is as follows: + * + *   Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output + * + */ + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_edid.h> +#include <drm/drmP.h> + +#define EDID_EXT_BLOCK_CNT 0x7E + +#define STDP4028_IRQ_OUT_CONF_REG 0x02 +#define STDP4028_DPTX_IRQ_EN_REG 0x3C +#define STDP4028_DPTX_IRQ_STS_REG 0x3D +#define STDP4028_DPTX_STS_REG 0x3E + +#define STDP4028_DPTX_DP_IRQ_EN 0x1000 + +#define STDP4028_DPTX_HOTPLUG_IRQ_EN 0x0400 +#define STDP4028_DPTX_LINK_CH_IRQ_EN 0x2000 +#define STDP4028_DPTX_IRQ_CONFIG \ +		(STDP4028_DPTX_LINK_CH_IRQ_EN | STDP4028_DPTX_HOTPLUG_IRQ_EN) + +#define STDP4028_DPTX_HOTPLUG_STS 0x0200 +#define STDP4028_DPTX_LINK_STS 0x1000 +#define STDP4028_CON_STATE_CONNECTED \ +		(STDP4028_DPTX_HOTPLUG_STS | STDP4028_DPTX_LINK_STS) + +#define STDP4028_DPTX_HOTPLUG_CH_STS 0x0400 +#define STDP4028_DPTX_LINK_CH_STS 0x2000 +#define STDP4028_DPTX_IRQ_CLEAR \ +		(STDP4028_DPTX_LINK_CH_STS | STDP4028_DPTX_HOTPLUG_CH_STS) + +static DEFINE_MUTEX(ge_b850v3_lvds_dev_mutex); + +struct ge_b850v3_lvds { +	struct drm_connector connector; +	struct drm_bridge bridge; +	struct i2c_client *stdp4028_i2c; +	struct i2c_client *stdp2690_i2c; +	struct edid *edid; +}; + +static struct ge_b850v3_lvds *ge_b850v3_lvds_ptr; + +static u8 *stdp2690_get_edid(struct i2c_client *client) +{ +	struct i2c_adapter *adapter = client->adapter; +	unsigned char start = 0x00; +	unsigned int total_size; +	u8 *block = kmalloc(EDID_LENGTH, GFP_KERNEL); + +	struct i2c_msg msgs[] = { +		{ +			.addr	= client->addr, +			.flags	= 0, +			.len	= 1, +			.buf	= &start, +		}, { +			.addr	= client->addr, +			.flags	= I2C_M_RD, +			.len	= EDID_LENGTH, +			.buf	= block, +		} +	}; + +	if (!block) +		return NULL; + +	if (i2c_transfer(adapter, msgs, 2) != 2) { +		DRM_ERROR("Unable to read EDID.\n"); +		goto err; +	} + +	if (!drm_edid_block_valid(block, 0, false, NULL)) { +		DRM_ERROR("Invalid EDID data\n"); +		goto err; +	} + +	total_size = (block[EDID_EXT_BLOCK_CNT] + 1) * EDID_LENGTH; +	if (total_size > EDID_LENGTH) { +		kfree(block); +		block = kmalloc(total_size, GFP_KERNEL); +		if (!block) +			return NULL; + +		/* Yes, read the entire buffer, and do not skip the first +		 * EDID_LENGTH bytes. +		 */ +		start = 0x00; +		msgs[1].len = total_size; +		msgs[1].buf = block; + +		if (i2c_transfer(adapter, msgs, 2) != 2) { +			DRM_ERROR("Unable to read EDID extension blocks.\n"); +			goto err; +		} +		if (!drm_edid_block_valid(block, 1, false, NULL)) { +			DRM_ERROR("Invalid EDID data\n"); +			goto err; +		} +	} + +	return block; + +err: +	kfree(block); +	return NULL; +} + +static int ge_b850v3_lvds_get_modes(struct drm_connector *connector) +{ +	struct i2c_client *client; +	int num_modes = 0; + +	client = ge_b850v3_lvds_ptr->stdp2690_i2c; + +	kfree(ge_b850v3_lvds_ptr->edid); +	ge_b850v3_lvds_ptr->edid = (struct edid *)stdp2690_get_edid(client); + +	if (ge_b850v3_lvds_ptr->edid) { +		drm_mode_connector_update_edid_property(connector, +						      ge_b850v3_lvds_ptr->edid); +		num_modes = drm_add_edid_modes(connector, +					       ge_b850v3_lvds_ptr->edid); +	} + +	return num_modes; +} + +static enum drm_mode_status ge_b850v3_lvds_mode_valid( +		struct drm_connector *connector, struct drm_display_mode *mode) +{ +	return MODE_OK; +} + +static const struct +drm_connector_helper_funcs ge_b850v3_lvds_connector_helper_funcs = { +	.get_modes = ge_b850v3_lvds_get_modes, +	.mode_valid = ge_b850v3_lvds_mode_valid, +}; + +static enum drm_connector_status ge_b850v3_lvds_detect( +		struct drm_connector *connector, bool force) +{ +	struct i2c_client *stdp4028_i2c = +			ge_b850v3_lvds_ptr->stdp4028_i2c; +	s32 link_state; + +	link_state = i2c_smbus_read_word_data(stdp4028_i2c, +					      STDP4028_DPTX_STS_REG); + +	if (link_state == STDP4028_CON_STATE_CONNECTED) +		return connector_status_connected; + +	if (link_state == 0) +		return connector_status_disconnected; + +	return connector_status_unknown; +} + +static const struct drm_connector_funcs ge_b850v3_lvds_connector_funcs = { +	.dpms = drm_atomic_helper_connector_dpms, +	.fill_modes = drm_helper_probe_single_connector_modes, +	.detect = ge_b850v3_lvds_detect, +	.destroy = drm_connector_cleanup, +	.reset = drm_atomic_helper_connector_reset, +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id) +{ +	struct i2c_client *stdp4028_i2c +			= ge_b850v3_lvds_ptr->stdp4028_i2c; + +	i2c_smbus_write_word_data(stdp4028_i2c, +				  STDP4028_DPTX_IRQ_STS_REG, +				  STDP4028_DPTX_IRQ_CLEAR); + +	if (ge_b850v3_lvds_ptr->connector.dev) +		drm_kms_helper_hotplug_event(ge_b850v3_lvds_ptr->connector.dev); + +	return IRQ_HANDLED; +} + +static int ge_b850v3_lvds_attach(struct drm_bridge *bridge) +{ +	struct drm_connector *connector = &ge_b850v3_lvds_ptr->connector; +	struct i2c_client *stdp4028_i2c +			= ge_b850v3_lvds_ptr->stdp4028_i2c; +	int ret; + +	if (!bridge->encoder) { +		DRM_ERROR("Parent encoder object not found"); +		return -ENODEV; +	} + +	connector->polled = DRM_CONNECTOR_POLL_HPD; + +	drm_connector_helper_add(connector, +				 &ge_b850v3_lvds_connector_helper_funcs); + +	ret = drm_connector_init(bridge->dev, connector, +				 &ge_b850v3_lvds_connector_funcs, +				 DRM_MODE_CONNECTOR_DisplayPort); +	if (ret) { +		DRM_ERROR("Failed to initialize connector with drm\n"); +		return ret; +	} + +	ret = drm_mode_connector_attach_encoder(connector, bridge->encoder); +	if (ret) +		return ret; + +	/* Configures the bridge to re-enable interrupts after each ack. */ +	i2c_smbus_write_word_data(stdp4028_i2c, +				  STDP4028_IRQ_OUT_CONF_REG, +				  STDP4028_DPTX_DP_IRQ_EN); + +	/* Enable interrupts */ +	i2c_smbus_write_word_data(stdp4028_i2c, +				  STDP4028_DPTX_IRQ_EN_REG, +				  STDP4028_DPTX_IRQ_CONFIG); + +	return 0; +} + +static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = { +	.attach = ge_b850v3_lvds_attach, +}; + +static int ge_b850v3_lvds_init(struct device *dev) +{ +	mutex_lock(&ge_b850v3_lvds_dev_mutex); + +	if (ge_b850v3_lvds_ptr) +		goto success; + +	ge_b850v3_lvds_ptr = devm_kzalloc(dev, +					  sizeof(*ge_b850v3_lvds_ptr), +					  GFP_KERNEL); + +	if (!ge_b850v3_lvds_ptr) { +		mutex_unlock(&ge_b850v3_lvds_dev_mutex); +		return -ENOMEM; +	} + +	ge_b850v3_lvds_ptr->bridge.funcs = &ge_b850v3_lvds_funcs; +	ge_b850v3_lvds_ptr->bridge.of_node = dev->of_node; +	drm_bridge_add(&ge_b850v3_lvds_ptr->bridge); + +success: +	mutex_unlock(&ge_b850v3_lvds_dev_mutex); +	return 0; +} + +static void ge_b850v3_lvds_remove(void) +{ +	mutex_lock(&ge_b850v3_lvds_dev_mutex); +	/* +	 * This check is to avoid both the drivers +	 * removing the bridge in their remove() function +	 */ +	if (!ge_b850v3_lvds_ptr) +		goto out; + +	drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); + +	kfree(ge_b850v3_lvds_ptr->edid); + +	ge_b850v3_lvds_ptr = NULL; +out: +	mutex_unlock(&ge_b850v3_lvds_dev_mutex); +} + +static int stdp4028_ge_b850v3_fw_probe(struct i2c_client *stdp4028_i2c, +				       const struct i2c_device_id *id) +{ +	struct device *dev = &stdp4028_i2c->dev; + +	ge_b850v3_lvds_init(dev); + +	ge_b850v3_lvds_ptr->stdp4028_i2c = stdp4028_i2c; +	i2c_set_clientdata(stdp4028_i2c, ge_b850v3_lvds_ptr); + +	/* Clear pending interrupts since power up. */ +	i2c_smbus_write_word_data(stdp4028_i2c, +				  STDP4028_DPTX_IRQ_STS_REG, +				  STDP4028_DPTX_IRQ_CLEAR); + +	if (!stdp4028_i2c->irq) +		return 0; + +	return devm_request_threaded_irq(&stdp4028_i2c->dev, +			stdp4028_i2c->irq, NULL, +			ge_b850v3_lvds_irq_handler, +			IRQF_TRIGGER_HIGH | IRQF_ONESHOT, +			"ge-b850v3-lvds-dp", ge_b850v3_lvds_ptr); +} + +static int stdp4028_ge_b850v3_fw_remove(struct i2c_client *stdp4028_i2c) +{ +	ge_b850v3_lvds_remove(); + +	return 0; +} + +static const struct i2c_device_id stdp4028_ge_b850v3_fw_i2c_table[] = { +	{"stdp4028_ge_fw", 0}, +	{}, +}; +MODULE_DEVICE_TABLE(i2c, stdp4028_ge_b850v3_fw_i2c_table); + +static const struct of_device_id stdp4028_ge_b850v3_fw_match[] = { +	{ .compatible = "megachips,stdp4028-ge-b850v3-fw" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, stdp4028_ge_b850v3_fw_match); + +static struct i2c_driver stdp4028_ge_b850v3_fw_driver = { +	.id_table	= stdp4028_ge_b850v3_fw_i2c_table, +	.probe		= stdp4028_ge_b850v3_fw_probe, +	.remove		= stdp4028_ge_b850v3_fw_remove, +	.driver		= { +		.name		= "stdp4028-ge-b850v3-fw", +		.of_match_table = stdp4028_ge_b850v3_fw_match, +	}, +}; + +static int stdp2690_ge_b850v3_fw_probe(struct i2c_client *stdp2690_i2c, +				       const struct i2c_device_id *id) +{ +	struct device *dev = &stdp2690_i2c->dev; + +	ge_b850v3_lvds_init(dev); + +	ge_b850v3_lvds_ptr->stdp2690_i2c = stdp2690_i2c; +	i2c_set_clientdata(stdp2690_i2c, ge_b850v3_lvds_ptr); + +	return 0; +} + +static int stdp2690_ge_b850v3_fw_remove(struct i2c_client *stdp2690_i2c) +{ +	ge_b850v3_lvds_remove(); + +	return 0; +} + +static const struct i2c_device_id stdp2690_ge_b850v3_fw_i2c_table[] = { +	{"stdp2690_ge_fw", 0}, +	{}, +}; +MODULE_DEVICE_TABLE(i2c, stdp2690_ge_b850v3_fw_i2c_table); + +static const struct of_device_id stdp2690_ge_b850v3_fw_match[] = { +	{ .compatible = "megachips,stdp2690-ge-b850v3-fw" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, stdp2690_ge_b850v3_fw_match); + +static struct i2c_driver stdp2690_ge_b850v3_fw_driver = { +	.id_table	= stdp2690_ge_b850v3_fw_i2c_table, +	.probe		= stdp2690_ge_b850v3_fw_probe, +	.remove		= stdp2690_ge_b850v3_fw_remove, +	.driver		= { +		.name		= "stdp2690-ge-b850v3-fw", +		.of_match_table = stdp2690_ge_b850v3_fw_match, +	}, +}; + +static int __init stdpxxxx_ge_b850v3_init(void) +{ +	int ret; + +	ret = i2c_add_driver(&stdp4028_ge_b850v3_fw_driver); +	if (ret) +		return ret; + +	return i2c_add_driver(&stdp2690_ge_b850v3_fw_driver); +} +module_init(stdpxxxx_ge_b850v3_init); + +static void __exit stdpxxxx_ge_b850v3_exit(void) +{ +	i2c_del_driver(&stdp2690_ge_b850v3_fw_driver); +	i2c_del_driver(&stdp4028_ge_b850v3_fw_driver); +} +module_exit(stdpxxxx_ge_b850v3_exit); + +MODULE_AUTHOR("Peter Senna Tschudin <peter.senna@collabora.com>"); +MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk>"); +MODULE_DESCRIPTION("GE LVDS to DP++ display bridge)"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig new file mode 100644 index 000000000000..40d2827a6d19 --- /dev/null +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig @@ -0,0 +1,23 @@ +config DRM_DW_HDMI +	tristate +	select DRM_KMS_HELPER + +config DRM_DW_HDMI_AHB_AUDIO +	tristate "Synopsys Designware AHB Audio interface" +	depends on DRM_DW_HDMI && SND +	select SND_PCM +	select SND_PCM_ELD +	select SND_PCM_IEC958 +	help +	  Support the AHB Audio interface which is part of the Synopsys +	  Designware HDMI block.  This is used in conjunction with +	  the i.MX6 HDMI driver. + +config DRM_DW_HDMI_I2S_AUDIO +	tristate "Synopsys Designware I2S Audio interface" +	depends on SND_SOC +	depends on DRM_DW_HDMI +	select SND_SOC_HDMI_CODEC +	help +	  Support the I2S Audio interface which is part of the Synopsys +	  Designware HDMI block. diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile new file mode 100644 index 000000000000..17aa7a65b57e --- /dev/null +++ b/drivers/gpu/drm/bridge/synopsys/Makefile @@ -0,0 +1,5 @@ +#ccflags-y := -Iinclude/drm + +obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o +obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o +obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o diff --git a/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c index 8f2d1379c880..8f2d1379c880 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c diff --git a/drivers/gpu/drm/bridge/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h index fd1f745c6073..fd1f745c6073 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi-audio.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h diff --git a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c index aaf287d2e91d..aaf287d2e91d 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi-i2s-audio.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 9a9ec27d9e28..026a0dce7661 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -19,6 +19,7 @@  #include <linux/hdmi.h>  #include <linux/mutex.h>  #include <linux/of_device.h> +#include <linux/regmap.h>  #include <linux/spinlock.h>  #include <drm/drm_of.h> @@ -116,14 +117,17 @@ struct dw_hdmi_i2c {  struct dw_hdmi_phy_data {  	enum dw_hdmi_phy_type type;  	const char *name; +	unsigned int gen;  	bool has_svsret; +	int (*configure)(struct dw_hdmi *hdmi, +			 const struct dw_hdmi_plat_data *pdata, +			 unsigned long mpixelclock);  };  struct dw_hdmi {  	struct drm_connector connector;  	struct drm_bridge bridge; -	enum dw_hdmi_devtype dev_type;  	unsigned int version;  	struct platform_device *audio; @@ -140,8 +144,12 @@ struct dw_hdmi {  	u8 edid[HDMI_EDID_LEN];  	bool cable_plugin; -	const struct dw_hdmi_phy_data *phy; -	bool phy_enabled; +	struct { +		const struct dw_hdmi_phy_ops *ops; +		const char *name; +		void *data; +		bool enabled; +	} phy;  	struct drm_display_mode previous_mode; @@ -164,8 +172,8 @@ struct dw_hdmi {  	unsigned int audio_n;  	bool audio_enable; -	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); -	u8 (*read)(struct dw_hdmi *hdmi, int offset); +	unsigned int reg_shift; +	struct regmap *regm;  };  #define HDMI_IH_PHY_STAT0_RX_SENSE \ @@ -176,42 +184,23 @@ struct dw_hdmi {  	(HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \  	 HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3) -static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset) -{ -	writel(val, hdmi->regs + (offset << 2)); -} - -static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset) -{ -	return readl(hdmi->regs + (offset << 2)); -} - -static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset) -{ -	writeb(val, hdmi->regs + offset); -} - -static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset) -{ -	return readb(hdmi->regs + offset); -} -  static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)  { -	hdmi->write(hdmi, val, offset); +	regmap_write(hdmi->regm, offset << hdmi->reg_shift, val);  }  static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)  { -	return hdmi->read(hdmi, offset); +	unsigned int val = 0; + +	regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val); + +	return val;  }  static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)  { -	u8 val = hdmi_readb(hdmi, reg) & ~mask; - -	val |= data & mask; -	hdmi_writeb(hdmi, val, reg); +	regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);  }  static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, @@ -830,6 +819,10 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)  		  HDMI_VP_CONF);  } +/* ----------------------------------------------------------------------------- + * Synopsys PHY Handling + */ +  static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,  				       unsigned char bit)  { @@ -837,32 +830,6 @@ static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,  		  HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);  } -static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi, -					unsigned char bit) -{ -	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, -		  HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); -} - -static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi, -				       unsigned char bit) -{ -	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, -		  HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); -} - -static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi, -				     unsigned char bit) -{ -	hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); -} - -static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi, -				      unsigned char bit) -{ -	hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); -} -  static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)  {  	u32 val; @@ -877,8 +844,8 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)  	return true;  } -static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, -				 unsigned char addr) +void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, +			   unsigned char addr)  {  	hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);  	hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); @@ -890,6 +857,7 @@ static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,  		    HDMI_PHY_I2CM_OPERATION_ADDR);  	hdmi_phy_wait_i2c_done(hdmi, 1000);  } +EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);  static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)  { @@ -940,54 +908,142 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)  			 HDMI_PHY_CONF0_SELDIPIF_MASK);  } -static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) +static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi) +{ +	const struct dw_hdmi_phy_data *phy = hdmi->phy.data; +	unsigned int i; +	u16 val; + +	if (phy->gen == 1) { +		dw_hdmi_phy_enable_tmds(hdmi, 0); +		dw_hdmi_phy_enable_powerdown(hdmi, true); +		return; +	} + +	dw_hdmi_phy_gen2_txpwron(hdmi, 0); + +	/* +	 * Wait for TX_PHY_LOCK to be deasserted to indicate that the PHY went +	 * to low power mode. +	 */ +	for (i = 0; i < 5; ++i) { +		val = hdmi_readb(hdmi, HDMI_PHY_STAT0); +		if (!(val & HDMI_PHY_TX_PHY_LOCK)) +			break; + +		usleep_range(1000, 2000); +	} + +	if (val & HDMI_PHY_TX_PHY_LOCK) +		dev_warn(hdmi->dev, "PHY failed to power down\n"); +	else +		dev_dbg(hdmi->dev, "PHY powered down in %u iterations\n", i); + +	dw_hdmi_phy_gen2_pddq(hdmi, 1); +} + +static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi) +{ +	const struct dw_hdmi_phy_data *phy = hdmi->phy.data; +	unsigned int i; +	u8 val; + +	if (phy->gen == 1) { +		dw_hdmi_phy_enable_powerdown(hdmi, false); + +		/* Toggle TMDS enable. */ +		dw_hdmi_phy_enable_tmds(hdmi, 0); +		dw_hdmi_phy_enable_tmds(hdmi, 1); +		return 0; +	} + +	dw_hdmi_phy_gen2_txpwron(hdmi, 1); +	dw_hdmi_phy_gen2_pddq(hdmi, 0); + +	/* Wait for PHY PLL lock */ +	for (i = 0; i < 5; ++i) { +		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; +		if (val) +			break; + +		usleep_range(1000, 2000); +	} + +	if (!val) { +		dev_err(hdmi->dev, "PHY PLL failed to lock\n"); +		return -ETIMEDOUT; +	} + +	dev_dbg(hdmi->dev, "PHY PLL locked %u iterations\n", i); +	return 0; +} + +/* + * PHY configuration function for the DWC HDMI 3D TX PHY. Based on the available + * information the DWC MHL PHY has the same register layout and is thus also + * supported by this function. + */ +static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, +		const struct dw_hdmi_plat_data *pdata, +		unsigned long mpixelclock)  { -	u8 val, msec; -	const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;  	const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;  	const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;  	const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;  	/* PLL/MPLL Cfg - always match on final entry */  	for (; mpll_config->mpixelclock != ~0UL; mpll_config++) -		if (hdmi->hdmi_data.video_mode.mpixelclock <= -		    mpll_config->mpixelclock) +		if (mpixelclock <= mpll_config->mpixelclock)  			break;  	for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++) -		if (hdmi->hdmi_data.video_mode.mpixelclock <= -		    curr_ctrl->mpixelclock) +		if (mpixelclock <= curr_ctrl->mpixelclock)  			break;  	for (; phy_config->mpixelclock != ~0UL; phy_config++) -		if (hdmi->hdmi_data.video_mode.mpixelclock <= -		    phy_config->mpixelclock) +		if (mpixelclock <= phy_config->mpixelclock)  			break;  	if (mpll_config->mpixelclock == ~0UL ||  	    curr_ctrl->mpixelclock == ~0UL || -	    phy_config->mpixelclock == ~0UL) { -		dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", -			hdmi->hdmi_data.video_mode.mpixelclock); +	    phy_config->mpixelclock == ~0UL)  		return -EINVAL; -	} -	/* Enable csc path */ -	if (cscon) -		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH; -	else -		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS; +	dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, +			      HDMI_3D_TX_PHY_CPCE_CTRL); +	dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, +			      HDMI_3D_TX_PHY_GMPCTRL); +	dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], +			      HDMI_3D_TX_PHY_CURRCTRL); -	hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL); +	dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); +	dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK, +			      HDMI_3D_TX_PHY_MSM_CTRL); -	/* gen2 tx power off */ -	dw_hdmi_phy_gen2_txpwron(hdmi, 0); +	dw_hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM); +	dw_hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, +			      HDMI_3D_TX_PHY_CKSYMTXCTRL); +	dw_hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, +			      HDMI_3D_TX_PHY_VLEVCTRL); -	/* gen2 pddq */ -	dw_hdmi_phy_gen2_pddq(hdmi, 1); +	/* Override and disable clock termination. */ +	dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE, +			      HDMI_3D_TX_PHY_CKCALCTRL); + +	return 0; +} + +static int hdmi_phy_configure(struct dw_hdmi *hdmi) +{ +	const struct dw_hdmi_phy_data *phy = hdmi->phy.data; +	const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; +	unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock; +	int ret; + +	dw_hdmi_phy_power_off(hdmi);  	/* Leave low power consumption mode by asserting SVSRET. */ -	if (hdmi->phy->has_svsret) +	if (phy->has_svsret)  		dw_hdmi_phy_enable_svsret(hdmi, 1);  	/* PHY reset. The reset signal is active high on Gen2 PHYs. */ @@ -1001,81 +1057,60 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)  		    HDMI_PHY_I2CM_SLAVE_ADDR);  	hdmi_phy_test_clear(hdmi, 0); -	hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, -			   HDMI_3D_TX_PHY_CPCE_CTRL); -	hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, -			   HDMI_3D_TX_PHY_GMPCTRL); -	hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], -			   HDMI_3D_TX_PHY_CURRCTRL); - -	hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL); -	hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK, -			   HDMI_3D_TX_PHY_MSM_CTRL); - -	hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM); -	hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, -			   HDMI_3D_TX_PHY_CKSYMTXCTRL); -	hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, -			   HDMI_3D_TX_PHY_VLEVCTRL); - -	/* Override and disable clock termination. */ -	hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE, -			   HDMI_3D_TX_PHY_CKCALCTRL); - -	dw_hdmi_phy_enable_powerdown(hdmi, false); - -	/* toggle TMDS enable */ -	dw_hdmi_phy_enable_tmds(hdmi, 0); -	dw_hdmi_phy_enable_tmds(hdmi, 1); - -	/* gen2 tx power on */ -	dw_hdmi_phy_gen2_txpwron(hdmi, 1); -	dw_hdmi_phy_gen2_pddq(hdmi, 0); - -	/* Wait for PHY PLL lock */ -	msec = 5; -	do { -		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; -		if (!val) -			break; - -		if (msec == 0) { -			dev_err(hdmi->dev, "PHY PLL not locked\n"); -			return -ETIMEDOUT; -		} - -		udelay(1000); -		msec--; -	} while (1); +	/* Write to the PHY as configured by the platform */ +	if (pdata->configure_phy) +		ret = pdata->configure_phy(hdmi, pdata, mpixelclock); +	else +		ret = phy->configure(hdmi, pdata, mpixelclock); +	if (ret) { +		dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n", +			mpixelclock); +		return ret; +	} -	return 0; +	return dw_hdmi_phy_power_on(hdmi);  } -static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) +static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, +			    struct drm_display_mode *mode)  {  	int i, ret; -	bool cscon; - -	/*check csc whether needed activated in HDMI mode */ -	cscon = hdmi->sink_is_hdmi && is_color_space_conversion(hdmi);  	/* HDMI Phy spec says to do the phy initialization sequence twice */  	for (i = 0; i < 2; i++) {  		dw_hdmi_phy_sel_data_en_pol(hdmi, 1);  		dw_hdmi_phy_sel_interface_control(hdmi, 0); -		dw_hdmi_phy_enable_tmds(hdmi, 0); -		dw_hdmi_phy_enable_powerdown(hdmi, true); -		/* Enable CSC */ -		ret = hdmi_phy_configure(hdmi, cscon); +		ret = hdmi_phy_configure(hdmi);  		if (ret)  			return ret;  	} -	hdmi->phy_enabled = true;  	return 0;  } +static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data) +{ +	dw_hdmi_phy_power_off(hdmi); +} + +static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi, +						      void *data) +{ +	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? +		connector_status_connected : connector_status_disconnected; +} + +static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = { +	.init = dw_hdmi_phy_init, +	.disable = dw_hdmi_phy_disable, +	.read_hpd = dw_hdmi_phy_read_hpd, +}; + +/* ----------------------------------------------------------------------------- + * HDMI TX Setup + */ +  static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)  {  	u8 de; @@ -1290,17 +1325,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,  	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);  } -static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi) -{ -	if (!hdmi->phy_enabled) -		return; - -	dw_hdmi_phy_enable_tmds(hdmi, 0); -	dw_hdmi_phy_enable_powerdown(hdmi, true); - -	hdmi->phy_enabled = false; -} -  /* HDMI Initialization Step B.4 */  static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)  { @@ -1329,6 +1353,14 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)  		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;  		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);  	} + +	/* Enable color space conversion if needed */ +	if (is_color_space_conversion(hdmi)) +		hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH, +			    HDMI_MC_FLOWCTRL); +	else +		hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS, +			    HDMI_MC_FLOWCTRL);  }  static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi) @@ -1425,9 +1457,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)  	hdmi_av_composer(hdmi, mode);  	/* HDMI Initializateion Step B.2 */ -	ret = dw_hdmi_phy_init(hdmi); +	ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode);  	if (ret)  		return ret; +	hdmi->phy.enabled = true;  	/* HDMI Initialization Step B.3 */  	dw_hdmi_enable_video_path(hdmi); @@ -1542,7 +1575,11 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)  static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)  { -	dw_hdmi_phy_disable(hdmi); +	if (hdmi->phy.enabled) { +		hdmi->phy.ops->disable(hdmi, hdmi->phy.data); +		hdmi->phy.enabled = false; +	} +  	hdmi->bridge_is_on = false;  } @@ -1605,8 +1642,7 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)  	dw_hdmi_update_phy_mask(hdmi);  	mutex_unlock(&hdmi->mutex); -	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ? -		connector_status_connected : connector_status_disconnected; +	return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);  }  static int dw_hdmi_connector_get_modes(struct drm_connector *connector) @@ -1858,24 +1894,37 @@ static const struct dw_hdmi_phy_data dw_hdmi_phys[] = {  	{  		.type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,  		.name = "DWC HDMI TX PHY", +		.gen = 1,  	}, {  		.type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,  		.name = "DWC MHL PHY + HEAC PHY", +		.gen = 2,  		.has_svsret = true, +		.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,  	}, {  		.type = DW_HDMI_PHY_DWC_MHL_PHY,  		.name = "DWC MHL PHY", +		.gen = 2,  		.has_svsret = true, +		.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,  	}, {  		.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,  		.name = "DWC HDMI 3D TX PHY + HEAC PHY", +		.gen = 2, +		.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,  	}, {  		.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,  		.name = "DWC HDMI 3D TX PHY", +		.gen = 2, +		.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,  	}, {  		.type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,  		.name = "DWC HDMI 2.0 TX PHY", +		.gen = 2,  		.has_svsret = true, +	}, { +		.type = DW_HDMI_PHY_VENDOR_PHY, +		.name = "Vendor PHY",  	}  }; @@ -1886,22 +1935,56 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)  	phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID); +	if (phy_type == DW_HDMI_PHY_VENDOR_PHY) { +		/* Vendor PHYs require support from the glue layer. */ +		if (!hdmi->plat_data->phy_ops || !hdmi->plat_data->phy_name) { +			dev_err(hdmi->dev, +				"Vendor HDMI PHY not supported by glue layer\n"); +			return -ENODEV; +		} + +		hdmi->phy.ops = hdmi->plat_data->phy_ops; +		hdmi->phy.data = hdmi->plat_data->phy_data; +		hdmi->phy.name = hdmi->plat_data->phy_name; +		return 0; +	} + +	/* Synopsys PHYs are handled internally. */  	for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {  		if (dw_hdmi_phys[i].type == phy_type) { -			hdmi->phy = &dw_hdmi_phys[i]; +			hdmi->phy.ops = &dw_hdmi_synopsys_phy_ops; +			hdmi->phy.name = dw_hdmi_phys[i].name; +			hdmi->phy.data = (void *)&dw_hdmi_phys[i]; + +			if (!dw_hdmi_phys[i].configure && +			    !hdmi->plat_data->configure_phy) { +				dev_err(hdmi->dev, "%s requires platform support\n", +					hdmi->phy.name); +				return -ENODEV; +			} +  			return 0;  		}  	} -	if (phy_type == DW_HDMI_PHY_VENDOR_PHY) -		dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n"); -	else -		dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", -			phy_type); - +	dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", phy_type);  	return -ENODEV;  } +static const struct regmap_config hdmi_regmap_8bit_config = { +	.reg_bits	= 32, +	.val_bits	= 8, +	.reg_stride	= 1, +	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR, +}; + +static const struct regmap_config hdmi_regmap_32bit_config = { +	.reg_bits	= 32, +	.val_bits	= 32, +	.reg_stride	= 4, +	.max_register	= HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2, +}; +  static struct dw_hdmi *  __dw_hdmi_probe(struct platform_device *pdev,  		const struct dw_hdmi_plat_data *plat_data) @@ -1911,7 +1994,7 @@ __dw_hdmi_probe(struct platform_device *pdev,  	struct platform_device_info pdevinfo;  	struct device_node *ddc_node;  	struct dw_hdmi *hdmi; -	struct resource *iores; +	struct resource *iores = NULL;  	int irq;  	int ret;  	u32 val = 1; @@ -1926,7 +2009,6 @@ __dw_hdmi_probe(struct platform_device *pdev,  	hdmi->plat_data = plat_data;  	hdmi->dev = dev; -	hdmi->dev_type = plat_data->dev_type;  	hdmi->sample_rate = 48000;  	hdmi->disabled = true;  	hdmi->rxsense = true; @@ -1936,22 +2018,6 @@ __dw_hdmi_probe(struct platform_device *pdev,  	mutex_init(&hdmi->audio_mutex);  	spin_lock_init(&hdmi->audio_lock); -	of_property_read_u32(np, "reg-io-width", &val); - -	switch (val) { -	case 4: -		hdmi->write = dw_hdmi_writel; -		hdmi->read = dw_hdmi_readl; -		break; -	case 1: -		hdmi->write = dw_hdmi_writeb; -		hdmi->read = dw_hdmi_readb; -		break; -	default: -		dev_err(dev, "reg-io-width must be 1 or 4\n"); -		return ERR_PTR(-EINVAL); -	} -  	ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);  	if (ddc_node) {  		hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); @@ -1965,11 +2031,38 @@ __dw_hdmi_probe(struct platform_device *pdev,  		dev_dbg(hdmi->dev, "no ddc property found\n");  	} -	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	hdmi->regs = devm_ioremap_resource(dev, iores); -	if (IS_ERR(hdmi->regs)) { -		ret = PTR_ERR(hdmi->regs); -		goto err_res; +	if (!plat_data->regm) { +		const struct regmap_config *reg_config; + +		of_property_read_u32(np, "reg-io-width", &val); +		switch (val) { +		case 4: +			reg_config = &hdmi_regmap_32bit_config; +			hdmi->reg_shift = 2; +			break; +		case 1: +			reg_config = &hdmi_regmap_8bit_config; +			break; +		default: +			dev_err(dev, "reg-io-width must be 1 or 4\n"); +			return ERR_PTR(-EINVAL); +		} + +		iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); +		hdmi->regs = devm_ioremap_resource(dev, iores); +		if (IS_ERR(hdmi->regs)) { +			ret = PTR_ERR(hdmi->regs); +			goto err_res; +		} + +		hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config); +		if (IS_ERR(hdmi->regm)) { +			dev_err(dev, "Failed to configure regmap\n"); +			ret = PTR_ERR(hdmi->regm); +			goto err_res; +		} +	} else { +		hdmi->regm = plat_data->regm;  	}  	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); @@ -2019,7 +2112,7 @@ __dw_hdmi_probe(struct platform_device *pdev,  	dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",  		 hdmi->version >> 12, hdmi->version & 0xfff,  		 prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without", -		 hdmi->phy->name); +		 hdmi->phy.name);  	initialize_hdmi_ih_mutes(hdmi); @@ -2079,7 +2172,7 @@ __dw_hdmi_probe(struct platform_device *pdev,  	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);  	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); -	if (config3 & HDMI_CONFIG3_AHBAUDDMA) { +	if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) {  		struct dw_hdmi_audio_data audio;  		audio.phys = iores->start; diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h index 325b0b8ae639..325b0b8ae639 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 236d947011f9..9b892af7811a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1374,8 +1374,8 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,  		return 0;  	if (conn_state->crtc) { -		crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state, -								conn_state->crtc); +		crtc_state = drm_atomic_get_new_crtc_state(conn_state->state, +							   conn_state->crtc);  		crtc_state->connector_mask &=  			~(1 << drm_connector_index(conn_state->connector)); @@ -1492,7 +1492,7 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,  {  	struct drm_plane *plane; -	WARN_ON(!drm_atomic_get_existing_crtc_state(state, crtc)); +	WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc));  	drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) {  		struct drm_plane_state *plane_state = diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 6b12396f718b..4e26b73bb0d5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -63,14 +63,15 @@   */  static void  drm_atomic_helper_plane_changed(struct drm_atomic_state *state, +				struct drm_plane_state *old_plane_state,  				struct drm_plane_state *plane_state,  				struct drm_plane *plane)  {  	struct drm_crtc_state *crtc_state; -	if (plane->state->crtc) { -		crtc_state = drm_atomic_get_existing_crtc_state(state, -								plane->state->crtc); +	if (old_plane_state->crtc) { +		crtc_state = drm_atomic_get_new_crtc_state(state, +							   old_plane_state->crtc);  		if (WARN_ON(!crtc_state))  			return; @@ -79,8 +80,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,  	}  	if (plane_state->crtc) { -		crtc_state = drm_atomic_get_existing_crtc_state(state, -								plane_state->crtc); +		crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);  		if (WARN_ON(!crtc_state))  			return; @@ -92,7 +92,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,  static int handle_conflicting_encoders(struct drm_atomic_state *state,  				       bool disable_conflicting_encoders)  { -	struct drm_connector_state *conn_state; +	struct drm_connector_state *new_conn_state;  	struct drm_connector *connector;  	struct drm_connector_list_iter conn_iter;  	struct drm_encoder *encoder; @@ -104,15 +104,15 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,  	 * part of the state. If the same encoder is assigned to multiple  	 * connectors bail out.  	 */ -	for_each_connector_in_state(state, connector, conn_state, i) { +	for_each_new_connector_in_state(state, connector, new_conn_state, i) {  		const struct drm_connector_helper_funcs *funcs = connector->helper_private;  		struct drm_encoder *new_encoder; -		if (!conn_state->crtc) +		if (!new_conn_state->crtc)  			continue;  		if (funcs->atomic_best_encoder) -			new_encoder = funcs->atomic_best_encoder(connector, conn_state); +			new_encoder = funcs->atomic_best_encoder(connector, new_conn_state);  		else if (funcs->best_encoder)  			new_encoder = funcs->best_encoder(connector);  		else @@ -149,7 +149,7 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,  	drm_for_each_connector_iter(connector, &conn_iter) {  		struct drm_crtc_state *crtc_state; -		if (drm_atomic_get_existing_connector_state(state, connector)) +		if (drm_atomic_get_new_connector_state(state, connector))  			continue;  		encoder = connector->state->best_encoder; @@ -166,20 +166,20 @@ static int handle_conflicting_encoders(struct drm_atomic_state *state,  			goto out;  		} -		conn_state = drm_atomic_get_connector_state(state, connector); -		if (IS_ERR(conn_state)) { -			ret = PTR_ERR(conn_state); +		new_conn_state = drm_atomic_get_connector_state(state, connector); +		if (IS_ERR(new_conn_state)) { +			ret = PTR_ERR(new_conn_state);  			goto out;  		}  		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], disabling [CONNECTOR:%d:%s]\n",  				 encoder->base.id, encoder->name, -				 conn_state->crtc->base.id, conn_state->crtc->name, +				 new_conn_state->crtc->base.id, new_conn_state->crtc->name,  				 connector->base.id, connector->name); -		crtc_state = drm_atomic_get_existing_crtc_state(state, conn_state->crtc); +		crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); -		ret = drm_atomic_set_crtc_for_connector(conn_state, NULL); +		ret = drm_atomic_set_crtc_for_connector(new_conn_state, NULL);  		if (ret)  			goto out; @@ -218,7 +218,7 @@ set_best_encoder(struct drm_atomic_state *state,  		 */  		WARN_ON(!crtc && encoder != conn_state->best_encoder);  		if (crtc) { -			crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); +			crtc_state = drm_atomic_get_new_crtc_state(state, crtc);  			crtc_state->encoder_mask &=  				~(1 << drm_encoder_index(conn_state->best_encoder)); @@ -229,7 +229,7 @@ set_best_encoder(struct drm_atomic_state *state,  		crtc = conn_state->crtc;  		WARN_ON(!crtc);  		if (crtc) { -			crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); +			crtc_state = drm_atomic_get_new_crtc_state(state, crtc);  			crtc_state->encoder_mask |=  				1 << drm_encoder_index(encoder); @@ -245,24 +245,24 @@ steal_encoder(struct drm_atomic_state *state,  {  	struct drm_crtc_state *crtc_state;  	struct drm_connector *connector; -	struct drm_connector_state *connector_state; +	struct drm_connector_state *old_connector_state, *new_connector_state;  	int i; -	for_each_connector_in_state(state, connector, connector_state, i) { +	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {  		struct drm_crtc *encoder_crtc; -		if (connector_state->best_encoder != encoder) +		if (new_connector_state->best_encoder != encoder)  			continue; -		encoder_crtc = connector->state->crtc; +		encoder_crtc = old_connector_state->crtc;  		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], stealing it\n",  				 encoder->base.id, encoder->name,  				 encoder_crtc->base.id, encoder_crtc->name); -		set_best_encoder(state, connector_state, NULL); +		set_best_encoder(state, new_connector_state, NULL); -		crtc_state = drm_atomic_get_existing_crtc_state(state, encoder_crtc); +		crtc_state = drm_atomic_get_new_crtc_state(state, encoder_crtc);  		crtc_state->connectors_changed = true;  		return; @@ -272,7 +272,8 @@ steal_encoder(struct drm_atomic_state *state,  static int  update_connector_routing(struct drm_atomic_state *state,  			 struct drm_connector *connector, -			 struct drm_connector_state *connector_state) +			 struct drm_connector_state *old_connector_state, +			 struct drm_connector_state *new_connector_state)  {  	const struct drm_connector_helper_funcs *funcs;  	struct drm_encoder *new_encoder; @@ -282,24 +283,24 @@ update_connector_routing(struct drm_atomic_state *state,  			 connector->base.id,  			 connector->name); -	if (connector->state->crtc != connector_state->crtc) { -		if (connector->state->crtc) { -			crtc_state = drm_atomic_get_existing_crtc_state(state, connector->state->crtc); +	if (old_connector_state->crtc != new_connector_state->crtc) { +		if (old_connector_state->crtc) { +			crtc_state = drm_atomic_get_new_crtc_state(state, old_connector_state->crtc);  			crtc_state->connectors_changed = true;  		} -		if (connector_state->crtc) { -			crtc_state = drm_atomic_get_existing_crtc_state(state, connector_state->crtc); +		if (new_connector_state->crtc) { +			crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);  			crtc_state->connectors_changed = true;  		}  	} -	if (!connector_state->crtc) { +	if (!new_connector_state->crtc) {  		DRM_DEBUG_ATOMIC("Disabling [CONNECTOR:%d:%s]\n",  				connector->base.id,  				connector->name); -		set_best_encoder(state, connector_state, NULL); +		set_best_encoder(state, new_connector_state, NULL);  		return 0;  	} @@ -308,7 +309,7 @@ update_connector_routing(struct drm_atomic_state *state,  	if (funcs->atomic_best_encoder)  		new_encoder = funcs->atomic_best_encoder(connector, -							 connector_state); +							 new_connector_state);  	else if (funcs->best_encoder)  		new_encoder = funcs->best_encoder(connector);  	else @@ -321,34 +322,34 @@ update_connector_routing(struct drm_atomic_state *state,  		return -EINVAL;  	} -	if (!drm_encoder_crtc_ok(new_encoder, connector_state->crtc)) { +	if (!drm_encoder_crtc_ok(new_encoder, new_connector_state->crtc)) {  		DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] incompatible with [CRTC:%d:%s]\n",  				 new_encoder->base.id,  				 new_encoder->name, -				 connector_state->crtc->base.id, -				 connector_state->crtc->name); +				 new_connector_state->crtc->base.id, +				 new_connector_state->crtc->name);  		return -EINVAL;  	} -	if (new_encoder == connector_state->best_encoder) { -		set_best_encoder(state, connector_state, new_encoder); +	if (new_encoder == new_connector_state->best_encoder) { +		set_best_encoder(state, new_connector_state, new_encoder);  		DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",  				 connector->base.id,  				 connector->name,  				 new_encoder->base.id,  				 new_encoder->name, -				 connector_state->crtc->base.id, -				 connector_state->crtc->name); +				 new_connector_state->crtc->base.id, +				 new_connector_state->crtc->name);  		return 0;  	}  	steal_encoder(state, new_encoder); -	set_best_encoder(state, connector_state, new_encoder); +	set_best_encoder(state, new_connector_state, new_encoder); -	crtc_state = drm_atomic_get_existing_crtc_state(state, connector_state->crtc); +	crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);  	crtc_state->connectors_changed = true;  	DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n", @@ -356,8 +357,8 @@ update_connector_routing(struct drm_atomic_state *state,  			 connector->name,  			 new_encoder->base.id,  			 new_encoder->name, -			 connector_state->crtc->base.id, -			 connector_state->crtc->name); +			 new_connector_state->crtc->base.id, +			 new_connector_state->crtc->name);  	return 0;  } @@ -366,57 +367,57 @@ static int  mode_fixup(struct drm_atomic_state *state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_connector *connector; -	struct drm_connector_state *conn_state; +	struct drm_connector_state *new_conn_state;  	int i;  	int ret; -	for_each_crtc_in_state(state, crtc, crtc_state, i) { -		if (!crtc_state->mode_changed && -		    !crtc_state->connectors_changed) +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { +		if (!new_crtc_state->mode_changed && +		    !new_crtc_state->connectors_changed)  			continue; -		drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); +		drm_mode_copy(&new_crtc_state->adjusted_mode, &new_crtc_state->mode);  	} -	for_each_connector_in_state(state, connector, conn_state, i) { +	for_each_new_connector_in_state(state, connector, new_conn_state, i) {  		const struct drm_encoder_helper_funcs *funcs;  		struct drm_encoder *encoder; -		WARN_ON(!!conn_state->best_encoder != !!conn_state->crtc); +		WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc); -		if (!conn_state->crtc || !conn_state->best_encoder) +		if (!new_conn_state->crtc || !new_conn_state->best_encoder)  			continue; -		crtc_state = drm_atomic_get_existing_crtc_state(state, -								conn_state->crtc); +		new_crtc_state = +			drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);  		/*  		 * Each encoder has at most one connector (since we always steal  		 * it away), so we won't call ->mode_fixup twice.  		 */ -		encoder = conn_state->best_encoder; +		encoder = new_conn_state->best_encoder;  		funcs = encoder->helper_private; -		ret = drm_bridge_mode_fixup(encoder->bridge, &crtc_state->mode, -				&crtc_state->adjusted_mode); +		ret = drm_bridge_mode_fixup(encoder->bridge, &new_crtc_state->mode, +				&new_crtc_state->adjusted_mode);  		if (!ret) {  			DRM_DEBUG_ATOMIC("Bridge fixup failed\n");  			return -EINVAL;  		}  		if (funcs && funcs->atomic_check) { -			ret = funcs->atomic_check(encoder, crtc_state, -						  conn_state); +			ret = funcs->atomic_check(encoder, new_crtc_state, +						  new_conn_state);  			if (ret) {  				DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] check failed\n",  						 encoder->base.id, encoder->name);  				return ret;  			}  		} else if (funcs && funcs->mode_fixup) { -			ret = funcs->mode_fixup(encoder, &crtc_state->mode, -						&crtc_state->adjusted_mode); +			ret = funcs->mode_fixup(encoder, &new_crtc_state->mode, +						&new_crtc_state->adjusted_mode);  			if (!ret) {  				DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] fixup failed\n",  						 encoder->base.id, encoder->name); @@ -425,22 +426,22 @@ mode_fixup(struct drm_atomic_state *state)  		}  	} -	for_each_crtc_in_state(state, crtc, crtc_state, i) { +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs; -		if (!crtc_state->enable) +		if (!new_crtc_state->enable)  			continue; -		if (!crtc_state->mode_changed && -		    !crtc_state->connectors_changed) +		if (!new_crtc_state->mode_changed && +		    !new_crtc_state->connectors_changed)  			continue;  		funcs = crtc->helper_private;  		if (!funcs->mode_fixup)  			continue; -		ret = funcs->mode_fixup(crtc, &crtc_state->mode, -					&crtc_state->adjusted_mode); +		ret = funcs->mode_fixup(crtc, &new_crtc_state->mode, +					&new_crtc_state->adjusted_mode);  		if (!ret) {  			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] fixup failed\n",  					 crtc->base.id, crtc->name); @@ -487,19 +488,19 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,  				struct drm_atomic_state *state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	struct drm_connector *connector; -	struct drm_connector_state *connector_state; +	struct drm_connector_state *old_connector_state, *new_connector_state;  	int i, ret; -	for_each_crtc_in_state(state, crtc, crtc_state, i) { -		if (!drm_mode_equal(&crtc->state->mode, &crtc_state->mode)) { +	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { +		if (!drm_mode_equal(&old_crtc_state->mode, &new_crtc_state->mode)) {  			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode changed\n",  					 crtc->base.id, crtc->name); -			crtc_state->mode_changed = true; +			new_crtc_state->mode_changed = true;  		} -		if (crtc->state->enable != crtc_state->enable) { +		if (old_crtc_state->enable != new_crtc_state->enable) {  			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enable changed\n",  					 crtc->base.id, crtc->name); @@ -511,8 +512,8 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,  			 * The other way around is true as well. enable != 0  			 * iff connectors are attached and a mode is set.  			 */ -			crtc_state->mode_changed = true; -			crtc_state->connectors_changed = true; +			new_crtc_state->mode_changed = true; +			new_crtc_state->connectors_changed = true;  		}  	} @@ -520,22 +521,23 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,  	if (ret)  		return ret; -	for_each_connector_in_state(state, connector, connector_state, i) { +	for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {  		/*  		 * This only sets crtc->connectors_changed for routing changes,  		 * drivers must set crtc->connectors_changed themselves when  		 * connector properties need to be updated.  		 */  		ret = update_connector_routing(state, connector, -					       connector_state); +					       old_connector_state, +					       new_connector_state);  		if (ret)  			return ret; -		if (connector->state->crtc) { -			crtc_state = drm_atomic_get_existing_crtc_state(state, -									connector->state->crtc); -			if (connector->state->link_status != -			    connector_state->link_status) -				crtc_state->connectors_changed = true; +		if (old_connector_state->crtc) { +			new_crtc_state = drm_atomic_get_new_crtc_state(state, +								       old_connector_state->crtc); +			if (old_connector_state->link_status != +			    new_connector_state->link_status) +				new_crtc_state->connectors_changed = true;  		}  	} @@ -545,28 +547,28 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,  	 * configuration. This must be done before calling mode_fixup in case a  	 * crtc only changed its mode but has the same set of connectors.  	 */ -	for_each_crtc_in_state(state, crtc, crtc_state, i) { +	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {  		bool has_connectors = -			!!crtc_state->connector_mask; +			!!new_crtc_state->connector_mask;  		/*  		 * We must set ->active_changed after walking connectors for  		 * otherwise an update that only changes active would result in  		 * a full modeset because update_connector_routing force that.  		 */ -		if (crtc->state->active != crtc_state->active) { +		if (old_crtc_state->active != new_crtc_state->active) {  			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n",  					 crtc->base.id, crtc->name); -			crtc_state->active_changed = true; +			new_crtc_state->active_changed = true;  		} -		if (!drm_atomic_crtc_needs_modeset(crtc_state)) +		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))  			continue;  		DRM_DEBUG_ATOMIC("[CRTC:%d:%s] needs all connectors, enable: %c, active: %c\n",  				 crtc->base.id, crtc->name, -				 crtc_state->enable ? 'y' : 'n', -				 crtc_state->active ? 'y' : 'n'); +				 new_crtc_state->enable ? 'y' : 'n', +				 new_crtc_state->active ? 'y' : 'n');  		ret = drm_atomic_add_affected_connectors(state, crtc);  		if (ret != 0) @@ -576,7 +578,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,  		if (ret != 0)  			return ret; -		if (crtc_state->enable != has_connectors) { +		if (new_crtc_state->enable != has_connectors) {  			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n",  					 crtc->base.id, crtc->name); @@ -609,22 +611,22 @@ drm_atomic_helper_check_planes(struct drm_device *dev,  			       struct drm_atomic_state *state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_plane *plane; -	struct drm_plane_state *plane_state; +	struct drm_plane_state *new_plane_state, *old_plane_state;  	int i, ret = 0; -	for_each_plane_in_state(state, plane, plane_state, i) { +	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {  		const struct drm_plane_helper_funcs *funcs;  		funcs = plane->helper_private; -		drm_atomic_helper_plane_changed(state, plane_state, plane); +		drm_atomic_helper_plane_changed(state, old_plane_state, new_plane_state, plane);  		if (!funcs || !funcs->atomic_check)  			continue; -		ret = funcs->atomic_check(plane, plane_state); +		ret = funcs->atomic_check(plane, new_plane_state);  		if (ret) {  			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic driver check failed\n",  					 plane->base.id, plane->name); @@ -632,7 +634,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,  		}  	} -	for_each_crtc_in_state(state, crtc, crtc_state, i) { +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs;  		funcs = crtc->helper_private; @@ -640,7 +642,7 @@ drm_atomic_helper_check_planes(struct drm_device *dev,  		if (!funcs || !funcs->atomic_check)  			continue; -		ret = funcs->atomic_check(crtc, crtc_state); +		ret = funcs->atomic_check(crtc, new_crtc_state);  		if (ret) {  			DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic driver check failed\n",  					 crtc->base.id, crtc->name); @@ -694,12 +696,12 @@ static void  disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)  {  	struct drm_connector *connector; -	struct drm_connector_state *old_conn_state; +	struct drm_connector_state *old_conn_state, *new_conn_state;  	struct drm_crtc *crtc; -	struct drm_crtc_state *old_crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	int i; -	for_each_connector_in_state(old_state, connector, old_conn_state, i) { +	for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {  		const struct drm_encoder_helper_funcs *funcs;  		struct drm_encoder *encoder; @@ -708,8 +710,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)  		if (!old_conn_state->crtc)  			continue; -		old_crtc_state = drm_atomic_get_existing_crtc_state(old_state, -								    old_conn_state->crtc); +		old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);  		if (!old_crtc_state->active ||  		    !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state)) @@ -736,7 +737,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)  		/* Right function depends upon target state. */  		if (funcs) { -			if (connector->state->crtc && funcs->prepare) +			if (new_conn_state->crtc && funcs->prepare)  				funcs->prepare(encoder);  			else if (funcs->disable)  				funcs->disable(encoder); @@ -747,11 +748,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)  		drm_bridge_post_disable(encoder->bridge);  	} -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs;  		/* Shut down everything that needs a full modeset. */ -		if (!drm_atomic_crtc_needs_modeset(crtc->state)) +		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))  			continue;  		if (!old_crtc_state->active) @@ -764,7 +765,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)  		/* Right function depends upon target state. */ -		if (crtc->state->enable && funcs->prepare) +		if (new_crtc_state->enable && funcs->prepare)  			funcs->prepare(crtc);  		else if (funcs->atomic_disable)  			funcs->atomic_disable(crtc, old_crtc_state); @@ -793,13 +794,13 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,  					      struct drm_atomic_state *old_state)  {  	struct drm_connector *connector; -	struct drm_connector_state *old_conn_state; +	struct drm_connector_state *old_conn_state, *new_conn_state;  	struct drm_crtc *crtc; -	struct drm_crtc_state *old_crtc_state; +	struct drm_crtc_state *new_crtc_state;  	int i;  	/* clear out existing links and update dpms */ -	for_each_connector_in_state(old_state, connector, old_conn_state, i) { +	for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) {  		if (connector->encoder) {  			WARN_ON(!connector->encoder->crtc); @@ -807,7 +808,7 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,  			connector->encoder = NULL;  		} -		crtc = connector->state->crtc; +		crtc = new_conn_state->crtc;  		if ((!crtc && old_conn_state->crtc) ||  		    (crtc && drm_atomic_crtc_needs_modeset(crtc->state))) {  			struct drm_property *dpms_prop = @@ -824,33 +825,36 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev,  	}  	/* set new links */ -	for_each_connector_in_state(old_state, connector, old_conn_state, i) { -		if (!connector->state->crtc) +	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) { +		if (!new_conn_state->crtc)  			continue; -		if (WARN_ON(!connector->state->best_encoder)) +		if (WARN_ON(!new_conn_state->best_encoder))  			continue; -		connector->encoder = connector->state->best_encoder; -		connector->encoder->crtc = connector->state->crtc; +		connector->encoder = new_conn_state->best_encoder; +		connector->encoder->crtc = new_conn_state->crtc;  	}  	/* set legacy state in the crtc structure */ -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {  		struct drm_plane *primary = crtc->primary; +		struct drm_plane_state *new_plane_state; -		crtc->mode = crtc->state->mode; -		crtc->enabled = crtc->state->enable; +		crtc->mode = new_crtc_state->mode; +		crtc->enabled = new_crtc_state->enable; -		if (drm_atomic_get_existing_plane_state(old_state, primary) && -		    primary->state->crtc == crtc) { -			crtc->x = primary->state->src_x >> 16; -			crtc->y = primary->state->src_y >> 16; +		new_plane_state = +			drm_atomic_get_new_plane_state(old_state, primary); + +		if (new_plane_state && new_plane_state->crtc == crtc) { +			crtc->x = new_plane_state->src_x >> 16; +			crtc->y = new_plane_state->src_y >> 16;  		} -		if (crtc->state->enable) +		if (new_crtc_state->enable)  			drm_calc_timestamping_constants(crtc, -							&crtc->state->adjusted_mode); +							&new_crtc_state->adjusted_mode);  	}  }  EXPORT_SYMBOL(drm_atomic_helper_update_legacy_modeset_state); @@ -859,20 +863,20 @@ static void  crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *old_crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_connector *connector; -	struct drm_connector_state *old_conn_state; +	struct drm_connector_state *new_conn_state;  	int i; -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs; -		if (!crtc->state->mode_changed) +		if (!new_crtc_state->mode_changed)  			continue;  		funcs = crtc->helper_private; -		if (crtc->state->enable && funcs->mode_set_nofb) { +		if (new_crtc_state->enable && funcs->mode_set_nofb) {  			DRM_DEBUG_ATOMIC("modeset on [CRTC:%d:%s]\n",  					 crtc->base.id, crtc->name); @@ -880,18 +884,17 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)  		}  	} -	for_each_connector_in_state(old_state, connector, old_conn_state, i) { +	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {  		const struct drm_encoder_helper_funcs *funcs; -		struct drm_crtc_state *new_crtc_state;  		struct drm_encoder *encoder;  		struct drm_display_mode *mode, *adjusted_mode; -		if (!connector->state->best_encoder) +		if (!new_conn_state->best_encoder)  			continue; -		encoder = connector->state->best_encoder; +		encoder = new_conn_state->best_encoder;  		funcs = encoder->helper_private; -		new_crtc_state = connector->state->crtc->state; +		new_crtc_state = new_conn_state->crtc->state;  		mode = &new_crtc_state->mode;  		adjusted_mode = &new_crtc_state->adjusted_mode; @@ -907,7 +910,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)  		 */  		if (funcs && funcs->atomic_mode_set) {  			funcs->atomic_mode_set(encoder, new_crtc_state, -					       connector->state); +					       new_conn_state);  		} else if (funcs && funcs->mode_set) {  			funcs->mode_set(encoder, mode, adjusted_mode);  		} @@ -959,24 +962,24 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,  					      struct drm_atomic_state *old_state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *old_crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_connector *connector; -	struct drm_connector_state *old_conn_state; +	struct drm_connector_state *new_conn_state;  	int i; -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs;  		/* Need to filter out CRTCs where only planes change. */ -		if (!drm_atomic_crtc_needs_modeset(crtc->state)) +		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))  			continue; -		if (!crtc->state->active) +		if (!new_crtc_state->active)  			continue;  		funcs = crtc->helper_private; -		if (crtc->state->enable) { +		if (new_crtc_state->enable) {  			DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",  					 crtc->base.id, crtc->name); @@ -987,18 +990,18 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,  		}  	} -	for_each_connector_in_state(old_state, connector, old_conn_state, i) { +	for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {  		const struct drm_encoder_helper_funcs *funcs;  		struct drm_encoder *encoder; -		if (!connector->state->best_encoder) +		if (!new_conn_state->best_encoder)  			continue; -		if (!connector->state->crtc->state->active || -		    !drm_atomic_crtc_needs_modeset(connector->state->crtc->state)) +		if (!new_conn_state->crtc->state->active || +		    !drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))  			continue; -		encoder = connector->state->best_encoder; +		encoder = new_conn_state->best_encoder;  		funcs = encoder->helper_private;  		DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n", @@ -1048,29 +1051,26 @@ int drm_atomic_helper_wait_for_fences(struct drm_device *dev,  				      bool pre_swap)  {  	struct drm_plane *plane; -	struct drm_plane_state *plane_state; +	struct drm_plane_state *new_plane_state;  	int i, ret; -	for_each_plane_in_state(state, plane, plane_state, i) { -		if (!pre_swap) -			plane_state = plane->state; - -		if (!plane_state->fence) +	for_each_new_plane_in_state(state, plane, new_plane_state, i) { +		if (!new_plane_state->fence)  			continue; -		WARN_ON(!plane_state->fb); +		WARN_ON(!new_plane_state->fb);  		/*  		 * If waiting for fences pre-swap (ie: nonblock), userspace can  		 * still interrupt the operation. Instead of blocking until the  		 * timer expires, make the wait interruptible.  		 */ -		ret = dma_fence_wait(plane_state->fence, pre_swap); +		ret = dma_fence_wait(new_plane_state->fence, pre_swap);  		if (ret)  			return ret; -		dma_fence_put(plane_state->fence); -		plane_state->fence = NULL; +		dma_fence_put(new_plane_state->fence); +		new_plane_state->fence = NULL;  	}  	return 0; @@ -1093,7 +1093,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,  		struct drm_atomic_state *old_state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *old_crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	int i, ret;  	unsigned crtc_mask = 0; @@ -1104,9 +1104,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,  	if (old_state->legacy_cursor_update)  		return; -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { -		struct drm_crtc_state *new_crtc_state = crtc->state; - +	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {  		if (!new_crtc_state->active || !new_crtc_state->planes_changed)  			continue; @@ -1118,7 +1116,7 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,  		old_state->crtcs[i].last_vblank_count = drm_crtc_vblank_count(crtc);  	} -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) {  		if (!(crtc_mask & drm_crtc_mask(crtc)))  			continue; @@ -1427,11 +1425,11 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,  				   bool nonblock)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	struct drm_crtc_commit *commit;  	int i, ret; -	for_each_crtc_in_state(state, crtc, crtc_state, i) { +	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {  		commit = kzalloc(sizeof(*commit), GFP_KERNEL);  		if (!commit)  			return -ENOMEM; @@ -1452,7 +1450,7 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,  		/* Drivers only send out events when at least either current or  		 * new CRTC state is active. Complete right away if everything  		 * stays off. */ -		if (!crtc->state->active && !crtc_state->active) { +		if (!old_crtc_state->active && !new_crtc_state->active) {  			complete_all(&commit->flip_done);  			continue;  		} @@ -1463,17 +1461,17 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,  			continue;  		} -		if (!crtc_state->event) { +		if (!new_crtc_state->event) {  			commit->event = kzalloc(sizeof(*commit->event),  						GFP_KERNEL);  			if (!commit->event)  				return -ENOMEM; -			crtc_state->event = commit->event; +			new_crtc_state->event = commit->event;  		} -		crtc_state->event->base.completion = &commit->flip_done; -		crtc_state->event->base.completion_release = release_crtc_commit; +		new_crtc_state->event->base.completion = &commit->flip_done; +		new_crtc_state->event->base.completion_release = release_crtc_commit;  		drm_crtc_commit_get(commit);  	} @@ -1512,12 +1510,12 @@ static struct drm_crtc_commit *preceeding_commit(struct drm_crtc *crtc)  void drm_atomic_helper_wait_for_dependencies(struct drm_atomic_state *old_state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_crtc_commit *commit;  	int i;  	long ret; -	for_each_crtc_in_state(old_state, crtc, crtc_state, i) { +	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {  		spin_lock(&crtc->commit_lock);  		commit = preceeding_commit(crtc);  		if (commit) @@ -1564,17 +1562,17 @@ EXPORT_SYMBOL(drm_atomic_helper_wait_for_dependencies);  void drm_atomic_helper_commit_hw_done(struct drm_atomic_state *old_state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_crtc_commit *commit;  	int i; -	for_each_crtc_in_state(old_state, crtc, crtc_state, i) { +	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {  		commit = old_state->crtcs[i].commit;  		if (!commit)  			continue;  		/* backend must have consumed any event by now */ -		WARN_ON(crtc->state->event); +		WARN_ON(new_crtc_state->event);  		spin_lock(&crtc->commit_lock);  		complete_all(&commit->hw_done);  		spin_unlock(&crtc->commit_lock); @@ -1596,12 +1594,12 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_hw_done);  void drm_atomic_helper_commit_cleanup_done(struct drm_atomic_state *old_state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_crtc_commit *commit;  	int i;  	long ret; -	for_each_crtc_in_state(old_state, crtc, crtc_state, i) { +	for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {  		commit = old_state->crtcs[i].commit;  		if (WARN_ON(!commit))  			continue; @@ -1652,16 +1650,16 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,  				     struct drm_atomic_state *state)  {  	struct drm_plane *plane; -	struct drm_plane_state *plane_state; +	struct drm_plane_state *new_plane_state;  	int ret, i, j; -	for_each_plane_in_state(state, plane, plane_state, i) { +	for_each_new_plane_in_state(state, plane, new_plane_state, i) {  		const struct drm_plane_helper_funcs *funcs;  		funcs = plane->helper_private;  		if (funcs->prepare_fb) { -			ret = funcs->prepare_fb(plane, plane_state); +			ret = funcs->prepare_fb(plane, new_plane_state);  			if (ret)  				goto fail;  		} @@ -1670,7 +1668,7 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,  	return 0;  fail: -	for_each_plane_in_state(state, plane, plane_state, j) { +	for_each_new_plane_in_state(state, plane, new_plane_state, j) {  		const struct drm_plane_helper_funcs *funcs;  		if (j >= i) @@ -1679,7 +1677,7 @@ fail:  		funcs = plane->helper_private;  		if (funcs->cleanup_fb) -			funcs->cleanup_fb(plane, plane_state); +			funcs->cleanup_fb(plane, new_plane_state);  	}  	return ret; @@ -1737,14 +1735,14 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  				     uint32_t flags)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *old_crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	struct drm_plane *plane; -	struct drm_plane_state *old_plane_state; +	struct drm_plane_state *old_plane_state, *new_plane_state;  	int i;  	bool active_only = flags & DRM_PLANE_COMMIT_ACTIVE_ONLY;  	bool no_disable = flags & DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET; -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs;  		funcs = crtc->helper_private; @@ -1752,13 +1750,13 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  		if (!funcs || !funcs->atomic_begin)  			continue; -		if (active_only && !crtc->state->active) +		if (active_only && !new_crtc_state->active)  			continue;  		funcs->atomic_begin(crtc, old_crtc_state);  	} -	for_each_plane_in_state(old_state, plane, old_plane_state, i) { +	for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {  		const struct drm_plane_helper_funcs *funcs;  		bool disabling; @@ -1767,7 +1765,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  		if (!funcs)  			continue; -		disabling = drm_atomic_plane_disabling(plane, old_plane_state); +		disabling = drm_atomic_plane_disabling(old_plane_state, +						       new_plane_state);  		if (active_only) {  			/* @@ -1777,7 +1776,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  			 * CRTC to avoid skipping planes being disabled on an  			 * active CRTC.  			 */ -			if (!disabling && !plane_crtc_active(plane->state)) +			if (!disabling && !plane_crtc_active(new_plane_state))  				continue;  			if (disabling && !plane_crtc_active(old_plane_state))  				continue; @@ -1796,12 +1795,12 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  				continue;  			funcs->atomic_disable(plane, old_plane_state); -		} else if (plane->state->crtc || disabling) { +		} else if (new_plane_state->crtc || disabling) {  			funcs->atomic_update(plane, old_plane_state);  		}  	} -	for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { +	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {  		const struct drm_crtc_helper_funcs *funcs;  		funcs = crtc->helper_private; @@ -1809,7 +1808,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,  		if (!funcs || !funcs->atomic_flush)  			continue; -		if (active_only && !crtc->state->active) +		if (active_only && !new_crtc_state->active)  			continue;  		funcs->atomic_flush(crtc, old_crtc_state); @@ -1852,7 +1851,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)  	drm_for_each_plane_mask(plane, crtc->dev, plane_mask) {  		struct drm_plane_state *old_plane_state = -			drm_atomic_get_existing_plane_state(old_state, plane); +			drm_atomic_get_old_plane_state(old_state, plane);  		const struct drm_plane_helper_funcs *plane_funcs;  		plane_funcs = plane->helper_private; @@ -1862,11 +1861,11 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)  		WARN_ON(plane->state->crtc && plane->state->crtc != crtc); -		if (drm_atomic_plane_disabling(plane, old_plane_state) && +		if (drm_atomic_plane_disabling(old_plane_state, plane->state) &&  		    plane_funcs->atomic_disable)  			plane_funcs->atomic_disable(plane, old_plane_state);  		else if (plane->state->crtc || -			 drm_atomic_plane_disabling(plane, old_plane_state)) +			 drm_atomic_plane_disabling(old_plane_state, plane->state))  			plane_funcs->atomic_update(plane, old_plane_state);  	} @@ -1936,11 +1935,21 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,  				      struct drm_atomic_state *old_state)  {  	struct drm_plane *plane; -	struct drm_plane_state *plane_state; +	struct drm_plane_state *old_plane_state, *new_plane_state;  	int i; -	for_each_plane_in_state(old_state, plane, plane_state, i) { +	for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {  		const struct drm_plane_helper_funcs *funcs; +		struct drm_plane_state *plane_state; + +		/* +		 * This might be called before swapping when commit is aborted, +		 * in which case we have to cleanup the new state. +		 */ +		if (old_plane_state == plane->state) +			plane_state = new_plane_state; +		else +			plane_state = old_plane_state;  		funcs = plane->helper_private; @@ -1986,15 +1995,15 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,  	int i;  	long ret;  	struct drm_connector *connector; -	struct drm_connector_state *conn_state, *old_conn_state; +	struct drm_connector_state *old_conn_state, *new_conn_state;  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state, *old_crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	struct drm_plane *plane; -	struct drm_plane_state *plane_state, *old_plane_state; +	struct drm_plane_state *old_plane_state, *new_plane_state;  	struct drm_crtc_commit *commit;  	if (stall) { -		for_each_crtc_in_state(state, crtc, crtc_state, i) { +		for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {  			spin_lock(&crtc->commit_lock);  			commit = list_first_entry_or_null(&crtc->commit_list,  					struct drm_crtc_commit, commit_entry); @@ -2014,20 +2023,24 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,  		}  	} -	for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn_state, i) { +	for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {  		WARN_ON(connector->state != old_conn_state); -		connector->state->state = state; -		swap(state->connectors[i].state, connector->state); -		connector->state->state = NULL; +		old_conn_state->state = state; +		new_conn_state->state = NULL; + +		state->connectors[i].state = old_conn_state; +		connector->state = new_conn_state;  	} -	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) { +	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {  		WARN_ON(crtc->state != old_crtc_state); -		crtc->state->state = state; -		swap(state->crtcs[i].state, crtc->state); -		crtc->state->state = NULL; +		old_crtc_state->state = state; +		new_crtc_state->state = NULL; + +		state->crtcs[i].state = old_crtc_state; +		crtc->state = new_crtc_state;  		if (state->crtcs[i].commit) {  			spin_lock(&crtc->commit_lock); @@ -2039,12 +2052,14 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,  		}  	} -	for_each_oldnew_plane_in_state(state, plane, old_plane_state, plane_state, i) { +	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {  		WARN_ON(plane->state != old_plane_state); -		plane->state->state = state; -		swap(state->planes[i].state, plane->state); -		plane->state->state = NULL; +		old_plane_state->state = state; +		new_plane_state->state = NULL; + +		state->planes[i].state = old_plane_state; +		plane->state = new_plane_state;  	}  }  EXPORT_SYMBOL(drm_atomic_helper_swap_state); @@ -2227,9 +2242,9 @@ static int update_output_state(struct drm_atomic_state *state,  {  	struct drm_device *dev = set->crtc->dev;  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	struct drm_connector *connector; -	struct drm_connector_state *conn_state; +	struct drm_connector_state *new_conn_state;  	int ret, i;  	ret = drm_modeset_lock(&dev->mode_config.connection_mutex, @@ -2242,31 +2257,32 @@ static int update_output_state(struct drm_atomic_state *state,  	if (ret)  		return ret; -	for_each_connector_in_state(state, connector, conn_state, i) { -		if (conn_state->crtc == set->crtc) { -			ret = drm_atomic_set_crtc_for_connector(conn_state, +	for_each_new_connector_in_state(state, connector, new_conn_state, i) { +		if (new_conn_state->crtc == set->crtc) { +			ret = drm_atomic_set_crtc_for_connector(new_conn_state,  								NULL);  			if (ret)  				return ret; +  			/* Make sure legacy setCrtc always re-trains */ -			conn_state->link_status = DRM_LINK_STATUS_GOOD; +			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;  		}  	}  	/* Then set all connectors from set->connectors on the target crtc */  	for (i = 0; i < set->num_connectors; i++) { -		conn_state = drm_atomic_get_connector_state(state, +		new_conn_state = drm_atomic_get_connector_state(state,  							    set->connectors[i]); -		if (IS_ERR(conn_state)) -			return PTR_ERR(conn_state); +		if (IS_ERR(new_conn_state)) +			return PTR_ERR(new_conn_state); -		ret = drm_atomic_set_crtc_for_connector(conn_state, +		ret = drm_atomic_set_crtc_for_connector(new_conn_state,  							set->crtc);  		if (ret)  			return ret;  	} -	for_each_crtc_in_state(state, crtc, crtc_state, i) { +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {  		/* Don't update ->enable for the CRTC in the set_config request,  		 * since a mismatch would indicate a bug in the upper layers.  		 * The actual modeset code later on will catch any @@ -2274,13 +2290,13 @@ static int update_output_state(struct drm_atomic_state *state,  		if (crtc == set->crtc)  			continue; -		if (!crtc_state->connector_mask) { -			ret = drm_atomic_set_mode_prop_for_crtc(crtc_state, +		if (!new_crtc_state->connector_mask) { +			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,  								NULL);  			if (ret < 0)  				return ret; -			crtc_state->active = false; +			new_crtc_state->active = false;  		}  	} @@ -2583,21 +2599,21 @@ int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,  {  	int i;  	struct drm_plane *plane; -	struct drm_plane_state *plane_state; +	struct drm_plane_state *new_plane_state;  	struct drm_connector *connector; -	struct drm_connector_state *conn_state; +	struct drm_connector_state *new_conn_state;  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *new_crtc_state;  	state->acquire_ctx = ctx; -	for_each_new_plane_in_state(state, plane, plane_state, i) +	for_each_new_plane_in_state(state, plane, new_plane_state, i)  		state->planes[i].old_state = plane->state; -	for_each_new_crtc_in_state(state, crtc, crtc_state, i) +	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)  		state->crtcs[i].old_state = crtc->state; -	for_each_new_connector_in_state(state, connector, conn_state, i) +	for_each_new_connector_in_state(state, connector, new_conn_state, i)  		state->connectors[i].old_state = connector->state;  	return drm_atomic_commit(state); @@ -2938,7 +2954,7 @@ retry:  	if (ret != 0)  		goto fail; -	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);  	if (WARN_ON(!crtc_state)) {  		ret = -EINVAL;  		goto fail; diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c index 665aafc6ad68..a0d0d6843288 100644 --- a/drivers/gpu/drm/drm_blend.c +++ b/drivers/gpu/drm/drm_blend.c @@ -377,27 +377,26 @@ int drm_atomic_normalize_zpos(struct drm_device *dev,  			      struct drm_atomic_state *state)  {  	struct drm_crtc *crtc; -	struct drm_crtc_state *crtc_state; +	struct drm_crtc_state *old_crtc_state, *new_crtc_state;  	struct drm_plane *plane; -	struct drm_plane_state *plane_state; +	struct drm_plane_state *old_plane_state, *new_plane_state;  	int i, ret = 0; -	for_each_plane_in_state(state, plane, plane_state, i) { -		crtc = plane_state->crtc; +	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { +		crtc = new_plane_state->crtc;  		if (!crtc)  			continue; -		if (plane->state->zpos != plane_state->zpos) { -			crtc_state = -				drm_atomic_get_existing_crtc_state(state, crtc); -			crtc_state->zpos_changed = true; +		if (old_plane_state->zpos != new_plane_state->zpos) { +			new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); +			new_crtc_state->zpos_changed = true;  		}  	} -	for_each_crtc_in_state(state, crtc, crtc_state, i) { -		if (crtc_state->plane_mask != crtc->state->plane_mask || -		    crtc_state->zpos_changed) { +	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { +		if (old_crtc_state->plane_mask != new_crtc_state->plane_mask || +		    new_crtc_state->zpos_changed) {  			ret = drm_atomic_helper_crtc_normalize_zpos(crtc, -								    crtc_state); +								    new_crtc_state);  			if (ret)  				return ret;  		} diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 8b2c61ae0004..1d2d18d82d2e 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -242,14 +242,9 @@ static void drm_debugfs_remove_all_files(struct drm_minor *minor)   */  int drm_debugfs_cleanup(struct drm_minor *minor)  { -	struct drm_device *dev = minor->dev; -  	if (!minor->debugfs_root)  		return 0; -	if (dev->driver->debugfs_cleanup) -		dev->driver->debugfs_cleanup(minor); -  	drm_debugfs_remove_all_files(minor);  	debugfs_remove_recursive(minor->debugfs_root); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 68908c1d5ca1..3e5f52110ea1 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -981,6 +981,78 @@ static const struct i2c_lock_operations drm_dp_i2c_lock_ops = {  	.unlock_bus = unlock_bus,  }; +static int drm_dp_aux_get_crc(struct drm_dp_aux *aux, u8 *crc) +{ +	u8 buf, count; +	int ret; + +	ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf); +	if (ret < 0) +		return ret; + +	WARN_ON(!(buf & DP_TEST_SINK_START)); + +	ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK_MISC, &buf); +	if (ret < 0) +		return ret; + +	count = buf & DP_TEST_COUNT_MASK; +	if (count == aux->crc_count) +		return -EAGAIN; /* No CRC yet */ + +	aux->crc_count = count; + +	/* +	 * At DP_TEST_CRC_R_CR, there's 6 bytes containing CRC data, 2 bytes +	 * per component (RGB or CrYCb). +	 */ +	ret = drm_dp_dpcd_read(aux, DP_TEST_CRC_R_CR, crc, 6); +	if (ret < 0) +		return ret; + +	return 0; +} + +static void drm_dp_aux_crc_work(struct work_struct *work) +{ +	struct drm_dp_aux *aux = container_of(work, struct drm_dp_aux, +					      crc_work); +	struct drm_crtc *crtc; +	u8 crc_bytes[6]; +	uint32_t crcs[3]; +	int ret; + +	if (WARN_ON(!aux->crtc)) +		return; + +	crtc = aux->crtc; +	while (crtc->crc.opened) { +		drm_crtc_wait_one_vblank(crtc); +		if (!crtc->crc.opened) +			break; + +		ret = drm_dp_aux_get_crc(aux, crc_bytes); +		if (ret == -EAGAIN) { +			usleep_range(1000, 2000); +			ret = drm_dp_aux_get_crc(aux, crc_bytes); +		} + +		if (ret == -EAGAIN) { +			DRM_DEBUG_KMS("Get CRC failed after retrying: %d\n", +				      ret); +			continue; +		} else if (ret) { +			DRM_DEBUG_KMS("Failed to get a CRC: %d\n", ret); +			continue; +		} + +		crcs[0] = crc_bytes[0] | crc_bytes[1] << 8; +		crcs[1] = crc_bytes[2] | crc_bytes[3] << 8; +		crcs[2] = crc_bytes[4] | crc_bytes[5] << 8; +		drm_crtc_add_crc_entry(crtc, false, 0, crcs); +	} +} +  /**   * drm_dp_aux_init() - minimally initialise an aux channel   * @aux: DisplayPort AUX channel @@ -993,6 +1065,7 @@ static const struct i2c_lock_operations drm_dp_i2c_lock_ops = {  void drm_dp_aux_init(struct drm_dp_aux *aux)  {  	mutex_init(&aux->hw_mutex); +	INIT_WORK(&aux->crc_work, drm_dp_aux_crc_work);  	aux->ddc.algo = &drm_dp_i2c_algo;  	aux->ddc.algo_data = aux; @@ -1081,3 +1154,57 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE])  EXPORT_SYMBOL(drm_dp_psr_setup_time);  #undef PSR_SETUP_TIME + +/** + * drm_dp_start_crc() - start capture of frame CRCs + * @aux: DisplayPort AUX channel + * @crtc: CRTC displaying the frames whose CRCs are to be captured + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc) +{ +	u8 buf; +	int ret; + +	ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf); +	if (ret < 0) +		return ret; + +	ret = drm_dp_dpcd_writeb(aux, DP_TEST_SINK, buf | DP_TEST_SINK_START); +	if (ret < 0) +		return ret; + +	aux->crc_count = 0; +	aux->crtc = crtc; +	schedule_work(&aux->crc_work); + +	return 0; +} +EXPORT_SYMBOL(drm_dp_start_crc); + +/** + * drm_dp_stop_crc() - stop capture of frame CRCs + * @aux: DisplayPort AUX channel + * + * Returns 0 on success or a negative error code on failure. + */ +int drm_dp_stop_crc(struct drm_dp_aux *aux) +{ +	u8 buf; +	int ret; + +	ret = drm_dp_dpcd_readb(aux, DP_TEST_SINK, &buf); +	if (ret < 0) +		return ret; + +	ret = drm_dp_dpcd_writeb(aux, DP_TEST_SINK, buf & ~DP_TEST_SINK_START); +	if (ret < 0) +		return ret; + +	flush_work(&aux->crc_work); +	aux->crtc = NULL; + +	return 0; +} +EXPORT_SYMBOL(drm_dp_stop_crc); diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_file.c index afdf5b147f39..d9e63d73d3ec 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_file.c @@ -1,7 +1,4 @@  /* - * \file drm_fops.c - * File operations for DRM - *   * \author Rickard E. (Rik) Faith <faith@valinux.com>   * \author Daryll Strauss <daryll@valinux.com>   * \author Gareth Hughes <gareth@valinux.com> @@ -34,10 +31,13 @@   * OTHER DEALINGS IN THE SOFTWARE.   */ -#include <drm/drmP.h>  #include <linux/poll.h>  #include <linux/slab.h>  #include <linux/module.h> + +#include <drm/drm_file.h> +#include <drm/drmP.h> +  #include "drm_legacy.h"  #include "drm_internal.h"  #include "drm_crtc_internal.h" diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index f37388cb2fde..92ff4b9393b1 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -24,7 +24,7 @@  #define DRM_IF_MAJOR 1  #define DRM_IF_MINOR 4 -/* drm_fops.c */ +/* drm_file.c */  extern struct mutex drm_global_mutex;  void drm_lastclose(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 45db36cd3d20..6e35a56a6102 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c @@ -25,8 +25,7 @@   *   */ -#include <drm/drmP.h> -#include <drm/drm_fb_helper.h> +#include <linux/module.h>  #include "drm_crtc_helper_internal.h" diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index a3b356e70b35..1eb4fc3eee20 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -26,6 +26,7 @@  #include <linux/slab.h>  #include <linux/dma-mapping.h>  #include <linux/export.h> +#include <drm/drm_pci.h>  #include <drm/drmP.h>  #include "drm_internal.h"  #include "drm_legacy.h" @@ -36,6 +37,9 @@   * @size: size of block to allocate   * @align: alignment of block   * + * FIXME: This is a needless abstraction of the Linux dma-api and should be + * removed. + *   * Return: A handle to the allocated memory block on success or NULL on   * failure.   */ @@ -104,6 +108,9 @@ void __drm_legacy_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)   * drm_pci_free - Free a PCI consistent memory block   * @dev: DRM device   * @dmah: handle to memory block + * + * FIXME: This is a needless abstraction of the Linux dma-api and should be + * removed.   */  void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)  { diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 244cf2619294..de1ac5e08f4d 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -469,7 +469,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,  	 * Drivers may optionally implement the ->atomic_disable callback, so  	 * special-case that here.  	 */ -	if (drm_atomic_plane_disabling(plane, plane_state) && +	if (drm_atomic_plane_disabling(plane_state, plane->state) &&  	    plane_funcs->atomic_disable)  		plane_funcs->atomic_disable(plane, plane_state);  	else diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c deleted file mode 100644 index 56d2f93ed6b9..000000000000 --- a/drivers/gpu/drm/drm_platform.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Derived from drm_pci.c - * - * Copyright 2003 José Fonseca. - * Copyright 2003 Leif Delgass. - * Copyright (c) 2009, Code Aurora Forum. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE - * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <linux/export.h> -#include <drm/drmP.h> - -/* - * Register. - * - * \param platdev - Platform device struture - * \return zero on success or a negative number on failure. - * - * Attempt to gets inter module "drm" information. If we are first - * then register the character device and inter module information. - * Try and register, if we fail to register, backout previous work. - */ - -static int drm_get_platform_dev(struct platform_device *platdev, -				struct drm_driver *driver) -{ -	struct drm_device *dev; -	int ret; - -	DRM_DEBUG("\n"); - -	dev = drm_dev_alloc(driver, &platdev->dev); -	if (IS_ERR(dev)) -		return PTR_ERR(dev); - -	dev->platformdev = platdev; - -	ret = drm_dev_register(dev, 0); -	if (ret) -		goto err_free; - -	return 0; - -err_free: -	drm_dev_unref(dev); -	return ret; -} - -/** - * drm_platform_init - Register a platform device with the DRM subsystem - * @driver: DRM device driver - * @platform_device: platform device to register - * - * Registers the specified DRM device driver and platform device with the DRM - * subsystem, initializing a drm_device structure and calling the driver's - * .load() function. - * - * NOTE: This function is deprecated, please use drm_dev_alloc() and - * drm_dev_register() instead and remove your &drm_driver.load callback. - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device) -{ -	DRM_DEBUG("\n"); - -	return drm_get_platform_dev(platform_device, driver); -} -EXPORT_SYMBOL(drm_platform_init); diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 866b294e7c61..9fb65b736a90 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -29,8 +29,9 @@  #include <linux/export.h>  #include <linux/dma-buf.h>  #include <linux/rbtree.h> -#include <drm/drmP.h> +#include <drm/drm_prime.h>  #include <drm/drm_gem.h> +#include <drm/drmP.h>  #include "drm_internal.h" diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 35c5d99296b9..16789faa9291 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -86,8 +86,8 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,  	int ret;  	pipe = container_of(plane, struct drm_simple_display_pipe, plane); -	crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state, -							&pipe->crtc); +	crtc_state = drm_atomic_get_new_crtc_state(plane_state->state, +						   &pipe->crtc);  	if (crtc_state->enable != !!plane_state->crtc)  		return -EINVAL; /* plane must match crtc enable state */ diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 1ef0be338b85..b445b50a5dc4 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -101,7 +101,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,  	struct exynos_dp_device *dp = to_dp(plat_data);  	int ret; -	drm_connector_register(connector);  	dp->connector = connector;  	/* Pre-empt DP connector creation if there's a bridge */ diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index ad6b73c7fc59..3aab71a485ba 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -114,7 +114,6 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder)  	}  	drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs); -	drm_connector_register(connector);  	drm_mode_connector_attach_encoder(connector, encoder);  	return 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index b4522f67b3cb..09d3c4c3c858 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -39,118 +39,6 @@  static struct device *exynos_drm_get_dma_device(void); -static int exynos_drm_load(struct drm_device *dev, unsigned long flags) -{ -	struct exynos_drm_private *private; -	struct drm_encoder *encoder; -	unsigned int clone_mask; -	int cnt, ret; - -	private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); -	if (!private) -		return -ENOMEM; - -	init_waitqueue_head(&private->wait); -	spin_lock_init(&private->lock); - -	dev_set_drvdata(dev->dev, dev); -	dev->dev_private = (void *)private; - -	/* the first real CRTC device is used for all dma mapping operations */ -	private->dma_dev = exynos_drm_get_dma_device(); -	if (!private->dma_dev) { -		DRM_ERROR("no device found for DMA mapping operations.\n"); -		ret = -ENODEV; -		goto err_free_private; -	} -	DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n", -		 dev_name(private->dma_dev)); - -	/* create common IOMMU mapping for all devices attached to Exynos DRM */ -	ret = drm_create_iommu_mapping(dev); -	if (ret < 0) { -		DRM_ERROR("failed to create iommu mapping.\n"); -		goto err_free_private; -	} - -	drm_mode_config_init(dev); - -	exynos_drm_mode_config_init(dev); - -	/* setup possible_clones. */ -	cnt = 0; -	clone_mask = 0; -	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) -		clone_mask |= (1 << (cnt++)); - -	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) -		encoder->possible_clones = clone_mask; - -	platform_set_drvdata(dev->platformdev, dev); - -	/* Try to bind all sub drivers. */ -	ret = component_bind_all(dev->dev, dev); -	if (ret) -		goto err_mode_config_cleanup; - -	ret = drm_vblank_init(dev, dev->mode_config.num_crtc); -	if (ret) -		goto err_unbind_all; - -	/* Probe non kms sub drivers and virtual display driver. */ -	ret = exynos_drm_device_subdrv_probe(dev); -	if (ret) -		goto err_cleanup_vblank; - -	drm_mode_config_reset(dev); - -	/* -	 * enable drm irq mode. -	 * - with irq_enabled = true, we can use the vblank feature. -	 * -	 * P.S. note that we wouldn't use drm irq handler but -	 *	just specific driver own one instead because -	 *	drm framework supports only one irq handler. -	 */ -	dev->irq_enabled = true; - -	/* init kms poll for handling hpd */ -	drm_kms_helper_poll_init(dev); - -	/* force connectors detection */ -	drm_helper_hpd_irq_event(dev); - -	return 0; - -err_cleanup_vblank: -	drm_vblank_cleanup(dev); -err_unbind_all: -	component_unbind_all(dev->dev, dev); -err_mode_config_cleanup: -	drm_mode_config_cleanup(dev); -	drm_release_iommu_mapping(dev); -err_free_private: -	kfree(private); - -	return ret; -} - -static void exynos_drm_unload(struct drm_device *dev) -{ -	exynos_drm_device_subdrv_remove(dev); - -	exynos_drm_fbdev_fini(dev); -	drm_kms_helper_poll_fini(dev); - -	drm_vblank_cleanup(dev); -	component_unbind_all(dev->dev, dev); -	drm_mode_config_cleanup(dev); -	drm_release_iommu_mapping(dev); - -	kfree(dev->dev_private); -	dev->dev_private = NULL; -} -  int exynos_atomic_check(struct drm_device *dev,  			struct drm_atomic_state *state)  { @@ -256,8 +144,6 @@ static const struct file_operations exynos_drm_driver_fops = {  static struct drm_driver exynos_drm_driver = {  	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME  				  | DRIVER_ATOMIC | DRIVER_RENDER, -	.load			= exynos_drm_load, -	.unload			= exynos_drm_unload,  	.open			= exynos_drm_open,  	.preclose		= exynos_drm_preclose,  	.lastclose		= exynos_drm_lastclose, @@ -432,12 +318,135 @@ static struct component_match *exynos_drm_match_add(struct device *dev)  static int exynos_drm_bind(struct device *dev)  { -	return drm_platform_init(&exynos_drm_driver, to_platform_device(dev)); +	struct exynos_drm_private *private; +	struct drm_encoder *encoder; +	struct drm_device *drm; +	unsigned int clone_mask; +	int cnt, ret; + +	drm = drm_dev_alloc(&exynos_drm_driver, dev); +	if (IS_ERR(drm)) +		return PTR_ERR(drm); + +	private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); +	if (!private) { +		ret = -ENOMEM; +		goto err_free_drm; +	} + +	init_waitqueue_head(&private->wait); +	spin_lock_init(&private->lock); + +	dev_set_drvdata(dev, drm); +	drm->dev_private = (void *)private; + +	/* the first real CRTC device is used for all dma mapping operations */ +	private->dma_dev = exynos_drm_get_dma_device(); +	if (!private->dma_dev) { +		DRM_ERROR("no device found for DMA mapping operations.\n"); +		ret = -ENODEV; +		goto err_free_private; +	} +	DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n", +		 dev_name(private->dma_dev)); + +	/* create common IOMMU mapping for all devices attached to Exynos DRM */ +	ret = drm_create_iommu_mapping(drm); +	if (ret < 0) { +		DRM_ERROR("failed to create iommu mapping.\n"); +		goto err_free_private; +	} + +	drm_mode_config_init(drm); + +	exynos_drm_mode_config_init(drm); + +	/* setup possible_clones. */ +	cnt = 0; +	clone_mask = 0; +	list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) +		clone_mask |= (1 << (cnt++)); + +	list_for_each_entry(encoder, &drm->mode_config.encoder_list, head) +		encoder->possible_clones = clone_mask; + +	/* Try to bind all sub drivers. */ +	ret = component_bind_all(drm->dev, drm); +	if (ret) +		goto err_mode_config_cleanup; + +	ret = drm_vblank_init(drm, drm->mode_config.num_crtc); +	if (ret) +		goto err_unbind_all; + +	/* Probe non kms sub drivers and virtual display driver. */ +	ret = exynos_drm_device_subdrv_probe(drm); +	if (ret) +		goto err_cleanup_vblank; + +	drm_mode_config_reset(drm); + +	/* +	 * enable drm irq mode. +	 * - with irq_enabled = true, we can use the vblank feature. +	 * +	 * P.S. note that we wouldn't use drm irq handler but +	 *	just specific driver own one instead because +	 *	drm framework supports only one irq handler. +	 */ +	drm->irq_enabled = true; + +	/* init kms poll for handling hpd */ +	drm_kms_helper_poll_init(drm); + +	/* force connectors detection */ +	drm_helper_hpd_irq_event(drm); + +	/* register the DRM device */ +	ret = drm_dev_register(drm, 0); +	if (ret < 0) +		goto err_cleanup_fbdev; + +	return 0; + +err_cleanup_fbdev: +	exynos_drm_fbdev_fini(drm); +	drm_kms_helper_poll_fini(drm); +	exynos_drm_device_subdrv_remove(drm); +err_cleanup_vblank: +	drm_vblank_cleanup(drm); +err_unbind_all: +	component_unbind_all(drm->dev, drm); +err_mode_config_cleanup: +	drm_mode_config_cleanup(drm); +	drm_release_iommu_mapping(drm); +err_free_private: +	kfree(private); +err_free_drm: +	drm_dev_unref(drm); + +	return ret;  }  static void exynos_drm_unbind(struct device *dev)  { -	drm_put_dev(dev_get_drvdata(dev)); +	struct drm_device *drm = dev_get_drvdata(dev); + +	drm_dev_unregister(drm); + +	exynos_drm_device_subdrv_remove(drm); + +	exynos_drm_fbdev_fini(drm); +	drm_kms_helper_poll_fini(drm); + +	component_unbind_all(drm->dev, drm); +	drm_mode_config_cleanup(drm); +	drm_release_iommu_mapping(drm); + +	kfree(drm->dev_private); +	drm->dev_private = NULL; + +	drm_dev_unref(drm);  }  static const struct component_master_ops exynos_drm_ops = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 812e2ec0761d..43a45abc524f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1587,7 +1587,6 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder)  	}  	drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); -	drm_connector_register(connector);  	drm_mode_connector_attach_encoder(connector, encoder);  	return 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 40aa5056d4ae..641531243e04 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -119,7 +119,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,  	struct exynos_drm_gem *exynos_gem;  	struct drm_device *dev = helper->dev;  	struct drm_mode_fb_cmd2 mode_cmd = { 0 }; -	struct platform_device *pdev = dev->platformdev;  	unsigned long size;  	int ret; @@ -142,7 +141,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,  	 * memory area.  	 */  	if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) { -		dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); +		dev_warn(dev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n");  		exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG,  						   size);  	} diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 57fe514d5c5b..6bbb0ea8a6af 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -359,7 +359,6 @@ static int vidi_create_connector(struct drm_encoder *encoder)  	}  	drm_connector_helper_add(connector, &vidi_connector_helper_funcs); -	drm_connector_register(connector);  	drm_mode_connector_attach_encoder(connector, encoder);  	return 0; diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 0814ed76445c..52438404c8c9 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -920,7 +920,6 @@ static int hdmi_create_connector(struct drm_encoder *encoder)  	}  	drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); -	drm_connector_register(connector);  	drm_mode_connector_attach_encoder(connector, encoder);  	if (hdata->bridge) { diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index f645275e6e63..f039641070ac 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -175,7 +175,6 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {  	.mpll_cfg   = imx_mpll_cfg,  	.cur_ctr    = imx_cur_ctr,  	.phy_config = imx_phy_config, -	.dev_type   = IMX6Q_HDMI,  	.mode_valid = imx6q_hdmi_mode_valid,  }; @@ -183,7 +182,6 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {  	.mpll_cfg = imx_mpll_cfg,  	.cur_ctr  = imx_cur_ctr,  	.phy_config = imx_phy_config, -	.dev_type = IMX6DL_HDMI,  	.mode_valid = imx6dl_hdmi_mode_valid,  }; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 94ea963519b2..a4e1206a66a8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -434,7 +434,7 @@ fail:  struct msm_kms *mdp4_kms_init(struct drm_device *dev)  { -	struct platform_device *pdev = dev->platformdev; +	struct platform_device *pdev = to_platform_device(dev->dev);  	struct mdp4_platform_config *config = mdp4_get_config(pdev);  	struct mdp4_kms *mdp4_kms;  	struct msm_kms *kms = NULL; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index 34ab553f6897..ba2d017f6591 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -505,7 +505,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,  		uint32_t major, uint32_t minor)  {  	struct drm_device *dev = mdp5_kms->dev; -	struct platform_device *pdev = dev->platformdev; +	struct platform_device *pdev = to_platform_device(dev->dev);  	struct mdp5_cfg_handler *cfg_handler;  	struct mdp5_cfg_platform *pconfig;  	int i, ret = 0; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c index d444a6901fff..f8f48d014978 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_mdss.c @@ -160,7 +160,7 @@ void msm_mdss_destroy(struct drm_device *dev)  int msm_mdss_init(struct drm_device *dev)  { -	struct platform_device *pdev = dev->platformdev; +	struct platform_device *pdev = to_platform_device(dev->dev);  	struct msm_drm_private *priv = dev->dev_private;  	struct msm_mdss *mdss;  	int ret; diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 75609a1debf7..4f35d4eb85d0 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -164,20 +164,5 @@ int msm_debugfs_init(struct drm_minor *minor)  	return ret;  } - -void msm_debugfs_cleanup(struct drm_minor *minor) -{ -	struct drm_device *dev = minor->dev; -	struct msm_drm_private *priv = dev->dev_private; - -	if (!priv) -		return; - -	if (priv->kms->funcs->debugfs_cleanup) -		priv->kms->funcs->debugfs_cleanup(priv->kms, minor); - -	msm_rd_debugfs_cleanup(minor); -	msm_perf_debugfs_cleanup(minor); -}  #endif diff --git a/drivers/gpu/drm/msm/msm_debugfs.h b/drivers/gpu/drm/msm/msm_debugfs.h index 6110c972fd15..f4077e344e3a 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.h +++ b/drivers/gpu/drm/msm/msm_debugfs.h @@ -20,7 +20,6 @@  #ifdef CONFIG_DEBUG_FS  int msm_debugfs_init(struct drm_minor *minor); -void msm_debugfs_cleanup(struct drm_minor *minor);  #endif  #endif /* __MSM_DEBUGFS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 6842d427cc2b..9208e67be453 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -241,6 +241,9 @@ static int msm_drm_uninit(struct device *dev)  	drm_dev_unregister(ddev); +	msm_perf_debugfs_cleanup(priv); +	msm_rd_debugfs_cleanup(priv); +  #ifdef CONFIG_DRM_FBDEV_EMULATION  	if (fbdev && priv->fbdev)  		msm_fbdev_free(ddev); @@ -383,7 +386,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)  	}  	platform_set_drvdata(pdev, ddev); -	ddev->platformdev = pdev;  	priv = kzalloc(sizeof(*priv), GFP_KERNEL);  	if (!priv) { @@ -836,7 +838,6 @@ static struct drm_driver msm_driver = {  	.gem_prime_mmap     = msm_gem_prime_mmap,  #ifdef CONFIG_DEBUG_FS  	.debugfs_init       = msm_debugfs_init, -	.debugfs_cleanup    = msm_debugfs_cleanup,  #endif  	.ioctls             = msm_ioctls,  	.num_ioctls         = DRM_MSM_NUM_IOCTLS, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index c3b14876edaa..b51fb0d70f43 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -304,10 +304,10 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);  void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);  int msm_debugfs_late_init(struct drm_device *dev);  int msm_rd_debugfs_init(struct drm_minor *minor); -void msm_rd_debugfs_cleanup(struct drm_minor *minor); +void msm_rd_debugfs_cleanup(struct msm_drm_private *priv);  void msm_rd_dump_submit(struct msm_gem_submit *submit);  int msm_perf_debugfs_init(struct drm_minor *minor); -void msm_perf_debugfs_cleanup(struct drm_minor *minor); +void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);  #else  static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }  static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {} diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 117635d2b8c5..faa22c7c5423 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -64,7 +64,6 @@ struct msm_kms_funcs {  #ifdef CONFIG_DEBUG_FS  	/* debugfs: */  	int (*debugfs_init)(struct msm_kms *kms, struct drm_minor *minor); -	void (*debugfs_cleanup)(struct msm_kms *kms, struct drm_minor *minor);  #endif  }; diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index fc5a948c124c..5ab21bd2decb 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -231,13 +231,12 @@ int msm_perf_debugfs_init(struct drm_minor *minor)  	return 0;  fail: -	msm_perf_debugfs_cleanup(minor); +	msm_perf_debugfs_cleanup(priv);  	return -1;  } -void msm_perf_debugfs_cleanup(struct drm_minor *minor) +void msm_perf_debugfs_cleanup(struct msm_drm_private *priv)  { -	struct msm_drm_private *priv = minor->dev->dev_private;  	struct msm_perf_state *perf = priv->perf;  	if (!perf) diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index ab0b39f56780..3df7322fd74e 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -245,13 +245,12 @@ int msm_rd_debugfs_init(struct drm_minor *minor)  	return 0;  fail: -	msm_rd_debugfs_cleanup(minor); +	msm_rd_debugfs_cleanup(priv);  	return -1;  } -void msm_rd_debugfs_cleanup(struct drm_minor *minor) +void msm_rd_debugfs_cleanup(struct msm_drm_private *priv)  { -	struct msm_drm_private *priv = minor->dev->dev_private;  	struct msm_rd_state *rd = priv->rd;  	if (!rd) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index f0bb7606eb8b..2b6ac24ce690 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -108,7 +108,7 @@ nouveau_name(struct drm_device *dev)  	if (dev->pdev)  		return nouveau_pci_name(dev->pdev);  	else -		return nouveau_platform_name(dev->platformdev); +		return nouveau_platform_name(to_platform_device(dev->dev));  }  static void @@ -1095,7 +1095,6 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,  		goto err_free;  	} -	drm->platformdev = pdev;  	platform_set_drvdata(pdev, drm);  	return drm; diff --git a/drivers/gpu/drm/qxl/qxl_debugfs.c b/drivers/gpu/drm/qxl/qxl_debugfs.c index 8e6c78003226..ffe821b61f7d 100644 --- a/drivers/gpu/drm/qxl/qxl_debugfs.c +++ b/drivers/gpu/drm/qxl/qxl_debugfs.c @@ -129,16 +129,3 @@ int qxl_debugfs_add_files(struct qxl_device *qdev,  #endif  	return 0;  } - -void qxl_debugfs_remove_files(struct qxl_device *qdev) -{ -#if defined(CONFIG_DEBUG_FS) -	unsigned i; - -	for (i = 0; i < qdev->debugfs_count; i++) { -		drm_debugfs_remove_files(qdev->debugfs[i].files, -					 qdev->debugfs[i].num_files, -					 qdev->ddev.primary); -	} -#endif -} diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 2cd14bebc49c..9548bb58d3bc 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -81,6 +81,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)  			   qdev->rom->client_monitors_config_crc);  		return MONITORS_CONFIG_BAD_CRC;  	} +	if (!num_monitors) { +		DRM_DEBUG_KMS("no client monitors configured\n"); +		return status; +	}  	if (num_monitors > qdev->monitors_config->max_allowed) {  		DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",  			      qdev->monitors_config->max_allowed, num_monitors); @@ -157,19 +161,23 @@ static void qxl_update_offset_props(struct qxl_device *qdev)  void qxl_display_read_client_monitors_config(struct qxl_device *qdev)  { -  	struct drm_device *dev = &qdev->ddev; -	int status; +	int status, retries; -	status = qxl_display_copy_rom_client_monitors_config(qdev); -	while (status == MONITORS_CONFIG_BAD_CRC) { -		qxl_io_log(qdev, "failed crc check for client_monitors_config," -				 " retrying\n"); +	for (retries = 0; retries < 10; retries++) {  		status = qxl_display_copy_rom_client_monitors_config(qdev); +		if (status != MONITORS_CONFIG_BAD_CRC) +			break; +		udelay(5); +	} +	if (status == MONITORS_CONFIG_BAD_CRC) { +		qxl_io_log(qdev, "config: bad crc\n"); +		DRM_DEBUG_KMS("ignoring client monitors config: bad crc"); +		return;  	}  	if (status == MONITORS_CONFIG_UNCHANGED) { -		qxl_io_log(qdev, "config unchanged\n"); -		DRM_DEBUG("ignoring unchanged client monitors config"); +		qxl_io_log(qdev, "config: unchanged\n"); +		DRM_DEBUG_KMS("ignoring client monitors config: unchanged");  		return;  	} @@ -194,9 +202,17 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector,  	struct drm_display_mode *mode = NULL;  	struct qxl_head *head; +	if (!qdev->monitors_config) +		return 0; +	if (h >= qdev->monitors_config->max_allowed) +		return 0;  	if (!qdev->client_monitors_config)  		return 0; +	if (h >= qdev->client_monitors_config->count) +		return 0; +  	head = &qdev->client_monitors_config->heads[h]; +	DRM_DEBUG_KMS("head %d is %dx%d\n", h, head->width, head->height);  	mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false,  			    false); @@ -903,19 +919,13 @@ static void qxl_enc_mode_set(struct drm_encoder *encoder,  static int qxl_conn_get_modes(struct drm_connector *connector)  { -	int ret = 0; -	struct qxl_device *qdev = connector->dev->dev_private;  	unsigned pwidth = 1024;  	unsigned pheight = 768; +	int ret = 0; -	DRM_DEBUG_KMS("monitors_config=%p\n", qdev->monitors_config); -	/* TODO: what should we do here? only show the configured modes for the -	 * device, or allow the full list, or both? */ -	if (qdev->monitors_config && qdev->monitors_config->count) { -		ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight); -		if (ret < 0) -			return ret; -	} +	ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight); +	if (ret < 0) +		return ret;  	ret += qxl_add_common_modes(connector, pwidth, pheight);  	return ret;  } @@ -1188,6 +1198,7 @@ int qxl_modeset_init(struct qxl_device *qdev)  		qdev_output_init(&qdev->ddev, i);  	} +	qxl_display_read_client_monitors_config(qdev);  	qdev->mode_info.mode_config_initialized = true;  	drm_mode_config_reset(&qdev->ddev); diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index c0481706e4b0..5ea290a33a68 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -160,8 +160,6 @@ struct qxl_mman {  };  struct qxl_mode_info { -	int num_modes; -	struct qxl_mode *modes;  	bool mode_config_initialized;  	/* pointer to fbdev info structure */ @@ -232,7 +230,6 @@ int qxl_debugfs_add_files(struct qxl_device *rdev,  			     struct drm_info_list *files,  			     unsigned nfiles);  int qxl_debugfs_fence_init(struct qxl_device *rdev); -void qxl_debugfs_remove_files(struct qxl_device *qdev);  struct qxl_device; diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 35124737666e..14e2a49a4dcf 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -368,9 +368,11 @@ static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = {  int qxl_fbdev_init(struct qxl_device *qdev)  { +	int ret = 0; + +#ifdef CONFIG_DRM_FBDEV_EMULATION  	struct qxl_fbdev *qfbdev;  	int bpp_sel = 32; /* TODO: parameter from somewhere? */ -	int ret;  	qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);  	if (!qfbdev) @@ -403,6 +405,8 @@ fini:  	drm_fb_helper_fini(&qfbdev->helper);  free:  	kfree(qfbdev); +#endif +  	return ret;  } @@ -418,6 +422,9 @@ void qxl_fbdev_fini(struct qxl_device *qdev)  void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)  { +	if (!qdev->mode_info.qfbdev) +		return; +  	drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);  } diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 2b1e1f3c825d..c5716a0ca3b8 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -31,19 +31,9 @@  int qxl_log_level; -static void qxl_dump_mode(struct qxl_device *qdev, void *p) -{ -	struct qxl_mode *m = p; -	DRM_DEBUG_KMS("%d: %dx%d %d bits, stride %d, %dmm x %dmm, orientation %d\n", -		      m->id, m->x_res, m->y_res, m->bits, m->stride, m->x_mili, -		      m->y_mili, m->orientation); -} -  static bool qxl_check_device(struct qxl_device *qdev)  {  	struct qxl_rom *rom = qdev->rom; -	int mode_offset; -	int i;  	if (rom->magic != 0x4f525851) {  		DRM_ERROR("bad rom signature %x\n", rom->magic); @@ -53,8 +43,6 @@ static bool qxl_check_device(struct qxl_device *qdev)  	DRM_INFO("Device Version %d.%d\n", rom->id, rom->update_id);  	DRM_INFO("Compression level %d log level %d\n", rom->compression_level,  		 rom->log_level); -	DRM_INFO("Currently using mode #%d, list at 0x%x\n", -		 rom->mode, rom->modes_offset);  	DRM_INFO("%d io pages at offset 0x%x\n",  		 rom->num_io_pages, rom->pages_offset);  	DRM_INFO("%d byte draw area at offset 0x%x\n", @@ -62,14 +50,6 @@ static bool qxl_check_device(struct qxl_device *qdev)  	qdev->vram_size = rom->surface0_area_size;  	DRM_INFO("RAM header offset: 0x%x\n", rom->ram_header_offset); - -	mode_offset = rom->modes_offset / 4; -	qdev->mode_info.num_modes = ((u32 *)rom)[mode_offset]; -	DRM_INFO("rom modes offset 0x%x for %d modes\n", rom->modes_offset, -		 qdev->mode_info.num_modes); -	qdev->mode_info.modes = (void *)((uint32_t *)rom + mode_offset + 1); -	for (i = 0; i < qdev->mode_info.num_modes; i++) -		qxl_dump_mode(qdev, qdev->mode_info.modes + i);  	return true;  } @@ -282,7 +262,4 @@ void qxl_device_fini(struct qxl_device *qdev)  	iounmap(qdev->ram_header);  	iounmap(qdev->rom);  	qdev->rom = NULL; -	qdev->mode_info.modes = NULL; -	qdev->mode_info.num_modes = 0; -	qxl_debugfs_remove_files(qdev);  } diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index a6d4a0236e8f..d53827413996 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -237,7 +237,6 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {  	.mpll_cfg   = rockchip_mpll_cfg,  	.cur_ctr    = rockchip_cur_ctr,  	.phy_config = rockchip_phy_config, -	.dev_type   = RK3288_HDMI,  };  static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 94d7b7327ff7..2151e1cee4b4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -19,6 +19,9 @@  #include <drm/drm_crtc_helper.h>  #include <drm/drm_flip_work.h>  #include <drm/drm_plane_helper.h> +#ifdef CONFIG_DRM_ANALOGIX_DP +#include <drm/bridge/analogix_dp.h> +#endif  #include <linux/kernel.h>  #include <linux/module.h> @@ -1111,6 +1114,53 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc,  	kfree(s);  } +#ifdef CONFIG_DRM_ANALOGIX_DP +static struct drm_connector *vop_get_edp_connector(struct vop *vop) +{ +	struct drm_crtc *crtc = &vop->crtc; +	struct drm_connector *connector; + +	mutex_lock(&crtc->dev->mode_config.mutex); +	drm_for_each_connector(connector, crtc->dev) +		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { +			mutex_unlock(&crtc->dev->mode_config.mutex); +			return connector; +		} +	mutex_unlock(&crtc->dev->mode_config.mutex); + +	return NULL; +} + +static int vop_crtc_set_crc_source(struct drm_crtc *crtc, +				   const char *source_name, size_t *values_cnt) +{ +	struct vop *vop = to_vop(crtc); +	struct drm_connector *connector; +	int ret; + +	connector = vop_get_edp_connector(vop); +	if (!connector) +		return -EINVAL; + +	*values_cnt = 3; + +	if (source_name && strcmp(source_name, "auto") == 0) +		ret = analogix_dp_start_crc(connector); +	else if (!source_name) +		ret = analogix_dp_stop_crc(connector); +	else +		ret = -EINVAL; + +	return ret; +} +#else +static int vop_crtc_set_crc_source(struct drm_crtc *crtc, +				   const char *source_name, size_t *values_cnt) +{ +	return -ENODEV; +} +#endif +  static const struct drm_crtc_funcs vop_crtc_funcs = {  	.set_config = drm_atomic_helper_set_config,  	.page_flip = drm_atomic_helper_page_flip, @@ -1120,6 +1170,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {  	.atomic_destroy_state = vop_crtc_destroy_state,  	.enable_vblank = vop_crtc_enable_vblank,  	.disable_vblank = vop_crtc_disable_vblank, +	.set_crc_source = vop_crtc_set_crc_source,  };  static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 8244890e6d53..5fcabc04f307 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -711,13 +711,10 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,  		return ret;  	drm_connector_helper_add(connector, &connector_helper_funcs); -	ret = drm_connector_register(connector); -	if (ret < 0) -		goto err_cleanup;  	ret = shmob_drm_backlight_init(&sdev->connector);  	if (ret < 0) -		goto err_sysfs; +		goto err_cleanup;  	ret = drm_mode_connector_attach_encoder(connector, encoder);  	if (ret < 0) @@ -731,8 +728,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,  err_backlight:  	shmob_drm_backlight_exit(&sdev->connector); -err_sysfs: -	drm_connector_unregister(connector);  err_cleanup:  	drm_connector_cleanup(connector);  	return ret; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 34fefa0ba0f0..1c7b318b8998 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -103,100 +103,6 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,   * DRM operations   */ -static void shmob_drm_unload(struct drm_device *dev) -{ -	drm_kms_helper_poll_fini(dev); -	drm_mode_config_cleanup(dev); -	drm_vblank_cleanup(dev); -	drm_irq_uninstall(dev); - -	dev->dev_private = NULL; -} - -static int shmob_drm_load(struct drm_device *dev, unsigned long flags) -{ -	struct shmob_drm_platform_data *pdata = dev->dev->platform_data; -	struct platform_device *pdev = dev->platformdev; -	struct shmob_drm_device *sdev; -	struct resource *res; -	unsigned int i; -	int ret; - -	if (pdata == NULL) { -		dev_err(dev->dev, "no platform data\n"); -		return -EINVAL; -	} - -	sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); -	if (sdev == NULL) { -		dev_err(dev->dev, "failed to allocate private data\n"); -		return -ENOMEM; -	} - -	sdev->dev = &pdev->dev; -	sdev->pdata = pdata; -	spin_lock_init(&sdev->irq_lock); - -	sdev->ddev = dev; -	dev->dev_private = sdev; - -	/* I/O resources and clocks */ -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (res == NULL) { -		dev_err(&pdev->dev, "failed to get memory resource\n"); -		return -EINVAL; -	} - -	sdev->mmio = devm_ioremap_nocache(&pdev->dev, res->start, -					  resource_size(res)); -	if (sdev->mmio == NULL) { -		dev_err(&pdev->dev, "failed to remap memory resource\n"); -		return -ENOMEM; -	} - -	ret = shmob_drm_setup_clocks(sdev, pdata->clk_source); -	if (ret < 0) -		return ret; - -	ret = shmob_drm_init_interface(sdev); -	if (ret < 0) -		return ret; - -	ret = shmob_drm_modeset_init(sdev); -	if (ret < 0) { -		dev_err(&pdev->dev, "failed to initialize mode setting\n"); -		return ret; -	} - -	for (i = 0; i < 4; ++i) { -		ret = shmob_drm_plane_create(sdev, i); -		if (ret < 0) { -			dev_err(&pdev->dev, "failed to create plane %u\n", i); -			goto done; -		} -	} - -	ret = drm_vblank_init(dev, 1); -	if (ret < 0) { -		dev_err(&pdev->dev, "failed to initialize vblank\n"); -		goto done; -	} - -	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); -	if (ret < 0) { -		dev_err(&pdev->dev, "failed to install IRQ handler\n"); -		goto done; -	} - -	platform_set_drvdata(pdev, sdev); - -done: -	if (ret) -		shmob_drm_unload(dev); - -	return ret; -} -  static irqreturn_t shmob_drm_irq(int irq, void *arg)  {  	struct drm_device *dev = arg; @@ -236,8 +142,6 @@ static const struct file_operations shmob_drm_fops = {  static struct drm_driver shmob_drm_driver = {  	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET  				| DRIVER_PRIME, -	.load			= shmob_drm_load, -	.unload			= shmob_drm_unload,  	.irq_handler		= shmob_drm_irq,  	.gem_free_object_unlocked = drm_gem_cma_free_object,  	.gem_vm_ops		= &drm_gem_cma_vm_ops, @@ -297,18 +201,116 @@ static const struct dev_pm_ops shmob_drm_pm_ops = {   * Platform driver   */ -static int shmob_drm_probe(struct platform_device *pdev) +static int shmob_drm_remove(struct platform_device *pdev)  { -	return drm_platform_init(&shmob_drm_driver, pdev); +	struct shmob_drm_device *sdev = platform_get_drvdata(pdev); +	struct drm_device *ddev = sdev->ddev; + +	drm_dev_unregister(ddev); +	drm_kms_helper_poll_fini(ddev); +	drm_mode_config_cleanup(ddev); +	drm_irq_uninstall(ddev); +	drm_dev_unref(ddev); + +	return 0;  } -static int shmob_drm_remove(struct platform_device *pdev) +static int shmob_drm_probe(struct platform_device *pdev)  { -	struct shmob_drm_device *sdev = platform_get_drvdata(pdev); +	struct shmob_drm_platform_data *pdata = pdev->dev.platform_data; +	struct shmob_drm_device *sdev; +	struct drm_device *ddev; +	struct resource *res; +	unsigned int i; +	int ret; + +	if (pdata == NULL) { +		dev_err(&pdev->dev, "no platform data\n"); +		return -EINVAL; +	} -	drm_put_dev(sdev->ddev); +	/* +	 * Allocate and initialize the driver private data, I/O resources and +	 * clocks. +	 */ +	sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); +	if (sdev == NULL) +		return -ENOMEM; + +	sdev->dev = &pdev->dev; +	sdev->pdata = pdata; +	spin_lock_init(&sdev->irq_lock); + +	platform_set_drvdata(pdev, sdev); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	sdev->mmio = devm_ioremap_resource(&pdev->dev, res); +	if (sdev->mmio == NULL) +		return -ENOMEM; + +	ret = shmob_drm_setup_clocks(sdev, pdata->clk_source); +	if (ret < 0) +		return ret; + +	ret = shmob_drm_init_interface(sdev); +	if (ret < 0) +		return ret; + +	/* Allocate and initialize the DRM device. */ +	ddev = drm_dev_alloc(&shmob_drm_driver, &pdev->dev); +	if (IS_ERR(ddev)) +		return PTR_ERR(ddev); + +	sdev->ddev = ddev; +	ddev->dev_private = sdev; + +	ret = shmob_drm_modeset_init(sdev); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to initialize mode setting\n"); +		goto err_free_drm_dev; +	} + +	for (i = 0; i < 4; ++i) { +		ret = shmob_drm_plane_create(sdev, i); +		if (ret < 0) { +			dev_err(&pdev->dev, "failed to create plane %u\n", i); +			goto err_modeset_cleanup; +		} +	} + +	ret = drm_vblank_init(ddev, 1); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to initialize vblank\n"); +		goto err_modeset_cleanup; +	} + +	ret = drm_irq_install(ddev, platform_get_irq(pdev, 0)); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to install IRQ handler\n"); +		goto err_vblank_cleanup; +	} + +	/* +	 * Register the DRM device with the core and the connectors with +	 * sysfs. +	 */ +	ret = drm_dev_register(ddev, 0); +	if (ret < 0) +		goto err_irq_uninstall;  	return 0; + +err_irq_uninstall: +	drm_irq_uninstall(ddev); +err_vblank_cleanup: +	drm_vblank_cleanup(ddev); +err_modeset_cleanup: +	drm_kms_helper_poll_fini(ddev); +	drm_mode_config_cleanup(ddev); +err_free_drm_dev: +	drm_dev_unref(ddev); + +	return ret;  }  static struct platform_driver shmob_drm_platform_driver = { diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 3b15c2cb2306..6003c664ba0b 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -263,8 +263,6 @@ static int sti_bind(struct device *dev)  	if (IS_ERR(ddev))  		return PTR_ERR(ddev); -	ddev->platformdev = to_platform_device(dev); -  	ret = sti_init(ddev);  	if (ret)  		goto err_drm_dev_unref; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 81d80a2ffeb1..5b4ed0ea7768 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -245,7 +245,6 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)  	if (IS_ERR(ddev))  		return PTR_ERR(ddev); -	ddev->platformdev = pdev;  	ddev->dev_private = priv;  	platform_set_drvdata(pdev, ddev);  	drm_mode_config_init(ddev); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index d59f68936306..93900a83dced 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -178,9 +178,7 @@ struct virtio_gpu_device {  	struct virtio_gpu_queue ctrlq;  	struct virtio_gpu_queue cursorq; -	struct list_head free_vbufs; -	spinlock_t free_vbufs_lock; -	void *vbufs; +	struct kmem_cache *vbufs;  	bool vqs_ready;  	struct idr	resource_idr; diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 43ea0dc957d2..472e34986a44 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -74,51 +74,19 @@ void virtio_gpu_cursor_ack(struct virtqueue *vq)  int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev)  { -	struct virtio_gpu_vbuffer *vbuf; -	int i, size, count = 16; -	void *ptr; - -	INIT_LIST_HEAD(&vgdev->free_vbufs); -	spin_lock_init(&vgdev->free_vbufs_lock); -	count += virtqueue_get_vring_size(vgdev->ctrlq.vq); -	count += virtqueue_get_vring_size(vgdev->cursorq.vq); -	size = count * VBUFFER_SIZE; -	DRM_INFO("virtio vbuffers: %d bufs, %zdB each, %dkB total.\n", -		 count, VBUFFER_SIZE, size / 1024); - -	vgdev->vbufs = kzalloc(size, GFP_KERNEL); +	vgdev->vbufs = kmem_cache_create("virtio-gpu-vbufs", +					 VBUFFER_SIZE, +					 __alignof__(struct virtio_gpu_vbuffer), +					 0, NULL);  	if (!vgdev->vbufs)  		return -ENOMEM; - -	for (i = 0, ptr = vgdev->vbufs; -	     i < count; -	     i++, ptr += VBUFFER_SIZE) { -		vbuf = ptr; -		list_add(&vbuf->list, &vgdev->free_vbufs); -	}  	return 0;  }  void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev)  { -	struct virtio_gpu_vbuffer *vbuf; -	int i, count = 0; - -	count += virtqueue_get_vring_size(vgdev->ctrlq.vq); -	count += virtqueue_get_vring_size(vgdev->cursorq.vq); - -	spin_lock(&vgdev->free_vbufs_lock); -	for (i = 0; i < count; i++) { -		if (WARN_ON(list_empty(&vgdev->free_vbufs))) { -			spin_unlock(&vgdev->free_vbufs_lock); -			return; -		} -		vbuf = list_first_entry(&vgdev->free_vbufs, -					struct virtio_gpu_vbuffer, list); -		list_del(&vbuf->list); -	} -	spin_unlock(&vgdev->free_vbufs_lock); -	kfree(vgdev->vbufs); +	kmem_cache_destroy(vgdev->vbufs); +	vgdev->vbufs = NULL;  }  static struct virtio_gpu_vbuffer* @@ -128,12 +96,9 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,  {  	struct virtio_gpu_vbuffer *vbuf; -	spin_lock(&vgdev->free_vbufs_lock); -	BUG_ON(list_empty(&vgdev->free_vbufs)); -	vbuf = list_first_entry(&vgdev->free_vbufs, -				struct virtio_gpu_vbuffer, list); -	list_del(&vbuf->list); -	spin_unlock(&vgdev->free_vbufs_lock); +	vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL); +	if (IS_ERR(vbuf)) +		return ERR_CAST(vbuf);  	memset(vbuf, 0, VBUFFER_SIZE);  	BUG_ON(size > MAX_INLINE_CMD_SIZE); @@ -208,9 +173,7 @@ static void free_vbuf(struct virtio_gpu_device *vgdev,  	if (vbuf->resp_size > MAX_INLINE_RESP_SIZE)  		kfree(vbuf->resp_buf);  	kfree(vbuf->data_buf); -	spin_lock(&vgdev->free_vbufs_lock); -	list_add(&vbuf->list, &vgdev->free_vbufs); -	spin_unlock(&vgdev->free_vbufs_lock); +	kmem_cache_free(vgdev->vbufs, vbuf);  }  static void reclaim_vbufs(struct virtqueue *vq, struct list_head *reclaim_list) diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h index f6f0c062205c..c99d6eaef1ac 100644 --- a/include/drm/bridge/analogix_dp.h +++ b/include/drm/bridge/analogix_dp.h @@ -49,4 +49,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,  		     struct analogix_dp_plat_data *plat_data);  void analogix_dp_unbind(struct device *dev, struct device *master, void *data); +int analogix_dp_start_crc(struct drm_connector *connector); +int analogix_dp_stop_crc(struct drm_connector *connector); +  #endif /* _ANALOGIX_DP_H_ */ diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index b080a171a23f..bcceee8114a4 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -21,12 +21,6 @@ enum {  	DW_HDMI_RES_MAX,  }; -enum dw_hdmi_devtype { -	IMX6Q_HDMI, -	IMX6DL_HDMI, -	RK3288_HDMI, -}; -  enum dw_hdmi_phy_type {  	DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,  	DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2, @@ -57,13 +51,30 @@ struct dw_hdmi_phy_config {  	u16 vlev_ctr;   /* voltage level control */  }; +struct dw_hdmi_phy_ops { +	int (*init)(struct dw_hdmi *hdmi, void *data, +		    struct drm_display_mode *mode); +	void (*disable)(struct dw_hdmi *hdmi, void *data); +	enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); +}; +  struct dw_hdmi_plat_data { -	enum dw_hdmi_devtype dev_type; +	struct regmap *regm; +	enum drm_mode_status (*mode_valid)(struct drm_connector *connector, +					   struct drm_display_mode *mode); + +	/* Vendor PHY support */ +	const struct dw_hdmi_phy_ops *phy_ops; +	const char *phy_name; +	void *phy_data; + +	/* Synopsys PHY support */  	const struct dw_hdmi_mpll_config *mpll_cfg;  	const struct dw_hdmi_curr_ctrl *cur_ctr;  	const struct dw_hdmi_phy_config *phy_config; -	enum drm_mode_status (*mode_valid)(struct drm_connector *connector, -					   struct drm_display_mode *mode); +	int (*configure_phy)(struct dw_hdmi *hdmi, +			     const struct dw_hdmi_plat_data *pdata, +			     unsigned long mpixelclock);  };  int dw_hdmi_probe(struct platform_device *pdev, @@ -77,4 +88,8 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);  void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);  void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); +/* PHY configuration */ +void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data, +			   unsigned char addr); +  #endif /* __IMX_HDMI_H__ */ diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 6105c050d7bc..0e383438f793 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -47,17 +47,16 @@  #include <linux/miscdevice.h>  #include <linux/mm.h>  #include <linux/mutex.h> -#include <linux/pci.h>  #include <linux/platform_device.h>  #include <linux/poll.h>  #include <linux/ratelimit.h> -#include <linux/rbtree.h>  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/types.h>  #include <linux/vmalloc.h>  #include <linux/workqueue.h>  #include <linux/dma-fence.h> +#include <linux/module.h>  #include <asm/mman.h>  #include <asm/pgalloc.h> @@ -75,26 +74,30 @@  #include <drm/drm_mm.h>  #include <drm/drm_os_linux.h>  #include <drm/drm_sarea.h> -#include <drm/drm_vma_manager.h>  #include <drm/drm_drv.h> +#include <drm/drm_prime.h> +#include <drm/drm_pci.h> +#include <drm/drm_file.h>  struct module; -struct drm_file;  struct drm_device;  struct drm_agp_head;  struct drm_local_map;  struct drm_device_dma; -struct drm_dma_handle;  struct drm_gem_object;  struct drm_master;  struct drm_vblank_crtc; +struct drm_vma_offset_manager;  struct device_node;  struct videomode;  struct reservation_object;  struct dma_buf_attachment; +struct pci_dev; +struct pci_controller; +  /*   * The following categories are defined:   * @@ -357,97 +360,6 @@ struct drm_ioctl_desc {  		.name = #ioctl						\  	 } -/* Event queued up for userspace to read */ -struct drm_pending_event { -	struct completion *completion; -	void (*completion_release)(struct completion *completion); -	struct drm_event *event; -	struct dma_fence *fence; -	struct list_head link; -	struct list_head pending_link; -	struct drm_file *file_priv; -	pid_t pid; /* pid of requester, no guarantee it's valid by the time -		      we deliver the event, for tracing only */ -}; - -struct drm_prime_file_private { -	struct mutex lock; -	struct rb_root dmabufs; -	struct rb_root handles; -}; - -/** File private data */ -struct drm_file { -	unsigned authenticated :1; -	/* true when the client has asked us to expose stereo 3D mode flags */ -	unsigned stereo_allowed :1; -	/* -	 * true if client understands CRTC primary planes and cursor planes -	 * in the plane list -	 */ -	unsigned universal_planes:1; -	/* true if client understands atomic properties */ -	unsigned atomic:1; -	/* -	 * This client is the creator of @master. -	 * Protected by struct drm_device::master_mutex. -	 */ -	unsigned is_master:1; - -	struct pid *pid; -	drm_magic_t magic; -	struct list_head lhead; -	struct drm_minor *minor; -	unsigned long lock_count; - -	/** Mapping of mm object handles to object pointers. */ -	struct idr object_idr; -	/** Lock for synchronization of access to object_idr. */ -	spinlock_t table_lock; - -	struct file *filp; -	void *driver_priv; - -	struct drm_master *master; /* master this node is currently associated with -				      N.B. not always dev->master */ -	/** -	 * fbs - List of framebuffers associated with this file. -	 * -	 * Protected by fbs_lock. Note that the fbs list holds a reference on -	 * the fb object to prevent it from untimely disappearing. -	 */ -	struct list_head fbs; -	struct mutex fbs_lock; - -	/** User-created blob properties; this retains a reference on the -	 *  property. */ -	struct list_head blobs; - -	wait_queue_head_t event_wait; -	struct list_head pending_event_list; -	struct list_head event_list; -	int event_space; - -	struct mutex event_read_lock; - -	struct drm_prime_file_private prime; -}; - -/** - * Lock data. - */ -struct drm_lock_data { -	struct drm_hw_lock *hw_lock;	/**< Hardware lock */ -	/** Private of lock holder's file (NULL=kernel) */ -	struct drm_file *file_priv; -	wait_queue_head_t lock_queue;	/**< Queue of blocked processes */ -	unsigned long lock_time;	/**< Time of last lock in jiffies */ -	spinlock_t spinlock; -	uint32_t kernel_waiters; -	uint32_t user_waiters; -	int idle_has_lock; -}; -  /* Flags and return codes for get_vblank_timestamp() driver function. */  #define DRM_CALLED_FROM_VBLIRQ 1  #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) @@ -458,13 +370,6 @@ struct drm_lock_data {  #define DRM_SCANOUTPOS_IN_VBLANK    (1 << 1)  #define DRM_SCANOUTPOS_ACCURATE     (1 << 2) -enum drm_minor_type { -	DRM_MINOR_PRIMARY, -	DRM_MINOR_CONTROL, -	DRM_MINOR_RENDER, -	DRM_MINOR_CNT, -}; -  /**   * Info file list entry. This structure represents a debugfs or proc file to   * be created by the drm core @@ -487,21 +392,6 @@ struct drm_info_node {  };  /** - * DRM minor structure. This structure represents a drm minor number. - */ -struct drm_minor { -	int index;			/**< Minor device number */ -	int type;                       /**< Control or render */ -	struct device *kdev;		/**< Linux device */ -	struct drm_device *dev; - -	struct dentry *debugfs_root; - -	struct list_head debugfs_list; -	struct mutex debugfs_lock; /* Protects debugfs_list. */ -}; - -/**   * DRM device structure. This structure represent a complete card that   * may contain multiple heads.   */ @@ -611,7 +501,6 @@ struct drm_device {  	struct pci_controller *hose;  #endif -	struct platform_device *platformdev; /**< Platform device struture */  	struct virtio_device *virtdev;  	struct drm_sg_mem *sg;	/**< Scatter gather memory */ @@ -675,21 +564,6 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)  	return ret;  } -static inline bool drm_is_render_client(const struct drm_file *file_priv) -{ -	return file_priv->minor->type == DRM_MINOR_RENDER; -} - -static inline bool drm_is_control_client(const struct drm_file *file_priv) -{ -	return file_priv->minor->type == DRM_MINOR_CONTROL; -} - -static inline bool drm_is_primary_client(const struct drm_file *file_priv) -{ -	return file_priv->minor->type == DRM_MINOR_PRIMARY; -} -  /******************************************************************/  /** \name Internal function definitions */  /*@{*/ @@ -707,25 +581,6 @@ extern long drm_compat_ioctl(struct file *filp,  #endif  extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); -/* File Operations (drm_fops.c) */ -int drm_open(struct inode *inode, struct file *filp); -ssize_t drm_read(struct file *filp, char __user *buffer, -		 size_t count, loff_t *offset); -int drm_release(struct inode *inode, struct file *filp); -unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); -int drm_event_reserve_init_locked(struct drm_device *dev, -				  struct drm_file *file_priv, -				  struct drm_pending_event *p, -				  struct drm_event *e); -int drm_event_reserve_init(struct drm_device *dev, -			   struct drm_file *file_priv, -			   struct drm_pending_event *p, -			   struct drm_event *e); -void drm_event_cancel_free(struct drm_device *dev, -			   struct drm_pending_event *p); -void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e); -void drm_send_event(struct drm_device *dev, struct drm_pending_event *e); -  /* Misc. IOCTL support (drm_ioctl.c) */  int drm_noop(struct drm_device *dev, void *data,  	     struct drm_file *file_priv); @@ -759,70 +614,12 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,  }  #endif -struct dma_buf_export_info; - -extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev, -					    struct drm_gem_object *obj, -					    int flags); -extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, -		struct drm_file *file_priv, uint32_t handle, uint32_t flags, -		int *prime_fd); -extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, -		struct dma_buf *dma_buf); -extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, -		struct drm_file *file_priv, int prime_fd, uint32_t *handle); -struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, -				      struct dma_buf_export_info *exp_info); -extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf); - -extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, -					    dma_addr_t *addrs, int max_pages); -extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); -extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); - - -extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, -					    size_t align); -extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); -  			       /* sysfs support (drm_sysfs.c) */  extern void drm_sysfs_hotplug_event(struct drm_device *dev);  /*@}*/ -extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); -extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); -#ifdef CONFIG_PCI -extern int drm_get_pci_dev(struct pci_dev *pdev, -			   const struct pci_device_id *ent, -			   struct drm_driver *driver); -extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); -#else -static inline int drm_get_pci_dev(struct pci_dev *pdev, -				  const struct pci_device_id *ent, -				  struct drm_driver *driver) -{ -	return -ENOSYS; -} - -static inline int drm_pci_set_busid(struct drm_device *dev, -				    struct drm_master *master) -{ -	return -ENOSYS; -} -#endif - -#define DRM_PCIE_SPEED_25 1 -#define DRM_PCIE_SPEED_50 2 -#define DRM_PCIE_SPEED_80 4 - -extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); -extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); - -/* platform section */ -extern int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device); -  /* returns true if currently okay to sleep */  static __inline__ bool drm_can_sleep(void)  { diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index c6f355a970d2..0147a047878d 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -277,6 +277,9 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,   *   * This function returns the crtc state for the given crtc, or NULL   * if the crtc is not part of the global atomic state. + * + * This function is deprecated, @drm_atomic_get_old_crtc_state or + * @drm_atomic_get_new_crtc_state should be used instead.   */  static inline struct drm_crtc_state *  drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state, @@ -286,12 +289,44 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,  }  /** + * drm_atomic_get_old_crtc_state - get old crtc state, if it exists + * @state: global atomic state object + * @crtc: crtc to grab + * + * This function returns the old crtc state for the given crtc, or + * NULL if the crtc is not part of the global atomic state. + */ +static inline struct drm_crtc_state * +drm_atomic_get_old_crtc_state(struct drm_atomic_state *state, +			      struct drm_crtc *crtc) +{ +	return state->crtcs[drm_crtc_index(crtc)].old_state; +} +/** + * drm_atomic_get_new_crtc_state - get new crtc state, if it exists + * @state: global atomic state object + * @crtc: crtc to grab + * + * This function returns the new crtc state for the given crtc, or + * NULL if the crtc is not part of the global atomic state. + */ +static inline struct drm_crtc_state * +drm_atomic_get_new_crtc_state(struct drm_atomic_state *state, +			      struct drm_crtc *crtc) +{ +	return state->crtcs[drm_crtc_index(crtc)].new_state; +} + +/**   * drm_atomic_get_existing_plane_state - get plane state, if it exists   * @state: global atomic state object   * @plane: plane to grab   *   * This function returns the plane state for the given plane, or NULL   * if the plane is not part of the global atomic state. + * + * This function is deprecated, @drm_atomic_get_old_plane_state or + * @drm_atomic_get_new_plane_state should be used instead.   */  static inline struct drm_plane_state *  drm_atomic_get_existing_plane_state(struct drm_atomic_state *state, @@ -301,12 +336,45 @@ drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,  }  /** + * drm_atomic_get_old_plane_state - get plane state, if it exists + * @state: global atomic state object + * @plane: plane to grab + * + * This function returns the old plane state for the given plane, or + * NULL if the plane is not part of the global atomic state. + */ +static inline struct drm_plane_state * +drm_atomic_get_old_plane_state(struct drm_atomic_state *state, +			       struct drm_plane *plane) +{ +	return state->planes[drm_plane_index(plane)].old_state; +} + +/** + * drm_atomic_get_new_plane_state - get plane state, if it exists + * @state: global atomic state object + * @plane: plane to grab + * + * This function returns the new plane state for the given plane, or + * NULL if the plane is not part of the global atomic state. + */ +static inline struct drm_plane_state * +drm_atomic_get_new_plane_state(struct drm_atomic_state *state, +			       struct drm_plane *plane) +{ +	return state->planes[drm_plane_index(plane)].new_state; +} + +/**   * drm_atomic_get_existing_connector_state - get connector state, if it exists   * @state: global atomic state object   * @connector: connector to grab   *   * This function returns the connector state for the given connector,   * or NULL if the connector is not part of the global atomic state. + * + * This function is deprecated, @drm_atomic_get_old_connector_state or + * @drm_atomic_get_new_connector_state should be used instead.   */  static inline struct drm_connector_state *  drm_atomic_get_existing_connector_state(struct drm_atomic_state *state, @@ -321,6 +389,46 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,  }  /** + * drm_atomic_get_old_connector_state - get connector state, if it exists + * @state: global atomic state object + * @connector: connector to grab + * + * This function returns the old connector state for the given connector, + * or NULL if the connector is not part of the global atomic state. + */ +static inline struct drm_connector_state * +drm_atomic_get_old_connector_state(struct drm_atomic_state *state, +				   struct drm_connector *connector) +{ +	int index = drm_connector_index(connector); + +	if (index >= state->num_connector) +		return NULL; + +	return state->connectors[index].old_state; +} + +/** + * drm_atomic_get_new_connector_state - get connector state, if it exists + * @state: global atomic state object + * @connector: connector to grab + * + * This function returns the new connector state for the given connector, + * or NULL if the connector is not part of the global atomic state. + */ +static inline struct drm_connector_state * +drm_atomic_get_new_connector_state(struct drm_atomic_state *state, +				   struct drm_connector *connector) +{ +	int index = drm_connector_index(connector); + +	if (index >= state->num_connector) +		return NULL; + +	return state->connectors[index].new_state; +} + +/**   * __drm_atomic_get_current_plane_state - get current plane state   * @state: global atomic state object   * @plane: plane to grab diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 9ceda379ce58..dc16274987c7 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -220,10 +220,10 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,  			      __drm_atomic_get_current_plane_state((crtc_state)->state, \  								   plane))) -/* +/**   * drm_atomic_plane_disabling - check whether a plane is being disabled - * @plane: plane object - * @old_state: previous atomic state + * @old_plane_state: old atomic plane state + * @new_plane_state: new atomic plane state   *   * Checks the atomic state of a plane to determine whether it's being disabled   * or not. This also WARNs if it detects an invalid state (both CRTC and FB @@ -233,28 +233,18 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,   * True if the plane is being disabled, false otherwise.   */  static inline bool -drm_atomic_plane_disabling(struct drm_plane *plane, -			   struct drm_plane_state *old_state) +drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state, +			   struct drm_plane_state *new_plane_state)  {  	/*  	 * When disabling a plane, CRTC and FB should always be NULL together.  	 * Anything else should be considered a bug in the atomic core, so we  	 * gently warn about it.  	 */ -	WARN_ON((plane->state->crtc == NULL && plane->state->fb != NULL) || -		(plane->state->crtc != NULL && plane->state->fb == NULL)); +	WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) || +		(new_plane_state->crtc != NULL && new_plane_state->fb == NULL)); -	/* -	 * When using the transitional helpers, old_state may be NULL. If so, -	 * we know nothing about the current state and have to assume that it -	 * might be enabled. -	 * -	 * When using the atomic helpers, old_state won't be NULL. Therefore -	 * this check assumes that either the driver will have reconstructed -	 * the correct state in ->reset() or that the driver will have taken -	 * appropriate measures to disable all planes. -	 */ -	return (!old_state || old_state->crtc) && !plane->state->crtc; +	return old_plane_state->crtc && !new_plane_state->crtc;  }  #endif /* DRM_ATOMIC_HELPER_H_ */ diff --git a/include/drm/drm_auth.h b/include/drm/drm_auth.h index 1eb4a52cad8d..81a40c2a9a3e 100644 --- a/include/drm/drm_auth.h +++ b/include/drm/drm_auth.h @@ -28,6 +28,23 @@  #ifndef _DRM_AUTH_H_  #define _DRM_AUTH_H_ +/* + * Legacy DRI1 locking data structure. Only here instead of in drm_legacy.h for + * include ordering reasons. + * + * DO NOT USE. + */ +struct drm_lock_data { +	struct drm_hw_lock *hw_lock; +	struct drm_file *file_priv; +	wait_queue_head_t lock_queue; +	unsigned long lock_time; +	spinlock_t spinlock; +	uint32_t kernel_waiters; +	uint32_t user_waiters; +	int idle_has_lock; +}; +  /**   * struct drm_master - drm master structure   * diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index bda9347554a1..6ef59da3fd8e 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -204,6 +204,12 @@ struct drm_crtc_state {  	 * drm_crtc_arm_vblank_event(). See the documentation of that function  	 * for a detailed discussion of the constraints it needs to be used  	 * safely. +	 * +	 * If the device can't notify of flip completion in a race-free way +	 * at all, then the event should be armed just after the page flip is +	 * committed. In the worst case the driver will send the event to +	 * userspace one frame too late. This doesn't allow for a real atomic +	 * update, but it should avoid tearing.  	 */  	struct drm_pending_vblank_event *event; @@ -776,6 +782,7 @@ struct drm_crtc {  	 * Debugfs directory for this CRTC.  	 */  	struct dentry *debugfs_entry; +#endif  	/**  	 * @crc: @@ -783,7 +790,6 @@ struct drm_crtc {  	 * Configuration settings of CRC capture.  	 */  	struct drm_crtc_crc crc; -#endif  	/**  	 * @fence_context: diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index ba89295c8651..c0bd0d7651a9 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -789,7 +789,10 @@ struct drm_dp_aux_msg {   * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter   * @ddc: I2C adapter that can be used for I2C-over-AUX communication   * @dev: pointer to struct device that is the parent for this AUX channel + * @crtc: backpointer to the crtc that is currently using this AUX channel   * @hw_mutex: internal mutex used for locking transfers + * @crc_work: worker that captures CRCs for each frame + * @crc_count: counter of captured frame CRCs   * @transfer: transfers a message representing a single AUX transaction   *   * The .dev field should be set to a pointer to the device that implements @@ -825,7 +828,10 @@ struct drm_dp_aux {  	const char *name;  	struct i2c_adapter ddc;  	struct device *dev; +	struct drm_crtc *crtc;  	struct mutex hw_mutex; +	struct work_struct crc_work; +	u8 crc_count;  	ssize_t (*transfer)(struct drm_dp_aux *aux,  			    struct drm_dp_aux_msg *msg);  	/** @@ -904,4 +910,7 @@ void drm_dp_aux_init(struct drm_dp_aux *aux);  int drm_dp_aux_register(struct drm_dp_aux *aux);  void drm_dp_aux_unregister(struct drm_dp_aux *aux); +int drm_dp_start_crc(struct drm_dp_aux *aux, struct drm_crtc *crtc); +int drm_dp_stop_crc(struct drm_dp_aux *aux); +  #endif /* _DRM_DP_HELPER_H_ */ diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 4e66fbb56773..4321d012c4ba 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -302,7 +302,6 @@ struct drm_driver {  	void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);  	int (*debugfs_init)(struct drm_minor *minor); -	void (*debugfs_cleanup)(struct drm_minor *minor);  	/**  	 * @gem_free_object: deconstructor for drm_gem_objects diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h new file mode 100644 index 000000000000..d1a25cc17fd1 --- /dev/null +++ b/include/drm/drm_file.h @@ -0,0 +1,172 @@ +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * + * Author: Rickard E. (Rik) Faith <faith@valinux.com> + * Author: Gareth Hughes <gareth@valinux.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DRM_FILE_H_ +#define _DRM_FILE_H_ + +#include <linux/types.h> +#include <linux/completion.h> + +#include <uapi/drm/drm.h> + +#include <drm/drm_prime.h> + +struct dma_fence; +struct drm_file; +struct drm_device; + +/* + * FIXME: Not sure we want to have drm_minor here in the end, but to avoid + * header include loops we need it here for now. + */ +enum drm_minor_type { +	DRM_MINOR_PRIMARY, +	DRM_MINOR_CONTROL, +	DRM_MINOR_RENDER, +}; + +/** + * DRM minor structure. This structure represents a drm minor number. + */ +struct drm_minor { +	int index;			/**< Minor device number */ +	int type;                       /**< Control or render */ +	struct device *kdev;		/**< Linux device */ +	struct drm_device *dev; + +	struct dentry *debugfs_root; + +	struct list_head debugfs_list; +	struct mutex debugfs_lock; /* Protects debugfs_list. */ +}; + +/* Event queued up for userspace to read */ +struct drm_pending_event { +	struct completion *completion; +	void (*completion_release)(struct completion *completion); +	struct drm_event *event; +	struct dma_fence *fence; +	struct list_head link; +	struct list_head pending_link; +	struct drm_file *file_priv; +	pid_t pid; /* pid of requester, no guarantee it's valid by the time +		      we deliver the event, for tracing only */ +}; + +/** File private data */ +struct drm_file { +	unsigned authenticated :1; +	/* true when the client has asked us to expose stereo 3D mode flags */ +	unsigned stereo_allowed :1; +	/* +	 * true if client understands CRTC primary planes and cursor planes +	 * in the plane list +	 */ +	unsigned universal_planes:1; +	/* true if client understands atomic properties */ +	unsigned atomic:1; +	/* +	 * This client is the creator of @master. +	 * Protected by struct drm_device::master_mutex. +	 */ +	unsigned is_master:1; + +	struct pid *pid; +	drm_magic_t magic; +	struct list_head lhead; +	struct drm_minor *minor; +	unsigned long lock_count; + +	/** Mapping of mm object handles to object pointers. */ +	struct idr object_idr; +	/** Lock for synchronization of access to object_idr. */ +	spinlock_t table_lock; + +	struct file *filp; +	void *driver_priv; + +	struct drm_master *master; /* master this node is currently associated with +				      N.B. not always dev->master */ +	/** +	 * fbs - List of framebuffers associated with this file. +	 * +	 * Protected by fbs_lock. Note that the fbs list holds a reference on +	 * the fb object to prevent it from untimely disappearing. +	 */ +	struct list_head fbs; +	struct mutex fbs_lock; + +	/** User-created blob properties; this retains a reference on the +	 *  property. */ +	struct list_head blobs; + +	wait_queue_head_t event_wait; +	struct list_head pending_event_list; +	struct list_head event_list; +	int event_space; + +	struct mutex event_read_lock; + +	struct drm_prime_file_private prime; +}; + +static inline bool drm_is_render_client(const struct drm_file *file_priv) +{ +	return file_priv->minor->type == DRM_MINOR_RENDER; +} + +static inline bool drm_is_control_client(const struct drm_file *file_priv) +{ +	return file_priv->minor->type == DRM_MINOR_CONTROL; +} + +static inline bool drm_is_primary_client(const struct drm_file *file_priv) +{ +	return file_priv->minor->type == DRM_MINOR_PRIMARY; +} + +int drm_open(struct inode *inode, struct file *filp); +ssize_t drm_read(struct file *filp, char __user *buffer, +		 size_t count, loff_t *offset); +int drm_release(struct inode *inode, struct file *filp); +unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); +int drm_event_reserve_init_locked(struct drm_device *dev, +				  struct drm_file *file_priv, +				  struct drm_pending_event *p, +				  struct drm_event *e); +int drm_event_reserve_init(struct drm_device *dev, +			   struct drm_file *file_priv, +			   struct drm_pending_event *p, +			   struct drm_event *e); +void drm_event_cancel_free(struct drm_device *dev, +			   struct drm_pending_event *p); +void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e); +void drm_send_event(struct drm_device *dev, struct drm_pending_event *e); + +#endif /* _DRM_FILE_H_ */ diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 3b2a28f7f49f..b9ade75ecd82 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -34,6 +34,10 @@   * OTHER DEALINGS IN THE SOFTWARE.   */ +#include <linux/kref.h> + +#include <drm/drm_vma_manager.h> +  /**   * struct drm_gem_object - GEM buffer object   * diff --git a/include/drm/drm_pci.h b/include/drm/drm_pci.h new file mode 100644 index 000000000000..f5ebfcaf69e0 --- /dev/null +++ b/include/drm/drm_pci.h @@ -0,0 +1,75 @@ +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * + * Author: Rickard E. (Rik) Faith <faith@valinux.com> + * Author: Gareth Hughes <gareth@valinux.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DRM_PCI_H_ +#define _DRM_PCI_H_ + +#include <linux/pci.h> + +struct drm_dma_handle; +struct drm_device; +struct drm_driver; +struct drm_master; + +extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, +					    size_t align); +extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); + +extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); +extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); +#ifdef CONFIG_PCI +extern int drm_get_pci_dev(struct pci_dev *pdev, +			   const struct pci_device_id *ent, +			   struct drm_driver *driver); +extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); +#else +static inline int drm_get_pci_dev(struct pci_dev *pdev, +				  const struct pci_device_id *ent, +				  struct drm_driver *driver) +{ +	return -ENOSYS; +} + +static inline int drm_pci_set_busid(struct drm_device *dev, +				    struct drm_master *master) +{ +	return -ENOSYS; +} +#endif + +#define DRM_PCIE_SPEED_25 1 +#define DRM_PCIE_SPEED_50 2 +#define DRM_PCIE_SPEED_80 4 + +extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); +extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); + +#endif /* _DRM_PCI_H_ */ diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h new file mode 100644 index 000000000000..d09563ecc4b7 --- /dev/null +++ b/include/drm/drm_prime.h @@ -0,0 +1,80 @@ +/* + * Copyright © 2012 Red Hat + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + *      Dave Airlie <airlied@redhat.com> + *      Rob Clark <rob.clark@linaro.org> + * + */ + +#ifndef __DRM_PRIME_H__ +#define __DRM_PRIME_H__ + +#include <linux/mutex.h> +#include <linux/rbtree.h> +#include <linux/scatterlist.h> + +/** + * struct drm_prime_file_private - per-file tracking for PRIME + * + * This just contains the internal &struct dma_buf and handle caches for each + * &struct drm_file used by the PRIME core code. + */ + +struct drm_prime_file_private { +/* private: */ +	struct mutex lock; +	struct rb_root dmabufs; +	struct rb_root handles; +}; + +struct dma_buf_export_info; +struct dma_buf; + +struct drm_device; +struct drm_gem_object; +struct drm_file; + +extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev, +					    struct drm_gem_object *obj, +					    int flags); +extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, +		struct drm_file *file_priv, uint32_t handle, uint32_t flags, +		int *prime_fd); +extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, +		struct dma_buf *dma_buf); +extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, +		struct drm_file *file_priv, int prime_fd, uint32_t *handle); +struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, +				      struct dma_buf_export_info *exp_info); +extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf); + +extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, +					    dma_addr_t *addrs, int max_pages); +extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); +extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); + + +#endif /* __DRM_PRIME_H__ */ diff --git a/include/drm/drm_vma_manager.h b/include/drm/drm_vma_manager.h index 9c03895dc479..d84d52f6d2b1 100644 --- a/include/drm/drm_vma_manager.h +++ b/include/drm/drm_vma_manager.h @@ -25,7 +25,6 @@  #include <drm/drm_mm.h>  #include <linux/mm.h> -#include <linux/module.h>  #include <linux/rbtree.h>  #include <linux/spinlock.h>  #include <linux/types.h> | 
