mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Merge tag 'drm-misc-next-2017-03-12' of git://anongit.freedesktop.org/git/drm-misc into drm-next
More drm-misc stuff for 4.12: - drm_platform removal from Laurent - more dw-hdmi bridge driver updates (Laurent, Kieran, Neil) - more header cleanup and documentation - more drm_debugs_remove_files removal (Noralf) - minor qxl updates (Gerd) - edp crc support in helper + analogix_dp (Tomeu) for more igt testing! - old/new iterator roll-out (Maarten) - new bridge drivers: lvds (Laurent), megachips-something (Peter Senna) * tag 'drm-misc-next-2017-03-12' of git://anongit.freedesktop.org/git/drm-misc: (51 commits) drm: bridge: dw-hdmi: Move the driver to a separate directory. drm: bridge: dw-hdmi: Switch to regmap for register access drm: bridge: dw-hdmi: Remove device type from platform data drm: bridge: dw-hdmi: Add support for custom PHY configuration drm: bridge: dw-hdmi: Create PHY operations drm: bridge: dw-hdmi: Fix the PHY power up sequence drm: bridge: dw-hdmi: Fix the PHY power down sequence drm: bridge: dw-hdmi: Enable CSC even for DVI drm: bridge: dw-hdmi: Move CSC configuration out of PHY code drm: bridge: dw-hdmi: Remove unused functions drm: Extract drm_file.h drm: Remove DRM_MINOR_CNT drm: rename drm_fops.c to drm_file.c drm/doc: document fallback behaviour for atomic events drm: Remove drmP.h include from drm_kms_helper_common.c drm: Extract drm_pci.h drm: Move drm_lock_data out of drmP.h drm: Extract drm_prime.h drm/doc: Add todo about connector_list_iter drm/qxl: Remove qxl_debugfs_remove_files() ...
This commit is contained in:
		
						commit
						9c233760a6
					
				
					 81 changed files with 2445 additions and 1189 deletions
				
			
		| 
						 | 
					@ -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>;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -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 */
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -178,6 +178,7 @@ maxim	Maxim Integrated Products
 | 
				
			||||||
mcube	mCube
 | 
					mcube	mCube
 | 
				
			||||||
meas	Measurement Specialties
 | 
					meas	Measurement Specialties
 | 
				
			||||||
mediatek	MediaTek Inc.
 | 
					mediatek	MediaTek Inc.
 | 
				
			||||||
 | 
					megachips	MegaChips
 | 
				
			||||||
melexis	Melexis N.V.
 | 
					melexis	Melexis N.V.
 | 
				
			||||||
melfas	MELFAS Inc.
 | 
					melfas	MELFAS Inc.
 | 
				
			||||||
memsic	MEMSIC Inc.
 | 
					memsic	MEMSIC Inc.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,9 +240,6 @@ drivers.
 | 
				
			||||||
.. kernel-doc:: drivers/gpu/drm/drm_pci.c
 | 
					.. kernel-doc:: drivers/gpu/drm/drm_pci.c
 | 
				
			||||||
   :export:
 | 
					   :export:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. kernel-doc:: drivers/gpu/drm/drm_platform.c
 | 
					 | 
				
			||||||
   :export:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Open/Close, File Operations and IOCTLs
 | 
					Open/Close, File Operations and IOCTLs
 | 
				
			||||||
======================================
 | 
					======================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,10 +295,10 @@ over.
 | 
				
			||||||
File Operations
 | 
					File Operations
 | 
				
			||||||
---------------
 | 
					---------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. kernel-doc:: drivers/gpu/drm/drm_fops.c
 | 
					.. kernel-doc:: drivers/gpu/drm/drm_file.c
 | 
				
			||||||
   :doc: file operations
 | 
					   :doc: file operations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. kernel-doc:: drivers/gpu/drm/drm_fops.c
 | 
					.. kernel-doc:: drivers/gpu/drm/drm_file.c
 | 
				
			||||||
   :export:
 | 
					   :export:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
IOCTLs
 | 
					IOCTLs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -449,6 +449,9 @@ PRIME Helper Functions
 | 
				
			||||||
PRIME Function References
 | 
					PRIME Function References
 | 
				
			||||||
-------------------------
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. kernel-doc:: include/drm/drm_prime.h
 | 
				
			||||||
 | 
					   :internal:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. kernel-doc:: drivers/gpu/drm/drm_prime.c
 | 
					.. kernel-doc:: drivers/gpu/drm/drm_prime.c
 | 
				
			||||||
   :export:
 | 
					   :export:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,6 +153,19 @@ following drivers still use ``struct_mutex``: ``msm``, ``omapdrm`` and
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Contact: Daniel Vetter
 | 
					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
 | 
					Core refactorings
 | 
				
			||||||
=================
 | 
					=================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8123,6 +8123,14 @@ L:	linux-wireless@vger.kernel.org
 | 
				
			||||||
S:	Maintained
 | 
					S:	Maintained
 | 
				
			||||||
F:	drivers/net/wireless/mediatek/mt7601u/
 | 
					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
 | 
					MEGARAID SCSI/SAS DRIVERS
 | 
				
			||||||
M:	Kashyap Desai <kashyap.desai@broadcom.com>
 | 
					M:	Kashyap Desai <kashyap.desai@broadcom.com>
 | 
				
			||||||
M:	Sumit Saxena <sumit.saxena@broadcom.com>
 | 
					M:	Sumit Saxena <sumit.saxena@broadcom.com>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 | 
					drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 | 
				
			||||||
		drm_context.o drm_dma.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_lock.o drm_memory.o drm_drv.o \
 | 
				
			||||||
		drm_scatter.o drm_pci.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_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
 | 
				
			||||||
		drm_info.o drm_encoder_slave.o \
 | 
							drm_info.o drm_encoder_slave.o \
 | 
				
			||||||
		drm_trace_points.o drm_global.o drm_prime.o \
 | 
							drm_trace_points.o drm_global.o drm_prime.o \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,10 +137,9 @@ static int armada_drm_bind(struct device *dev)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv->drm.platformdev = to_platform_device(dev);
 | 
					 | 
				
			||||||
	priv->drm.dev_private = priv;
 | 
						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_WORK(&priv->fb_unref_work, armada_drm_unref_work);
 | 
				
			||||||
	INIT_KFIFO(priv->fb_unref);
 | 
						INIT_KFIFO(priv->fb_unref);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,29 +24,25 @@ config DRM_DUMB_VGA_DAC
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Support for RGB to VGA DAC based bridges
 | 
						  Support for RGB to VGA DAC based bridges
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config DRM_DW_HDMI
 | 
					config DRM_LVDS_ENCODER
 | 
				
			||||||
	tristate
 | 
						tristate "Transparent parallel to LVDS encoder support"
 | 
				
			||||||
 | 
						depends on OF
 | 
				
			||||||
	select DRM_KMS_HELPER
 | 
						select DRM_KMS_HELPER
 | 
				
			||||||
 | 
						select DRM_PANEL
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Support the AHB Audio interface which is part of the Synopsis
 | 
						  Support for transparent parallel to LVDS encoders that don't require
 | 
				
			||||||
	  Designware HDMI block.  This is used in conjunction with
 | 
						  any configuration.
 | 
				
			||||||
	  the i.MX6 HDMI driver.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
config DRM_DW_HDMI_I2S_AUDIO
 | 
					config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW
 | 
				
			||||||
	tristate "Synopsis Designware I2S Audio interface"
 | 
						tristate "MegaChips stdp4028-ge-b850v3-fw and stdp2690-ge-b850v3-fw"
 | 
				
			||||||
	depends on SND_SOC
 | 
						depends on OF
 | 
				
			||||||
	depends on DRM_DW_HDMI
 | 
						select DRM_KMS_HELPER
 | 
				
			||||||
	select SND_SOC_HDMI_CODEC
 | 
						select DRM_PANEL
 | 
				
			||||||
	help
 | 
						---help---
 | 
				
			||||||
	  Support the I2S Audio interface which is part of the Synopsis
 | 
					          This is a driver for the display bridges of
 | 
				
			||||||
	  Designware HDMI block.
 | 
					          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
 | 
					config DRM_NXP_PTN3460
 | 
				
			||||||
	tristate "NXP PTN3460 DP/LVDS bridge"
 | 
						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/adv7511/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source "drivers/gpu/drm/bridge/synopsys/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,9 +2,8 @@ ccflags-y := -Iinclude/drm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
 | 
					obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
 | 
				
			||||||
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
 | 
					obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
 | 
				
			||||||
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
 | 
					obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 | 
				
			||||||
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
 | 
					obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 | 
				
			||||||
obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o
 | 
					 | 
				
			||||||
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 | 
					obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
 | 
				
			||||||
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 | 
					obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
 | 
				
			||||||
obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.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_ANALOGIX_DP) += analogix/
 | 
				
			||||||
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
 | 
					obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
 | 
				
			||||||
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
 | 
					obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
 | 
				
			||||||
 | 
					obj-y += synopsys/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1488,6 +1488,28 @@ int analogix_dp_resume(struct device *dev)
 | 
				
			||||||
EXPORT_SYMBOL_GPL(analogix_dp_resume);
 | 
					EXPORT_SYMBOL_GPL(analogix_dp_resume);
 | 
				
			||||||
#endif
 | 
					#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_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
 | 
				
			||||||
MODULE_DESCRIPTION("Analogix DP Core Driver");
 | 
					MODULE_DESCRIPTION("Analogix DP Core Driver");
 | 
				
			||||||
MODULE_LICENSE("GPL v2");
 | 
					MODULE_LICENSE("GPL v2");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,6 +237,7 @@ static int dumb_vga_remove(struct platform_device *pdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct of_device_id dumb_vga_match[] = {
 | 
					static const struct of_device_id dumb_vga_match[] = {
 | 
				
			||||||
	{ .compatible = "dumb-vga-dac" },
 | 
						{ .compatible = "dumb-vga-dac" },
 | 
				
			||||||
 | 
						{ .compatible = "adi,adv7123" },
 | 
				
			||||||
	{ .compatible = "ti,ths8135" },
 | 
						{ .compatible = "ti,ths8135" },
 | 
				
			||||||
	{},
 | 
						{},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										210
									
								
								drivers/gpu/drm/bridge/lvds-encoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								drivers/gpu/drm/bridge/lvds-encoder.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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");
 | 
				
			||||||
							
								
								
									
										428
									
								
								drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										428
									
								
								drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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");
 | 
				
			||||||
							
								
								
									
										23
									
								
								drivers/gpu/drm/bridge/synopsys/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								drivers/gpu/drm/bridge/synopsys/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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.
 | 
				
			||||||
							
								
								
									
										5
									
								
								drivers/gpu/drm/bridge/synopsys/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								drivers/gpu/drm/bridge/synopsys/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
#include <linux/hdmi.h>
 | 
					#include <linux/hdmi.h>
 | 
				
			||||||
#include <linux/mutex.h>
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
#include <linux/of_device.h>
 | 
					#include <linux/of_device.h>
 | 
				
			||||||
 | 
					#include <linux/regmap.h>
 | 
				
			||||||
#include <linux/spinlock.h>
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <drm/drm_of.h>
 | 
					#include <drm/drm_of.h>
 | 
				
			||||||
| 
						 | 
					@ -116,14 +117,17 @@ struct dw_hdmi_i2c {
 | 
				
			||||||
struct dw_hdmi_phy_data {
 | 
					struct dw_hdmi_phy_data {
 | 
				
			||||||
	enum dw_hdmi_phy_type type;
 | 
						enum dw_hdmi_phy_type type;
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
 | 
						unsigned int gen;
 | 
				
			||||||
	bool has_svsret;
 | 
						bool has_svsret;
 | 
				
			||||||
 | 
						int (*configure)(struct dw_hdmi *hdmi,
 | 
				
			||||||
 | 
								 const struct dw_hdmi_plat_data *pdata,
 | 
				
			||||||
 | 
								 unsigned long mpixelclock);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dw_hdmi {
 | 
					struct dw_hdmi {
 | 
				
			||||||
	struct drm_connector connector;
 | 
						struct drm_connector connector;
 | 
				
			||||||
	struct drm_bridge bridge;
 | 
						struct drm_bridge bridge;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enum dw_hdmi_devtype dev_type;
 | 
					 | 
				
			||||||
	unsigned int version;
 | 
						unsigned int version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct platform_device *audio;
 | 
						struct platform_device *audio;
 | 
				
			||||||
| 
						 | 
					@ -140,8 +144,12 @@ struct dw_hdmi {
 | 
				
			||||||
	u8 edid[HDMI_EDID_LEN];
 | 
						u8 edid[HDMI_EDID_LEN];
 | 
				
			||||||
	bool cable_plugin;
 | 
						bool cable_plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const struct dw_hdmi_phy_data *phy;
 | 
						struct {
 | 
				
			||||||
	bool phy_enabled;
 | 
							const struct dw_hdmi_phy_ops *ops;
 | 
				
			||||||
 | 
							const char *name;
 | 
				
			||||||
 | 
							void *data;
 | 
				
			||||||
 | 
							bool enabled;
 | 
				
			||||||
 | 
						} phy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct drm_display_mode previous_mode;
 | 
						struct drm_display_mode previous_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,8 +172,8 @@ struct dw_hdmi {
 | 
				
			||||||
	unsigned int audio_n;
 | 
						unsigned int audio_n;
 | 
				
			||||||
	bool audio_enable;
 | 
						bool audio_enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
 | 
						unsigned int reg_shift;
 | 
				
			||||||
	u8 (*read)(struct dw_hdmi *hdmi, int offset);
 | 
						struct regmap *regm;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HDMI_IH_PHY_STAT0_RX_SENSE \
 | 
					#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_SENSE0 | HDMI_PHY_RX_SENSE1 | \
 | 
				
			||||||
	 HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3)
 | 
						 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)
 | 
					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)
 | 
					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)
 | 
					static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u8 val = hdmi_readb(hdmi, reg) & ~mask;
 | 
						regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	val |= data & mask;
 | 
					 | 
				
			||||||
	hdmi_writeb(hdmi, val, reg);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
 | 
					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);
 | 
							  HDMI_VP_CONF);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* -----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * Synopsys PHY Handling
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
 | 
					static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
 | 
				
			||||||
				       unsigned char bit)
 | 
									       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);
 | 
							  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)
 | 
					static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 val;
 | 
						u32 val;
 | 
				
			||||||
| 
						 | 
					@ -877,7 +844,7 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
 | 
					void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
 | 
				
			||||||
			   unsigned char addr)
 | 
								   unsigned char addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
 | 
						hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
 | 
				
			||||||
| 
						 | 
					@ -890,6 +857,7 @@ static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
 | 
				
			||||||
		    HDMI_PHY_I2CM_OPERATION_ADDR);
 | 
							    HDMI_PHY_I2CM_OPERATION_ADDR);
 | 
				
			||||||
	hdmi_phy_wait_i2c_done(hdmi, 1000);
 | 
						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)
 | 
					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);
 | 
								 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_mpll_config *mpll_config = pdata->mpll_cfg;
 | 
				
			||||||
	const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
 | 
						const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
 | 
				
			||||||
	const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
 | 
						const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* PLL/MPLL Cfg - always match on final entry */
 | 
						/* PLL/MPLL Cfg - always match on final entry */
 | 
				
			||||||
	for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
 | 
						for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
 | 
				
			||||||
		if (hdmi->hdmi_data.video_mode.mpixelclock <=
 | 
							if (mpixelclock <= mpll_config->mpixelclock)
 | 
				
			||||||
		    mpll_config->mpixelclock)
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
 | 
						for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
 | 
				
			||||||
		if (hdmi->hdmi_data.video_mode.mpixelclock <=
 | 
							if (mpixelclock <= curr_ctrl->mpixelclock)
 | 
				
			||||||
		    curr_ctrl->mpixelclock)
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (; phy_config->mpixelclock != ~0UL; phy_config++)
 | 
						for (; phy_config->mpixelclock != ~0UL; phy_config++)
 | 
				
			||||||
		if (hdmi->hdmi_data.video_mode.mpixelclock <=
 | 
							if (mpixelclock <= phy_config->mpixelclock)
 | 
				
			||||||
		    phy_config->mpixelclock)
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mpll_config->mpixelclock == ~0UL ||
 | 
						if (mpll_config->mpixelclock == ~0UL ||
 | 
				
			||||||
	    curr_ctrl->mpixelclock == ~0UL ||
 | 
						    curr_ctrl->mpixelclock == ~0UL ||
 | 
				
			||||||
	    phy_config->mpixelclock == ~0UL) {
 | 
						    phy_config->mpixelclock == ~0UL)
 | 
				
			||||||
		dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
 | 
					 | 
				
			||||||
			hdmi->hdmi_data.video_mode.mpixelclock);
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Enable csc path */
 | 
						dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
 | 
				
			||||||
	if (cscon)
 | 
								      HDMI_3D_TX_PHY_CPCE_CTRL);
 | 
				
			||||||
		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
 | 
						dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
 | 
				
			||||||
	else
 | 
								      HDMI_3D_TX_PHY_GMPCTRL);
 | 
				
			||||||
		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
 | 
						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_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
 | 
				
			||||||
	dw_hdmi_phy_gen2_txpwron(hdmi, 0);
 | 
						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 */
 | 
						/* Override and disable clock termination. */
 | 
				
			||||||
	dw_hdmi_phy_gen2_pddq(hdmi, 1);
 | 
						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. */
 | 
						/* Leave low power consumption mode by asserting SVSRET. */
 | 
				
			||||||
	if (hdmi->phy->has_svsret)
 | 
						if (phy->has_svsret)
 | 
				
			||||||
		dw_hdmi_phy_enable_svsret(hdmi, 1);
 | 
							dw_hdmi_phy_enable_svsret(hdmi, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* PHY reset. The reset signal is active high on Gen2 PHYs. */
 | 
						/* 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_I2CM_SLAVE_ADDR);
 | 
				
			||||||
	hdmi_phy_test_clear(hdmi, 0);
 | 
						hdmi_phy_test_clear(hdmi, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
 | 
						/* Write to the PHY as configured by the platform */
 | 
				
			||||||
			   HDMI_3D_TX_PHY_CPCE_CTRL);
 | 
						if (pdata->configure_phy)
 | 
				
			||||||
	hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
 | 
							ret = pdata->configure_phy(hdmi, pdata, mpixelclock);
 | 
				
			||||||
			   HDMI_3D_TX_PHY_GMPCTRL);
 | 
						else
 | 
				
			||||||
	hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
 | 
							ret = phy->configure(hdmi, pdata, mpixelclock);
 | 
				
			||||||
			   HDMI_3D_TX_PHY_CURRCTRL);
 | 
						if (ret) {
 | 
				
			||||||
 | 
							dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
 | 
				
			||||||
	hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
 | 
								mpixelclock);
 | 
				
			||||||
	hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
 | 
							return ret;
 | 
				
			||||||
			   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);
 | 
						return dw_hdmi_phy_power_on(hdmi);
 | 
				
			||||||
		msec--;
 | 
					 | 
				
			||||||
	} while (1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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;
 | 
						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 */
 | 
						/* HDMI Phy spec says to do the phy initialization sequence twice */
 | 
				
			||||||
	for (i = 0; i < 2; i++) {
 | 
						for (i = 0; i < 2; i++) {
 | 
				
			||||||
		dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
 | 
							dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
 | 
				
			||||||
		dw_hdmi_phy_sel_interface_control(hdmi, 0);
 | 
							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);
 | 
				
			||||||
		ret = hdmi_phy_configure(hdmi, cscon);
 | 
					 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdmi->phy_enabled = true;
 | 
					 | 
				
			||||||
	return 0;
 | 
						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)
 | 
					static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u8 de;
 | 
						u8 de;
 | 
				
			||||||
| 
						 | 
					@ -1290,17 +1325,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
 | 
				
			||||||
	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 | 
						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 */
 | 
					/* HDMI Initialization Step B.4 */
 | 
				
			||||||
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
 | 
					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;
 | 
							clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
 | 
				
			||||||
		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
 | 
							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)
 | 
					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_av_composer(hdmi, mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* HDMI Initializateion Step B.2 */
 | 
						/* 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)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
						hdmi->phy.enabled = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* HDMI Initialization Step B.3 */
 | 
						/* HDMI Initialization Step B.3 */
 | 
				
			||||||
	dw_hdmi_enable_video_path(hdmi);
 | 
						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)
 | 
					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;
 | 
						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);
 | 
						dw_hdmi_update_phy_mask(hdmi);
 | 
				
			||||||
	mutex_unlock(&hdmi->mutex);
 | 
						mutex_unlock(&hdmi->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
 | 
						return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
 | 
				
			||||||
		connector_status_connected : connector_status_disconnected;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
 | 
					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,
 | 
							.type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
 | 
				
			||||||
		.name = "DWC HDMI TX PHY",
 | 
							.name = "DWC HDMI TX PHY",
 | 
				
			||||||
 | 
							.gen = 1,
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		.type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
 | 
							.type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
 | 
				
			||||||
		.name = "DWC MHL PHY + HEAC PHY",
 | 
							.name = "DWC MHL PHY + HEAC PHY",
 | 
				
			||||||
 | 
							.gen = 2,
 | 
				
			||||||
		.has_svsret = true,
 | 
							.has_svsret = true,
 | 
				
			||||||
 | 
							.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		.type = DW_HDMI_PHY_DWC_MHL_PHY,
 | 
							.type = DW_HDMI_PHY_DWC_MHL_PHY,
 | 
				
			||||||
		.name = "DWC MHL PHY",
 | 
							.name = "DWC MHL PHY",
 | 
				
			||||||
 | 
							.gen = 2,
 | 
				
			||||||
		.has_svsret = true,
 | 
							.has_svsret = true,
 | 
				
			||||||
 | 
							.configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
 | 
							.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
 | 
				
			||||||
		.name = "DWC HDMI 3D TX PHY + HEAC PHY",
 | 
							.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,
 | 
							.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
 | 
				
			||||||
		.name = "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,
 | 
							.type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
 | 
				
			||||||
		.name = "DWC HDMI 2.0 TX PHY",
 | 
							.name = "DWC HDMI 2.0 TX PHY",
 | 
				
			||||||
 | 
							.gen = 2,
 | 
				
			||||||
		.has_svsret = true,
 | 
							.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);
 | 
						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) {
 | 
						for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
 | 
				
			||||||
		if (dw_hdmi_phys[i].type == phy_type) {
 | 
							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;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
 | 
						dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", phy_type);
 | 
				
			||||||
		dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
 | 
					 | 
				
			||||||
			phy_type);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return -ENODEV;
 | 
						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 *
 | 
					static struct dw_hdmi *
 | 
				
			||||||
__dw_hdmi_probe(struct platform_device *pdev,
 | 
					__dw_hdmi_probe(struct platform_device *pdev,
 | 
				
			||||||
		const struct dw_hdmi_plat_data *plat_data)
 | 
							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 platform_device_info pdevinfo;
 | 
				
			||||||
	struct device_node *ddc_node;
 | 
						struct device_node *ddc_node;
 | 
				
			||||||
	struct dw_hdmi *hdmi;
 | 
						struct dw_hdmi *hdmi;
 | 
				
			||||||
	struct resource *iores;
 | 
						struct resource *iores = NULL;
 | 
				
			||||||
	int irq;
 | 
						int irq;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	u32 val = 1;
 | 
						u32 val = 1;
 | 
				
			||||||
| 
						 | 
					@ -1926,7 +2009,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hdmi->plat_data = plat_data;
 | 
						hdmi->plat_data = plat_data;
 | 
				
			||||||
	hdmi->dev = dev;
 | 
						hdmi->dev = dev;
 | 
				
			||||||
	hdmi->dev_type = plat_data->dev_type;
 | 
					 | 
				
			||||||
	hdmi->sample_rate = 48000;
 | 
						hdmi->sample_rate = 48000;
 | 
				
			||||||
	hdmi->disabled = true;
 | 
						hdmi->disabled = true;
 | 
				
			||||||
	hdmi->rxsense = true;
 | 
						hdmi->rxsense = true;
 | 
				
			||||||
| 
						 | 
					@ -1936,22 +2018,6 @@ __dw_hdmi_probe(struct platform_device *pdev,
 | 
				
			||||||
	mutex_init(&hdmi->audio_mutex);
 | 
						mutex_init(&hdmi->audio_mutex);
 | 
				
			||||||
	spin_lock_init(&hdmi->audio_lock);
 | 
						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);
 | 
						ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
 | 
				
			||||||
	if (ddc_node) {
 | 
						if (ddc_node) {
 | 
				
			||||||
		hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
 | 
							hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
 | 
				
			||||||
| 
						 | 
					@ -1965,6 +2031,23 @@ __dw_hdmi_probe(struct platform_device *pdev,
 | 
				
			||||||
		dev_dbg(hdmi->dev, "no ddc property found\n");
 | 
							dev_dbg(hdmi->dev, "no ddc property found\n");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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);
 | 
							iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
		hdmi->regs = devm_ioremap_resource(dev, iores);
 | 
							hdmi->regs = devm_ioremap_resource(dev, iores);
 | 
				
			||||||
		if (IS_ERR(hdmi->regs)) {
 | 
							if (IS_ERR(hdmi->regs)) {
 | 
				
			||||||
| 
						 | 
					@ -1972,6 +2055,16 @@ __dw_hdmi_probe(struct platform_device *pdev,
 | 
				
			||||||
			goto err_res;
 | 
								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");
 | 
						hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
 | 
				
			||||||
	if (IS_ERR(hdmi->isfr_clk)) {
 | 
						if (IS_ERR(hdmi->isfr_clk)) {
 | 
				
			||||||
		ret = PTR_ERR(hdmi->isfr_clk);
 | 
							ret = PTR_ERR(hdmi->isfr_clk);
 | 
				
			||||||
| 
						 | 
					@ -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",
 | 
						dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
 | 
				
			||||||
		 hdmi->version >> 12, hdmi->version & 0xfff,
 | 
							 hdmi->version >> 12, hdmi->version & 0xfff,
 | 
				
			||||||
		 prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
 | 
							 prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
 | 
				
			||||||
		 hdmi->phy->name);
 | 
							 hdmi->phy.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialize_hdmi_ih_mutes(hdmi);
 | 
						initialize_hdmi_ih_mutes(hdmi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2079,7 +2172,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
 | 
				
			||||||
	config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
 | 
						config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
 | 
				
			||||||
	config3 = hdmi_readb(hdmi, HDMI_CONFIG3_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;
 | 
							struct dw_hdmi_audio_data audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		audio.phys = iores->start;
 | 
							audio.phys = iores->start;
 | 
				
			||||||
| 
						 | 
					@ -1374,7 +1374,7 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (conn_state->crtc) {
 | 
						if (conn_state->crtc) {
 | 
				
			||||||
		crtc_state = drm_atomic_get_existing_crtc_state(conn_state->state,
 | 
							crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
 | 
				
			||||||
							   conn_state->crtc);
 | 
												   conn_state->crtc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		crtc_state->connector_mask &=
 | 
							crtc_state->connector_mask &=
 | 
				
			||||||
| 
						 | 
					@ -1492,7 +1492,7 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_plane *plane;
 | 
						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) {
 | 
						drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) {
 | 
				
			||||||
		struct drm_plane_state *plane_state =
 | 
							struct drm_plane_state *plane_state =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -377,27 +377,26 @@ int drm_atomic_normalize_zpos(struct drm_device *dev,
 | 
				
			||||||
			      struct drm_atomic_state *state)
 | 
								      struct drm_atomic_state *state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_crtc *crtc;
 | 
						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 *plane;
 | 
				
			||||||
	struct drm_plane_state *plane_state;
 | 
						struct drm_plane_state *old_plane_state, *new_plane_state;
 | 
				
			||||||
	int i, ret = 0;
 | 
						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) {
 | 
				
			||||||
		crtc = plane_state->crtc;
 | 
							crtc = new_plane_state->crtc;
 | 
				
			||||||
		if (!crtc)
 | 
							if (!crtc)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (plane->state->zpos != plane_state->zpos) {
 | 
							if (old_plane_state->zpos != new_plane_state->zpos) {
 | 
				
			||||||
			crtc_state =
 | 
								new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 | 
				
			||||||
				drm_atomic_get_existing_crtc_state(state, crtc);
 | 
								new_crtc_state->zpos_changed = true;
 | 
				
			||||||
			crtc_state->zpos_changed = true;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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) {
 | 
				
			||||||
		if (crtc_state->plane_mask != crtc->state->plane_mask ||
 | 
							if (old_crtc_state->plane_mask != new_crtc_state->plane_mask ||
 | 
				
			||||||
		    crtc_state->zpos_changed) {
 | 
							    new_crtc_state->zpos_changed) {
 | 
				
			||||||
			ret = drm_atomic_helper_crtc_normalize_zpos(crtc,
 | 
								ret = drm_atomic_helper_crtc_normalize_zpos(crtc,
 | 
				
			||||||
								    crtc_state);
 | 
													    new_crtc_state);
 | 
				
			||||||
			if (ret)
 | 
								if (ret)
 | 
				
			||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -242,14 +242,9 @@ static void drm_debugfs_remove_all_files(struct drm_minor *minor)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int drm_debugfs_cleanup(struct drm_minor *minor)
 | 
					int drm_debugfs_cleanup(struct drm_minor *minor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_device *dev = minor->dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!minor->debugfs_root)
 | 
						if (!minor->debugfs_root)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev->driver->debugfs_cleanup)
 | 
					 | 
				
			||||||
		dev->driver->debugfs_cleanup(minor);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	drm_debugfs_remove_all_files(minor);
 | 
						drm_debugfs_remove_all_files(minor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	debugfs_remove_recursive(minor->debugfs_root);
 | 
						debugfs_remove_recursive(minor->debugfs_root);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -981,6 +981,78 @@ static const struct i2c_lock_operations drm_dp_i2c_lock_ops = {
 | 
				
			||||||
	.unlock_bus = unlock_bus,
 | 
						.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
 | 
					 * drm_dp_aux_init() - minimally initialise an aux channel
 | 
				
			||||||
 * @aux: DisplayPort 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)
 | 
					void drm_dp_aux_init(struct drm_dp_aux *aux)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mutex_init(&aux->hw_mutex);
 | 
						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 = &drm_dp_i2c_algo;
 | 
				
			||||||
	aux->ddc.algo_data = aux;
 | 
						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);
 | 
					EXPORT_SYMBOL(drm_dp_psr_setup_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef 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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,4 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * \file drm_fops.c
 | 
					 | 
				
			||||||
 * File operations for DRM
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \author Rickard E. (Rik) Faith <faith@valinux.com>
 | 
					 * \author Rickard E. (Rik) Faith <faith@valinux.com>
 | 
				
			||||||
 * \author Daryll Strauss <daryll@valinux.com>
 | 
					 * \author Daryll Strauss <daryll@valinux.com>
 | 
				
			||||||
 * \author Gareth Hughes <gareth@valinux.com>
 | 
					 * \author Gareth Hughes <gareth@valinux.com>
 | 
				
			||||||
| 
						 | 
					@ -34,10 +31,13 @@
 | 
				
			||||||
 * OTHER DEALINGS IN THE SOFTWARE.
 | 
					 * OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <drm/drmP.h>
 | 
					 | 
				
			||||||
#include <linux/poll.h>
 | 
					#include <linux/poll.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <drm/drm_file.h>
 | 
				
			||||||
 | 
					#include <drm/drmP.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "drm_legacy.h"
 | 
					#include "drm_legacy.h"
 | 
				
			||||||
#include "drm_internal.h"
 | 
					#include "drm_internal.h"
 | 
				
			||||||
#include "drm_crtc_internal.h"
 | 
					#include "drm_crtc_internal.h"
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@
 | 
				
			||||||
#define DRM_IF_MAJOR 1
 | 
					#define DRM_IF_MAJOR 1
 | 
				
			||||||
#define DRM_IF_MINOR 4
 | 
					#define DRM_IF_MINOR 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* drm_fops.c */
 | 
					/* drm_file.c */
 | 
				
			||||||
extern struct mutex drm_global_mutex;
 | 
					extern struct mutex drm_global_mutex;
 | 
				
			||||||
void drm_lastclose(struct drm_device *dev);
 | 
					void drm_lastclose(struct drm_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,8 +25,7 @@
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <drm/drmP.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <drm/drm_fb_helper.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "drm_crtc_helper_internal.h"
 | 
					#include "drm_crtc_helper_internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/dma-mapping.h>
 | 
					#include <linux/dma-mapping.h>
 | 
				
			||||||
#include <linux/export.h>
 | 
					#include <linux/export.h>
 | 
				
			||||||
 | 
					#include <drm/drm_pci.h>
 | 
				
			||||||
#include <drm/drmP.h>
 | 
					#include <drm/drmP.h>
 | 
				
			||||||
#include "drm_internal.h"
 | 
					#include "drm_internal.h"
 | 
				
			||||||
#include "drm_legacy.h"
 | 
					#include "drm_legacy.h"
 | 
				
			||||||
| 
						 | 
					@ -36,6 +37,9 @@
 | 
				
			||||||
 * @size: size of block to allocate
 | 
					 * @size: size of block to allocate
 | 
				
			||||||
 * @align: alignment of block
 | 
					 * @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
 | 
					 * Return: A handle to the allocated memory block on success or NULL on
 | 
				
			||||||
 * failure.
 | 
					 * 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
 | 
					 * drm_pci_free - Free a PCI consistent memory block
 | 
				
			||||||
 * @dev: DRM device
 | 
					 * @dev: DRM device
 | 
				
			||||||
 * @dmah: handle to memory block
 | 
					 * @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)
 | 
					void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -469,7 +469,7 @@ int drm_plane_helper_commit(struct drm_plane *plane,
 | 
				
			||||||
	 * Drivers may optionally implement the ->atomic_disable callback, so
 | 
						 * Drivers may optionally implement the ->atomic_disable callback, so
 | 
				
			||||||
	 * special-case that here.
 | 
						 * 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_funcs->atomic_disable(plane, plane_state);
 | 
							plane_funcs->atomic_disable(plane, plane_state);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -29,8 +29,9 @@
 | 
				
			||||||
#include <linux/export.h>
 | 
					#include <linux/export.h>
 | 
				
			||||||
#include <linux/dma-buf.h>
 | 
					#include <linux/dma-buf.h>
 | 
				
			||||||
#include <linux/rbtree.h>
 | 
					#include <linux/rbtree.h>
 | 
				
			||||||
#include <drm/drmP.h>
 | 
					#include <drm/drm_prime.h>
 | 
				
			||||||
#include <drm/drm_gem.h>
 | 
					#include <drm/drm_gem.h>
 | 
				
			||||||
 | 
					#include <drm/drmP.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "drm_internal.h"
 | 
					#include "drm_internal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,7 +86,7 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane,
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
 | 
						pipe = container_of(plane, struct drm_simple_display_pipe, plane);
 | 
				
			||||||
	crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
 | 
						crtc_state = drm_atomic_get_new_crtc_state(plane_state->state,
 | 
				
			||||||
						   &pipe->crtc);
 | 
											   &pipe->crtc);
 | 
				
			||||||
	if (crtc_state->enable != !!plane_state->crtc)
 | 
						if (crtc_state->enable != !!plane_state->crtc)
 | 
				
			||||||
		return -EINVAL; /* plane must match crtc enable state */
 | 
							return -EINVAL; /* plane must match crtc enable state */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
						struct exynos_dp_device *dp = to_dp(plat_data);
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_connector_register(connector);
 | 
					 | 
				
			||||||
	dp->connector = connector;
 | 
						dp->connector = connector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Pre-empt DP connector creation if there's a bridge */
 | 
						/* Pre-empt DP connector creation if there's a bridge */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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_helper_add(connector, &exynos_dpi_connector_helper_funcs);
 | 
				
			||||||
	drm_connector_register(connector);
 | 
					 | 
				
			||||||
	drm_mode_connector_attach_encoder(connector, encoder);
 | 
						drm_mode_connector_attach_encoder(connector, encoder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,118 +39,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct device *exynos_drm_get_dma_device(void);
 | 
					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,
 | 
					int exynos_atomic_check(struct drm_device *dev,
 | 
				
			||||||
			struct drm_atomic_state *state)
 | 
								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 = {
 | 
					static struct drm_driver exynos_drm_driver = {
 | 
				
			||||||
	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
 | 
						.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
 | 
				
			||||||
				  | DRIVER_ATOMIC | DRIVER_RENDER,
 | 
									  | DRIVER_ATOMIC | DRIVER_RENDER,
 | 
				
			||||||
	.load			= exynos_drm_load,
 | 
					 | 
				
			||||||
	.unload			= exynos_drm_unload,
 | 
					 | 
				
			||||||
	.open			= exynos_drm_open,
 | 
						.open			= exynos_drm_open,
 | 
				
			||||||
	.preclose		= exynos_drm_preclose,
 | 
						.preclose		= exynos_drm_preclose,
 | 
				
			||||||
	.lastclose		= exynos_drm_lastclose,
 | 
						.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)
 | 
					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)
 | 
					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 = {
 | 
					static const struct component_master_ops exynos_drm_ops = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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_helper_add(connector, &exynos_dsi_connector_helper_funcs);
 | 
				
			||||||
	drm_connector_register(connector);
 | 
					 | 
				
			||||||
	drm_mode_connector_attach_encoder(connector, encoder);
 | 
						drm_mode_connector_attach_encoder(connector, encoder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,7 +119,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 | 
				
			||||||
	struct exynos_drm_gem *exynos_gem;
 | 
						struct exynos_drm_gem *exynos_gem;
 | 
				
			||||||
	struct drm_device *dev = helper->dev;
 | 
						struct drm_device *dev = helper->dev;
 | 
				
			||||||
	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
 | 
						struct drm_mode_fb_cmd2 mode_cmd = { 0 };
 | 
				
			||||||
	struct platform_device *pdev = dev->platformdev;
 | 
					 | 
				
			||||||
	unsigned long size;
 | 
						unsigned long size;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,7 +141,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 | 
				
			||||||
	 * memory area.
 | 
						 * memory area.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (IS_ERR(exynos_gem) && is_drm_iommu_supported(dev)) {
 | 
						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,
 | 
							exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG,
 | 
				
			||||||
						   size);
 | 
											   size);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -359,7 +359,6 @@ static int vidi_create_connector(struct drm_encoder *encoder)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
 | 
						drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
 | 
				
			||||||
	drm_connector_register(connector);
 | 
					 | 
				
			||||||
	drm_mode_connector_attach_encoder(connector, encoder);
 | 
						drm_mode_connector_attach_encoder(connector, encoder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -920,7 +920,6 @@ static int hdmi_create_connector(struct drm_encoder *encoder)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
 | 
						drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
 | 
				
			||||||
	drm_connector_register(connector);
 | 
					 | 
				
			||||||
	drm_mode_connector_attach_encoder(connector, encoder);
 | 
						drm_mode_connector_attach_encoder(connector, encoder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hdata->bridge) {
 | 
						if (hdata->bridge) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,7 +175,6 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
 | 
				
			||||||
	.mpll_cfg   = imx_mpll_cfg,
 | 
						.mpll_cfg   = imx_mpll_cfg,
 | 
				
			||||||
	.cur_ctr    = imx_cur_ctr,
 | 
						.cur_ctr    = imx_cur_ctr,
 | 
				
			||||||
	.phy_config = imx_phy_config,
 | 
						.phy_config = imx_phy_config,
 | 
				
			||||||
	.dev_type   = IMX6Q_HDMI,
 | 
					 | 
				
			||||||
	.mode_valid = imx6q_hdmi_mode_valid,
 | 
						.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,
 | 
						.mpll_cfg = imx_mpll_cfg,
 | 
				
			||||||
	.cur_ctr  = imx_cur_ctr,
 | 
						.cur_ctr  = imx_cur_ctr,
 | 
				
			||||||
	.phy_config = imx_phy_config,
 | 
						.phy_config = imx_phy_config,
 | 
				
			||||||
	.dev_type = IMX6DL_HDMI,
 | 
					 | 
				
			||||||
	.mode_valid = imx6dl_hdmi_mode_valid,
 | 
						.mode_valid = imx6dl_hdmi_mode_valid,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -434,7 +434,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msm_kms *mdp4_kms_init(struct drm_device *dev)
 | 
					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_platform_config *config = mdp4_get_config(pdev);
 | 
				
			||||||
	struct mdp4_kms *mdp4_kms;
 | 
						struct mdp4_kms *mdp4_kms;
 | 
				
			||||||
	struct msm_kms *kms = NULL;
 | 
						struct msm_kms *kms = NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -505,7 +505,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
 | 
				
			||||||
		uint32_t major, uint32_t minor)
 | 
							uint32_t major, uint32_t minor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_device *dev = mdp5_kms->dev;
 | 
						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_handler *cfg_handler;
 | 
				
			||||||
	struct mdp5_cfg_platform *pconfig;
 | 
						struct mdp5_cfg_platform *pconfig;
 | 
				
			||||||
	int i, ret = 0;
 | 
						int i, ret = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,7 +160,7 @@ void msm_mdss_destroy(struct drm_device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int msm_mdss_init(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_drm_private *priv = dev->dev_private;
 | 
				
			||||||
	struct msm_mdss *mdss;
 | 
						struct msm_mdss *mdss;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -164,20 +164,5 @@ int msm_debugfs_init(struct drm_minor *minor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						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
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DEBUG_FS
 | 
					#ifdef CONFIG_DEBUG_FS
 | 
				
			||||||
int msm_debugfs_init(struct drm_minor *minor);
 | 
					int msm_debugfs_init(struct drm_minor *minor);
 | 
				
			||||||
void msm_debugfs_cleanup(struct drm_minor *minor);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __MSM_DEBUGFS_H__ */
 | 
					#endif /* __MSM_DEBUGFS_H__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -241,6 +241,9 @@ static int msm_drm_uninit(struct device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_dev_unregister(ddev);
 | 
						drm_dev_unregister(ddev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msm_perf_debugfs_cleanup(priv);
 | 
				
			||||||
 | 
						msm_rd_debugfs_cleanup(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DRM_FBDEV_EMULATION
 | 
					#ifdef CONFIG_DRM_FBDEV_EMULATION
 | 
				
			||||||
	if (fbdev && priv->fbdev)
 | 
						if (fbdev && priv->fbdev)
 | 
				
			||||||
		msm_fbdev_free(ddev);
 | 
							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);
 | 
						platform_set_drvdata(pdev, ddev);
 | 
				
			||||||
	ddev->platformdev = pdev;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 | 
						priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 | 
				
			||||||
	if (!priv) {
 | 
						if (!priv) {
 | 
				
			||||||
| 
						 | 
					@ -836,7 +838,6 @@ static struct drm_driver msm_driver = {
 | 
				
			||||||
	.gem_prime_mmap     = msm_gem_prime_mmap,
 | 
						.gem_prime_mmap     = msm_gem_prime_mmap,
 | 
				
			||||||
#ifdef CONFIG_DEBUG_FS
 | 
					#ifdef CONFIG_DEBUG_FS
 | 
				
			||||||
	.debugfs_init       = msm_debugfs_init,
 | 
						.debugfs_init       = msm_debugfs_init,
 | 
				
			||||||
	.debugfs_cleanup    = msm_debugfs_cleanup,
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	.ioctls             = msm_ioctls,
 | 
						.ioctls             = msm_ioctls,
 | 
				
			||||||
	.num_ioctls         = DRM_MSM_NUM_IOCTLS,
 | 
						.num_ioctls         = DRM_MSM_NUM_IOCTLS,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
					void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
 | 
				
			||||||
int msm_debugfs_late_init(struct drm_device *dev);
 | 
					int msm_debugfs_late_init(struct drm_device *dev);
 | 
				
			||||||
int msm_rd_debugfs_init(struct drm_minor *minor);
 | 
					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);
 | 
					void msm_rd_dump_submit(struct msm_gem_submit *submit);
 | 
				
			||||||
int msm_perf_debugfs_init(struct drm_minor *minor);
 | 
					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
 | 
					#else
 | 
				
			||||||
static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }
 | 
					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) {}
 | 
					static inline void msm_rd_dump_submit(struct msm_gem_submit *submit) {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,6 @@ struct msm_kms_funcs {
 | 
				
			||||||
#ifdef CONFIG_DEBUG_FS
 | 
					#ifdef CONFIG_DEBUG_FS
 | 
				
			||||||
	/* debugfs: */
 | 
						/* debugfs: */
 | 
				
			||||||
	int (*debugfs_init)(struct msm_kms *kms, struct drm_minor *minor);
 | 
						int (*debugfs_init)(struct msm_kms *kms, struct drm_minor *minor);
 | 
				
			||||||
	void (*debugfs_cleanup)(struct msm_kms *kms, struct drm_minor *minor);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,13 +231,12 @@ int msm_perf_debugfs_init(struct drm_minor *minor)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
	msm_perf_debugfs_cleanup(minor);
 | 
						msm_perf_debugfs_cleanup(priv);
 | 
				
			||||||
	return -1;
 | 
						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;
 | 
						struct msm_perf_state *perf = priv->perf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!perf)
 | 
						if (!perf)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,13 +245,12 @@ int msm_rd_debugfs_init(struct drm_minor *minor)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
	msm_rd_debugfs_cleanup(minor);
 | 
						msm_rd_debugfs_cleanup(priv);
 | 
				
			||||||
	return -1;
 | 
						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;
 | 
						struct msm_rd_state *rd = priv->rd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rd)
 | 
						if (!rd)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,7 +108,7 @@ nouveau_name(struct drm_device *dev)
 | 
				
			||||||
	if (dev->pdev)
 | 
						if (dev->pdev)
 | 
				
			||||||
		return nouveau_pci_name(dev->pdev);
 | 
							return nouveau_pci_name(dev->pdev);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return nouveau_platform_name(dev->platformdev);
 | 
							return nouveau_platform_name(to_platform_device(dev->dev));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -1095,7 +1095,6 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,
 | 
				
			||||||
		goto err_free;
 | 
							goto err_free;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm->platformdev = pdev;
 | 
					 | 
				
			||||||
	platform_set_drvdata(pdev, drm);
 | 
						platform_set_drvdata(pdev, drm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return drm;
 | 
						return drm;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,16 +129,3 @@ int qxl_debugfs_add_files(struct qxl_device *qdev,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	return 0;
 | 
						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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,6 +81,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
 | 
				
			||||||
			   qdev->rom->client_monitors_config_crc);
 | 
								   qdev->rom->client_monitors_config_crc);
 | 
				
			||||||
		return MONITORS_CONFIG_BAD_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) {
 | 
						if (num_monitors > qdev->monitors_config->max_allowed) {
 | 
				
			||||||
		DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
 | 
							DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
 | 
				
			||||||
			      qdev->monitors_config->max_allowed, num_monitors);
 | 
								      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)
 | 
					void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct drm_device *dev = &qdev->ddev;
 | 
						struct drm_device *dev = &qdev->ddev;
 | 
				
			||||||
	int status;
 | 
						int status, retries;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (retries = 0; retries < 10; retries++) {
 | 
				
			||||||
		status = qxl_display_copy_rom_client_monitors_config(qdev);
 | 
							status = qxl_display_copy_rom_client_monitors_config(qdev);
 | 
				
			||||||
	while (status == MONITORS_CONFIG_BAD_CRC) {
 | 
							if (status != MONITORS_CONFIG_BAD_CRC)
 | 
				
			||||||
		qxl_io_log(qdev, "failed crc check for client_monitors_config,"
 | 
								break;
 | 
				
			||||||
				 " retrying\n");
 | 
							udelay(5);
 | 
				
			||||||
		status = qxl_display_copy_rom_client_monitors_config(qdev);
 | 
						}
 | 
				
			||||||
 | 
						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) {
 | 
						if (status == MONITORS_CONFIG_UNCHANGED) {
 | 
				
			||||||
		qxl_io_log(qdev, "config unchanged\n");
 | 
							qxl_io_log(qdev, "config: unchanged\n");
 | 
				
			||||||
		DRM_DEBUG("ignoring unchanged client monitors config");
 | 
							DRM_DEBUG_KMS("ignoring client monitors config: unchanged");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,9 +202,17 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector,
 | 
				
			||||||
	struct drm_display_mode *mode = NULL;
 | 
						struct drm_display_mode *mode = NULL;
 | 
				
			||||||
	struct qxl_head *head;
 | 
						struct qxl_head *head;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!qdev->monitors_config)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						if (h >= qdev->monitors_config->max_allowed)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	if (!qdev->client_monitors_config)
 | 
						if (!qdev->client_monitors_config)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
						if (h >= qdev->client_monitors_config->count)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	head = &qdev->client_monitors_config->heads[h];
 | 
						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,
 | 
						mode = drm_cvt_mode(dev, head->width, head->height, 60, false, 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)
 | 
					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 pwidth = 1024;
 | 
				
			||||||
	unsigned pheight = 768;
 | 
						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);
 | 
						ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ret += qxl_add_common_modes(connector, pwidth, pheight);
 | 
						ret += qxl_add_common_modes(connector, pwidth, pheight);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1188,6 +1198,7 @@ int qxl_modeset_init(struct qxl_device *qdev)
 | 
				
			||||||
		qdev_output_init(&qdev->ddev, i);
 | 
							qdev_output_init(&qdev->ddev, i);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qxl_display_read_client_monitors_config(qdev);
 | 
				
			||||||
	qdev->mode_info.mode_config_initialized = true;
 | 
						qdev->mode_info.mode_config_initialized = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_mode_config_reset(&qdev->ddev);
 | 
						drm_mode_config_reset(&qdev->ddev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,8 +160,6 @@ struct qxl_mman {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct qxl_mode_info {
 | 
					struct qxl_mode_info {
 | 
				
			||||||
	int num_modes;
 | 
					 | 
				
			||||||
	struct qxl_mode *modes;
 | 
					 | 
				
			||||||
	bool mode_config_initialized;
 | 
						bool mode_config_initialized;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* pointer to fbdev info structure */
 | 
						/* pointer to fbdev info structure */
 | 
				
			||||||
| 
						 | 
					@ -232,7 +230,6 @@ int qxl_debugfs_add_files(struct qxl_device *rdev,
 | 
				
			||||||
			     struct drm_info_list *files,
 | 
								     struct drm_info_list *files,
 | 
				
			||||||
			     unsigned nfiles);
 | 
								     unsigned nfiles);
 | 
				
			||||||
int qxl_debugfs_fence_init(struct qxl_device *rdev);
 | 
					int qxl_debugfs_fence_init(struct qxl_device *rdev);
 | 
				
			||||||
void qxl_debugfs_remove_files(struct qxl_device *qdev);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct qxl_device;
 | 
					struct qxl_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -368,9 +368,11 @@ static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qxl_fbdev_init(struct qxl_device *qdev)
 | 
					int qxl_fbdev_init(struct qxl_device *qdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_DRM_FBDEV_EMULATION
 | 
				
			||||||
	struct qxl_fbdev *qfbdev;
 | 
						struct qxl_fbdev *qfbdev;
 | 
				
			||||||
	int bpp_sel = 32; /* TODO: parameter from somewhere? */
 | 
						int bpp_sel = 32; /* TODO: parameter from somewhere? */
 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);
 | 
						qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL);
 | 
				
			||||||
	if (!qfbdev)
 | 
						if (!qfbdev)
 | 
				
			||||||
| 
						 | 
					@ -403,6 +405,8 @@ int qxl_fbdev_init(struct qxl_device *qdev)
 | 
				
			||||||
	drm_fb_helper_fini(&qfbdev->helper);
 | 
						drm_fb_helper_fini(&qfbdev->helper);
 | 
				
			||||||
free:
 | 
					free:
 | 
				
			||||||
	kfree(qfbdev);
 | 
						kfree(qfbdev);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						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)
 | 
					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);
 | 
						drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,19 +31,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qxl_log_level;
 | 
					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)
 | 
					static bool qxl_check_device(struct qxl_device *qdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct qxl_rom *rom = qdev->rom;
 | 
						struct qxl_rom *rom = qdev->rom;
 | 
				
			||||||
	int mode_offset;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rom->magic != 0x4f525851) {
 | 
						if (rom->magic != 0x4f525851) {
 | 
				
			||||||
		DRM_ERROR("bad rom signature %x\n", rom->magic);
 | 
							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("Device Version %d.%d\n", rom->id, rom->update_id);
 | 
				
			||||||
	DRM_INFO("Compression level %d log level %d\n", rom->compression_level,
 | 
						DRM_INFO("Compression level %d log level %d\n", rom->compression_level,
 | 
				
			||||||
		 rom->log_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",
 | 
						DRM_INFO("%d io pages at offset 0x%x\n",
 | 
				
			||||||
		 rom->num_io_pages, rom->pages_offset);
 | 
							 rom->num_io_pages, rom->pages_offset);
 | 
				
			||||||
	DRM_INFO("%d byte draw area at offset 0x%x\n",
 | 
						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;
 | 
						qdev->vram_size = rom->surface0_area_size;
 | 
				
			||||||
	DRM_INFO("RAM header offset: 0x%x\n", rom->ram_header_offset);
 | 
						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;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,7 +262,4 @@ void qxl_device_fini(struct qxl_device *qdev)
 | 
				
			||||||
	iounmap(qdev->ram_header);
 | 
						iounmap(qdev->ram_header);
 | 
				
			||||||
	iounmap(qdev->rom);
 | 
						iounmap(qdev->rom);
 | 
				
			||||||
	qdev->rom = NULL;
 | 
						qdev->rom = NULL;
 | 
				
			||||||
	qdev->mode_info.modes = NULL;
 | 
					 | 
				
			||||||
	qdev->mode_info.num_modes = 0;
 | 
					 | 
				
			||||||
	qxl_debugfs_remove_files(qdev);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,7 +237,6 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
 | 
				
			||||||
	.mpll_cfg   = rockchip_mpll_cfg,
 | 
						.mpll_cfg   = rockchip_mpll_cfg,
 | 
				
			||||||
	.cur_ctr    = rockchip_cur_ctr,
 | 
						.cur_ctr    = rockchip_cur_ctr,
 | 
				
			||||||
	.phy_config = rockchip_phy_config,
 | 
						.phy_config = rockchip_phy_config,
 | 
				
			||||||
	.dev_type   = RK3288_HDMI,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 | 
					static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,9 @@
 | 
				
			||||||
#include <drm/drm_crtc_helper.h>
 | 
					#include <drm/drm_crtc_helper.h>
 | 
				
			||||||
#include <drm/drm_flip_work.h>
 | 
					#include <drm/drm_flip_work.h>
 | 
				
			||||||
#include <drm/drm_plane_helper.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/kernel.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
| 
						 | 
					@ -1111,6 +1114,53 @@ static void vop_crtc_destroy_state(struct drm_crtc *crtc,
 | 
				
			||||||
	kfree(s);
 | 
						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 = {
 | 
					static const struct drm_crtc_funcs vop_crtc_funcs = {
 | 
				
			||||||
	.set_config = drm_atomic_helper_set_config,
 | 
						.set_config = drm_atomic_helper_set_config,
 | 
				
			||||||
	.page_flip = drm_atomic_helper_page_flip,
 | 
						.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,
 | 
						.atomic_destroy_state = vop_crtc_destroy_state,
 | 
				
			||||||
	.enable_vblank = vop_crtc_enable_vblank,
 | 
						.enable_vblank = vop_crtc_enable_vblank,
 | 
				
			||||||
	.disable_vblank = vop_crtc_disable_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)
 | 
					static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -711,13 +711,10 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_connector_helper_add(connector, &connector_helper_funcs);
 | 
						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);
 | 
						ret = shmob_drm_backlight_init(&sdev->connector);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto err_sysfs;
 | 
							goto err_cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = drm_mode_connector_attach_encoder(connector, encoder);
 | 
						ret = drm_mode_connector_attach_encoder(connector, encoder);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
| 
						 | 
					@ -731,8 +728,6 @@ int shmob_drm_connector_create(struct shmob_drm_device *sdev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_backlight:
 | 
					err_backlight:
 | 
				
			||||||
	shmob_drm_backlight_exit(&sdev->connector);
 | 
						shmob_drm_backlight_exit(&sdev->connector);
 | 
				
			||||||
err_sysfs:
 | 
					 | 
				
			||||||
	drm_connector_unregister(connector);
 | 
					 | 
				
			||||||
err_cleanup:
 | 
					err_cleanup:
 | 
				
			||||||
	drm_connector_cleanup(connector);
 | 
						drm_connector_cleanup(connector);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,100 +103,6 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
 | 
				
			||||||
 * DRM operations
 | 
					 * 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)
 | 
					static irqreturn_t shmob_drm_irq(int irq, void *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct drm_device *dev = 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 = {
 | 
					static struct drm_driver shmob_drm_driver = {
 | 
				
			||||||
	.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
 | 
						.driver_features	= DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
 | 
				
			||||||
				| DRIVER_PRIME,
 | 
									| DRIVER_PRIME,
 | 
				
			||||||
	.load			= shmob_drm_load,
 | 
					 | 
				
			||||||
	.unload			= shmob_drm_unload,
 | 
					 | 
				
			||||||
	.irq_handler		= shmob_drm_irq,
 | 
						.irq_handler		= shmob_drm_irq,
 | 
				
			||||||
	.gem_free_object_unlocked = drm_gem_cma_free_object,
 | 
						.gem_free_object_unlocked = drm_gem_cma_free_object,
 | 
				
			||||||
	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 | 
						.gem_vm_ops		= &drm_gem_cma_vm_ops,
 | 
				
			||||||
| 
						 | 
					@ -297,20 +201,118 @@ static const struct dev_pm_ops shmob_drm_pm_ops = {
 | 
				
			||||||
 * Platform driver
 | 
					 * Platform driver
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int shmob_drm_probe(struct platform_device *pdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return drm_platform_init(&shmob_drm_driver, pdev);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int shmob_drm_remove(struct platform_device *pdev)
 | 
					static int shmob_drm_remove(struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct shmob_drm_device *sdev = platform_get_drvdata(pdev);
 | 
						struct shmob_drm_device *sdev = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
						struct drm_device *ddev = sdev->ddev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drm_put_dev(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;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int shmob_drm_probe(struct platform_device *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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * 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 = {
 | 
					static struct platform_driver shmob_drm_platform_driver = {
 | 
				
			||||||
	.probe		= shmob_drm_probe,
 | 
						.probe		= shmob_drm_probe,
 | 
				
			||||||
	.remove		= shmob_drm_remove,
 | 
						.remove		= shmob_drm_remove,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -263,8 +263,6 @@ static int sti_bind(struct device *dev)
 | 
				
			||||||
	if (IS_ERR(ddev))
 | 
						if (IS_ERR(ddev))
 | 
				
			||||||
		return PTR_ERR(ddev);
 | 
							return PTR_ERR(ddev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ddev->platformdev = to_platform_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = sti_init(ddev);
 | 
						ret = sti_init(ddev);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto err_drm_dev_unref;
 | 
							goto err_drm_dev_unref;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,7 +245,6 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
 | 
				
			||||||
	if (IS_ERR(ddev))
 | 
						if (IS_ERR(ddev))
 | 
				
			||||||
		return PTR_ERR(ddev);
 | 
							return PTR_ERR(ddev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ddev->platformdev = pdev;
 | 
					 | 
				
			||||||
	ddev->dev_private = priv;
 | 
						ddev->dev_private = priv;
 | 
				
			||||||
	platform_set_drvdata(pdev, ddev);
 | 
						platform_set_drvdata(pdev, ddev);
 | 
				
			||||||
	drm_mode_config_init(ddev);
 | 
						drm_mode_config_init(ddev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -178,9 +178,7 @@ struct virtio_gpu_device {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct virtio_gpu_queue ctrlq;
 | 
						struct virtio_gpu_queue ctrlq;
 | 
				
			||||||
	struct virtio_gpu_queue cursorq;
 | 
						struct virtio_gpu_queue cursorq;
 | 
				
			||||||
	struct list_head free_vbufs;
 | 
						struct kmem_cache *vbufs;
 | 
				
			||||||
	spinlock_t free_vbufs_lock;
 | 
					 | 
				
			||||||
	void *vbufs;
 | 
					 | 
				
			||||||
	bool vqs_ready;
 | 
						bool vqs_ready;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct idr	resource_idr;
 | 
						struct idr	resource_idr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,51 +74,19 @@ void virtio_gpu_cursor_ack(struct virtqueue *vq)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev)
 | 
					int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct virtio_gpu_vbuffer *vbuf;
 | 
						vgdev->vbufs = kmem_cache_create("virtio-gpu-vbufs",
 | 
				
			||||||
	int i, size, count = 16;
 | 
										 VBUFFER_SIZE,
 | 
				
			||||||
	void *ptr;
 | 
										 __alignof__(struct virtio_gpu_vbuffer),
 | 
				
			||||||
 | 
										 0, NULL);
 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
	if (!vgdev->vbufs)
 | 
						if (!vgdev->vbufs)
 | 
				
			||||||
		return -ENOMEM;
 | 
							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;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev)
 | 
					void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct virtio_gpu_vbuffer *vbuf;
 | 
						kmem_cache_destroy(vgdev->vbufs);
 | 
				
			||||||
	int i, count = 0;
 | 
						vgdev->vbufs = NULL;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct virtio_gpu_vbuffer*
 | 
					static struct virtio_gpu_vbuffer*
 | 
				
			||||||
| 
						 | 
					@ -128,12 +96,9 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct virtio_gpu_vbuffer *vbuf;
 | 
						struct virtio_gpu_vbuffer *vbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&vgdev->free_vbufs_lock);
 | 
						vbuf = kmem_cache_alloc(vgdev->vbufs, GFP_KERNEL);
 | 
				
			||||||
	BUG_ON(list_empty(&vgdev->free_vbufs));
 | 
						if (IS_ERR(vbuf))
 | 
				
			||||||
	vbuf = list_first_entry(&vgdev->free_vbufs,
 | 
							return ERR_CAST(vbuf);
 | 
				
			||||||
				struct virtio_gpu_vbuffer, list);
 | 
					 | 
				
			||||||
	list_del(&vbuf->list);
 | 
					 | 
				
			||||||
	spin_unlock(&vgdev->free_vbufs_lock);
 | 
					 | 
				
			||||||
	memset(vbuf, 0, VBUFFER_SIZE);
 | 
						memset(vbuf, 0, VBUFFER_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(size > MAX_INLINE_CMD_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)
 | 
						if (vbuf->resp_size > MAX_INLINE_RESP_SIZE)
 | 
				
			||||||
		kfree(vbuf->resp_buf);
 | 
							kfree(vbuf->resp_buf);
 | 
				
			||||||
	kfree(vbuf->data_buf);
 | 
						kfree(vbuf->data_buf);
 | 
				
			||||||
	spin_lock(&vgdev->free_vbufs_lock);
 | 
						kmem_cache_free(vgdev->vbufs, vbuf);
 | 
				
			||||||
	list_add(&vbuf->list, &vgdev->free_vbufs);
 | 
					 | 
				
			||||||
	spin_unlock(&vgdev->free_vbufs_lock);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void reclaim_vbufs(struct virtqueue *vq, struct list_head *reclaim_list)
 | 
					static void reclaim_vbufs(struct virtqueue *vq, struct list_head *reclaim_list)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,4 +49,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 | 
				
			||||||
		     struct analogix_dp_plat_data *plat_data);
 | 
							     struct analogix_dp_plat_data *plat_data);
 | 
				
			||||||
void analogix_dp_unbind(struct device *dev, struct device *master, void *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_ */
 | 
					#endif /* _ANALOGIX_DP_H_ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,12 +21,6 @@ enum {
 | 
				
			||||||
	DW_HDMI_RES_MAX,
 | 
						DW_HDMI_RES_MAX,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum dw_hdmi_devtype {
 | 
					 | 
				
			||||||
	IMX6Q_HDMI,
 | 
					 | 
				
			||||||
	IMX6DL_HDMI,
 | 
					 | 
				
			||||||
	RK3288_HDMI,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum dw_hdmi_phy_type {
 | 
					enum dw_hdmi_phy_type {
 | 
				
			||||||
	DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
 | 
						DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
 | 
				
			||||||
	DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
 | 
						DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
 | 
				
			||||||
| 
						 | 
					@ -57,13 +51,30 @@ struct dw_hdmi_phy_config {
 | 
				
			||||||
	u16 vlev_ctr;   /* voltage level control */
 | 
						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 {
 | 
					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_mpll_config *mpll_cfg;
 | 
				
			||||||
	const struct dw_hdmi_curr_ctrl *cur_ctr;
 | 
						const struct dw_hdmi_curr_ctrl *cur_ctr;
 | 
				
			||||||
	const struct dw_hdmi_phy_config *phy_config;
 | 
						const struct dw_hdmi_phy_config *phy_config;
 | 
				
			||||||
	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 | 
						int (*configure_phy)(struct dw_hdmi *hdmi,
 | 
				
			||||||
					   struct drm_display_mode *mode);
 | 
								     const struct dw_hdmi_plat_data *pdata,
 | 
				
			||||||
 | 
								     unsigned long mpixelclock);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int dw_hdmi_probe(struct platform_device *pdev,
 | 
					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_enable(struct dw_hdmi *hdmi);
 | 
				
			||||||
void dw_hdmi_audio_disable(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__ */
 | 
					#endif /* __IMX_HDMI_H__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,17 +47,16 @@
 | 
				
			||||||
#include <linux/miscdevice.h>
 | 
					#include <linux/miscdevice.h>
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/mutex.h>
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
#include <linux/pci.h>
 | 
					 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
#include <linux/poll.h>
 | 
					#include <linux/poll.h>
 | 
				
			||||||
#include <linux/ratelimit.h>
 | 
					#include <linux/ratelimit.h>
 | 
				
			||||||
#include <linux/rbtree.h>
 | 
					 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
#include <linux/vmalloc.h>
 | 
					#include <linux/vmalloc.h>
 | 
				
			||||||
#include <linux/workqueue.h>
 | 
					#include <linux/workqueue.h>
 | 
				
			||||||
#include <linux/dma-fence.h>
 | 
					#include <linux/dma-fence.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/mman.h>
 | 
					#include <asm/mman.h>
 | 
				
			||||||
#include <asm/pgalloc.h>
 | 
					#include <asm/pgalloc.h>
 | 
				
			||||||
| 
						 | 
					@ -75,26 +74,30 @@
 | 
				
			||||||
#include <drm/drm_mm.h>
 | 
					#include <drm/drm_mm.h>
 | 
				
			||||||
#include <drm/drm_os_linux.h>
 | 
					#include <drm/drm_os_linux.h>
 | 
				
			||||||
#include <drm/drm_sarea.h>
 | 
					#include <drm/drm_sarea.h>
 | 
				
			||||||
#include <drm/drm_vma_manager.h>
 | 
					 | 
				
			||||||
#include <drm/drm_drv.h>
 | 
					#include <drm/drm_drv.h>
 | 
				
			||||||
 | 
					#include <drm/drm_prime.h>
 | 
				
			||||||
 | 
					#include <drm/drm_pci.h>
 | 
				
			||||||
 | 
					#include <drm/drm_file.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct module;
 | 
					struct module;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct drm_file;
 | 
					 | 
				
			||||||
struct drm_device;
 | 
					struct drm_device;
 | 
				
			||||||
struct drm_agp_head;
 | 
					struct drm_agp_head;
 | 
				
			||||||
struct drm_local_map;
 | 
					struct drm_local_map;
 | 
				
			||||||
struct drm_device_dma;
 | 
					struct drm_device_dma;
 | 
				
			||||||
struct drm_dma_handle;
 | 
					 | 
				
			||||||
struct drm_gem_object;
 | 
					struct drm_gem_object;
 | 
				
			||||||
struct drm_master;
 | 
					struct drm_master;
 | 
				
			||||||
struct drm_vblank_crtc;
 | 
					struct drm_vblank_crtc;
 | 
				
			||||||
 | 
					struct drm_vma_offset_manager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct device_node;
 | 
					struct device_node;
 | 
				
			||||||
struct videomode;
 | 
					struct videomode;
 | 
				
			||||||
struct reservation_object;
 | 
					struct reservation_object;
 | 
				
			||||||
struct dma_buf_attachment;
 | 
					struct dma_buf_attachment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pci_dev;
 | 
				
			||||||
 | 
					struct pci_controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The following categories are defined:
 | 
					 * The following categories are defined:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -357,97 +360,6 @@ struct drm_ioctl_desc {
 | 
				
			||||||
		.name = #ioctl						\
 | 
							.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. */
 | 
					/* Flags and return codes for get_vblank_timestamp() driver function. */
 | 
				
			||||||
#define DRM_CALLED_FROM_VBLIRQ 1
 | 
					#define DRM_CALLED_FROM_VBLIRQ 1
 | 
				
			||||||
#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
 | 
					#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_IN_VBLANK    (1 << 1)
 | 
				
			||||||
#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
 | 
					#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
 | 
					 * Info file list entry. This structure represents a debugfs or proc file to
 | 
				
			||||||
 * be created by the drm core
 | 
					 * be created by the drm core
 | 
				
			||||||
| 
						 | 
					@ -486,21 +391,6 @@ struct drm_info_node {
 | 
				
			||||||
	struct dentry *dent;
 | 
						struct dentry *dent;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * 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
 | 
					 * DRM device structure. This structure represent a complete card that
 | 
				
			||||||
 * may contain multiple heads.
 | 
					 * may contain multiple heads.
 | 
				
			||||||
| 
						 | 
					@ -611,7 +501,6 @@ struct drm_device {
 | 
				
			||||||
	struct pci_controller *hose;
 | 
						struct pci_controller *hose;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct platform_device *platformdev; /**< Platform device struture */
 | 
					 | 
				
			||||||
	struct virtio_device *virtdev;
 | 
						struct virtio_device *virtdev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct drm_sg_mem *sg;	/**< Scatter gather memory */
 | 
						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;
 | 
						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 */
 | 
					/** \name Internal function definitions */
 | 
				
			||||||
/*@{*/
 | 
					/*@{*/
 | 
				
			||||||
| 
						 | 
					@ -707,25 +581,6 @@ extern long drm_compat_ioctl(struct file *filp,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags);
 | 
					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) */
 | 
					/* Misc. IOCTL support (drm_ioctl.c) */
 | 
				
			||||||
int drm_noop(struct drm_device *dev, void *data,
 | 
					int drm_noop(struct drm_device *dev, void *data,
 | 
				
			||||||
	     struct drm_file *file_priv);
 | 
						     struct drm_file *file_priv);
 | 
				
			||||||
| 
						 | 
					@ -759,70 +614,12 @@ static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#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) */
 | 
								       /* sysfs support (drm_sysfs.c) */
 | 
				
			||||||
extern void drm_sysfs_hotplug_event(struct drm_device *dev);
 | 
					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 */
 | 
					/* returns true if currently okay to sleep */
 | 
				
			||||||
static __inline__ bool drm_can_sleep(void)
 | 
					static __inline__ bool drm_can_sleep(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					 * This function returns the crtc state for the given crtc, or NULL
 | 
				
			||||||
 * if the crtc is not part of the global atomic state.
 | 
					 * 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 *
 | 
					static inline struct drm_crtc_state *
 | 
				
			||||||
drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
 | 
					drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
 | 
				
			||||||
| 
						 | 
					@ -285,6 +288,35 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
 | 
				
			||||||
	return state->crtcs[drm_crtc_index(crtc)].state;
 | 
						return state->crtcs[drm_crtc_index(crtc)].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
 | 
					 * drm_atomic_get_existing_plane_state - get plane state, if it exists
 | 
				
			||||||
 * @state: global atomic state object
 | 
					 * @state: global atomic state object
 | 
				
			||||||
| 
						 | 
					@ -292,6 +324,9 @@ drm_atomic_get_existing_crtc_state(struct drm_atomic_state *state,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This function returns the plane state for the given plane, or NULL
 | 
					 * This function returns the plane state for the given plane, or NULL
 | 
				
			||||||
 * if the plane is not part of the global atomic state.
 | 
					 * 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 *
 | 
					static inline struct drm_plane_state *
 | 
				
			||||||
drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
 | 
					drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
 | 
				
			||||||
| 
						 | 
					@ -300,6 +335,36 @@ drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
 | 
				
			||||||
	return state->planes[drm_plane_index(plane)].state;
 | 
						return state->planes[drm_plane_index(plane)].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
 | 
					 * drm_atomic_get_existing_connector_state - get connector state, if it exists
 | 
				
			||||||
 * @state: global atomic state object
 | 
					 * @state: global atomic state object
 | 
				
			||||||
| 
						 | 
					@ -307,6 +372,9 @@ drm_atomic_get_existing_plane_state(struct drm_atomic_state *state,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This function returns the connector state for the given connector,
 | 
					 * This function returns the connector state for the given connector,
 | 
				
			||||||
 * or NULL if the connector is not part of the global atomic state.
 | 
					 * 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 *
 | 
					static inline struct drm_connector_state *
 | 
				
			||||||
drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
 | 
					drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
 | 
				
			||||||
| 
						 | 
					@ -320,6 +388,46 @@ drm_atomic_get_existing_connector_state(struct drm_atomic_state *state,
 | 
				
			||||||
	return state->connectors[index].state;
 | 
						return state->connectors[index].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
 | 
					 * __drm_atomic_get_current_plane_state - get current plane state
 | 
				
			||||||
 * @state: global atomic state object
 | 
					 * @state: global atomic state object
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,10 +220,10 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
 | 
				
			||||||
			      __drm_atomic_get_current_plane_state((crtc_state)->state, \
 | 
								      __drm_atomic_get_current_plane_state((crtc_state)->state, \
 | 
				
			||||||
								   plane)))
 | 
													   plane)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/**
 | 
				
			||||||
 * drm_atomic_plane_disabling - check whether a plane is being disabled
 | 
					 * drm_atomic_plane_disabling - check whether a plane is being disabled
 | 
				
			||||||
 * @plane: plane object
 | 
					 * @old_plane_state: old atomic plane state
 | 
				
			||||||
 * @old_state: previous atomic state
 | 
					 * @new_plane_state: new atomic plane state
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Checks the atomic state of a plane to determine whether it's being disabled
 | 
					 * 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
 | 
					 * 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.
 | 
					 * True if the plane is being disabled, false otherwise.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static inline bool
 | 
					static inline bool
 | 
				
			||||||
drm_atomic_plane_disabling(struct drm_plane *plane,
 | 
					drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state,
 | 
				
			||||||
			   struct drm_plane_state *old_state)
 | 
								   struct drm_plane_state *new_plane_state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * When disabling a plane, CRTC and FB should always be NULL together.
 | 
						 * 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
 | 
						 * Anything else should be considered a bug in the atomic core, so we
 | 
				
			||||||
	 * gently warn about it.
 | 
						 * gently warn about it.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	WARN_ON((plane->state->crtc == NULL && plane->state->fb != NULL) ||
 | 
						WARN_ON((new_plane_state->crtc == NULL && new_plane_state->fb != NULL) ||
 | 
				
			||||||
		(plane->state->crtc != NULL && plane->state->fb == NULL));
 | 
							(new_plane_state->crtc != NULL && new_plane_state->fb == NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						return old_plane_state->crtc && !new_plane_state->crtc;
 | 
				
			||||||
	 * 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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* DRM_ATOMIC_HELPER_H_ */
 | 
					#endif /* DRM_ATOMIC_HELPER_H_ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,23 @@
 | 
				
			||||||
#ifndef _DRM_AUTH_H_
 | 
					#ifndef _DRM_AUTH_H_
 | 
				
			||||||
#define _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
 | 
					 * struct drm_master - drm master structure
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -204,6 +204,12 @@ struct drm_crtc_state {
 | 
				
			||||||
	 * drm_crtc_arm_vblank_event(). See the documentation of that function
 | 
						 * drm_crtc_arm_vblank_event(). See the documentation of that function
 | 
				
			||||||
	 * for a detailed discussion of the constraints it needs to be used
 | 
						 * for a detailed discussion of the constraints it needs to be used
 | 
				
			||||||
	 * safely.
 | 
						 * 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;
 | 
						struct drm_pending_vblank_event *event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -776,6 +782,7 @@ struct drm_crtc {
 | 
				
			||||||
	 * Debugfs directory for this CRTC.
 | 
						 * Debugfs directory for this CRTC.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct dentry *debugfs_entry;
 | 
						struct dentry *debugfs_entry;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @crc:
 | 
						 * @crc:
 | 
				
			||||||
| 
						 | 
					@ -783,7 +790,6 @@ struct drm_crtc {
 | 
				
			||||||
	 * Configuration settings of CRC capture.
 | 
						 * Configuration settings of CRC capture.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct drm_crtc_crc crc;
 | 
						struct drm_crtc_crc crc;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @fence_context:
 | 
						 * @fence_context:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -789,7 +789,10 @@ struct drm_dp_aux_msg {
 | 
				
			||||||
 * @name: user-visible name of this AUX channel and the I2C-over-AUX adapter
 | 
					 * @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
 | 
					 * @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
 | 
					 * @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
 | 
					 * @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
 | 
					 * @transfer: transfers a message representing a single AUX transaction
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The .dev field should be set to a pointer to the device that implements
 | 
					 * 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;
 | 
						const char *name;
 | 
				
			||||||
	struct i2c_adapter ddc;
 | 
						struct i2c_adapter ddc;
 | 
				
			||||||
	struct device *dev;
 | 
						struct device *dev;
 | 
				
			||||||
 | 
						struct drm_crtc *crtc;
 | 
				
			||||||
	struct mutex hw_mutex;
 | 
						struct mutex hw_mutex;
 | 
				
			||||||
 | 
						struct work_struct crc_work;
 | 
				
			||||||
 | 
						u8 crc_count;
 | 
				
			||||||
	ssize_t (*transfer)(struct drm_dp_aux *aux,
 | 
						ssize_t (*transfer)(struct drm_dp_aux *aux,
 | 
				
			||||||
			    struct drm_dp_aux_msg *msg);
 | 
								    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);
 | 
					int drm_dp_aux_register(struct drm_dp_aux *aux);
 | 
				
			||||||
void drm_dp_aux_unregister(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_ */
 | 
					#endif /* _DRM_DP_HELPER_H_ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,7 +302,6 @@ struct drm_driver {
 | 
				
			||||||
	void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
 | 
						void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int (*debugfs_init)(struct drm_minor *minor);
 | 
						int (*debugfs_init)(struct drm_minor *minor);
 | 
				
			||||||
	void (*debugfs_cleanup)(struct drm_minor *minor);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @gem_free_object: deconstructor for drm_gem_objects
 | 
						 * @gem_free_object: deconstructor for drm_gem_objects
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										172
									
								
								include/drm/drm_file.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								include/drm/drm_file.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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_ */
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,10 @@
 | 
				
			||||||
 * OTHER DEALINGS IN THE SOFTWARE.
 | 
					 * OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kref.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <drm/drm_vma_manager.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct drm_gem_object - GEM buffer object
 | 
					 * struct drm_gem_object - GEM buffer object
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										75
									
								
								include/drm/drm_pci.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								include/drm/drm_pci.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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_ */
 | 
				
			||||||
							
								
								
									
										80
									
								
								include/drm/drm_prime.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								include/drm/drm_prime.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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__ */
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <drm/drm_mm.h>
 | 
					#include <drm/drm_mm.h>
 | 
				
			||||||
#include <linux/mm.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/rbtree.h>
 | 
					#include <linux/rbtree.h>
 | 
				
			||||||
#include <linux/spinlock.h>
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue