Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
 "This is the main drm pull request for 3.10.
  Wierd bits:
   - OMAP drm changes required OMAP dss changes, in drivers/video, so I
     took them in here.
   - one more fbcon fix for font handover
   - VT switch avoidance in pm code
   - scatterlist helpers for gpu drivers - have acks from akpm
  Highlights:
   - qxl kms driver - driver for the spice qxl virtual GPU
  Nouveau:
   - fermi/kepler VRAM compression
   - GK110/nvf0 modesetting support.
  Tegra:
   - host1x core merged with 2D engine support
  i915:
   - vt switchless resume
   - more valleyview support
   - vblank fixes
   - modesetting pipe config rework
  radeon:
   - UVD engine support
   - SI chip tiling support
   - GPU registers initialisation from golden values.
  exynos:
   - device tree changes
   - fimc block support
  Otherwise:
   - bunches of fixes all over the place."
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (513 commits)
  qxl: update to new idr interfaces.
  drm/nouveau: fix build with nv50->nvc0
  drm/radeon: fix handling of v6 power tables
  drm/radeon: clarify family checks in pm table parsing
  drm/radeon: consolidate UVD clock programming
  drm/radeon: fix UPLL_REF_DIV_MASK definition
  radeon: add bo tracking debugfs
  drm/radeon: add new richland pci ids
  drm/radeon: add some new SI PCI ids
  drm/radeon: fix scratch reg handling for UVD fence
  drm/radeon: allocate SA bo in the requested domain
  drm/radeon: fix possible segfault when parsing pm tables
  drm/radeon: fix endian bugs in atom_allocate_fb_scratch()
  OMAPDSS: TFP410: return EPROBE_DEFER if the i2c adapter not found
  OMAPDSS: VENC: Add error handling for venc_probe_pdata
  OMAPDSS: HDMI: Add error handling for hdmi_probe_pdata
  OMAPDSS: RFBI: Add error handling for rfbi_probe_pdata
  OMAPDSS: DSI: Add error handling for dsi_probe_pdata
  OMAPDSS: SDI: Add error handling for sdi_probe_pdata
  OMAPDSS: DPI: Add error handling for dpi_probe_pdata
  ...
	
	
This commit is contained in:
		
				commit
				
					
						20a2078ce7
					
				
			
		
					 404 changed files with 29319 additions and 7341 deletions
				
			
		
							
								
								
									
										44
									
								
								Documentation/EDID/1600x1200.S
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Documentation/EDID/1600x1200.S
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | ||||||
|  | /* | ||||||
|  |    1600x1200.S: EDID data set for standard 1600x1200 60 Hz monitor | ||||||
|  | 
 | ||||||
|  |    Copyright (C) 2013 Carsten Emde <C.Emde@osadl.org>
 | ||||||
|  | 
 | ||||||
|  |    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. | ||||||
|  | 
 | ||||||
|  |    This program is distributed in the hope that 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, write to the Free Software
 | ||||||
|  |    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | /* EDID */ | ||||||
|  | #define VERSION 1 | ||||||
|  | #define REVISION 3 | ||||||
|  | 
 | ||||||
|  | /* Display */ | ||||||
|  | #define CLOCK 162000 /* kHz */ | ||||||
|  | #define XPIX 1600 | ||||||
|  | #define YPIX 1200 | ||||||
|  | #define XY_RATIO XY_RATIO_4_3 | ||||||
|  | #define XBLANK 560 | ||||||
|  | #define YBLANK 50 | ||||||
|  | #define XOFFSET 64 | ||||||
|  | #define XPULSE 192 | ||||||
|  | #define YOFFSET (63+1) | ||||||
|  | #define YPULSE (63+3) | ||||||
|  | #define DPI 72 | ||||||
|  | #define VFREQ 60 /* Hz */ | ||||||
|  | #define TIMING_NAME "Linux UXGA" | ||||||
|  | #define ESTABLISHED_TIMINGS_BITS 0x00 /* none */ | ||||||
|  | #define HSYNC_POL 1 | ||||||
|  | #define VSYNC_POL 1 | ||||||
|  | #define CRC 0x9d | ||||||
|  | 
 | ||||||
|  | #include "edid.S" | ||||||
|  | @ -18,12 +18,12 @@ CONFIG_DRM_LOAD_EDID_FIRMWARE was introduced. It allows to provide an | ||||||
| individually prepared or corrected EDID data set in the /lib/firmware | individually prepared or corrected EDID data set in the /lib/firmware | ||||||
| directory from where it is loaded via the firmware interface. The code | directory from where it is loaded via the firmware interface. The code | ||||||
| (see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for | (see drivers/gpu/drm/drm_edid_load.c) contains built-in data sets for | ||||||
| commonly used screen resolutions (1024x768, 1280x1024, 1680x1050, | commonly used screen resolutions (1024x768, 1280x1024, 1600x1200, | ||||||
| 1920x1080) as binary blobs, but the kernel source tree does not contain | 1680x1050, 1920x1080) as binary blobs, but the kernel source tree does | ||||||
| code to create these data. In order to elucidate the origin of the | not contain code to create these data. In order to elucidate the origin | ||||||
| built-in binary EDID blobs and to facilitate the creation of individual | of the built-in binary EDID blobs and to facilitate the creation of | ||||||
| data for a specific misbehaving monitor, commented sources and a | individual data for a specific misbehaving monitor, commented sources | ||||||
| Makefile environment are given here. | and a Makefile environment are given here. | ||||||
| 
 | 
 | ||||||
| To create binary EDID and C source code files from the existing data | To create binary EDID and C source code files from the existing data | ||||||
| material, simply type "make". | material, simply type "make". | ||||||
|  |  | ||||||
|  | @ -1,22 +0,0 @@ | ||||||
| Samsung 2D Graphic Accelerator using DRM frame work |  | ||||||
| 
 |  | ||||||
| Samsung FIMG2D is a graphics 2D accelerator which supports Bit Block Transfer. |  | ||||||
| We set the drawing-context registers for configuring rendering parameters and |  | ||||||
| then start rendering. |  | ||||||
| This driver is for SOCs which contain G2D IPs with version 4.1. |  | ||||||
| 
 |  | ||||||
| Required properties: |  | ||||||
| 	-compatible: |  | ||||||
| 		should be "samsung,exynos-g2d-41". |  | ||||||
| 	-reg: |  | ||||||
| 		physical base address of the controller and length |  | ||||||
| 		of memory mapped region. |  | ||||||
| 	-interrupts: |  | ||||||
| 		interrupt combiner values. |  | ||||||
| 
 |  | ||||||
| Example: |  | ||||||
| 	g2d { |  | ||||||
| 		compatible = "samsung,exynos-g2d-41"; |  | ||||||
| 		reg = <0x10850000 0x1000>; |  | ||||||
| 		interrupts = <0 91 0>; |  | ||||||
| 	}; |  | ||||||
|  | @ -38,7 +38,7 @@ | ||||||
| #include "gpmc-smc91x.h" | #include "gpmc-smc91x.h" | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| 
 | 
 | ||||||
| #include "mux.h" | #include "mux.h" | ||||||
| #include "hsmmc.h" | #include "hsmmc.h" | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ | ||||||
| #include "common.h" | #include "common.h" | ||||||
| #include <linux/omap-dma.h> | #include <linux/omap-dma.h> | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-tfp410.h> | #include <video/omap-panel-data.h> | ||||||
| 
 | 
 | ||||||
| #include "gpmc.h" | #include "gpmc.h" | ||||||
| #include "gpmc-smc91x.h" | #include "gpmc-smc91x.h" | ||||||
|  |  | ||||||
|  | @ -35,8 +35,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| #include <video/omap-panel-tfp410.h> |  | ||||||
| 
 | 
 | ||||||
| #include "am35xx-emac.h" | #include "am35xx-emac.h" | ||||||
| #include "mux.h" | #include "mux.h" | ||||||
|  |  | ||||||
|  | @ -41,8 +41,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/platform_data/mtd-nand-omap2.h> | #include <linux/platform_data/mtd-nand-omap2.h> | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| #include <video/omap-panel-tfp410.h> |  | ||||||
| #include <linux/platform_data/spi-omap2-mcspi.h> | #include <linux/platform_data/spi-omap2-mcspi.h> | ||||||
| 
 | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
|  |  | ||||||
|  | @ -43,8 +43,7 @@ | ||||||
| #include "gpmc.h" | #include "gpmc.h" | ||||||
| #include <linux/platform_data/mtd-nand-omap2.h> | #include <linux/platform_data/mtd-nand-omap2.h> | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| #include <video/omap-panel-tfp410.h> |  | ||||||
| 
 | 
 | ||||||
| #include <linux/platform_data/spi-omap2-mcspi.h> | #include <linux/platform_data/spi-omap2-mcspi.h> | ||||||
| #include <linux/input/matrix_keypad.h> | #include <linux/input/matrix_keypad.h> | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ | ||||||
| #include <asm/mach/map.h> | #include <asm/mach/map.h> | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| 
 | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
| #include "mux.h" | #include "mux.h" | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ | ||||||
| #include <asm/mach/arch.h> | #include <asm/mach/arch.h> | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-tfp410.h> | #include <video/omap-panel-data.h> | ||||||
| #include <linux/platform_data/mtd-onenand-omap2.h> | #include <linux/platform_data/mtd-onenand-omap2.h> | ||||||
| 
 | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ | ||||||
| #include "gpmc-smsc911x.h" | #include "gpmc-smsc911x.h" | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| 
 | 
 | ||||||
| #include "board-flash.h" | #include "board-flash.h" | ||||||
| #include "mux.h" | #include "mux.h" | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ | ||||||
| #include <asm/mach/flash.h> | #include <asm/mach/flash.h> | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-tfp410.h> | #include <video/omap-panel-data.h> | ||||||
| #include <linux/platform_data/mtd-nand-omap2.h> | #include <linux/platform_data/mtd-nand-omap2.h> | ||||||
| 
 | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ | ||||||
| #include "common.h" | #include "common.h" | ||||||
| #include <linux/platform_data/spi-omap2-mcspi.h> | #include <linux/platform_data/spi-omap2-mcspi.h> | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-tfp410.h> | #include <video/omap-panel-data.h> | ||||||
| 
 | 
 | ||||||
| #include "soc.h" | #include "soc.h" | ||||||
| #include "mux.h" | #include "mux.h" | ||||||
|  |  | ||||||
|  | @ -44,8 +44,7 @@ | ||||||
| #include "gpmc.h" | #include "gpmc.h" | ||||||
| #include <linux/platform_data/mtd-nand-omap2.h> | #include <linux/platform_data/mtd-nand-omap2.h> | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| #include <video/omap-panel-tfp410.h> |  | ||||||
| 
 | 
 | ||||||
| #include <linux/platform_data/spi-omap2-mcspi.h> | #include <linux/platform_data/spi-omap2-mcspi.h> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -47,8 +47,7 @@ | ||||||
| #include <asm/mach/map.h> | #include <asm/mach/map.h> | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-generic-dpi.h> | #include <video/omap-panel-data.h> | ||||||
| #include <video/omap-panel-tfp410.h> |  | ||||||
| 
 | 
 | ||||||
| #include "common.h" | #include "common.h" | ||||||
| #include "mux.h" | #include "mux.h" | ||||||
|  |  | ||||||
|  | @ -27,9 +27,7 @@ | ||||||
| #include <linux/gpio.h> | #include <linux/gpio.h> | ||||||
| 
 | 
 | ||||||
| #include <video/omapdss.h> | #include <video/omapdss.h> | ||||||
| #include <video/omap-panel-tfp410.h> | #include <video/omap-panel-data.h> | ||||||
| #include <video/omap-panel-nokia-dsi.h> |  | ||||||
| #include <video/omap-panel-picodlp.h> |  | ||||||
| 
 | 
 | ||||||
| #include "soc.h" | #include "soc.h" | ||||||
| #include "dss-common.h" | #include "dss-common.h" | ||||||
|  |  | ||||||
|  | @ -1 +1,2 @@ | ||||||
| obj-y			+= drm/ vga/ | obj-y			+= drm/ vga/ | ||||||
|  | obj-$(CONFIG_TEGRA_HOST1X)	+= host1x/ | ||||||
|  |  | ||||||
|  | @ -215,8 +215,8 @@ source "drivers/gpu/drm/cirrus/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/gpu/drm/shmobile/Kconfig" | source "drivers/gpu/drm/shmobile/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/gpu/drm/tegra/Kconfig" |  | ||||||
| 
 |  | ||||||
| source "drivers/gpu/drm/omapdrm/Kconfig" | source "drivers/gpu/drm/omapdrm/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/gpu/drm/tilcdc/Kconfig" | source "drivers/gpu/drm/tilcdc/Kconfig" | ||||||
|  | 
 | ||||||
|  | source "drivers/gpu/drm/qxl/Kconfig" | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/ | ||||||
| obj-$(CONFIG_DRM_UDL) += udl/ | obj-$(CONFIG_DRM_UDL) += udl/ | ||||||
| obj-$(CONFIG_DRM_AST) += ast/ | obj-$(CONFIG_DRM_AST) += ast/ | ||||||
| obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ | obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ | ||||||
| obj-$(CONFIG_DRM_TEGRA) += tegra/ |  | ||||||
| obj-$(CONFIG_DRM_OMAP)	+= omapdrm/ | obj-$(CONFIG_DRM_OMAP)	+= omapdrm/ | ||||||
| obj-$(CONFIG_DRM_TILCDC)	+= tilcdc/ | obj-$(CONFIG_DRM_TILCDC)	+= tilcdc/ | ||||||
|  | obj-$(CONFIG_DRM_QXL) += qxl/ | ||||||
| obj-y			+= i2c/ | obj-y			+= i2c/ | ||||||
|  |  | ||||||
|  | @ -241,6 +241,8 @@ struct ast_fbdev { | ||||||
| 	void *sysram; | 	void *sysram; | ||||||
| 	int size; | 	int size; | ||||||
| 	struct ttm_bo_kmap_obj mapping; | 	struct ttm_bo_kmap_obj mapping; | ||||||
|  | 	int x1, y1, x2, y2; /* dirty rect */ | ||||||
|  | 	spinlock_t dirty_lock; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define to_ast_crtc(x) container_of(x, struct ast_crtc, base) | #define to_ast_crtc(x) container_of(x, struct ast_crtc, base) | ||||||
|  |  | ||||||
|  | @ -53,16 +53,52 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, | ||||||
| 	int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8; | 	int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	bool unmap = false; | 	bool unmap = false; | ||||||
|  | 	bool store_for_later = false; | ||||||
|  | 	int x2, y2; | ||||||
|  | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
| 	obj = afbdev->afb.obj; | 	obj = afbdev->afb.obj; | ||||||
| 	bo = gem_to_ast_bo(obj); | 	bo = gem_to_ast_bo(obj); | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * try and reserve the BO, if we fail with busy | ||||||
|  | 	 * then the BO is being moved and we should | ||||||
|  | 	 * store up the damage until later. | ||||||
|  | 	 */ | ||||||
| 	ret = ast_bo_reserve(bo, true); | 	ret = ast_bo_reserve(bo, true); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		DRM_ERROR("failed to reserve fb bo\n"); | 		if (ret != -EBUSY) | ||||||
|  | 			return; | ||||||
|  | 
 | ||||||
|  | 		store_for_later = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	x2 = x + width - 1; | ||||||
|  | 	y2 = y + height - 1; | ||||||
|  | 	spin_lock_irqsave(&afbdev->dirty_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	if (afbdev->y1 < y) | ||||||
|  | 		y = afbdev->y1; | ||||||
|  | 	if (afbdev->y2 > y2) | ||||||
|  | 		y2 = afbdev->y2; | ||||||
|  | 	if (afbdev->x1 < x) | ||||||
|  | 		x = afbdev->x1; | ||||||
|  | 	if (afbdev->x2 > x2) | ||||||
|  | 		x2 = afbdev->x2; | ||||||
|  | 
 | ||||||
|  | 	if (store_for_later) { | ||||||
|  | 		afbdev->x1 = x; | ||||||
|  | 		afbdev->x2 = x2; | ||||||
|  | 		afbdev->y1 = y; | ||||||
|  | 		afbdev->y2 = y2; | ||||||
|  | 		spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	afbdev->x1 = afbdev->y1 = INT_MAX; | ||||||
|  | 	afbdev->x2 = afbdev->y2 = 0; | ||||||
|  | 	spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | ||||||
|  | 
 | ||||||
| 	if (!bo->kmap.virtual) { | 	if (!bo->kmap.virtual) { | ||||||
| 		ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 		ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
|  | @ -72,10 +108,10 @@ static void ast_dirty_update(struct ast_fbdev *afbdev, | ||||||
| 		} | 		} | ||||||
| 		unmap = true; | 		unmap = true; | ||||||
| 	} | 	} | ||||||
| 	for (i = y; i < y + height; i++) { | 	for (i = y; i <= y2; i++) { | ||||||
| 		/* assume equal stride for now */ | 		/* assume equal stride for now */ | ||||||
| 		src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp); | 		src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp); | ||||||
| 		memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp); | 		memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, (x2 - x + 1) * bpp); | ||||||
| 
 | 
 | ||||||
| 	} | 	} | ||||||
| 	if (unmap) | 	if (unmap) | ||||||
|  | @ -292,6 +328,7 @@ int ast_fbdev_init(struct drm_device *dev) | ||||||
| 
 | 
 | ||||||
| 	ast->fbdev = afbdev; | 	ast->fbdev = afbdev; | ||||||
| 	afbdev->helper.funcs = &ast_fb_helper_funcs; | 	afbdev->helper.funcs = &ast_fb_helper_funcs; | ||||||
|  | 	spin_lock_init(&afbdev->dirty_lock); | ||||||
| 	ret = drm_fb_helper_init(dev, &afbdev->helper, | 	ret = drm_fb_helper_init(dev, &afbdev->helper, | ||||||
| 				 1, 1); | 				 1, 1); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
|  |  | ||||||
|  | @ -316,7 +316,7 @@ int ast_bo_reserve(struct ast_bo *bo, bool no_wait) | ||||||
| 
 | 
 | ||||||
| 	ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | 	ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		if (ret != -ERESTARTSYS) | 		if (ret != -ERESTARTSYS && ret != -EBUSY) | ||||||
| 			DRM_ERROR("reserve failed %p\n", bo); | 			DRM_ERROR("reserve failed %p\n", bo); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -154,6 +154,8 @@ struct cirrus_fbdev { | ||||||
| 	struct list_head fbdev_list; | 	struct list_head fbdev_list; | ||||||
| 	void *sysram; | 	void *sysram; | ||||||
| 	int size; | 	int size; | ||||||
|  | 	int x1, y1, x2, y2; /* dirty rect */ | ||||||
|  | 	spinlock_t dirty_lock; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct cirrus_bo { | struct cirrus_bo { | ||||||
|  |  | ||||||
|  | @ -27,16 +27,51 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev, | ||||||
| 	int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; | 	int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	bool unmap = false; | 	bool unmap = false; | ||||||
|  | 	bool store_for_later = false; | ||||||
|  | 	int x2, y2; | ||||||
|  | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
| 	obj = afbdev->gfb.obj; | 	obj = afbdev->gfb.obj; | ||||||
| 	bo = gem_to_cirrus_bo(obj); | 	bo = gem_to_cirrus_bo(obj); | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * try and reserve the BO, if we fail with busy | ||||||
|  | 	 * then the BO is being moved and we should | ||||||
|  | 	 * store up the damage until later. | ||||||
|  | 	 */ | ||||||
| 	ret = cirrus_bo_reserve(bo, true); | 	ret = cirrus_bo_reserve(bo, true); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		DRM_ERROR("failed to reserve fb bo\n"); | 		if (ret != -EBUSY) | ||||||
|  | 			return; | ||||||
|  | 		store_for_later = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	x2 = x + width - 1; | ||||||
|  | 	y2 = y + height - 1; | ||||||
|  | 	spin_lock_irqsave(&afbdev->dirty_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	if (afbdev->y1 < y) | ||||||
|  | 		y = afbdev->y1; | ||||||
|  | 	if (afbdev->y2 > y2) | ||||||
|  | 		y2 = afbdev->y2; | ||||||
|  | 	if (afbdev->x1 < x) | ||||||
|  | 		x = afbdev->x1; | ||||||
|  | 	if (afbdev->x2 > x2) | ||||||
|  | 		x2 = afbdev->x2; | ||||||
|  | 
 | ||||||
|  | 	if (store_for_later) { | ||||||
|  | 		afbdev->x1 = x; | ||||||
|  | 		afbdev->x2 = x2; | ||||||
|  | 		afbdev->y1 = y; | ||||||
|  | 		afbdev->y2 = y2; | ||||||
|  | 		spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	afbdev->x1 = afbdev->y1 = INT_MAX; | ||||||
|  | 	afbdev->x2 = afbdev->y2 = 0; | ||||||
|  | 	spin_unlock_irqrestore(&afbdev->dirty_lock, flags); | ||||||
|  | 
 | ||||||
| 	if (!bo->kmap.virtual) { | 	if (!bo->kmap.virtual) { | ||||||
| 		ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | 		ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
|  | @ -268,6 +303,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev) | ||||||
| 
 | 
 | ||||||
| 	cdev->mode_info.gfbdev = gfbdev; | 	cdev->mode_info.gfbdev = gfbdev; | ||||||
| 	gfbdev->helper.funcs = &cirrus_fb_helper_funcs; | 	gfbdev->helper.funcs = &cirrus_fb_helper_funcs; | ||||||
|  | 	spin_lock_init(&gfbdev->dirty_lock); | ||||||
| 
 | 
 | ||||||
| 	ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, | 	ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, | ||||||
| 				 cdev->num_crtc, CIRRUSFB_CONN_LIMIT); | 				 cdev->num_crtc, CIRRUSFB_CONN_LIMIT); | ||||||
|  |  | ||||||
|  | @ -321,7 +321,7 @@ int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait) | ||||||
| 
 | 
 | ||||||
| 	ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | 	ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		if (ret != -ERESTARTSYS) | 		if (ret != -ERESTARTSYS && ret != -EBUSY) | ||||||
| 			DRM_ERROR("reserve failed %p\n", bo); | 			DRM_ERROR("reserve failed %p\n", bo); | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -105,12 +105,11 @@ drm_clflush_sg(struct sg_table *st) | ||||||
| { | { | ||||||
| #if defined(CONFIG_X86) | #if defined(CONFIG_X86) | ||||||
| 	if (cpu_has_clflush) { | 	if (cpu_has_clflush) { | ||||||
| 		struct scatterlist *sg; | 		struct sg_page_iter sg_iter; | ||||||
| 		int i; |  | ||||||
| 
 | 
 | ||||||
| 		mb(); | 		mb(); | ||||||
| 		for_each_sg(st->sgl, sg, st->nents, i) | 		for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) | ||||||
| 			drm_clflush_page(sg_page(sg)); | 			drm_clflush_page(sg_page_iter_page(&sg_iter)); | ||||||
| 		mb(); | 		mb(); | ||||||
| 
 | 
 | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
|  | @ -178,9 +178,6 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { | ||||||
| 	{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, | 	{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| DRM_ENUM_NAME_FN(drm_get_dirty_info_name, |  | ||||||
| 		 drm_dirty_info_enum_list) |  | ||||||
| 
 |  | ||||||
| struct drm_conn_prop_enum_list { | struct drm_conn_prop_enum_list { | ||||||
| 	int type; | 	int type; | ||||||
| 	char *name; | 	char *name; | ||||||
|  | @ -412,7 +409,7 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, | ||||||
| 	mutex_lock(&dev->mode_config.fb_lock); | 	mutex_lock(&dev->mode_config.fb_lock); | ||||||
| 	fb = __drm_framebuffer_lookup(dev, id); | 	fb = __drm_framebuffer_lookup(dev, id); | ||||||
| 	if (fb) | 	if (fb) | ||||||
| 		kref_get(&fb->refcount); | 		drm_framebuffer_reference(fb); | ||||||
| 	mutex_unlock(&dev->mode_config.fb_lock); | 	mutex_unlock(&dev->mode_config.fb_lock); | ||||||
| 
 | 
 | ||||||
| 	return fb; | 	return fb; | ||||||
|  | @ -706,7 +703,6 @@ int drm_connector_init(struct drm_device *dev, | ||||||
| 	connector->connector_type = connector_type; | 	connector->connector_type = connector_type; | ||||||
| 	connector->connector_type_id = | 	connector->connector_type_id = | ||||||
| 		++drm_connector_enum_list[connector_type].count; /* TODO */ | 		++drm_connector_enum_list[connector_type].count; /* TODO */ | ||||||
| 	INIT_LIST_HEAD(&connector->user_modes); |  | ||||||
| 	INIT_LIST_HEAD(&connector->probed_modes); | 	INIT_LIST_HEAD(&connector->probed_modes); | ||||||
| 	INIT_LIST_HEAD(&connector->modes); | 	INIT_LIST_HEAD(&connector->modes); | ||||||
| 	connector->edid_blob_ptr = NULL; | 	connector->edid_blob_ptr = NULL; | ||||||
|  | @ -747,9 +743,6 @@ void drm_connector_cleanup(struct drm_connector *connector) | ||||||
| 	list_for_each_entry_safe(mode, t, &connector->modes, head) | 	list_for_each_entry_safe(mode, t, &connector->modes, head) | ||||||
| 		drm_mode_remove(connector, mode); | 		drm_mode_remove(connector, mode); | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry_safe(mode, t, &connector->user_modes, head) |  | ||||||
| 		drm_mode_remove(connector, mode); |  | ||||||
| 
 |  | ||||||
| 	drm_mode_object_put(dev, &connector->base); | 	drm_mode_object_put(dev, &connector->base); | ||||||
| 	list_del(&connector->head); | 	list_del(&connector->head); | ||||||
| 	dev->mode_config.num_connector--; | 	dev->mode_config.num_connector--; | ||||||
|  | @ -1120,45 +1113,7 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_mode_create_dirty_info_property); | EXPORT_SYMBOL(drm_mode_create_dirty_info_property); | ||||||
| 
 | 
 | ||||||
| /**
 | static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) | ||||||
|  * drm_mode_config_init - initialize DRM mode_configuration structure |  | ||||||
|  * @dev: DRM device |  | ||||||
|  * |  | ||||||
|  * Initialize @dev's mode_config structure, used for tracking the graphics |  | ||||||
|  * configuration of @dev. |  | ||||||
|  * |  | ||||||
|  * Since this initializes the modeset locks, no locking is possible. Which is no |  | ||||||
|  * problem, since this should happen single threaded at init time. It is the |  | ||||||
|  * driver's problem to ensure this guarantee. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| void drm_mode_config_init(struct drm_device *dev) |  | ||||||
| { |  | ||||||
| 	mutex_init(&dev->mode_config.mutex); |  | ||||||
| 	mutex_init(&dev->mode_config.idr_mutex); |  | ||||||
| 	mutex_init(&dev->mode_config.fb_lock); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.fb_list); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.crtc_list); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.connector_list); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.encoder_list); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.property_list); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |  | ||||||
| 	INIT_LIST_HEAD(&dev->mode_config.plane_list); |  | ||||||
| 	idr_init(&dev->mode_config.crtc_idr); |  | ||||||
| 
 |  | ||||||
| 	drm_modeset_lock_all(dev); |  | ||||||
| 	drm_mode_create_standard_connector_properties(dev); |  | ||||||
| 	drm_modeset_unlock_all(dev); |  | ||||||
| 
 |  | ||||||
| 	/* Just to be sure */ |  | ||||||
| 	dev->mode_config.num_fb = 0; |  | ||||||
| 	dev->mode_config.num_connector = 0; |  | ||||||
| 	dev->mode_config.num_crtc = 0; |  | ||||||
| 	dev->mode_config.num_encoder = 0; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(drm_mode_config_init); |  | ||||||
| 
 |  | ||||||
| int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) |  | ||||||
| { | { | ||||||
| 	uint32_t total_objects = 0; | 	uint32_t total_objects = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -1202,69 +1157,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_mode_group_init_legacy_group); | EXPORT_SYMBOL(drm_mode_group_init_legacy_group); | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * drm_mode_config_cleanup - free up DRM mode_config info |  | ||||||
|  * @dev: DRM device |  | ||||||
|  * |  | ||||||
|  * Free up all the connectors and CRTCs associated with this DRM device, then |  | ||||||
|  * free up the framebuffers and associated buffer objects. |  | ||||||
|  * |  | ||||||
|  * Note that since this /should/ happen single-threaded at driver/device |  | ||||||
|  * teardown time, no locking is required. It's the driver's job to ensure that |  | ||||||
|  * this guarantee actually holds true. |  | ||||||
|  * |  | ||||||
|  * FIXME: cleanup any dangling user buffer objects too |  | ||||||
|  */ |  | ||||||
| void drm_mode_config_cleanup(struct drm_device *dev) |  | ||||||
| { |  | ||||||
| 	struct drm_connector *connector, *ot; |  | ||||||
| 	struct drm_crtc *crtc, *ct; |  | ||||||
| 	struct drm_encoder *encoder, *enct; |  | ||||||
| 	struct drm_framebuffer *fb, *fbt; |  | ||||||
| 	struct drm_property *property, *pt; |  | ||||||
| 	struct drm_plane *plane, *plt; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, |  | ||||||
| 				 head) { |  | ||||||
| 		encoder->funcs->destroy(encoder); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(connector, ot, |  | ||||||
| 				 &dev->mode_config.connector_list, head) { |  | ||||||
| 		connector->funcs->destroy(connector); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, |  | ||||||
| 				 head) { |  | ||||||
| 		drm_property_destroy(dev, property); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * Single-threaded teardown context, so it's not required to grab the |  | ||||||
| 	 * fb_lock to protect against concurrent fb_list access. Contrary, it |  | ||||||
| 	 * would actually deadlock with the drm_framebuffer_cleanup function. |  | ||||||
| 	 * |  | ||||||
| 	 * Also, if there are any framebuffers left, that's a driver leak now, |  | ||||||
| 	 * so politely WARN about this. |  | ||||||
| 	 */ |  | ||||||
| 	WARN_ON(!list_empty(&dev->mode_config.fb_list)); |  | ||||||
| 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { |  | ||||||
| 		drm_framebuffer_remove(fb); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, |  | ||||||
| 				 head) { |  | ||||||
| 		plane->funcs->destroy(plane); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { |  | ||||||
| 		crtc->funcs->destroy(crtc); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	idr_destroy(&dev->mode_config.crtc_idr); |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(drm_mode_config_cleanup); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo |  * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo | ||||||
|  * @out: drm_mode_modeinfo struct to return to the user |  * @out: drm_mode_modeinfo struct to return to the user | ||||||
|  | @ -2717,192 +2609,6 @@ void drm_fb_release(struct drm_file *priv) | ||||||
| 	mutex_unlock(&priv->fbs_lock); | 	mutex_unlock(&priv->fbs_lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * drm_mode_attachmode - add a mode to the user mode list |  | ||||||
|  * @dev: DRM device |  | ||||||
|  * @connector: connector to add the mode to |  | ||||||
|  * @mode: mode to add |  | ||||||
|  * |  | ||||||
|  * Add @mode to @connector's user mode list. |  | ||||||
|  */ |  | ||||||
| static void drm_mode_attachmode(struct drm_device *dev, |  | ||||||
| 				struct drm_connector *connector, |  | ||||||
| 				struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	list_add_tail(&mode->head, &connector->user_modes); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, |  | ||||||
| 			     const struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	struct drm_connector *connector; |  | ||||||
| 	int ret = 0; |  | ||||||
| 	struct drm_display_mode *dup_mode, *next; |  | ||||||
| 	LIST_HEAD(list); |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |  | ||||||
| 		if (!connector->encoder) |  | ||||||
| 			continue; |  | ||||||
| 		if (connector->encoder->crtc == crtc) { |  | ||||||
| 			dup_mode = drm_mode_duplicate(dev, mode); |  | ||||||
| 			if (!dup_mode) { |  | ||||||
| 				ret = -ENOMEM; |  | ||||||
| 				goto out; |  | ||||||
| 			} |  | ||||||
| 			list_add_tail(&dup_mode->head, &list); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |  | ||||||
| 		if (!connector->encoder) |  | ||||||
| 			continue; |  | ||||||
| 		if (connector->encoder->crtc == crtc) |  | ||||||
| 			list_move_tail(list.next, &connector->user_modes); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	WARN_ON(!list_empty(&list)); |  | ||||||
| 
 |  | ||||||
|  out: |  | ||||||
| 	list_for_each_entry_safe(dup_mode, next, &list, head) |  | ||||||
| 		drm_mode_destroy(dev, dup_mode); |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(drm_mode_attachmode_crtc); |  | ||||||
| 
 |  | ||||||
| static int drm_mode_detachmode(struct drm_device *dev, |  | ||||||
| 			       struct drm_connector *connector, |  | ||||||
| 			       struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	int found = 0; |  | ||||||
| 	int ret = 0; |  | ||||||
| 	struct drm_display_mode *match_mode, *t; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { |  | ||||||
| 		if (drm_mode_equal(match_mode, mode)) { |  | ||||||
| 			list_del(&match_mode->head); |  | ||||||
| 			drm_mode_destroy(dev, match_mode); |  | ||||||
| 			found = 1; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!found) |  | ||||||
| 		ret = -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	struct drm_connector *connector; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |  | ||||||
| 		drm_mode_detachmode(dev, connector, mode); |  | ||||||
| 	} |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(drm_mode_detachmode_crtc); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * drm_fb_attachmode - Attach a user mode to an connector |  | ||||||
|  * @dev: drm device for the ioctl |  | ||||||
|  * @data: data pointer for the ioctl |  | ||||||
|  * @file_priv: drm file for the ioctl call |  | ||||||
|  * |  | ||||||
|  * This attaches a user specified mode to an connector. |  | ||||||
|  * Called by the user via ioctl. |  | ||||||
|  * |  | ||||||
|  * RETURNS: |  | ||||||
|  * Zero on success, errno on failure. |  | ||||||
|  */ |  | ||||||
| int drm_mode_attachmode_ioctl(struct drm_device *dev, |  | ||||||
| 			      void *data, struct drm_file *file_priv) |  | ||||||
| { |  | ||||||
| 	struct drm_mode_mode_cmd *mode_cmd = data; |  | ||||||
| 	struct drm_connector *connector; |  | ||||||
| 	struct drm_display_mode *mode; |  | ||||||
| 	struct drm_mode_object *obj; |  | ||||||
| 	struct drm_mode_modeinfo *umode = &mode_cmd->mode; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	if (!drm_core_check_feature(dev, DRIVER_MODESET)) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	drm_modeset_lock_all(dev); |  | ||||||
| 
 |  | ||||||
| 	obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |  | ||||||
| 	if (!obj) { |  | ||||||
| 		ret = -EINVAL; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 	connector = obj_to_connector(obj); |  | ||||||
| 
 |  | ||||||
| 	mode = drm_mode_create(dev); |  | ||||||
| 	if (!mode) { |  | ||||||
| 		ret = -ENOMEM; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = drm_crtc_convert_umode(mode, umode); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_DEBUG_KMS("Invalid mode\n"); |  | ||||||
| 		drm_mode_destroy(dev, mode); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	drm_mode_attachmode(dev, connector, mode); |  | ||||||
| out: |  | ||||||
| 	drm_modeset_unlock_all(dev); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * drm_fb_detachmode - Detach a user specified mode from an connector |  | ||||||
|  * @dev: drm device for the ioctl |  | ||||||
|  * @data: data pointer for the ioctl |  | ||||||
|  * @file_priv: drm file for the ioctl call |  | ||||||
|  * |  | ||||||
|  * Called by the user via ioctl. |  | ||||||
|  * |  | ||||||
|  * RETURNS: |  | ||||||
|  * Zero on success, errno on failure. |  | ||||||
|  */ |  | ||||||
| int drm_mode_detachmode_ioctl(struct drm_device *dev, |  | ||||||
| 			      void *data, struct drm_file *file_priv) |  | ||||||
| { |  | ||||||
| 	struct drm_mode_object *obj; |  | ||||||
| 	struct drm_mode_mode_cmd *mode_cmd = data; |  | ||||||
| 	struct drm_connector *connector; |  | ||||||
| 	struct drm_display_mode mode; |  | ||||||
| 	struct drm_mode_modeinfo *umode = &mode_cmd->mode; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	if (!drm_core_check_feature(dev, DRIVER_MODESET)) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	drm_modeset_lock_all(dev); |  | ||||||
| 
 |  | ||||||
| 	obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); |  | ||||||
| 	if (!obj) { |  | ||||||
| 		ret = -EINVAL; |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 	connector = obj_to_connector(obj); |  | ||||||
| 
 |  | ||||||
| 	ret = drm_crtc_convert_umode(&mode, umode); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_DEBUG_KMS("Invalid mode\n"); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = drm_mode_detachmode(dev, connector, &mode); |  | ||||||
| out: |  | ||||||
| 	drm_modeset_unlock_all(dev); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct drm_property *drm_property_create(struct drm_device *dev, int flags, | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||||||
| 					 const char *name, int num_values) | 					 const char *name, int num_values) | ||||||
| { | { | ||||||
|  | @ -3739,6 +3445,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (crtc->fb->pixel_format != fb->pixel_format) { | ||||||
|  | 		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); | ||||||
|  | 		ret = -EINVAL; | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||||||
| 		ret = -ENOMEM; | 		ret = -ENOMEM; | ||||||
| 		spin_lock_irqsave(&dev->event_lock, flags); | 		spin_lock_irqsave(&dev->event_lock, flags); | ||||||
|  | @ -4064,3 +3776,110 @@ int drm_format_vert_chroma_subsampling(uint32_t format) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); | EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * drm_mode_config_init - initialize DRM mode_configuration structure | ||||||
|  |  * @dev: DRM device | ||||||
|  |  * | ||||||
|  |  * Initialize @dev's mode_config structure, used for tracking the graphics | ||||||
|  |  * configuration of @dev. | ||||||
|  |  * | ||||||
|  |  * Since this initializes the modeset locks, no locking is possible. Which is no | ||||||
|  |  * problem, since this should happen single threaded at init time. It is the | ||||||
|  |  * driver's problem to ensure this guarantee. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | void drm_mode_config_init(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	mutex_init(&dev->mode_config.mutex); | ||||||
|  | 	mutex_init(&dev->mode_config.idr_mutex); | ||||||
|  | 	mutex_init(&dev->mode_config.fb_lock); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.fb_list); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.crtc_list); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.connector_list); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.encoder_list); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.property_list); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list); | ||||||
|  | 	INIT_LIST_HEAD(&dev->mode_config.plane_list); | ||||||
|  | 	idr_init(&dev->mode_config.crtc_idr); | ||||||
|  | 
 | ||||||
|  | 	drm_modeset_lock_all(dev); | ||||||
|  | 	drm_mode_create_standard_connector_properties(dev); | ||||||
|  | 	drm_modeset_unlock_all(dev); | ||||||
|  | 
 | ||||||
|  | 	/* Just to be sure */ | ||||||
|  | 	dev->mode_config.num_fb = 0; | ||||||
|  | 	dev->mode_config.num_connector = 0; | ||||||
|  | 	dev->mode_config.num_crtc = 0; | ||||||
|  | 	dev->mode_config.num_encoder = 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(drm_mode_config_init); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * drm_mode_config_cleanup - free up DRM mode_config info | ||||||
|  |  * @dev: DRM device | ||||||
|  |  * | ||||||
|  |  * Free up all the connectors and CRTCs associated with this DRM device, then | ||||||
|  |  * free up the framebuffers and associated buffer objects. | ||||||
|  |  * | ||||||
|  |  * Note that since this /should/ happen single-threaded at driver/device | ||||||
|  |  * teardown time, no locking is required. It's the driver's job to ensure that | ||||||
|  |  * this guarantee actually holds true. | ||||||
|  |  * | ||||||
|  |  * FIXME: cleanup any dangling user buffer objects too | ||||||
|  |  */ | ||||||
|  | void drm_mode_config_cleanup(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	struct drm_connector *connector, *ot; | ||||||
|  | 	struct drm_crtc *crtc, *ct; | ||||||
|  | 	struct drm_encoder *encoder, *enct; | ||||||
|  | 	struct drm_framebuffer *fb, *fbt; | ||||||
|  | 	struct drm_property *property, *pt; | ||||||
|  | 	struct drm_property_blob *blob, *bt; | ||||||
|  | 	struct drm_plane *plane, *plt; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, | ||||||
|  | 				 head) { | ||||||
|  | 		encoder->funcs->destroy(encoder); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(connector, ot, | ||||||
|  | 				 &dev->mode_config.connector_list, head) { | ||||||
|  | 		connector->funcs->destroy(connector); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, | ||||||
|  | 				 head) { | ||||||
|  | 		drm_property_destroy(dev, property); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, | ||||||
|  | 				 head) { | ||||||
|  | 		drm_property_destroy_blob(dev, blob); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Single-threaded teardown context, so it's not required to grab the | ||||||
|  | 	 * fb_lock to protect against concurrent fb_list access. Contrary, it | ||||||
|  | 	 * would actually deadlock with the drm_framebuffer_cleanup function. | ||||||
|  | 	 * | ||||||
|  | 	 * Also, if there are any framebuffers left, that's a driver leak now, | ||||||
|  | 	 * so politely WARN about this. | ||||||
|  | 	 */ | ||||||
|  | 	WARN_ON(!list_empty(&dev->mode_config.fb_list)); | ||||||
|  | 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { | ||||||
|  | 		drm_framebuffer_remove(fb); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, | ||||||
|  | 				 head) { | ||||||
|  | 		plane->funcs->destroy(plane); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { | ||||||
|  | 		crtc->funcs->destroy(crtc); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	idr_destroy(&dev->mode_config.crtc_idr); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(drm_mode_config_cleanup); | ||||||
|  |  | ||||||
|  | @ -648,6 +648,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) | ||||||
| 		} else if (set->fb->bits_per_pixel != | 		} else if (set->fb->bits_per_pixel != | ||||||
| 			   set->crtc->fb->bits_per_pixel) { | 			   set->crtc->fb->bits_per_pixel) { | ||||||
| 			mode_changed = true; | 			mode_changed = true; | ||||||
|  | 		} else if (set->fb->pixel_format != | ||||||
|  | 			   set->crtc->fb->pixel_format) { | ||||||
|  | 			mode_changed = true; | ||||||
| 		} else | 		} else | ||||||
| 			fb_changed = true; | 			fb_changed = true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -60,7 +60,7 @@ static int drm_version(struct drm_device *dev, void *data, | ||||||
| 	[DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} | 	[DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} | ||||||
| 
 | 
 | ||||||
| /** Ioctl table */ | /** Ioctl table */ | ||||||
| static struct drm_ioctl_desc drm_ioctls[] = { | static const struct drm_ioctl_desc drm_ioctls[] = { | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), | 	DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), | 	DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), | ||||||
|  | @ -150,8 +150,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
| 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), | ||||||
|  | @ -375,7 +375,7 @@ long drm_ioctl(struct file *filp, | ||||||
| { | { | ||||||
| 	struct drm_file *file_priv = filp->private_data; | 	struct drm_file *file_priv = filp->private_data; | ||||||
| 	struct drm_device *dev; | 	struct drm_device *dev; | ||||||
| 	struct drm_ioctl_desc *ioctl; | 	const struct drm_ioctl_desc *ioctl; | ||||||
| 	drm_ioctl_t *func; | 	drm_ioctl_t *func; | ||||||
| 	unsigned int nr = DRM_IOCTL_NR(cmd); | 	unsigned int nr = DRM_IOCTL_NR(cmd); | ||||||
| 	int retcode = -EINVAL; | 	int retcode = -EINVAL; | ||||||
|  | @ -408,6 +408,7 @@ long drm_ioctl(struct file *filp, | ||||||
| 		usize = asize = _IOC_SIZE(cmd); | 		usize = asize = _IOC_SIZE(cmd); | ||||||
| 		if (drv_size > asize) | 		if (drv_size > asize) | ||||||
| 			asize = drv_size; | 			asize = drv_size; | ||||||
|  | 		cmd = ioctl->cmd_drv; | ||||||
| 	} | 	} | ||||||
| 	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { | 	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { | ||||||
| 		ioctl = &drm_ioctls[nr]; | 		ioctl = &drm_ioctls[nr]; | ||||||
|  |  | ||||||
|  | @ -587,284 +587,348 @@ static const struct drm_display_mode edid_cea_modes[] = { | ||||||
| 	/* 1 - 640x480@60Hz */ | 	/* 1 - 640x480@60Hz */ | ||||||
| 	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, | 	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, | ||||||
| 		   752, 800, 0, 480, 490, 492, 525, 0, | 		   752, 800, 0, 480, 490, 492, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 2 - 720x480@60Hz */ | 	/* 2 - 720x480@60Hz */ | ||||||
| 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, | 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, | ||||||
| 		   798, 858, 0, 480, 489, 495, 525, 0, | 		   798, 858, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 3 - 720x480@60Hz */ | 	/* 3 - 720x480@60Hz */ | ||||||
| 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, | 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, | ||||||
| 		   798, 858, 0, 480, 489, 495, 525, 0, | 		   798, 858, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 4 - 1280x720@60Hz */ | 	/* 4 - 1280x720@60Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, | ||||||
| 		   1430, 1650, 0, 720, 725, 730, 750, 0, | 		   1430, 1650, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 5 - 1920x1080i@60Hz */ | 	/* 5 - 1920x1080i@60Hz */ | ||||||
| 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, | 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, | ||||||
| 		   2052, 2200, 0, 1080, 1084, 1094, 1125, 0, | 		   2052, 2200, 0, 1080, 1084, 1094, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 6 - 1440x480i@60Hz */ | 	/* 6 - 1440x480i@60Hz */ | ||||||
| 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 480, 488, 494, 525, 0, | 		   1602, 1716, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 7 - 1440x480i@60Hz */ | 	/* 7 - 1440x480i@60Hz */ | ||||||
| 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 480, 488, 494, 525, 0, | 		   1602, 1716, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 8 - 1440x240@60Hz */ | 	/* 8 - 1440x240@60Hz */ | ||||||
| 	{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | 	{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 240, 244, 247, 262, 0, | 		   1602, 1716, 0, 240, 244, 247, 262, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 9 - 1440x240@60Hz */ | 	/* 9 - 1440x240@60Hz */ | ||||||
| 	{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | 	{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 240, 244, 247, 262, 0, | 		   1602, 1716, 0, 240, 244, 247, 262, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 10 - 2880x480i@60Hz */ | 	/* 10 - 2880x480i@60Hz */ | ||||||
| 	{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | 	{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | ||||||
| 		   3204, 3432, 0, 480, 488, 494, 525, 0, | 		   3204, 3432, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 11 - 2880x480i@60Hz */ | 	/* 11 - 2880x480i@60Hz */ | ||||||
| 	{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | 	{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | ||||||
| 		   3204, 3432, 0, 480, 488, 494, 525, 0, | 		   3204, 3432, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 12 - 2880x240@60Hz */ | 	/* 12 - 2880x240@60Hz */ | ||||||
| 	{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | 	{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | ||||||
| 		   3204, 3432, 0, 240, 244, 247, 262, 0, | 		   3204, 3432, 0, 240, 244, 247, 262, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 13 - 2880x240@60Hz */ | 	/* 13 - 2880x240@60Hz */ | ||||||
| 	{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | 	{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, | ||||||
| 		   3204, 3432, 0, 240, 244, 247, 262, 0, | 		   3204, 3432, 0, 240, 244, 247, 262, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 14 - 1440x480@60Hz */ | 	/* 14 - 1440x480@60Hz */ | ||||||
| 	{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, | 	{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, | ||||||
| 		   1596, 1716, 0, 480, 489, 495, 525, 0, | 		   1596, 1716, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 15 - 1440x480@60Hz */ | 	/* 15 - 1440x480@60Hz */ | ||||||
| 	{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, | 	{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472, | ||||||
| 		   1596, 1716, 0, 480, 489, 495, 525, 0, | 		   1596, 1716, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 16 - 1920x1080@60Hz */ | 	/* 16 - 1920x1080@60Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, | ||||||
| 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 17 - 720x576@50Hz */ | 	/* 17 - 720x576@50Hz */ | ||||||
| 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, | 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, | ||||||
| 		   796, 864, 0, 576, 581, 586, 625, 0, | 		   796, 864, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 18 - 720x576@50Hz */ | 	/* 18 - 720x576@50Hz */ | ||||||
| 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, | 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, | ||||||
| 		   796, 864, 0, 576, 581, 586, 625, 0, | 		   796, 864, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 19 - 1280x720@50Hz */ | 	/* 19 - 1280x720@50Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, | ||||||
| 		   1760, 1980, 0, 720, 725, 730, 750, 0, | 		   1760, 1980, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 20 - 1920x1080i@50Hz */ | 	/* 20 - 1920x1080i@50Hz */ | ||||||
| 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, | 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, | ||||||
| 		   2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | 		   2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 21 - 1440x576i@50Hz */ | 	/* 21 - 1440x576i@50Hz */ | ||||||
| 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 576, 580, 586, 625, 0, | 		   1590, 1728, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 22 - 1440x576i@50Hz */ | 	/* 22 - 1440x576i@50Hz */ | ||||||
| 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 576, 580, 586, 625, 0, | 		   1590, 1728, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 23 - 1440x288@50Hz */ | 	/* 23 - 1440x288@50Hz */ | ||||||
| 	{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | 	{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 288, 290, 293, 312, 0, | 		   1590, 1728, 0, 288, 290, 293, 312, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 24 - 1440x288@50Hz */ | 	/* 24 - 1440x288@50Hz */ | ||||||
| 	{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | 	{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 288, 290, 293, 312, 0, | 		   1590, 1728, 0, 288, 290, 293, 312, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 25 - 2880x576i@50Hz */ | 	/* 25 - 2880x576i@50Hz */ | ||||||
| 	{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | 	{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | ||||||
| 		   3180, 3456, 0, 576, 580, 586, 625, 0, | 		   3180, 3456, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 26 - 2880x576i@50Hz */ | 	/* 26 - 2880x576i@50Hz */ | ||||||
| 	{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | 	{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | ||||||
| 		   3180, 3456, 0, 576, 580, 586, 625, 0, | 		   3180, 3456, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 27 - 2880x288@50Hz */ | 	/* 27 - 2880x288@50Hz */ | ||||||
| 	{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | 	{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | ||||||
| 		   3180, 3456, 0, 288, 290, 293, 312, 0, | 		   3180, 3456, 0, 288, 290, 293, 312, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 28 - 2880x288@50Hz */ | 	/* 28 - 2880x288@50Hz */ | ||||||
| 	{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | 	{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, | ||||||
| 		   3180, 3456, 0, 288, 290, 293, 312, 0, | 		   3180, 3456, 0, 288, 290, 293, 312, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 29 - 1440x576@50Hz */ | 	/* 29 - 1440x576@50Hz */ | ||||||
| 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | ||||||
| 		   1592, 1728, 0, 576, 581, 586, 625, 0, | 		   1592, 1728, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 30 - 1440x576@50Hz */ | 	/* 30 - 1440x576@50Hz */ | ||||||
| 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | ||||||
| 		   1592, 1728, 0, 576, 581, 586, 625, 0, | 		   1592, 1728, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 31 - 1920x1080@50Hz */ | 	/* 31 - 1920x1080@50Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, | ||||||
| 		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | 		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 32 - 1920x1080@24Hz */ | 	/* 32 - 1920x1080@24Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, | ||||||
| 		   2602, 2750, 0, 1080, 1084, 1089, 1125, 0, | 		   2602, 2750, 0, 1080, 1084, 1089, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 24, }, | ||||||
| 	/* 33 - 1920x1080@25Hz */ | 	/* 33 - 1920x1080@25Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, | ||||||
| 		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | 		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 25, }, | ||||||
| 	/* 34 - 1920x1080@30Hz */ | 	/* 34 - 1920x1080@30Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, | ||||||
| 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 30, }, | ||||||
| 	/* 35 - 2880x480@60Hz */ | 	/* 35 - 2880x480@60Hz */ | ||||||
| 	{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, | 	{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, | ||||||
| 		   3192, 3432, 0, 480, 489, 495, 525, 0, | 		   3192, 3432, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 36 - 2880x480@60Hz */ | 	/* 36 - 2880x480@60Hz */ | ||||||
| 	{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, | 	{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944, | ||||||
| 		   3192, 3432, 0, 480, 489, 495, 525, 0, | 		   3192, 3432, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 60, }, | ||||||
| 	/* 37 - 2880x576@50Hz */ | 	/* 37 - 2880x576@50Hz */ | ||||||
| 	{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, | 	{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, | ||||||
| 		   3184, 3456, 0, 576, 581, 586, 625, 0, | 		   3184, 3456, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 38 - 2880x576@50Hz */ | 	/* 38 - 2880x576@50Hz */ | ||||||
| 	{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, | 	{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928, | ||||||
| 		   3184, 3456, 0, 576, 581, 586, 625, 0, | 		   3184, 3456, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 39 - 1920x1080i@50Hz */ | 	/* 39 - 1920x1080i@50Hz */ | ||||||
| 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, | 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, | ||||||
| 		   2120, 2304, 0, 1080, 1126, 1136, 1250, 0, | 		   2120, 2304, 0, 1080, 1126, 1136, 1250, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 50, }, | ||||||
| 	/* 40 - 1920x1080i@100Hz */ | 	/* 40 - 1920x1080i@100Hz */ | ||||||
| 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, | 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, | ||||||
| 		   2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | 		   2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 100, }, | ||||||
| 	/* 41 - 1280x720@100Hz */ | 	/* 41 - 1280x720@100Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, | ||||||
| 		   1760, 1980, 0, 720, 725, 730, 750, 0, | 		   1760, 1980, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 100, }, | ||||||
| 	/* 42 - 720x576@100Hz */ | 	/* 42 - 720x576@100Hz */ | ||||||
| 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, | 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, | ||||||
| 		   796, 864, 0, 576, 581, 586, 625, 0, | 		   796, 864, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 100, }, | ||||||
| 	/* 43 - 720x576@100Hz */ | 	/* 43 - 720x576@100Hz */ | ||||||
| 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, | 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732, | ||||||
| 		   796, 864, 0, 576, 581, 586, 625, 0, | 		   796, 864, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 100, }, | ||||||
| 	/* 44 - 1440x576i@100Hz */ | 	/* 44 - 1440x576i@100Hz */ | ||||||
| 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 576, 580, 586, 625, 0, | 		   1590, 1728, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 100, }, | ||||||
| 	/* 45 - 1440x576i@100Hz */ | 	/* 45 - 1440x576i@100Hz */ | ||||||
| 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | 	{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 576, 580, 586, 625, 0, | 		   1590, 1728, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 100, }, | ||||||
| 	/* 46 - 1920x1080i@120Hz */ | 	/* 46 - 1920x1080i@120Hz */ | ||||||
| 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, | 	{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, | ||||||
| 		   2052, 2200, 0, 1080, 1084, 1094, 1125, 0, | 		   2052, 2200, 0, 1080, 1084, 1094, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE) }, | 			DRM_MODE_FLAG_INTERLACE), | ||||||
|  | 	  .vrefresh = 120, }, | ||||||
| 	/* 47 - 1280x720@120Hz */ | 	/* 47 - 1280x720@120Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, | ||||||
| 		   1430, 1650, 0, 720, 725, 730, 750, 0, | 		   1430, 1650, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 120, }, | ||||||
| 	/* 48 - 720x480@120Hz */ | 	/* 48 - 720x480@120Hz */ | ||||||
| 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, | 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, | ||||||
| 		   798, 858, 0, 480, 489, 495, 525, 0, | 		   798, 858, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 120, }, | ||||||
| 	/* 49 - 720x480@120Hz */ | 	/* 49 - 720x480@120Hz */ | ||||||
| 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, | 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736, | ||||||
| 		   798, 858, 0, 480, 489, 495, 525, 0, | 		   798, 858, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 120, }, | ||||||
| 	/* 50 - 1440x480i@120Hz */ | 	/* 50 - 1440x480i@120Hz */ | ||||||
| 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, | 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 480, 488, 494, 525, 0, | 		   1602, 1716, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 120, }, | ||||||
| 	/* 51 - 1440x480i@120Hz */ | 	/* 51 - 1440x480i@120Hz */ | ||||||
| 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, | 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 480, 488, 494, 525, 0, | 		   1602, 1716, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 120, }, | ||||||
| 	/* 52 - 720x576@200Hz */ | 	/* 52 - 720x576@200Hz */ | ||||||
| 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, | 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, | ||||||
| 		   796, 864, 0, 576, 581, 586, 625, 0, | 		   796, 864, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 200, }, | ||||||
| 	/* 53 - 720x576@200Hz */ | 	/* 53 - 720x576@200Hz */ | ||||||
| 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, | 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732, | ||||||
| 		   796, 864, 0, 576, 581, 586, 625, 0, | 		   796, 864, 0, 576, 581, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 200, }, | ||||||
| 	/* 54 - 1440x576i@200Hz */ | 	/* 54 - 1440x576i@200Hz */ | ||||||
| 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, | 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 576, 580, 586, 625, 0, | 		   1590, 1728, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 200, }, | ||||||
| 	/* 55 - 1440x576i@200Hz */ | 	/* 55 - 1440x576i@200Hz */ | ||||||
| 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, | 	{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, | ||||||
| 		   1590, 1728, 0, 576, 580, 586, 625, 0, | 		   1590, 1728, 0, 576, 580, 586, 625, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 200, }, | ||||||
| 	/* 56 - 720x480@240Hz */ | 	/* 56 - 720x480@240Hz */ | ||||||
| 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, | 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, | ||||||
| 		   798, 858, 0, 480, 489, 495, 525, 0, | 		   798, 858, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 240, }, | ||||||
| 	/* 57 - 720x480@240Hz */ | 	/* 57 - 720x480@240Hz */ | ||||||
| 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, | 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736, | ||||||
| 		   798, 858, 0, 480, 489, 495, 525, 0, | 		   798, 858, 0, 480, 489, 495, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||||||
|  | 	  .vrefresh = 240, }, | ||||||
| 	/* 58 - 1440x480i@240 */ | 	/* 58 - 1440x480i@240 */ | ||||||
| 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, | 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 480, 488, 494, 525, 0, | 		   1602, 1716, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 240, }, | ||||||
| 	/* 59 - 1440x480i@240 */ | 	/* 59 - 1440x480i@240 */ | ||||||
| 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, | 	{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, | ||||||
| 		   1602, 1716, 0, 480, 488, 494, 525, 0, | 		   1602, 1716, 0, 480, 488, 494, 525, 0, | ||||||
| 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | | ||||||
| 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, | 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), | ||||||
|  | 	  .vrefresh = 240, }, | ||||||
| 	/* 60 - 1280x720@24Hz */ | 	/* 60 - 1280x720@24Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040, | ||||||
| 		   3080, 3300, 0, 720, 725, 730, 750, 0, | 		   3080, 3300, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 24, }, | ||||||
| 	/* 61 - 1280x720@25Hz */ | 	/* 61 - 1280x720@25Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700, | ||||||
| 		   3740, 3960, 0, 720, 725, 730, 750, 0, | 		   3740, 3960, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 25, }, | ||||||
| 	/* 62 - 1280x720@30Hz */ | 	/* 62 - 1280x720@30Hz */ | ||||||
| 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, | 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, | ||||||
| 		   3080, 3300, 0, 720, 725, 730, 750, 0, | 		   3080, 3300, 0, 720, 725, 730, 750, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	  .vrefresh = 30, }, | ||||||
| 	/* 63 - 1920x1080@120Hz */ | 	/* 63 - 1920x1080@120Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, | ||||||
| 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	 .vrefresh = 120, }, | ||||||
| 	/* 64 - 1920x1080@100Hz */ | 	/* 64 - 1920x1080@100Hz */ | ||||||
| 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, | 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, | ||||||
| 		   2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | 		   2492, 2640, 0, 1080, 1084, 1094, 1125, 0, | ||||||
| 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), | ||||||
|  | 	 .vrefresh = 100, }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*** DDC fetch and block validation ***/ | /*** DDC fetch and block validation ***/ | ||||||
|  | @ -2266,13 +2330,34 @@ EXPORT_SYMBOL(drm_find_cea_extension); | ||||||
|  */ |  */ | ||||||
| u8 drm_match_cea_mode(const struct drm_display_mode *to_match) | u8 drm_match_cea_mode(const struct drm_display_mode *to_match) | ||||||
| { | { | ||||||
| 	struct drm_display_mode *cea_mode; |  | ||||||
| 	u8 mode; | 	u8 mode; | ||||||
| 
 | 
 | ||||||
| 	for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { | 	if (!to_match->clock) | ||||||
| 		cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode]; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 		if (drm_mode_equal(to_match, cea_mode)) | 	for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { | ||||||
|  | 		const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; | ||||||
|  | 		unsigned int clock1, clock2; | ||||||
|  | 
 | ||||||
|  | 		clock1 = clock2 = cea_mode->clock; | ||||||
|  | 
 | ||||||
|  | 		/* Check both 60Hz and 59.94Hz */ | ||||||
|  | 		if (cea_mode->vrefresh % 6 == 0) { | ||||||
|  | 			/*
 | ||||||
|  | 			 * edid_cea_modes contains the 59.94Hz | ||||||
|  | 			 * variant for 240 and 480 line modes, | ||||||
|  | 			 * and the 60Hz variant otherwise. | ||||||
|  | 			 */ | ||||||
|  | 			if (cea_mode->vdisplay == 240 || | ||||||
|  | 			    cea_mode->vdisplay == 480) | ||||||
|  | 				clock1 = clock1 * 1001 / 1000; | ||||||
|  | 			else | ||||||
|  | 				clock2 = DIV_ROUND_UP(clock2 * 1000, 1001); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || | ||||||
|  | 		     KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && | ||||||
|  | 		    drm_mode_equal_no_clocks(to_match, cea_mode)) | ||||||
| 			return mode + 1; | 			return mode + 1; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -2294,6 +2379,7 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) | ||||||
| 			newmode = drm_mode_duplicate(dev, | 			newmode = drm_mode_duplicate(dev, | ||||||
| 						     &edid_cea_modes[cea_mode]); | 						     &edid_cea_modes[cea_mode]); | ||||||
| 			if (newmode) { | 			if (newmode) { | ||||||
|  | 				newmode->vrefresh = 0; | ||||||
| 				drm_mode_probed_add(connector, newmode); | 				drm_mode_probed_add(connector, newmode); | ||||||
| 				modes++; | 				modes++; | ||||||
| 			} | 			} | ||||||
|  | @ -2510,6 +2596,65 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_edid_to_eld); | EXPORT_SYMBOL(drm_edid_to_eld); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * drm_edid_to_sad - extracts SADs from EDID | ||||||
|  |  * @edid: EDID to parse | ||||||
|  |  * @sads: pointer that will be set to the extracted SADs | ||||||
|  |  * | ||||||
|  |  * Looks for CEA EDID block and extracts SADs (Short Audio Descriptors) from it. | ||||||
|  |  * Note: returned pointer needs to be kfreed | ||||||
|  |  * | ||||||
|  |  * Return number of found SADs or negative number on error. | ||||||
|  |  */ | ||||||
|  | int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads) | ||||||
|  | { | ||||||
|  | 	int count = 0; | ||||||
|  | 	int i, start, end, dbl; | ||||||
|  | 	u8 *cea; | ||||||
|  | 
 | ||||||
|  | 	cea = drm_find_cea_extension(edid); | ||||||
|  | 	if (!cea) { | ||||||
|  | 		DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); | ||||||
|  | 		return -ENOENT; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (cea_revision(cea) < 3) { | ||||||
|  | 		DRM_DEBUG_KMS("SAD: wrong CEA revision\n"); | ||||||
|  | 		return -ENOTSUPP; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (cea_db_offsets(cea, &start, &end)) { | ||||||
|  | 		DRM_DEBUG_KMS("SAD: invalid data block offsets\n"); | ||||||
|  | 		return -EPROTO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for_each_cea_db(cea, i, start, end) { | ||||||
|  | 		u8 *db = &cea[i]; | ||||||
|  | 
 | ||||||
|  | 		if (cea_db_tag(db) == AUDIO_BLOCK) { | ||||||
|  | 			int j; | ||||||
|  | 			dbl = cea_db_payload_len(db); | ||||||
|  | 
 | ||||||
|  | 			count = dbl / 3; /* SAD is 3B */ | ||||||
|  | 			*sads = kcalloc(count, sizeof(**sads), GFP_KERNEL); | ||||||
|  | 			if (!*sads) | ||||||
|  | 				return -ENOMEM; | ||||||
|  | 			for (j = 0; j < count; j++) { | ||||||
|  | 				u8 *sad = &db[1 + j * 3]; | ||||||
|  | 
 | ||||||
|  | 				(*sads)[j].format = (sad[0] & 0x78) >> 3; | ||||||
|  | 				(*sads)[j].channels = sad[0] & 0x7; | ||||||
|  | 				(*sads)[j].freq = sad[1] & 0x7F; | ||||||
|  | 				(*sads)[j].byte2 = sad[2]; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(drm_edid_to_sad); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond |  * drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond | ||||||
|  * @connector: connector associated with the HDMI/DP sink |  * @connector: connector associated with the HDMI/DP sink | ||||||
|  |  | ||||||
|  | @ -31,10 +31,11 @@ module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); | ||||||
| MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " | MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " | ||||||
| 	"from built-in data or /lib/firmware instead. "); | 	"from built-in data or /lib/firmware instead. "); | ||||||
| 
 | 
 | ||||||
| #define GENERIC_EDIDS 4 | #define GENERIC_EDIDS 5 | ||||||
| static char *generic_edid_name[GENERIC_EDIDS] = { | static char *generic_edid_name[GENERIC_EDIDS] = { | ||||||
| 	"edid/1024x768.bin", | 	"edid/1024x768.bin", | ||||||
| 	"edid/1280x1024.bin", | 	"edid/1280x1024.bin", | ||||||
|  | 	"edid/1600x1200.bin", | ||||||
| 	"edid/1680x1050.bin", | 	"edid/1680x1050.bin", | ||||||
| 	"edid/1920x1080.bin", | 	"edid/1920x1080.bin", | ||||||
| }; | }; | ||||||
|  | @ -79,6 +80,24 @@ static u8 generic_edid[GENERIC_EDIDS][128] = { | ||||||
| 	{ | 	{ | ||||||
| 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, | 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, | ||||||
| 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78, | ||||||
|  | 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25, | ||||||
|  | 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40, | ||||||
|  | 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||||
|  | 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f, | ||||||
|  | 	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0, | ||||||
|  | 	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e, | ||||||
|  | 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e, | ||||||
|  | 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20, | ||||||
|  | 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b, | ||||||
|  | 	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20, | ||||||
|  | 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, | ||||||
|  | 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55, | ||||||
|  | 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, | ||||||
|  | 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
| 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78, | 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78, | ||||||
| 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25, | 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25, | ||||||
| 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00, | 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00, | ||||||
|  |  | ||||||
|  | @ -1398,7 +1398,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | ||||||
| 	struct drm_mode_set *modeset; | 	struct drm_mode_set *modeset; | ||||||
| 	bool *enabled; | 	bool *enabled; | ||||||
| 	int width, height; | 	int width, height; | ||||||
| 	int i, ret; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("\n"); | 	DRM_DEBUG_KMS("\n"); | ||||||
| 
 | 
 | ||||||
|  | @ -1419,16 +1419,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | ||||||
| 
 | 
 | ||||||
| 	drm_enable_connectors(fb_helper, enabled); | 	drm_enable_connectors(fb_helper, enabled); | ||||||
| 
 | 
 | ||||||
| 	ret = drm_target_cloned(fb_helper, modes, enabled, width, height); | 	if (!(fb_helper->funcs->initial_config && | ||||||
| 	if (!ret) { | 	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes, | ||||||
| 		ret = drm_target_preferred(fb_helper, modes, enabled, width, height); | 					       enabled, width, height))) { | ||||||
| 		if (!ret) | 		memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); | ||||||
| 			DRM_ERROR("Unable to find initial modes\n"); | 		memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); | 		if (!drm_target_cloned(fb_helper, | ||||||
|  | 				       modes, enabled, width, height) && | ||||||
|  | 		    !drm_target_preferred(fb_helper, | ||||||
|  | 					  modes, enabled, width, height)) | ||||||
|  | 			DRM_ERROR("Unable to find initial modes\n"); | ||||||
|  | 
 | ||||||
|  | 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", | ||||||
|  | 			      width, height); | ||||||
| 
 | 
 | ||||||
| 		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); | 		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* need to set the modesets up here for use later */ | 	/* need to set the modesets up here for use later */ | ||||||
| 	/* fill out the connector<->crtc mappings into the modesets */ | 	/* fill out the connector<->crtc mappings into the modesets */ | ||||||
|  |  | ||||||
|  | @ -205,11 +205,11 @@ static void | ||||||
| drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) | drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) | ||||||
| { | { | ||||||
| 	if (obj->import_attach) { | 	if (obj->import_attach) { | ||||||
| 		drm_prime_remove_imported_buf_handle(&filp->prime, | 		drm_prime_remove_buf_handle(&filp->prime, | ||||||
| 				obj->import_attach->dmabuf); | 				obj->import_attach->dmabuf); | ||||||
| 	} | 	} | ||||||
| 	if (obj->export_dma_buf) { | 	if (obj->export_dma_buf) { | ||||||
| 		drm_prime_remove_imported_buf_handle(&filp->prime, | 		drm_prime_remove_buf_handle(&filp->prime, | ||||||
| 				obj->export_dma_buf); | 				obj->export_dma_buf); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -848,6 +848,26 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ | ||||||
| 	} else if (mode1->clock != mode2->clock) | 	} else if (mode1->clock != mode2->clock) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
|  | 	return drm_mode_equal_no_clocks(mode1, mode2); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(drm_mode_equal); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * drm_mode_equal_no_clocks - test modes for equality | ||||||
|  |  * @mode1: first mode | ||||||
|  |  * @mode2: second mode | ||||||
|  |  * | ||||||
|  |  * LOCKING: | ||||||
|  |  * None. | ||||||
|  |  * | ||||||
|  |  * Check to see if @mode1 and @mode2 are equivalent, but | ||||||
|  |  * don't check the pixel clocks. | ||||||
|  |  * | ||||||
|  |  * RETURNS: | ||||||
|  |  * True if the modes are equal, false otherwise. | ||||||
|  |  */ | ||||||
|  | bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) | ||||||
|  | { | ||||||
| 	if (mode1->hdisplay == mode2->hdisplay && | 	if (mode1->hdisplay == mode2->hdisplay && | ||||||
| 	    mode1->hsync_start == mode2->hsync_start && | 	    mode1->hsync_start == mode2->hsync_start && | ||||||
| 	    mode1->hsync_end == mode2->hsync_end && | 	    mode1->hsync_end == mode2->hsync_end && | ||||||
|  | @ -863,7 +883,7 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ | ||||||
| 
 | 
 | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_mode_equal); | EXPORT_SYMBOL(drm_mode_equal_no_clocks); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * drm_mode_validate_size - make sure modes adhere to size constraints |  * drm_mode_validate_size - make sure modes adhere to size constraints | ||||||
|  |  | ||||||
|  | @ -152,7 +152,7 @@ static const char *drm_pci_get_name(struct drm_device *dev) | ||||||
| 	return pdriver->name; | 	return pdriver->name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) | static int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) | ||||||
| { | { | ||||||
| 	int len, ret; | 	int len, ret; | ||||||
| 	struct pci_driver *pdriver = dev->driver->kdriver.pci; | 	struct pci_driver *pdriver = dev->driver->kdriver.pci; | ||||||
|  | @ -194,7 +194,7 @@ err: | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int drm_pci_set_unique(struct drm_device *dev, | static int drm_pci_set_unique(struct drm_device *dev, | ||||||
| 			      struct drm_master *master, | 			      struct drm_master *master, | ||||||
| 			      struct drm_unique *u) | 			      struct drm_unique *u) | ||||||
| { | { | ||||||
|  | @ -266,7 +266,7 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int drm_pci_agp_init(struct drm_device *dev) | static int drm_pci_agp_init(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	if (drm_core_has_AGP(dev)) { | 	if (drm_core_has_AGP(dev)) { | ||||||
| 		if (drm_pci_device_is_agp(dev)) | 		if (drm_pci_device_is_agp(dev)) | ||||||
|  |  | ||||||
|  | @ -62,6 +62,7 @@ struct drm_prime_member { | ||||||
| 	struct dma_buf *dma_buf; | 	struct dma_buf *dma_buf; | ||||||
| 	uint32_t handle; | 	uint32_t handle; | ||||||
| }; | }; | ||||||
|  | static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); | ||||||
| 
 | 
 | ||||||
| static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, | ||||||
| 		enum dma_data_direction dir) | 		enum dma_data_direction dir) | ||||||
|  | @ -200,7 +201,8 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | ||||||
| { | { | ||||||
| 	struct drm_gem_object *obj; | 	struct drm_gem_object *obj; | ||||||
| 	void *buf; | 	void *buf; | ||||||
| 	int ret; | 	int ret = 0; | ||||||
|  | 	struct dma_buf *dmabuf; | ||||||
| 
 | 
 | ||||||
| 	obj = drm_gem_object_lookup(dev, file_priv, handle); | 	obj = drm_gem_object_lookup(dev, file_priv, handle); | ||||||
| 	if (!obj) | 	if (!obj) | ||||||
|  | @ -209,43 +211,44 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | ||||||
| 	mutex_lock(&file_priv->prime.lock); | 	mutex_lock(&file_priv->prime.lock); | ||||||
| 	/* re-export the original imported object */ | 	/* re-export the original imported object */ | ||||||
| 	if (obj->import_attach) { | 	if (obj->import_attach) { | ||||||
| 		get_dma_buf(obj->import_attach->dmabuf); | 		dmabuf = obj->import_attach->dmabuf; | ||||||
| 		*prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags); | 		goto out_have_obj; | ||||||
| 		drm_gem_object_unreference_unlocked(obj); |  | ||||||
| 		mutex_unlock(&file_priv->prime.lock); |  | ||||||
| 		return 0; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (obj->export_dma_buf) { | 	if (obj->export_dma_buf) { | ||||||
| 		get_dma_buf(obj->export_dma_buf); | 		dmabuf = obj->export_dma_buf; | ||||||
| 		*prime_fd = dma_buf_fd(obj->export_dma_buf, flags); | 		goto out_have_obj; | ||||||
| 		drm_gem_object_unreference_unlocked(obj); | 	} | ||||||
| 	} else { | 
 | ||||||
| 	buf = dev->driver->gem_prime_export(dev, obj, flags); | 	buf = dev->driver->gem_prime_export(dev, obj, flags); | ||||||
| 	if (IS_ERR(buf)) { | 	if (IS_ERR(buf)) { | ||||||
| 		/* normally the created dma-buf takes ownership of the ref,
 | 		/* normally the created dma-buf takes ownership of the ref,
 | ||||||
| 		 * but if that fails then drop the ref | 		 * but if that fails then drop the ref | ||||||
| 		 */ | 		 */ | ||||||
| 			drm_gem_object_unreference_unlocked(obj); | 		ret = PTR_ERR(buf); | ||||||
| 			mutex_unlock(&file_priv->prime.lock); | 		goto out; | ||||||
| 			return PTR_ERR(buf); |  | ||||||
| 	} | 	} | ||||||
| 	obj->export_dma_buf = buf; | 	obj->export_dma_buf = buf; | ||||||
| 		*prime_fd = dma_buf_fd(buf, flags); | 
 | ||||||
| 	} |  | ||||||
| 	/* if we've exported this buffer the cheat and add it to the import list
 | 	/* if we've exported this buffer the cheat and add it to the import list
 | ||||||
| 	 * so we get the correct handle back | 	 * so we get the correct handle back | ||||||
| 	 */ | 	 */ | ||||||
| 	ret = drm_prime_add_imported_buf_handle(&file_priv->prime, | 	ret = drm_prime_add_buf_handle(&file_priv->prime, | ||||||
| 				       obj->export_dma_buf, handle); | 				       obj->export_dma_buf, handle); | ||||||
| 	if (ret) { | 	if (ret) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	*prime_fd = dma_buf_fd(buf, flags); | ||||||
|  | 	mutex_unlock(&file_priv->prime.lock); | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | out_have_obj: | ||||||
|  | 	get_dma_buf(dmabuf); | ||||||
|  | 	*prime_fd = dma_buf_fd(dmabuf, flags); | ||||||
|  | out: | ||||||
| 	drm_gem_object_unreference_unlocked(obj); | 	drm_gem_object_unreference_unlocked(obj); | ||||||
| 	mutex_unlock(&file_priv->prime.lock); | 	mutex_unlock(&file_priv->prime.lock); | ||||||
| 	return ret; | 	return ret; | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	mutex_unlock(&file_priv->prime.lock); |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); | EXPORT_SYMBOL(drm_gem_prime_handle_to_fd); | ||||||
| 
 | 
 | ||||||
|  | @ -268,7 +271,6 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | ||||||
| 			 * refcount on gem itself instead of f_count of dmabuf. | 			 * refcount on gem itself instead of f_count of dmabuf. | ||||||
| 			 */ | 			 */ | ||||||
| 			drm_gem_object_reference(obj); | 			drm_gem_object_reference(obj); | ||||||
| 			dma_buf_put(dma_buf); |  | ||||||
| 			return obj; | 			return obj; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -277,6 +279,8 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, | ||||||
| 	if (IS_ERR(attach)) | 	if (IS_ERR(attach)) | ||||||
| 		return ERR_PTR(PTR_ERR(attach)); | 		return ERR_PTR(PTR_ERR(attach)); | ||||||
| 
 | 
 | ||||||
|  | 	get_dma_buf(dma_buf); | ||||||
|  | 
 | ||||||
| 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | ||||||
| 	if (IS_ERR_OR_NULL(sgt)) { | 	if (IS_ERR_OR_NULL(sgt)) { | ||||||
| 		ret = PTR_ERR(sgt); | 		ret = PTR_ERR(sgt); | ||||||
|  | @ -297,6 +301,8 @@ fail_unmap: | ||||||
| 	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | 	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | ||||||
| fail_detach: | fail_detach: | ||||||
| 	dma_buf_detach(dma_buf, attach); | 	dma_buf_detach(dma_buf, attach); | ||||||
|  | 	dma_buf_put(dma_buf); | ||||||
|  | 
 | ||||||
| 	return ERR_PTR(ret); | 	return ERR_PTR(ret); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_gem_prime_import); | EXPORT_SYMBOL(drm_gem_prime_import); | ||||||
|  | @ -314,7 +320,7 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&file_priv->prime.lock); | 	mutex_lock(&file_priv->prime.lock); | ||||||
| 
 | 
 | ||||||
| 	ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime, | 	ret = drm_prime_lookup_buf_handle(&file_priv->prime, | ||||||
| 			dma_buf, handle); | 			dma_buf, handle); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		ret = 0; | 		ret = 0; | ||||||
|  | @ -333,12 +339,15 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto out_put; | 		goto out_put; | ||||||
| 
 | 
 | ||||||
| 	ret = drm_prime_add_imported_buf_handle(&file_priv->prime, | 	ret = drm_prime_add_buf_handle(&file_priv->prime, | ||||||
| 			dma_buf, *handle); | 			dma_buf, *handle); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 
 | 
 | ||||||
| 	mutex_unlock(&file_priv->prime.lock); | 	mutex_unlock(&file_priv->prime.lock); | ||||||
|  | 
 | ||||||
|  | 	dma_buf_put(dma_buf); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| fail: | fail: | ||||||
|  | @ -401,21 +410,17 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, | ||||||
| struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) | struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages) | ||||||
| { | { | ||||||
| 	struct sg_table *sg = NULL; | 	struct sg_table *sg = NULL; | ||||||
| 	struct scatterlist *iter; |  | ||||||
| 	int i; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL); | 	sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL); | ||||||
| 	if (!sg) | 	if (!sg) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	ret = sg_alloc_table(sg, nr_pages, GFP_KERNEL); | 	ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0, | ||||||
|  | 				nr_pages << PAGE_SHIFT, GFP_KERNEL); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(sg->sgl, iter, nr_pages, i) |  | ||||||
| 		sg_set_page(iter, pages[i], PAGE_SIZE, 0); |  | ||||||
| 
 |  | ||||||
| 	return sg; | 	return sg; | ||||||
| out: | out: | ||||||
| 	kfree(sg); | 	kfree(sg); | ||||||
|  | @ -483,15 +488,12 @@ EXPORT_SYMBOL(drm_prime_init_file_private); | ||||||
| 
 | 
 | ||||||
| void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) | void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv) | ||||||
| { | { | ||||||
| 	struct drm_prime_member *member, *safe; | 	/* by now drm_gem_release should've made sure the list is empty */ | ||||||
| 	list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { | 	WARN_ON(!list_empty(&prime_fpriv->head)); | ||||||
| 		list_del(&member->entry); |  | ||||||
| 		kfree(member); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_prime_destroy_file_private); | EXPORT_SYMBOL(drm_prime_destroy_file_private); | ||||||
| 
 | 
 | ||||||
| int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) | static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) | ||||||
| { | { | ||||||
| 	struct drm_prime_member *member; | 	struct drm_prime_member *member; | ||||||
| 
 | 
 | ||||||
|  | @ -499,14 +501,14 @@ int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv | ||||||
| 	if (!member) | 	if (!member) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | 	get_dma_buf(dma_buf); | ||||||
| 	member->dma_buf = dma_buf; | 	member->dma_buf = dma_buf; | ||||||
| 	member->handle = handle; | 	member->handle = handle; | ||||||
| 	list_add(&member->entry, &prime_fpriv->head); | 	list_add(&member->entry, &prime_fpriv->head); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_prime_add_imported_buf_handle); |  | ||||||
| 
 | 
 | ||||||
| int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) | int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle) | ||||||
| { | { | ||||||
| 	struct drm_prime_member *member; | 	struct drm_prime_member *member; | ||||||
| 
 | 
 | ||||||
|  | @ -518,19 +520,20 @@ int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fp | ||||||
| 	} | 	} | ||||||
| 	return -ENOENT; | 	return -ENOENT; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_prime_lookup_imported_buf_handle); | EXPORT_SYMBOL(drm_prime_lookup_buf_handle); | ||||||
| 
 | 
 | ||||||
| void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) | void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf) | ||||||
| { | { | ||||||
| 	struct drm_prime_member *member, *safe; | 	struct drm_prime_member *member, *safe; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&prime_fpriv->lock); | 	mutex_lock(&prime_fpriv->lock); | ||||||
| 	list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { | 	list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) { | ||||||
| 		if (member->dma_buf == dma_buf) { | 		if (member->dma_buf == dma_buf) { | ||||||
|  | 			dma_buf_put(dma_buf); | ||||||
| 			list_del(&member->entry); | 			list_del(&member->entry); | ||||||
| 			kfree(member); | 			kfree(member); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&prime_fpriv->lock); | 	mutex_unlock(&prime_fpriv->lock); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(drm_prime_remove_imported_buf_handle); | EXPORT_SYMBOL(drm_prime_remove_buf_handle); | ||||||
|  |  | ||||||
|  | @ -422,6 +422,7 @@ void drm_vm_open_locked(struct drm_device *dev, | ||||||
| 		list_add(&vma_entry->head, &dev->vmalist); | 		list_add(&vma_entry->head, &dev->vmalist); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(drm_vm_open_locked); | ||||||
| 
 | 
 | ||||||
| static void drm_vm_open(struct vm_area_struct *vma) | static void drm_vm_open(struct vm_area_struct *vma) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -24,7 +24,9 @@ config DRM_EXYNOS_DMABUF | ||||||
| 
 | 
 | ||||||
| config DRM_EXYNOS_FIMD | config DRM_EXYNOS_FIMD | ||||||
| 	bool "Exynos DRM FIMD" | 	bool "Exynos DRM FIMD" | ||||||
| 	depends on DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM | 	depends on OF && DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM | ||||||
|  | 	select FB_MODE_HELPERS | ||||||
|  | 	select VIDEOMODE_HELPERS | ||||||
| 	help | 	help | ||||||
| 	  Choose this option if you want to use Exynos FIMD for DRM. | 	  Choose this option if you want to use Exynos FIMD for DRM. | ||||||
| 
 | 
 | ||||||
|  | @ -54,7 +56,7 @@ config DRM_EXYNOS_IPP | ||||||
| 
 | 
 | ||||||
| config DRM_EXYNOS_FIMC | config DRM_EXYNOS_FIMC | ||||||
| 	bool "Exynos DRM FIMC" | 	bool "Exynos DRM FIMC" | ||||||
| 	depends on DRM_EXYNOS_IPP | 	depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF | ||||||
| 	help | 	help | ||||||
| 	  Choose this option if you want to use Exynos FIMC for DRM. | 	  Choose this option if you want to use Exynos FIMC for DRM. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -124,7 +124,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		count = drm_add_edid_modes(connector, edid); | 		count = drm_add_edid_modes(connector, edid); | ||||||
| 		if (count < 0) { | 		if (!count) { | ||||||
| 			DRM_ERROR("Add edid modes failed %d\n", count); | 			DRM_ERROR("Add edid modes failed %d\n", count); | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -235,7 +235,6 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, | ||||||
| 			 * refcount on gem itself instead of f_count of dmabuf. | 			 * refcount on gem itself instead of f_count of dmabuf. | ||||||
| 			 */ | 			 */ | ||||||
| 			drm_gem_object_reference(obj); | 			drm_gem_object_reference(obj); | ||||||
| 			dma_buf_put(dma_buf); |  | ||||||
| 			return obj; | 			return obj; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -244,6 +243,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, | ||||||
| 	if (IS_ERR(attach)) | 	if (IS_ERR(attach)) | ||||||
| 		return ERR_PTR(-EINVAL); | 		return ERR_PTR(-EINVAL); | ||||||
| 
 | 
 | ||||||
|  | 	get_dma_buf(dma_buf); | ||||||
| 
 | 
 | ||||||
| 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | ||||||
| 	if (IS_ERR_OR_NULL(sgt)) { | 	if (IS_ERR_OR_NULL(sgt)) { | ||||||
|  | @ -298,6 +298,8 @@ err_unmap_attach: | ||||||
| 	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | 	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | ||||||
| err_buf_detach: | err_buf_detach: | ||||||
| 	dma_buf_detach(dma_buf, attach); | 	dma_buf_detach(dma_buf, attach); | ||||||
|  | 	dma_buf_put(dma_buf); | ||||||
|  | 
 | ||||||
| 	return ERR_PTR(ret); | 	return ERR_PTR(ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -380,6 +380,10 @@ static int __init exynos_drm_init(void) | ||||||
| 	ret = platform_driver_register(&ipp_driver); | 	ret = platform_driver_register(&ipp_driver); | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		goto out_ipp; | 		goto out_ipp; | ||||||
|  | 
 | ||||||
|  | 	ret = exynos_platform_device_ipp_register(); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		goto out_ipp_dev; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	ret = platform_driver_register(&exynos_drm_platform_driver); | 	ret = platform_driver_register(&exynos_drm_platform_driver); | ||||||
|  | @ -388,7 +392,7 @@ static int __init exynos_drm_init(void) | ||||||
| 
 | 
 | ||||||
| 	exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, | 	exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, | ||||||
| 				NULL, 0); | 				NULL, 0); | ||||||
| 	if (IS_ERR_OR_NULL(exynos_drm_pdev)) { | 	if (IS_ERR(exynos_drm_pdev)) { | ||||||
| 		ret = PTR_ERR(exynos_drm_pdev); | 		ret = PTR_ERR(exynos_drm_pdev); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
|  | @ -400,6 +404,8 @@ out: | ||||||
| 
 | 
 | ||||||
| out_drm: | out_drm: | ||||||
| #ifdef CONFIG_DRM_EXYNOS_IPP | #ifdef CONFIG_DRM_EXYNOS_IPP | ||||||
|  | 	exynos_platform_device_ipp_unregister(); | ||||||
|  | out_ipp_dev: | ||||||
| 	platform_driver_unregister(&ipp_driver); | 	platform_driver_unregister(&ipp_driver); | ||||||
| out_ipp: | out_ipp: | ||||||
| #endif | #endif | ||||||
|  | @ -456,6 +462,7 @@ static void __exit exynos_drm_exit(void) | ||||||
| 	platform_driver_unregister(&exynos_drm_platform_driver); | 	platform_driver_unregister(&exynos_drm_platform_driver); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_DRM_EXYNOS_IPP | #ifdef CONFIG_DRM_EXYNOS_IPP | ||||||
|  | 	exynos_platform_device_ipp_unregister(); | ||||||
| 	platform_driver_unregister(&ipp_driver); | 	platform_driver_unregister(&ipp_driver); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -322,13 +322,23 @@ void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); | ||||||
|  * this function registers exynos drm hdmi platform device. It ensures only one |  * this function registers exynos drm hdmi platform device. It ensures only one | ||||||
|  * instance of the device is created. |  * instance of the device is created. | ||||||
|  */ |  */ | ||||||
| extern int exynos_platform_device_hdmi_register(void); | int exynos_platform_device_hdmi_register(void); | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * this function unregisters exynos drm hdmi platform device if it exists. |  * this function unregisters exynos drm hdmi platform device if it exists. | ||||||
|  */ |  */ | ||||||
| void exynos_platform_device_hdmi_unregister(void); | void exynos_platform_device_hdmi_unregister(void); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * this function registers exynos drm ipp platform device. | ||||||
|  |  */ | ||||||
|  | int exynos_platform_device_ipp_register(void); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * this function unregisters exynos drm ipp platform device if it exists. | ||||||
|  |  */ | ||||||
|  | void exynos_platform_device_ipp_unregister(void); | ||||||
|  | 
 | ||||||
| extern struct platform_driver fimd_driver; | extern struct platform_driver fimd_driver; | ||||||
| extern struct platform_driver hdmi_driver; | extern struct platform_driver hdmi_driver; | ||||||
| extern struct platform_driver mixer_driver; | extern struct platform_driver mixer_driver; | ||||||
|  |  | ||||||
|  | @ -12,11 +12,12 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
|  | #include <linux/mfd/syscon.h> | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/platform_device.h> | #include <linux/platform_device.h> | ||||||
|  | #include <linux/regmap.h> | ||||||
| #include <linux/clk.h> | #include <linux/clk.h> | ||||||
| #include <linux/pm_runtime.h> | #include <linux/pm_runtime.h> | ||||||
| #include <plat/map-base.h> |  | ||||||
| 
 | 
 | ||||||
| #include <drm/drmP.h> | #include <drm/drmP.h> | ||||||
| #include <drm/exynos_drm.h> | #include <drm/exynos_drm.h> | ||||||
|  | @ -76,6 +77,27 @@ enum fimc_wb { | ||||||
| 	FIMC_WB_B, | 	FIMC_WB_B, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum { | ||||||
|  | 	FIMC_CLK_LCLK, | ||||||
|  | 	FIMC_CLK_GATE, | ||||||
|  | 	FIMC_CLK_WB_A, | ||||||
|  | 	FIMC_CLK_WB_B, | ||||||
|  | 	FIMC_CLK_MUX, | ||||||
|  | 	FIMC_CLK_PARENT, | ||||||
|  | 	FIMC_CLKS_MAX | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const char * const fimc_clock_names[] = { | ||||||
|  | 	[FIMC_CLK_LCLK]   = "sclk_fimc", | ||||||
|  | 	[FIMC_CLK_GATE]   = "fimc", | ||||||
|  | 	[FIMC_CLK_WB_A]   = "pxl_async0", | ||||||
|  | 	[FIMC_CLK_WB_B]   = "pxl_async1", | ||||||
|  | 	[FIMC_CLK_MUX]    = "mux", | ||||||
|  | 	[FIMC_CLK_PARENT] = "parent", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * A structure of scaler. |  * A structure of scaler. | ||||||
|  * |  * | ||||||
|  | @ -118,15 +140,6 @@ struct fimc_capability { | ||||||
| 	u32	rl_h_rot; | 	u32	rl_h_rot; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * A structure of fimc driver data. |  | ||||||
|  * |  | ||||||
|  * @parent_clk: name of parent clock. |  | ||||||
|  */ |  | ||||||
| struct fimc_driverdata { |  | ||||||
| 	char	*parent_clk; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * A structure of fimc context. |  * A structure of fimc context. | ||||||
|  * |  * | ||||||
|  | @ -134,13 +147,10 @@ struct fimc_driverdata { | ||||||
|  * @regs_res: register resources. |  * @regs_res: register resources. | ||||||
|  * @regs: memory mapped io registers. |  * @regs: memory mapped io registers. | ||||||
|  * @lock: locking of operations. |  * @lock: locking of operations. | ||||||
|  * @sclk_fimc_clk: fimc source clock. |  * @clocks: fimc clocks. | ||||||
|  * @fimc_clk: fimc clock. |  * @clk_frequency: LCLK clock frequency. | ||||||
|  * @wb_clk: writeback a clock. |  * @sysreg: handle to SYSREG block regmap. | ||||||
|  * @wb_b_clk: writeback b clock. |  | ||||||
|  * @sc: scaler infomations. |  * @sc: scaler infomations. | ||||||
|  * @odr: ordering of YUV. |  | ||||||
|  * @ver: fimc version. |  | ||||||
|  * @pol: porarity of writeback. |  * @pol: porarity of writeback. | ||||||
|  * @id: fimc id. |  * @id: fimc id. | ||||||
|  * @irq: irq number. |  * @irq: irq number. | ||||||
|  | @ -151,12 +161,10 @@ struct fimc_context { | ||||||
| 	struct resource	*regs_res; | 	struct resource	*regs_res; | ||||||
| 	void __iomem	*regs; | 	void __iomem	*regs; | ||||||
| 	struct mutex	lock; | 	struct mutex	lock; | ||||||
| 	struct clk	*sclk_fimc_clk; | 	struct clk	*clocks[FIMC_CLKS_MAX]; | ||||||
| 	struct clk	*fimc_clk; | 	u32		clk_frequency; | ||||||
| 	struct clk	*wb_clk; | 	struct regmap	*sysreg; | ||||||
| 	struct clk	*wb_b_clk; |  | ||||||
| 	struct fimc_scaler	sc; | 	struct fimc_scaler	sc; | ||||||
| 	struct fimc_driverdata	*ddata; |  | ||||||
| 	struct exynos_drm_ipp_pol	pol; | 	struct exynos_drm_ipp_pol	pol; | ||||||
| 	int	id; | 	int	id; | ||||||
| 	int	irq; | 	int	irq; | ||||||
|  | @ -200,17 +208,13 @@ static void fimc_sw_reset(struct fimc_context *ctx) | ||||||
| 	fimc_write(0x0, EXYNOS_CIFCNTSEQ); | 	fimc_write(0x0, EXYNOS_CIFCNTSEQ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) | static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) | ||||||
| { | { | ||||||
| 	u32 camblk_cfg; |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_KMS("%s\n", __func__); | 	DRM_DEBUG_KMS("%s\n", __func__); | ||||||
| 
 | 
 | ||||||
| 	camblk_cfg = readl(SYSREG_CAMERA_BLK); | 	return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK, | ||||||
| 	camblk_cfg &= ~(SYSREG_FIMD0WB_DEST_MASK); | 				  SYSREG_FIMD0WB_DEST_MASK, | ||||||
| 	camblk_cfg |= ctx->id << (SYSREG_FIMD0WB_DEST_SHIFT); | 				  ctx->id << SYSREG_FIMD0WB_DEST_SHIFT); | ||||||
| 
 |  | ||||||
| 	writel(camblk_cfg, SYSREG_CAMERA_BLK); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) | static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) | ||||||
|  | @ -1301,14 +1305,12 @@ static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) | ||||||
| 	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable); | 	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable); | ||||||
| 
 | 
 | ||||||
| 	if (enable) { | 	if (enable) { | ||||||
| 		clk_enable(ctx->sclk_fimc_clk); | 		clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); | ||||||
| 		clk_enable(ctx->fimc_clk); | 		clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); | ||||||
| 		clk_enable(ctx->wb_clk); |  | ||||||
| 		ctx->suspended = false; | 		ctx->suspended = false; | ||||||
| 	} else { | 	} else { | ||||||
| 		clk_disable(ctx->sclk_fimc_clk); | 		clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); | ||||||
| 		clk_disable(ctx->fimc_clk); | 		clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); | ||||||
| 		clk_disable(ctx->wb_clk); |  | ||||||
| 		ctx->suspended = true; | 		ctx->suspended = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1613,7 +1615,11 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) | ||||||
| 		fimc_handle_lastend(ctx, true); | 		fimc_handle_lastend(ctx, true); | ||||||
| 
 | 
 | ||||||
| 		/* setup FIMD */ | 		/* setup FIMD */ | ||||||
| 		fimc_set_camblk_fimd0_wb(ctx); | 		ret = fimc_set_camblk_fimd0_wb(ctx); | ||||||
|  | 		if (ret < 0) { | ||||||
|  | 			dev_err(dev, "camblk setup failed.\n"); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		set_wb.enable = 1; | 		set_wb.enable = 1; | ||||||
| 		set_wb.refresh = property->refresh_rate; | 		set_wb.refresh = property->refresh_rate; | ||||||
|  | @ -1713,75 +1719,117 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) | ||||||
| 	fimc_write(cfg, EXYNOS_CIGCTRL); | 	fimc_write(cfg, EXYNOS_CIGCTRL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void fimc_put_clocks(struct fimc_context *ctx) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < FIMC_CLKS_MAX; i++) { | ||||||
|  | 		if (IS_ERR(ctx->clocks[i])) | ||||||
|  | 			continue; | ||||||
|  | 		clk_put(ctx->clocks[i]); | ||||||
|  | 		ctx->clocks[i] = ERR_PTR(-EINVAL); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int fimc_setup_clocks(struct fimc_context *ctx) | ||||||
|  | { | ||||||
|  | 	struct device *fimc_dev = ctx->ippdrv.dev; | ||||||
|  | 	struct device *dev; | ||||||
|  | 	int ret, i; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < FIMC_CLKS_MAX; i++) | ||||||
|  | 		ctx->clocks[i] = ERR_PTR(-EINVAL); | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < FIMC_CLKS_MAX; i++) { | ||||||
|  | 		if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B) | ||||||
|  | 			dev = fimc_dev->parent; | ||||||
|  | 		else | ||||||
|  | 			dev = fimc_dev; | ||||||
|  | 
 | ||||||
|  | 		ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]); | ||||||
|  | 		if (IS_ERR(ctx->clocks[i])) { | ||||||
|  | 			if (i >= FIMC_CLK_MUX) | ||||||
|  | 				break; | ||||||
|  | 			ret = PTR_ERR(ctx->clocks[i]); | ||||||
|  | 			dev_err(fimc_dev, "failed to get clock: %s\n", | ||||||
|  | 						fimc_clock_names[i]); | ||||||
|  | 			goto e_clk_free; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Optional FIMC LCLK parent clock setting */ | ||||||
|  | 	if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) { | ||||||
|  | 		ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX], | ||||||
|  | 				     ctx->clocks[FIMC_CLK_PARENT]); | ||||||
|  | 		if (ret < 0) { | ||||||
|  | 			dev_err(fimc_dev, "failed to set parent.\n"); | ||||||
|  | 			goto e_clk_free; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		goto e_clk_free; | ||||||
|  | 
 | ||||||
|  | 	ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]); | ||||||
|  | 	if (!ret) | ||||||
|  | 		return ret; | ||||||
|  | e_clk_free: | ||||||
|  | 	fimc_put_clocks(ctx); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int fimc_parse_dt(struct fimc_context *ctx) | ||||||
|  | { | ||||||
|  | 	struct device_node *node = ctx->ippdrv.dev->of_node; | ||||||
|  | 
 | ||||||
|  | 	/* Handle only devices that support the LCD Writeback data path */ | ||||||
|  | 	if (!of_property_read_bool(node, "samsung,lcd-wb")) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
|  | 	if (of_property_read_u32(node, "clock-frequency", | ||||||
|  | 					&ctx->clk_frequency)) | ||||||
|  | 		ctx->clk_frequency = FIMC_DEFAULT_LCLK_FREQUENCY; | ||||||
|  | 
 | ||||||
|  | 	ctx->id = of_alias_get_id(node, "fimc"); | ||||||
|  | 
 | ||||||
|  | 	if (ctx->id < 0) { | ||||||
|  | 		dev_err(ctx->ippdrv.dev, "failed to get node alias id.\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int fimc_probe(struct platform_device *pdev) | static int fimc_probe(struct platform_device *pdev) | ||||||
| { | { | ||||||
| 	struct device *dev = &pdev->dev; | 	struct device *dev = &pdev->dev; | ||||||
| 	struct fimc_context *ctx; | 	struct fimc_context *ctx; | ||||||
| 	struct clk	*parent_clk; |  | ||||||
| 	struct resource *res; | 	struct resource *res; | ||||||
| 	struct exynos_drm_ippdrv *ippdrv; | 	struct exynos_drm_ippdrv *ippdrv; | ||||||
| 	struct exynos_drm_fimc_pdata *pdata; |  | ||||||
| 	struct fimc_driverdata *ddata; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	pdata = pdev->dev.platform_data; | 	if (!dev->of_node) { | ||||||
| 	if (!pdata) { | 		dev_err(dev, "device tree node not found.\n"); | ||||||
| 		dev_err(dev, "no platform data specified.\n"); | 		return -ENODEV; | ||||||
| 		return -EINVAL; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | ||||||
| 	if (!ctx) | 	if (!ctx) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	ddata = (struct fimc_driverdata *) | 	ctx->ippdrv.dev = dev; | ||||||
| 		platform_get_device_id(pdev)->driver_data; |  | ||||||
| 
 | 
 | ||||||
| 	/* clock control */ | 	ret = fimc_parse_dt(ctx); | ||||||
| 	ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc"); | 	if (ret < 0) | ||||||
| 	if (IS_ERR(ctx->sclk_fimc_clk)) { | 		return ret; | ||||||
| 		dev_err(dev, "failed to get src fimc clock.\n"); | 
 | ||||||
| 		return PTR_ERR(ctx->sclk_fimc_clk); | 	ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, | ||||||
|  | 						"samsung,sysreg"); | ||||||
|  | 	if (IS_ERR(ctx->sysreg)) { | ||||||
|  | 		dev_err(dev, "syscon regmap lookup failed.\n"); | ||||||
|  | 		return PTR_ERR(ctx->sysreg); | ||||||
| 	} | 	} | ||||||
| 	clk_enable(ctx->sclk_fimc_clk); |  | ||||||
| 
 |  | ||||||
| 	ctx->fimc_clk = devm_clk_get(dev, "fimc"); |  | ||||||
| 	if (IS_ERR(ctx->fimc_clk)) { |  | ||||||
| 		dev_err(dev, "failed to get fimc clock.\n"); |  | ||||||
| 		clk_disable(ctx->sclk_fimc_clk); |  | ||||||
| 		return PTR_ERR(ctx->fimc_clk); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ctx->wb_clk = devm_clk_get(dev, "pxl_async0"); |  | ||||||
| 	if (IS_ERR(ctx->wb_clk)) { |  | ||||||
| 		dev_err(dev, "failed to get writeback a clock.\n"); |  | ||||||
| 		clk_disable(ctx->sclk_fimc_clk); |  | ||||||
| 		return PTR_ERR(ctx->wb_clk); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1"); |  | ||||||
| 	if (IS_ERR(ctx->wb_b_clk)) { |  | ||||||
| 		dev_err(dev, "failed to get writeback b clock.\n"); |  | ||||||
| 		clk_disable(ctx->sclk_fimc_clk); |  | ||||||
| 		return PTR_ERR(ctx->wb_b_clk); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	parent_clk = devm_clk_get(dev, ddata->parent_clk); |  | ||||||
| 
 |  | ||||||
| 	if (IS_ERR(parent_clk)) { |  | ||||||
| 		dev_err(dev, "failed to get parent clock.\n"); |  | ||||||
| 		clk_disable(ctx->sclk_fimc_clk); |  | ||||||
| 		return PTR_ERR(parent_clk); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) { |  | ||||||
| 		dev_err(dev, "failed to set parent.\n"); |  | ||||||
| 		clk_disable(ctx->sclk_fimc_clk); |  | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	devm_clk_put(dev, parent_clk); |  | ||||||
| 	clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate); |  | ||||||
| 
 | 
 | ||||||
| 	/* resource memory */ | 	/* resource memory */ | ||||||
| 	ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 	ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | @ -1804,13 +1852,11 @@ static int fimc_probe(struct platform_device *pdev) | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* context initailization */ | 	ret = fimc_setup_clocks(ctx); | ||||||
| 	ctx->id = pdev->id; | 	if (ret < 0) | ||||||
| 	ctx->pol = pdata->pol; | 		goto err_free_irq; | ||||||
| 	ctx->ddata = ddata; |  | ||||||
| 
 | 
 | ||||||
| 	ippdrv = &ctx->ippdrv; | 	ippdrv = &ctx->ippdrv; | ||||||
| 	ippdrv->dev = dev; |  | ||||||
| 	ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops; | 	ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops; | ||||||
| 	ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops; | 	ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops; | ||||||
| 	ippdrv->check_property = fimc_ippdrv_check_property; | 	ippdrv->check_property = fimc_ippdrv_check_property; | ||||||
|  | @ -1820,7 +1866,7 @@ static int fimc_probe(struct platform_device *pdev) | ||||||
| 	ret = fimc_init_prop_list(ippdrv); | 	ret = fimc_init_prop_list(ippdrv); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		dev_err(dev, "failed to init property list.\n"); | 		dev_err(dev, "failed to init property list.\n"); | ||||||
| 		goto err_get_irq; | 		goto err_put_clk; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, | 	DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, | ||||||
|  | @ -1835,17 +1881,18 @@ static int fimc_probe(struct platform_device *pdev) | ||||||
| 	ret = exynos_drm_ippdrv_register(ippdrv); | 	ret = exynos_drm_ippdrv_register(ippdrv); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		dev_err(dev, "failed to register drm fimc device.\n"); | 		dev_err(dev, "failed to register drm fimc device.\n"); | ||||||
| 		goto err_ippdrv_register; | 		goto err_pm_dis; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dev_info(&pdev->dev, "drm fimc registered successfully.\n"); | 	dev_info(&pdev->dev, "drm fimc registered successfully.\n"); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| err_ippdrv_register: | err_pm_dis: | ||||||
| 	devm_kfree(dev, ippdrv->prop_list); |  | ||||||
| 	pm_runtime_disable(dev); | 	pm_runtime_disable(dev); | ||||||
| err_get_irq: | err_put_clk: | ||||||
|  | 	fimc_put_clocks(ctx); | ||||||
|  | err_free_irq: | ||||||
| 	free_irq(ctx->irq, ctx); | 	free_irq(ctx->irq, ctx); | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
|  | @ -1857,10 +1904,10 @@ static int fimc_remove(struct platform_device *pdev) | ||||||
| 	struct fimc_context *ctx = get_fimc_context(dev); | 	struct fimc_context *ctx = get_fimc_context(dev); | ||||||
| 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | ||||||
| 
 | 
 | ||||||
| 	devm_kfree(dev, ippdrv->prop_list); |  | ||||||
| 	exynos_drm_ippdrv_unregister(ippdrv); | 	exynos_drm_ippdrv_unregister(ippdrv); | ||||||
| 	mutex_destroy(&ctx->lock); | 	mutex_destroy(&ctx->lock); | ||||||
| 
 | 
 | ||||||
|  | 	fimc_put_clocks(ctx); | ||||||
| 	pm_runtime_set_suspended(dev); | 	pm_runtime_set_suspended(dev); | ||||||
| 	pm_runtime_disable(dev); | 	pm_runtime_disable(dev); | ||||||
| 
 | 
 | ||||||
|  | @ -1915,36 +1962,22 @@ static int fimc_runtime_resume(struct device *dev) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static struct fimc_driverdata exynos4210_fimc_data = { |  | ||||||
| 	.parent_clk = "mout_mpll", |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static struct fimc_driverdata exynos4410_fimc_data = { |  | ||||||
| 	.parent_clk = "mout_mpll_user", |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static struct platform_device_id fimc_driver_ids[] = { |  | ||||||
| 	{ |  | ||||||
| 		.name		= "exynos4210-fimc", |  | ||||||
| 		.driver_data	= (unsigned long)&exynos4210_fimc_data, |  | ||||||
| 	}, { |  | ||||||
| 		.name		= "exynos4412-fimc", |  | ||||||
| 		.driver_data	= (unsigned long)&exynos4410_fimc_data, |  | ||||||
| 	}, |  | ||||||
| 	{}, |  | ||||||
| }; |  | ||||||
| MODULE_DEVICE_TABLE(platform, fimc_driver_ids); |  | ||||||
| 
 |  | ||||||
| static const struct dev_pm_ops fimc_pm_ops = { | static const struct dev_pm_ops fimc_pm_ops = { | ||||||
| 	SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) | 	SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) | ||||||
| 	SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) | 	SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const struct of_device_id fimc_of_match[] = { | ||||||
|  | 	{ .compatible = "samsung,exynos4210-fimc" }, | ||||||
|  | 	{ .compatible = "samsung,exynos4212-fimc" }, | ||||||
|  | 	{ }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct platform_driver fimc_driver = { | struct platform_driver fimc_driver = { | ||||||
| 	.probe		= fimc_probe, | 	.probe		= fimc_probe, | ||||||
| 	.remove		= fimc_remove, | 	.remove		= fimc_remove, | ||||||
| 	.id_table	= fimc_driver_ids, |  | ||||||
| 	.driver		= { | 	.driver		= { | ||||||
|  | 		.of_match_table = fimc_of_match, | ||||||
| 		.name	= "exynos-drm-fimc", | 		.name	= "exynos-drm-fimc", | ||||||
| 		.owner	= THIS_MODULE, | 		.owner	= THIS_MODULE, | ||||||
| 		.pm	= &fimc_pm_ops, | 		.pm	= &fimc_pm_ops, | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| #include <linux/of_device.h> | #include <linux/of_device.h> | ||||||
| #include <linux/pm_runtime.h> | #include <linux/pm_runtime.h> | ||||||
| 
 | 
 | ||||||
|  | #include <video/of_display_timing.h> | ||||||
| #include <video/samsung_fimd.h> | #include <video/samsung_fimd.h> | ||||||
| #include <drm/exynos_drm.h> | #include <drm/exynos_drm.h> | ||||||
| 
 | 
 | ||||||
|  | @ -800,18 +801,18 @@ static int fimd_clock(struct fimd_context *ctx, bool enable) | ||||||
| 	if (enable) { | 	if (enable) { | ||||||
| 		int ret; | 		int ret; | ||||||
| 
 | 
 | ||||||
| 		ret = clk_enable(ctx->bus_clk); | 		ret = clk_prepare_enable(ctx->bus_clk); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
| 			return ret; | 			return ret; | ||||||
| 
 | 
 | ||||||
| 		ret = clk_enable(ctx->lcd_clk); | 		ret = clk_prepare_enable(ctx->lcd_clk); | ||||||
| 		if  (ret < 0) { | 		if  (ret < 0) { | ||||||
| 			clk_disable(ctx->bus_clk); | 			clk_disable_unprepare(ctx->bus_clk); | ||||||
| 			return ret; | 			return ret; | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		clk_disable(ctx->lcd_clk); | 		clk_disable_unprepare(ctx->lcd_clk); | ||||||
| 		clk_disable(ctx->bus_clk); | 		clk_disable_unprepare(ctx->bus_clk); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -884,11 +885,26 @@ static int fimd_probe(struct platform_device *pdev) | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("%s\n", __FILE__); | 	DRM_DEBUG_KMS("%s\n", __FILE__); | ||||||
| 
 | 
 | ||||||
|  | 	if (pdev->dev.of_node) { | ||||||
|  | 		pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||||||
|  | 		if (!pdata) { | ||||||
|  | 			DRM_ERROR("memory allocation for pdata failed\n"); | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		ret = of_get_fb_videomode(dev->of_node, &pdata->panel.timing, | ||||||
|  | 					OF_USE_NATIVE_MODE); | ||||||
|  | 		if (ret) { | ||||||
|  | 			DRM_ERROR("failed: of_get_fb_videomode() : %d\n", ret); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
| 		pdata = pdev->dev.platform_data; | 		pdata = pdev->dev.platform_data; | ||||||
| 		if (!pdata) { | 		if (!pdata) { | ||||||
| 		dev_err(dev, "no platform data specified\n"); | 			DRM_ERROR("no platform data specified\n"); | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	panel = &pdata->panel; | 	panel = &pdata->panel; | ||||||
| 	if (!panel) { | 	if (!panel) { | ||||||
|  | @ -918,7 +934,7 @@ static int fimd_probe(struct platform_device *pdev) | ||||||
| 	if (IS_ERR(ctx->regs)) | 	if (IS_ERR(ctx->regs)) | ||||||
| 		return PTR_ERR(ctx->regs); | 		return PTR_ERR(ctx->regs); | ||||||
| 
 | 
 | ||||||
| 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); | ||||||
| 	if (!res) { | 	if (!res) { | ||||||
| 		dev_err(dev, "irq request failed.\n"); | 		dev_err(dev, "irq request failed.\n"); | ||||||
| 		return -ENXIO; | 		return -ENXIO; | ||||||
|  | @ -980,9 +996,6 @@ static int fimd_remove(struct platform_device *pdev) | ||||||
| 	if (ctx->suspended) | 	if (ctx->suspended) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	clk_disable(ctx->lcd_clk); |  | ||||||
| 	clk_disable(ctx->bus_clk); |  | ||||||
| 
 |  | ||||||
| 	pm_runtime_set_suspended(dev); | 	pm_runtime_set_suspended(dev); | ||||||
| 	pm_runtime_put_sync(dev); | 	pm_runtime_put_sync(dev); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -682,7 +682,8 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, | ||||||
| 	args->pitch = args->width * ((args->bpp + 7) / 8); | 	args->pitch = args->width * ((args->bpp + 7) / 8); | ||||||
| 	args->size = args->pitch * args->height; | 	args->size = args->pitch * args->height; | ||||||
| 
 | 
 | ||||||
| 	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); | 	exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG | | ||||||
|  | 						EXYNOS_BO_WC, args->size); | ||||||
| 	if (IS_ERR(exynos_gem_obj)) | 	if (IS_ERR(exynos_gem_obj)) | ||||||
| 		return PTR_ERR(exynos_gem_obj); | 		return PTR_ERR(exynos_gem_obj); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,21 +51,27 @@ struct drm_hdmi_context { | ||||||
| 
 | 
 | ||||||
| int exynos_platform_device_hdmi_register(void) | int exynos_platform_device_hdmi_register(void) | ||||||
| { | { | ||||||
|  | 	struct platform_device *pdev; | ||||||
|  | 
 | ||||||
| 	if (exynos_drm_hdmi_pdev) | 	if (exynos_drm_hdmi_pdev) | ||||||
| 		return -EEXIST; | 		return -EEXIST; | ||||||
| 
 | 
 | ||||||
| 	exynos_drm_hdmi_pdev = platform_device_register_simple( | 	pdev = platform_device_register_simple( | ||||||
| 			"exynos-drm-hdmi", -1, NULL, 0); | 			"exynos-drm-hdmi", -1, NULL, 0); | ||||||
| 	if (IS_ERR_OR_NULL(exynos_drm_hdmi_pdev)) | 	if (IS_ERR(pdev)) | ||||||
| 		return PTR_ERR(exynos_drm_hdmi_pdev); | 		return PTR_ERR(pdev); | ||||||
|  | 
 | ||||||
|  | 	exynos_drm_hdmi_pdev = pdev; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void exynos_platform_device_hdmi_unregister(void) | void exynos_platform_device_hdmi_unregister(void) | ||||||
| { | { | ||||||
| 	if (exynos_drm_hdmi_pdev) | 	if (exynos_drm_hdmi_pdev) { | ||||||
| 		platform_device_unregister(exynos_drm_hdmi_pdev); | 		platform_device_unregister(exynos_drm_hdmi_pdev); | ||||||
|  | 		exynos_drm_hdmi_pdev = NULL; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx) | void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx) | ||||||
|  | @ -205,13 +211,45 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev, | ||||||
| 				const struct drm_display_mode *mode, | 				const struct drm_display_mode *mode, | ||||||
| 				struct drm_display_mode *adjusted_mode) | 				struct drm_display_mode *adjusted_mode) | ||||||
| { | { | ||||||
| 	struct drm_hdmi_context *ctx = to_context(subdrv_dev); | 	struct drm_display_mode *m; | ||||||
|  | 	int mode_ok; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("%s\n", __FILE__); | 	DRM_DEBUG_KMS("%s\n", __FILE__); | ||||||
| 
 | 
 | ||||||
| 	if (hdmi_ops && hdmi_ops->mode_fixup) | 	drm_mode_set_crtcinfo(adjusted_mode, 0); | ||||||
| 		hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode, | 
 | ||||||
| 				     adjusted_mode); | 	mode_ok = drm_hdmi_check_timing(subdrv_dev, adjusted_mode); | ||||||
|  | 
 | ||||||
|  | 	/* just return if user desired mode exists. */ | ||||||
|  | 	if (mode_ok == 0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * otherwise, find the most suitable mode among modes and change it | ||||||
|  | 	 * to adjusted_mode. | ||||||
|  | 	 */ | ||||||
|  | 	list_for_each_entry(m, &connector->modes, head) { | ||||||
|  | 		mode_ok = drm_hdmi_check_timing(subdrv_dev, m); | ||||||
|  | 
 | ||||||
|  | 		if (mode_ok == 0) { | ||||||
|  | 			struct drm_mode_object base; | ||||||
|  | 			struct list_head head; | ||||||
|  | 
 | ||||||
|  | 			DRM_INFO("desired mode doesn't exist so\n"); | ||||||
|  | 			DRM_INFO("use the most suitable mode among modes.\n"); | ||||||
|  | 
 | ||||||
|  | 			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", | ||||||
|  | 				m->hdisplay, m->vdisplay, m->vrefresh); | ||||||
|  | 
 | ||||||
|  | 			/* preserve display mode header while copying. */ | ||||||
|  | 			head = adjusted_mode->head; | ||||||
|  | 			base = adjusted_mode->base; | ||||||
|  | 			memcpy(adjusted_mode, m, sizeof(*m)); | ||||||
|  | 			adjusted_mode->head = head; | ||||||
|  | 			adjusted_mode->base = base; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode) | static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode) | ||||||
|  |  | ||||||
|  | @ -36,9 +36,6 @@ struct exynos_hdmi_ops { | ||||||
| 	int (*power_on)(void *ctx, int mode); | 	int (*power_on)(void *ctx, int mode); | ||||||
| 
 | 
 | ||||||
| 	/* manager */ | 	/* manager */ | ||||||
| 	void (*mode_fixup)(void *ctx, struct drm_connector *connector, |  | ||||||
| 				const struct drm_display_mode *mode, |  | ||||||
| 				struct drm_display_mode *adjusted_mode); |  | ||||||
| 	void (*mode_set)(void *ctx, void *mode); | 	void (*mode_set)(void *ctx, void *mode); | ||||||
| 	void (*get_max_resol)(void *ctx, unsigned int *width, | 	void (*get_max_resol)(void *ctx, unsigned int *width, | ||||||
| 				unsigned int *height); | 				unsigned int *height); | ||||||
|  |  | ||||||
|  | @ -47,6 +47,9 @@ | ||||||
| #define get_ipp_context(dev)	platform_get_drvdata(to_platform_device(dev)) | #define get_ipp_context(dev)	platform_get_drvdata(to_platform_device(dev)) | ||||||
| #define ipp_is_m2m_cmd(c)	(c == IPP_CMD_M2M) | #define ipp_is_m2m_cmd(c)	(c == IPP_CMD_M2M) | ||||||
| 
 | 
 | ||||||
|  | /* platform device pointer for ipp device. */ | ||||||
|  | static struct platform_device *exynos_drm_ipp_pdev; | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * A structure of event. |  * A structure of event. | ||||||
|  * |  * | ||||||
|  | @ -102,6 +105,30 @@ static LIST_HEAD(exynos_drm_ippdrv_list); | ||||||
| static DEFINE_MUTEX(exynos_drm_ippdrv_lock); | static DEFINE_MUTEX(exynos_drm_ippdrv_lock); | ||||||
| static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); | static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); | ||||||
| 
 | 
 | ||||||
|  | int exynos_platform_device_ipp_register(void) | ||||||
|  | { | ||||||
|  | 	struct platform_device *pdev; | ||||||
|  | 
 | ||||||
|  | 	if (exynos_drm_ipp_pdev) | ||||||
|  | 		return -EEXIST; | ||||||
|  | 
 | ||||||
|  | 	pdev = platform_device_register_simple("exynos-drm-ipp", -1, NULL, 0); | ||||||
|  | 	if (IS_ERR(pdev)) | ||||||
|  | 		return PTR_ERR(pdev); | ||||||
|  | 
 | ||||||
|  | 	exynos_drm_ipp_pdev = pdev; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void exynos_platform_device_ipp_unregister(void) | ||||||
|  | { | ||||||
|  | 	if (exynos_drm_ipp_pdev) { | ||||||
|  | 		platform_device_unregister(exynos_drm_ipp_pdev); | ||||||
|  | 		exynos_drm_ipp_pdev = NULL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) | int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) | ||||||
| { | { | ||||||
| 	DRM_DEBUG_KMS("%s\n", __func__); | 	DRM_DEBUG_KMS("%s\n", __func__); | ||||||
|  |  | ||||||
|  | @ -674,7 +674,7 @@ static int rotator_probe(struct platform_device *pdev) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	rot->clock = devm_clk_get(dev, "rotator"); | 	rot->clock = devm_clk_get(dev, "rotator"); | ||||||
| 	if (IS_ERR_OR_NULL(rot->clock)) { | 	if (IS_ERR(rot->clock)) { | ||||||
| 		dev_err(dev, "failed to get clock\n"); | 		dev_err(dev, "failed to get clock\n"); | ||||||
| 		ret = PTR_ERR(rot->clock); | 		ret = PTR_ERR(rot->clock); | ||||||
| 		goto err_clk_get; | 		goto err_clk_get; | ||||||
|  |  | ||||||
|  | @ -108,7 +108,20 @@ struct hdmi_tg_regs { | ||||||
| 	u8 tg_3d[1]; | 	u8 tg_3d[1]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hdmi_core_regs { | struct hdmi_v13_core_regs { | ||||||
|  | 	u8 h_blank[2]; | ||||||
|  | 	u8 v_blank[3]; | ||||||
|  | 	u8 h_v_line[3]; | ||||||
|  | 	u8 vsync_pol[1]; | ||||||
|  | 	u8 int_pro_mode[1]; | ||||||
|  | 	u8 v_blank_f[3]; | ||||||
|  | 	u8 h_sync_gen[3]; | ||||||
|  | 	u8 v_sync_gen1[3]; | ||||||
|  | 	u8 v_sync_gen2[3]; | ||||||
|  | 	u8 v_sync_gen3[3]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct hdmi_v14_core_regs { | ||||||
| 	u8 h_blank[2]; | 	u8 h_blank[2]; | ||||||
| 	u8 v2_blank[2]; | 	u8 v2_blank[2]; | ||||||
| 	u8 v1_blank[2]; | 	u8 v1_blank[2]; | ||||||
|  | @ -147,11 +160,23 @@ struct hdmi_core_regs { | ||||||
| 	u8 vact_space_6[2]; | 	u8 vact_space_6[2]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hdmi_v14_conf { | struct hdmi_v13_conf { | ||||||
| 	int pixel_clock; | 	struct hdmi_v13_core_regs core; | ||||||
| 	struct hdmi_core_regs core; |  | ||||||
| 	struct hdmi_tg_regs tg; | 	struct hdmi_tg_regs tg; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct hdmi_v14_conf { | ||||||
|  | 	struct hdmi_v14_core_regs core; | ||||||
|  | 	struct hdmi_tg_regs tg; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct hdmi_conf_regs { | ||||||
|  | 	int pixel_clock; | ||||||
| 	int cea_video_id; | 	int cea_video_id; | ||||||
|  | 	union { | ||||||
|  | 		struct hdmi_v13_conf v13_conf; | ||||||
|  | 		struct hdmi_v14_conf v14_conf; | ||||||
|  | 	} conf; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hdmi_context { | struct hdmi_context { | ||||||
|  | @ -169,9 +194,8 @@ struct hdmi_context { | ||||||
| 	struct i2c_client		*ddc_port; | 	struct i2c_client		*ddc_port; | ||||||
| 	struct i2c_client		*hdmiphy_port; | 	struct i2c_client		*hdmiphy_port; | ||||||
| 
 | 
 | ||||||
| 	/* current hdmiphy conf index */ | 	/* current hdmiphy conf regs */ | ||||||
| 	int cur_conf; | 	struct hdmi_conf_regs		mode_conf; | ||||||
| 	struct hdmi_v14_conf		mode_conf; |  | ||||||
| 
 | 
 | ||||||
| 	struct hdmi_resources		res; | 	struct hdmi_resources		res; | ||||||
| 
 | 
 | ||||||
|  | @ -180,292 +204,60 @@ struct hdmi_context { | ||||||
| 	enum hdmi_type			type; | 	enum hdmi_type			type; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* HDMI Version 1.3 */ |  | ||||||
| static const u8 hdmiphy_v13_conf27[32] = { |  | ||||||
| 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, |  | ||||||
| 	0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, |  | ||||||
| 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, |  | ||||||
| 	0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const u8 hdmiphy_v13_conf27_027[32] = { |  | ||||||
| 	0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, |  | ||||||
| 	0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, |  | ||||||
| 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, |  | ||||||
| 	0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const u8 hdmiphy_v13_conf74_175[32] = { |  | ||||||
| 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, |  | ||||||
| 	0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9, |  | ||||||
| 	0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, |  | ||||||
| 	0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const u8 hdmiphy_v13_conf74_25[32] = { |  | ||||||
| 	0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40, |  | ||||||
| 	0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba, |  | ||||||
| 	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0, |  | ||||||
| 	0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const u8 hdmiphy_v13_conf148_5[32] = { |  | ||||||
| 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, |  | ||||||
| 	0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba, |  | ||||||
| 	0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, |  | ||||||
| 	0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct hdmi_v13_tg_regs { |  | ||||||
| 	u8 cmd; |  | ||||||
| 	u8 h_fsz_l; |  | ||||||
| 	u8 h_fsz_h; |  | ||||||
| 	u8 hact_st_l; |  | ||||||
| 	u8 hact_st_h; |  | ||||||
| 	u8 hact_sz_l; |  | ||||||
| 	u8 hact_sz_h; |  | ||||||
| 	u8 v_fsz_l; |  | ||||||
| 	u8 v_fsz_h; |  | ||||||
| 	u8 vsync_l; |  | ||||||
| 	u8 vsync_h; |  | ||||||
| 	u8 vsync2_l; |  | ||||||
| 	u8 vsync2_h; |  | ||||||
| 	u8 vact_st_l; |  | ||||||
| 	u8 vact_st_h; |  | ||||||
| 	u8 vact_sz_l; |  | ||||||
| 	u8 vact_sz_h; |  | ||||||
| 	u8 field_chg_l; |  | ||||||
| 	u8 field_chg_h; |  | ||||||
| 	u8 vact_st2_l; |  | ||||||
| 	u8 vact_st2_h; |  | ||||||
| 	u8 vsync_top_hdmi_l; |  | ||||||
| 	u8 vsync_top_hdmi_h; |  | ||||||
| 	u8 vsync_bot_hdmi_l; |  | ||||||
| 	u8 vsync_bot_hdmi_h; |  | ||||||
| 	u8 field_top_hdmi_l; |  | ||||||
| 	u8 field_top_hdmi_h; |  | ||||||
| 	u8 field_bot_hdmi_l; |  | ||||||
| 	u8 field_bot_hdmi_h; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct hdmi_v13_core_regs { |  | ||||||
| 	u8 h_blank[2]; |  | ||||||
| 	u8 v_blank[3]; |  | ||||||
| 	u8 h_v_line[3]; |  | ||||||
| 	u8 vsync_pol[1]; |  | ||||||
| 	u8 int_pro_mode[1]; |  | ||||||
| 	u8 v_blank_f[3]; |  | ||||||
| 	u8 h_sync_gen[3]; |  | ||||||
| 	u8 v_sync_gen1[3]; |  | ||||||
| 	u8 v_sync_gen2[3]; |  | ||||||
| 	u8 v_sync_gen3[3]; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct hdmi_v13_preset_conf { |  | ||||||
| 	struct hdmi_v13_core_regs core; |  | ||||||
| 	struct hdmi_v13_tg_regs tg; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct hdmi_v13_conf { |  | ||||||
| 	int width; |  | ||||||
| 	int height; |  | ||||||
| 	int vrefresh; |  | ||||||
| 	bool interlace; |  | ||||||
| 	int cea_video_id; |  | ||||||
| 	const u8 *hdmiphy_data; |  | ||||||
| 	const struct hdmi_v13_preset_conf *conf; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_preset_conf hdmi_v13_conf_480p = { |  | ||||||
| 	.core = { |  | ||||||
| 		.h_blank = {0x8a, 0x00}, |  | ||||||
| 		.v_blank = {0x0d, 0x6a, 0x01}, |  | ||||||
| 		.h_v_line = {0x0d, 0xa2, 0x35}, |  | ||||||
| 		.vsync_pol = {0x01}, |  | ||||||
| 		.int_pro_mode = {0x00}, |  | ||||||
| 		.v_blank_f = {0x00, 0x00, 0x00}, |  | ||||||
| 		.h_sync_gen = {0x0e, 0x30, 0x11}, |  | ||||||
| 		.v_sync_gen1 = {0x0f, 0x90, 0x00}, |  | ||||||
| 		/* other don't care */ |  | ||||||
| 	}, |  | ||||||
| 	.tg = { |  | ||||||
| 		0x00, /* cmd */ |  | ||||||
| 		0x5a, 0x03, /* h_fsz */ |  | ||||||
| 		0x8a, 0x00, 0xd0, 0x02, /* hact */ |  | ||||||
| 		0x0d, 0x02, /* v_fsz */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync */ |  | ||||||
| 		0x2d, 0x00, 0xe0, 0x01, /* vact */ |  | ||||||
| 		0x33, 0x02, /* field_chg */ |  | ||||||
| 		0x49, 0x02, /* vact_st2 */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* field top/bot */ |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_preset_conf hdmi_v13_conf_720p60 = { |  | ||||||
| 	.core = { |  | ||||||
| 		.h_blank = {0x72, 0x01}, |  | ||||||
| 		.v_blank = {0xee, 0xf2, 0x00}, |  | ||||||
| 		.h_v_line = {0xee, 0x22, 0x67}, |  | ||||||
| 		.vsync_pol = {0x00}, |  | ||||||
| 		.int_pro_mode = {0x00}, |  | ||||||
| 		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ |  | ||||||
| 		.h_sync_gen = {0x6c, 0x50, 0x02}, |  | ||||||
| 		.v_sync_gen1 = {0x0a, 0x50, 0x00}, |  | ||||||
| 		.v_sync_gen2 = {0x01, 0x10, 0x00}, |  | ||||||
| 		.v_sync_gen3 = {0x01, 0x10, 0x00}, |  | ||||||
| 		/* other don't care */ |  | ||||||
| 	}, |  | ||||||
| 	.tg = { |  | ||||||
| 		0x00, /* cmd */ |  | ||||||
| 		0x72, 0x06, /* h_fsz */ |  | ||||||
| 		0x71, 0x01, 0x01, 0x05, /* hact */ |  | ||||||
| 		0xee, 0x02, /* v_fsz */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync */ |  | ||||||
| 		0x1e, 0x00, 0xd0, 0x02, /* vact */ |  | ||||||
| 		0x33, 0x02, /* field_chg */ |  | ||||||
| 		0x49, 0x02, /* vact_st2 */ |  | ||||||
| 		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* field top/bot */ |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i50 = { |  | ||||||
| 	.core = { |  | ||||||
| 		.h_blank = {0xd0, 0x02}, |  | ||||||
| 		.v_blank = {0x32, 0xB2, 0x00}, |  | ||||||
| 		.h_v_line = {0x65, 0x04, 0xa5}, |  | ||||||
| 		.vsync_pol = {0x00}, |  | ||||||
| 		.int_pro_mode = {0x01}, |  | ||||||
| 		.v_blank_f = {0x49, 0x2A, 0x23}, |  | ||||||
| 		.h_sync_gen = {0x0E, 0xEA, 0x08}, |  | ||||||
| 		.v_sync_gen1 = {0x07, 0x20, 0x00}, |  | ||||||
| 		.v_sync_gen2 = {0x39, 0x42, 0x23}, |  | ||||||
| 		.v_sync_gen3 = {0x38, 0x87, 0x73}, |  | ||||||
| 		/* other don't care */ |  | ||||||
| 	}, |  | ||||||
| 	.tg = { |  | ||||||
| 		0x00, /* cmd */ |  | ||||||
| 		0x50, 0x0A, /* h_fsz */ |  | ||||||
| 		0xCF, 0x02, 0x81, 0x07, /* hact */ |  | ||||||
| 		0x65, 0x04, /* v_fsz */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync */ |  | ||||||
| 		0x16, 0x00, 0x1c, 0x02, /* vact */ |  | ||||||
| 		0x33, 0x02, /* field_chg */ |  | ||||||
| 		0x49, 0x02, /* vact_st2 */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* field top/bot */ |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p50 = { |  | ||||||
| 	.core = { |  | ||||||
| 		.h_blank = {0xd0, 0x02}, |  | ||||||
| 		.v_blank = {0x65, 0x6c, 0x01}, |  | ||||||
| 		.h_v_line = {0x65, 0x04, 0xa5}, |  | ||||||
| 		.vsync_pol = {0x00}, |  | ||||||
| 		.int_pro_mode = {0x00}, |  | ||||||
| 		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ |  | ||||||
| 		.h_sync_gen = {0x0e, 0xea, 0x08}, |  | ||||||
| 		.v_sync_gen1 = {0x09, 0x40, 0x00}, |  | ||||||
| 		.v_sync_gen2 = {0x01, 0x10, 0x00}, |  | ||||||
| 		.v_sync_gen3 = {0x01, 0x10, 0x00}, |  | ||||||
| 		/* other don't care */ |  | ||||||
| 	}, |  | ||||||
| 	.tg = { |  | ||||||
| 		0x00, /* cmd */ |  | ||||||
| 		0x50, 0x0A, /* h_fsz */ |  | ||||||
| 		0xCF, 0x02, 0x81, 0x07, /* hact */ |  | ||||||
| 		0x65, 0x04, /* v_fsz */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync */ |  | ||||||
| 		0x2d, 0x00, 0x38, 0x04, /* vact */ |  | ||||||
| 		0x33, 0x02, /* field_chg */ |  | ||||||
| 		0x48, 0x02, /* vact_st2 */ |  | ||||||
| 		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* field top/bot */ |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i60 = { |  | ||||||
| 	.core = { |  | ||||||
| 		.h_blank = {0x18, 0x01}, |  | ||||||
| 		.v_blank = {0x32, 0xB2, 0x00}, |  | ||||||
| 		.h_v_line = {0x65, 0x84, 0x89}, |  | ||||||
| 		.vsync_pol = {0x00}, |  | ||||||
| 		.int_pro_mode = {0x01}, |  | ||||||
| 		.v_blank_f = {0x49, 0x2A, 0x23}, |  | ||||||
| 		.h_sync_gen = {0x56, 0x08, 0x02}, |  | ||||||
| 		.v_sync_gen1 = {0x07, 0x20, 0x00}, |  | ||||||
| 		.v_sync_gen2 = {0x39, 0x42, 0x23}, |  | ||||||
| 		.v_sync_gen3 = {0xa4, 0x44, 0x4a}, |  | ||||||
| 		/* other don't care */ |  | ||||||
| 	}, |  | ||||||
| 	.tg = { |  | ||||||
| 		0x00, /* cmd */ |  | ||||||
| 		0x98, 0x08, /* h_fsz */ |  | ||||||
| 		0x17, 0x01, 0x81, 0x07, /* hact */ |  | ||||||
| 		0x65, 0x04, /* v_fsz */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync */ |  | ||||||
| 		0x16, 0x00, 0x1c, 0x02, /* vact */ |  | ||||||
| 		0x33, 0x02, /* field_chg */ |  | ||||||
| 		0x49, 0x02, /* vact_st2 */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* field top/bot */ |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p60 = { |  | ||||||
| 	.core = { |  | ||||||
| 		.h_blank = {0x18, 0x01}, |  | ||||||
| 		.v_blank = {0x65, 0x6c, 0x01}, |  | ||||||
| 		.h_v_line = {0x65, 0x84, 0x89}, |  | ||||||
| 		.vsync_pol = {0x00}, |  | ||||||
| 		.int_pro_mode = {0x00}, |  | ||||||
| 		.v_blank_f = {0x00, 0x00, 0x00}, /* don't care */ |  | ||||||
| 		.h_sync_gen = {0x56, 0x08, 0x02}, |  | ||||||
| 		.v_sync_gen1 = {0x09, 0x40, 0x00}, |  | ||||||
| 		.v_sync_gen2 = {0x01, 0x10, 0x00}, |  | ||||||
| 		.v_sync_gen3 = {0x01, 0x10, 0x00}, |  | ||||||
| 		/* other don't care */ |  | ||||||
| 	}, |  | ||||||
| 	.tg = { |  | ||||||
| 		0x00, /* cmd */ |  | ||||||
| 		0x98, 0x08, /* h_fsz */ |  | ||||||
| 		0x17, 0x01, 0x81, 0x07, /* hact */ |  | ||||||
| 		0x65, 0x04, /* v_fsz */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* vsync */ |  | ||||||
| 		0x2d, 0x00, 0x38, 0x04, /* vact */ |  | ||||||
| 		0x33, 0x02, /* field_chg */ |  | ||||||
| 		0x48, 0x02, /* vact_st2 */ |  | ||||||
| 		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ |  | ||||||
| 		0x01, 0x00, 0x33, 0x02, /* field top/bot */ |  | ||||||
| 	}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const struct hdmi_v13_conf hdmi_v13_confs[] = { |  | ||||||
| 	{ 1280, 720, 60, false, 4, hdmiphy_v13_conf74_25, |  | ||||||
| 			&hdmi_v13_conf_720p60 }, |  | ||||||
| 	{ 1280, 720, 50, false, 19, hdmiphy_v13_conf74_25, |  | ||||||
| 			&hdmi_v13_conf_720p60 }, |  | ||||||
| 	{ 720, 480, 60, false, 3, hdmiphy_v13_conf27_027, |  | ||||||
| 			&hdmi_v13_conf_480p }, |  | ||||||
| 	{ 1920, 1080, 50, true, 20, hdmiphy_v13_conf74_25, |  | ||||||
| 			&hdmi_v13_conf_1080i50 }, |  | ||||||
| 	{ 1920, 1080, 50, false, 31, hdmiphy_v13_conf148_5, |  | ||||||
| 			&hdmi_v13_conf_1080p50 }, |  | ||||||
| 	{ 1920, 1080, 60, true, 5, hdmiphy_v13_conf74_25, |  | ||||||
| 			&hdmi_v13_conf_1080i60 }, |  | ||||||
| 	{ 1920, 1080, 60, false, 16, hdmiphy_v13_conf148_5, |  | ||||||
| 			&hdmi_v13_conf_1080p60 }, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /* HDMI Version 1.4 */ |  | ||||||
| struct hdmiphy_config { | struct hdmiphy_config { | ||||||
| 	int pixel_clock; | 	int pixel_clock; | ||||||
| 	u8 conf[32]; | 	u8 conf[32]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* list of all required phy config settings */ | /* list of phy config settings */ | ||||||
|  | static const struct hdmiphy_config hdmiphy_v13_configs[] = { | ||||||
|  | 	{ | ||||||
|  | 		.pixel_clock = 27000000, | ||||||
|  | 		.conf = { | ||||||
|  | 			0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40, | ||||||
|  | 			0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, | ||||||
|  | 			0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||||||
|  | 			0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		.pixel_clock = 27027000, | ||||||
|  | 		.conf = { | ||||||
|  | 			0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64, | ||||||
|  | 			0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87, | ||||||
|  | 			0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||||||
|  | 			0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		.pixel_clock = 74176000, | ||||||
|  | 		.conf = { | ||||||
|  | 			0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B, | ||||||
|  | 			0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9, | ||||||
|  | 			0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||||||
|  | 			0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		.pixel_clock = 74250000, | ||||||
|  | 		.conf = { | ||||||
|  | 			0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40, | ||||||
|  | 			0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba, | ||||||
|  | 			0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0, | ||||||
|  | 			0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		.pixel_clock = 148500000, | ||||||
|  | 		.conf = { | ||||||
|  | 			0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40, | ||||||
|  | 			0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba, | ||||||
|  | 			0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0, | ||||||
|  | 			0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static const struct hdmiphy_config hdmiphy_v14_configs[] = { | static const struct hdmiphy_config hdmiphy_v14_configs[] = { | ||||||
| 	{ | 	{ | ||||||
| 		.pixel_clock = 25200000, | 		.pixel_clock = 25200000, | ||||||
|  | @ -873,22 +665,6 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) | ||||||
| 		hdmi_v14_regs_dump(hdata, prefix); | 		hdmi_v14_regs_dump(hdata, prefix); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int hdmi_v13_conf_index(struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i) |  | ||||||
| 		if (hdmi_v13_confs[i].width == mode->hdisplay && |  | ||||||
| 				hdmi_v13_confs[i].height == mode->vdisplay && |  | ||||||
| 				hdmi_v13_confs[i].vrefresh == mode->vrefresh && |  | ||||||
| 				hdmi_v13_confs[i].interlace == |  | ||||||
| 				((mode->flags & DRM_MODE_FLAG_INTERLACE) ? |  | ||||||
| 				 true : false)) |  | ||||||
| 			return i; |  | ||||||
| 
 |  | ||||||
| 	return -EINVAL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static u8 hdmi_chksum(struct hdmi_context *hdata, | static u8 hdmi_chksum(struct hdmi_context *hdata, | ||||||
| 			u32 start, u8 len, u32 hdr_sum) | 			u32 start, u8 len, u32 hdr_sum) | ||||||
| { | { | ||||||
|  | @ -943,11 +719,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, | ||||||
| 		hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio | | 		hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio | | ||||||
| 				AVI_SAME_AS_PIC_ASPECT_RATIO); | 				AVI_SAME_AS_PIC_ASPECT_RATIO); | ||||||
| 
 | 
 | ||||||
| 		if (hdata->type == HDMI_TYPE13) |  | ||||||
| 			vic = hdmi_v13_confs[hdata->cur_conf].cea_video_id; |  | ||||||
| 		else |  | ||||||
| 		vic = hdata->mode_conf.cea_video_id; | 		vic = hdata->mode_conf.cea_video_id; | ||||||
| 
 |  | ||||||
| 		hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); | 		hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); | ||||||
| 
 | 
 | ||||||
| 		chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), | 		chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), | ||||||
|  | @ -1000,63 +772,34 @@ static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector) | ||||||
| 	return raw_edid; | 	return raw_edid; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int hdmi_v13_check_timing(struct fb_videomode *check_timing) | static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) | ||||||
| { | { | ||||||
| 	int i; | 	const struct hdmiphy_config *confs; | ||||||
|  | 	int count, i; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n", | 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||||||
| 			check_timing->xres, check_timing->yres, |  | ||||||
| 			check_timing->refresh, (check_timing->vmode & |  | ||||||
| 			FB_VMODE_INTERLACED) ? true : false); |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i) |  | ||||||
| 		if (hdmi_v13_confs[i].width == check_timing->xres && |  | ||||||
| 			hdmi_v13_confs[i].height == check_timing->yres && |  | ||||||
| 			hdmi_v13_confs[i].vrefresh == check_timing->refresh && |  | ||||||
| 			hdmi_v13_confs[i].interlace == |  | ||||||
| 			((check_timing->vmode & FB_VMODE_INTERLACED) ? |  | ||||||
| 			 true : false)) |  | ||||||
| 				return 0; |  | ||||||
| 
 |  | ||||||
| 	/* TODO */ |  | ||||||
| 
 | 
 | ||||||
|  | 	if (hdata->type == HDMI_TYPE13) { | ||||||
|  | 		confs = hdmiphy_v13_configs; | ||||||
|  | 		count = ARRAY_SIZE(hdmiphy_v13_configs); | ||||||
|  | 	} else if (hdata->type == HDMI_TYPE14) { | ||||||
|  | 		confs = hdmiphy_v14_configs; | ||||||
|  | 		count = ARRAY_SIZE(hdmiphy_v14_configs); | ||||||
|  | 	} else | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static int hdmi_v14_find_phy_conf(int pixel_clock) | 	for (i = 0; i < count; i++) | ||||||
| { | 		if (confs[i].pixel_clock == pixel_clock) | ||||||
| 	int i; |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) { |  | ||||||
| 		if (hdmiphy_v14_configs[i].pixel_clock == pixel_clock) |  | ||||||
| 			return i; | 			return i; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); | 	DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); | ||||||
| 	return -EINVAL; | 	return -EINVAL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int hdmi_v14_check_timing(struct fb_videomode *check_timing) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_KMS("mode: xres=%d, yres=%d, refresh=%d, clock=%d, intl=%d\n", |  | ||||||
| 			check_timing->xres, check_timing->yres, |  | ||||||
| 			check_timing->refresh, check_timing->pixclock, |  | ||||||
| 			(check_timing->vmode & FB_VMODE_INTERLACED) ? |  | ||||||
| 			true : false); |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) |  | ||||||
| 		if (hdmiphy_v14_configs[i].pixel_clock == |  | ||||||
| 			check_timing->pixclock) |  | ||||||
| 			return 0; |  | ||||||
| 
 |  | ||||||
| 	return -EINVAL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int hdmi_check_timing(void *ctx, struct fb_videomode *timing) | static int hdmi_check_timing(void *ctx, struct fb_videomode *timing) | ||||||
| { | { | ||||||
| 	struct hdmi_context *hdata = ctx; | 	struct hdmi_context *hdata = ctx; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | ||||||
| 
 | 
 | ||||||
|  | @ -1064,10 +807,10 @@ static int hdmi_check_timing(void *ctx, struct fb_videomode *timing) | ||||||
| 			timing->yres, timing->refresh, | 			timing->yres, timing->refresh, | ||||||
| 			timing->vmode); | 			timing->vmode); | ||||||
| 
 | 
 | ||||||
| 	if (hdata->type == HDMI_TYPE13) | 	ret = hdmi_find_phy_conf(hdata, timing->pixclock); | ||||||
| 		return hdmi_v13_check_timing(timing); | 	if (ret < 0) | ||||||
| 	else | 		return ret; | ||||||
| 		return hdmi_v14_check_timing(timing); | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void hdmi_set_acr(u32 freq, u8 *acr) | static void hdmi_set_acr(u32 freq, u8 *acr) | ||||||
|  | @ -1301,10 +1044,9 @@ static void hdmi_conf_init(struct hdmi_context *hdata) | ||||||
| 
 | 
 | ||||||
| static void hdmi_v13_timing_apply(struct hdmi_context *hdata) | static void hdmi_v13_timing_apply(struct hdmi_context *hdata) | ||||||
| { | { | ||||||
| 	const struct hdmi_v13_preset_conf *conf = | 	const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg; | ||||||
| 		hdmi_v13_confs[hdata->cur_conf].conf; | 	const struct hdmi_v13_core_regs *core = | ||||||
| 	const struct hdmi_v13_core_regs *core = &conf->core; | 		&hdata->mode_conf.conf.v13_conf.core; | ||||||
| 	const struct hdmi_v13_tg_regs *tg = &conf->tg; |  | ||||||
| 	int tries; | 	int tries; | ||||||
| 
 | 
 | ||||||
| 	/* setting core registers */ | 	/* setting core registers */ | ||||||
|  | @ -1334,34 +1076,34 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata) | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]); | 	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]); | 	hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]); | ||||||
| 	/* Timing generator registers */ | 	/* Timing generator registers */ | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l); | 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]); | ||||||
| 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h); | 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]); | ||||||
| 
 | 
 | ||||||
| 	/* waiting for HDMIPHY's PLL to get to steady state */ | 	/* waiting for HDMIPHY's PLL to get to steady state */ | ||||||
| 	for (tries = 100; tries; --tries) { | 	for (tries = 100; tries; --tries) { | ||||||
|  | @ -1391,8 +1133,9 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata) | ||||||
| 
 | 
 | ||||||
| static void hdmi_v14_timing_apply(struct hdmi_context *hdata) | static void hdmi_v14_timing_apply(struct hdmi_context *hdata) | ||||||
| { | { | ||||||
| 	struct hdmi_core_regs *core = &hdata->mode_conf.core; | 	const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg; | ||||||
| 	struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; | 	const struct hdmi_v14_core_regs *core = | ||||||
|  | 		&hdata->mode_conf.conf.v14_conf.core; | ||||||
| 	int tries; | 	int tries; | ||||||
| 
 | 
 | ||||||
| 	/* setting core registers */ | 	/* setting core registers */ | ||||||
|  | @ -1624,17 +1367,16 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* pixel clock */ | 	/* pixel clock */ | ||||||
| 	if (hdata->type == HDMI_TYPE13) { | 	i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock); | ||||||
| 		hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data; |  | ||||||
| 	} else { |  | ||||||
| 		i = hdmi_v14_find_phy_conf(hdata->mode_conf.pixel_clock); |  | ||||||
| 	if (i < 0) { | 	if (i < 0) { | ||||||
| 		DRM_ERROR("failed to find hdmiphy conf\n"); | 		DRM_ERROR("failed to find hdmiphy conf\n"); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (hdata->type == HDMI_TYPE13) | ||||||
|  | 		hdmiphy_data = hdmiphy_v13_configs[i].conf; | ||||||
|  | 	else | ||||||
| 		hdmiphy_data = hdmiphy_v14_configs[i].conf; | 		hdmiphy_data = hdmiphy_v14_configs[i].conf; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	memcpy(buffer, hdmiphy_data, 32); | 	memcpy(buffer, hdmiphy_data, 32); | ||||||
| 	ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32); | 	ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32); | ||||||
|  | @ -1687,58 +1429,6 @@ static void hdmi_conf_apply(struct hdmi_context *hdata) | ||||||
| 	hdmi_regs_dump(hdata, "start"); | 	hdmi_regs_dump(hdata, "start"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, |  | ||||||
| 				const struct drm_display_mode *mode, |  | ||||||
| 				struct drm_display_mode *adjusted_mode) |  | ||||||
| { |  | ||||||
| 	struct drm_display_mode *m; |  | ||||||
| 	struct hdmi_context *hdata = ctx; |  | ||||||
| 	int index; |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); |  | ||||||
| 
 |  | ||||||
| 	drm_mode_set_crtcinfo(adjusted_mode, 0); |  | ||||||
| 
 |  | ||||||
| 	if (hdata->type == HDMI_TYPE13) |  | ||||||
| 		index = hdmi_v13_conf_index(adjusted_mode); |  | ||||||
| 	else |  | ||||||
| 		index = hdmi_v14_find_phy_conf(adjusted_mode->clock * 1000); |  | ||||||
| 
 |  | ||||||
| 	/* just return if user desired mode exists. */ |  | ||||||
| 	if (index >= 0) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * otherwise, find the most suitable mode among modes and change it |  | ||||||
| 	 * to adjusted_mode. |  | ||||||
| 	 */ |  | ||||||
| 	list_for_each_entry(m, &connector->modes, head) { |  | ||||||
| 		if (hdata->type == HDMI_TYPE13) |  | ||||||
| 			index = hdmi_v13_conf_index(m); |  | ||||||
| 		else |  | ||||||
| 			index = hdmi_v14_find_phy_conf(m->clock * 1000); |  | ||||||
| 
 |  | ||||||
| 		if (index >= 0) { |  | ||||||
| 			struct drm_mode_object base; |  | ||||||
| 			struct list_head head; |  | ||||||
| 
 |  | ||||||
| 			DRM_INFO("desired mode doesn't exist so\n"); |  | ||||||
| 			DRM_INFO("use the most suitable mode among modes.\n"); |  | ||||||
| 
 |  | ||||||
| 			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", |  | ||||||
| 				m->hdisplay, m->vdisplay, m->vrefresh); |  | ||||||
| 
 |  | ||||||
| 			/* preserve display mode header while copying. */ |  | ||||||
| 			head = adjusted_mode->head; |  | ||||||
| 			base = adjusted_mode->base; |  | ||||||
| 			memcpy(adjusted_mode, m, sizeof(*m)); |  | ||||||
| 			adjusted_mode->head = head; |  | ||||||
| 			adjusted_mode->base = base; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) | static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -1747,15 +1437,113 @@ static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) | ||||||
| 		reg_pair[i] = (value >> (8 * i)) & 0xff; | 		reg_pair[i] = (value >> (8 * i)) & 0xff; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void hdmi_v13_mode_set(struct hdmi_context *hdata, | ||||||
|  | 			struct drm_display_mode *m) | ||||||
|  | { | ||||||
|  | 	struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core; | ||||||
|  | 	struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg; | ||||||
|  | 	unsigned int val; | ||||||
|  | 
 | ||||||
|  | 	hdata->mode_conf.cea_video_id = | ||||||
|  | 		drm_match_cea_mode((struct drm_display_mode *)m); | ||||||
|  | 	hdata->mode_conf.pixel_clock = m->clock * 1000; | ||||||
|  | 
 | ||||||
|  | 	hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); | ||||||
|  | 	hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal); | ||||||
|  | 
 | ||||||
|  | 	val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; | ||||||
|  | 	hdmi_set_reg(core->vsync_pol, 1, val); | ||||||
|  | 
 | ||||||
|  | 	val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0; | ||||||
|  | 	hdmi_set_reg(core->int_pro_mode, 1, val); | ||||||
|  | 
 | ||||||
|  | 	val = (m->hsync_start - m->hdisplay - 2); | ||||||
|  | 	val |= ((m->hsync_end - m->hdisplay - 2) << 10); | ||||||
|  | 	val |= ((m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0)<<20; | ||||||
|  | 	hdmi_set_reg(core->h_sync_gen, 3, val); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Quirk requirement for exynos HDMI IP design, | ||||||
|  | 	 * 2 pixels less than the actual calculation for hsync_start | ||||||
|  | 	 * and end. | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	/* Following values & calculations differ for different type of modes */ | ||||||
|  | 	if (m->flags & DRM_MODE_FLAG_INTERLACE) { | ||||||
|  | 		/* Interlaced Mode */ | ||||||
|  | 		val = ((m->vsync_end - m->vdisplay) / 2); | ||||||
|  | 		val |= ((m->vsync_start - m->vdisplay) / 2) << 12; | ||||||
|  | 		hdmi_set_reg(core->v_sync_gen1, 3, val); | ||||||
|  | 
 | ||||||
|  | 		val = m->vtotal / 2; | ||||||
|  | 		val |= ((m->vtotal - m->vdisplay) / 2) << 11; | ||||||
|  | 		hdmi_set_reg(core->v_blank, 3, val); | ||||||
|  | 
 | ||||||
|  | 		val = (m->vtotal + | ||||||
|  | 			((m->vsync_end - m->vsync_start) * 4) + 5) / 2; | ||||||
|  | 		val |= m->vtotal << 11; | ||||||
|  | 		hdmi_set_reg(core->v_blank_f, 3, val); | ||||||
|  | 
 | ||||||
|  | 		val = ((m->vtotal / 2) + 7); | ||||||
|  | 		val |= ((m->vtotal / 2) + 2) << 12; | ||||||
|  | 		hdmi_set_reg(core->v_sync_gen2, 3, val); | ||||||
|  | 
 | ||||||
|  | 		val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay)); | ||||||
|  | 		val |= ((m->htotal / 2) + | ||||||
|  | 			(m->hsync_start - m->hdisplay)) << 12; | ||||||
|  | 		hdmi_set_reg(core->v_sync_gen3, 3, val); | ||||||
|  | 
 | ||||||
|  | 		hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2); | ||||||
|  | 		hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2); | ||||||
|  | 
 | ||||||
|  | 		hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/ | ||||||
|  | 	} else { | ||||||
|  | 		/* Progressive Mode */ | ||||||
|  | 
 | ||||||
|  | 		val = m->vtotal; | ||||||
|  | 		val |= (m->vtotal - m->vdisplay) << 11; | ||||||
|  | 		hdmi_set_reg(core->v_blank, 3, val); | ||||||
|  | 
 | ||||||
|  | 		hdmi_set_reg(core->v_blank_f, 3, 0); | ||||||
|  | 
 | ||||||
|  | 		val = (m->vsync_end - m->vdisplay); | ||||||
|  | 		val |= ((m->vsync_start - m->vdisplay) << 12); | ||||||
|  | 		hdmi_set_reg(core->v_sync_gen1, 3, val); | ||||||
|  | 
 | ||||||
|  | 		hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value  */ | ||||||
|  | 		hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value  */ | ||||||
|  | 		hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay); | ||||||
|  | 		hdmi_set_reg(tg->vact_sz, 2, m->vdisplay); | ||||||
|  | 		hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Timing generator registers */ | ||||||
|  | 	hdmi_set_reg(tg->cmd, 1, 0x0); | ||||||
|  | 	hdmi_set_reg(tg->h_fsz, 2, m->htotal); | ||||||
|  | 	hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay); | ||||||
|  | 	hdmi_set_reg(tg->hact_sz, 2, m->hdisplay); | ||||||
|  | 	hdmi_set_reg(tg->v_fsz, 2, m->vtotal); | ||||||
|  | 	hdmi_set_reg(tg->vsync, 2, 0x1); | ||||||
|  | 	hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */ | ||||||
|  | 	hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */ | ||||||
|  | 	hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */ | ||||||
|  | 	hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */ | ||||||
|  | 	hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ | ||||||
|  | 	hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ | ||||||
|  | 	hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void hdmi_v14_mode_set(struct hdmi_context *hdata, | static void hdmi_v14_mode_set(struct hdmi_context *hdata, | ||||||
| 			struct drm_display_mode *m) | 			struct drm_display_mode *m) | ||||||
| { | { | ||||||
| 	struct hdmi_core_regs *core = &hdata->mode_conf.core; | 	struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg; | ||||||
| 	struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; | 	struct hdmi_v14_core_regs *core = | ||||||
| 
 | 		&hdata->mode_conf.conf.v14_conf.core; | ||||||
| 	hdata->mode_conf.cea_video_id = drm_match_cea_mode(m); |  | ||||||
| 
 | 
 | ||||||
|  | 	hdata->mode_conf.cea_video_id = | ||||||
|  | 		drm_match_cea_mode((struct drm_display_mode *)m); | ||||||
| 	hdata->mode_conf.pixel_clock = m->clock * 1000; | 	hdata->mode_conf.pixel_clock = m->clock * 1000; | ||||||
|  | 
 | ||||||
| 	hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); | 	hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); | ||||||
| 	hdmi_set_reg(core->v_line, 2, m->vtotal); | 	hdmi_set_reg(core->v_line, 2, m->vtotal); | ||||||
| 	hdmi_set_reg(core->h_line, 2, m->htotal); | 	hdmi_set_reg(core->h_line, 2, m->htotal); | ||||||
|  | @ -1852,25 +1640,22 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, | ||||||
| 	hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ | 	hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ | ||||||
| 	hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ | 	hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ | ||||||
| 	hdmi_set_reg(tg->tg_3d, 1, 0x0); | 	hdmi_set_reg(tg->tg_3d, 1, 0x0); | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void hdmi_mode_set(void *ctx, void *mode) | static void hdmi_mode_set(void *ctx, void *mode) | ||||||
| { | { | ||||||
| 	struct hdmi_context *hdata = ctx; | 	struct hdmi_context *hdata = ctx; | ||||||
| 	int conf_idx; | 	struct drm_display_mode *m = mode; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); | 	DRM_DEBUG_KMS("[%s]: xres=%d, yres=%d, refresh=%d, intl=%s\n", | ||||||
|  | 		__func__, m->hdisplay, m->vdisplay, | ||||||
|  | 		m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? | ||||||
|  | 		"INTERLACED" : "PROGERESSIVE"); | ||||||
| 
 | 
 | ||||||
| 	if (hdata->type == HDMI_TYPE13) { | 	if (hdata->type == HDMI_TYPE13) | ||||||
| 		conf_idx = hdmi_v13_conf_index(mode); | 		hdmi_v13_mode_set(hdata, mode); | ||||||
| 		if (conf_idx >= 0) |  | ||||||
| 			hdata->cur_conf = conf_idx; |  | ||||||
| 	else | 	else | ||||||
| 			DRM_DEBUG_KMS("not supported mode\n"); |  | ||||||
| 	} else { |  | ||||||
| 		hdmi_v14_mode_set(hdata, mode); | 		hdmi_v14_mode_set(hdata, mode); | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void hdmi_get_max_resol(void *ctx, unsigned int *width, | static void hdmi_get_max_resol(void *ctx, unsigned int *width, | ||||||
|  | @ -1983,7 +1768,6 @@ static struct exynos_hdmi_ops hdmi_ops = { | ||||||
| 	.check_timing	= hdmi_check_timing, | 	.check_timing	= hdmi_check_timing, | ||||||
| 
 | 
 | ||||||
| 	/* manager */ | 	/* manager */ | ||||||
| 	.mode_fixup	= hdmi_mode_fixup, |  | ||||||
| 	.mode_set	= hdmi_mode_set, | 	.mode_set	= hdmi_mode_set, | ||||||
| 	.get_max_resol	= hdmi_get_max_resol, | 	.get_max_resol	= hdmi_get_max_resol, | ||||||
| 	.commit		= hdmi_commit, | 	.commit		= hdmi_commit, | ||||||
|  | @ -2023,27 +1807,27 @@ static int hdmi_resources_init(struct hdmi_context *hdata) | ||||||
| 
 | 
 | ||||||
| 	/* get clocks, power */ | 	/* get clocks, power */ | ||||||
| 	res->hdmi = devm_clk_get(dev, "hdmi"); | 	res->hdmi = devm_clk_get(dev, "hdmi"); | ||||||
| 	if (IS_ERR_OR_NULL(res->hdmi)) { | 	if (IS_ERR(res->hdmi)) { | ||||||
| 		DRM_ERROR("failed to get clock 'hdmi'\n"); | 		DRM_ERROR("failed to get clock 'hdmi'\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 	res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); | 	res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); | ||||||
| 	if (IS_ERR_OR_NULL(res->sclk_hdmi)) { | 	if (IS_ERR(res->sclk_hdmi)) { | ||||||
| 		DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); | 		DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 	res->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); | 	res->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); | ||||||
| 	if (IS_ERR_OR_NULL(res->sclk_pixel)) { | 	if (IS_ERR(res->sclk_pixel)) { | ||||||
| 		DRM_ERROR("failed to get clock 'sclk_pixel'\n"); | 		DRM_ERROR("failed to get clock 'sclk_pixel'\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 	res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); | 	res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); | ||||||
| 	if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) { | 	if (IS_ERR(res->sclk_hdmiphy)) { | ||||||
| 		DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); | 		DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 	res->hdmiphy = devm_clk_get(dev, "hdmiphy"); | 	res->hdmiphy = devm_clk_get(dev, "hdmiphy"); | ||||||
| 	if (IS_ERR_OR_NULL(res->hdmiphy)) { | 	if (IS_ERR(res->hdmiphy)) { | ||||||
| 		DRM_ERROR("failed to get clock 'hdmiphy'\n"); | 		DRM_ERROR("failed to get clock 'hdmiphy'\n"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -643,12 +643,14 @@ static void mixer_win_reset(struct mixer_context *ctx) | ||||||
| 	/* setting graphical layers */ | 	/* setting graphical layers */ | ||||||
| 	val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ | 	val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ | ||||||
| 	val |= MXR_GRP_CFG_WIN_BLEND_EN; | 	val |= MXR_GRP_CFG_WIN_BLEND_EN; | ||||||
| 	val |= MXR_GRP_CFG_BLEND_PRE_MUL; |  | ||||||
| 	val |= MXR_GRP_CFG_PIXEL_BLEND_EN; |  | ||||||
| 	val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ | 	val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ | ||||||
| 
 | 
 | ||||||
| 	/* the same configuration for both layers */ | 	/* Don't blend layer 0 onto the mixer background */ | ||||||
| 	mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); | 	mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); | ||||||
|  | 
 | ||||||
|  | 	/* Blend layer 1 into layer 0 */ | ||||||
|  | 	val |= MXR_GRP_CFG_BLEND_PRE_MUL; | ||||||
|  | 	val |= MXR_GRP_CFG_PIXEL_BLEND_EN; | ||||||
| 	mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); | 	mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); | ||||||
| 
 | 
 | ||||||
| 	/* setting video layers */ | 	/* setting video layers */ | ||||||
|  | @ -820,7 +822,6 @@ static void mixer_win_disable(void *ctx, int win) | ||||||
| 
 | 
 | ||||||
| static int mixer_check_timing(void *ctx, struct fb_videomode *timing) | static int mixer_check_timing(void *ctx, struct fb_videomode *timing) | ||||||
| { | { | ||||||
| 	struct mixer_context *mixer_ctx = ctx; |  | ||||||
| 	u32 w, h; | 	u32 w, h; | ||||||
| 
 | 
 | ||||||
| 	w = timing->xres; | 	w = timing->xres; | ||||||
|  | @ -831,9 +832,6 @@ static int mixer_check_timing(void *ctx, struct fb_videomode *timing) | ||||||
| 		timing->refresh, (timing->vmode & | 		timing->refresh, (timing->vmode & | ||||||
| 		FB_VMODE_INTERLACED) ? true : false); | 		FB_VMODE_INTERLACED) ? true : false); | ||||||
| 
 | 
 | ||||||
| 	if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || | 	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || | ||||||
| 		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || | 		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || | ||||||
| 		(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) | 		(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) | ||||||
|  | @ -1047,13 +1045,13 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx, | ||||||
| 	spin_lock_init(&mixer_res->reg_slock); | 	spin_lock_init(&mixer_res->reg_slock); | ||||||
| 
 | 
 | ||||||
| 	mixer_res->mixer = devm_clk_get(dev, "mixer"); | 	mixer_res->mixer = devm_clk_get(dev, "mixer"); | ||||||
| 	if (IS_ERR_OR_NULL(mixer_res->mixer)) { | 	if (IS_ERR(mixer_res->mixer)) { | ||||||
| 		dev_err(dev, "failed to get clock 'mixer'\n"); | 		dev_err(dev, "failed to get clock 'mixer'\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); | 	mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); | ||||||
| 	if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) { | 	if (IS_ERR(mixer_res->sclk_hdmi)) { | ||||||
| 		dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); | 		dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
|  | @ -1096,17 +1094,17 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx, | ||||||
| 	struct resource *res; | 	struct resource *res; | ||||||
| 
 | 
 | ||||||
| 	mixer_res->vp = devm_clk_get(dev, "vp"); | 	mixer_res->vp = devm_clk_get(dev, "vp"); | ||||||
| 	if (IS_ERR_OR_NULL(mixer_res->vp)) { | 	if (IS_ERR(mixer_res->vp)) { | ||||||
| 		dev_err(dev, "failed to get clock 'vp'\n"); | 		dev_err(dev, "failed to get clock 'vp'\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
| 	mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); | 	mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); | ||||||
| 	if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) { | 	if (IS_ERR(mixer_res->sclk_mixer)) { | ||||||
| 		dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | 		dev_err(dev, "failed to get clock 'sclk_mixer'\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
| 	mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac"); | 	mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac"); | ||||||
| 	if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) { | 	if (IS_ERR(mixer_res->sclk_dac)) { | ||||||
| 		dev_err(dev, "failed to get clock 'sclk_dac'\n"); | 		dev_err(dev, "failed to get clock 'sclk_dac'\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -661,8 +661,7 @@ | ||||||
| #define EXYNOS_CLKSRC_SCLK				(1 << 1) | #define EXYNOS_CLKSRC_SCLK				(1 << 1) | ||||||
| 
 | 
 | ||||||
| /* SYSREG for FIMC writeback */ | /* SYSREG for FIMC writeback */ | ||||||
| #define SYSREG_CAMERA_BLK			(S3C_VA_SYS + 0x0218) | #define SYSREG_CAMERA_BLK			(0x0218) | ||||||
| #define SYSREG_ISP_BLK				(S3C_VA_SYS + 0x020c) |  | ||||||
| #define SYSREG_FIMD0WB_DEST_MASK		(0x3 << 23) | #define SYSREG_FIMD0WB_DEST_MASK		(0x3 << 23) | ||||||
| #define SYSREG_FIMD0WB_DEST_SHIFT		23 | #define SYSREG_FIMD0WB_DEST_SHIFT		23 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,6 +6,11 @@ config DRM_GMA500 | ||||||
| 	select FB_CFB_IMAGEBLIT | 	select FB_CFB_IMAGEBLIT | ||||||
| 	select DRM_KMS_HELPER | 	select DRM_KMS_HELPER | ||||||
| 	select DRM_TTM | 	select DRM_TTM | ||||||
|  | 	# GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 | ||||||
|  | 	select ACPI_VIDEO if ACPI | ||||||
|  | 	select BACKLIGHT_CLASS_DEVICE if ACPI | ||||||
|  | 	select VIDEO_OUTPUT_CONTROL if ACPI | ||||||
|  | 	select INPUT if ACPI | ||||||
| 	help | 	help | ||||||
| 	  Say yes for an experimental 2D KMS framebuffer driver for the | 	  Say yes for an experimental 2D KMS framebuffer driver for the | ||||||
| 	  Intel GMA500 ('Poulsbo') and other Intel IMG based graphics | 	  Intel GMA500 ('Poulsbo') and other Intel IMG based graphics | ||||||
|  |  | ||||||
|  | @ -276,6 +276,7 @@ void cdv_intel_crt_init(struct drm_device *dev, | ||||||
| 		goto failed_connector; | 		goto failed_connector; | ||||||
| 
 | 
 | ||||||
| 	connector = &psb_intel_connector->base; | 	connector = &psb_intel_connector->base; | ||||||
|  | 	connector->polled = DRM_CONNECTOR_POLL_HPD; | ||||||
| 	drm_connector_init(dev, connector, | 	drm_connector_init(dev, connector, | ||||||
| 		&cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); | 		&cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -319,6 +319,7 @@ void cdv_hdmi_init(struct drm_device *dev, | ||||||
| 		goto err_priv; | 		goto err_priv; | ||||||
| 
 | 
 | ||||||
| 	connector = &psb_intel_connector->base; | 	connector = &psb_intel_connector->base; | ||||||
|  | 	connector->polled = DRM_CONNECTOR_POLL_HPD; | ||||||
| 	encoder = &psb_intel_encoder->base; | 	encoder = &psb_intel_encoder->base; | ||||||
| 	drm_connector_init(dev, connector, | 	drm_connector_init(dev, connector, | ||||||
| 			   &cdv_hdmi_connector_funcs, | 			   &cdv_hdmi_connector_funcs, | ||||||
|  |  | ||||||
|  | @ -431,7 +431,7 @@ static int psbfb_create(struct psb_fbdev *fbdev, | ||||||
| 	fbdev->psb_fb_helper.fbdev = info; | 	fbdev->psb_fb_helper.fbdev = info; | ||||||
| 
 | 
 | ||||||
| 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||||||
| 	strcpy(info->fix.id, "psbfb"); | 	strcpy(info->fix.id, "psbdrmfb"); | ||||||
| 
 | 
 | ||||||
| 	info->flags = FBINFO_DEFAULT; | 	info->flags = FBINFO_DEFAULT; | ||||||
| 	if (dev_priv->ops->accel_2d && pitch_lines > 8)	/* 2D engine */ | 	if (dev_priv->ops->accel_2d && pitch_lines > 8)	/* 2D engine */ | ||||||
|  | @ -772,8 +772,8 @@ void psb_modeset_init(struct drm_device *dev) | ||||||
| 	for (i = 0; i < dev_priv->num_pipe; i++) | 	for (i = 0; i < dev_priv->num_pipe; i++) | ||||||
| 		psb_intel_crtc_init(dev, i, mode_dev); | 		psb_intel_crtc_init(dev, i, mode_dev); | ||||||
| 
 | 
 | ||||||
| 	dev->mode_config.max_width = 2048; | 	dev->mode_config.max_width = 4096; | ||||||
| 	dev->mode_config.max_height = 2048; | 	dev->mode_config.max_height = 4096; | ||||||
| 
 | 
 | ||||||
| 	psb_setup_outputs(dev); | 	psb_setup_outputs(dev); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -80,7 +80,8 @@ static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r) | ||||||
|  *	the GTT. This is protected via the gtt mutex which the caller |  *	the GTT. This is protected via the gtt mutex which the caller | ||||||
|  *	must hold. |  *	must hold. | ||||||
|  */ |  */ | ||||||
| static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r) | static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, | ||||||
|  | 			  int resume) | ||||||
| { | { | ||||||
| 	u32 __iomem *gtt_slot; | 	u32 __iomem *gtt_slot; | ||||||
| 	u32 pte; | 	u32 pte; | ||||||
|  | @ -97,8 +98,10 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r) | ||||||
| 	gtt_slot = psb_gtt_entry(dev, r); | 	gtt_slot = psb_gtt_entry(dev, r); | ||||||
| 	pages = r->pages; | 	pages = r->pages; | ||||||
| 
 | 
 | ||||||
|  | 	if (!resume) { | ||||||
| 		/* Make sure changes are visible to the GPU */ | 		/* Make sure changes are visible to the GPU */ | ||||||
| 		set_pages_array_wc(pages, r->npage); | 		set_pages_array_wc(pages, r->npage); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Write our page entries into the GTT itself */ | 	/* Write our page entries into the GTT itself */ | ||||||
| 	for (i = r->roll; i < r->npage; i++) { | 	for (i = r->roll; i < r->npage; i++) { | ||||||
|  | @ -269,7 +272,7 @@ int psb_gtt_pin(struct gtt_range *gt) | ||||||
| 		ret = psb_gtt_attach_pages(gt); | 		ret = psb_gtt_attach_pages(gt); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
| 			goto out; | 			goto out; | ||||||
| 		ret = psb_gtt_insert(dev, gt); | 		ret = psb_gtt_insert(dev, gt, 0); | ||||||
| 		if (ret < 0) { | 		if (ret < 0) { | ||||||
| 			psb_gtt_detach_pages(gt); | 			psb_gtt_detach_pages(gt); | ||||||
| 			goto out; | 			goto out; | ||||||
|  | @ -421,9 +424,11 @@ int psb_gtt_init(struct drm_device *dev, int resume) | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	uint32_t pte; | 	uint32_t pte; | ||||||
| 
 | 
 | ||||||
|  | 	if (!resume) { | ||||||
| 		mutex_init(&dev_priv->gtt_mutex); | 		mutex_init(&dev_priv->gtt_mutex); | ||||||
| 
 |  | ||||||
| 		psb_gtt_alloc(dev); | 		psb_gtt_alloc(dev); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	pg = &dev_priv->gtt; | 	pg = &dev_priv->gtt; | ||||||
| 
 | 
 | ||||||
| 	/* Enable the GTT */ | 	/* Enable the GTT */ | ||||||
|  | @ -505,6 +510,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 *	Map the GTT and the stolen memory area | 	 *	Map the GTT and the stolen memory area | ||||||
| 	 */ | 	 */ | ||||||
|  | 	if (!resume) | ||||||
| 		dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start, | 		dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start, | ||||||
| 						gtt_pages << PAGE_SHIFT); | 						gtt_pages << PAGE_SHIFT); | ||||||
| 	if (!dev_priv->gtt_map) { | 	if (!dev_priv->gtt_map) { | ||||||
|  | @ -513,7 +519,9 @@ int psb_gtt_init(struct drm_device *dev, int resume) | ||||||
| 		goto out_err; | 		goto out_err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); | 	if (!resume) | ||||||
|  | 		dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, | ||||||
|  | 						 stolen_size); | ||||||
| 	if (!dev_priv->vram_addr) { | 	if (!dev_priv->vram_addr) { | ||||||
| 		dev_err(dev->dev, "Failure to map stolen base.\n"); | 		dev_err(dev->dev, "Failure to map stolen base.\n"); | ||||||
| 		ret = -ENOMEM; | 		ret = -ENOMEM; | ||||||
|  | @ -549,3 +557,31 @@ out_err: | ||||||
| 	psb_gtt_takedown(dev); | 	psb_gtt_takedown(dev); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int psb_gtt_restore(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	struct drm_psb_private *dev_priv = dev->dev_private; | ||||||
|  | 	struct resource *r = dev_priv->gtt_mem->child; | ||||||
|  | 	struct gtt_range *range; | ||||||
|  | 	unsigned int restored = 0, total = 0, size = 0; | ||||||
|  | 
 | ||||||
|  | 	/* On resume, the gtt_mutex is already initialized */ | ||||||
|  | 	mutex_lock(&dev_priv->gtt_mutex); | ||||||
|  | 	psb_gtt_init(dev, 1); | ||||||
|  | 
 | ||||||
|  | 	while (r != NULL) { | ||||||
|  | 		range = container_of(r, struct gtt_range, resource); | ||||||
|  | 		if (range->pages) { | ||||||
|  | 			psb_gtt_insert(dev, range, 1); | ||||||
|  | 			size += range->resource.end - range->resource.start; | ||||||
|  | 			restored++; | ||||||
|  | 		} | ||||||
|  | 		r = r->sibling; | ||||||
|  | 		total++; | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&dev_priv->gtt_mutex); | ||||||
|  | 	DRM_DEBUG_DRIVER("Restored %u of %u gtt ranges (%u KB)", restored, | ||||||
|  | 			 total, (size / 1024)); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -60,5 +60,5 @@ extern int psb_gtt_pin(struct gtt_range *gt); | ||||||
| extern void psb_gtt_unpin(struct gtt_range *gt); | extern void psb_gtt_unpin(struct gtt_range *gt); | ||||||
| extern void psb_gtt_roll(struct drm_device *dev, | extern void psb_gtt_roll(struct drm_device *dev, | ||||||
| 					struct gtt_range *gt, int roll); | 					struct gtt_range *gt, int roll); | ||||||
| 
 | extern int psb_gtt_restore(struct drm_device *dev); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -218,12 +218,11 @@ static void parse_backlight_data(struct drm_psb_private *dev_priv, | ||||||
| 	bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT); | 	bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT); | ||||||
| 	vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type; | 	vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start + 1) + p_type; | ||||||
| 
 | 
 | ||||||
| 	lvds_bl = kzalloc(sizeof(*vbt_lvds_bl), GFP_KERNEL); | 	lvds_bl = kmemdup(vbt_lvds_bl, sizeof(*vbt_lvds_bl), GFP_KERNEL); | ||||||
| 	if (!lvds_bl) { | 	if (!lvds_bl) { | ||||||
| 		dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); | 		dev_err(dev_priv->dev->dev, "out of memory for backlight data\n"); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl)); |  | ||||||
| 	dev_priv->lvds_bl = lvds_bl; | 	dev_priv->lvds_bl = lvds_bl; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,8 +19,8 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef _I830_BIOS_H_ | #ifndef _INTEL_BIOS_H_ | ||||||
| #define _I830_BIOS_H_ | #define _INTEL_BIOS_H_ | ||||||
| 
 | 
 | ||||||
| #include <drm/drmP.h> | #include <drm/drmP.h> | ||||||
| #include <drm/drm_dp_helper.h> | #include <drm/drm_dp_helper.h> | ||||||
|  | @ -618,4 +618,4 @@ extern void psb_intel_destroy_bios(struct drm_device *dev); | ||||||
| #define		PORT_IDPC	8 | #define		PORT_IDPC	8 | ||||||
| #define		PORT_IDPD	9 | #define		PORT_IDPD	9 | ||||||
| 
 | 
 | ||||||
| #endif /* _I830_BIOS_H_ */ | #endif /* _INTEL_BIOS_H_ */ | ||||||
|  |  | ||||||
|  | @ -92,8 +92,8 @@ void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) | ||||||
| { | { | ||||||
| 	struct mdfld_dsi_pkg_sender *sender = | 	struct mdfld_dsi_pkg_sender *sender = | ||||||
| 				mdfld_dsi_get_pkg_sender(dsi_config); | 				mdfld_dsi_get_pkg_sender(dsi_config); | ||||||
| 	struct drm_device *dev = sender->dev; | 	struct drm_device *dev; | ||||||
| 	struct drm_psb_private *dev_priv = dev->dev_private; | 	struct drm_psb_private *dev_priv; | ||||||
| 	u32 gen_ctrl_val; | 	u32 gen_ctrl_val; | ||||||
| 
 | 
 | ||||||
| 	if (!sender) { | 	if (!sender) { | ||||||
|  | @ -101,6 +101,9 @@ void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	dev = sender->dev; | ||||||
|  | 	dev_priv = dev->dev_private; | ||||||
|  | 
 | ||||||
| 	/* Set default display backlight value to 85% (0xd8)*/ | 	/* Set default display backlight value to 85% (0xd8)*/ | ||||||
| 	mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, | 	mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, | ||||||
| 				true); | 				true); | ||||||
|  |  | ||||||
|  | @ -110,6 +110,8 @@ static void gma_resume_display(struct pci_dev *pdev) | ||||||
| 	PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); | 	PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); | ||||||
| 	pci_write_config_word(pdev, PSB_GMCH_CTRL, | 	pci_write_config_word(pdev, PSB_GMCH_CTRL, | ||||||
| 			dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); | 			dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); | ||||||
|  | 
 | ||||||
|  | 	psb_gtt_restore(dev); /* Rebuild our GTT mappings */ | ||||||
| 	dev_priv->ops->restore_regs(dev); | 	dev_priv->ops->restore_regs(dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -313,3 +315,18 @@ int psb_runtime_idle(struct device *dev) | ||||||
| 	else | 	else | ||||||
| 		return 1; | 		return 1; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int gma_power_thaw(struct device *_dev) | ||||||
|  | { | ||||||
|  | 	return gma_power_resume(_dev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int gma_power_freeze(struct device *_dev) | ||||||
|  | { | ||||||
|  | 	return gma_power_suspend(_dev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int gma_power_restore(struct device *_dev) | ||||||
|  | { | ||||||
|  | 	return gma_power_resume(_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -41,6 +41,9 @@ void gma_power_uninit(struct drm_device *dev); | ||||||
|  */ |  */ | ||||||
| int gma_power_suspend(struct device *dev); | int gma_power_suspend(struct device *dev); | ||||||
| int gma_power_resume(struct device *dev); | int gma_power_resume(struct device *dev); | ||||||
|  | int gma_power_thaw(struct device *dev); | ||||||
|  | int gma_power_freeze(struct device *dev); | ||||||
|  | int gma_power_restore(struct device *_dev); | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * These are the functions the driver should use to wrap all hw access |  * These are the functions the driver should use to wrap all hw access | ||||||
|  |  | ||||||
|  | @ -601,6 +601,9 @@ static void psb_remove(struct pci_dev *pdev) | ||||||
| static const struct dev_pm_ops psb_pm_ops = { | static const struct dev_pm_ops psb_pm_ops = { | ||||||
| 	.resume = gma_power_resume, | 	.resume = gma_power_resume, | ||||||
| 	.suspend = gma_power_suspend, | 	.suspend = gma_power_suspend, | ||||||
|  | 	.thaw = gma_power_thaw, | ||||||
|  | 	.freeze = gma_power_freeze, | ||||||
|  | 	.restore = gma_power_restore, | ||||||
| 	.runtime_suspend = psb_runtime_suspend, | 	.runtime_suspend = psb_runtime_suspend, | ||||||
| 	.runtime_resume = psb_runtime_resume, | 	.runtime_resume = psb_runtime_resume, | ||||||
| 	.runtime_idle = psb_runtime_idle, | 	.runtime_idle = psb_runtime_idle, | ||||||
|  |  | ||||||
|  | @ -876,7 +876,6 @@ extern const struct psb_ops cdv_chip_ops; | ||||||
| #define PSB_D_MSVDX   (1 << 9) | #define PSB_D_MSVDX   (1 << 9) | ||||||
| #define PSB_D_TOPAZ   (1 << 10) | #define PSB_D_TOPAZ   (1 << 10) | ||||||
| 
 | 
 | ||||||
| extern int drm_psb_no_fb; |  | ||||||
| extern int drm_idle_check_interval; | extern int drm_idle_check_interval; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -50,119 +50,41 @@ struct psb_intel_p2_t { | ||||||
| 	int p2_slow, p2_fast; | 	int p2_slow, p2_fast; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define INTEL_P2_NUM		      2 |  | ||||||
| 
 |  | ||||||
| struct psb_intel_limit_t { | struct psb_intel_limit_t { | ||||||
| 	struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1; | 	struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1; | ||||||
| 	struct psb_intel_p2_t p2; | 	struct psb_intel_p2_t p2; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define I8XX_DOT_MIN		  25000 | #define INTEL_LIMIT_I9XX_SDVO_DAC   0 | ||||||
| #define I8XX_DOT_MAX		 350000 | #define INTEL_LIMIT_I9XX_LVDS	    1 | ||||||
| #define I8XX_VCO_MIN		 930000 |  | ||||||
| #define I8XX_VCO_MAX		1400000 |  | ||||||
| #define I8XX_N_MIN		      3 |  | ||||||
| #define I8XX_N_MAX		     16 |  | ||||||
| #define I8XX_M_MIN		     96 |  | ||||||
| #define I8XX_M_MAX		    140 |  | ||||||
| #define I8XX_M1_MIN		     18 |  | ||||||
| #define I8XX_M1_MAX		     26 |  | ||||||
| #define I8XX_M2_MIN		      6 |  | ||||||
| #define I8XX_M2_MAX		     16 |  | ||||||
| #define I8XX_P_MIN		      4 |  | ||||||
| #define I8XX_P_MAX		    128 |  | ||||||
| #define I8XX_P1_MIN		      2 |  | ||||||
| #define I8XX_P1_MAX		     33 |  | ||||||
| #define I8XX_P1_LVDS_MIN	      1 |  | ||||||
| #define I8XX_P1_LVDS_MAX	      6 |  | ||||||
| #define I8XX_P2_SLOW		      4 |  | ||||||
| #define I8XX_P2_FAST		      2 |  | ||||||
| #define I8XX_P2_LVDS_SLOW	      14 |  | ||||||
| #define I8XX_P2_LVDS_FAST	      14	/* No fast option */ |  | ||||||
| #define I8XX_P2_SLOW_LIMIT	 165000 |  | ||||||
| 
 |  | ||||||
| #define I9XX_DOT_MIN		  20000 |  | ||||||
| #define I9XX_DOT_MAX		 400000 |  | ||||||
| #define I9XX_VCO_MIN		1400000 |  | ||||||
| #define I9XX_VCO_MAX		2800000 |  | ||||||
| #define I9XX_N_MIN		      1 |  | ||||||
| #define I9XX_N_MAX		      6 |  | ||||||
| #define I9XX_M_MIN		     70 |  | ||||||
| #define I9XX_M_MAX		    120 |  | ||||||
| #define I9XX_M1_MIN		      8 |  | ||||||
| #define I9XX_M1_MAX		     18 |  | ||||||
| #define I9XX_M2_MIN		      3 |  | ||||||
| #define I9XX_M2_MAX		      7 |  | ||||||
| #define I9XX_P_SDVO_DAC_MIN	      5 |  | ||||||
| #define I9XX_P_SDVO_DAC_MAX	     80 |  | ||||||
| #define I9XX_P_LVDS_MIN		      7 |  | ||||||
| #define I9XX_P_LVDS_MAX		     98 |  | ||||||
| #define I9XX_P1_MIN		      1 |  | ||||||
| #define I9XX_P1_MAX		      8 |  | ||||||
| #define I9XX_P2_SDVO_DAC_SLOW		     10 |  | ||||||
| #define I9XX_P2_SDVO_DAC_FAST		      5 |  | ||||||
| #define I9XX_P2_SDVO_DAC_SLOW_LIMIT	 200000 |  | ||||||
| #define I9XX_P2_LVDS_SLOW		     14 |  | ||||||
| #define I9XX_P2_LVDS_FAST		      7 |  | ||||||
| #define I9XX_P2_LVDS_SLOW_LIMIT		 112000 |  | ||||||
| 
 |  | ||||||
| #define INTEL_LIMIT_I8XX_DVO_DAC    0 |  | ||||||
| #define INTEL_LIMIT_I8XX_LVDS	    1 |  | ||||||
| #define INTEL_LIMIT_I9XX_SDVO_DAC   2 |  | ||||||
| #define INTEL_LIMIT_I9XX_LVDS	    3 |  | ||||||
| 
 | 
 | ||||||
| static const struct psb_intel_limit_t psb_intel_limits[] = { | static const struct psb_intel_limit_t psb_intel_limits[] = { | ||||||
| 	{			/* INTEL_LIMIT_I8XX_DVO_DAC */ |  | ||||||
| 	 .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX}, |  | ||||||
| 	 .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX}, |  | ||||||
| 	 .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX}, |  | ||||||
| 	 .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX}, |  | ||||||
| 	 .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX}, |  | ||||||
| 	 .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX}, |  | ||||||
| 	 .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX}, |  | ||||||
| 	 .p1 = {.min = I8XX_P1_MIN, .max = I8XX_P1_MAX}, |  | ||||||
| 	 .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT, |  | ||||||
| 		.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST}, |  | ||||||
| 	 }, |  | ||||||
| 	{			/* INTEL_LIMIT_I8XX_LVDS */ |  | ||||||
| 	 .dot = {.min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX}, |  | ||||||
| 	 .vco = {.min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX}, |  | ||||||
| 	 .n = {.min = I8XX_N_MIN, .max = I8XX_N_MAX}, |  | ||||||
| 	 .m = {.min = I8XX_M_MIN, .max = I8XX_M_MAX}, |  | ||||||
| 	 .m1 = {.min = I8XX_M1_MIN, .max = I8XX_M1_MAX}, |  | ||||||
| 	 .m2 = {.min = I8XX_M2_MIN, .max = I8XX_M2_MAX}, |  | ||||||
| 	 .p = {.min = I8XX_P_MIN, .max = I8XX_P_MAX}, |  | ||||||
| 	 .p1 = {.min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX}, |  | ||||||
| 	 .p2 = {.dot_limit = I8XX_P2_SLOW_LIMIT, |  | ||||||
| 		.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST}, |  | ||||||
| 	 }, |  | ||||||
| 	{			/* INTEL_LIMIT_I9XX_SDVO_DAC */ | 	{			/* INTEL_LIMIT_I9XX_SDVO_DAC */ | ||||||
| 	 .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, | 	 .dot = {.min = 20000, .max = 400000}, | ||||||
| 	 .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX}, | 	 .vco = {.min = 1400000, .max = 2800000}, | ||||||
| 	 .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX}, | 	 .n = {.min = 1, .max = 6}, | ||||||
| 	 .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX}, | 	 .m = {.min = 70, .max = 120}, | ||||||
| 	 .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX}, | 	 .m1 = {.min = 8, .max = 18}, | ||||||
| 	 .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX}, | 	 .m2 = {.min = 3, .max = 7}, | ||||||
| 	 .p = {.min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX}, | 	 .p = {.min = 5, .max = 80}, | ||||||
| 	 .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX}, | 	 .p1 = {.min = 1, .max = 8}, | ||||||
| 	 .p2 = {.dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, | 	 .p2 = {.dot_limit = 200000, | ||||||
| 		.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = | 		.p2_slow = 10, .p2_fast = 5}, | ||||||
| 		I9XX_P2_SDVO_DAC_FAST}, |  | ||||||
| 	 }, | 	 }, | ||||||
| 	{			/* INTEL_LIMIT_I9XX_LVDS */ | 	{			/* INTEL_LIMIT_I9XX_LVDS */ | ||||||
| 	 .dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, | 	 .dot = {.min = 20000, .max = 400000}, | ||||||
| 	 .vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX}, | 	 .vco = {.min = 1400000, .max = 2800000}, | ||||||
| 	 .n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX}, | 	 .n = {.min = 1, .max = 6}, | ||||||
| 	 .m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX}, | 	 .m = {.min = 70, .max = 120}, | ||||||
| 	 .m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX}, | 	 .m1 = {.min = 8, .max = 18}, | ||||||
| 	 .m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX}, | 	 .m2 = {.min = 3, .max = 7}, | ||||||
| 	 .p = {.min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX}, | 	 .p = {.min = 7, .max = 98}, | ||||||
| 	 .p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX}, | 	 .p1 = {.min = 1, .max = 8}, | ||||||
| 	 /* The single-channel range is 25-112Mhz, and dual-channel
 | 	 /* The single-channel range is 25-112Mhz, and dual-channel
 | ||||||
| 	  * is 80-224Mhz.  Prefer single channel as much as possible. | 	  * is 80-224Mhz.  Prefer single channel as much as possible. | ||||||
| 	  */ | 	  */ | ||||||
| 	 .p2 = {.dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, | 	 .p2 = {.dot_limit = 112000, | ||||||
| 		.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST}, | 		.p2_slow = 14, .p2_fast = 7}, | ||||||
| 	 }, | 	 }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -177,9 +99,7 @@ static const struct psb_intel_limit_t *psb_intel_limit(struct drm_crtc *crtc) | ||||||
| 	return limit; | 	return limit; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | static void psb_intel_clock(int refclk, struct psb_intel_clock_t *clock) | ||||||
| 
 |  | ||||||
| static void i8xx_clock(int refclk, struct psb_intel_clock_t *clock) |  | ||||||
| { | { | ||||||
| 	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | 	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||||||
| 	clock->p = clock->p1 * clock->p2; | 	clock->p = clock->p1 * clock->p2; | ||||||
|  | @ -187,22 +107,6 @@ static void i8xx_clock(int refclk, struct psb_intel_clock_t *clock) | ||||||
| 	clock->dot = clock->vco / clock->p; | 	clock->dot = clock->vco / clock->p; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ |  | ||||||
| 
 |  | ||||||
| static void i9xx_clock(int refclk, struct psb_intel_clock_t *clock) |  | ||||||
| { |  | ||||||
| 	clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); |  | ||||||
| 	clock->p = clock->p1 * clock->p2; |  | ||||||
| 	clock->vco = refclk * clock->m / (clock->n + 2); |  | ||||||
| 	clock->dot = clock->vco / clock->p; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void psb_intel_clock(struct drm_device *dev, int refclk, |  | ||||||
| 			struct psb_intel_clock_t *clock) |  | ||||||
| { |  | ||||||
| 	return i9xx_clock(refclk, clock); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Returns whether any output on the specified pipe is of the specified type |  * Returns whether any output on the specified pipe is of the specified type | ||||||
|  */ |  */ | ||||||
|  | @ -308,7 +212,7 @@ static bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target, | ||||||
| 				     clock.p1++) { | 				     clock.p1++) { | ||||||
| 					int this_err; | 					int this_err; | ||||||
| 
 | 
 | ||||||
| 					psb_intel_clock(dev, refclk, &clock); | 					psb_intel_clock(refclk, &clock); | ||||||
| 
 | 
 | ||||||
| 					if (!psb_intel_PLL_is_valid | 					if (!psb_intel_PLL_is_valid | ||||||
| 					    (crtc, &clock)) | 					    (crtc, &clock)) | ||||||
|  | @ -1068,7 +972,7 @@ static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, | static void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, | ||||||
| 			 u16 *green, u16 *blue, uint32_t type, uint32_t size) | 			 u16 *green, u16 *blue, uint32_t type, uint32_t size) | ||||||
| { | { | ||||||
| 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||||||
|  | @ -1149,9 +1053,9 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev, | ||||||
| 		if ((dpll & PLL_REF_INPUT_MASK) == | 		if ((dpll & PLL_REF_INPUT_MASK) == | ||||||
| 		    PLLB_REF_INPUT_SPREADSPECTRUMIN) { | 		    PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||||||
| 			/* XXX: might not be 66MHz */ | 			/* XXX: might not be 66MHz */ | ||||||
| 			i8xx_clock(66000, &clock); | 			psb_intel_clock(66000, &clock); | ||||||
| 		} else | 		} else | ||||||
| 			i8xx_clock(48000, &clock); | 			psb_intel_clock(48000, &clock); | ||||||
| 	} else { | 	} else { | ||||||
| 		if (dpll & PLL_P1_DIVIDE_BY_TWO) | 		if (dpll & PLL_P1_DIVIDE_BY_TWO) | ||||||
| 			clock.p1 = 2; | 			clock.p1 = 2; | ||||||
|  | @ -1166,7 +1070,7 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev, | ||||||
| 		else | 		else | ||||||
| 			clock.p2 = 2; | 			clock.p2 = 2; | ||||||
| 
 | 
 | ||||||
| 		i8xx_clock(48000, &clock); | 		psb_intel_clock(48000, &clock); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* XXX: It would be nice to validate the clocks, but we can't reuse
 | 	/* XXX: It would be nice to validate the clocks, but we can't reuse
 | ||||||
|  | @ -1225,7 +1129,7 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, | ||||||
| 	return mode; | 	return mode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void psb_intel_crtc_destroy(struct drm_crtc *crtc) | static void psb_intel_crtc_destroy(struct drm_crtc *crtc) | ||||||
| { | { | ||||||
| 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | 	struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); | ||||||
| 	struct gtt_range *gt; | 	struct gtt_range *gt; | ||||||
|  |  | ||||||
|  | @ -21,8 +21,5 @@ | ||||||
| #define _INTEL_DISPLAY_H_ | #define _INTEL_DISPLAY_H_ | ||||||
| 
 | 
 | ||||||
| bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type); | bool psb_intel_pipe_has_type(struct drm_crtc *crtc, int type); | ||||||
| void psb_intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, |  | ||||||
| 			 u16 *green, u16 *blue, uint32_t type, uint32_t size); |  | ||||||
| void psb_intel_crtc_destroy(struct drm_crtc *crtc); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -32,9 +32,6 @@ | ||||||
| /* maximum connectors per crtcs in the mode set */ | /* maximum connectors per crtcs in the mode set */ | ||||||
| #define INTELFB_CONN_LIMIT 4 | #define INTELFB_CONN_LIMIT 4 | ||||||
| 
 | 
 | ||||||
| #define INTEL_I2C_BUS_DVO 1 |  | ||||||
| #define INTEL_I2C_BUS_SDVO 2 |  | ||||||
| 
 |  | ||||||
| /* Intel Pipe Clone Bit */ | /* Intel Pipe Clone Bit */ | ||||||
| #define INTEL_HDMIB_CLONE_BIT 1 | #define INTEL_HDMIB_CLONE_BIT 1 | ||||||
| #define INTEL_HDMIC_CLONE_BIT 2 | #define INTEL_HDMIC_CLONE_BIT 2 | ||||||
|  | @ -68,11 +65,6 @@ | ||||||
| #define INTEL_OUTPUT_DISPLAYPORT 9 | #define INTEL_OUTPUT_DISPLAYPORT 9 | ||||||
| #define INTEL_OUTPUT_EDP 10 | #define INTEL_OUTPUT_EDP 10 | ||||||
| 
 | 
 | ||||||
| #define INTEL_DVO_CHIP_NONE 0 |  | ||||||
| #define INTEL_DVO_CHIP_LVDS 1 |  | ||||||
| #define INTEL_DVO_CHIP_TMDS 2 |  | ||||||
| #define INTEL_DVO_CHIP_TVOUT 4 |  | ||||||
| 
 |  | ||||||
| #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) | #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) | ||||||
| #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) | #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -493,7 +493,6 @@ | ||||||
| #define PIPEACONF_DISABLE		0 | #define PIPEACONF_DISABLE		0 | ||||||
| #define PIPEACONF_DOUBLE_WIDE		(1 << 30) | #define PIPEACONF_DOUBLE_WIDE		(1 << 30) | ||||||
| #define PIPECONF_ACTIVE			(1 << 30) | #define PIPECONF_ACTIVE			(1 << 30) | ||||||
| #define I965_PIPECONF_ACTIVE		(1 << 30) |  | ||||||
| #define PIPECONF_DSIPLL_LOCK		(1 << 29) | #define PIPECONF_DSIPLL_LOCK		(1 << 29) | ||||||
| #define PIPEACONF_SINGLE_WIDE		0 | #define PIPEACONF_SINGLE_WIDE		0 | ||||||
| #define PIPEACONF_PIPE_UNLOCKED		0 | #define PIPEACONF_PIPE_UNLOCKED		0 | ||||||
|  |  | ||||||
|  | @ -134,6 +134,9 @@ struct psb_intel_sdvo { | ||||||
| 
 | 
 | ||||||
| 	/* Input timings for adjusted_mode */ | 	/* Input timings for adjusted_mode */ | ||||||
| 	struct psb_intel_sdvo_dtd input_dtd; | 	struct psb_intel_sdvo_dtd input_dtd; | ||||||
|  | 
 | ||||||
|  | 	/* Saved SDVO output states */ | ||||||
|  | 	uint32_t saveSDVO; /* Can be SDVOB or SDVOC depending on sdvo_reg */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct psb_intel_sdvo_connector { | struct psb_intel_sdvo_connector { | ||||||
|  | @ -1830,6 +1833,34 @@ done: | ||||||
| #undef CHECK_PROPERTY | #undef CHECK_PROPERTY | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void psb_intel_sdvo_save(struct drm_connector *connector) | ||||||
|  | { | ||||||
|  | 	struct drm_device *dev = connector->dev; | ||||||
|  | 	struct psb_intel_encoder *psb_intel_encoder = | ||||||
|  | 					psb_intel_attached_encoder(connector); | ||||||
|  | 	struct psb_intel_sdvo *sdvo = | ||||||
|  | 				to_psb_intel_sdvo(&psb_intel_encoder->base); | ||||||
|  | 
 | ||||||
|  | 	sdvo->saveSDVO = REG_READ(sdvo->sdvo_reg); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void psb_intel_sdvo_restore(struct drm_connector *connector) | ||||||
|  | { | ||||||
|  | 	struct drm_device *dev = connector->dev; | ||||||
|  | 	struct drm_encoder *encoder = | ||||||
|  | 				&psb_intel_attached_encoder(connector)->base; | ||||||
|  | 	struct psb_intel_sdvo *sdvo = to_psb_intel_sdvo(encoder); | ||||||
|  | 	struct drm_crtc *crtc = encoder->crtc; | ||||||
|  | 
 | ||||||
|  | 	REG_WRITE(sdvo->sdvo_reg, sdvo->saveSDVO); | ||||||
|  | 
 | ||||||
|  | 	/* Force a full mode set on the crtc. We're supposed to have the
 | ||||||
|  | 	   mode_config lock already. */ | ||||||
|  | 	if (connector->status == connector_status_connected) | ||||||
|  | 		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, | ||||||
|  | 					 NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = { | static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = { | ||||||
| 	.dpms = psb_intel_sdvo_dpms, | 	.dpms = psb_intel_sdvo_dpms, | ||||||
| 	.mode_fixup = psb_intel_sdvo_mode_fixup, | 	.mode_fixup = psb_intel_sdvo_mode_fixup, | ||||||
|  | @ -1840,6 +1871,8 @@ static const struct drm_encoder_helper_funcs psb_intel_sdvo_helper_funcs = { | ||||||
| 
 | 
 | ||||||
| static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = { | static const struct drm_connector_funcs psb_intel_sdvo_connector_funcs = { | ||||||
| 	.dpms = drm_helper_connector_dpms, | 	.dpms = drm_helper_connector_dpms, | ||||||
|  | 	.save = psb_intel_sdvo_save, | ||||||
|  | 	.restore = psb_intel_sdvo_restore, | ||||||
| 	.detect = psb_intel_sdvo_detect, | 	.detect = psb_intel_sdvo_detect, | ||||||
| 	.fill_modes = drm_helper_probe_single_connector_modes, | 	.fill_modes = drm_helper_probe_single_connector_modes, | ||||||
| 	.set_property = psb_intel_sdvo_set_property, | 	.set_property = psb_intel_sdvo_set_property, | ||||||
|  |  | ||||||
|  | @ -211,7 +211,7 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS) | ||||||
| 
 | 
 | ||||||
| 	vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R); | 	vdc_stat = PSB_RVDC32(PSB_INT_IDENTITY_R); | ||||||
| 
 | 
 | ||||||
| 	if (vdc_stat & _PSB_PIPE_EVENT_FLAG) | 	if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE)) | ||||||
| 		dsp_int = 1; | 		dsp_int = 1; | ||||||
| 
 | 
 | ||||||
| 	/* FIXME: Handle Medfield
 | 	/* FIXME: Handle Medfield
 | ||||||
|  |  | ||||||
|  | @ -21,8 +21,8 @@ | ||||||
|  * |  * | ||||||
|  **************************************************************************/ |  **************************************************************************/ | ||||||
| 
 | 
 | ||||||
| #ifndef _SYSIRQ_H_ | #ifndef _PSB_IRQ_H_ | ||||||
| #define _SYSIRQ_H_ | #define _PSB_IRQ_H_ | ||||||
| 
 | 
 | ||||||
| #include <drm/drmP.h> | #include <drm/drmP.h> | ||||||
| 
 | 
 | ||||||
|  | @ -44,4 +44,4 @@ u32  psb_get_vblank_counter(struct drm_device *dev, int pipe); | ||||||
| 
 | 
 | ||||||
| int mdfld_enable_te(struct drm_device *dev, int pipe); | int mdfld_enable_te(struct drm_device *dev, int pipe); | ||||||
| void mdfld_disable_te(struct drm_device *dev, int pipe); | void mdfld_disable_te(struct drm_device *dev, int pipe); | ||||||
| #endif /* _SYSIRQ_H_ */ | #endif /* _PSB_IRQ_H_ */ | ||||||
|  |  | ||||||
|  | @ -772,6 +772,23 @@ static int i915_error_state(struct seq_file *m, void *unused) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		obj = error->ring[i].ctx; | ||||||
|  | 		if (obj) { | ||||||
|  | 			seq_printf(m, "%s --- HW Context = 0x%08x\n", | ||||||
|  | 				   dev_priv->ring[i].name, | ||||||
|  | 				   obj->gtt_offset); | ||||||
|  | 			offset = 0; | ||||||
|  | 			for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { | ||||||
|  | 				seq_printf(m, "[%04x] %08x %08x %08x %08x\n", | ||||||
|  | 					   offset, | ||||||
|  | 					   obj->pages[0][elt], | ||||||
|  | 					   obj->pages[0][elt+1], | ||||||
|  | 					   obj->pages[0][elt+2], | ||||||
|  | 					   obj->pages[0][elt+3]); | ||||||
|  | 					offset += 16; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (error->overlay) | 	if (error->overlay) | ||||||
|  | @ -849,76 +866,42 @@ static const struct file_operations i915_error_state_fops = { | ||||||
| 	.release = i915_error_state_release, | 	.release = i915_error_state_release, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_next_seqno_read(struct file *filp, | i915_next_seqno_get(void *data, u64 *val) | ||||||
| 		 char __user *ubuf, |  | ||||||
| 		 size_t max, |  | ||||||
| 		 loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
| 	char buf[80]; |  | ||||||
| 	int len; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = mutex_lock_interruptible(&dev->struct_mutex); | 	ret = mutex_lock_interruptible(&dev->struct_mutex); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), | 	*val = dev_priv->next_seqno; | ||||||
| 		       "next_seqno :  0x%x\n", |  | ||||||
| 		       dev_priv->next_seqno); |  | ||||||
| 
 |  | ||||||
| 	mutex_unlock(&dev->struct_mutex); | 	mutex_unlock(&dev->struct_mutex); | ||||||
| 
 | 
 | ||||||
| 	if (len > sizeof(buf)) | 	return 0; | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_next_seqno_write(struct file *filp, | i915_next_seqno_set(void *data, u64 val) | ||||||
| 		      const char __user *ubuf, |  | ||||||
| 		      size_t cnt, |  | ||||||
| 		      loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	char buf[20]; |  | ||||||
| 	u32 val = 1; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { |  | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 			return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		ret = kstrtouint(buf, 0, &val); |  | ||||||
| 		if (ret < 0) |  | ||||||
| 			return ret; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = mutex_lock_interruptible(&dev->struct_mutex); | 	ret = mutex_lock_interruptible(&dev->struct_mutex); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	ret = i915_gem_set_seqno(dev, val); | 	ret = i915_gem_set_seqno(dev, val); | ||||||
| 
 |  | ||||||
| 	mutex_unlock(&dev->struct_mutex); | 	mutex_unlock(&dev->struct_mutex); | ||||||
| 
 | 
 | ||||||
| 	return ret ?: cnt; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_next_seqno_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_next_seqno_get, i915_next_seqno_set, | ||||||
| 	.open = simple_open, | 			"0x%llx\n"); | ||||||
| 	.read = i915_next_seqno_read, |  | ||||||
| 	.write = i915_next_seqno_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static int i915_rstdby_delays(struct seq_file *m, void *unused) | static int i915_rstdby_delays(struct seq_file *m, void *unused) | ||||||
| { | { | ||||||
|  | @ -1023,6 +1006,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) | ||||||
| 		max_freq = rp_state_cap & 0xff; | 		max_freq = rp_state_cap & 0xff; | ||||||
| 		seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", | 		seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", | ||||||
| 			   max_freq * GT_FREQUENCY_MULTIPLIER); | 			   max_freq * GT_FREQUENCY_MULTIPLIER); | ||||||
|  | 
 | ||||||
|  | 		seq_printf(m, "Max overclocked frequency: %dMHz\n", | ||||||
|  | 			   dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER); | ||||||
| 	} else { | 	} else { | ||||||
| 		seq_printf(m, "no P-state info available\n"); | 		seq_printf(m, "no P-state info available\n"); | ||||||
| 	} | 	} | ||||||
|  | @ -1371,7 +1357,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n"); | 	seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); | ||||||
| 
 | 
 | ||||||
| 	for (gpu_freq = dev_priv->rps.min_delay; | 	for (gpu_freq = dev_priv->rps.min_delay; | ||||||
| 	     gpu_freq <= dev_priv->rps.max_delay; | 	     gpu_freq <= dev_priv->rps.max_delay; | ||||||
|  | @ -1380,7 +1366,10 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) | ||||||
| 		sandybridge_pcode_read(dev_priv, | 		sandybridge_pcode_read(dev_priv, | ||||||
| 				       GEN6_PCODE_READ_MIN_FREQ_TABLE, | 				       GEN6_PCODE_READ_MIN_FREQ_TABLE, | ||||||
| 				       &ia_freq); | 				       &ia_freq); | ||||||
| 		seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100); | 		seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", | ||||||
|  | 			   gpu_freq * GT_FREQUENCY_MULTIPLIER, | ||||||
|  | 			   ((ia_freq >> 0) & 0xff) * 100, | ||||||
|  | 			   ((ia_freq >> 8) & 0xff) * 100); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
|  | @ -1680,105 +1669,51 @@ static int i915_dpio_info(struct seq_file *m, void *data) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_wedged_read(struct file *filp, | i915_wedged_get(void *data, u64 *val) | ||||||
| 		 char __user *ubuf, |  | ||||||
| 		 size_t max, |  | ||||||
| 		 loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
| 	char buf[80]; |  | ||||||
| 	int len; |  | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), | 	*val = atomic_read(&dev_priv->gpu_error.reset_counter); | ||||||
| 		       "wedged :  %d\n", |  | ||||||
| 		       atomic_read(&dev_priv->gpu_error.reset_counter)); |  | ||||||
| 
 | 
 | ||||||
| 	if (len > sizeof(buf)) | 	return 0; | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_wedged_write(struct file *filp, | i915_wedged_set(void *data, u64 val) | ||||||
| 		  const char __user *ubuf, |  | ||||||
| 		  size_t cnt, |  | ||||||
| 		  loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	char buf[20]; |  | ||||||
| 	int val = 1; |  | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { | 	DRM_INFO("Manually setting wedged to %llu\n", val); | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 			return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		val = simple_strtoul(buf, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	DRM_INFO("Manually setting wedged to %d\n", val); |  | ||||||
| 	i915_handle_error(dev, val); | 	i915_handle_error(dev, val); | ||||||
| 
 | 
 | ||||||
| 	return cnt; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_wedged_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_wedged_get, i915_wedged_set, | ||||||
| 	.open = simple_open, | 			"%llu\n"); | ||||||
| 	.read = i915_wedged_read, |  | ||||||
| 	.write = i915_wedged_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_ring_stop_read(struct file *filp, | i915_ring_stop_get(void *data, u64 *val) | ||||||
| 		    char __user *ubuf, |  | ||||||
| 		    size_t max, |  | ||||||
| 		    loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
| 	char buf[20]; |  | ||||||
| 	int len; |  | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), | 	*val = dev_priv->gpu_error.stop_rings; | ||||||
| 		       "0x%08x\n", dev_priv->gpu_error.stop_rings); |  | ||||||
| 
 | 
 | ||||||
| 	if (len > sizeof(buf)) | 	return 0; | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_ring_stop_write(struct file *filp, | i915_ring_stop_set(void *data, u64 val) | ||||||
| 		     const char __user *ubuf, |  | ||||||
| 		     size_t cnt, |  | ||||||
| 		     loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	char buf[20]; | 	int ret; | ||||||
| 	int val = 0, ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { | 	DRM_DEBUG_DRIVER("Stopping rings 0x%08llx\n", val); | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 			return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		val = simple_strtoul(buf, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val); |  | ||||||
| 
 | 
 | ||||||
| 	ret = mutex_lock_interruptible(&dev->struct_mutex); | 	ret = mutex_lock_interruptible(&dev->struct_mutex); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -1787,16 +1722,12 @@ i915_ring_stop_write(struct file *filp, | ||||||
| 	dev_priv->gpu_error.stop_rings = val; | 	dev_priv->gpu_error.stop_rings = val; | ||||||
| 	mutex_unlock(&dev->struct_mutex); | 	mutex_unlock(&dev->struct_mutex); | ||||||
| 
 | 
 | ||||||
| 	return cnt; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_ring_stop_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_ring_stop_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_ring_stop_get, i915_ring_stop_set, | ||||||
| 	.open = simple_open, | 			"0x%08llx\n"); | ||||||
| 	.read = i915_ring_stop_read, |  | ||||||
| 	.write = i915_ring_stop_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| #define DROP_UNBOUND 0x1 | #define DROP_UNBOUND 0x1 | ||||||
| #define DROP_BOUND 0x2 | #define DROP_BOUND 0x2 | ||||||
|  | @ -1806,46 +1737,23 @@ static const struct file_operations i915_ring_stop_fops = { | ||||||
| 		  DROP_BOUND | \ | 		  DROP_BOUND | \ | ||||||
| 		  DROP_RETIRE | \ | 		  DROP_RETIRE | \ | ||||||
| 		  DROP_ACTIVE) | 		  DROP_ACTIVE) | ||||||
| static ssize_t | static int | ||||||
| i915_drop_caches_read(struct file *filp, | i915_drop_caches_get(void *data, u64 *val) | ||||||
| 		      char __user *ubuf, |  | ||||||
| 		      size_t max, |  | ||||||
| 		      loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	char buf[20]; | 	*val = DROP_ALL; | ||||||
| 	int len; |  | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL); | 	return 0; | ||||||
| 	if (len > sizeof(buf)) |  | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_drop_caches_write(struct file *filp, | i915_drop_caches_set(void *data, u64 val) | ||||||
| 		       const char __user *ubuf, |  | ||||||
| 		       size_t cnt, |  | ||||||
| 		       loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct drm_i915_gem_object *obj, *next; | 	struct drm_i915_gem_object *obj, *next; | ||||||
| 	char buf[20]; | 	int ret; | ||||||
| 	int val = 0, ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { | 	DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val); | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 			return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		val = simple_strtoul(buf, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val); |  | ||||||
| 
 | 
 | ||||||
| 	/* No need to check and wait for gpu resets, only libdrm auto-restarts
 | 	/* No need to check and wait for gpu resets, only libdrm auto-restarts
 | ||||||
| 	 * on ioctls on -EAGAIN. */ | 	 * on ioctls on -EAGAIN. */ | ||||||
|  | @ -1883,27 +1791,19 @@ i915_drop_caches_write(struct file *filp, | ||||||
| unlock: | unlock: | ||||||
| 	mutex_unlock(&dev->struct_mutex); | 	mutex_unlock(&dev->struct_mutex); | ||||||
| 
 | 
 | ||||||
| 	return ret ?: cnt; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_drop_caches_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_drop_caches_get, i915_drop_caches_set, | ||||||
| 	.open = simple_open, | 			"0x%08llx\n"); | ||||||
| 	.read = i915_drop_caches_read, |  | ||||||
| 	.write = i915_drop_caches_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_max_freq_read(struct file *filp, | i915_max_freq_get(void *data, u64 *val) | ||||||
| 		   char __user *ubuf, |  | ||||||
| 		   size_t max, |  | ||||||
| 		   loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
| 	char buf[80]; | 	int ret; | ||||||
| 	int len, ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
|  | @ -1912,42 +1812,23 @@ i915_max_freq_read(struct file *filp, | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), | 	*val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; | ||||||
| 		       "max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER); |  | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	if (len > sizeof(buf)) | 	return 0; | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_max_freq_write(struct file *filp, | i915_max_freq_set(void *data, u64 val) | ||||||
| 		  const char __user *ubuf, |  | ||||||
| 		  size_t cnt, |  | ||||||
| 		  loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	char buf[20]; | 	int ret; | ||||||
| 	int val = 1, ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { | 	DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val); | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 			return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		val = simple_strtoul(buf, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val); |  | ||||||
| 
 | 
 | ||||||
| 	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); | 	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -1956,30 +1837,24 @@ i915_max_freq_write(struct file *filp, | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Turbo will still be enabled, but won't go above the set value. | 	 * Turbo will still be enabled, but won't go above the set value. | ||||||
| 	 */ | 	 */ | ||||||
| 	dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER; | 	do_div(val, GT_FREQUENCY_MULTIPLIER); | ||||||
| 
 | 	dev_priv->rps.max_delay = val; | ||||||
| 	gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); | 	gen6_set_rps(dev, val); | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	return cnt; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_max_freq_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_max_freq_get, i915_max_freq_set, | ||||||
| 	.open = simple_open, | 			"%llu\n"); | ||||||
| 	.read = i915_max_freq_read, |  | ||||||
| 	.write = i915_max_freq_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, | i915_min_freq_get(void *data, u64 *val) | ||||||
| 		   loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
| 	char buf[80]; | 	int ret; | ||||||
| 	int len, ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
|  | @ -1988,40 +1863,23 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max, | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), | 	*val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; | ||||||
| 		       "min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER); |  | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	if (len > sizeof(buf)) | 	return 0; | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, | i915_min_freq_set(void *data, u64 val) | ||||||
| 		    loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	char buf[20]; | 	int ret; | ||||||
| 	int val = 1, ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { | 	DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val); | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 			return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) |  | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		val = simple_strtoul(buf, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_DRIVER("Manually setting min freq to %d\n", val); |  | ||||||
| 
 | 
 | ||||||
| 	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); | 	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -2030,33 +1888,25 @@ i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Turbo will still be enabled, but won't go below the set value. | 	 * Turbo will still be enabled, but won't go below the set value. | ||||||
| 	 */ | 	 */ | ||||||
| 	dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER; | 	do_div(val, GT_FREQUENCY_MULTIPLIER); | ||||||
| 
 | 	dev_priv->rps.min_delay = val; | ||||||
| 	gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER); | 	gen6_set_rps(dev, val); | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	return cnt; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_min_freq_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_min_freq_get, i915_min_freq_set, | ||||||
| 	.open = simple_open, | 			"%llu\n"); | ||||||
| 	.read = i915_min_freq_read, |  | ||||||
| 	.write = i915_min_freq_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_cache_sharing_read(struct file *filp, | i915_cache_sharing_get(void *data, u64 *val) | ||||||
| 		   char __user *ubuf, |  | ||||||
| 		   size_t max, |  | ||||||
| 		   loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
| 	char buf[80]; |  | ||||||
| 	u32 snpcr; | 	u32 snpcr; | ||||||
| 	int len, ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
|  | @ -2068,46 +1918,25 @@ i915_cache_sharing_read(struct file *filp, | ||||||
| 	snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); | 	snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); | ||||||
| 	mutex_unlock(&dev_priv->dev->struct_mutex); | 	mutex_unlock(&dev_priv->dev->struct_mutex); | ||||||
| 
 | 
 | ||||||
| 	len = snprintf(buf, sizeof(buf), | 	*val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT; | ||||||
| 		       "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >> |  | ||||||
| 		       GEN6_MBC_SNPCR_SHIFT); |  | ||||||
| 
 | 
 | ||||||
| 	if (len > sizeof(buf)) | 	return 0; | ||||||
| 		len = sizeof(buf); |  | ||||||
| 
 |  | ||||||
| 	return simple_read_from_buffer(ubuf, max, ppos, buf, len); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static int | ||||||
| i915_cache_sharing_write(struct file *filp, | i915_cache_sharing_set(void *data, u64 val) | ||||||
| 		  const char __user *ubuf, |  | ||||||
| 		  size_t cnt, |  | ||||||
| 		  loff_t *ppos) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = filp->private_data; | 	struct drm_device *dev = data; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	char buf[20]; |  | ||||||
| 	u32 snpcr; | 	u32 snpcr; | ||||||
| 	int val = 1; |  | ||||||
| 
 | 
 | ||||||
| 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | 	if (!(IS_GEN6(dev) || IS_GEN7(dev))) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	if (cnt > 0) { | 	if (val > 3) | ||||||
| 		if (cnt > sizeof(buf) - 1) |  | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 		if (copy_from_user(buf, ubuf, cnt)) | 	DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val); | ||||||
| 			return -EFAULT; |  | ||||||
| 		buf[cnt] = 0; |  | ||||||
| 
 |  | ||||||
| 		val = simple_strtoul(buf, NULL, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (val < 0 || val > 3) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val); |  | ||||||
| 
 | 
 | ||||||
| 	/* Update the cache sharing policy here as well */ | 	/* Update the cache sharing policy here as well */ | ||||||
| 	snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); | 	snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); | ||||||
|  | @ -2115,16 +1944,12 @@ i915_cache_sharing_write(struct file *filp, | ||||||
| 	snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); | 	snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); | ||||||
| 	I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); | 	I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); | ||||||
| 
 | 
 | ||||||
| 	return cnt; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct file_operations i915_cache_sharing_fops = { | DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops, | ||||||
| 	.owner = THIS_MODULE, | 			i915_cache_sharing_get, i915_cache_sharing_set, | ||||||
| 	.open = simple_open, | 			"%llu\n"); | ||||||
| 	.read = i915_cache_sharing_read, |  | ||||||
| 	.write = i915_cache_sharing_write, |  | ||||||
| 	.llseek = default_llseek, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| /* As the drm_debugfs_init() routines are called before dev->dev_private is
 | /* As the drm_debugfs_init() routines are called before dev->dev_private is
 | ||||||
|  * allocated we need to hook into the minor for release. */ |  * allocated we need to hook into the minor for release. */ | ||||||
|  |  | ||||||
|  | @ -1322,6 +1322,10 @@ static int i915_load_modeset_init(struct drm_device *dev) | ||||||
| 	/* Always safe in the mode setting case. */ | 	/* Always safe in the mode setting case. */ | ||||||
| 	/* FIXME: do pre/post-mode set stuff in core KMS code */ | 	/* FIXME: do pre/post-mode set stuff in core KMS code */ | ||||||
| 	dev->vblank_disable_allowed = 1; | 	dev->vblank_disable_allowed = 1; | ||||||
|  | 	if (INTEL_INFO(dev)->num_pipes == 0) { | ||||||
|  | 		dev_priv->mm.suspended = 0; | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = intel_fbdev_init(dev); | 	ret = intel_fbdev_init(dev); | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -1452,6 +1456,22 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv) | ||||||
| #undef DEV_INFO_SEP | #undef DEV_INFO_SEP | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * intel_early_sanitize_regs - clean up BIOS state | ||||||
|  |  * @dev: DRM device | ||||||
|  |  * | ||||||
|  |  * This function must be called before we do any I915_READ or I915_WRITE. Its | ||||||
|  |  * purpose is to clean up any state left by the BIOS that may affect us when | ||||||
|  |  * reading and/or writing registers. | ||||||
|  |  */ | ||||||
|  | static void intel_early_sanitize_regs(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 
 | ||||||
|  | 	if (IS_HASWELL(dev)) | ||||||
|  | 		I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * i915_driver_load - setup chip and create an initial config |  * i915_driver_load - setup chip and create an initial config | ||||||
|  * @dev: DRM device |  * @dev: DRM device | ||||||
|  | @ -1498,6 +1518,28 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | ||||||
| 		goto free_priv; | 		goto free_priv; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	mmio_bar = IS_GEN2(dev) ? 1 : 0; | ||||||
|  | 	/* Before gen4, the registers and the GTT are behind different BARs.
 | ||||||
|  | 	 * However, from gen4 onwards, the registers and the GTT are shared | ||||||
|  | 	 * in the same BAR, so we want to restrict this ioremap from | ||||||
|  | 	 * clobbering the GTT which we want ioremap_wc instead. Fortunately, | ||||||
|  | 	 * the register BAR remains the same size for all the earlier | ||||||
|  | 	 * generations up to Ironlake. | ||||||
|  | 	 */ | ||||||
|  | 	if (info->gen < 5) | ||||||
|  | 		mmio_size = 512*1024; | ||||||
|  | 	else | ||||||
|  | 		mmio_size = 2*1024*1024; | ||||||
|  | 
 | ||||||
|  | 	dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); | ||||||
|  | 	if (!dev_priv->regs) { | ||||||
|  | 		DRM_ERROR("failed to map registers\n"); | ||||||
|  | 		ret = -EIO; | ||||||
|  | 		goto put_bridge; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	intel_early_sanitize_regs(dev); | ||||||
|  | 
 | ||||||
| 	ret = i915_gem_gtt_init(dev); | 	ret = i915_gem_gtt_init(dev); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto put_bridge; | 		goto put_bridge; | ||||||
|  | @ -1522,26 +1564,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | ||||||
| 	if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) | 	if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) | ||||||
| 		dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); | 		dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); | ||||||
| 
 | 
 | ||||||
| 	mmio_bar = IS_GEN2(dev) ? 1 : 0; |  | ||||||
| 	/* Before gen4, the registers and the GTT are behind different BARs.
 |  | ||||||
| 	 * However, from gen4 onwards, the registers and the GTT are shared |  | ||||||
| 	 * in the same BAR, so we want to restrict this ioremap from |  | ||||||
| 	 * clobbering the GTT which we want ioremap_wc instead. Fortunately, |  | ||||||
| 	 * the register BAR remains the same size for all the earlier |  | ||||||
| 	 * generations up to Ironlake. |  | ||||||
| 	 */ |  | ||||||
| 	if (info->gen < 5) |  | ||||||
| 		mmio_size = 512*1024; |  | ||||||
| 	else |  | ||||||
| 		mmio_size = 2*1024*1024; |  | ||||||
| 
 |  | ||||||
| 	dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); |  | ||||||
| 	if (!dev_priv->regs) { |  | ||||||
| 		DRM_ERROR("failed to map registers\n"); |  | ||||||
| 		ret = -EIO; |  | ||||||
| 		goto put_gmch; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	aperture_size = dev_priv->gtt.mappable_end; | 	aperture_size = dev_priv->gtt.mappable_end; | ||||||
| 
 | 
 | ||||||
| 	dev_priv->gtt.mappable = | 	dev_priv->gtt.mappable = | ||||||
|  | @ -1612,16 +1634,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | ||||||
| 	mutex_init(&dev_priv->rps.hw_lock); | 	mutex_init(&dev_priv->rps.hw_lock); | ||||||
| 	mutex_init(&dev_priv->modeset_restore_lock); | 	mutex_init(&dev_priv->modeset_restore_lock); | ||||||
| 
 | 
 | ||||||
| 	if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) | 	dev_priv->num_plane = 1; | ||||||
| 		dev_priv->num_pipe = 3; | 	if (IS_VALLEYVIEW(dev)) | ||||||
| 	else if (IS_MOBILE(dev) || !IS_GEN2(dev)) | 		dev_priv->num_plane = 2; | ||||||
| 		dev_priv->num_pipe = 2; |  | ||||||
| 	else |  | ||||||
| 		dev_priv->num_pipe = 1; |  | ||||||
| 
 | 
 | ||||||
| 	ret = drm_vblank_init(dev, dev_priv->num_pipe); | 	if (INTEL_INFO(dev)->num_pipes) { | ||||||
|  | 		ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes); | ||||||
| 		if (ret) | 		if (ret) | ||||||
| 			goto out_gem_unload; | 			goto out_gem_unload; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Start out suspended */ | 	/* Start out suspended */ | ||||||
| 	dev_priv->mm.suspended = 1; | 	dev_priv->mm.suspended = 1; | ||||||
|  | @ -1636,9 +1657,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | ||||||
| 
 | 
 | ||||||
| 	i915_setup_sysfs(dev); | 	i915_setup_sysfs(dev); | ||||||
| 
 | 
 | ||||||
|  | 	if (INTEL_INFO(dev)->num_pipes) { | ||||||
| 		/* Must be done after probing outputs */ | 		/* Must be done after probing outputs */ | ||||||
| 		intel_opregion_init(dev); | 		intel_opregion_init(dev); | ||||||
| 		acpi_video_register(); | 		acpi_video_register(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (IS_GEN5(dev)) | 	if (IS_GEN5(dev)) | ||||||
| 		intel_gpu_ips_init(dev_priv); | 		intel_gpu_ips_init(dev_priv); | ||||||
|  | @ -1663,10 +1686,9 @@ out_mtrrfree: | ||||||
| 		dev_priv->mm.gtt_mtrr = -1; | 		dev_priv->mm.gtt_mtrr = -1; | ||||||
| 	} | 	} | ||||||
| 	io_mapping_free(dev_priv->gtt.mappable); | 	io_mapping_free(dev_priv->gtt.mappable); | ||||||
|  | 	dev_priv->gtt.gtt_remove(dev); | ||||||
| out_rmmap: | out_rmmap: | ||||||
| 	pci_iounmap(dev->pdev, dev_priv->regs); | 	pci_iounmap(dev->pdev, dev_priv->regs); | ||||||
| put_gmch: |  | ||||||
| 	dev_priv->gtt.gtt_remove(dev); |  | ||||||
| put_bridge: | put_bridge: | ||||||
| 	pci_dev_put(dev_priv->bridge_dev); | 	pci_dev_put(dev_priv->bridge_dev); | ||||||
| free_priv: | free_priv: | ||||||
|  |  | ||||||
|  | @ -121,9 +121,7 @@ MODULE_PARM_DESC(i915_enable_ppgtt, | ||||||
| unsigned int i915_preliminary_hw_support __read_mostly = 0; | unsigned int i915_preliminary_hw_support __read_mostly = 0; | ||||||
| module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); | module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600); | ||||||
| MODULE_PARM_DESC(preliminary_hw_support, | MODULE_PARM_DESC(preliminary_hw_support, | ||||||
| 		"Enable preliminary hardware support. " | 		"Enable preliminary hardware support. (default: false)"); | ||||||
| 		"Enable Haswell and ValleyView Support. " |  | ||||||
| 		"(default: false)"); |  | ||||||
| 
 | 
 | ||||||
| int i915_disable_power_well __read_mostly = 0; | int i915_disable_power_well __read_mostly = 0; | ||||||
| module_param_named(disable_power_well, i915_disable_power_well, int, 0600); | module_param_named(disable_power_well, i915_disable_power_well, int, 0600); | ||||||
|  | @ -142,75 +140,85 @@ extern int intel_agp_enabled; | ||||||
| 	.subdevice = PCI_ANY_ID,		\ | 	.subdevice = PCI_ANY_ID,		\ | ||||||
| 	.driver_data = (unsigned long) info } | 	.driver_data = (unsigned long) info } | ||||||
| 
 | 
 | ||||||
|  | #define INTEL_QUANTA_VGA_DEVICE(info) {		\ | ||||||
|  | 	.class = PCI_BASE_CLASS_DISPLAY << 16,	\ | ||||||
|  | 	.class_mask = 0xff0000,			\ | ||||||
|  | 	.vendor = 0x8086,			\ | ||||||
|  | 	.device = 0x16a,			\ | ||||||
|  | 	.subvendor = 0x152d,			\ | ||||||
|  | 	.subdevice = 0x8990,			\ | ||||||
|  | 	.driver_data = (unsigned long) info } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static const struct intel_device_info intel_i830_info = { | static const struct intel_device_info intel_i830_info = { | ||||||
| 	.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, | 	.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_845g_info = { | static const struct intel_device_info intel_845g_info = { | ||||||
| 	.gen = 2, | 	.gen = 2, .num_pipes = 1, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_i85x_info = { | static const struct intel_device_info intel_i85x_info = { | ||||||
| 	.gen = 2, .is_i85x = 1, .is_mobile = 1, | 	.gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, | ||||||
| 	.cursor_needs_physical = 1, | 	.cursor_needs_physical = 1, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_i865g_info = { | static const struct intel_device_info intel_i865g_info = { | ||||||
| 	.gen = 2, | 	.gen = 2, .num_pipes = 1, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_i915g_info = { | static const struct intel_device_info intel_i915g_info = { | ||||||
| 	.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, | 	.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| }; | }; | ||||||
| static const struct intel_device_info intel_i915gm_info = { | static const struct intel_device_info intel_i915gm_info = { | ||||||
| 	.gen = 3, .is_mobile = 1, | 	.gen = 3, .is_mobile = 1, .num_pipes = 2, | ||||||
| 	.cursor_needs_physical = 1, | 	.cursor_needs_physical = 1, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| 	.supports_tv = 1, | 	.supports_tv = 1, | ||||||
| }; | }; | ||||||
| static const struct intel_device_info intel_i945g_info = { | static const struct intel_device_info intel_i945g_info = { | ||||||
| 	.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, | 	.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| }; | }; | ||||||
| static const struct intel_device_info intel_i945gm_info = { | static const struct intel_device_info intel_i945gm_info = { | ||||||
| 	.gen = 3, .is_i945gm = 1, .is_mobile = 1, | 	.gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2, | ||||||
| 	.has_hotplug = 1, .cursor_needs_physical = 1, | 	.has_hotplug = 1, .cursor_needs_physical = 1, | ||||||
| 	.has_overlay = 1, .overlay_needs_physical = 1, | 	.has_overlay = 1, .overlay_needs_physical = 1, | ||||||
| 	.supports_tv = 1, | 	.supports_tv = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_i965g_info = { | static const struct intel_device_info intel_i965g_info = { | ||||||
| 	.gen = 4, .is_broadwater = 1, | 	.gen = 4, .is_broadwater = 1, .num_pipes = 2, | ||||||
| 	.has_hotplug = 1, | 	.has_hotplug = 1, | ||||||
| 	.has_overlay = 1, | 	.has_overlay = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_i965gm_info = { | static const struct intel_device_info intel_i965gm_info = { | ||||||
| 	.gen = 4, .is_crestline = 1, | 	.gen = 4, .is_crestline = 1, .num_pipes = 2, | ||||||
| 	.is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, | 	.is_mobile = 1, .has_fbc = 1, .has_hotplug = 1, | ||||||
| 	.has_overlay = 1, | 	.has_overlay = 1, | ||||||
| 	.supports_tv = 1, | 	.supports_tv = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_g33_info = { | static const struct intel_device_info intel_g33_info = { | ||||||
| 	.gen = 3, .is_g33 = 1, | 	.gen = 3, .is_g33 = 1, .num_pipes = 2, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.need_gfx_hws = 1, .has_hotplug = 1, | ||||||
| 	.has_overlay = 1, | 	.has_overlay = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_g45_info = { | static const struct intel_device_info intel_g45_info = { | ||||||
| 	.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, | 	.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2, | ||||||
| 	.has_pipe_cxsr = 1, .has_hotplug = 1, | 	.has_pipe_cxsr = 1, .has_hotplug = 1, | ||||||
| 	.has_bsd_ring = 1, | 	.has_bsd_ring = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_gm45_info = { | static const struct intel_device_info intel_gm45_info = { | ||||||
| 	.gen = 4, .is_g4x = 1, | 	.gen = 4, .is_g4x = 1, .num_pipes = 2, | ||||||
| 	.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, | 	.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, | ||||||
| 	.has_pipe_cxsr = 1, .has_hotplug = 1, | 	.has_pipe_cxsr = 1, .has_hotplug = 1, | ||||||
| 	.supports_tv = 1, | 	.supports_tv = 1, | ||||||
|  | @ -218,26 +226,26 @@ static const struct intel_device_info intel_gm45_info = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_pineview_info = { | static const struct intel_device_info intel_pineview_info = { | ||||||
| 	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, | 	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.need_gfx_hws = 1, .has_hotplug = 1, | ||||||
| 	.has_overlay = 1, | 	.has_overlay = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_ironlake_d_info = { | static const struct intel_device_info intel_ironlake_d_info = { | ||||||
| 	.gen = 5, | 	.gen = 5, .num_pipes = 2, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.need_gfx_hws = 1, .has_hotplug = 1, | ||||||
| 	.has_bsd_ring = 1, | 	.has_bsd_ring = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_ironlake_m_info = { | static const struct intel_device_info intel_ironlake_m_info = { | ||||||
| 	.gen = 5, .is_mobile = 1, | 	.gen = 5, .is_mobile = 1, .num_pipes = 2, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.need_gfx_hws = 1, .has_hotplug = 1, | ||||||
| 	.has_fbc = 1, | 	.has_fbc = 1, | ||||||
| 	.has_bsd_ring = 1, | 	.has_bsd_ring = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_sandybridge_d_info = { | static const struct intel_device_info intel_sandybridge_d_info = { | ||||||
| 	.gen = 6, | 	.gen = 6, .num_pipes = 2, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.need_gfx_hws = 1, .has_hotplug = 1, | ||||||
| 	.has_bsd_ring = 1, | 	.has_bsd_ring = 1, | ||||||
| 	.has_blt_ring = 1, | 	.has_blt_ring = 1, | ||||||
|  | @ -246,7 +254,7 @@ static const struct intel_device_info intel_sandybridge_d_info = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_sandybridge_m_info = { | static const struct intel_device_info intel_sandybridge_m_info = { | ||||||
| 	.gen = 6, .is_mobile = 1, | 	.gen = 6, .is_mobile = 1, .num_pipes = 2, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.need_gfx_hws = 1, .has_hotplug = 1, | ||||||
| 	.has_fbc = 1, | 	.has_fbc = 1, | ||||||
| 	.has_bsd_ring = 1, | 	.has_bsd_ring = 1, | ||||||
|  | @ -255,61 +263,57 @@ static const struct intel_device_info intel_sandybridge_m_info = { | ||||||
| 	.has_force_wake = 1, | 	.has_force_wake = 1, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define GEN7_FEATURES  \ | ||||||
|  | 	.gen = 7, .num_pipes = 3, \ | ||||||
|  | 	.need_gfx_hws = 1, .has_hotplug = 1, \ | ||||||
|  | 	.has_bsd_ring = 1, \ | ||||||
|  | 	.has_blt_ring = 1, \ | ||||||
|  | 	.has_llc = 1, \ | ||||||
|  | 	.has_force_wake = 1 | ||||||
|  | 
 | ||||||
| static const struct intel_device_info intel_ivybridge_d_info = { | static const struct intel_device_info intel_ivybridge_d_info = { | ||||||
| 	.is_ivybridge = 1, .gen = 7, | 	GEN7_FEATURES, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.is_ivybridge = 1, | ||||||
| 	.has_bsd_ring = 1, |  | ||||||
| 	.has_blt_ring = 1, |  | ||||||
| 	.has_llc = 1, |  | ||||||
| 	.has_force_wake = 1, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_ivybridge_m_info = { | static const struct intel_device_info intel_ivybridge_m_info = { | ||||||
| 	.is_ivybridge = 1, .gen = 7, .is_mobile = 1, | 	GEN7_FEATURES, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.is_ivybridge = 1, | ||||||
| 	.has_fbc = 0,	/* FBC is not enabled on Ivybridge mobile yet */ | 	.is_mobile = 1, | ||||||
| 	.has_bsd_ring = 1, | }; | ||||||
| 	.has_blt_ring = 1, | 
 | ||||||
| 	.has_llc = 1, | static const struct intel_device_info intel_ivybridge_q_info = { | ||||||
| 	.has_force_wake = 1, | 	GEN7_FEATURES, | ||||||
|  | 	.is_ivybridge = 1, | ||||||
|  | 	.num_pipes = 0, /* legal, last one wins */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_valleyview_m_info = { | static const struct intel_device_info intel_valleyview_m_info = { | ||||||
| 	.gen = 7, .is_mobile = 1, | 	GEN7_FEATURES, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.is_mobile = 1, | ||||||
| 	.has_fbc = 0, | 	.num_pipes = 2, | ||||||
| 	.has_bsd_ring = 1, |  | ||||||
| 	.has_blt_ring = 1, |  | ||||||
| 	.is_valleyview = 1, | 	.is_valleyview = 1, | ||||||
| 	.display_mmio_offset = VLV_DISPLAY_BASE, | 	.display_mmio_offset = VLV_DISPLAY_BASE, | ||||||
|  | 	.has_llc = 0, /* legal, last one wins */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_valleyview_d_info = { | static const struct intel_device_info intel_valleyview_d_info = { | ||||||
| 	.gen = 7, | 	GEN7_FEATURES, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.num_pipes = 2, | ||||||
| 	.has_fbc = 0, |  | ||||||
| 	.has_bsd_ring = 1, |  | ||||||
| 	.has_blt_ring = 1, |  | ||||||
| 	.is_valleyview = 1, | 	.is_valleyview = 1, | ||||||
| 	.display_mmio_offset = VLV_DISPLAY_BASE, | 	.display_mmio_offset = VLV_DISPLAY_BASE, | ||||||
|  | 	.has_llc = 0, /* legal, last one wins */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_haswell_d_info = { | static const struct intel_device_info intel_haswell_d_info = { | ||||||
| 	.is_haswell = 1, .gen = 7, | 	GEN7_FEATURES, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.is_haswell = 1, | ||||||
| 	.has_bsd_ring = 1, |  | ||||||
| 	.has_blt_ring = 1, |  | ||||||
| 	.has_llc = 1, |  | ||||||
| 	.has_force_wake = 1, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct intel_device_info intel_haswell_m_info = { | static const struct intel_device_info intel_haswell_m_info = { | ||||||
| 	.is_haswell = 1, .gen = 7, .is_mobile = 1, | 	GEN7_FEATURES, | ||||||
| 	.need_gfx_hws = 1, .has_hotplug = 1, | 	.is_haswell = 1, | ||||||
| 	.has_bsd_ring = 1, | 	.is_mobile = 1, | ||||||
| 	.has_blt_ring = 1, |  | ||||||
| 	.has_llc = 1, |  | ||||||
| 	.has_force_wake = 1, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct pci_device_id pciidlist[] = {		/* aka */ | static const struct pci_device_id pciidlist[] = {		/* aka */ | ||||||
|  | @ -356,6 +360,7 @@ static const struct pci_device_id pciidlist[] = {		/* aka */ | ||||||
| 	INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ | 	INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ | ||||||
| 	INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ | 	INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ | ||||||
| 	INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ | 	INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ | ||||||
|  | 	INTEL_QUANTA_VGA_DEVICE(&intel_ivybridge_q_info), /* Quanta transcode */ | ||||||
| 	INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ | 	INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ | ||||||
| 	INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ | 	INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ | ||||||
| 	INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ | 	INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ | ||||||
|  | @ -394,6 +399,9 @@ static const struct pci_device_id pciidlist[] = {		/* aka */ | ||||||
| 	INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ | 	INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ | ||||||
| 	INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ | 	INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ | ||||||
| 	INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), | 	INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), | ||||||
|  | 	INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info), | ||||||
|  | 	INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info), | ||||||
|  | 	INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info), | ||||||
| 	INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), | 	INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), | ||||||
| 	INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), | 	INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), | ||||||
| 	{0, 0, 0} | 	{0, 0, 0} | ||||||
|  | @ -408,6 +416,15 @@ void intel_detect_pch(struct drm_device *dev) | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct pci_dev *pch; | 	struct pci_dev *pch; | ||||||
| 
 | 
 | ||||||
|  | 	/* In all current cases, num_pipes is equivalent to the PCH_NOP setting
 | ||||||
|  | 	 * (which really amounts to a PCH but no South Display). | ||||||
|  | 	 */ | ||||||
|  | 	if (INTEL_INFO(dev)->num_pipes == 0) { | ||||||
|  | 		dev_priv->pch_type = PCH_NOP; | ||||||
|  | 		dev_priv->num_pch_pll = 0; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * The reason to probe ISA bridge instead of Dev31:Fun0 is to | 	 * The reason to probe ISA bridge instead of Dev31:Fun0 is to | ||||||
| 	 * make graphics device passthrough work easy for VMM, that only | 	 * make graphics device passthrough work easy for VMM, that only | ||||||
|  | @ -442,11 +459,13 @@ void intel_detect_pch(struct drm_device *dev) | ||||||
| 				dev_priv->num_pch_pll = 0; | 				dev_priv->num_pch_pll = 0; | ||||||
| 				DRM_DEBUG_KMS("Found LynxPoint PCH\n"); | 				DRM_DEBUG_KMS("Found LynxPoint PCH\n"); | ||||||
| 				WARN_ON(!IS_HASWELL(dev)); | 				WARN_ON(!IS_HASWELL(dev)); | ||||||
|  | 				WARN_ON(IS_ULT(dev)); | ||||||
| 			} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { | 			} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { | ||||||
| 				dev_priv->pch_type = PCH_LPT; | 				dev_priv->pch_type = PCH_LPT; | ||||||
| 				dev_priv->num_pch_pll = 0; | 				dev_priv->num_pch_pll = 0; | ||||||
| 				DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); | 				DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); | ||||||
| 				WARN_ON(!IS_HASWELL(dev)); | 				WARN_ON(!IS_HASWELL(dev)); | ||||||
|  | 				WARN_ON(!IS_ULT(dev)); | ||||||
| 			} | 			} | ||||||
| 			BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); | 			BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); | ||||||
| 		} | 		} | ||||||
|  | @ -474,6 +493,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) | ||||||
| static int i915_drm_freeze(struct drm_device *dev) | static int i915_drm_freeze(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	struct drm_crtc *crtc; | ||||||
| 
 | 
 | ||||||
| 	/* ignore lid events during suspend */ | 	/* ignore lid events during suspend */ | ||||||
| 	mutex_lock(&dev_priv->modeset_restore_lock); | 	mutex_lock(&dev_priv->modeset_restore_lock); | ||||||
|  | @ -497,10 +517,14 @@ static int i915_drm_freeze(struct drm_device *dev) | ||||||
| 
 | 
 | ||||||
| 		cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); | 		cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); | ||||||
| 
 | 
 | ||||||
| 		intel_modeset_disable(dev); |  | ||||||
| 
 |  | ||||||
| 		drm_irq_uninstall(dev); | 		drm_irq_uninstall(dev); | ||||||
| 		dev_priv->enable_hotplug_processing = false; | 		dev_priv->enable_hotplug_processing = false; | ||||||
|  | 		/*
 | ||||||
|  | 		 * Disable CRTCs directly since we want to preserve sw state | ||||||
|  | 		 * for _thaw. | ||||||
|  | 		 */ | ||||||
|  | 		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||||||
|  | 			dev_priv->display.crtc_disable(crtc); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	i915_save_state(dev); | 	i915_save_state(dev); | ||||||
|  | @ -556,6 +580,24 @@ void intel_console_resume(struct work_struct *work) | ||||||
| 	console_unlock(); | 	console_unlock(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void intel_resume_hotplug(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	struct drm_mode_config *mode_config = &dev->mode_config; | ||||||
|  | 	struct intel_encoder *encoder; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&mode_config->mutex); | ||||||
|  | 	DRM_DEBUG_KMS("running encoder hotplug functions\n"); | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry(encoder, &mode_config->encoder_list, base.head) | ||||||
|  | 		if (encoder->hot_plug) | ||||||
|  | 			encoder->hot_plug(encoder); | ||||||
|  | 
 | ||||||
|  | 	mutex_unlock(&mode_config->mutex); | ||||||
|  | 
 | ||||||
|  | 	/* Just fire off a uevent and let userspace tell us what to do */ | ||||||
|  | 	drm_helper_hpd_irq_event(dev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int __i915_drm_thaw(struct drm_device *dev) | static int __i915_drm_thaw(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | @ -578,7 +620,10 @@ static int __i915_drm_thaw(struct drm_device *dev) | ||||||
| 		drm_irq_install(dev); | 		drm_irq_install(dev); | ||||||
| 
 | 
 | ||||||
| 		intel_modeset_init_hw(dev); | 		intel_modeset_init_hw(dev); | ||||||
| 		intel_modeset_setup_hw_state(dev, false); | 
 | ||||||
|  | 		drm_modeset_lock_all(dev); | ||||||
|  | 		intel_modeset_setup_hw_state(dev, true); | ||||||
|  | 		drm_modeset_unlock_all(dev); | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * ... but also need to make sure that hotplug processing | 		 * ... but also need to make sure that hotplug processing | ||||||
|  | @ -588,6 +633,8 @@ static int __i915_drm_thaw(struct drm_device *dev) | ||||||
| 		 * */ | 		 * */ | ||||||
| 		intel_hpd_init(dev); | 		intel_hpd_init(dev); | ||||||
| 		dev_priv->enable_hotplug_processing = true; | 		dev_priv->enable_hotplug_processing = true; | ||||||
|  | 		/* Config may have changed between suspend and resume */ | ||||||
|  | 		intel_resume_hotplug(dev); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	intel_opregion_init(dev); | 	intel_opregion_init(dev); | ||||||
|  | @ -732,6 +779,7 @@ static int ironlake_do_reset(struct drm_device *dev) | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); | 	gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); | ||||||
|  | 	gdrst &= ~GRDOM_MASK; | ||||||
| 	I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, | 	I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, | ||||||
| 		   gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); | 		   gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); | ||||||
| 	ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); | 	ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); | ||||||
|  | @ -740,6 +788,7 @@ static int ironlake_do_reset(struct drm_device *dev) | ||||||
| 
 | 
 | ||||||
| 	/* We can't reset render&media without also resetting display ... */ | 	/* We can't reset render&media without also resetting display ... */ | ||||||
| 	gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); | 	gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); | ||||||
|  | 	gdrst &= ~GRDOM_MASK; | ||||||
| 	I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, | 	I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, | ||||||
| 		   gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); | 		   gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); | ||||||
| 	return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); | 	return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); | ||||||
|  | @ -803,7 +852,7 @@ int intel_gpu_reset(struct drm_device *dev) | ||||||
| 
 | 
 | ||||||
| 	/* Also reset the gpu hangman. */ | 	/* Also reset the gpu hangman. */ | ||||||
| 	if (dev_priv->gpu_error.stop_rings) { | 	if (dev_priv->gpu_error.stop_rings) { | ||||||
| 		DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); | 		DRM_INFO("Simulated gpu hang, resetting stop_rings\n"); | ||||||
| 		dev_priv->gpu_error.stop_rings = 0; | 		dev_priv->gpu_error.stop_rings = 0; | ||||||
| 		if (ret == -ENODEV) { | 		if (ret == -ENODEV) { | ||||||
| 			DRM_ERROR("Reset not implemented, but ignoring " | 			DRM_ERROR("Reset not implemented, but ignoring " | ||||||
|  | @ -882,7 +931,11 @@ int i915_reset(struct drm_device *dev) | ||||||
| 			ring->init(ring); | 			ring->init(ring); | ||||||
| 
 | 
 | ||||||
| 		i915_gem_context_init(dev); | 		i915_gem_context_init(dev); | ||||||
| 		i915_gem_init_ppgtt(dev); | 		if (dev_priv->mm.aliasing_ppgtt) { | ||||||
|  | 			ret = dev_priv->mm.aliasing_ppgtt->enable(dev); | ||||||
|  | 			if (ret) | ||||||
|  | 				i915_gem_cleanup_aliasing_ppgtt(dev); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * It would make sense to re-init all the other hw state, at | 		 * It would make sense to re-init all the other hw state, at | ||||||
|  | @ -1147,6 +1200,27 @@ ilk_dummy_write(struct drm_i915_private *dev_priv) | ||||||
| 	I915_WRITE_NOTRACE(MI_MODE, 0); | 	I915_WRITE_NOTRACE(MI_MODE, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void | ||||||
|  | hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) | ||||||
|  | { | ||||||
|  | 	if (IS_HASWELL(dev_priv->dev) && | ||||||
|  | 	    (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { | ||||||
|  | 		DRM_ERROR("Unknown unclaimed register before writing to %x\n", | ||||||
|  | 			  reg); | ||||||
|  | 		I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) | ||||||
|  | { | ||||||
|  | 	if (IS_HASWELL(dev_priv->dev) && | ||||||
|  | 	    (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { | ||||||
|  | 		DRM_ERROR("Unclaimed write to %x\n", reg); | ||||||
|  | 		I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #define __i915_read(x, y) \ | #define __i915_read(x, y) \ | ||||||
| u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ | ||||||
| 	u##x val = 0; \ | 	u##x val = 0; \ | ||||||
|  | @ -1183,18 +1257,12 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ | ||||||
| 	} \ | 	} \ | ||||||
| 	if (IS_GEN5(dev_priv->dev)) \ | 	if (IS_GEN5(dev_priv->dev)) \ | ||||||
| 		ilk_dummy_write(dev_priv); \ | 		ilk_dummy_write(dev_priv); \ | ||||||
| 	if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ | 	hsw_unclaimed_reg_clear(dev_priv, reg); \ | ||||||
| 		DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ |  | ||||||
| 		I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ |  | ||||||
| 	} \ |  | ||||||
| 	write##y(val, dev_priv->regs + reg); \ | 	write##y(val, dev_priv->regs + reg); \ | ||||||
| 	if (unlikely(__fifo_ret)) { \ | 	if (unlikely(__fifo_ret)) { \ | ||||||
| 		gen6_gt_check_fifodbg(dev_priv); \ | 		gen6_gt_check_fifodbg(dev_priv); \ | ||||||
| 	} \ | 	} \ | ||||||
| 	if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \ | 	hsw_unclaimed_reg_check(dev_priv, reg); \ | ||||||
| 		DRM_ERROR("Unclaimed write to %x\n", reg); \ |  | ||||||
| 		writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT);	\ |  | ||||||
| 	} \ |  | ||||||
| } | } | ||||||
| __i915_write(8, b) | __i915_write(8, b) | ||||||
| __i915_write(16, w) | __i915_write(16, w) | ||||||
|  |  | ||||||
|  | @ -86,6 +86,19 @@ enum port { | ||||||
| }; | }; | ||||||
| #define port_name(p) ((p) + 'A') | #define port_name(p) ((p) + 'A') | ||||||
| 
 | 
 | ||||||
|  | enum hpd_pin { | ||||||
|  | 	HPD_NONE = 0, | ||||||
|  | 	HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ | ||||||
|  | 	HPD_TV = HPD_NONE,     /* TV is known to be unreliable */ | ||||||
|  | 	HPD_CRT, | ||||||
|  | 	HPD_SDVO_B, | ||||||
|  | 	HPD_SDVO_C, | ||||||
|  | 	HPD_PORT_B, | ||||||
|  | 	HPD_PORT_C, | ||||||
|  | 	HPD_PORT_D, | ||||||
|  | 	HPD_NUM_PINS | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| #define I915_GEM_GPU_DOMAINS \ | #define I915_GEM_GPU_DOMAINS \ | ||||||
| 	(I915_GEM_DOMAIN_RENDER | \ | 	(I915_GEM_DOMAIN_RENDER | \ | ||||||
| 	 I915_GEM_DOMAIN_SAMPLER | \ | 	 I915_GEM_DOMAIN_SAMPLER | \ | ||||||
|  | @ -93,7 +106,7 @@ enum port { | ||||||
| 	 I915_GEM_DOMAIN_INSTRUCTION | \ | 	 I915_GEM_DOMAIN_INSTRUCTION | \ | ||||||
| 	 I915_GEM_DOMAIN_VERTEX) | 	 I915_GEM_DOMAIN_VERTEX) | ||||||
| 
 | 
 | ||||||
| #define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) | #define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++) | ||||||
| 
 | 
 | ||||||
| #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ | #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ | ||||||
| 	list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ | 	list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ | ||||||
|  | @ -182,9 +195,9 @@ struct drm_i915_master_private { | ||||||
| 	struct _drm_i915_sarea *sarea_priv; | 	struct _drm_i915_sarea *sarea_priv; | ||||||
| }; | }; | ||||||
| #define I915_FENCE_REG_NONE -1 | #define I915_FENCE_REG_NONE -1 | ||||||
| #define I915_MAX_NUM_FENCES 16 | #define I915_MAX_NUM_FENCES 32 | ||||||
| /* 16 fences + sign bit for FENCE_REG_NONE */ | /* 32 fences + sign bit for FENCE_REG_NONE */ | ||||||
| #define I915_MAX_NUM_FENCE_BITS 5 | #define I915_MAX_NUM_FENCE_BITS 6 | ||||||
| 
 | 
 | ||||||
| struct drm_i915_fence_reg { | struct drm_i915_fence_reg { | ||||||
| 	struct list_head lru_list; | 	struct list_head lru_list; | ||||||
|  | @ -243,7 +256,7 @@ struct drm_i915_error_state { | ||||||
| 			int page_count; | 			int page_count; | ||||||
| 			u32 gtt_offset; | 			u32 gtt_offset; | ||||||
| 			u32 *pages[0]; | 			u32 *pages[0]; | ||||||
| 		} *ringbuffer, *batchbuffer; | 		} *ringbuffer, *batchbuffer, *ctx; | ||||||
| 		struct drm_i915_error_request { | 		struct drm_i915_error_request { | ||||||
| 			long jiffies; | 			long jiffies; | ||||||
| 			u32 seqno; | 			u32 seqno; | ||||||
|  | @ -271,6 +284,9 @@ struct drm_i915_error_state { | ||||||
| 	struct intel_display_error_state *display; | 	struct intel_display_error_state *display; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct intel_crtc_config; | ||||||
|  | struct intel_crtc; | ||||||
|  | 
 | ||||||
| struct drm_i915_display_funcs { | struct drm_i915_display_funcs { | ||||||
| 	bool (*fbc_enabled)(struct drm_device *dev); | 	bool (*fbc_enabled)(struct drm_device *dev); | ||||||
| 	void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); | 	void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); | ||||||
|  | @ -283,9 +299,11 @@ struct drm_i915_display_funcs { | ||||||
| 	void (*update_linetime_wm)(struct drm_device *dev, int pipe, | 	void (*update_linetime_wm)(struct drm_device *dev, int pipe, | ||||||
| 				 struct drm_display_mode *mode); | 				 struct drm_display_mode *mode); | ||||||
| 	void (*modeset_global_resources)(struct drm_device *dev); | 	void (*modeset_global_resources)(struct drm_device *dev); | ||||||
|  | 	/* Returns the active state of the crtc, and if the crtc is active,
 | ||||||
|  | 	 * fills out the pipe-config with the hw state. */ | ||||||
|  | 	bool (*get_pipe_config)(struct intel_crtc *, | ||||||
|  | 				struct intel_crtc_config *); | ||||||
| 	int (*crtc_mode_set)(struct drm_crtc *crtc, | 	int (*crtc_mode_set)(struct drm_crtc *crtc, | ||||||
| 			     struct drm_display_mode *mode, |  | ||||||
| 			     struct drm_display_mode *adjusted_mode, |  | ||||||
| 			     int x, int y, | 			     int x, int y, | ||||||
| 			     struct drm_framebuffer *old_fb); | 			     struct drm_framebuffer *old_fb); | ||||||
| 	void (*crtc_enable)(struct drm_crtc *crtc); | 	void (*crtc_enable)(struct drm_crtc *crtc); | ||||||
|  | @ -341,6 +359,7 @@ struct drm_i915_gt_funcs { | ||||||
| 
 | 
 | ||||||
| struct intel_device_info { | struct intel_device_info { | ||||||
| 	u32 display_mmio_offset; | 	u32 display_mmio_offset; | ||||||
|  | 	u8 num_pipes:3; | ||||||
| 	u8 gen; | 	u8 gen; | ||||||
| 	u8 is_mobile:1; | 	u8 is_mobile:1; | ||||||
| 	u8 is_i85x:1; | 	u8 is_i85x:1; | ||||||
|  | @ -430,6 +449,7 @@ struct i915_hw_ppgtt { | ||||||
| 			       struct sg_table *st, | 			       struct sg_table *st, | ||||||
| 			       unsigned int pg_start, | 			       unsigned int pg_start, | ||||||
| 			       enum i915_cache_level cache_level); | 			       enum i915_cache_level cache_level); | ||||||
|  | 	int (*enable)(struct drm_device *dev); | ||||||
| 	void (*cleanup)(struct i915_hw_ppgtt *ppgtt); | 	void (*cleanup)(struct i915_hw_ppgtt *ppgtt); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -460,6 +480,7 @@ enum intel_pch { | ||||||
| 	PCH_IBX,	/* Ibexpeak PCH */ | 	PCH_IBX,	/* Ibexpeak PCH */ | ||||||
| 	PCH_CPT,	/* Cougarpoint PCH */ | 	PCH_CPT,	/* Cougarpoint PCH */ | ||||||
| 	PCH_LPT,	/* Lynxpoint PCH */ | 	PCH_LPT,	/* Lynxpoint PCH */ | ||||||
|  | 	PCH_NOP, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum intel_sbi_destination { | enum intel_sbi_destination { | ||||||
|  | @ -647,6 +668,7 @@ struct intel_gen6_power_mgmt { | ||||||
| 	u8 cur_delay; | 	u8 cur_delay; | ||||||
| 	u8 min_delay; | 	u8 min_delay; | ||||||
| 	u8 max_delay; | 	u8 max_delay; | ||||||
|  | 	u8 hw_max; | ||||||
| 
 | 
 | ||||||
| 	struct delayed_work delayed_resume_work; | 	struct delayed_work delayed_resume_work; | ||||||
| 
 | 
 | ||||||
|  | @ -905,16 +927,24 @@ typedef struct drm_i915_private { | ||||||
| 	struct mutex dpio_lock; | 	struct mutex dpio_lock; | ||||||
| 
 | 
 | ||||||
| 	/** Cached value of IMR to avoid reads in updating the bitfield */ | 	/** Cached value of IMR to avoid reads in updating the bitfield */ | ||||||
| 	u32 pipestat[2]; |  | ||||||
| 	u32 irq_mask; | 	u32 irq_mask; | ||||||
| 	u32 gt_irq_mask; | 	u32 gt_irq_mask; | ||||||
| 
 | 
 | ||||||
| 	u32 hotplug_supported_mask; |  | ||||||
| 	struct work_struct hotplug_work; | 	struct work_struct hotplug_work; | ||||||
| 	bool enable_hotplug_processing; | 	bool enable_hotplug_processing; | ||||||
|  | 	struct { | ||||||
|  | 		unsigned long hpd_last_jiffies; | ||||||
|  | 		int hpd_cnt; | ||||||
|  | 		enum { | ||||||
|  | 			HPD_ENABLED = 0, | ||||||
|  | 			HPD_DISABLED = 1, | ||||||
|  | 			HPD_MARK_DISABLED = 2 | ||||||
|  | 		} hpd_mark; | ||||||
|  | 	} hpd_stats[HPD_NUM_PINS]; | ||||||
|  | 	struct timer_list hotplug_reenable_timer; | ||||||
| 
 | 
 | ||||||
| 	int num_pipe; |  | ||||||
| 	int num_pch_pll; | 	int num_pch_pll; | ||||||
|  | 	int num_plane; | ||||||
| 
 | 
 | ||||||
| 	unsigned long cfb_size; | 	unsigned long cfb_size; | ||||||
| 	unsigned int cfb_fb; | 	unsigned int cfb_fb; | ||||||
|  | @ -928,9 +958,14 @@ typedef struct drm_i915_private { | ||||||
| 	struct intel_overlay *overlay; | 	struct intel_overlay *overlay; | ||||||
| 	unsigned int sprite_scaling_enabled; | 	unsigned int sprite_scaling_enabled; | ||||||
| 
 | 
 | ||||||
|  | 	/* backlight */ | ||||||
|  | 	struct { | ||||||
|  | 		int level; | ||||||
|  | 		bool enabled; | ||||||
|  | 		struct backlight_device *device; | ||||||
|  | 	} backlight; | ||||||
|  | 
 | ||||||
| 	/* LVDS info */ | 	/* LVDS info */ | ||||||
| 	int backlight_level;  /* restore backlight to this value */ |  | ||||||
| 	bool backlight_enabled; |  | ||||||
| 	struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ | 	struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ | ||||||
| 	struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ | 	struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ | ||||||
| 
 | 
 | ||||||
|  | @ -941,6 +976,7 @@ typedef struct drm_i915_private { | ||||||
| 	unsigned int int_crt_support:1; | 	unsigned int int_crt_support:1; | ||||||
| 	unsigned int lvds_use_ssc:1; | 	unsigned int lvds_use_ssc:1; | ||||||
| 	unsigned int display_clock_mode:1; | 	unsigned int display_clock_mode:1; | ||||||
|  | 	unsigned int fdi_rx_polarity_inverted:1; | ||||||
| 	int lvds_ssc_freq; | 	int lvds_ssc_freq; | ||||||
| 	unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ | 	unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ | ||||||
| 	struct { | 	struct { | ||||||
|  | @ -1032,8 +1068,6 @@ typedef struct drm_i915_private { | ||||||
| 	 */ | 	 */ | ||||||
| 	struct work_struct console_resume_work; | 	struct work_struct console_resume_work; | ||||||
| 
 | 
 | ||||||
| 	struct backlight_device *backlight; |  | ||||||
| 
 |  | ||||||
| 	struct drm_property *broadcast_rgb_property; | 	struct drm_property *broadcast_rgb_property; | ||||||
| 	struct drm_property *force_audio_property; | 	struct drm_property *force_audio_property; | ||||||
| 
 | 
 | ||||||
|  | @ -1340,6 +1374,7 @@ struct drm_i915_file_private { | ||||||
| #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) | #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) | ||||||
| 
 | 
 | ||||||
| #define HAS_DDI(dev)		(IS_HASWELL(dev)) | #define HAS_DDI(dev)		(IS_HASWELL(dev)) | ||||||
|  | #define HAS_POWER_WELL(dev)	(IS_HASWELL(dev)) | ||||||
| 
 | 
 | ||||||
| #define INTEL_PCH_DEVICE_ID_MASK		0xff00 | #define INTEL_PCH_DEVICE_ID_MASK		0xff00 | ||||||
| #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00 | #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00 | ||||||
|  | @ -1352,6 +1387,7 @@ struct drm_i915_file_private { | ||||||
| #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) | #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) | ||||||
| #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) | #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) | ||||||
| #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) | #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) | ||||||
|  | #define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP) | ||||||
| #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE) | #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE) | ||||||
| 
 | 
 | ||||||
| #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) | #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) | ||||||
|  | @ -1529,17 +1565,12 @@ void i915_gem_lastclose(struct drm_device *dev); | ||||||
| int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); | int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); | ||||||
| static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) | static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) | ||||||
| { | { | ||||||
| 	struct scatterlist *sg = obj->pages->sgl; | 	struct sg_page_iter sg_iter; | ||||||
| 	int nents = obj->pages->nents; |  | ||||||
| 	while (nents > SG_MAX_SINGLE_ALLOC) { |  | ||||||
| 		if (n < SG_MAX_SINGLE_ALLOC - 1) |  | ||||||
| 			break; |  | ||||||
| 
 | 
 | ||||||
| 		sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1); | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n) | ||||||
| 		n -= SG_MAX_SINGLE_ALLOC - 1; | 		return sg_page_iter_page(&sg_iter); | ||||||
| 		nents -= SG_MAX_SINGLE_ALLOC - 1; | 
 | ||||||
| 	} | 	return NULL; | ||||||
| 	return sg_page(sg+n); |  | ||||||
| } | } | ||||||
| static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) | static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) | ||||||
| { | { | ||||||
|  | @ -1624,7 +1655,6 @@ int __must_check i915_gem_init(struct drm_device *dev); | ||||||
| int __must_check i915_gem_init_hw(struct drm_device *dev); | int __must_check i915_gem_init_hw(struct drm_device *dev); | ||||||
| void i915_gem_l3_remap(struct drm_device *dev); | void i915_gem_l3_remap(struct drm_device *dev); | ||||||
| void i915_gem_init_swizzling(struct drm_device *dev); | void i915_gem_init_swizzling(struct drm_device *dev); | ||||||
| void i915_gem_init_ppgtt(struct drm_device *dev); |  | ||||||
| void i915_gem_cleanup_ringbuffer(struct drm_device *dev); | void i915_gem_cleanup_ringbuffer(struct drm_device *dev); | ||||||
| int __must_check i915_gpu_idle(struct drm_device *dev); | int __must_check i915_gpu_idle(struct drm_device *dev); | ||||||
| int __must_check i915_gem_idle(struct drm_device *dev); | int __must_check i915_gem_idle(struct drm_device *dev); | ||||||
|  | @ -1718,6 +1748,11 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev); | ||||||
| void i915_gem_cleanup_stolen(struct drm_device *dev); | void i915_gem_cleanup_stolen(struct drm_device *dev); | ||||||
| struct drm_i915_gem_object * | struct drm_i915_gem_object * | ||||||
| i915_gem_object_create_stolen(struct drm_device *dev, u32 size); | i915_gem_object_create_stolen(struct drm_device *dev, u32 size); | ||||||
|  | struct drm_i915_gem_object * | ||||||
|  | i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, | ||||||
|  | 					       u32 stolen_offset, | ||||||
|  | 					       u32 gtt_offset, | ||||||
|  | 					       u32 size); | ||||||
| void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); | void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); | ||||||
| 
 | 
 | ||||||
| /* i915_gem_tiling.c */ | /* i915_gem_tiling.c */ | ||||||
|  | @ -1848,6 +1883,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); | ||||||
| 
 | 
 | ||||||
| int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); | int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); | ||||||
| int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); | int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); | ||||||
|  | int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); | ||||||
|  | int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); | ||||||
| 
 | 
 | ||||||
| #define __i915_read(x, y) \ | #define __i915_read(x, y) \ | ||||||
| 	u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); | 	u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); | ||||||
|  | @ -1901,4 +1938,9 @@ static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) | ||||||
| 		return VGACNTRL; | 		return VGACNTRL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline void __user *to_user_ptr(u64 address) | ||||||
|  | { | ||||||
|  | 	return (void __user *)(uintptr_t)address; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -411,10 +411,9 @@ i915_gem_shmem_pread(struct drm_device *dev, | ||||||
| 	int obj_do_bit17_swizzling, page_do_bit17_swizzling; | 	int obj_do_bit17_swizzling, page_do_bit17_swizzling; | ||||||
| 	int prefaulted = 0; | 	int prefaulted = 0; | ||||||
| 	int needs_clflush = 0; | 	int needs_clflush = 0; | ||||||
| 	struct scatterlist *sg; | 	struct sg_page_iter sg_iter; | ||||||
| 	int i; |  | ||||||
| 
 | 
 | ||||||
| 	user_data = (char __user *) (uintptr_t) args->data_ptr; | 	user_data = to_user_ptr(args->data_ptr); | ||||||
| 	remain = args->size; | 	remain = args->size; | ||||||
| 
 | 
 | ||||||
| 	obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); | 	obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); | ||||||
|  | @ -441,11 +440,9 @@ i915_gem_shmem_pread(struct drm_device *dev, | ||||||
| 
 | 
 | ||||||
| 	offset = args->offset; | 	offset = args->offset; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, | ||||||
| 		struct page *page; | 			 offset >> PAGE_SHIFT) { | ||||||
| 
 | 		struct page *page = sg_page_iter_page(&sg_iter); | ||||||
| 		if (i < offset >> PAGE_SHIFT) |  | ||||||
| 			continue; |  | ||||||
| 
 | 
 | ||||||
| 		if (remain <= 0) | 		if (remain <= 0) | ||||||
| 			break; | 			break; | ||||||
|  | @ -460,7 +457,6 @@ i915_gem_shmem_pread(struct drm_device *dev, | ||||||
| 		if ((shmem_page_offset + page_length) > PAGE_SIZE) | 		if ((shmem_page_offset + page_length) > PAGE_SIZE) | ||||||
| 			page_length = PAGE_SIZE - shmem_page_offset; | 			page_length = PAGE_SIZE - shmem_page_offset; | ||||||
| 
 | 
 | ||||||
| 		page = sg_page(sg); |  | ||||||
| 		page_do_bit17_swizzling = obj_do_bit17_swizzling && | 		page_do_bit17_swizzling = obj_do_bit17_swizzling && | ||||||
| 			(page_to_phys(page) & (1 << 17)) != 0; | 			(page_to_phys(page) & (1 << 17)) != 0; | ||||||
| 
 | 
 | ||||||
|  | @ -522,7 +518,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	if (!access_ok(VERIFY_WRITE, | 	if (!access_ok(VERIFY_WRITE, | ||||||
| 		       (char __user *)(uintptr_t)args->data_ptr, | 		       to_user_ptr(args->data_ptr), | ||||||
| 		       args->size)) | 		       args->size)) | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
| 
 | 
 | ||||||
|  | @ -613,7 +609,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto out_unpin; | 		goto out_unpin; | ||||||
| 
 | 
 | ||||||
| 	user_data = (char __user *) (uintptr_t) args->data_ptr; | 	user_data = to_user_ptr(args->data_ptr); | ||||||
| 	remain = args->size; | 	remain = args->size; | ||||||
| 
 | 
 | ||||||
| 	offset = obj->gtt_offset + args->offset; | 	offset = obj->gtt_offset + args->offset; | ||||||
|  | @ -732,10 +728,9 @@ i915_gem_shmem_pwrite(struct drm_device *dev, | ||||||
| 	int hit_slowpath = 0; | 	int hit_slowpath = 0; | ||||||
| 	int needs_clflush_after = 0; | 	int needs_clflush_after = 0; | ||||||
| 	int needs_clflush_before = 0; | 	int needs_clflush_before = 0; | ||||||
| 	int i; | 	struct sg_page_iter sg_iter; | ||||||
| 	struct scatterlist *sg; |  | ||||||
| 
 | 
 | ||||||
| 	user_data = (char __user *) (uintptr_t) args->data_ptr; | 	user_data = to_user_ptr(args->data_ptr); | ||||||
| 	remain = args->size; | 	remain = args->size; | ||||||
| 
 | 
 | ||||||
| 	obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); | 	obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj); | ||||||
|  | @ -768,13 +763,11 @@ i915_gem_shmem_pwrite(struct drm_device *dev, | ||||||
| 	offset = args->offset; | 	offset = args->offset; | ||||||
| 	obj->dirty = 1; | 	obj->dirty = 1; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) { | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, | ||||||
| 		struct page *page; | 			 offset >> PAGE_SHIFT) { | ||||||
|  | 		struct page *page = sg_page_iter_page(&sg_iter); | ||||||
| 		int partial_cacheline_write; | 		int partial_cacheline_write; | ||||||
| 
 | 
 | ||||||
| 		if (i < offset >> PAGE_SHIFT) |  | ||||||
| 			continue; |  | ||||||
| 
 |  | ||||||
| 		if (remain <= 0) | 		if (remain <= 0) | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
|  | @ -796,7 +789,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev, | ||||||
| 			((shmem_page_offset | page_length) | 			((shmem_page_offset | page_length) | ||||||
| 				& (boot_cpu_data.x86_clflush_size - 1)); | 				& (boot_cpu_data.x86_clflush_size - 1)); | ||||||
| 
 | 
 | ||||||
| 		page = sg_page(sg); |  | ||||||
| 		page_do_bit17_swizzling = obj_do_bit17_swizzling && | 		page_do_bit17_swizzling = obj_do_bit17_swizzling && | ||||||
| 			(page_to_phys(page) & (1 << 17)) != 0; | 			(page_to_phys(page) & (1 << 17)) != 0; | ||||||
| 
 | 
 | ||||||
|  | @ -867,11 +859,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	if (!access_ok(VERIFY_READ, | 	if (!access_ok(VERIFY_READ, | ||||||
| 		       (char __user *)(uintptr_t)args->data_ptr, | 		       to_user_ptr(args->data_ptr), | ||||||
| 		       args->size)) | 		       args->size)) | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
| 
 | 
 | ||||||
| 	ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr, | 	ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr), | ||||||
| 					   args->size); | 					   args->size); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
|  | @ -1633,9 +1625,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) | ||||||
| static void | static void | ||||||
| i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) | i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) | ||||||
| { | { | ||||||
| 	int page_count = obj->base.size / PAGE_SIZE; | 	struct sg_page_iter sg_iter; | ||||||
| 	struct scatterlist *sg; | 	int ret; | ||||||
| 	int ret, i; |  | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(obj->madv == __I915_MADV_PURGED); | 	BUG_ON(obj->madv == __I915_MADV_PURGED); | ||||||
| 
 | 
 | ||||||
|  | @ -1655,8 +1646,8 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) | ||||||
| 	if (obj->madv == I915_MADV_DONTNEED) | 	if (obj->madv == I915_MADV_DONTNEED) | ||||||
| 		obj->dirty = 0; | 		obj->dirty = 0; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(obj->pages->sgl, sg, page_count, i) { | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { | ||||||
| 		struct page *page = sg_page(sg); | 		struct page *page = sg_page_iter_page(&sg_iter); | ||||||
| 
 | 
 | ||||||
| 		if (obj->dirty) | 		if (obj->dirty) | ||||||
| 			set_page_dirty(page); | 			set_page_dirty(page); | ||||||
|  | @ -1757,7 +1748,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | ||||||
| 	struct address_space *mapping; | 	struct address_space *mapping; | ||||||
| 	struct sg_table *st; | 	struct sg_table *st; | ||||||
| 	struct scatterlist *sg; | 	struct scatterlist *sg; | ||||||
|  | 	struct sg_page_iter sg_iter; | ||||||
| 	struct page *page; | 	struct page *page; | ||||||
|  | 	unsigned long last_pfn = 0;	/* suppress gcc warning */ | ||||||
| 	gfp_t gfp; | 	gfp_t gfp; | ||||||
| 
 | 
 | ||||||
| 	/* Assert that the object is not currently in any GPU domain. As it
 | 	/* Assert that the object is not currently in any GPU domain. As it
 | ||||||
|  | @ -1787,7 +1780,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | ||||||
| 	gfp = mapping_gfp_mask(mapping); | 	gfp = mapping_gfp_mask(mapping); | ||||||
| 	gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; | 	gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; | ||||||
| 	gfp &= ~(__GFP_IO | __GFP_WAIT); | 	gfp &= ~(__GFP_IO | __GFP_WAIT); | ||||||
| 	for_each_sg(st->sgl, sg, page_count, i) { | 	sg = st->sgl; | ||||||
|  | 	st->nents = 0; | ||||||
|  | 	for (i = 0; i < page_count; i++) { | ||||||
| 		page = shmem_read_mapping_page_gfp(mapping, i, gfp); | 		page = shmem_read_mapping_page_gfp(mapping, i, gfp); | ||||||
| 		if (IS_ERR(page)) { | 		if (IS_ERR(page)) { | ||||||
| 			i915_gem_purge(dev_priv, page_count); | 			i915_gem_purge(dev_priv, page_count); | ||||||
|  | @ -1810,9 +1805,18 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | ||||||
| 			gfp &= ~(__GFP_IO | __GFP_WAIT); | 			gfp &= ~(__GFP_IO | __GFP_WAIT); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (!i || page_to_pfn(page) != last_pfn + 1) { | ||||||
|  | 			if (i) | ||||||
|  | 				sg = sg_next(sg); | ||||||
|  | 			st->nents++; | ||||||
| 			sg_set_page(sg, page, PAGE_SIZE, 0); | 			sg_set_page(sg, page, PAGE_SIZE, 0); | ||||||
|  | 		} else { | ||||||
|  | 			sg->length += PAGE_SIZE; | ||||||
|  | 		} | ||||||
|  | 		last_pfn = page_to_pfn(page); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	sg_mark_end(sg); | ||||||
| 	obj->pages = st; | 	obj->pages = st; | ||||||
| 
 | 
 | ||||||
| 	if (i915_gem_object_needs_bit17_swizzle(obj)) | 	if (i915_gem_object_needs_bit17_swizzle(obj)) | ||||||
|  | @ -1821,8 +1825,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| err_pages: | err_pages: | ||||||
| 	for_each_sg(st->sgl, sg, i, page_count) | 	sg_mark_end(sg); | ||||||
| 		page_cache_release(sg_page(sg)); | 	for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) | ||||||
|  | 		page_cache_release(sg_page_iter_page(&sg_iter)); | ||||||
| 	sg_free_table(st); | 	sg_free_table(st); | ||||||
| 	kfree(st); | 	kfree(st); | ||||||
| 	return PTR_ERR(page); | 	return PTR_ERR(page); | ||||||
|  | @ -2123,11 +2128,11 @@ static void i915_gem_reset_fences(struct drm_device *dev) | ||||||
| 	for (i = 0; i < dev_priv->num_fence_regs; i++) { | 	for (i = 0; i < dev_priv->num_fence_regs; i++) { | ||||||
| 		struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; | 		struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; | ||||||
| 
 | 
 | ||||||
| 		i915_gem_write_fence(dev, i, NULL); |  | ||||||
| 
 |  | ||||||
| 		if (reg->obj) | 		if (reg->obj) | ||||||
| 			i915_gem_object_fence_lost(reg->obj); | 			i915_gem_object_fence_lost(reg->obj); | ||||||
| 
 | 
 | ||||||
|  | 		i915_gem_write_fence(dev, i, NULL); | ||||||
|  | 
 | ||||||
| 		reg->pin_count = 0; | 		reg->pin_count = 0; | ||||||
| 		reg->obj = NULL; | 		reg->obj = NULL; | ||||||
| 		INIT_LIST_HEAD(®->lru_list); | 		INIT_LIST_HEAD(®->lru_list); | ||||||
|  | @ -2678,17 +2683,35 @@ static inline int fence_number(struct drm_i915_private *dev_priv, | ||||||
| 	return fence - dev_priv->fence_regs; | 	return fence - dev_priv->fence_regs; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void i915_gem_write_fence__ipi(void *data) | ||||||
|  | { | ||||||
|  | 	wbinvd(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, | static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, | ||||||
| 					 struct drm_i915_fence_reg *fence, | 					 struct drm_i915_fence_reg *fence, | ||||||
| 					 bool enable) | 					 bool enable) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = obj->base.dev->dev_private; | 	struct drm_device *dev = obj->base.dev; | ||||||
| 	int reg = fence_number(dev_priv, fence); | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	int fence_reg = fence_number(dev_priv, fence); | ||||||
| 
 | 
 | ||||||
| 	i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); | 	/* In order to fully serialize access to the fenced region and
 | ||||||
|  | 	 * the update to the fence register we need to take extreme | ||||||
|  | 	 * measures on SNB+. In theory, the write to the fence register | ||||||
|  | 	 * flushes all memory transactions before, and coupled with the | ||||||
|  | 	 * mb() placed around the register write we serialise all memory | ||||||
|  | 	 * operations with respect to the changes in the tiler. Yet, on | ||||||
|  | 	 * SNB+ we need to take a step further and emit an explicit wbinvd() | ||||||
|  | 	 * on each processor in order to manually flush all memory | ||||||
|  | 	 * transactions before updating the fence register. | ||||||
|  | 	 */ | ||||||
|  | 	if (HAS_LLC(obj->base.dev)) | ||||||
|  | 		on_each_cpu(i915_gem_write_fence__ipi, NULL, 1); | ||||||
|  | 	i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); | ||||||
| 
 | 
 | ||||||
| 	if (enable) { | 	if (enable) { | ||||||
| 		obj->fence_reg = reg; | 		obj->fence_reg = fence_reg; | ||||||
| 		fence->obj = obj; | 		fence->obj = obj; | ||||||
| 		list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); | 		list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -2717,6 +2740,7 @@ int | ||||||
| i915_gem_object_put_fence(struct drm_i915_gem_object *obj) | i915_gem_object_put_fence(struct drm_i915_gem_object *obj) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = obj->base.dev->dev_private; | 	struct drm_i915_private *dev_priv = obj->base.dev->dev_private; | ||||||
|  | 	struct drm_i915_fence_reg *fence; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = i915_gem_object_wait_fence(obj); | 	ret = i915_gem_object_wait_fence(obj); | ||||||
|  | @ -2726,10 +2750,10 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) | ||||||
| 	if (obj->fence_reg == I915_FENCE_REG_NONE) | 	if (obj->fence_reg == I915_FENCE_REG_NONE) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	i915_gem_object_update_fence(obj, | 	fence = &dev_priv->fence_regs[obj->fence_reg]; | ||||||
| 				     &dev_priv->fence_regs[obj->fence_reg], | 
 | ||||||
| 				     false); |  | ||||||
| 	i915_gem_object_fence_lost(obj); | 	i915_gem_object_fence_lost(obj); | ||||||
|  | 	i915_gem_object_update_fence(obj, fence, false); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -3986,6 +4010,12 @@ i915_gem_init_hw(struct drm_device *dev) | ||||||
| 	if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) | 	if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) | ||||||
| 		I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); | 		I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); | ||||||
| 
 | 
 | ||||||
|  | 	if (HAS_PCH_NOP(dev)) { | ||||||
|  | 		u32 temp = I915_READ(GEN7_MSG_CTL); | ||||||
|  | 		temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); | ||||||
|  | 		I915_WRITE(GEN7_MSG_CTL, temp); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	i915_gem_l3_remap(dev); | 	i915_gem_l3_remap(dev); | ||||||
| 
 | 
 | ||||||
| 	i915_gem_init_swizzling(dev); | 	i915_gem_init_swizzling(dev); | ||||||
|  | @ -3999,7 +4029,13 @@ i915_gem_init_hw(struct drm_device *dev) | ||||||
| 	 * contexts before PPGTT. | 	 * contexts before PPGTT. | ||||||
| 	 */ | 	 */ | ||||||
| 	i915_gem_context_init(dev); | 	i915_gem_context_init(dev); | ||||||
| 	i915_gem_init_ppgtt(dev); | 	if (dev_priv->mm.aliasing_ppgtt) { | ||||||
|  | 		ret = dev_priv->mm.aliasing_ppgtt->enable(dev); | ||||||
|  | 		if (ret) { | ||||||
|  | 			i915_gem_cleanup_aliasing_ppgtt(dev); | ||||||
|  | 			DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -4010,7 +4046,16 @@ int i915_gem_init(struct drm_device *dev) | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&dev->struct_mutex); | 	mutex_lock(&dev->struct_mutex); | ||||||
|  | 
 | ||||||
|  | 	if (IS_VALLEYVIEW(dev)) { | ||||||
|  | 		/* VLVA0 (potential hack), BIOS isn't actually waking us */ | ||||||
|  | 		I915_WRITE(VLV_GTLC_WAKE_CTRL, 1); | ||||||
|  | 		if (wait_for((I915_READ(VLV_GTLC_PW_STATUS) & 1) == 1, 10)) | ||||||
|  | 			DRM_DEBUG_DRIVER("allow wake ack timed out\n"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	i915_gem_init_global_gtt(dev); | 	i915_gem_init_global_gtt(dev); | ||||||
|  | 
 | ||||||
| 	ret = i915_gem_init_hw(dev); | 	ret = i915_gem_init_hw(dev); | ||||||
| 	mutex_unlock(&dev->struct_mutex); | 	mutex_unlock(&dev->struct_mutex); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
|  | @ -4145,7 +4190,9 @@ i915_gem_load(struct drm_device *dev) | ||||||
| 	if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 	if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||||||
| 		dev_priv->fence_reg_start = 3; | 		dev_priv->fence_reg_start = 3; | ||||||
| 
 | 
 | ||||||
| 	if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) | 	if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) | ||||||
|  | 		dev_priv->num_fence_regs = 32; | ||||||
|  | 	else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) | ||||||
| 		dev_priv->num_fence_regs = 16; | 		dev_priv->num_fence_regs = 16; | ||||||
| 	else | 	else | ||||||
| 		dev_priv->num_fence_regs = 8; | 		dev_priv->num_fence_regs = 8; | ||||||
|  | @ -4327,7 +4374,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, | ||||||
| 		     struct drm_file *file_priv) | 		     struct drm_file *file_priv) | ||||||
| { | { | ||||||
| 	void *vaddr = obj->phys_obj->handle->vaddr + args->offset; | 	void *vaddr = obj->phys_obj->handle->vaddr + args->offset; | ||||||
| 	char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; | 	char __user *user_data = to_user_ptr(args->data_ptr); | ||||||
| 
 | 
 | ||||||
| 	if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { | 	if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { | ||||||
| 		unsigned long unwritten; | 		unsigned long unwritten; | ||||||
|  |  | ||||||
|  | @ -152,6 +152,13 @@ create_hw_context(struct drm_device *dev, | ||||||
| 		return ERR_PTR(-ENOMEM); | 		return ERR_PTR(-ENOMEM); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (INTEL_INFO(dev)->gen >= 7) { | ||||||
|  | 		ret = i915_gem_object_set_cache_level(ctx->obj, | ||||||
|  | 						      I915_CACHE_LLC_MLC); | ||||||
|  | 		if (ret) | ||||||
|  | 			goto err_out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* The ring associated with the context object is handled by the normal
 | 	/* The ring associated with the context object is handled by the normal
 | ||||||
| 	 * object tracking code. We give an initial ring value simple to pass an | 	 * object tracking code. We give an initial ring value simple to pass an | ||||||
| 	 * assertion in the context switch code. | 	 * assertion in the context switch code. | ||||||
|  |  | ||||||
|  | @ -62,7 +62,7 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme | ||||||
| 	src = obj->pages->sgl; | 	src = obj->pages->sgl; | ||||||
| 	dst = st->sgl; | 	dst = st->sgl; | ||||||
| 	for (i = 0; i < obj->pages->nents; i++) { | 	for (i = 0; i < obj->pages->nents; i++) { | ||||||
| 		sg_set_page(dst, sg_page(src), PAGE_SIZE, 0); | 		sg_set_page(dst, sg_page(src), src->length, 0); | ||||||
| 		dst = sg_next(dst); | 		dst = sg_next(dst); | ||||||
| 		src = sg_next(src); | 		src = sg_next(src); | ||||||
| 	} | 	} | ||||||
|  | @ -105,7 +105,7 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) | ||||||
| { | { | ||||||
| 	struct drm_i915_gem_object *obj = dma_buf->priv; | 	struct drm_i915_gem_object *obj = dma_buf->priv; | ||||||
| 	struct drm_device *dev = obj->base.dev; | 	struct drm_device *dev = obj->base.dev; | ||||||
| 	struct scatterlist *sg; | 	struct sg_page_iter sg_iter; | ||||||
| 	struct page **pages; | 	struct page **pages; | ||||||
| 	int ret, i; | 	int ret, i; | ||||||
| 
 | 
 | ||||||
|  | @ -124,14 +124,15 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) | ||||||
| 
 | 
 | ||||||
| 	ret = -ENOMEM; | 	ret = -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	pages = drm_malloc_ab(obj->pages->nents, sizeof(struct page *)); | 	pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages)); | ||||||
| 	if (pages == NULL) | 	if (pages == NULL) | ||||||
| 		goto error; | 		goto error; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) | 	i = 0; | ||||||
| 		pages[i] = sg_page(sg); | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) | ||||||
|  | 		pages[i++] = sg_page_iter_page(&sg_iter); | ||||||
| 
 | 
 | ||||||
| 	obj->dma_buf_vmapping = vmap(pages, obj->pages->nents, 0, PAGE_KERNEL); | 	obj->dma_buf_vmapping = vmap(pages, i, 0, PAGE_KERNEL); | ||||||
| 	drm_free_large(pages); | 	drm_free_large(pages); | ||||||
| 
 | 
 | ||||||
| 	if (!obj->dma_buf_vmapping) | 	if (!obj->dma_buf_vmapping) | ||||||
|  | @ -271,7 +272,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, | ||||||
| 			 * refcount on gem itself instead of f_count of dmabuf. | 			 * refcount on gem itself instead of f_count of dmabuf. | ||||||
| 			 */ | 			 */ | ||||||
| 			drm_gem_object_reference(&obj->base); | 			drm_gem_object_reference(&obj->base); | ||||||
| 			dma_buf_put(dma_buf); |  | ||||||
| 			return &obj->base; | 			return &obj->base; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -281,6 +281,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, | ||||||
| 	if (IS_ERR(attach)) | 	if (IS_ERR(attach)) | ||||||
| 		return ERR_CAST(attach); | 		return ERR_CAST(attach); | ||||||
| 
 | 
 | ||||||
|  | 	get_dma_buf(dma_buf); | ||||||
|  | 
 | ||||||
| 	obj = i915_gem_object_alloc(dev); | 	obj = i915_gem_object_alloc(dev); | ||||||
| 	if (obj == NULL) { | 	if (obj == NULL) { | ||||||
| 		ret = -ENOMEM; | 		ret = -ENOMEM; | ||||||
|  | @ -300,5 +302,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, | ||||||
| 
 | 
 | ||||||
| fail_detach: | fail_detach: | ||||||
| 	dma_buf_detach(dma_buf, attach); | 	dma_buf_detach(dma_buf, attach); | ||||||
|  | 	dma_buf_put(dma_buf); | ||||||
|  | 
 | ||||||
| 	return ERR_PTR(ret); | 	return ERR_PTR(ret); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -305,7 +305,7 @@ i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj, | ||||||
| 	struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; | 	struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; | ||||||
| 	int remain, ret; | 	int remain, ret; | ||||||
| 
 | 
 | ||||||
| 	user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr; | 	user_relocs = to_user_ptr(entry->relocs_ptr); | ||||||
| 
 | 
 | ||||||
| 	remain = entry->relocation_count; | 	remain = entry->relocation_count; | ||||||
| 	while (remain) { | 	while (remain) { | ||||||
|  | @ -359,8 +359,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| i915_gem_execbuffer_relocate(struct drm_device *dev, | i915_gem_execbuffer_relocate(struct eb_objects *eb) | ||||||
| 			     struct eb_objects *eb) |  | ||||||
| { | { | ||||||
| 	struct drm_i915_gem_object *obj; | 	struct drm_i915_gem_object *obj; | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
|  | @ -475,7 +474,6 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj) | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, | ||||||
| 			    struct drm_file *file, |  | ||||||
| 			    struct list_head *objects, | 			    struct list_head *objects, | ||||||
| 			    bool *need_relocs) | 			    bool *need_relocs) | ||||||
| { | { | ||||||
|  | @ -618,7 +616,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, | ||||||
| 		u64 invalid_offset = (u64)-1; | 		u64 invalid_offset = (u64)-1; | ||||||
| 		int j; | 		int j; | ||||||
| 
 | 
 | ||||||
| 		user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr; | 		user_relocs = to_user_ptr(exec[i].relocs_ptr); | ||||||
| 
 | 
 | ||||||
| 		if (copy_from_user(reloc+total, user_relocs, | 		if (copy_from_user(reloc+total, user_relocs, | ||||||
| 				   exec[i].relocation_count * sizeof(*reloc))) { | 				   exec[i].relocation_count * sizeof(*reloc))) { | ||||||
|  | @ -663,7 +661,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; | 	need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; | ||||||
| 	ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); | 	ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
|  | @ -736,7 +734,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, | ||||||
| 	int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); | 	int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < count; i++) { | 	for (i = 0; i < count; i++) { | ||||||
| 		char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr; | 		char __user *ptr = to_user_ptr(exec[i].relocs_ptr); | ||||||
| 		int length; /* limited by fault_in_pages_readable() */ | 		int length; /* limited by fault_in_pages_readable() */ | ||||||
| 
 | 
 | ||||||
| 		if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) | 		if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) | ||||||
|  | @ -752,7 +750,11 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, | ||||||
| 
 | 
 | ||||||
| 		length = exec[i].relocation_count * | 		length = exec[i].relocation_count * | ||||||
| 			sizeof(struct drm_i915_gem_relocation_entry); | 			sizeof(struct drm_i915_gem_relocation_entry); | ||||||
| 		/* we may also need to update the presumed offsets */ | 		/*
 | ||||||
|  | 		 * We must check that the entire relocation array is safe | ||||||
|  | 		 * to read, but since we may need to update the presumed | ||||||
|  | 		 * offsets during execution, check for full write access. | ||||||
|  | 		 */ | ||||||
| 		if (!access_ok(VERIFY_WRITE, ptr, length)) | 		if (!access_ok(VERIFY_WRITE, ptr, length)) | ||||||
| 			return -EFAULT; | 			return -EFAULT; | ||||||
| 
 | 
 | ||||||
|  | @ -949,8 +951,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (copy_from_user(cliprects, | 		if (copy_from_user(cliprects, | ||||||
| 				     (struct drm_clip_rect __user *)(uintptr_t) | 				   to_user_ptr(args->cliprects_ptr), | ||||||
| 				     args->cliprects_ptr, |  | ||||||
| 				   sizeof(*cliprects)*args->num_cliprects)) { | 				   sizeof(*cliprects)*args->num_cliprects)) { | ||||||
| 			ret = -EFAULT; | 			ret = -EFAULT; | ||||||
| 			goto pre_mutex_err; | 			goto pre_mutex_err; | ||||||
|  | @ -986,13 +987,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, | ||||||
| 
 | 
 | ||||||
| 	/* Move the objects en-masse into the GTT, evicting if necessary. */ | 	/* Move the objects en-masse into the GTT, evicting if necessary. */ | ||||||
| 	need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; | 	need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; | ||||||
| 	ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); | 	ret = i915_gem_execbuffer_reserve(ring, &eb->objects, &need_relocs); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	/* The objects are in their final locations, apply the relocations. */ | 	/* The objects are in their final locations, apply the relocations. */ | ||||||
| 	if (need_relocs) | 	if (need_relocs) | ||||||
| 		ret = i915_gem_execbuffer_relocate(dev, eb); | 		ret = i915_gem_execbuffer_relocate(eb); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		if (ret == -EFAULT) { | 		if (ret == -EFAULT) { | ||||||
| 			ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, | 			ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, | ||||||
|  | @ -1115,7 +1116,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 	ret = copy_from_user(exec_list, | 	ret = copy_from_user(exec_list, | ||||||
| 			     (void __user *)(uintptr_t)args->buffers_ptr, | 			     to_user_ptr(args->buffers_ptr), | ||||||
| 			     sizeof(*exec_list) * args->buffer_count); | 			     sizeof(*exec_list) * args->buffer_count); | ||||||
| 	if (ret != 0) { | 	if (ret != 0) { | ||||||
| 		DRM_DEBUG("copy %d exec entries failed %d\n", | 		DRM_DEBUG("copy %d exec entries failed %d\n", | ||||||
|  | @ -1154,7 +1155,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | ||||||
| 		for (i = 0; i < args->buffer_count; i++) | 		for (i = 0; i < args->buffer_count; i++) | ||||||
| 			exec_list[i].offset = exec2_list[i].offset; | 			exec_list[i].offset = exec2_list[i].offset; | ||||||
| 		/* ... and back out to userspace */ | 		/* ... and back out to userspace */ | ||||||
| 		ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr, | 		ret = copy_to_user(to_user_ptr(args->buffers_ptr), | ||||||
| 				   exec_list, | 				   exec_list, | ||||||
| 				   sizeof(*exec_list) * args->buffer_count); | 				   sizeof(*exec_list) * args->buffer_count); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
|  | @ -1195,8 +1196,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 	ret = copy_from_user(exec2_list, | 	ret = copy_from_user(exec2_list, | ||||||
| 			     (struct drm_i915_relocation_entry __user *) | 			     to_user_ptr(args->buffers_ptr), | ||||||
| 			     (uintptr_t) args->buffers_ptr, |  | ||||||
| 			     sizeof(*exec2_list) * args->buffer_count); | 			     sizeof(*exec2_list) * args->buffer_count); | ||||||
| 	if (ret != 0) { | 	if (ret != 0) { | ||||||
| 		DRM_DEBUG("copy %d exec entries failed %d\n", | 		DRM_DEBUG("copy %d exec entries failed %d\n", | ||||||
|  | @ -1208,7 +1208,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, | ||||||
| 	ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); | 	ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		/* Copy the new buffer offsets back to the user's exec list. */ | 		/* Copy the new buffer offsets back to the user's exec list. */ | ||||||
| 		ret = copy_to_user((void __user *)(uintptr_t)args->buffers_ptr, | 		ret = copy_to_user(to_user_ptr(args->buffers_ptr), | ||||||
| 				   exec2_list, | 				   exec2_list, | ||||||
| 				   sizeof(*exec2_list) * args->buffer_count); | 				   sizeof(*exec2_list) * args->buffer_count); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ | ||||||
| #include "i915_trace.h" | #include "i915_trace.h" | ||||||
| #include "intel_drv.h" | #include "intel_drv.h" | ||||||
| 
 | 
 | ||||||
| typedef uint32_t gtt_pte_t; | typedef uint32_t gen6_gtt_pte_t; | ||||||
| 
 | 
 | ||||||
| /* PPGTT stuff */ | /* PPGTT stuff */ | ||||||
| #define GEN6_GTT_ADDR_ENCODE(addr)	((addr) | (((addr) >> 28) & 0xff0)) | #define GEN6_GTT_ADDR_ENCODE(addr)	((addr) | (((addr) >> 28) & 0xff0)) | ||||||
|  | @ -44,11 +44,11 @@ typedef uint32_t gtt_pte_t; | ||||||
| #define GEN6_PTE_CACHE_LLC_MLC		(3 << 1) | #define GEN6_PTE_CACHE_LLC_MLC		(3 << 1) | ||||||
| #define GEN6_PTE_ADDR_ENCODE(addr)	GEN6_GTT_ADDR_ENCODE(addr) | #define GEN6_PTE_ADDR_ENCODE(addr)	GEN6_GTT_ADDR_ENCODE(addr) | ||||||
| 
 | 
 | ||||||
| static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, | static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, | ||||||
| 					     dma_addr_t addr, | 					     dma_addr_t addr, | ||||||
| 					     enum i915_cache_level level) | 					     enum i915_cache_level level) | ||||||
| { | { | ||||||
| 	gtt_pte_t pte = GEN6_PTE_VALID; | 	gen6_gtt_pte_t pte = GEN6_PTE_VALID; | ||||||
| 	pte |= GEN6_PTE_ADDR_ENCODE(addr); | 	pte |= GEN6_PTE_ADDR_ENCODE(addr); | ||||||
| 
 | 
 | ||||||
| 	switch (level) { | 	switch (level) { | ||||||
|  | @ -72,18 +72,85 @@ static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, | ||||||
| 		BUG(); | 		BUG(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	return pte; | 	return pte; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int gen6_ppgtt_enable(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	drm_i915_private_t *dev_priv = dev->dev_private; | ||||||
|  | 	uint32_t pd_offset; | ||||||
|  | 	struct intel_ring_buffer *ring; | ||||||
|  | 	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; | ||||||
|  | 	gen6_gtt_pte_t __iomem *pd_addr; | ||||||
|  | 	uint32_t pd_entry; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm + | ||||||
|  | 		ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); | ||||||
|  | 	for (i = 0; i < ppgtt->num_pd_entries; i++) { | ||||||
|  | 		dma_addr_t pt_addr; | ||||||
|  | 
 | ||||||
|  | 		pt_addr = ppgtt->pt_dma_addr[i]; | ||||||
|  | 		pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); | ||||||
|  | 		pd_entry |= GEN6_PDE_VALID; | ||||||
|  | 
 | ||||||
|  | 		writel(pd_entry, pd_addr + i); | ||||||
|  | 	} | ||||||
|  | 	readl(pd_addr); | ||||||
|  | 
 | ||||||
|  | 	pd_offset = ppgtt->pd_offset; | ||||||
|  | 	pd_offset /= 64; /* in cachelines, */ | ||||||
|  | 	pd_offset <<= 16; | ||||||
|  | 
 | ||||||
|  | 	if (INTEL_INFO(dev)->gen == 6) { | ||||||
|  | 		uint32_t ecochk, gab_ctl, ecobits; | ||||||
|  | 
 | ||||||
|  | 		ecobits = I915_READ(GAC_ECO_BITS); | ||||||
|  | 		I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | | ||||||
|  | 					 ECOBITS_PPGTT_CACHE64B); | ||||||
|  | 
 | ||||||
|  | 		gab_ctl = I915_READ(GAB_CTL); | ||||||
|  | 		I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); | ||||||
|  | 
 | ||||||
|  | 		ecochk = I915_READ(GAM_ECOCHK); | ||||||
|  | 		I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | | ||||||
|  | 				       ECOCHK_PPGTT_CACHE64B); | ||||||
|  | 		I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); | ||||||
|  | 	} else if (INTEL_INFO(dev)->gen >= 7) { | ||||||
|  | 		uint32_t ecochk, ecobits; | ||||||
|  | 
 | ||||||
|  | 		ecobits = I915_READ(GAC_ECO_BITS); | ||||||
|  | 		I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); | ||||||
|  | 
 | ||||||
|  | 		ecochk = I915_READ(GAM_ECOCHK); | ||||||
|  | 		if (IS_HASWELL(dev)) { | ||||||
|  | 			ecochk |= ECOCHK_PPGTT_WB_HSW; | ||||||
|  | 		} else { | ||||||
|  | 			ecochk |= ECOCHK_PPGTT_LLC_IVB; | ||||||
|  | 			ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; | ||||||
|  | 		} | ||||||
|  | 		I915_WRITE(GAM_ECOCHK, ecochk); | ||||||
|  | 		/* GFX_MODE is per-ring on gen7+ */ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for_each_ring(ring, dev_priv, i) { | ||||||
|  | 		if (INTEL_INFO(dev)->gen >= 7) | ||||||
|  | 			I915_WRITE(RING_MODE_GEN7(ring), | ||||||
|  | 				   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); | ||||||
|  | 
 | ||||||
|  | 		I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); | ||||||
|  | 		I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* PPGTT support for Sandybdrige/Gen6 and later */ | /* PPGTT support for Sandybdrige/Gen6 and later */ | ||||||
| static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, | static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, | ||||||
| 				   unsigned first_entry, | 				   unsigned first_entry, | ||||||
| 				   unsigned num_entries) | 				   unsigned num_entries) | ||||||
| { | { | ||||||
| 	gtt_pte_t *pt_vaddr; | 	gen6_gtt_pte_t *pt_vaddr, scratch_pte; | ||||||
| 	gtt_pte_t scratch_pte; | 	unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; | ||||||
| 	unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; |  | ||||||
| 	unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; | 	unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; | ||||||
| 	unsigned last_pte, i; | 	unsigned last_pte, i; | ||||||
| 
 | 
 | ||||||
|  | @ -96,7 +163,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, | ||||||
| 		if (last_pte > I915_PPGTT_PT_ENTRIES) | 		if (last_pte > I915_PPGTT_PT_ENTRIES) | ||||||
| 			last_pte = I915_PPGTT_PT_ENTRIES; | 			last_pte = I915_PPGTT_PT_ENTRIES; | ||||||
| 
 | 
 | ||||||
| 		pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); | 		pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); | ||||||
| 
 | 
 | ||||||
| 		for (i = first_pte; i < last_pte; i++) | 		for (i = first_pte; i < last_pte; i++) | ||||||
| 			pt_vaddr[i] = scratch_pte; | 			pt_vaddr[i] = scratch_pte; | ||||||
|  | @ -105,7 +172,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, | ||||||
| 
 | 
 | ||||||
| 		num_entries -= last_pte - first_pte; | 		num_entries -= last_pte - first_pte; | ||||||
| 		first_pte = 0; | 		first_pte = 0; | ||||||
| 		act_pd++; | 		act_pt++; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -114,43 +181,27 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, | ||||||
| 				      unsigned first_entry, | 				      unsigned first_entry, | ||||||
| 				      enum i915_cache_level cache_level) | 				      enum i915_cache_level cache_level) | ||||||
| { | { | ||||||
| 	gtt_pte_t *pt_vaddr; | 	gen6_gtt_pte_t *pt_vaddr; | ||||||
| 	unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; | 	unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; | ||||||
| 	unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; | 	unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; | ||||||
| 	unsigned i, j, m, segment_len; | 	struct sg_page_iter sg_iter; | ||||||
|  | 
 | ||||||
|  | 	pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); | ||||||
|  | 	for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { | ||||||
| 		dma_addr_t page_addr; | 		dma_addr_t page_addr; | ||||||
| 	struct scatterlist *sg; |  | ||||||
| 
 | 
 | ||||||
| 	/* init sg walking */ | 		page_addr = sg_page_iter_dma_address(&sg_iter); | ||||||
| 	sg = pages->sgl; | 		pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, | ||||||
| 	i = 0; |  | ||||||
| 	segment_len = sg_dma_len(sg) >> PAGE_SHIFT; |  | ||||||
| 	m = 0; |  | ||||||
| 
 |  | ||||||
| 	while (i < pages->nents) { |  | ||||||
| 		pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); |  | ||||||
| 
 |  | ||||||
| 		for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { |  | ||||||
| 			page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); |  | ||||||
| 			pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr, |  | ||||||
| 						    cache_level); | 						    cache_level); | ||||||
| 
 | 		if (++act_pte == I915_PPGTT_PT_ENTRIES) { | ||||||
| 			/* grab the next page */ |  | ||||||
| 			if (++m == segment_len) { |  | ||||||
| 				if (++i == pages->nents) |  | ||||||
| 					break; |  | ||||||
| 
 |  | ||||||
| 				sg = sg_next(sg); |  | ||||||
| 				segment_len = sg_dma_len(sg) >> PAGE_SHIFT; |  | ||||||
| 				m = 0; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 			kunmap_atomic(pt_vaddr); | 			kunmap_atomic(pt_vaddr); | ||||||
|  | 			act_pt++; | ||||||
|  | 			pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]); | ||||||
|  | 			act_pte = 0; | ||||||
| 
 | 
 | ||||||
| 		first_pte = 0; |  | ||||||
| 		act_pd++; |  | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  | 	kunmap_atomic(pt_vaddr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) | static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) | ||||||
|  | @ -182,10 +233,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) | ||||||
| 	/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
 | 	/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
 | ||||||
| 	 * entries. For aliasing ppgtt support we just steal them at the end for | 	 * entries. For aliasing ppgtt support we just steal them at the end for | ||||||
| 	 * now. */ | 	 * now. */ | ||||||
| 	first_pd_entry_in_global_pt = |        first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt); | ||||||
| 		gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; |  | ||||||
| 
 | 
 | ||||||
| 	ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; | 	ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; | ||||||
|  | 	ppgtt->enable = gen6_ppgtt_enable; | ||||||
| 	ppgtt->clear_range = gen6_ppgtt_clear_range; | 	ppgtt->clear_range = gen6_ppgtt_clear_range; | ||||||
| 	ppgtt->insert_entries = gen6_ppgtt_insert_entries; | 	ppgtt->insert_entries = gen6_ppgtt_insert_entries; | ||||||
| 	ppgtt->cleanup = gen6_ppgtt_cleanup; | 	ppgtt->cleanup = gen6_ppgtt_cleanup; | ||||||
|  | @ -219,12 +270,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) | ||||||
| 		ppgtt->pt_dma_addr[i] = pt_addr; | 		ppgtt->pt_dma_addr[i] = pt_addr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; |  | ||||||
| 
 |  | ||||||
| 	ppgtt->clear_range(ppgtt, 0, | 	ppgtt->clear_range(ppgtt, 0, | ||||||
| 			   ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); | 			   ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); | ||||||
| 
 | 
 | ||||||
| 	ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); | 	ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
|  | @ -256,8 +305,13 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	ppgtt->dev = dev; | 	ppgtt->dev = dev; | ||||||
|  | 	ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; | ||||||
| 
 | 
 | ||||||
|  | 	if (INTEL_INFO(dev)->gen < 8) | ||||||
| 		ret = gen6_ppgtt_init(ppgtt); | 		ret = gen6_ppgtt_init(ppgtt); | ||||||
|  | 	else | ||||||
|  | 		BUG(); | ||||||
|  | 
 | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		kfree(ppgtt); | 		kfree(ppgtt); | ||||||
| 	else | 	else | ||||||
|  | @ -275,6 +329,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	ppgtt->cleanup(ppgtt); | 	ppgtt->cleanup(ppgtt); | ||||||
|  | 	dev_priv->mm.aliasing_ppgtt = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, | void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, | ||||||
|  | @ -294,64 +349,6 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, | ||||||
| 			   obj->base.size >> PAGE_SHIFT); | 			   obj->base.size >> PAGE_SHIFT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void i915_gem_init_ppgtt(struct drm_device *dev) |  | ||||||
| { |  | ||||||
| 	drm_i915_private_t *dev_priv = dev->dev_private; |  | ||||||
| 	uint32_t pd_offset; |  | ||||||
| 	struct intel_ring_buffer *ring; |  | ||||||
| 	struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; |  | ||||||
| 	gtt_pte_t __iomem *pd_addr; |  | ||||||
| 	uint32_t pd_entry; |  | ||||||
| 	int i; |  | ||||||
| 
 |  | ||||||
| 	if (!dev_priv->mm.aliasing_ppgtt) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); |  | ||||||
| 	for (i = 0; i < ppgtt->num_pd_entries; i++) { |  | ||||||
| 		dma_addr_t pt_addr; |  | ||||||
| 
 |  | ||||||
| 		pt_addr = ppgtt->pt_dma_addr[i]; |  | ||||||
| 		pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); |  | ||||||
| 		pd_entry |= GEN6_PDE_VALID; |  | ||||||
| 
 |  | ||||||
| 		writel(pd_entry, pd_addr + i); |  | ||||||
| 	} |  | ||||||
| 	readl(pd_addr); |  | ||||||
| 
 |  | ||||||
| 	pd_offset = ppgtt->pd_offset; |  | ||||||
| 	pd_offset /= 64; /* in cachelines, */ |  | ||||||
| 	pd_offset <<= 16; |  | ||||||
| 
 |  | ||||||
| 	if (INTEL_INFO(dev)->gen == 6) { |  | ||||||
| 		uint32_t ecochk, gab_ctl, ecobits; |  | ||||||
| 
 |  | ||||||
| 		ecobits = I915_READ(GAC_ECO_BITS); |  | ||||||
| 		I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); |  | ||||||
| 
 |  | ||||||
| 		gab_ctl = I915_READ(GAB_CTL); |  | ||||||
| 		I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); |  | ||||||
| 
 |  | ||||||
| 		ecochk = I915_READ(GAM_ECOCHK); |  | ||||||
| 		I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | |  | ||||||
| 				       ECOCHK_PPGTT_CACHE64B); |  | ||||||
| 		I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); |  | ||||||
| 	} else if (INTEL_INFO(dev)->gen >= 7) { |  | ||||||
| 		I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); |  | ||||||
| 		/* GFX_MODE is per-ring on gen7+ */ |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for_each_ring(ring, dev_priv, i) { |  | ||||||
| 		if (INTEL_INFO(dev)->gen >= 7) |  | ||||||
| 			I915_WRITE(RING_MODE_GEN7(ring), |  | ||||||
| 				   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); |  | ||||||
| 
 |  | ||||||
| 		I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); |  | ||||||
| 		I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| extern int intel_iommu_gfx_mapped; | extern int intel_iommu_gfx_mapped; | ||||||
| /* Certain Gen5 chipsets require require idling the GPU before
 | /* Certain Gen5 chipsets require require idling the GPU before
 | ||||||
|  * unmapping anything from the GTT when VT-d is enabled. |  * unmapping anything from the GTT when VT-d is enabled. | ||||||
|  | @ -432,22 +429,17 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, | ||||||
| 				     enum i915_cache_level level) | 				     enum i915_cache_level level) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct scatterlist *sg = st->sgl; | 	gen6_gtt_pte_t __iomem *gtt_entries = | ||||||
| 	gtt_pte_t __iomem *gtt_entries = | 		(gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; | ||||||
| 		(gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; | 	int i = 0; | ||||||
| 	int unused, i = 0; | 	struct sg_page_iter sg_iter; | ||||||
| 	unsigned int len, m = 0; |  | ||||||
| 	dma_addr_t addr; | 	dma_addr_t addr; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(st->sgl, sg, st->nents, unused) { | 	for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { | ||||||
| 		len = sg_dma_len(sg) >> PAGE_SHIFT; | 		addr = sg_page_iter_dma_address(&sg_iter); | ||||||
| 		for (m = 0; m < len; m++) { | 		iowrite32(gen6_pte_encode(dev, addr, level), >t_entries[i]); | ||||||
| 			addr = sg_dma_address(sg) + (m << PAGE_SHIFT); |  | ||||||
| 			iowrite32(gen6_pte_encode(dev, addr, level), |  | ||||||
| 				  >t_entries[i]); |  | ||||||
| 		i++; | 		i++; | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* XXX: This serves as a posting read to make sure that the PTE has
 | 	/* XXX: This serves as a posting read to make sure that the PTE has
 | ||||||
| 	 * actually been updated. There is some concern that even though | 	 * actually been updated. There is some concern that even though | ||||||
|  | @ -472,8 +464,8 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, | ||||||
| 				  unsigned int num_entries) | 				  unsigned int num_entries) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	gtt_pte_t scratch_pte; | 	gen6_gtt_pte_t scratch_pte, __iomem *gtt_base = | ||||||
| 	gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; | 		(gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; | ||||||
| 	const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; | 	const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
|  | @ -647,9 +639,12 @@ void i915_gem_init_global_gtt(struct drm_device *dev) | ||||||
| 
 | 
 | ||||||
| 	if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { | 	if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { | ||||||
| 		int ret; | 		int ret; | ||||||
|  | 
 | ||||||
|  | 		if (INTEL_INFO(dev)->gen <= 7) { | ||||||
| 			/* PPGTT pdes are stolen from global gtt ptes, so shrink the
 | 			/* PPGTT pdes are stolen from global gtt ptes, so shrink the
 | ||||||
| 			 * aperture accordingly when using aliasing ppgtt. */ | 			 * aperture accordingly when using aliasing ppgtt. */ | ||||||
| 			gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; | 			gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); | 		i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); | ||||||
| 
 | 
 | ||||||
|  | @ -752,15 +747,17 @@ static int gen6_gmch_probe(struct drm_device *dev, | ||||||
| 	pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); | 	pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); | ||||||
| 	gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); | 	gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl); | ||||||
| 
 | 
 | ||||||
| 	if (IS_GEN7(dev)) | 	if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) | ||||||
| 		*stolen = gen7_get_stolen_size(snb_gmch_ctl); | 		*stolen = gen7_get_stolen_size(snb_gmch_ctl); | ||||||
| 	else | 	else | ||||||
| 		*stolen = gen6_get_stolen_size(snb_gmch_ctl); | 		*stolen = gen6_get_stolen_size(snb_gmch_ctl); | ||||||
| 
 | 
 | ||||||
| 	*gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; | 	*gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT; | ||||||
|  | 
 | ||||||
|  | 	/* For Modern GENs the PTEs and register space are split in the BAR */ | ||||||
|  | 	gtt_bus_addr = pci_resource_start(dev->pdev, 0) + | ||||||
|  | 		(pci_resource_len(dev->pdev, 0) / 2); | ||||||
| 
 | 
 | ||||||
| 	/* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ |  | ||||||
| 	gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); |  | ||||||
| 	dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); | 	dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); | ||||||
| 	if (!dev_priv->gtt.gsm) { | 	if (!dev_priv->gtt.gsm) { | ||||||
| 		DRM_ERROR("Failed to map the gtt page table\n"); | 		DRM_ERROR("Failed to map the gtt page table\n"); | ||||||
|  | @ -817,7 +814,6 @@ int i915_gem_gtt_init(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct i915_gtt *gtt = &dev_priv->gtt; | 	struct i915_gtt *gtt = &dev_priv->gtt; | ||||||
| 	unsigned long gtt_size; |  | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (INTEL_INFO(dev)->gen <= 5) { | 	if (INTEL_INFO(dev)->gen <= 5) { | ||||||
|  | @ -835,8 +831,6 @@ int i915_gem_gtt_init(struct drm_device *dev) | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); |  | ||||||
| 
 |  | ||||||
| 	/* GMADR is the PCI mmio aperture into the global GTT. */ | 	/* GMADR is the PCI mmio aperture into the global GTT. */ | ||||||
| 	DRM_INFO("Memory usable by graphics device = %zdM\n", | 	DRM_INFO("Memory usable by graphics device = %zdM\n", | ||||||
| 		 dev_priv->gtt.total >> 20); | 		 dev_priv->gtt.total >> 20); | ||||||
|  |  | ||||||
|  | @ -312,6 +312,71 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | struct drm_i915_gem_object * | ||||||
|  | i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, | ||||||
|  | 					       u32 stolen_offset, | ||||||
|  | 					       u32 gtt_offset, | ||||||
|  | 					       u32 size) | ||||||
|  | { | ||||||
|  | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	struct drm_i915_gem_object *obj; | ||||||
|  | 	struct drm_mm_node *stolen; | ||||||
|  | 
 | ||||||
|  | 	if (dev_priv->mm.stolen_base == 0) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n", | ||||||
|  | 			stolen_offset, gtt_offset, size); | ||||||
|  | 
 | ||||||
|  | 	/* KISS and expect everything to be page-aligned */ | ||||||
|  | 	BUG_ON(stolen_offset & 4095); | ||||||
|  | 	BUG_ON(gtt_offset & 4095); | ||||||
|  | 	BUG_ON(size & 4095); | ||||||
|  | 
 | ||||||
|  | 	if (WARN_ON(size == 0)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	stolen = drm_mm_create_block(&dev_priv->mm.stolen, | ||||||
|  | 				     stolen_offset, size, | ||||||
|  | 				     false); | ||||||
|  | 	if (stolen == NULL) { | ||||||
|  | 		DRM_DEBUG_KMS("failed to allocate stolen space\n"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	obj = _i915_gem_object_create_stolen(dev, stolen); | ||||||
|  | 	if (obj == NULL) { | ||||||
|  | 		DRM_DEBUG_KMS("failed to allocate stolen object\n"); | ||||||
|  | 		drm_mm_put_block(stolen); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* To simplify the initialisation sequence between KMS and GTT,
 | ||||||
|  | 	 * we allow construction of the stolen object prior to | ||||||
|  | 	 * setting up the GTT space. The actual reservation will occur | ||||||
|  | 	 * later. | ||||||
|  | 	 */ | ||||||
|  | 	if (drm_mm_initialized(&dev_priv->mm.gtt_space)) { | ||||||
|  | 		obj->gtt_space = drm_mm_create_block(&dev_priv->mm.gtt_space, | ||||||
|  | 						     gtt_offset, size, | ||||||
|  | 						     false); | ||||||
|  | 		if (obj->gtt_space == NULL) { | ||||||
|  | 			DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); | ||||||
|  | 			drm_gem_object_unreference(&obj->base); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 	} else | ||||||
|  | 		obj->gtt_space = I915_GTT_RESERVED; | ||||||
|  | 
 | ||||||
|  | 	obj->gtt_offset = gtt_offset; | ||||||
|  | 	obj->has_global_gtt_mapping = 1; | ||||||
|  | 
 | ||||||
|  | 	list_add_tail(&obj->gtt_list, &dev_priv->mm.bound_list); | ||||||
|  | 	list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); | ||||||
|  | 
 | ||||||
|  | 	return obj; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void | void | ||||||
| i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) | i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -217,9 +217,12 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) | ||||||
| 		tile_width = 512; | 		tile_width = 512; | ||||||
| 
 | 
 | ||||||
| 	/* check maximum stride & object size */ | 	/* check maximum stride & object size */ | ||||||
| 	if (INTEL_INFO(dev)->gen >= 4) { | 	/* i965+ stores the end address of the gtt mapping in the fence
 | ||||||
| 		/* i965 stores the end address of the gtt mapping in the fence
 |  | ||||||
| 	 * reg, so dont bother to check the size */ | 	 * reg, so dont bother to check the size */ | ||||||
|  | 	if (INTEL_INFO(dev)->gen >= 7) { | ||||||
|  | 		if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL) | ||||||
|  | 			return false; | ||||||
|  | 	} else if (INTEL_INFO(dev)->gen >= 4) { | ||||||
| 		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) | 		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) | ||||||
| 			return false; | 			return false; | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -235,6 +238,9 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (stride < tile_width) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
| 	/* 965+ just needs multiples of tile width */ | 	/* 965+ just needs multiples of tile width */ | ||||||
| 	if (INTEL_INFO(dev)->gen >= 4) { | 	if (INTEL_INFO(dev)->gen >= 4) { | ||||||
| 		if (stride & (tile_width - 1)) | 		if (stride & (tile_width - 1)) | ||||||
|  | @ -243,9 +249,6 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Pre-965 needs power of two tile widths */ | 	/* Pre-965 needs power of two tile widths */ | ||||||
| 	if (stride < tile_width) |  | ||||||
| 		return false; |  | ||||||
| 
 |  | ||||||
| 	if (stride & (stride - 1)) | 	if (stride & (stride - 1)) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
|  | @ -473,28 +476,29 @@ i915_gem_swizzle_page(struct page *page) | ||||||
| void | void | ||||||
| i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) | i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) | ||||||
| { | { | ||||||
| 	struct scatterlist *sg; | 	struct sg_page_iter sg_iter; | ||||||
| 	int page_count = obj->base.size >> PAGE_SHIFT; |  | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	if (obj->bit_17 == NULL) | 	if (obj->bit_17 == NULL) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(obj->pages->sgl, sg, page_count, i) { | 	i = 0; | ||||||
| 		struct page *page = sg_page(sg); | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { | ||||||
|  | 		struct page *page = sg_page_iter_page(&sg_iter); | ||||||
| 		char new_bit_17 = page_to_phys(page) >> 17; | 		char new_bit_17 = page_to_phys(page) >> 17; | ||||||
| 		if ((new_bit_17 & 0x1) != | 		if ((new_bit_17 & 0x1) != | ||||||
| 		    (test_bit(i, obj->bit_17) != 0)) { | 		    (test_bit(i, obj->bit_17) != 0)) { | ||||||
| 			i915_gem_swizzle_page(page); | 			i915_gem_swizzle_page(page); | ||||||
| 			set_page_dirty(page); | 			set_page_dirty(page); | ||||||
| 		} | 		} | ||||||
|  | 		i++; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) | i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) | ||||||
| { | { | ||||||
| 	struct scatterlist *sg; | 	struct sg_page_iter sg_iter; | ||||||
| 	int page_count = obj->base.size >> PAGE_SHIFT; | 	int page_count = obj->base.size >> PAGE_SHIFT; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
|  | @ -508,11 +512,12 @@ i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for_each_sg(obj->pages->sgl, sg, page_count, i) { | 	i = 0; | ||||||
| 		struct page *page = sg_page(sg); | 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { | ||||||
| 		if (page_to_phys(page) & (1 << 17)) | 		if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) | ||||||
| 			__set_bit(i, obj->bit_17); | 			__set_bit(i, obj->bit_17); | ||||||
| 		else | 		else | ||||||
| 			__clear_bit(i, obj->bit_17); | 			__clear_bit(i, obj->bit_17); | ||||||
|  | 		i++; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -91,6 +91,7 @@ | ||||||
| #define  GRDOM_FULL	(0<<2) | #define  GRDOM_FULL	(0<<2) | ||||||
| #define  GRDOM_RENDER	(1<<2) | #define  GRDOM_RENDER	(1<<2) | ||||||
| #define  GRDOM_MEDIA	(3<<2) | #define  GRDOM_MEDIA	(3<<2) | ||||||
|  | #define  GRDOM_MASK	(3<<2) | ||||||
| #define  GRDOM_RESET_ENABLE (1<<0) | #define  GRDOM_RESET_ENABLE (1<<0) | ||||||
| 
 | 
 | ||||||
| #define GEN6_MBCUNIT_SNPCR	0x900c /* for LLC config */ | #define GEN6_MBCUNIT_SNPCR	0x900c /* for LLC config */ | ||||||
|  | @ -121,10 +122,17 @@ | ||||||
| 
 | 
 | ||||||
| #define GAM_ECOCHK			0x4090 | #define GAM_ECOCHK			0x4090 | ||||||
| #define   ECOCHK_SNB_BIT		(1<<10) | #define   ECOCHK_SNB_BIT		(1<<10) | ||||||
|  | #define   HSW_ECOCHK_ARB_PRIO_SOL	(1<<6) | ||||||
| #define   ECOCHK_PPGTT_CACHE64B		(0x3<<3) | #define   ECOCHK_PPGTT_CACHE64B		(0x3<<3) | ||||||
| #define   ECOCHK_PPGTT_CACHE4B		(0x0<<3) | #define   ECOCHK_PPGTT_CACHE4B		(0x0<<3) | ||||||
|  | #define   ECOCHK_PPGTT_GFDT_IVB		(0x1<<4) | ||||||
|  | #define   ECOCHK_PPGTT_LLC_IVB		(0x1<<3) | ||||||
|  | #define   ECOCHK_PPGTT_UC_HSW		(0x1<<3) | ||||||
|  | #define   ECOCHK_PPGTT_WT_HSW		(0x2<<3) | ||||||
|  | #define   ECOCHK_PPGTT_WB_HSW		(0x3<<3) | ||||||
| 
 | 
 | ||||||
| #define GAC_ECO_BITS			0x14090 | #define GAC_ECO_BITS			0x14090 | ||||||
|  | #define   ECOBITS_SNB_BIT		(1<<13) | ||||||
| #define   ECOBITS_PPGTT_CACHE64B	(3<<8) | #define   ECOBITS_PPGTT_CACHE64B	(3<<8) | ||||||
| #define   ECOBITS_PPGTT_CACHE4B		(0<<8) | #define   ECOBITS_PPGTT_CACHE4B		(0<<8) | ||||||
| 
 | 
 | ||||||
|  | @ -422,6 +430,7 @@ | ||||||
| 
 | 
 | ||||||
| #define FENCE_REG_SANDYBRIDGE_0		0x100000 | #define FENCE_REG_SANDYBRIDGE_0		0x100000 | ||||||
| #define   SANDYBRIDGE_FENCE_PITCH_SHIFT	32 | #define   SANDYBRIDGE_FENCE_PITCH_SHIFT	32 | ||||||
|  | #define   GEN7_FENCE_MAX_PITCH_VAL	0x0800 | ||||||
| 
 | 
 | ||||||
| /* control register for cpu gtt access */ | /* control register for cpu gtt access */ | ||||||
| #define TILECTL				0x101000 | #define TILECTL				0x101000 | ||||||
|  | @ -522,6 +531,9 @@ | ||||||
| #define GEN7_ERR_INT	0x44040 | #define GEN7_ERR_INT	0x44040 | ||||||
| #define   ERR_INT_MMIO_UNCLAIMED (1<<13) | #define   ERR_INT_MMIO_UNCLAIMED (1<<13) | ||||||
| 
 | 
 | ||||||
|  | #define FPGA_DBG		0x42300 | ||||||
|  | #define   FPGA_DBG_RM_NOCLAIM	(1<<31) | ||||||
|  | 
 | ||||||
| #define DERRMR		0x44050 | #define DERRMR		0x44050 | ||||||
| 
 | 
 | ||||||
| /* GM45+ chicken bits -- debug workaround bits that may be required
 | /* GM45+ chicken bits -- debug workaround bits that may be required
 | ||||||
|  | @ -591,6 +603,7 @@ | ||||||
| #define   I915_USER_INTERRUPT				(1<<1) | #define   I915_USER_INTERRUPT				(1<<1) | ||||||
| #define   I915_ASLE_INTERRUPT				(1<<0) | #define   I915_ASLE_INTERRUPT				(1<<0) | ||||||
| #define   I915_BSD_USER_INTERRUPT                      (1<<25) | #define   I915_BSD_USER_INTERRUPT                      (1<<25) | ||||||
|  | #define   DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ | ||||||
| #define EIR		0x020b0 | #define EIR		0x020b0 | ||||||
| #define EMR		0x020b4 | #define EMR		0x020b4 | ||||||
| #define ESR		0x020b8 | #define ESR		0x020b8 | ||||||
|  | @ -1197,6 +1210,9 @@ | ||||||
| 
 | 
 | ||||||
| #define MCHBAR_MIRROR_BASE_SNB	0x140000 | #define MCHBAR_MIRROR_BASE_SNB	0x140000 | ||||||
| 
 | 
 | ||||||
|  | /* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ | ||||||
|  | #define DCLK 0x5e04 | ||||||
|  | 
 | ||||||
| /** 915-945 and GM965 MCH register controlling DRAM channel access */ | /** 915-945 and GM965 MCH register controlling DRAM channel access */ | ||||||
| #define DCC			0x10200 | #define DCC			0x10200 | ||||||
| #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL		(0 << 0) | #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL		(0 << 0) | ||||||
|  | @ -1637,6 +1653,12 @@ | ||||||
| #define   SDVOC_HOTPLUG_INT_EN			(1 << 25) | #define   SDVOC_HOTPLUG_INT_EN			(1 << 25) | ||||||
| #define   TV_HOTPLUG_INT_EN			(1 << 18) | #define   TV_HOTPLUG_INT_EN			(1 << 18) | ||||||
| #define   CRT_HOTPLUG_INT_EN			(1 << 9) | #define   CRT_HOTPLUG_INT_EN			(1 << 9) | ||||||
|  | #define HOTPLUG_INT_EN_MASK			(PORTB_HOTPLUG_INT_EN | \ | ||||||
|  | 						 PORTC_HOTPLUG_INT_EN | \ | ||||||
|  | 						 PORTD_HOTPLUG_INT_EN | \ | ||||||
|  | 						 SDVOC_HOTPLUG_INT_EN | \ | ||||||
|  | 						 SDVOB_HOTPLUG_INT_EN | \ | ||||||
|  | 						 CRT_HOTPLUG_INT_EN) | ||||||
| #define   CRT_HOTPLUG_FORCE_DETECT		(1 << 3) | #define   CRT_HOTPLUG_FORCE_DETECT		(1 << 3) | ||||||
| #define CRT_HOTPLUG_ACTIVATION_PERIOD_32	(0 << 8) | #define CRT_HOTPLUG_ACTIVATION_PERIOD_32	(0 << 8) | ||||||
| /* must use period 64 on GM45 according to docs */ | /* must use period 64 on GM45 according to docs */ | ||||||
|  | @ -1675,19 +1697,48 @@ | ||||||
| #define   SDVOB_HOTPLUG_INT_STATUS_I965		(3 << 2) | #define   SDVOB_HOTPLUG_INT_STATUS_I965		(3 << 2) | ||||||
| #define   SDVOC_HOTPLUG_INT_STATUS_I915		(1 << 7) | #define   SDVOC_HOTPLUG_INT_STATUS_I915		(1 << 7) | ||||||
| #define   SDVOB_HOTPLUG_INT_STATUS_I915		(1 << 6) | #define   SDVOB_HOTPLUG_INT_STATUS_I915		(1 << 6) | ||||||
|  | #define   HOTPLUG_INT_STATUS_G4X		(CRT_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 SDVOB_HOTPLUG_INT_STATUS_G4X | \ | ||||||
|  | 						 SDVOC_HOTPLUG_INT_STATUS_G4X | \ | ||||||
|  | 						 PORTB_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 PORTC_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 PORTD_HOTPLUG_INT_STATUS) | ||||||
| 
 | 
 | ||||||
| /* SDVO port control */ | #define HOTPLUG_INT_STATUS_I965			(CRT_HOTPLUG_INT_STATUS | \ | ||||||
| #define SDVOB			0x61140 | 						 SDVOB_HOTPLUG_INT_STATUS_I965 | \ | ||||||
| #define SDVOC			0x61160 | 						 SDVOC_HOTPLUG_INT_STATUS_I965 | \ | ||||||
|  | 						 PORTB_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 PORTC_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 PORTD_HOTPLUG_INT_STATUS) | ||||||
|  | 
 | ||||||
|  | #define HOTPLUG_INT_STATUS_I915			(CRT_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 SDVOB_HOTPLUG_INT_STATUS_I915 | \ | ||||||
|  | 						 SDVOC_HOTPLUG_INT_STATUS_I915 | \ | ||||||
|  | 						 PORTB_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 PORTC_HOTPLUG_INT_STATUS | \ | ||||||
|  | 						 PORTD_HOTPLUG_INT_STATUS) | ||||||
|  | 
 | ||||||
|  | /* SDVO and HDMI port control.
 | ||||||
|  |  * The same register may be used for SDVO or HDMI */ | ||||||
|  | #define GEN3_SDVOB	0x61140 | ||||||
|  | #define GEN3_SDVOC	0x61160 | ||||||
|  | #define GEN4_HDMIB	GEN3_SDVOB | ||||||
|  | #define GEN4_HDMIC	GEN3_SDVOC | ||||||
|  | #define PCH_SDVOB	0xe1140 | ||||||
|  | #define PCH_HDMIB	PCH_SDVOB | ||||||
|  | #define PCH_HDMIC	0xe1150 | ||||||
|  | #define PCH_HDMID	0xe1160 | ||||||
|  | 
 | ||||||
|  | /* Gen 3 SDVO bits: */ | ||||||
| #define   SDVO_ENABLE				(1 << 31) | #define   SDVO_ENABLE				(1 << 31) | ||||||
|  | #define   SDVO_PIPE_SEL(pipe)			((pipe) << 30) | ||||||
|  | #define   SDVO_PIPE_SEL_MASK			(1 << 30) | ||||||
| #define   SDVO_PIPE_B_SELECT			(1 << 30) | #define   SDVO_PIPE_B_SELECT			(1 << 30) | ||||||
| #define   SDVO_STALL_SELECT			(1 << 29) | #define   SDVO_STALL_SELECT			(1 << 29) | ||||||
| #define   SDVO_INTERRUPT_ENABLE			(1 << 26) | #define   SDVO_INTERRUPT_ENABLE			(1 << 26) | ||||||
| /**
 | /**
 | ||||||
|  * 915G/GM SDVO pixel multiplier. |  * 915G/GM SDVO pixel multiplier. | ||||||
|  * |  | ||||||
|  * Programmed value is multiplier - 1, up to 5x. |  * Programmed value is multiplier - 1, up to 5x. | ||||||
|  * |  | ||||||
|  * \sa DPLL_MD_UDI_MULTIPLIER_MASK |  * \sa DPLL_MD_UDI_MULTIPLIER_MASK | ||||||
|  */ |  */ | ||||||
| #define   SDVO_PORT_MULTIPLY_MASK		(7 << 23) | #define   SDVO_PORT_MULTIPLY_MASK		(7 << 23) | ||||||
|  | @ -1695,23 +1746,35 @@ | ||||||
| #define   SDVO_PHASE_SELECT_MASK		(15 << 19) | #define   SDVO_PHASE_SELECT_MASK		(15 << 19) | ||||||
| #define   SDVO_PHASE_SELECT_DEFAULT		(6 << 19) | #define   SDVO_PHASE_SELECT_DEFAULT		(6 << 19) | ||||||
| #define   SDVO_CLOCK_OUTPUT_INVERT		(1 << 18) | #define   SDVO_CLOCK_OUTPUT_INVERT		(1 << 18) | ||||||
| #define   SDVOC_GANG_MODE		(1 << 16) | #define   SDVOC_GANG_MODE			(1 << 16) /* Port C only */ | ||||||
| #define   SDVO_ENCODING_SDVO		(0x0 << 10) | #define   SDVO_BORDER_ENABLE			(1 << 7) /* SDVO only */ | ||||||
| #define   SDVO_ENCODING_HDMI		(0x2 << 10) | #define   SDVOB_PCIE_CONCURRENCY		(1 << 3) /* Port B only */ | ||||||
| /** Requird for HDMI operation */ |  | ||||||
| #define   SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) |  | ||||||
| #define   SDVO_COLOR_RANGE_16_235	(1 << 8) |  | ||||||
| #define   SDVO_BORDER_ENABLE		(1 << 7) |  | ||||||
| #define   SDVO_AUDIO_ENABLE		(1 << 6) |  | ||||||
| /** New with 965, default is to be set */ |  | ||||||
| #define   SDVO_VSYNC_ACTIVE_HIGH	(1 << 4) |  | ||||||
| /** New with 965, default is to be set */ |  | ||||||
| #define   SDVO_HSYNC_ACTIVE_HIGH	(1 << 3) |  | ||||||
| #define   SDVOB_PCIE_CONCURRENCY	(1 << 3) |  | ||||||
| #define   SDVO_DETECTED				(1 << 2) | #define   SDVO_DETECTED				(1 << 2) | ||||||
| /* Bits to be preserved when writing */ | /* Bits to be preserved when writing */ | ||||||
| #define   SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) | #define   SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \ | ||||||
| #define   SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) | 			       SDVO_INTERRUPT_ENABLE) | ||||||
|  | #define   SDVOC_PRESERVE_MASK ((1 << 17) | SDVO_INTERRUPT_ENABLE) | ||||||
|  | 
 | ||||||
|  | /* Gen 4 SDVO/HDMI bits: */ | ||||||
|  | #define   SDVO_COLOR_FORMAT_8bpc		(0 << 26) | ||||||
|  | #define   SDVO_ENCODING_SDVO			(0 << 10) | ||||||
|  | #define   SDVO_ENCODING_HDMI			(2 << 10) | ||||||
|  | #define   HDMI_MODE_SELECT_HDMI			(1 << 9) /* HDMI only */ | ||||||
|  | #define   HDMI_MODE_SELECT_DVI			(0 << 9) /* HDMI only */ | ||||||
|  | #define   HDMI_COLOR_RANGE_16_235		(1 << 8) /* HDMI only */ | ||||||
|  | #define   SDVO_AUDIO_ENABLE			(1 << 6) | ||||||
|  | /* VSYNC/HSYNC bits new with 965, default is to be set */ | ||||||
|  | #define   SDVO_VSYNC_ACTIVE_HIGH		(1 << 4) | ||||||
|  | #define   SDVO_HSYNC_ACTIVE_HIGH		(1 << 3) | ||||||
|  | 
 | ||||||
|  | /* Gen 5 (IBX) SDVO/HDMI bits: */ | ||||||
|  | #define   HDMI_COLOR_FORMAT_12bpc		(3 << 26) /* HDMI only */ | ||||||
|  | #define   SDVOB_HOTPLUG_ENABLE			(1 << 23) /* SDVO only */ | ||||||
|  | 
 | ||||||
|  | /* Gen 6 (CPT) SDVO/HDMI bits: */ | ||||||
|  | #define   SDVO_PIPE_SEL_CPT(pipe)		((pipe) << 29) | ||||||
|  | #define   SDVO_PIPE_SEL_MASK_CPT		(3 << 29) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /* DVO port control */ | /* DVO port control */ | ||||||
| #define DVOA			0x61120 | #define DVOA			0x61120 | ||||||
|  | @ -1898,7 +1961,7 @@ | ||||||
| #define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) | #define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) | ||||||
| 
 | 
 | ||||||
| /* Backlight control */ | /* Backlight control */ | ||||||
| #define BLC_PWM_CTL2		0x61250 /* 965+ only */ | #define BLC_PWM_CTL2	(dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */ | ||||||
| #define   BLM_PWM_ENABLE		(1 << 31) | #define   BLM_PWM_ENABLE		(1 << 31) | ||||||
| #define   BLM_COMBINATION_MODE		(1 << 30) /* gen4 only */ | #define   BLM_COMBINATION_MODE		(1 << 30) /* gen4 only */ | ||||||
| #define   BLM_PIPE_SELECT		(1 << 29) | #define   BLM_PIPE_SELECT		(1 << 29) | ||||||
|  | @ -1917,7 +1980,7 @@ | ||||||
| #define   BLM_PHASE_IN_COUNT_MASK	(0xff << 8) | #define   BLM_PHASE_IN_COUNT_MASK	(0xff << 8) | ||||||
| #define   BLM_PHASE_IN_INCR_SHIFT	(0) | #define   BLM_PHASE_IN_INCR_SHIFT	(0) | ||||||
| #define   BLM_PHASE_IN_INCR_MASK	(0xff << 0) | #define   BLM_PHASE_IN_INCR_MASK	(0xff << 0) | ||||||
| #define BLC_PWM_CTL		0x61254 | #define BLC_PWM_CTL	(dev_priv->info->display_mmio_offset + 0x61254) | ||||||
| /*
 | /*
 | ||||||
|  * This is the most significant 15 bits of the number of backlight cycles in a |  * This is the most significant 15 bits of the number of backlight cycles in a | ||||||
|  * complete cycle of the modulated backlight control. |  * complete cycle of the modulated backlight control. | ||||||
|  | @ -1939,7 +2002,7 @@ | ||||||
| #define   BACKLIGHT_DUTY_CYCLE_MASK_PNV		(0xfffe) | #define   BACKLIGHT_DUTY_CYCLE_MASK_PNV		(0xfffe) | ||||||
| #define   BLM_POLARITY_PNV			(1 << 0) /* pnv only */ | #define   BLM_POLARITY_PNV			(1 << 0) /* pnv only */ | ||||||
| 
 | 
 | ||||||
| #define BLC_HIST_CTL		0x61260 | #define BLC_HIST_CTL	(dev_priv->info->display_mmio_offset + 0x61260) | ||||||
| 
 | 
 | ||||||
| /* New registers for PCH-split platforms. Safe where new bits show up, the
 | /* New registers for PCH-split platforms. Safe where new bits show up, the
 | ||||||
|  * register layout machtes with gen4 BLC_PWM_CTL[12]. */ |  * register layout machtes with gen4 BLC_PWM_CTL[12]. */ | ||||||
|  | @ -2589,14 +2652,14 @@ | ||||||
| #define _PIPEB_GMCH_DATA_M			0x71050 | #define _PIPEB_GMCH_DATA_M			0x71050 | ||||||
| 
 | 
 | ||||||
| /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ | /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ | ||||||
| #define   PIPE_GMCH_DATA_M_TU_SIZE_MASK		(0x3f << 25) | #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */ | ||||||
| #define   PIPE_GMCH_DATA_M_TU_SIZE_SHIFT	25 | #define  TU_SIZE_MASK           (0x3f << 25) | ||||||
| 
 | 
 | ||||||
| #define   PIPE_GMCH_DATA_M_MASK			(0xffffff) | #define  DATA_LINK_M_N_MASK	(0xffffff) | ||||||
|  | #define  DATA_LINK_N_MAX	(0x800000) | ||||||
| 
 | 
 | ||||||
| #define _PIPEA_GMCH_DATA_N			0x70054 | #define _PIPEA_GMCH_DATA_N			0x70054 | ||||||
| #define _PIPEB_GMCH_DATA_N			0x71054 | #define _PIPEB_GMCH_DATA_N			0x71054 | ||||||
| #define   PIPE_GMCH_DATA_N_MASK			(0xffffff) |  | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Computing Link M and N values for the Display Port link |  * Computing Link M and N values for the Display Port link | ||||||
|  | @ -2611,11 +2674,9 @@ | ||||||
| 
 | 
 | ||||||
| #define _PIPEA_DP_LINK_M				0x70060 | #define _PIPEA_DP_LINK_M				0x70060 | ||||||
| #define _PIPEB_DP_LINK_M				0x71060 | #define _PIPEB_DP_LINK_M				0x71060 | ||||||
| #define   PIPEA_DP_LINK_M_MASK			(0xffffff) |  | ||||||
| 
 | 
 | ||||||
| #define _PIPEA_DP_LINK_N				0x70064 | #define _PIPEA_DP_LINK_N				0x70064 | ||||||
| #define _PIPEB_DP_LINK_N				0x71064 | #define _PIPEB_DP_LINK_N				0x71064 | ||||||
| #define   PIPEA_DP_LINK_N_MASK			(0xffffff) |  | ||||||
| 
 | 
 | ||||||
| #define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) | #define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) | ||||||
| #define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) | #define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) | ||||||
|  | @ -2776,6 +2837,8 @@ | ||||||
| #define   DSPFW_HPLL_CURSOR_SHIFT	16 | #define   DSPFW_HPLL_CURSOR_SHIFT	16 | ||||||
| #define   DSPFW_HPLL_CURSOR_MASK	(0x3f<<16) | #define   DSPFW_HPLL_CURSOR_MASK	(0x3f<<16) | ||||||
| #define   DSPFW_HPLL_SR_MASK		(0x1ff) | #define   DSPFW_HPLL_SR_MASK		(0x1ff) | ||||||
|  | #define DSPFW4			(dev_priv->info->display_mmio_offset + 0x70070) | ||||||
|  | #define DSPFW7			(dev_priv->info->display_mmio_offset + 0x7007c) | ||||||
| 
 | 
 | ||||||
| /* drain latency register values*/ | /* drain latency register values*/ | ||||||
| #define DRAIN_LATENCY_PRECISION_32	32 | #define DRAIN_LATENCY_PRECISION_32	32 | ||||||
|  | @ -3233,6 +3296,63 @@ | ||||||
| #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) | #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) | ||||||
| #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) | #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) | ||||||
| 
 | 
 | ||||||
|  | #define _SPACNTR		0x72180 | ||||||
|  | #define   SP_ENABLE			(1<<31) | ||||||
|  | #define   SP_GEAMMA_ENABLE		(1<<30) | ||||||
|  | #define   SP_PIXFORMAT_MASK		(0xf<<26) | ||||||
|  | #define   SP_FORMAT_YUV422		(0<<26) | ||||||
|  | #define   SP_FORMAT_BGR565		(5<<26) | ||||||
|  | #define   SP_FORMAT_BGRX8888		(6<<26) | ||||||
|  | #define   SP_FORMAT_BGRA8888		(7<<26) | ||||||
|  | #define   SP_FORMAT_RGBX1010102		(8<<26) | ||||||
|  | #define   SP_FORMAT_RGBA1010102		(9<<26) | ||||||
|  | #define   SP_FORMAT_RGBX8888		(0xe<<26) | ||||||
|  | #define   SP_FORMAT_RGBA8888		(0xf<<26) | ||||||
|  | #define   SP_SOURCE_KEY			(1<<22) | ||||||
|  | #define   SP_YUV_BYTE_ORDER_MASK	(3<<16) | ||||||
|  | #define   SP_YUV_ORDER_YUYV		(0<<16) | ||||||
|  | #define   SP_YUV_ORDER_UYVY		(1<<16) | ||||||
|  | #define   SP_YUV_ORDER_YVYU		(2<<16) | ||||||
|  | #define   SP_YUV_ORDER_VYUY		(3<<16) | ||||||
|  | #define   SP_TILED			(1<<10) | ||||||
|  | #define _SPALINOFF		0x72184 | ||||||
|  | #define _SPASTRIDE		0x72188 | ||||||
|  | #define _SPAPOS			0x7218c | ||||||
|  | #define _SPASIZE		0x72190 | ||||||
|  | #define _SPAKEYMINVAL		0x72194 | ||||||
|  | #define _SPAKEYMSK		0x72198 | ||||||
|  | #define _SPASURF		0x7219c | ||||||
|  | #define _SPAKEYMAXVAL		0x721a0 | ||||||
|  | #define _SPATILEOFF		0x721a4 | ||||||
|  | #define _SPACONSTALPHA		0x721a8 | ||||||
|  | #define _SPAGAMC		0x721f4 | ||||||
|  | 
 | ||||||
|  | #define _SPBCNTR		0x72280 | ||||||
|  | #define _SPBLINOFF		0x72284 | ||||||
|  | #define _SPBSTRIDE		0x72288 | ||||||
|  | #define _SPBPOS			0x7228c | ||||||
|  | #define _SPBSIZE		0x72290 | ||||||
|  | #define _SPBKEYMINVAL		0x72294 | ||||||
|  | #define _SPBKEYMSK		0x72298 | ||||||
|  | #define _SPBSURF		0x7229c | ||||||
|  | #define _SPBKEYMAXVAL		0x722a0 | ||||||
|  | #define _SPBTILEOFF		0x722a4 | ||||||
|  | #define _SPBCONSTALPHA		0x722a8 | ||||||
|  | #define _SPBGAMC		0x722f4 | ||||||
|  | 
 | ||||||
|  | #define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) | ||||||
|  | #define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) | ||||||
|  | #define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE) | ||||||
|  | #define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS) | ||||||
|  | #define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE) | ||||||
|  | #define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL) | ||||||
|  | #define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK) | ||||||
|  | #define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF) | ||||||
|  | #define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL) | ||||||
|  | #define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF) | ||||||
|  | #define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA) | ||||||
|  | #define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC) | ||||||
|  | 
 | ||||||
| /* VBIOS regs */ | /* VBIOS regs */ | ||||||
| #define VGACNTRL		0x71400 | #define VGACNTRL		0x71400 | ||||||
| # define VGA_DISP_DISABLE			(1 << 31) | # define VGA_DISP_DISABLE			(1 << 31) | ||||||
|  | @ -3282,8 +3402,6 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define _PIPEA_DATA_M1           (dev_priv->info->display_mmio_offset + 0x60030) | #define _PIPEA_DATA_M1           (dev_priv->info->display_mmio_offset + 0x60030) | ||||||
| #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */ |  | ||||||
| #define  TU_SIZE_MASK           0x7e000000 |  | ||||||
| #define  PIPE_DATA_M1_OFFSET    0 | #define  PIPE_DATA_M1_OFFSET    0 | ||||||
| #define _PIPEA_DATA_N1           (dev_priv->info->display_mmio_offset + 0x60034) | #define _PIPEA_DATA_N1           (dev_priv->info->display_mmio_offset + 0x60034) | ||||||
| #define  PIPE_DATA_N1_OFFSET    0 | #define  PIPE_DATA_N1_OFFSET    0 | ||||||
|  | @ -3456,6 +3574,9 @@ | ||||||
| #define DISP_ARB_CTL	0x45000 | #define DISP_ARB_CTL	0x45000 | ||||||
| #define  DISP_TILE_SURFACE_SWIZZLING	(1<<13) | #define  DISP_TILE_SURFACE_SWIZZLING	(1<<13) | ||||||
| #define  DISP_FBC_WM_DIS		(1<<15) | #define  DISP_FBC_WM_DIS		(1<<15) | ||||||
|  | #define GEN7_MSG_CTL	0x45010 | ||||||
|  | #define  WAIT_FOR_PCH_RESET_ACK		(1<<1) | ||||||
|  | #define  WAIT_FOR_PCH_FLR_ACK		(1<<0) | ||||||
| 
 | 
 | ||||||
| /* GEN7 chicken */ | /* GEN7 chicken */ | ||||||
| #define GEN7_COMMON_SLICE_CHICKEN1		0x7010 | #define GEN7_COMMON_SLICE_CHICKEN1		0x7010 | ||||||
|  | @ -3508,7 +3629,11 @@ | ||||||
| #define SDE_PORTC_HOTPLUG       (1 << 9) | #define SDE_PORTC_HOTPLUG       (1 << 9) | ||||||
| #define SDE_PORTB_HOTPLUG       (1 << 8) | #define SDE_PORTB_HOTPLUG       (1 << 8) | ||||||
| #define SDE_SDVOB_HOTPLUG       (1 << 6) | #define SDE_SDVOB_HOTPLUG       (1 << 6) | ||||||
| #define SDE_HOTPLUG_MASK	(0xf << 8) | #define SDE_HOTPLUG_MASK        (SDE_CRT_HOTPLUG | \ | ||||||
|  | 				 SDE_SDVOB_HOTPLUG |	\ | ||||||
|  | 				 SDE_PORTB_HOTPLUG |	\ | ||||||
|  | 				 SDE_PORTC_HOTPLUG |	\ | ||||||
|  | 				 SDE_PORTD_HOTPLUG) | ||||||
| #define SDE_TRANSB_CRC_DONE	(1 << 5) | #define SDE_TRANSB_CRC_DONE	(1 << 5) | ||||||
| #define SDE_TRANSB_CRC_ERR	(1 << 4) | #define SDE_TRANSB_CRC_ERR	(1 << 4) | ||||||
| #define SDE_TRANSB_FIFO_UNDER	(1 << 3) | #define SDE_TRANSB_FIFO_UNDER	(1 << 3) | ||||||
|  | @ -3531,7 +3656,9 @@ | ||||||
| #define SDE_PORTC_HOTPLUG_CPT	(1 << 22) | #define SDE_PORTC_HOTPLUG_CPT	(1 << 22) | ||||||
| #define SDE_PORTB_HOTPLUG_CPT	(1 << 21) | #define SDE_PORTB_HOTPLUG_CPT	(1 << 21) | ||||||
| #define SDE_CRT_HOTPLUG_CPT	(1 << 19) | #define SDE_CRT_HOTPLUG_CPT	(1 << 19) | ||||||
|  | #define SDE_SDVOB_HOTPLUG_CPT	(1 << 18) | ||||||
| #define SDE_HOTPLUG_MASK_CPT	(SDE_CRT_HOTPLUG_CPT |		\ | #define SDE_HOTPLUG_MASK_CPT	(SDE_CRT_HOTPLUG_CPT |		\ | ||||||
|  | 				 SDE_SDVOB_HOTPLUG_CPT |	\ | ||||||
| 				 SDE_PORTD_HOTPLUG_CPT |	\ | 				 SDE_PORTD_HOTPLUG_CPT |	\ | ||||||
| 				 SDE_PORTC_HOTPLUG_CPT |	\ | 				 SDE_PORTC_HOTPLUG_CPT |	\ | ||||||
| 				 SDE_PORTB_HOTPLUG_CPT) | 				 SDE_PORTB_HOTPLUG_CPT) | ||||||
|  | @ -3754,14 +3881,16 @@ | ||||||
| #define HSW_VIDEO_DIP_VSC_ECC_B		0x61344 | #define HSW_VIDEO_DIP_VSC_ECC_B		0x61344 | ||||||
| #define HSW_VIDEO_DIP_GCP_B		0x61210 | #define HSW_VIDEO_DIP_GCP_B		0x61210 | ||||||
| 
 | 
 | ||||||
| #define HSW_TVIDEO_DIP_CTL(pipe) \ | #define HSW_TVIDEO_DIP_CTL(trans) \ | ||||||
| 	 _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) | 	 _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B) | ||||||
| #define HSW_TVIDEO_DIP_AVI_DATA(pipe) \ | #define HSW_TVIDEO_DIP_AVI_DATA(trans) \ | ||||||
| 	 _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) | 	 _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B) | ||||||
| #define HSW_TVIDEO_DIP_SPD_DATA(pipe) \ | #define HSW_TVIDEO_DIP_SPD_DATA(trans) \ | ||||||
| 	 _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) | 	 _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B) | ||||||
| #define HSW_TVIDEO_DIP_GCP(pipe) \ | #define HSW_TVIDEO_DIP_GCP(trans) \ | ||||||
| 	_PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) | 	_TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B) | ||||||
|  | #define HSW_TVIDEO_DIP_VSC_DATA(trans) \ | ||||||
|  | 	 _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) | ||||||
| 
 | 
 | ||||||
| #define _TRANS_HTOTAL_B          0xe1000 | #define _TRANS_HTOTAL_B          0xe1000 | ||||||
| #define _TRANS_HBLANK_B          0xe1004 | #define _TRANS_HBLANK_B          0xe1004 | ||||||
|  | @ -3827,7 +3956,10 @@ | ||||||
| #define _TRANSB_CHICKEN2	 0xf1064 | #define _TRANSB_CHICKEN2	 0xf1064 | ||||||
| #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) | #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) | ||||||
| #define  TRANS_CHICKEN2_TIMING_OVERRIDE			(1<<31) | #define  TRANS_CHICKEN2_TIMING_OVERRIDE			(1<<31) | ||||||
| 
 | #define  TRANS_CHICKEN2_FDI_POLARITY_REVERSED		(1<<29) | ||||||
|  | #define  TRANS_CHICKEN2_FRAME_START_DELAY_MASK		(3<<27) | ||||||
|  | #define  TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER	(1<<26) | ||||||
|  | #define  TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH	(1<<25) | ||||||
| 
 | 
 | ||||||
| #define SOUTH_CHICKEN1		0xc2000 | #define SOUTH_CHICKEN1		0xc2000 | ||||||
| #define  FDIA_PHASE_SYNC_SHIFT_OVR	19 | #define  FDIA_PHASE_SYNC_SHIFT_OVR	19 | ||||||
|  | @ -3976,34 +4108,6 @@ | ||||||
| #define FDI_PLL_CTL_1           0xfe000 | #define FDI_PLL_CTL_1           0xfe000 | ||||||
| #define FDI_PLL_CTL_2           0xfe004 | #define FDI_PLL_CTL_2           0xfe004 | ||||||
| 
 | 
 | ||||||
| /* or SDVOB */ |  | ||||||
| #define HDMIB   0xe1140 |  | ||||||
| #define  PORT_ENABLE    (1 << 31) |  | ||||||
| #define  TRANSCODER(pipe)       ((pipe) << 30) |  | ||||||
| #define  TRANSCODER_CPT(pipe)   ((pipe) << 29) |  | ||||||
| #define  TRANSCODER_MASK        (1 << 30) |  | ||||||
| #define  TRANSCODER_MASK_CPT    (3 << 29) |  | ||||||
| #define  COLOR_FORMAT_8bpc      (0) |  | ||||||
| #define  COLOR_FORMAT_12bpc     (3 << 26) |  | ||||||
| #define  SDVOB_HOTPLUG_ENABLE   (1 << 23) |  | ||||||
| #define  SDVO_ENCODING          (0) |  | ||||||
| #define  TMDS_ENCODING          (2 << 10) |  | ||||||
| #define  NULL_PACKET_VSYNC_ENABLE       (1 << 9) |  | ||||||
| /* CPT */ |  | ||||||
| #define  HDMI_MODE_SELECT	(1 << 9) |  | ||||||
| #define  DVI_MODE_SELECT	(0) |  | ||||||
| #define  SDVOB_BORDER_ENABLE    (1 << 7) |  | ||||||
| #define  AUDIO_ENABLE           (1 << 6) |  | ||||||
| #define  VSYNC_ACTIVE_HIGH      (1 << 4) |  | ||||||
| #define  HSYNC_ACTIVE_HIGH      (1 << 3) |  | ||||||
| #define  PORT_DETECTED          (1 << 2) |  | ||||||
| 
 |  | ||||||
| /* PCH SDVOB multiplex with HDMIB */ |  | ||||||
| #define PCH_SDVOB	HDMIB |  | ||||||
| 
 |  | ||||||
| #define HDMIC   0xe1150 |  | ||||||
| #define HDMID   0xe1160 |  | ||||||
| 
 |  | ||||||
| #define PCH_LVDS	0xe1180 | #define PCH_LVDS	0xe1180 | ||||||
| #define  LVDS_DETECTED	(1 << 1) | #define  LVDS_DETECTED	(1 << 1) | ||||||
| 
 | 
 | ||||||
|  | @ -4020,6 +4124,15 @@ | ||||||
| #define PIPEB_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6130c) | #define PIPEB_PP_OFF_DELAYS     (VLV_DISPLAY_BASE + 0x6130c) | ||||||
| #define PIPEB_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61310) | #define PIPEB_PP_DIVISOR        (VLV_DISPLAY_BASE + 0x61310) | ||||||
| 
 | 
 | ||||||
|  | #define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS) | ||||||
|  | #define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL) | ||||||
|  | #define VLV_PIPE_PP_ON_DELAYS(pipe) \ | ||||||
|  | 		_PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS) | ||||||
|  | #define VLV_PIPE_PP_OFF_DELAYS(pipe) \ | ||||||
|  | 		_PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS) | ||||||
|  | #define VLV_PIPE_PP_DIVISOR(pipe) \ | ||||||
|  | 		_PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR) | ||||||
|  | 
 | ||||||
| #define PCH_PP_STATUS		0xc7200 | #define PCH_PP_STATUS		0xc7200 | ||||||
| #define PCH_PP_CONTROL		0xc7204 | #define PCH_PP_CONTROL		0xc7204 | ||||||
| #define  PANEL_UNLOCK_REGS	(0xabcd << 16) | #define  PANEL_UNLOCK_REGS	(0xabcd << 16) | ||||||
|  | @ -4149,8 +4262,12 @@ | ||||||
| #define  FORCEWAKE				0xA18C | #define  FORCEWAKE				0xA18C | ||||||
| #define  FORCEWAKE_VLV				0x1300b0 | #define  FORCEWAKE_VLV				0x1300b0 | ||||||
| #define  FORCEWAKE_ACK_VLV			0x1300b4 | #define  FORCEWAKE_ACK_VLV			0x1300b4 | ||||||
|  | #define  FORCEWAKE_MEDIA_VLV			0x1300b8 | ||||||
|  | #define  FORCEWAKE_ACK_MEDIA_VLV		0x1300bc | ||||||
| #define  FORCEWAKE_ACK_HSW			0x130044 | #define  FORCEWAKE_ACK_HSW			0x130044 | ||||||
| #define  FORCEWAKE_ACK				0x130090 | #define  FORCEWAKE_ACK				0x130090 | ||||||
|  | #define  VLV_GTLC_WAKE_CTRL			0x130090 | ||||||
|  | #define  VLV_GTLC_PW_STATUS			0x130094 | ||||||
| #define  FORCEWAKE_MT				0xa188 /* multi-threaded */ | #define  FORCEWAKE_MT				0xa188 /* multi-threaded */ | ||||||
| #define   FORCEWAKE_KERNEL			0x1 | #define   FORCEWAKE_KERNEL			0x1 | ||||||
| #define   FORCEWAKE_USER			0x2 | #define   FORCEWAKE_USER			0x2 | ||||||
|  | @ -4184,6 +4301,7 @@ | ||||||
| #define GEN6_RPNSWREQ				0xA008 | #define GEN6_RPNSWREQ				0xA008 | ||||||
| #define   GEN6_TURBO_DISABLE			(1<<31) | #define   GEN6_TURBO_DISABLE			(1<<31) | ||||||
| #define   GEN6_FREQUENCY(x)			((x)<<25) | #define   GEN6_FREQUENCY(x)			((x)<<25) | ||||||
|  | #define   HSW_FREQUENCY(x)			((x)<<24) | ||||||
| #define   GEN6_OFFSET(x)			((x)<<19) | #define   GEN6_OFFSET(x)			((x)<<19) | ||||||
| #define   GEN6_AGGRESSIVE_TURBO			(0<<15) | #define   GEN6_AGGRESSIVE_TURBO			(0<<15) | ||||||
| #define GEN6_RC_VIDEO_FREQ			0xA00C | #define GEN6_RC_VIDEO_FREQ			0xA00C | ||||||
|  | @ -4274,6 +4392,21 @@ | ||||||
| #define   GEN6_DECODE_RC6_VID(vids)		(((vids) * 5) + 245) | #define   GEN6_DECODE_RC6_VID(vids)		(((vids) * 5) + 245) | ||||||
| #define GEN6_PCODE_DATA				0x138128 | #define GEN6_PCODE_DATA				0x138128 | ||||||
| #define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT	8 | #define   GEN6_PCODE_FREQ_IA_RATIO_SHIFT	8 | ||||||
|  | #define   GEN6_PCODE_FREQ_RING_RATIO_SHIFT	16 | ||||||
|  | 
 | ||||||
|  | #define VLV_IOSF_DOORBELL_REQ			0x182100 | ||||||
|  | #define   IOSF_DEVFN_SHIFT			24 | ||||||
|  | #define   IOSF_OPCODE_SHIFT			16 | ||||||
|  | #define   IOSF_PORT_SHIFT			8 | ||||||
|  | #define   IOSF_BYTE_ENABLES_SHIFT		4 | ||||||
|  | #define   IOSF_BAR_SHIFT			1 | ||||||
|  | #define   IOSF_SB_BUSY				(1<<0) | ||||||
|  | #define   IOSF_PORT_PUNIT			0x4 | ||||||
|  | #define VLV_IOSF_DATA				0x182104 | ||||||
|  | #define VLV_IOSF_ADDR				0x182108 | ||||||
|  | 
 | ||||||
|  | #define PUNIT_OPCODE_REG_READ			6 | ||||||
|  | #define PUNIT_OPCODE_REG_WRITE			7 | ||||||
| 
 | 
 | ||||||
| #define GEN6_GT_CORE_STATUS		0x138060 | #define GEN6_GT_CORE_STATUS		0x138060 | ||||||
| #define   GEN6_CORE_CPD_STATE_MASK	(7<<4) | #define   GEN6_CORE_CPD_STATE_MASK	(7<<4) | ||||||
|  |  | ||||||
|  | @ -209,6 +209,7 @@ static void i915_save_display(struct drm_device *dev) | ||||||
| 		dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); | 		dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); | ||||||
| 		dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); | 		dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); | ||||||
| 		dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); | 		dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); | ||||||
|  | 		if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) | ||||||
| 			dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); | 			dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); | ||||||
| 	} else { | 	} else { | ||||||
| 		dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); | 		dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); | ||||||
|  | @ -255,6 +256,7 @@ static void i915_save_display(struct drm_device *dev) | ||||||
| static void i915_restore_display(struct drm_device *dev) | static void i915_restore_display(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	u32 mask = 0xffffffff; | ||||||
| 
 | 
 | ||||||
| 	/* Display arbitration */ | 	/* Display arbitration */ | ||||||
| 	if (INTEL_INFO(dev)->gen <= 4) | 	if (INTEL_INFO(dev)->gen <= 4) | ||||||
|  | @ -267,10 +269,13 @@ static void i915_restore_display(struct drm_device *dev) | ||||||
| 	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) | 	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) | ||||||
| 		I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); | 		I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); | ||||||
| 
 | 
 | ||||||
| 	if (HAS_PCH_SPLIT(dev)) { | 	if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||||||
| 		I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS); | 		mask = ~LVDS_PORT_EN; | ||||||
| 	} else if (IS_MOBILE(dev) && !IS_I830(dev)) | 
 | ||||||
| 		I915_WRITE(LVDS, dev_priv->regfile.saveLVDS); | 	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) | ||||||
|  | 		I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS & mask); | ||||||
|  | 	else if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) | ||||||
|  | 		I915_WRITE(LVDS, dev_priv->regfile.saveLVDS & mask); | ||||||
| 
 | 
 | ||||||
| 	if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) | 	if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) | ||||||
| 		I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); | 		I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ static ssize_t | ||||||
| show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf) | show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf) | ||||||
| { | { | ||||||
| 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev)); | 	return snprintf(buf, PAGE_SIZE, "%x\n", intel_enable_rc6(dminor->dev)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static ssize_t | ||||||
|  | @ -57,7 +57,7 @@ show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf) | ||||||
| { | { | ||||||
| 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | ||||||
| 	u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); | 	u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%u", rc6_residency); | 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static ssize_t | ||||||
|  | @ -65,7 +65,7 @@ show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf) | ||||||
| { | { | ||||||
| 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | ||||||
| 	u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); | 	u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); | 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t | static ssize_t | ||||||
|  | @ -73,7 +73,7 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf) | ||||||
| { | { | ||||||
| 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | 	struct drm_minor *dminor = container_of(kdev, struct drm_minor, kdev); | ||||||
| 	u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); | 	u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency); | 	return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); | static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); | ||||||
|  | @ -215,7 +215,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, | ||||||
| 	ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; | 	ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%d", ret); | 	return snprintf(buf, PAGE_SIZE, "%d\n", ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) | static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf) | ||||||
|  | @ -229,7 +229,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute | ||||||
| 	ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; | 	ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%d", ret); | 	return snprintf(buf, PAGE_SIZE, "%d\n", ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t gt_max_freq_mhz_store(struct device *kdev, | static ssize_t gt_max_freq_mhz_store(struct device *kdev, | ||||||
|  | @ -239,7 +239,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, | ||||||
| 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); | 	struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); | ||||||
| 	struct drm_device *dev = minor->dev; | 	struct drm_device *dev = minor->dev; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 val, rp_state_cap, hw_max, hw_min; | 	u32 val, rp_state_cap, hw_max, hw_min, non_oc_max; | ||||||
| 	ssize_t ret; | 	ssize_t ret; | ||||||
| 
 | 
 | ||||||
| 	ret = kstrtou32(buf, 0, &val); | 	ret = kstrtou32(buf, 0, &val); | ||||||
|  | @ -251,7 +251,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, | ||||||
| 	mutex_lock(&dev_priv->rps.hw_lock); | 	mutex_lock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); | 	rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); | ||||||
| 	hw_max = (rp_state_cap & 0xff); | 	hw_max = dev_priv->rps.hw_max; | ||||||
|  | 	non_oc_max = (rp_state_cap & 0xff); | ||||||
| 	hw_min = ((rp_state_cap & 0xff0000) >> 16); | 	hw_min = ((rp_state_cap & 0xff0000) >> 16); | ||||||
| 
 | 
 | ||||||
| 	if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { | 	if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { | ||||||
|  | @ -259,6 +260,10 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (val > non_oc_max) | ||||||
|  | 		DRM_DEBUG("User requested overclocking to %d\n", | ||||||
|  | 			  val * GT_FREQUENCY_MULTIPLIER); | ||||||
|  | 
 | ||||||
| 	if (dev_priv->rps.cur_delay > val) | 	if (dev_priv->rps.cur_delay > val) | ||||||
| 		gen6_set_rps(dev_priv->dev, val); | 		gen6_set_rps(dev_priv->dev, val); | ||||||
| 
 | 
 | ||||||
|  | @ -280,7 +285,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute | ||||||
| 	ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; | 	ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; | ||||||
| 	mutex_unlock(&dev_priv->rps.hw_lock); | 	mutex_unlock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%d", ret); | 	return snprintf(buf, PAGE_SIZE, "%d\n", ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t gt_min_freq_mhz_store(struct device *kdev, | static ssize_t gt_min_freq_mhz_store(struct device *kdev, | ||||||
|  | @ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, | ||||||
| 	mutex_lock(&dev_priv->rps.hw_lock); | 	mutex_lock(&dev_priv->rps.hw_lock); | ||||||
| 
 | 
 | ||||||
| 	rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); | 	rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); | ||||||
| 	hw_max = (rp_state_cap & 0xff); | 	hw_max = dev_priv->rps.hw_max; | ||||||
| 	hw_min = ((rp_state_cap & 0xff0000) >> 16); | 	hw_min = ((rp_state_cap & 0xff0000) >> 16); | ||||||
| 
 | 
 | ||||||
| 	if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { | 	if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { | ||||||
|  | @ -355,7 +360,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr | ||||||
| 	} else { | 	} else { | ||||||
| 		BUG(); | 		BUG(); | ||||||
| 	} | 	} | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%d", val); | 	return snprintf(buf, PAGE_SIZE, "%d\n", val); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct attribute *gen6_attrs[] = { | static const struct attribute *gen6_attrs[] = { | ||||||
|  |  | ||||||
|  | @ -351,12 +351,14 @@ parse_general_features(struct drm_i915_private *dev_priv, | ||||||
| 		dev_priv->lvds_ssc_freq = | 		dev_priv->lvds_ssc_freq = | ||||||
| 			intel_bios_ssc_frequency(dev, general->ssc_freq); | 			intel_bios_ssc_frequency(dev, general->ssc_freq); | ||||||
| 		dev_priv->display_clock_mode = general->display_clock_mode; | 		dev_priv->display_clock_mode = general->display_clock_mode; | ||||||
| 		DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n", | 		dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; | ||||||
|  | 		DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", | ||||||
| 			      dev_priv->int_tv_support, | 			      dev_priv->int_tv_support, | ||||||
| 			      dev_priv->int_crt_support, | 			      dev_priv->int_crt_support, | ||||||
| 			      dev_priv->lvds_use_ssc, | 			      dev_priv->lvds_use_ssc, | ||||||
| 			      dev_priv->lvds_ssc_freq, | 			      dev_priv->lvds_ssc_freq, | ||||||
| 			      dev_priv->display_clock_mode); | 			      dev_priv->display_clock_mode, | ||||||
|  | 			      dev_priv->fdi_rx_polarity_inverted); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -692,6 +694,9 @@ intel_parse_bios(struct drm_device *dev) | ||||||
| 	struct bdb_header *bdb = NULL; | 	struct bdb_header *bdb = NULL; | ||||||
| 	u8 __iomem *bios = NULL; | 	u8 __iomem *bios = NULL; | ||||||
| 
 | 
 | ||||||
|  | 	if (HAS_PCH_NOP(dev)) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
| 	init_vbt_defaults(dev_priv); | 	init_vbt_defaults(dev_priv); | ||||||
| 
 | 
 | ||||||
| 	/* XXX Should this validation be moved to intel_opregion.c? */ | 	/* XXX Should this validation be moved to intel_opregion.c? */ | ||||||
|  |  | ||||||
|  | @ -127,7 +127,9 @@ struct bdb_general_features { | ||||||
|         /* bits 3 */ |         /* bits 3 */ | ||||||
| 	u8 disable_smooth_vision:1; | 	u8 disable_smooth_vision:1; | ||||||
| 	u8 single_dvi:1; | 	u8 single_dvi:1; | ||||||
| 	u8 rsvd9:6; /* finish byte */ | 	u8 rsvd9:1; | ||||||
|  | 	u8 fdi_rx_polarity_inverted:1; | ||||||
|  | 	u8 rsvd10:4; /* finish byte */ | ||||||
| 
 | 
 | ||||||
|         /* bits 4 */ |         /* bits 4 */ | ||||||
| 	u8 legacy_monitor_detect; | 	u8 legacy_monitor_detect; | ||||||
|  |  | ||||||
|  | @ -199,10 +199,14 @@ static int intel_crt_mode_valid(struct drm_connector *connector, | ||||||
| 	return MODE_OK; | 	return MODE_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool intel_crt_mode_fixup(struct drm_encoder *encoder, | static bool intel_crt_compute_config(struct intel_encoder *encoder, | ||||||
| 				 const struct drm_display_mode *mode, | 				     struct intel_crtc_config *pipe_config) | ||||||
| 				 struct drm_display_mode *adjusted_mode) |  | ||||||
| { | { | ||||||
|  | 	struct drm_device *dev = encoder->base.dev; | ||||||
|  | 
 | ||||||
|  | 	if (HAS_PCH_SPLIT(dev)) | ||||||
|  | 		pipe_config->has_pch_encoder = true; | ||||||
|  | 
 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -676,7 +680,6 @@ static void intel_crt_reset(struct drm_connector *connector) | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static const struct drm_encoder_helper_funcs crt_encoder_funcs = { | static const struct drm_encoder_helper_funcs crt_encoder_funcs = { | ||||||
| 	.mode_fixup = intel_crt_mode_fixup, |  | ||||||
| 	.mode_set = intel_crt_mode_set, | 	.mode_set = intel_crt_mode_set, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -768,8 +771,11 @@ void intel_crt_init(struct drm_device *dev) | ||||||
| 	else | 	else | ||||||
| 		crt->adpa_reg = ADPA; | 		crt->adpa_reg = ADPA; | ||||||
| 
 | 
 | ||||||
|  | 	crt->base.compute_config = intel_crt_compute_config; | ||||||
| 	crt->base.disable = intel_disable_crt; | 	crt->base.disable = intel_disable_crt; | ||||||
| 	crt->base.enable = intel_enable_crt; | 	crt->base.enable = intel_enable_crt; | ||||||
|  | 	if (I915_HAS_HOTPLUG(dev)) | ||||||
|  | 		crt->base.hpd_pin = HPD_CRT; | ||||||
| 	if (HAS_DDI(dev)) | 	if (HAS_DDI(dev)) | ||||||
| 		crt->base.get_hw_state = intel_ddi_get_hw_state; | 		crt->base.get_hw_state = intel_ddi_get_hw_state; | ||||||
| 	else | 	else | ||||||
|  | @ -781,18 +787,14 @@ void intel_crt_init(struct drm_device *dev) | ||||||
| 
 | 
 | ||||||
| 	drm_sysfs_connector_add(connector); | 	drm_sysfs_connector_add(connector); | ||||||
| 
 | 
 | ||||||
| 	if (I915_HAS_HOTPLUG(dev)) | 	if (!I915_HAS_HOTPLUG(dev)) | ||||||
| 		connector->polled = DRM_CONNECTOR_POLL_HPD; | 		intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; | ||||||
| 	else |  | ||||||
| 		connector->polled = DRM_CONNECTOR_POLL_CONNECT; |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Configure the automatic hotplug detection stuff | 	 * Configure the automatic hotplug detection stuff | ||||||
| 	 */ | 	 */ | ||||||
| 	crt->force_hotplug_required = 0; | 	crt->force_hotplug_required = 0; | ||||||
| 
 | 
 | ||||||
| 	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * TODO: find a proper way to discover whether we need to set the the | 	 * TODO: find a proper way to discover whether we need to set the the | ||||||
| 	 * polarity and link reversal bits or not, instead of relying on the | 	 * polarity and link reversal bits or not, instead of relying on the | ||||||
|  |  | ||||||
|  | @ -898,6 +898,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) | ||||||
| 			plls->spll_refcount++; | 			plls->spll_refcount++; | ||||||
| 			reg = SPLL_CTL; | 			reg = SPLL_CTL; | ||||||
| 			intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; | 			intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; | ||||||
|  | 		} else { | ||||||
|  | 			DRM_ERROR("SPLL already in use\n"); | ||||||
|  | 			return false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		WARN(I915_READ(reg) & SPLL_PLL_ENABLE, | 		WARN(I915_READ(reg) & SPLL_PLL_ENABLE, | ||||||
|  | @ -921,14 +924,14 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) | ||||||
| 	struct drm_i915_private *dev_priv = crtc->dev->dev_private; | 	struct drm_i915_private *dev_priv = crtc->dev->dev_private; | ||||||
| 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||||||
| 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); | 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); | ||||||
| 	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; | 	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; | ||||||
| 	int type = intel_encoder->type; | 	int type = intel_encoder->type; | ||||||
| 	uint32_t temp; | 	uint32_t temp; | ||||||
| 
 | 
 | ||||||
| 	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { | 	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { | ||||||
| 
 | 
 | ||||||
| 		temp = TRANS_MSA_SYNC_CLK; | 		temp = TRANS_MSA_SYNC_CLK; | ||||||
| 		switch (intel_crtc->bpp) { | 		switch (intel_crtc->config.pipe_bpp) { | ||||||
| 		case 18: | 		case 18: | ||||||
| 			temp |= TRANS_MSA_6_BPC; | 			temp |= TRANS_MSA_6_BPC; | ||||||
| 			break; | 			break; | ||||||
|  | @ -942,22 +945,20 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) | ||||||
| 			temp |= TRANS_MSA_12_BPC; | 			temp |= TRANS_MSA_12_BPC; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			temp |= TRANS_MSA_8_BPC; | 			BUG(); | ||||||
| 			WARN(1, "%d bpp unsupported by DDI function\n", |  | ||||||
| 			     intel_crtc->bpp); |  | ||||||
| 		} | 		} | ||||||
| 		I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); | 		I915_WRITE(TRANS_MSA_MISC(cpu_transcoder), temp); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) | void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) | ||||||
| { | { | ||||||
| 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||||||
| 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); | 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); | ||||||
| 	struct drm_encoder *encoder = &intel_encoder->base; | 	struct drm_encoder *encoder = &intel_encoder->base; | ||||||
| 	struct drm_i915_private *dev_priv = crtc->dev->dev_private; | 	struct drm_i915_private *dev_priv = crtc->dev->dev_private; | ||||||
| 	enum pipe pipe = intel_crtc->pipe; | 	enum pipe pipe = intel_crtc->pipe; | ||||||
| 	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; | 	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; | ||||||
| 	enum port port = intel_ddi_get_encoder_port(intel_encoder); | 	enum port port = intel_ddi_get_encoder_port(intel_encoder); | ||||||
| 	int type = intel_encoder->type; | 	int type = intel_encoder->type; | ||||||
| 	uint32_t temp; | 	uint32_t temp; | ||||||
|  | @ -966,7 +967,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) | ||||||
| 	temp = TRANS_DDI_FUNC_ENABLE; | 	temp = TRANS_DDI_FUNC_ENABLE; | ||||||
| 	temp |= TRANS_DDI_SELECT_PORT(port); | 	temp |= TRANS_DDI_SELECT_PORT(port); | ||||||
| 
 | 
 | ||||||
| 	switch (intel_crtc->bpp) { | 	switch (intel_crtc->config.pipe_bpp) { | ||||||
| 	case 18: | 	case 18: | ||||||
| 		temp |= TRANS_DDI_BPC_6; | 		temp |= TRANS_DDI_BPC_6; | ||||||
| 		break; | 		break; | ||||||
|  | @ -980,8 +981,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) | ||||||
| 		temp |= TRANS_DDI_BPC_12; | 		temp |= TRANS_DDI_BPC_12; | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		WARN(1, "%d bpp unsupported by transcoder DDI function\n", | 		BUG(); | ||||||
| 		     intel_crtc->bpp); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) | 	if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) | ||||||
|  | @ -1150,14 +1150,14 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); | 	DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, | static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, | ||||||
| 				       enum pipe pipe) | 				       enum pipe pipe) | ||||||
| { | { | ||||||
| 	uint32_t temp, ret; | 	uint32_t temp, ret; | ||||||
| 	enum port port; | 	enum port port = I915_MAX_PORTS; | ||||||
| 	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, | 	enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, | ||||||
| 								      pipe); | 								      pipe); | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -1173,10 +1173,16 @@ static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv, | ||||||
| 				port = i; | 				port = i; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (port == I915_MAX_PORTS) { | ||||||
|  | 		WARN(1, "Pipe %c enabled on an unknown port\n", | ||||||
|  | 		     pipe_name(pipe)); | ||||||
|  | 		ret = PORT_CLK_SEL_NONE; | ||||||
|  | 	} else { | ||||||
| 		ret = I915_READ(PORT_CLK_SEL(port)); | 		ret = I915_READ(PORT_CLK_SEL(port)); | ||||||
| 
 | 		DRM_DEBUG_KMS("Pipe %c connected to port %c using clock " | ||||||
| 	DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n", | 			      "0x%08x\n", pipe_name(pipe), port_name(port), | ||||||
| 		      pipe_name(pipe), port_name(port), ret); | 			      ret); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  | @ -1217,7 +1223,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) | ||||||
| 	struct drm_i915_private *dev_priv = crtc->dev->dev_private; | 	struct drm_i915_private *dev_priv = crtc->dev->dev_private; | ||||||
| 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); | 	struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); | ||||||
| 	enum port port = intel_ddi_get_encoder_port(intel_encoder); | 	enum port port = intel_ddi_get_encoder_port(intel_encoder); | ||||||
| 	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; | 	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; | ||||||
| 
 | 
 | ||||||
| 	if (cpu_transcoder != TRANSCODER_EDP) | 	if (cpu_transcoder != TRANSCODER_EDP) | ||||||
| 		I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), | 		I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), | ||||||
|  | @ -1227,7 +1233,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) | ||||||
| void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) | void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; | 	struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; | ||||||
| 	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; | 	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; | ||||||
| 
 | 
 | ||||||
| 	if (cpu_transcoder != TRANSCODER_EDP) | 	if (cpu_transcoder != TRANSCODER_EDP) | ||||||
| 		I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), | 		I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), | ||||||
|  | @ -1341,15 +1347,15 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	uint32_t tmp; | 	uint32_t tmp; | ||||||
| 
 | 
 | ||||||
|  | 	tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); | ||||||
|  | 	tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); | ||||||
|  | 	I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); | ||||||
|  | 
 | ||||||
| 	if (type == INTEL_OUTPUT_EDP) { | 	if (type == INTEL_OUTPUT_EDP) { | ||||||
| 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | ||||||
| 
 | 
 | ||||||
| 		ironlake_edp_backlight_off(intel_dp); | 		ironlake_edp_backlight_off(intel_dp); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); |  | ||||||
| 	tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); |  | ||||||
| 	I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) | int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) | ||||||
|  | @ -1467,19 +1473,17 @@ static void intel_ddi_destroy(struct drm_encoder *encoder) | ||||||
| 	intel_dp_encoder_destroy(encoder); | 	intel_dp_encoder_destroy(encoder); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool intel_ddi_mode_fixup(struct drm_encoder *encoder, | static bool intel_ddi_compute_config(struct intel_encoder *encoder, | ||||||
| 				 const struct drm_display_mode *mode, | 				     struct intel_crtc_config *pipe_config) | ||||||
| 				 struct drm_display_mode *adjusted_mode) |  | ||||||
| { | { | ||||||
| 	struct intel_encoder *intel_encoder = to_intel_encoder(encoder); | 	int type = encoder->type; | ||||||
| 	int type = intel_encoder->type; |  | ||||||
| 
 | 
 | ||||||
| 	WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n"); | 	WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); | ||||||
| 
 | 
 | ||||||
| 	if (type == INTEL_OUTPUT_HDMI) | 	if (type == INTEL_OUTPUT_HDMI) | ||||||
| 		return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode); | 		return intel_hdmi_compute_config(encoder, pipe_config); | ||||||
| 	else | 	else | ||||||
| 		return intel_dp_mode_fixup(encoder, mode, adjusted_mode); | 		return intel_dp_compute_config(encoder, pipe_config); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct drm_encoder_funcs intel_ddi_funcs = { | static const struct drm_encoder_funcs intel_ddi_funcs = { | ||||||
|  | @ -1487,7 +1491,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { | static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { | ||||||
| 	.mode_fixup = intel_ddi_mode_fixup, |  | ||||||
| 	.mode_set = intel_ddi_mode_set, | 	.mode_set = intel_ddi_mode_set, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1527,6 +1530,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) | ||||||
| 			 DRM_MODE_ENCODER_TMDS); | 			 DRM_MODE_ENCODER_TMDS); | ||||||
| 	drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); | 	drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); | ||||||
| 
 | 
 | ||||||
|  | 	intel_encoder->compute_config = intel_ddi_compute_config; | ||||||
| 	intel_encoder->enable = intel_enable_ddi; | 	intel_encoder->enable = intel_enable_ddi; | ||||||
| 	intel_encoder->pre_enable = intel_ddi_pre_enable; | 	intel_encoder->pre_enable = intel_ddi_pre_enable; | ||||||
| 	intel_encoder->disable = intel_disable_ddi; | 	intel_encoder->disable = intel_disable_ddi; | ||||||
|  | @ -1537,9 +1541,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) | ||||||
| 	intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & | 	intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & | ||||||
| 					DDI_BUF_PORT_REVERSAL; | 					DDI_BUF_PORT_REVERSAL; | ||||||
| 	if (hdmi_connector) | 	if (hdmi_connector) | ||||||
| 		intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); | 		intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); | ||||||
| 	else |  | ||||||
| 		intel_dig_port->hdmi.sdvox_reg = 0; |  | ||||||
| 	intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); | 	intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); | ||||||
| 
 | 
 | ||||||
| 	intel_encoder->type = INTEL_OUTPUT_UNKNOWN; | 	intel_encoder->type = INTEL_OUTPUT_UNKNOWN; | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -109,29 +109,6 @@ bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) | ||||||
| 
 | 
 | ||||||
| static void intel_dp_link_down(struct intel_dp *intel_dp); | static void intel_dp_link_down(struct intel_dp *intel_dp); | ||||||
| 
 | 
 | ||||||
| void |  | ||||||
| intel_edp_link_config(struct intel_encoder *intel_encoder, |  | ||||||
| 		       int *lane_num, int *link_bw) |  | ||||||
| { |  | ||||||
| 	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); |  | ||||||
| 
 |  | ||||||
| 	*lane_num = intel_dp->lane_count; |  | ||||||
| 	*link_bw = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int |  | ||||||
| intel_edp_target_clock(struct intel_encoder *intel_encoder, |  | ||||||
| 		       struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); |  | ||||||
| 	struct intel_connector *intel_connector = intel_dp->attached_connector; |  | ||||||
| 
 |  | ||||||
| 	if (intel_connector->panel.fixed_mode) |  | ||||||
| 		return intel_connector->panel.fixed_mode->clock; |  | ||||||
| 	else |  | ||||||
| 		return mode->clock; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int | static int | ||||||
| intel_dp_max_link_bw(struct intel_dp *intel_dp) | intel_dp_max_link_bw(struct intel_dp *intel_dp) | ||||||
| { | { | ||||||
|  | @ -177,34 +154,6 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes) | ||||||
| 	return (max_link_clock * max_lanes * 8) / 10; | 	return (max_link_clock * max_lanes * 8) / 10; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool |  | ||||||
| intel_dp_adjust_dithering(struct intel_dp *intel_dp, |  | ||||||
| 			  struct drm_display_mode *mode, |  | ||||||
| 			  bool adjust_mode) |  | ||||||
| { |  | ||||||
| 	int max_link_clock = |  | ||||||
| 		drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); |  | ||||||
| 	int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); |  | ||||||
| 	int max_rate, mode_rate; |  | ||||||
| 
 |  | ||||||
| 	mode_rate = intel_dp_link_required(mode->clock, 24); |  | ||||||
| 	max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); |  | ||||||
| 
 |  | ||||||
| 	if (mode_rate > max_rate) { |  | ||||||
| 		mode_rate = intel_dp_link_required(mode->clock, 18); |  | ||||||
| 		if (mode_rate > max_rate) |  | ||||||
| 			return false; |  | ||||||
| 
 |  | ||||||
| 		if (adjust_mode) |  | ||||||
| 			mode->private_flags |  | ||||||
| 				|= INTEL_MODE_DP_FORCE_6BPC; |  | ||||||
| 
 |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int | static int | ||||||
| intel_dp_mode_valid(struct drm_connector *connector, | intel_dp_mode_valid(struct drm_connector *connector, | ||||||
| 		    struct drm_display_mode *mode) | 		    struct drm_display_mode *mode) | ||||||
|  | @ -212,6 +161,8 @@ intel_dp_mode_valid(struct drm_connector *connector, | ||||||
| 	struct intel_dp *intel_dp = intel_attached_dp(connector); | 	struct intel_dp *intel_dp = intel_attached_dp(connector); | ||||||
| 	struct intel_connector *intel_connector = to_intel_connector(connector); | 	struct intel_connector *intel_connector = to_intel_connector(connector); | ||||||
| 	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; | 	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; | ||||||
|  | 	int target_clock = mode->clock; | ||||||
|  | 	int max_rate, mode_rate, max_lanes, max_link_clock; | ||||||
| 
 | 
 | ||||||
| 	if (is_edp(intel_dp) && fixed_mode) { | 	if (is_edp(intel_dp) && fixed_mode) { | ||||||
| 		if (mode->hdisplay > fixed_mode->hdisplay) | 		if (mode->hdisplay > fixed_mode->hdisplay) | ||||||
|  | @ -219,9 +170,17 @@ intel_dp_mode_valid(struct drm_connector *connector, | ||||||
| 
 | 
 | ||||||
| 		if (mode->vdisplay > fixed_mode->vdisplay) | 		if (mode->vdisplay > fixed_mode->vdisplay) | ||||||
| 			return MODE_PANEL; | 			return MODE_PANEL; | ||||||
|  | 
 | ||||||
|  | 		target_clock = fixed_mode->clock; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!intel_dp_adjust_dithering(intel_dp, mode, false)) | 	max_link_clock = drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); | ||||||
|  | 	max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); | ||||||
|  | 
 | ||||||
|  | 	max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); | ||||||
|  | 	mode_rate = intel_dp_link_required(target_clock, 18); | ||||||
|  | 
 | ||||||
|  | 	if (mode_rate > max_rate) | ||||||
| 		return MODE_CLOCK_HIGH; | 		return MODE_CLOCK_HIGH; | ||||||
| 
 | 
 | ||||||
| 	if (mode->clock < 10000) | 	if (mode->clock < 10000) | ||||||
|  | @ -294,16 +253,20 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	u32 pp_stat_reg; | ||||||
| 
 | 
 | ||||||
| 	return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0; | 	pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; | ||||||
|  | 	return (I915_READ(pp_stat_reg) & PP_ON) != 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) | static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	u32 pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0; | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 	return (I915_READ(pp_ctrl_reg) & EDP_FORCE_VDD) != 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
|  | @ -311,14 +274,19 @@ intel_dp_check_edp(struct intel_dp *intel_dp) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	u32 pp_stat_reg, pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	if (!is_edp(intel_dp)) | 	if (!is_edp(intel_dp)) | ||||||
| 		return; | 		return; | ||||||
|  | 
 | ||||||
|  | 	pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; | ||||||
|  | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 
 | ||||||
| 	if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { | 	if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { | ||||||
| 		WARN(1, "eDP powered off while attempting aux channel communication.\n"); | 		WARN(1, "eDP powered off while attempting aux channel communication.\n"); | ||||||
| 		DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", | 		DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", | ||||||
| 			      I915_READ(PCH_PP_STATUS), | 				I915_READ(pp_stat_reg), | ||||||
| 			      I915_READ(PCH_PP_CONTROL)); | 				I915_READ(pp_ctrl_reg)); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -328,29 +296,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) | ||||||
| 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | ||||||
| 	struct drm_device *dev = intel_dig_port->base.base.dev; | 	struct drm_device *dev = intel_dig_port->base.base.dev; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	uint32_t ch_ctl = intel_dp->output_reg + 0x10; | 	uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; | ||||||
| 	uint32_t status; | 	uint32_t status; | ||||||
| 	bool done; | 	bool done; | ||||||
| 
 | 
 | ||||||
| 	if (IS_HASWELL(dev)) { |  | ||||||
| 		switch (intel_dig_port->port) { |  | ||||||
| 		case PORT_A: |  | ||||||
| 			ch_ctl = DPA_AUX_CH_CTL; |  | ||||||
| 			break; |  | ||||||
| 		case PORT_B: |  | ||||||
| 			ch_ctl = PCH_DPB_AUX_CH_CTL; |  | ||||||
| 			break; |  | ||||||
| 		case PORT_C: |  | ||||||
| 			ch_ctl = PCH_DPC_AUX_CH_CTL; |  | ||||||
| 			break; |  | ||||||
| 		case PORT_D: |  | ||||||
| 			ch_ctl = PCH_DPD_AUX_CH_CTL; |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			BUG(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) | #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) | ||||||
| 	if (has_aux_irq) | 	if (has_aux_irq) | ||||||
| 		done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, | 		done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, | ||||||
|  | @ -370,11 +319,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, | ||||||
| 		uint8_t *send, int send_bytes, | 		uint8_t *send, int send_bytes, | ||||||
| 		uint8_t *recv, int recv_size) | 		uint8_t *recv, int recv_size) | ||||||
| { | { | ||||||
| 	uint32_t output_reg = intel_dp->output_reg; |  | ||||||
| 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | ||||||
| 	struct drm_device *dev = intel_dig_port->base.base.dev; | 	struct drm_device *dev = intel_dig_port->base.base.dev; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	uint32_t ch_ctl = output_reg + 0x10; | 	uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; | ||||||
| 	uint32_t ch_data = ch_ctl + 4; | 	uint32_t ch_data = ch_ctl + 4; | ||||||
| 	int i, ret, recv_bytes; | 	int i, ret, recv_bytes; | ||||||
| 	uint32_t status; | 	uint32_t status; | ||||||
|  | @ -388,29 +336,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, | ||||||
| 	 */ | 	 */ | ||||||
| 	pm_qos_update_request(&dev_priv->pm_qos, 0); | 	pm_qos_update_request(&dev_priv->pm_qos, 0); | ||||||
| 
 | 
 | ||||||
| 	if (IS_HASWELL(dev)) { |  | ||||||
| 		switch (intel_dig_port->port) { |  | ||||||
| 		case PORT_A: |  | ||||||
| 			ch_ctl = DPA_AUX_CH_CTL; |  | ||||||
| 			ch_data = DPA_AUX_CH_DATA1; |  | ||||||
| 			break; |  | ||||||
| 		case PORT_B: |  | ||||||
| 			ch_ctl = PCH_DPB_AUX_CH_CTL; |  | ||||||
| 			ch_data = PCH_DPB_AUX_CH_DATA1; |  | ||||||
| 			break; |  | ||||||
| 		case PORT_C: |  | ||||||
| 			ch_ctl = PCH_DPC_AUX_CH_CTL; |  | ||||||
| 			ch_data = PCH_DPC_AUX_CH_DATA1; |  | ||||||
| 			break; |  | ||||||
| 		case PORT_D: |  | ||||||
| 			ch_ctl = PCH_DPD_AUX_CH_CTL; |  | ||||||
| 			ch_data = PCH_DPD_AUX_CH_DATA1; |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			BUG(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	intel_dp_check_edp(intel_dp); | 	intel_dp_check_edp(intel_dp); | ||||||
| 	/* The clock divider is based off the hrawclk,
 | 	/* The clock divider is based off the hrawclk,
 | ||||||
| 	 * and would like to run at 2MHz. So, take the | 	 * and would like to run at 2MHz. So, take the | ||||||
|  | @ -428,10 +353,14 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, | ||||||
| 			aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ | 			aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ | ||||||
| 		else | 		else | ||||||
| 			aux_clock_divider = 225; /* eDP input clock at 450Mhz */ | 			aux_clock_divider = 225; /* eDP input clock at 450Mhz */ | ||||||
| 	} else if (HAS_PCH_SPLIT(dev)) | 	} else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { | ||||||
|  | 		/* Workaround for non-ULT HSW */ | ||||||
|  | 		aux_clock_divider = 74; | ||||||
|  | 	} else if (HAS_PCH_SPLIT(dev)) { | ||||||
| 		aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2); | 		aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2); | ||||||
| 	else | 	} else { | ||||||
| 		aux_clock_divider = intel_hrawclk(dev) / 2; | 		aux_clock_divider = intel_hrawclk(dev) / 2; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (IS_GEN6(dev)) | 	if (IS_GEN6(dev)) | ||||||
| 		precharge = 3; | 		precharge = 3; | ||||||
|  | @ -732,18 +661,26 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool | bool | ||||||
| intel_dp_mode_fixup(struct drm_encoder *encoder, | intel_dp_compute_config(struct intel_encoder *encoder, | ||||||
| 		    const struct drm_display_mode *mode, | 			struct intel_crtc_config *pipe_config) | ||||||
| 		    struct drm_display_mode *adjusted_mode) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = encoder->dev; | 	struct drm_device *dev = encoder->base.dev; | ||||||
| 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | ||||||
|  | 	struct drm_display_mode *mode = &pipe_config->requested_mode; | ||||||
|  | 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | ||||||
| 	struct intel_connector *intel_connector = intel_dp->attached_connector; | 	struct intel_connector *intel_connector = intel_dp->attached_connector; | ||||||
| 	int lane_count, clock; | 	int lane_count, clock; | ||||||
| 	int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); | 	int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); | ||||||
| 	int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; | 	int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; | ||||||
| 	int bpp, mode_rate; | 	int bpp, mode_rate; | ||||||
| 	static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; | 	static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; | ||||||
|  | 	int target_clock, link_avail, link_clock; | ||||||
|  | 
 | ||||||
|  | 	if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp)) | ||||||
|  | 		pipe_config->has_pch_encoder = true; | ||||||
|  | 
 | ||||||
|  | 	pipe_config->has_dp_encoder = true; | ||||||
| 
 | 
 | ||||||
| 	if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { | 	if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { | ||||||
| 		intel_fixed_panel_mode(intel_connector->panel.fixed_mode, | 		intel_fixed_panel_mode(intel_connector->panel.fixed_mode, | ||||||
|  | @ -752,6 +689,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, | ||||||
| 					intel_connector->panel.fitting_mode, | 					intel_connector->panel.fitting_mode, | ||||||
| 					mode, adjusted_mode); | 					mode, adjusted_mode); | ||||||
| 	} | 	} | ||||||
|  | 	/* We need to take the panel's fixed mode into account. */ | ||||||
|  | 	target_clock = adjusted_mode->clock; | ||||||
| 
 | 
 | ||||||
| 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) | 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -760,11 +699,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, | ||||||
| 		      "max bw %02x pixel clock %iKHz\n", | 		      "max bw %02x pixel clock %iKHz\n", | ||||||
| 		      max_lane_count, bws[max_clock], adjusted_mode->clock); | 		      max_lane_count, bws[max_clock], adjusted_mode->clock); | ||||||
| 
 | 
 | ||||||
| 	if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, true)) | 	/* Walk through all bpp values. Luckily they're all nicely spaced with 2
 | ||||||
|  | 	 * bpc in between. */ | ||||||
|  | 	bpp = min_t(int, 8*3, pipe_config->pipe_bpp); | ||||||
|  | 	for (; bpp >= 6*3; bpp -= 2*3) { | ||||||
|  | 		mode_rate = intel_dp_link_required(target_clock, bpp); | ||||||
|  | 
 | ||||||
|  | 		for (clock = 0; clock <= max_clock; clock++) { | ||||||
|  | 			for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { | ||||||
|  | 				link_clock = drm_dp_bw_code_to_link_rate(bws[clock]); | ||||||
|  | 				link_avail = intel_dp_max_data_rate(link_clock, | ||||||
|  | 								    lane_count); | ||||||
|  | 
 | ||||||
|  | 				if (mode_rate <= link_avail) { | ||||||
|  | 					goto found; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return false; | 	return false; | ||||||
| 
 | 
 | ||||||
| 	bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; | found: | ||||||
| 
 |  | ||||||
| 	if (intel_dp->color_range_auto) { | 	if (intel_dp->color_range_auto) { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * See: | 		 * See: | ||||||
|  | @ -778,104 +734,38 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (intel_dp->color_range) | 	if (intel_dp->color_range) | ||||||
| 		adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; | 		pipe_config->limited_color_range = true; | ||||||
| 
 | 
 | ||||||
| 	mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); |  | ||||||
| 
 |  | ||||||
| 	for (clock = 0; clock <= max_clock; clock++) { |  | ||||||
| 		for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { |  | ||||||
| 			int link_bw_clock = |  | ||||||
| 				drm_dp_bw_code_to_link_rate(bws[clock]); |  | ||||||
| 			int link_avail = intel_dp_max_data_rate(link_bw_clock, |  | ||||||
| 								lane_count); |  | ||||||
| 
 |  | ||||||
| 			if (mode_rate <= link_avail) { |  | ||||||
| 	intel_dp->link_bw = bws[clock]; | 	intel_dp->link_bw = bws[clock]; | ||||||
| 	intel_dp->lane_count = lane_count; | 	intel_dp->lane_count = lane_count; | ||||||
| 				adjusted_mode->clock = link_bw_clock; | 	adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); | ||||||
| 				DRM_DEBUG_KMS("DP link bw %02x lane " | 	pipe_config->pixel_target_clock = target_clock; | ||||||
| 						"count %d clock %d bpp %d\n", | 
 | ||||||
|  | 	DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n", | ||||||
| 		      intel_dp->link_bw, intel_dp->lane_count, | 		      intel_dp->link_bw, intel_dp->lane_count, | ||||||
| 		      adjusted_mode->clock, bpp); | 		      adjusted_mode->clock, bpp); | ||||||
| 	DRM_DEBUG_KMS("DP link bw required %i available %i\n", | 	DRM_DEBUG_KMS("DP link bw required %i available %i\n", | ||||||
| 		      mode_rate, link_avail); | 		      mode_rate, link_avail); | ||||||
|  | 
 | ||||||
|  | 	intel_link_compute_m_n(bpp, lane_count, | ||||||
|  | 			       target_clock, adjusted_mode->clock, | ||||||
|  | 			       &pipe_config->dp_m_n); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * XXX: We have a strange regression where using the vbt edp bpp value | ||||||
|  | 	 * for the link bw computation results in black screens, the panel only | ||||||
|  | 	 * works when we do the computation at the usual 24bpp (but still | ||||||
|  | 	 * requires us to use 18bpp). Until that's fully debugged, stay | ||||||
|  | 	 * bug-for-bug compatible with the old code. | ||||||
|  | 	 */ | ||||||
|  | 	if (is_edp(intel_dp) && dev_priv->edp.bpp) { | ||||||
|  | 		DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", | ||||||
|  | 			      bpp, dev_priv->edp.bpp); | ||||||
|  | 		bpp = min_t(int, bpp, dev_priv->edp.bpp); | ||||||
|  | 	} | ||||||
|  | 	pipe_config->pipe_bpp = bpp; | ||||||
|  | 
 | ||||||
| 	return true; | 	return true; | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void |  | ||||||
| intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, |  | ||||||
| 		 struct drm_display_mode *adjusted_mode) |  | ||||||
| { |  | ||||||
| 	struct drm_device *dev = crtc->dev; |  | ||||||
| 	struct intel_encoder *intel_encoder; |  | ||||||
| 	struct intel_dp *intel_dp; |  | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; |  | ||||||
| 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |  | ||||||
| 	int lane_count = 4; |  | ||||||
| 	struct intel_link_m_n m_n; |  | ||||||
| 	int pipe = intel_crtc->pipe; |  | ||||||
| 	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; |  | ||||||
| 	int target_clock; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * Find the lane count in the intel_encoder private |  | ||||||
| 	 */ |  | ||||||
| 	for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |  | ||||||
| 		intel_dp = enc_to_intel_dp(&intel_encoder->base); |  | ||||||
| 
 |  | ||||||
| 		if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || |  | ||||||
| 		    intel_encoder->type == INTEL_OUTPUT_EDP) |  | ||||||
| 		{ |  | ||||||
| 			lane_count = intel_dp->lane_count; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	target_clock = mode->clock; |  | ||||||
| 	for_each_encoder_on_crtc(dev, crtc, intel_encoder) { |  | ||||||
| 		if (intel_encoder->type == INTEL_OUTPUT_EDP) { |  | ||||||
| 			target_clock = intel_edp_target_clock(intel_encoder, |  | ||||||
| 							      mode); |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * Compute the GMCH and Link ratios. The '3' here is |  | ||||||
| 	 * the number of bytes_per_pixel post-LUT, which we always |  | ||||||
| 	 * set up for 8-bits of R/G/B, or 3 bytes total. |  | ||||||
| 	 */ |  | ||||||
| 	intel_link_compute_m_n(intel_crtc->bpp, lane_count, |  | ||||||
| 			       target_clock, adjusted_mode->clock, &m_n); |  | ||||||
| 
 |  | ||||||
| 	if (IS_HASWELL(dev)) { |  | ||||||
| 		I915_WRITE(PIPE_DATA_M1(cpu_transcoder), |  | ||||||
| 			   TU_SIZE(m_n.tu) | m_n.gmch_m); |  | ||||||
| 		I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); |  | ||||||
| 		I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m); |  | ||||||
| 		I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n); |  | ||||||
| 	} else if (HAS_PCH_SPLIT(dev)) { |  | ||||||
| 		I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); |  | ||||||
| 		I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n); |  | ||||||
| 		I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m); |  | ||||||
| 		I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n); |  | ||||||
| 	} else if (IS_VALLEYVIEW(dev)) { |  | ||||||
| 		I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m); |  | ||||||
| 		I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n); |  | ||||||
| 		I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); |  | ||||||
| 		I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); |  | ||||||
| 	} else { |  | ||||||
| 		I915_WRITE(PIPE_GMCH_DATA_M(pipe), |  | ||||||
| 			   TU_SIZE(m_n.tu) | m_n.gmch_m); |  | ||||||
| 		I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n); |  | ||||||
| 		I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m); |  | ||||||
| 		I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void intel_dp_init_link_config(struct intel_dp *intel_dp) | void intel_dp_init_link_config(struct intel_dp *intel_dp) | ||||||
|  | @ -994,7 +884,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||||||
| 		else | 		else | ||||||
| 			intel_dp->DP |= DP_PLL_FREQ_270MHZ; | 			intel_dp->DP |= DP_PLL_FREQ_270MHZ; | ||||||
| 	} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { | 	} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { | ||||||
| 		if (!HAS_PCH_SPLIT(dev)) | 		if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) | ||||||
| 			intel_dp->DP |= intel_dp->color_range; | 			intel_dp->DP |= intel_dp->color_range; | ||||||
| 
 | 
 | ||||||
| 		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | 		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||||||
|  | @ -1009,7 +899,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||||||
| 		if (intel_crtc->pipe == 1) | 		if (intel_crtc->pipe == 1) | ||||||
| 			intel_dp->DP |= DP_PIPEB_SELECT; | 			intel_dp->DP |= DP_PIPEB_SELECT; | ||||||
| 
 | 
 | ||||||
| 		if (is_cpu_edp(intel_dp)) { | 		if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { | ||||||
| 			/* don't miss out required setting for eDP */ | 			/* don't miss out required setting for eDP */ | ||||||
| 			if (adjusted_mode->clock < 200000) | 			if (adjusted_mode->clock < 200000) | ||||||
| 				intel_dp->DP |= DP_PLL_FREQ_160MHZ; | 				intel_dp->DP |= DP_PLL_FREQ_160MHZ; | ||||||
|  | @ -1020,7 +910,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||||||
| 		intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; | 		intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (is_cpu_edp(intel_dp)) | 	if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) | ||||||
| 		ironlake_set_pll_edp(crtc, adjusted_mode->clock); | 		ironlake_set_pll_edp(crtc, adjusted_mode->clock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1039,16 +929,20 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, | ||||||
| { | { | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	u32 pp_stat_reg, pp_ctrl_reg; | ||||||
|  | 
 | ||||||
|  | 	pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; | ||||||
|  | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n", | 	DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n", | ||||||
| 			mask, value, | 			mask, value, | ||||||
| 		      I915_READ(PCH_PP_STATUS), | 			I915_READ(pp_stat_reg), | ||||||
| 		      I915_READ(PCH_PP_CONTROL)); | 			I915_READ(pp_ctrl_reg)); | ||||||
| 
 | 
 | ||||||
| 	if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) { | 	if (_wait_for((I915_READ(pp_stat_reg) & mask) == value, 5000, 10)) { | ||||||
| 		DRM_ERROR("Panel status timeout: status %08x control %08x\n", | 		DRM_ERROR("Panel status timeout: status %08x control %08x\n", | ||||||
| 			  I915_READ(PCH_PP_STATUS), | 				I915_READ(pp_stat_reg), | ||||||
| 			  I915_READ(PCH_PP_CONTROL)); | 				I915_READ(pp_ctrl_reg)); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1075,9 +969,15 @@ static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp) | ||||||
|  * is locked |  * is locked | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| static  u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv) | static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp) | ||||||
| { | { | ||||||
| 	u32	control = I915_READ(PCH_PP_CONTROL); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
|  | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	u32 control; | ||||||
|  | 	u32 pp_ctrl_reg; | ||||||
|  | 
 | ||||||
|  | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 	control = I915_READ(pp_ctrl_reg); | ||||||
| 
 | 
 | ||||||
| 	control &= ~PANEL_UNLOCK_MASK; | 	control &= ~PANEL_UNLOCK_MASK; | ||||||
| 	control |= PANEL_UNLOCK_REGS; | 	control |= PANEL_UNLOCK_REGS; | ||||||
|  | @ -1089,6 +989,7 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 pp; | 	u32 pp; | ||||||
|  | 	u32 pp_stat_reg, pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	if (!is_edp(intel_dp)) | 	if (!is_edp(intel_dp)) | ||||||
| 		return; | 		return; | ||||||
|  | @ -1107,13 +1008,16 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) | ||||||
| 	if (!ironlake_edp_have_panel_power(intel_dp)) | 	if (!ironlake_edp_have_panel_power(intel_dp)) | ||||||
| 		ironlake_wait_panel_power_cycle(intel_dp); | 		ironlake_wait_panel_power_cycle(intel_dp); | ||||||
| 
 | 
 | ||||||
| 	pp = ironlake_get_pp_control(dev_priv); | 	pp = ironlake_get_pp_control(intel_dp); | ||||||
| 	pp |= EDP_FORCE_VDD; | 	pp |= EDP_FORCE_VDD; | ||||||
| 	I915_WRITE(PCH_PP_CONTROL, pp); |  | ||||||
| 	POSTING_READ(PCH_PP_CONTROL); |  | ||||||
| 	DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", |  | ||||||
| 		      I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); |  | ||||||
| 
 | 
 | ||||||
|  | 	pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; | ||||||
|  | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 
 | ||||||
|  | 	I915_WRITE(pp_ctrl_reg, pp); | ||||||
|  | 	POSTING_READ(pp_ctrl_reg); | ||||||
|  | 	DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", | ||||||
|  | 			I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * If the panel wasn't on, delay before accessing aux channel | 	 * If the panel wasn't on, delay before accessing aux channel | ||||||
| 	 */ | 	 */ | ||||||
|  | @ -1128,19 +1032,23 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 pp; | 	u32 pp; | ||||||
|  | 	u32 pp_stat_reg, pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||||||
| 
 | 
 | ||||||
| 	if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { | 	if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { | ||||||
| 		pp = ironlake_get_pp_control(dev_priv); | 		pp = ironlake_get_pp_control(intel_dp); | ||||||
| 		pp &= ~EDP_FORCE_VDD; | 		pp &= ~EDP_FORCE_VDD; | ||||||
| 		I915_WRITE(PCH_PP_CONTROL, pp); | 
 | ||||||
| 		POSTING_READ(PCH_PP_CONTROL); | 		pp_stat_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_STATUS : PCH_PP_STATUS; | ||||||
|  | 		pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 
 | ||||||
|  | 		I915_WRITE(pp_ctrl_reg, pp); | ||||||
|  | 		POSTING_READ(pp_ctrl_reg); | ||||||
| 
 | 
 | ||||||
| 		/* Make sure sequencer is idle before allowing subsequent activity */ | 		/* Make sure sequencer is idle before allowing subsequent activity */ | ||||||
| 		DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", | 		DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", | ||||||
| 			      I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); | 		I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); | ||||||
| 
 |  | ||||||
| 		msleep(intel_dp->panel_power_down_delay); | 		msleep(intel_dp->panel_power_down_delay); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -1184,6 +1092,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 pp; | 	u32 pp; | ||||||
|  | 	u32 pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	if (!is_edp(intel_dp)) | 	if (!is_edp(intel_dp)) | ||||||
| 		return; | 		return; | ||||||
|  | @ -1197,7 +1106,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) | ||||||
| 
 | 
 | ||||||
| 	ironlake_wait_panel_power_cycle(intel_dp); | 	ironlake_wait_panel_power_cycle(intel_dp); | ||||||
| 
 | 
 | ||||||
| 	pp = ironlake_get_pp_control(dev_priv); | 	pp = ironlake_get_pp_control(intel_dp); | ||||||
| 	if (IS_GEN5(dev)) { | 	if (IS_GEN5(dev)) { | ||||||
| 		/* ILK workaround: disable reset around power sequence */ | 		/* ILK workaround: disable reset around power sequence */ | ||||||
| 		pp &= ~PANEL_POWER_RESET; | 		pp &= ~PANEL_POWER_RESET; | ||||||
|  | @ -1209,8 +1118,10 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp) | ||||||
| 	if (!IS_GEN5(dev)) | 	if (!IS_GEN5(dev)) | ||||||
| 		pp |= PANEL_POWER_RESET; | 		pp |= PANEL_POWER_RESET; | ||||||
| 
 | 
 | ||||||
| 	I915_WRITE(PCH_PP_CONTROL, pp); | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
| 	POSTING_READ(PCH_PP_CONTROL); | 
 | ||||||
|  | 	I915_WRITE(pp_ctrl_reg, pp); | ||||||
|  | 	POSTING_READ(pp_ctrl_reg); | ||||||
| 
 | 
 | ||||||
| 	ironlake_wait_panel_on(intel_dp); | 	ironlake_wait_panel_on(intel_dp); | ||||||
| 
 | 
 | ||||||
|  | @ -1226,6 +1137,7 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 pp; | 	u32 pp; | ||||||
|  | 	u32 pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	if (!is_edp(intel_dp)) | 	if (!is_edp(intel_dp)) | ||||||
| 		return; | 		return; | ||||||
|  | @ -1234,12 +1146,15 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) | ||||||
| 
 | 
 | ||||||
| 	WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); | 	WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); | ||||||
| 
 | 
 | ||||||
| 	pp = ironlake_get_pp_control(dev_priv); | 	pp = ironlake_get_pp_control(intel_dp); | ||||||
| 	/* We need to switch off panel power _and_ force vdd, for otherwise some
 | 	/* We need to switch off panel power _and_ force vdd, for otherwise some
 | ||||||
| 	 * panels get very unhappy and cease to work. */ | 	 * panels get very unhappy and cease to work. */ | ||||||
| 	pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); | 	pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); | ||||||
| 	I915_WRITE(PCH_PP_CONTROL, pp); | 
 | ||||||
| 	POSTING_READ(PCH_PP_CONTROL); | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 
 | ||||||
|  | 	I915_WRITE(pp_ctrl_reg, pp); | ||||||
|  | 	POSTING_READ(pp_ctrl_reg); | ||||||
| 
 | 
 | ||||||
| 	intel_dp->want_panel_vdd = false; | 	intel_dp->want_panel_vdd = false; | ||||||
| 
 | 
 | ||||||
|  | @ -1253,6 +1168,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe; | 	int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe; | ||||||
| 	u32 pp; | 	u32 pp; | ||||||
|  | 	u32 pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	if (!is_edp(intel_dp)) | 	if (!is_edp(intel_dp)) | ||||||
| 		return; | 		return; | ||||||
|  | @ -1265,10 +1181,13 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp) | ||||||
| 	 * allowing it to appear. | 	 * allowing it to appear. | ||||||
| 	 */ | 	 */ | ||||||
| 	msleep(intel_dp->backlight_on_delay); | 	msleep(intel_dp->backlight_on_delay); | ||||||
| 	pp = ironlake_get_pp_control(dev_priv); | 	pp = ironlake_get_pp_control(intel_dp); | ||||||
| 	pp |= EDP_BLC_ENABLE; | 	pp |= EDP_BLC_ENABLE; | ||||||
| 	I915_WRITE(PCH_PP_CONTROL, pp); | 
 | ||||||
| 	POSTING_READ(PCH_PP_CONTROL); | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 
 | ||||||
|  | 	I915_WRITE(pp_ctrl_reg, pp); | ||||||
|  | 	POSTING_READ(pp_ctrl_reg); | ||||||
| 
 | 
 | ||||||
| 	intel_panel_enable_backlight(dev, pipe); | 	intel_panel_enable_backlight(dev, pipe); | ||||||
| } | } | ||||||
|  | @ -1278,6 +1197,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp) | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 pp; | 	u32 pp; | ||||||
|  | 	u32 pp_ctrl_reg; | ||||||
| 
 | 
 | ||||||
| 	if (!is_edp(intel_dp)) | 	if (!is_edp(intel_dp)) | ||||||
| 		return; | 		return; | ||||||
|  | @ -1285,10 +1205,13 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp) | ||||||
| 	intel_panel_disable_backlight(dev); | 	intel_panel_disable_backlight(dev); | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("\n"); | 	DRM_DEBUG_KMS("\n"); | ||||||
| 	pp = ironlake_get_pp_control(dev_priv); | 	pp = ironlake_get_pp_control(intel_dp); | ||||||
| 	pp &= ~EDP_BLC_ENABLE; | 	pp &= ~EDP_BLC_ENABLE; | ||||||
| 	I915_WRITE(PCH_PP_CONTROL, pp); | 
 | ||||||
| 	POSTING_READ(PCH_PP_CONTROL); | 	pp_ctrl_reg = IS_VALLEYVIEW(dev) ? PIPEA_PP_CONTROL : PCH_PP_CONTROL; | ||||||
|  | 
 | ||||||
|  | 	I915_WRITE(pp_ctrl_reg, pp); | ||||||
|  | 	POSTING_READ(pp_ctrl_reg); | ||||||
| 	msleep(intel_dp->backlight_off_delay); | 	msleep(intel_dp->backlight_off_delay); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1384,7 +1307,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, | ||||||
| 	if (!(tmp & DP_PORT_EN)) | 	if (!(tmp & DP_PORT_EN)) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { | 	if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { | ||||||
| 		*pipe = PORT_TO_PIPE_CPT(tmp); | 		*pipe = PORT_TO_PIPE_CPT(tmp); | ||||||
| 	} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { | 	} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { | ||||||
| 		*pipe = PORT_TO_PIPE(tmp); | 		*pipe = PORT_TO_PIPE(tmp); | ||||||
|  | @ -1441,9 +1364,11 @@ static void intel_disable_dp(struct intel_encoder *encoder) | ||||||
| static void intel_post_disable_dp(struct intel_encoder *encoder) | static void intel_post_disable_dp(struct intel_encoder *encoder) | ||||||
| { | { | ||||||
| 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | ||||||
|  | 	struct drm_device *dev = encoder->base.dev; | ||||||
| 
 | 
 | ||||||
| 	if (is_cpu_edp(intel_dp)) { | 	if (is_cpu_edp(intel_dp)) { | ||||||
| 		intel_dp_link_down(intel_dp); | 		intel_dp_link_down(intel_dp); | ||||||
|  | 		if (!IS_VALLEYVIEW(dev)) | ||||||
| 			ironlake_edp_pll_off(intel_dp); | 			ironlake_edp_pll_off(intel_dp); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -1470,8 +1395,9 @@ static void intel_enable_dp(struct intel_encoder *encoder) | ||||||
| static void intel_pre_enable_dp(struct intel_encoder *encoder) | static void intel_pre_enable_dp(struct intel_encoder *encoder) | ||||||
| { | { | ||||||
| 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); | ||||||
|  | 	struct drm_device *dev = encoder->base.dev; | ||||||
| 
 | 
 | ||||||
| 	if (is_cpu_edp(intel_dp)) | 	if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) | ||||||
| 		ironlake_edp_pll_on(intel_dp); | 		ironlake_edp_pll_on(intel_dp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1548,7 +1474,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | 	struct drm_device *dev = intel_dp_to_dev(intel_dp); | ||||||
| 
 | 
 | ||||||
| 	if (IS_HASWELL(dev)) { | 	if (HAS_DDI(dev)) { | ||||||
| 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { | 		switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { | ||||||
| 		case DP_TRAIN_VOLTAGE_SWING_400: | 		case DP_TRAIN_VOLTAGE_SWING_400: | ||||||
| 			return DP_TRAIN_PRE_EMPHASIS_9_5; | 			return DP_TRAIN_PRE_EMPHASIS_9_5; | ||||||
|  | @ -1756,7 +1682,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) | ||||||
| 	uint32_t signal_levels, mask; | 	uint32_t signal_levels, mask; | ||||||
| 	uint8_t train_set = intel_dp->train_set[0]; | 	uint8_t train_set = intel_dp->train_set[0]; | ||||||
| 
 | 
 | ||||||
| 	if (IS_HASWELL(dev)) { | 	if (HAS_DDI(dev)) { | ||||||
| 		signal_levels = intel_hsw_signal_levels(train_set); | 		signal_levels = intel_hsw_signal_levels(train_set); | ||||||
| 		mask = DDI_BUF_EMP_MASK; | 		mask = DDI_BUF_EMP_MASK; | ||||||
| 	} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { | 	} else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { | ||||||
|  | @ -1787,7 +1713,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, | ||||||
| 	int ret; | 	int ret; | ||||||
| 	uint32_t temp; | 	uint32_t temp; | ||||||
| 
 | 
 | ||||||
| 	if (IS_HASWELL(dev)) { | 	if (HAS_DDI(dev)) { | ||||||
| 		temp = I915_READ(DP_TP_CTL(port)); | 		temp = I915_READ(DP_TP_CTL(port)); | ||||||
| 
 | 
 | ||||||
| 		if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) | 		if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE) | ||||||
|  | @ -2311,6 +2237,16 @@ g4x_dp_detect(struct intel_dp *intel_dp) | ||||||
| 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | ||||||
| 	uint32_t bit; | 	uint32_t bit; | ||||||
| 
 | 
 | ||||||
|  | 	/* Can't disconnect eDP, but you can close the lid... */ | ||||||
|  | 	if (is_edp(intel_dp)) { | ||||||
|  | 		enum drm_connector_status status; | ||||||
|  | 
 | ||||||
|  | 		status = intel_panel_detect(dev); | ||||||
|  | 		if (status == connector_status_unknown) | ||||||
|  | 			status = connector_status_connected; | ||||||
|  | 		return status; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	switch (intel_dig_port->port) { | 	switch (intel_dig_port->port) { | ||||||
| 	case PORT_B: | 	case PORT_B: | ||||||
| 		bit = PORTB_HOTPLUG_LIVE_STATUS; | 		bit = PORTB_HOTPLUG_LIVE_STATUS; | ||||||
|  | @ -2492,6 +2428,9 @@ intel_dp_set_property(struct drm_connector *connector, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (property == dev_priv->broadcast_rgb_property) { | 	if (property == dev_priv->broadcast_rgb_property) { | ||||||
|  | 		bool old_auto = intel_dp->color_range_auto; | ||||||
|  | 		uint32_t old_range = intel_dp->color_range; | ||||||
|  | 
 | ||||||
| 		switch (val) { | 		switch (val) { | ||||||
| 		case INTEL_BROADCAST_RGB_AUTO: | 		case INTEL_BROADCAST_RGB_AUTO: | ||||||
| 			intel_dp->color_range_auto = true; | 			intel_dp->color_range_auto = true; | ||||||
|  | @ -2507,6 +2446,11 @@ intel_dp_set_property(struct drm_connector *connector, | ||||||
| 		default: | 		default: | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (old_auto == intel_dp->color_range_auto && | ||||||
|  | 		    old_range == intel_dp->color_range) | ||||||
|  | 			return 0; | ||||||
|  | 
 | ||||||
| 		goto done; | 		goto done; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2538,17 +2482,14 @@ done: | ||||||
| static void | static void | ||||||
| intel_dp_destroy(struct drm_connector *connector) | intel_dp_destroy(struct drm_connector *connector) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = connector->dev; |  | ||||||
| 	struct intel_dp *intel_dp = intel_attached_dp(connector); | 	struct intel_dp *intel_dp = intel_attached_dp(connector); | ||||||
| 	struct intel_connector *intel_connector = to_intel_connector(connector); | 	struct intel_connector *intel_connector = to_intel_connector(connector); | ||||||
| 
 | 
 | ||||||
| 	if (!IS_ERR_OR_NULL(intel_connector->edid)) | 	if (!IS_ERR_OR_NULL(intel_connector->edid)) | ||||||
| 		kfree(intel_connector->edid); | 		kfree(intel_connector->edid); | ||||||
| 
 | 
 | ||||||
| 	if (is_edp(intel_dp)) { | 	if (is_edp(intel_dp)) | ||||||
| 		intel_panel_destroy_backlight(dev); |  | ||||||
| 		intel_panel_fini(&intel_connector->panel); | 		intel_panel_fini(&intel_connector->panel); | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	drm_sysfs_connector_remove(connector); | 	drm_sysfs_connector_remove(connector); | ||||||
| 	drm_connector_cleanup(connector); | 	drm_connector_cleanup(connector); | ||||||
|  | @ -2573,7 +2514,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { | static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { | ||||||
| 	.mode_fixup = intel_dp_mode_fixup, |  | ||||||
| 	.mode_set = intel_dp_mode_set, | 	.mode_set = intel_dp_mode_set, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -2669,15 +2609,28 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct edp_power_seq cur, vbt, spec, final; | 	struct edp_power_seq cur, vbt, spec, final; | ||||||
| 	u32 pp_on, pp_off, pp_div, pp; | 	u32 pp_on, pp_off, pp_div, pp; | ||||||
|  | 	int pp_control_reg, pp_on_reg, pp_off_reg, pp_div_reg; | ||||||
|  | 
 | ||||||
|  | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
|  | 		pp_control_reg = PCH_PP_CONTROL; | ||||||
|  | 		pp_on_reg = PCH_PP_ON_DELAYS; | ||||||
|  | 		pp_off_reg = PCH_PP_OFF_DELAYS; | ||||||
|  | 		pp_div_reg = PCH_PP_DIVISOR; | ||||||
|  | 	} else { | ||||||
|  | 		pp_control_reg = PIPEA_PP_CONTROL; | ||||||
|  | 		pp_on_reg = PIPEA_PP_ON_DELAYS; | ||||||
|  | 		pp_off_reg = PIPEA_PP_OFF_DELAYS; | ||||||
|  | 		pp_div_reg = PIPEA_PP_DIVISOR; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Workaround: Need to write PP_CONTROL with the unlock key as
 | 	/* Workaround: Need to write PP_CONTROL with the unlock key as
 | ||||||
| 	 * the very first thing. */ | 	 * the very first thing. */ | ||||||
| 	pp = ironlake_get_pp_control(dev_priv); | 	pp = ironlake_get_pp_control(intel_dp); | ||||||
| 	I915_WRITE(PCH_PP_CONTROL, pp); | 	I915_WRITE(pp_control_reg, pp); | ||||||
| 
 | 
 | ||||||
| 	pp_on = I915_READ(PCH_PP_ON_DELAYS); | 	pp_on = I915_READ(pp_on_reg); | ||||||
| 	pp_off = I915_READ(PCH_PP_OFF_DELAYS); | 	pp_off = I915_READ(pp_off_reg); | ||||||
| 	pp_div = I915_READ(PCH_PP_DIVISOR); | 	pp_div = I915_READ(pp_div_reg); | ||||||
| 
 | 
 | ||||||
| 	/* Pull timing values out of registers */ | 	/* Pull timing values out of registers */ | ||||||
| 	cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> | 	cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> | ||||||
|  | @ -2752,7 +2705,22 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, | ||||||
| 					      struct edp_power_seq *seq) | 					      struct edp_power_seq *seq) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	u32 pp_on, pp_off, pp_div; | 	u32 pp_on, pp_off, pp_div, port_sel = 0; | ||||||
|  | 	int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); | ||||||
|  | 	int pp_on_reg, pp_off_reg, pp_div_reg; | ||||||
|  | 
 | ||||||
|  | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
|  | 		pp_on_reg = PCH_PP_ON_DELAYS; | ||||||
|  | 		pp_off_reg = PCH_PP_OFF_DELAYS; | ||||||
|  | 		pp_div_reg = PCH_PP_DIVISOR; | ||||||
|  | 	} else { | ||||||
|  | 		pp_on_reg = PIPEA_PP_ON_DELAYS; | ||||||
|  | 		pp_off_reg = PIPEA_PP_OFF_DELAYS; | ||||||
|  | 		pp_div_reg = PIPEA_PP_DIVISOR; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (IS_VALLEYVIEW(dev)) | ||||||
|  | 		port_sel = I915_READ(pp_on_reg) & 0xc0000000; | ||||||
| 
 | 
 | ||||||
| 	/* And finally store the new values in the power sequencer. */ | 	/* And finally store the new values in the power sequencer. */ | ||||||
| 	pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | | 	pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | | ||||||
|  | @ -2761,8 +2729,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, | ||||||
| 		 (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); | 		 (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); | ||||||
| 	/* Compute the divisor for the pp clock, simply match the Bspec
 | 	/* Compute the divisor for the pp clock, simply match the Bspec
 | ||||||
| 	 * formula. */ | 	 * formula. */ | ||||||
| 	pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1) | 	pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; | ||||||
| 			<< PP_REFERENCE_DIVIDER_SHIFT; |  | ||||||
| 	pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) | 	pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) | ||||||
| 			<< PANEL_POWER_CYCLE_DELAY_SHIFT); | 			<< PANEL_POWER_CYCLE_DELAY_SHIFT); | ||||||
| 
 | 
 | ||||||
|  | @ -2770,19 +2737,21 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, | ||||||
| 	 * power sequencer any more. */ | 	 * power sequencer any more. */ | ||||||
| 	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { | 	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { | ||||||
| 		if (is_cpu_edp(intel_dp)) | 		if (is_cpu_edp(intel_dp)) | ||||||
| 			pp_on |= PANEL_POWER_PORT_DP_A; | 			port_sel = PANEL_POWER_PORT_DP_A; | ||||||
| 		else | 		else | ||||||
| 			pp_on |= PANEL_POWER_PORT_DP_D; | 			port_sel = PANEL_POWER_PORT_DP_D; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	I915_WRITE(PCH_PP_ON_DELAYS, pp_on); | 	pp_on |= port_sel; | ||||||
| 	I915_WRITE(PCH_PP_OFF_DELAYS, pp_off); | 
 | ||||||
| 	I915_WRITE(PCH_PP_DIVISOR, pp_div); | 	I915_WRITE(pp_on_reg, pp_on); | ||||||
|  | 	I915_WRITE(pp_off_reg, pp_off); | ||||||
|  | 	I915_WRITE(pp_div_reg, pp_div); | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", | 	DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", | ||||||
| 		      I915_READ(PCH_PP_ON_DELAYS), | 		      I915_READ(pp_on_reg), | ||||||
| 		      I915_READ(PCH_PP_OFF_DELAYS), | 		      I915_READ(pp_off_reg), | ||||||
| 		      I915_READ(PCH_PP_DIVISOR)); | 		      I915_READ(pp_div_reg)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
|  | @ -2829,7 +2798,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | ||||||
| 	drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); | 	drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); | ||||||
| 	drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); | 	drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); | ||||||
| 
 | 
 | ||||||
| 	connector->polled = DRM_CONNECTOR_POLL_HPD; |  | ||||||
| 	connector->interlace_allowed = true; | 	connector->interlace_allowed = true; | ||||||
| 	connector->doublescan_allowed = 0; | 	connector->doublescan_allowed = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -2844,27 +2812,46 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | ||||||
| 	else | 	else | ||||||
| 		intel_connector->get_hw_state = intel_connector_get_hw_state; | 		intel_connector->get_hw_state = intel_connector_get_hw_state; | ||||||
| 
 | 
 | ||||||
|  | 	intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; | ||||||
|  | 	if (HAS_DDI(dev)) { | ||||||
|  | 		switch (intel_dig_port->port) { | ||||||
|  | 		case PORT_A: | ||||||
|  | 			intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; | ||||||
|  | 			break; | ||||||
|  | 		case PORT_B: | ||||||
|  | 			intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; | ||||||
|  | 			break; | ||||||
|  | 		case PORT_C: | ||||||
|  | 			intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; | ||||||
|  | 			break; | ||||||
|  | 		case PORT_D: | ||||||
|  | 			intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			BUG(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Set up the DDC bus. */ | 	/* Set up the DDC bus. */ | ||||||
| 	switch (port) { | 	switch (port) { | ||||||
| 	case PORT_A: | 	case PORT_A: | ||||||
|  | 		intel_encoder->hpd_pin = HPD_PORT_A; | ||||||
| 		name = "DPDDC-A"; | 		name = "DPDDC-A"; | ||||||
| 		break; | 		break; | ||||||
| 	case PORT_B: | 	case PORT_B: | ||||||
| 		dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; | 		intel_encoder->hpd_pin = HPD_PORT_B; | ||||||
| 		name = "DPDDC-B"; | 		name = "DPDDC-B"; | ||||||
| 		break; | 		break; | ||||||
| 	case PORT_C: | 	case PORT_C: | ||||||
| 		dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; | 		intel_encoder->hpd_pin = HPD_PORT_C; | ||||||
| 		name = "DPDDC-C"; | 		name = "DPDDC-C"; | ||||||
| 		break; | 		break; | ||||||
| 	case PORT_D: | 	case PORT_D: | ||||||
| 		dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; | 		intel_encoder->hpd_pin = HPD_PORT_D; | ||||||
| 		name = "DPDDC-D"; | 		name = "DPDDC-D"; | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		WARN(1, "Invalid port %c\n", port_name(port)); | 		BUG(); | ||||||
| 		break; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (is_edp(intel_dp)) | 	if (is_edp(intel_dp)) | ||||||
|  | @ -2974,6 +2961,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) | ||||||
| 			 DRM_MODE_ENCODER_TMDS); | 			 DRM_MODE_ENCODER_TMDS); | ||||||
| 	drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); | 	drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); | ||||||
| 
 | 
 | ||||||
|  | 	intel_encoder->compute_config = intel_dp_compute_config; | ||||||
| 	intel_encoder->enable = intel_enable_dp; | 	intel_encoder->enable = intel_enable_dp; | ||||||
| 	intel_encoder->pre_enable = intel_pre_enable_dp; | 	intel_encoder->pre_enable = intel_pre_enable_dp; | ||||||
| 	intel_encoder->disable = intel_disable_dp; | 	intel_encoder->disable = intel_disable_dp; | ||||||
|  |  | ||||||
|  | @ -33,11 +33,20 @@ | ||||||
| #include <drm/drm_fb_helper.h> | #include <drm/drm_fb_helper.h> | ||||||
| #include <drm/drm_dp_helper.h> | #include <drm/drm_dp_helper.h> | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * _wait_for - magic (register) wait macro | ||||||
|  |  * | ||||||
|  |  * Does the right thing for modeset paths when run under kdgb or similar atomic | ||||||
|  |  * contexts. Note that it's important that we check the condition again after | ||||||
|  |  * having timed out, since the timeout could be due to preemption or similar and | ||||||
|  |  * we've never had a chance to check the condition before the timeout. | ||||||
|  |  */ | ||||||
| #define _wait_for(COND, MS, W) ({ \ | #define _wait_for(COND, MS, W) ({ \ | ||||||
| 	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\ | 	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1;	\ | ||||||
| 	int ret__ = 0;							\ | 	int ret__ = 0;							\ | ||||||
| 	while (!(COND)) {						\ | 	while (!(COND)) {						\ | ||||||
| 		if (time_after(jiffies, timeout__)) {			\ | 		if (time_after(jiffies, timeout__)) {			\ | ||||||
|  | 			if (!(COND))					\ | ||||||
| 				ret__ = -ETIMEDOUT;			\ | 				ret__ = -ETIMEDOUT;			\ | ||||||
| 			break;						\ | 			break;						\ | ||||||
| 		}							\ | 		}							\ | ||||||
|  | @ -50,21 +59,10 @@ | ||||||
| 	ret__;								\ | 	ret__;								\ | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| #define wait_for_atomic_us(COND, US) ({ \ |  | ||||||
| 	unsigned long timeout__ = jiffies + usecs_to_jiffies(US);	\ |  | ||||||
| 	int ret__ = 0;							\ |  | ||||||
| 	while (!(COND)) {						\ |  | ||||||
| 		if (time_after(jiffies, timeout__)) {			\ |  | ||||||
| 			ret__ = -ETIMEDOUT;				\ |  | ||||||
| 			break;						\ |  | ||||||
| 		}							\ |  | ||||||
| 		cpu_relax();						\ |  | ||||||
| 	}								\ |  | ||||||
| 	ret__;								\ |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| #define wait_for(COND, MS) _wait_for(COND, MS, 1) | #define wait_for(COND, MS) _wait_for(COND, MS, 1) | ||||||
| #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) | #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) | ||||||
|  | #define wait_for_atomic_us(COND, US) _wait_for((COND), \ | ||||||
|  | 					       DIV_ROUND_UP((US), 1000), 0) | ||||||
| 
 | 
 | ||||||
| #define KHz(x) (1000*x) | #define KHz(x) (1000*x) | ||||||
| #define MHz(x) KHz(1000*x) | #define MHz(x) KHz(1000*x) | ||||||
|  | @ -101,34 +99,6 @@ | ||||||
| #define INTEL_DVO_CHIP_TMDS 2 | #define INTEL_DVO_CHIP_TMDS 2 | ||||||
| #define INTEL_DVO_CHIP_TVOUT 4 | #define INTEL_DVO_CHIP_TVOUT 4 | ||||||
| 
 | 
 | ||||||
| /* drm_display_mode->private_flags */ |  | ||||||
| #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) |  | ||||||
| #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) |  | ||||||
| #define INTEL_MODE_DP_FORCE_6BPC (0x10) |  | ||||||
| /* This flag must be set by the encoder's mode_fixup if it changes the crtc
 |  | ||||||
|  * timings in the mode to prevent the crtc fixup from overwriting them. |  | ||||||
|  * Currently only lvds needs that. */ |  | ||||||
| #define INTEL_MODE_CRTC_TIMINGS_SET (0x20) |  | ||||||
| /*
 |  | ||||||
|  * Set when limited 16-235 (as opposed to full 0-255) RGB color range is |  | ||||||
|  * to be used. |  | ||||||
|  */ |  | ||||||
| #define INTEL_MODE_LIMITED_COLOR_RANGE (0x40) |  | ||||||
| 
 |  | ||||||
| static inline void |  | ||||||
| intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, |  | ||||||
| 				int multiplier) |  | ||||||
| { |  | ||||||
| 	mode->clock *= multiplier; |  | ||||||
| 	mode->private_flags |= multiplier; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int |  | ||||||
| intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode) |  | ||||||
| { |  | ||||||
| 	return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct intel_framebuffer { | struct intel_framebuffer { | ||||||
| 	struct drm_framebuffer base; | 	struct drm_framebuffer base; | ||||||
| 	struct drm_i915_gem_object *obj; | 	struct drm_i915_gem_object *obj; | ||||||
|  | @ -158,9 +128,12 @@ struct intel_encoder { | ||||||
| 	bool cloneable; | 	bool cloneable; | ||||||
| 	bool connectors_active; | 	bool connectors_active; | ||||||
| 	void (*hot_plug)(struct intel_encoder *); | 	void (*hot_plug)(struct intel_encoder *); | ||||||
|  | 	bool (*compute_config)(struct intel_encoder *, | ||||||
|  | 			       struct intel_crtc_config *); | ||||||
| 	void (*pre_pll_enable)(struct intel_encoder *); | 	void (*pre_pll_enable)(struct intel_encoder *); | ||||||
| 	void (*pre_enable)(struct intel_encoder *); | 	void (*pre_enable)(struct intel_encoder *); | ||||||
| 	void (*enable)(struct intel_encoder *); | 	void (*enable)(struct intel_encoder *); | ||||||
|  | 	void (*mode_set)(struct intel_encoder *intel_encoder); | ||||||
| 	void (*disable)(struct intel_encoder *); | 	void (*disable)(struct intel_encoder *); | ||||||
| 	void (*post_disable)(struct intel_encoder *); | 	void (*post_disable)(struct intel_encoder *); | ||||||
| 	/* Read out the current hw state of this connector, returning true if
 | 	/* Read out the current hw state of this connector, returning true if
 | ||||||
|  | @ -168,6 +141,7 @@ struct intel_encoder { | ||||||
| 	 * it is connected to in the pipe parameter. */ | 	 * it is connected to in the pipe parameter. */ | ||||||
| 	bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); | 	bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); | ||||||
| 	int crtc_mask; | 	int crtc_mask; | ||||||
|  | 	enum hpd_pin hpd_pin; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct intel_panel { | struct intel_panel { | ||||||
|  | @ -197,13 +171,65 @@ struct intel_connector { | ||||||
| 
 | 
 | ||||||
| 	/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ | 	/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ | ||||||
| 	struct edid *edid; | 	struct edid *edid; | ||||||
|  | 
 | ||||||
|  | 	/* since POLL and HPD connectors may use the same HPD line keep the native
 | ||||||
|  | 	   state of connector->polled in case hotplug storm detection changes it */ | ||||||
|  | 	u8 polled; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct intel_crtc_config { | ||||||
|  | 	struct drm_display_mode requested_mode; | ||||||
|  | 	struct drm_display_mode adjusted_mode; | ||||||
|  | 	/* This flag must be set by the encoder's compute_config callback if it
 | ||||||
|  | 	 * changes the crtc timings in the mode to prevent the crtc fixup from | ||||||
|  | 	 * overwriting them.  Currently only lvds needs that. */ | ||||||
|  | 	bool timings_set; | ||||||
|  | 	/* Whether to set up the PCH/FDI. Note that we never allow sharing
 | ||||||
|  | 	 * between pch encoders and cpu encoders. */ | ||||||
|  | 	bool has_pch_encoder; | ||||||
|  | 
 | ||||||
|  | 	/* CPU Transcoder for the pipe. Currently this can only differ from the
 | ||||||
|  | 	 * pipe on Haswell (where we have a special eDP transcoder). */ | ||||||
|  | 	enum transcoder cpu_transcoder; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Use reduced/limited/broadcast rbg range, compressing from the full | ||||||
|  | 	 * range fed into the crtcs. | ||||||
|  | 	 */ | ||||||
|  | 	bool limited_color_range; | ||||||
|  | 
 | ||||||
|  | 	/* DP has a bunch of special case unfortunately, so mark the pipe
 | ||||||
|  | 	 * accordingly. */ | ||||||
|  | 	bool has_dp_encoder; | ||||||
|  | 	bool dither; | ||||||
|  | 
 | ||||||
|  | 	/* Controls for the clock computation, to override various stages. */ | ||||||
|  | 	bool clock_set; | ||||||
|  | 
 | ||||||
|  | 	/* Settings for the intel dpll used on pretty much everything but
 | ||||||
|  | 	 * haswell. */ | ||||||
|  | 	struct dpll { | ||||||
|  | 		unsigned n; | ||||||
|  | 		unsigned m1, m2; | ||||||
|  | 		unsigned p1, p2; | ||||||
|  | 	} dpll; | ||||||
|  | 
 | ||||||
|  | 	int pipe_bpp; | ||||||
|  | 	struct intel_link_m_n dp_m_n; | ||||||
|  | 	/**
 | ||||||
|  | 	 * This is currently used by DP and HDMI encoders since those can have a | ||||||
|  | 	 * target pixel clock != the port link clock (which is currently stored | ||||||
|  | 	 * in adjusted_mode->clock). | ||||||
|  | 	 */ | ||||||
|  | 	int pixel_target_clock; | ||||||
|  | 	/* Used by SDVO (and if we ever fix it, HDMI). */ | ||||||
|  | 	unsigned pixel_multiplier; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct intel_crtc { | struct intel_crtc { | ||||||
| 	struct drm_crtc base; | 	struct drm_crtc base; | ||||||
| 	enum pipe pipe; | 	enum pipe pipe; | ||||||
| 	enum plane plane; | 	enum plane plane; | ||||||
| 	enum transcoder cpu_transcoder; |  | ||||||
| 	u8 lut_r[256], lut_g[256], lut_b[256]; | 	u8 lut_r[256], lut_g[256], lut_b[256]; | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Whether the crtc and the connected output pipeline is active. Implies | 	 * Whether the crtc and the connected output pipeline is active. Implies | ||||||
|  | @ -230,7 +256,8 @@ struct intel_crtc { | ||||||
| 	int16_t cursor_x, cursor_y; | 	int16_t cursor_x, cursor_y; | ||||||
| 	int16_t cursor_width, cursor_height; | 	int16_t cursor_width, cursor_height; | ||||||
| 	bool cursor_visible; | 	bool cursor_visible; | ||||||
| 	unsigned int bpp; | 
 | ||||||
|  | 	struct intel_crtc_config config; | ||||||
| 
 | 
 | ||||||
| 	/* We can share PLLs across outputs if the timings match */ | 	/* We can share PLLs across outputs if the timings match */ | ||||||
| 	struct intel_pch_pll *pch_pll; | 	struct intel_pch_pll *pch_pll; | ||||||
|  | @ -242,11 +269,16 @@ struct intel_crtc { | ||||||
| 
 | 
 | ||||||
| struct intel_plane { | struct intel_plane { | ||||||
| 	struct drm_plane base; | 	struct drm_plane base; | ||||||
|  | 	int plane; | ||||||
| 	enum pipe pipe; | 	enum pipe pipe; | ||||||
| 	struct drm_i915_gem_object *obj; | 	struct drm_i915_gem_object *obj; | ||||||
| 	bool can_scale; | 	bool can_scale; | ||||||
| 	int max_downscale; | 	int max_downscale; | ||||||
| 	u32 lut_r[1024], lut_g[1024], lut_b[1024]; | 	u32 lut_r[1024], lut_g[1024], lut_b[1024]; | ||||||
|  | 	int crtc_x, crtc_y; | ||||||
|  | 	unsigned int crtc_w, crtc_h; | ||||||
|  | 	uint32_t src_x, src_y; | ||||||
|  | 	uint32_t src_w, src_h; | ||||||
| 	void (*update_plane)(struct drm_plane *plane, | 	void (*update_plane)(struct drm_plane *plane, | ||||||
| 			     struct drm_framebuffer *fb, | 			     struct drm_framebuffer *fb, | ||||||
| 			     struct drm_i915_gem_object *obj, | 			     struct drm_i915_gem_object *obj, | ||||||
|  | @ -347,7 +379,7 @@ struct dip_infoframe { | ||||||
| } __attribute__((packed)); | } __attribute__((packed)); | ||||||
| 
 | 
 | ||||||
| struct intel_hdmi { | struct intel_hdmi { | ||||||
| 	u32 sdvox_reg; | 	u32 hdmi_reg; | ||||||
| 	int ddc_bus; | 	int ddc_bus; | ||||||
| 	uint32_t color_range; | 	uint32_t color_range; | ||||||
| 	bool color_range_auto; | 	bool color_range_auto; | ||||||
|  | @ -366,6 +398,7 @@ struct intel_hdmi { | ||||||
| 
 | 
 | ||||||
| struct intel_dp { | struct intel_dp { | ||||||
| 	uint32_t output_reg; | 	uint32_t output_reg; | ||||||
|  | 	uint32_t aux_ch_ctl_reg; | ||||||
| 	uint32_t DP; | 	uint32_t DP; | ||||||
| 	uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE]; | 	uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE]; | ||||||
| 	bool has_audio; | 	bool has_audio; | ||||||
|  | @ -443,13 +476,12 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector) | ||||||
| 
 | 
 | ||||||
| extern void intel_crt_init(struct drm_device *dev); | extern void intel_crt_init(struct drm_device *dev); | ||||||
| extern void intel_hdmi_init(struct drm_device *dev, | extern void intel_hdmi_init(struct drm_device *dev, | ||||||
| 			    int sdvox_reg, enum port port); | 			    int hdmi_reg, enum port port); | ||||||
| extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, | extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, | ||||||
| 				      struct intel_connector *intel_connector); | 				      struct intel_connector *intel_connector); | ||||||
| extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); | extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); | ||||||
| extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, | extern bool intel_hdmi_compute_config(struct intel_encoder *encoder, | ||||||
| 				  const struct drm_display_mode *mode, | 				      struct intel_crtc_config *pipe_config); | ||||||
| 				  struct drm_display_mode *adjusted_mode); |  | ||||||
| extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); | extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); | ||||||
| extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, | extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, | ||||||
| 			    bool is_sdvob); | 			    bool is_sdvob); | ||||||
|  | @ -464,18 +496,14 @@ extern void intel_dp_init(struct drm_device *dev, int output_reg, | ||||||
| 			  enum port port); | 			  enum port port); | ||||||
| extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | ||||||
| 				    struct intel_connector *intel_connector); | 				    struct intel_connector *intel_connector); | ||||||
| void |  | ||||||
| intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, |  | ||||||
| 		 struct drm_display_mode *adjusted_mode); |  | ||||||
| extern void intel_dp_init_link_config(struct intel_dp *intel_dp); | extern void intel_dp_init_link_config(struct intel_dp *intel_dp); | ||||||
| extern void intel_dp_start_link_train(struct intel_dp *intel_dp); | extern void intel_dp_start_link_train(struct intel_dp *intel_dp); | ||||||
| extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); | extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); | ||||||
| extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); | extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); | ||||||
| extern void intel_dp_encoder_destroy(struct drm_encoder *encoder); | extern void intel_dp_encoder_destroy(struct drm_encoder *encoder); | ||||||
| extern void intel_dp_check_link_status(struct intel_dp *intel_dp); | extern void intel_dp_check_link_status(struct intel_dp *intel_dp); | ||||||
| extern bool intel_dp_mode_fixup(struct drm_encoder *encoder, | extern bool intel_dp_compute_config(struct intel_encoder *encoder, | ||||||
| 				const struct drm_display_mode *mode, | 				    struct intel_crtc_config *pipe_config); | ||||||
| 				struct drm_display_mode *adjusted_mode); |  | ||||||
| extern bool intel_dpd_is_edp(struct drm_device *dev); | extern bool intel_dpd_is_edp(struct drm_device *dev); | ||||||
| extern void ironlake_edp_backlight_on(struct intel_dp *intel_dp); | extern void ironlake_edp_backlight_on(struct intel_dp *intel_dp); | ||||||
| extern void ironlake_edp_backlight_off(struct intel_dp *intel_dp); | extern void ironlake_edp_backlight_off(struct intel_dp *intel_dp); | ||||||
|  | @ -483,11 +511,8 @@ extern void ironlake_edp_panel_on(struct intel_dp *intel_dp); | ||||||
| extern void ironlake_edp_panel_off(struct intel_dp *intel_dp); | extern void ironlake_edp_panel_off(struct intel_dp *intel_dp); | ||||||
| extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); | extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); | ||||||
| extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); | extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); | ||||||
| extern void intel_edp_link_config(struct intel_encoder *, int *, int *); |  | ||||||
| extern int intel_edp_target_clock(struct intel_encoder *, |  | ||||||
| 				  struct drm_display_mode *mode); |  | ||||||
| extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); | extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); | ||||||
| extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); | extern int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); | ||||||
| extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, | extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, | ||||||
| 				      enum plane plane); | 				      enum plane plane); | ||||||
| 
 | 
 | ||||||
|  | @ -531,6 +556,7 @@ extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); | ||||||
| extern void intel_connector_dpms(struct drm_connector *, int mode); | extern void intel_connector_dpms(struct drm_connector *, int mode); | ||||||
| extern bool intel_connector_get_hw_state(struct intel_connector *connector); | extern bool intel_connector_get_hw_state(struct intel_connector *connector); | ||||||
| extern void intel_modeset_check_state(struct drm_device *dev); | extern void intel_modeset_check_state(struct drm_device *dev); | ||||||
|  | extern void intel_plane_restore(struct drm_plane *plane); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) | static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) | ||||||
|  | @ -636,6 +662,10 @@ extern void intel_init_clock_gating(struct drm_device *dev); | ||||||
| extern void intel_write_eld(struct drm_encoder *encoder, | extern void intel_write_eld(struct drm_encoder *encoder, | ||||||
| 			    struct drm_display_mode *mode); | 			    struct drm_display_mode *mode); | ||||||
| extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); | extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); | ||||||
|  | extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, | ||||||
|  | 					 struct intel_link_m_n *m_n); | ||||||
|  | extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, | ||||||
|  | 					 struct intel_link_m_n *m_n); | ||||||
| extern void intel_prepare_ddi(struct drm_device *dev); | extern void intel_prepare_ddi(struct drm_device *dev); | ||||||
| extern void hsw_fdi_link_train(struct drm_crtc *crtc); | extern void hsw_fdi_link_train(struct drm_crtc *crtc); | ||||||
| extern void intel_ddi_init(struct drm_device *dev, enum port port); | extern void intel_ddi_init(struct drm_device *dev, enum port port); | ||||||
|  | @ -670,6 +700,7 @@ extern void intel_update_fbc(struct drm_device *dev); | ||||||
| extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); | extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); | ||||||
| extern void intel_gpu_ips_teardown(void); | extern void intel_gpu_ips_teardown(void); | ||||||
| 
 | 
 | ||||||
|  | extern bool intel_using_power_well(struct drm_device *dev); | ||||||
| extern void intel_init_power_well(struct drm_device *dev); | extern void intel_init_power_well(struct drm_device *dev); | ||||||
| extern void intel_set_power_well(struct drm_device *dev, bool enable); | extern void intel_set_power_well(struct drm_device *dev, bool enable); | ||||||
| extern void intel_enable_gt_powersave(struct drm_device *dev); | extern void intel_enable_gt_powersave(struct drm_device *dev); | ||||||
|  | @ -681,7 +712,7 @@ extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder, | ||||||
| 				   enum pipe *pipe); | 				   enum pipe *pipe); | ||||||
| extern int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv); | extern int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv); | ||||||
| extern void intel_ddi_pll_init(struct drm_device *dev); | extern void intel_ddi_pll_init(struct drm_device *dev); | ||||||
| extern void intel_ddi_enable_pipe_func(struct drm_crtc *crtc); | extern void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc); | ||||||
| extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, | extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, | ||||||
| 					      enum transcoder cpu_transcoder); | 					      enum transcoder cpu_transcoder); | ||||||
| extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); | extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); | ||||||
|  | @ -695,4 +726,6 @@ extern bool | ||||||
| intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); | intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); | ||||||
| extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); | extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); | ||||||
| 
 | 
 | ||||||
|  | extern void intel_display_handle_reset(struct drm_device *dev); | ||||||
|  | 
 | ||||||
| #endif /* __INTEL_DRV_H__ */ | #endif /* __INTEL_DRV_H__ */ | ||||||
|  |  | ||||||
|  | @ -448,6 +448,7 @@ void intel_dvo_init(struct drm_device *dev) | ||||||
| 		const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; | 		const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; | ||||||
| 		struct i2c_adapter *i2c; | 		struct i2c_adapter *i2c; | ||||||
| 		int gpio; | 		int gpio; | ||||||
|  | 		bool dvoinit; | ||||||
| 
 | 
 | ||||||
| 		/* Allow the I2C driver info to specify the GPIO to be used in
 | 		/* Allow the I2C driver info to specify the GPIO to be used in
 | ||||||
| 		 * special cases, but otherwise default to what's defined | 		 * special cases, but otherwise default to what's defined | ||||||
|  | @ -467,7 +468,17 @@ void intel_dvo_init(struct drm_device *dev) | ||||||
| 		i2c = intel_gmbus_get_adapter(dev_priv, gpio); | 		i2c = intel_gmbus_get_adapter(dev_priv, gpio); | ||||||
| 
 | 
 | ||||||
| 		intel_dvo->dev = *dvo; | 		intel_dvo->dev = *dvo; | ||||||
| 		if (!dvo->dev_ops->init(&intel_dvo->dev, i2c)) | 
 | ||||||
|  | 		/* GMBUS NAK handling seems to be unstable, hence let the
 | ||||||
|  | 		 * transmitter detection run in bit banging mode for now. | ||||||
|  | 		 */ | ||||||
|  | 		intel_gmbus_force_bit(i2c, true); | ||||||
|  | 
 | ||||||
|  | 		dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c); | ||||||
|  | 
 | ||||||
|  | 		intel_gmbus_force_bit(i2c, false); | ||||||
|  | 
 | ||||||
|  | 		if (!dvoinit) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		intel_encoder->type = INTEL_OUTPUT_DVO; | 		intel_encoder->type = INTEL_OUTPUT_DVO; | ||||||
|  |  | ||||||
|  | @ -150,7 +150,8 @@ static int intelfb_create(struct drm_fb_helper *helper, | ||||||
| 	} | 	} | ||||||
| 	info->screen_size = size; | 	info->screen_size = size; | ||||||
| 
 | 
 | ||||||
| //	memset(info->screen_base, 0, size);
 | 	/* This driver doesn't need a VT switch to restore the mode on resume */ | ||||||
|  | 	info->skip_vt_switch = true; | ||||||
| 
 | 
 | ||||||
| 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||||||
| 	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); | 	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); | ||||||
|  | @ -227,7 +228,7 @@ int intel_fbdev_init(struct drm_device *dev) | ||||||
| 	ifbdev->helper.funcs = &intel_fb_helper_funcs; | 	ifbdev->helper.funcs = &intel_fb_helper_funcs; | ||||||
| 
 | 
 | ||||||
| 	ret = drm_fb_helper_init(dev, &ifbdev->helper, | 	ret = drm_fb_helper_init(dev, &ifbdev->helper, | ||||||
| 				 dev_priv->num_pipe, | 				 INTEL_INFO(dev)->num_pipes, | ||||||
| 				 INTELFB_CONN_LIMIT); | 				 INTELFB_CONN_LIMIT); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		kfree(ifbdev); | 		kfree(ifbdev); | ||||||
|  | @ -282,6 +283,9 @@ void intel_fb_restore_mode(struct drm_device *dev) | ||||||
| 	struct drm_mode_config *config = &dev->mode_config; | 	struct drm_mode_config *config = &dev->mode_config; | ||||||
| 	struct drm_plane *plane; | 	struct drm_plane *plane; | ||||||
| 
 | 
 | ||||||
|  | 	if (INTEL_INFO(dev)->num_pipes == 0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	drm_modeset_lock_all(dev); | 	drm_modeset_lock_all(dev); | ||||||
| 
 | 
 | ||||||
| 	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); | 	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) | ||||||
| 
 | 
 | ||||||
| 	enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; | 	enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; | ||||||
| 
 | 
 | ||||||
| 	WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, | 	WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, | ||||||
| 	     "HDMI port enabled, expecting disabled\n"); | 	     "HDMI port enabled, expecting disabled\n"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -120,13 +120,14 @@ static u32 hsw_infoframe_enable(struct dip_infoframe *frame) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe) | static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, | ||||||
|  | 				  enum transcoder cpu_transcoder) | ||||||
| { | { | ||||||
| 	switch (frame->type) { | 	switch (frame->type) { | ||||||
| 	case DIP_TYPE_AVI: | 	case DIP_TYPE_AVI: | ||||||
| 		return HSW_TVIDEO_DIP_AVI_DATA(pipe); | 		return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); | ||||||
| 	case DIP_TYPE_SPD: | 	case DIP_TYPE_SPD: | ||||||
| 		return HSW_TVIDEO_DIP_SPD_DATA(pipe); | 		return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); | ||||||
| 	default: | 	default: | ||||||
| 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); | 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); | ||||||
| 		return 0; | 		return 0; | ||||||
|  | @ -293,8 +294,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, | ||||||
| 	struct drm_device *dev = encoder->dev; | 	struct drm_device *dev = encoder->dev; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||||||
| 	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); | 	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); | ||||||
| 	u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe); | 	u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder); | ||||||
| 	unsigned int i, len = DIP_HEADER_SIZE + frame->len; | 	unsigned int i, len = DIP_HEADER_SIZE + frame->len; | ||||||
| 	u32 val = I915_READ(ctl_reg); | 	u32 val = I915_READ(ctl_reg); | ||||||
| 
 | 
 | ||||||
|  | @ -332,6 +333,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, | ||||||
| 					 struct drm_display_mode *adjusted_mode) | 					 struct drm_display_mode *adjusted_mode) | ||||||
| { | { | ||||||
| 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | ||||||
|  | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||||||
| 	struct dip_infoframe avi_if = { | 	struct dip_infoframe avi_if = { | ||||||
| 		.type = DIP_TYPE_AVI, | 		.type = DIP_TYPE_AVI, | ||||||
| 		.ver = DIP_VERSION_AVI, | 		.ver = DIP_VERSION_AVI, | ||||||
|  | @ -342,7 +344,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, | ||||||
| 		avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; | 		avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; | ||||||
| 
 | 
 | ||||||
| 	if (intel_hdmi->rgb_quant_range_selectable) { | 	if (intel_hdmi->rgb_quant_range_selectable) { | ||||||
| 		if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) | 		if (intel_crtc->config.limited_color_range) | ||||||
| 			avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; | 			avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; | ||||||
| 		else | 		else | ||||||
| 			avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; | 			avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; | ||||||
|  | @ -568,7 +570,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, | ||||||
| 	struct drm_i915_private *dev_priv = encoder->dev->dev_private; | 	struct drm_i915_private *dev_priv = encoder->dev->dev_private; | ||||||
| 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||||||
| 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | ||||||
| 	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe); | 	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); | ||||||
| 	u32 val = I915_READ(reg); | 	u32 val = I915_READ(reg); | ||||||
| 
 | 
 | ||||||
| 	assert_hdmi_port_disabled(intel_hdmi); | 	assert_hdmi_port_disabled(intel_hdmi); | ||||||
|  | @ -597,40 +599,40 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||||||
| 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | ||||||
| 	u32 sdvox; | 	u32 hdmi_val; | ||||||
| 
 | 
 | ||||||
| 	sdvox = SDVO_ENCODING_HDMI; | 	hdmi_val = SDVO_ENCODING_HDMI; | ||||||
| 	if (!HAS_PCH_SPLIT(dev)) | 	if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) | ||||||
| 		sdvox |= intel_hdmi->color_range; | 		hdmi_val |= intel_hdmi->color_range; | ||||||
| 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||||||
| 		sdvox |= SDVO_VSYNC_ACTIVE_HIGH; | 		hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; | ||||||
| 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||||||
| 		sdvox |= SDVO_HSYNC_ACTIVE_HIGH; | 		hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; | ||||||
| 
 | 
 | ||||||
| 	if (intel_crtc->bpp > 24) | 	if (intel_crtc->config.pipe_bpp > 24) | ||||||
| 		sdvox |= COLOR_FORMAT_12bpc; | 		hdmi_val |= HDMI_COLOR_FORMAT_12bpc; | ||||||
| 	else | 	else | ||||||
| 		sdvox |= COLOR_FORMAT_8bpc; | 		hdmi_val |= SDVO_COLOR_FORMAT_8bpc; | ||||||
| 
 | 
 | ||||||
| 	/* Required on CPT */ | 	/* Required on CPT */ | ||||||
| 	if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) | 	if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) | ||||||
| 		sdvox |= HDMI_MODE_SELECT; | 		hdmi_val |= HDMI_MODE_SELECT_HDMI; | ||||||
| 
 | 
 | ||||||
| 	if (intel_hdmi->has_audio) { | 	if (intel_hdmi->has_audio) { | ||||||
| 		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", | 		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", | ||||||
| 				 pipe_name(intel_crtc->pipe)); | 				 pipe_name(intel_crtc->pipe)); | ||||||
| 		sdvox |= SDVO_AUDIO_ENABLE; | 		hdmi_val |= SDVO_AUDIO_ENABLE; | ||||||
| 		sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; | 		hdmi_val |= HDMI_MODE_SELECT_HDMI; | ||||||
| 		intel_write_eld(encoder, adjusted_mode); | 		intel_write_eld(encoder, adjusted_mode); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (HAS_PCH_CPT(dev)) | 	if (HAS_PCH_CPT(dev)) | ||||||
| 		sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe); | 		hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); | ||||||
| 	else if (intel_crtc->pipe == PIPE_B) | 	else | ||||||
| 		sdvox |= SDVO_PIPE_B_SELECT; | 		hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe); | ||||||
| 
 | 
 | ||||||
| 	I915_WRITE(intel_hdmi->sdvox_reg, sdvox); | 	I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); | ||||||
| 	POSTING_READ(intel_hdmi->sdvox_reg); | 	POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 	intel_hdmi->set_infoframes(encoder, adjusted_mode); | 	intel_hdmi->set_infoframes(encoder, adjusted_mode); | ||||||
| } | } | ||||||
|  | @ -643,7 +645,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, | ||||||
| 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | ||||||
| 	u32 tmp; | 	u32 tmp; | ||||||
| 
 | 
 | ||||||
| 	tmp = I915_READ(intel_hdmi->sdvox_reg); | 	tmp = I915_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 	if (!(tmp & SDVO_ENABLE)) | 	if (!(tmp & SDVO_ENABLE)) | ||||||
| 		return false; | 		return false; | ||||||
|  | @ -660,6 +662,7 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = encoder->base.dev; | 	struct drm_device *dev = encoder->base.dev; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
|  | 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); | ||||||
| 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | ||||||
| 	u32 temp; | 	u32 temp; | ||||||
| 	u32 enable_bits = SDVO_ENABLE; | 	u32 enable_bits = SDVO_ENABLE; | ||||||
|  | @ -667,38 +670,32 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) | ||||||
| 	if (intel_hdmi->has_audio) | 	if (intel_hdmi->has_audio) | ||||||
| 		enable_bits |= SDVO_AUDIO_ENABLE; | 		enable_bits |= SDVO_AUDIO_ENABLE; | ||||||
| 
 | 
 | ||||||
| 	temp = I915_READ(intel_hdmi->sdvox_reg); | 	temp = I915_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 	/* HW workaround for IBX, we need to move the port to transcoder A
 | 	/* HW workaround for IBX, we need to move the port to transcoder A
 | ||||||
| 	 * before disabling it. */ | 	 * before disabling it, so restore the transcoder select bit here. */ | ||||||
| 	if (HAS_PCH_IBX(dev)) { | 	if (HAS_PCH_IBX(dev)) | ||||||
| 		struct drm_crtc *crtc = encoder->base.crtc; | 		enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); | ||||||
| 		int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; |  | ||||||
| 
 |  | ||||||
| 		/* Restore the transcoder select bit. */ |  | ||||||
| 		if (pipe == PIPE_B) |  | ||||||
| 			enable_bits |= SDVO_PIPE_B_SELECT; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* HW workaround, need to toggle enable bit off and on for 12bpc, but
 | 	/* HW workaround, need to toggle enable bit off and on for 12bpc, but
 | ||||||
| 	 * we do this anyway which shows more stable in testing. | 	 * we do this anyway which shows more stable in testing. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (HAS_PCH_SPLIT(dev)) { | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
| 		I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); | 		I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); | ||||||
| 		POSTING_READ(intel_hdmi->sdvox_reg); | 		POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	temp |= enable_bits; | 	temp |= enable_bits; | ||||||
| 
 | 
 | ||||||
| 	I915_WRITE(intel_hdmi->sdvox_reg, temp); | 	I915_WRITE(intel_hdmi->hdmi_reg, temp); | ||||||
| 	POSTING_READ(intel_hdmi->sdvox_reg); | 	POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 	/* HW workaround, need to write this twice for issue that may result
 | 	/* HW workaround, need to write this twice for issue that may result
 | ||||||
| 	 * in first write getting masked. | 	 * in first write getting masked. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (HAS_PCH_SPLIT(dev)) { | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
| 		I915_WRITE(intel_hdmi->sdvox_reg, temp); | 		I915_WRITE(intel_hdmi->hdmi_reg, temp); | ||||||
| 		POSTING_READ(intel_hdmi->sdvox_reg); | 		POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -710,7 +707,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) | ||||||
| 	u32 temp; | 	u32 temp; | ||||||
| 	u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; | 	u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; | ||||||
| 
 | 
 | ||||||
| 	temp = I915_READ(intel_hdmi->sdvox_reg); | 	temp = I915_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 	/* HW workaround for IBX, we need to move the port to transcoder A
 | 	/* HW workaround for IBX, we need to move the port to transcoder A
 | ||||||
| 	 * before disabling it. */ | 	 * before disabling it. */ | ||||||
|  | @ -720,12 +717,12 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) | ||||||
| 
 | 
 | ||||||
| 		if (temp & SDVO_PIPE_B_SELECT) { | 		if (temp & SDVO_PIPE_B_SELECT) { | ||||||
| 			temp &= ~SDVO_PIPE_B_SELECT; | 			temp &= ~SDVO_PIPE_B_SELECT; | ||||||
| 			I915_WRITE(intel_hdmi->sdvox_reg, temp); | 			I915_WRITE(intel_hdmi->hdmi_reg, temp); | ||||||
| 			POSTING_READ(intel_hdmi->sdvox_reg); | 			POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 			/* Again we need to write this twice. */ | 			/* Again we need to write this twice. */ | ||||||
| 			I915_WRITE(intel_hdmi->sdvox_reg, temp); | 			I915_WRITE(intel_hdmi->hdmi_reg, temp); | ||||||
| 			POSTING_READ(intel_hdmi->sdvox_reg); | 			POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 			/* Transcoder selection bits only update
 | 			/* Transcoder selection bits only update
 | ||||||
| 			 * effectively on vblank. */ | 			 * effectively on vblank. */ | ||||||
|  | @ -740,21 +737,21 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) | ||||||
| 	 * we do this anyway which shows more stable in testing. | 	 * we do this anyway which shows more stable in testing. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (HAS_PCH_SPLIT(dev)) { | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
| 		I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); | 		I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); | ||||||
| 		POSTING_READ(intel_hdmi->sdvox_reg); | 		POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	temp &= ~enable_bits; | 	temp &= ~enable_bits; | ||||||
| 
 | 
 | ||||||
| 	I915_WRITE(intel_hdmi->sdvox_reg, temp); | 	I915_WRITE(intel_hdmi->hdmi_reg, temp); | ||||||
| 	POSTING_READ(intel_hdmi->sdvox_reg); | 	POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 
 | 
 | ||||||
| 	/* HW workaround, need to write this twice for issue that may result
 | 	/* HW workaround, need to write this twice for issue that may result
 | ||||||
| 	 * in first write getting masked. | 	 * in first write getting masked. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (HAS_PCH_SPLIT(dev)) { | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
| 		I915_WRITE(intel_hdmi->sdvox_reg, temp); | 		I915_WRITE(intel_hdmi->hdmi_reg, temp); | ||||||
| 		POSTING_READ(intel_hdmi->sdvox_reg); | 		POSTING_READ(intel_hdmi->hdmi_reg); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -772,23 +769,40 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector, | ||||||
| 	return MODE_OK; | 	return MODE_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, | bool intel_hdmi_compute_config(struct intel_encoder *encoder, | ||||||
| 			   const struct drm_display_mode *mode, | 			       struct intel_crtc_config *pipe_config) | ||||||
| 			   struct drm_display_mode *adjusted_mode) |  | ||||||
| { | { | ||||||
| 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); | ||||||
|  | 	struct drm_device *dev = encoder->base.dev; | ||||||
|  | 	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | ||||||
| 
 | 
 | ||||||
| 	if (intel_hdmi->color_range_auto) { | 	if (intel_hdmi->color_range_auto) { | ||||||
| 		/* See CEA-861-E - 5.1 Default Encoding Parameters */ | 		/* See CEA-861-E - 5.1 Default Encoding Parameters */ | ||||||
| 		if (intel_hdmi->has_hdmi_sink && | 		if (intel_hdmi->has_hdmi_sink && | ||||||
| 		    drm_match_cea_mode(adjusted_mode) > 1) | 		    drm_match_cea_mode(adjusted_mode) > 1) | ||||||
| 			intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; | 			intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; | ||||||
| 		else | 		else | ||||||
| 			intel_hdmi->color_range = 0; | 			intel_hdmi->color_range = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (intel_hdmi->color_range) | 	if (intel_hdmi->color_range) | ||||||
| 		adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; | 		pipe_config->limited_color_range = true; | ||||||
|  | 
 | ||||||
|  | 	if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) | ||||||
|  | 		pipe_config->has_pch_encoder = true; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * HDMI is either 12 or 8, so if the display lets 10bpc sneak | ||||||
|  | 	 * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi | ||||||
|  | 	 * outputs. | ||||||
|  | 	 */ | ||||||
|  | 	if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) { | ||||||
|  | 		DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); | ||||||
|  | 		pipe_config->pipe_bpp = 12*3; | ||||||
|  | 	} else { | ||||||
|  | 		DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); | ||||||
|  | 		pipe_config->pipe_bpp = 8*3; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  | @ -906,6 +920,9 @@ intel_hdmi_set_property(struct drm_connector *connector, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (property == dev_priv->broadcast_rgb_property) { | 	if (property == dev_priv->broadcast_rgb_property) { | ||||||
|  | 		bool old_auto = intel_hdmi->color_range_auto; | ||||||
|  | 		uint32_t old_range = intel_hdmi->color_range; | ||||||
|  | 
 | ||||||
| 		switch (val) { | 		switch (val) { | ||||||
| 		case INTEL_BROADCAST_RGB_AUTO: | 		case INTEL_BROADCAST_RGB_AUTO: | ||||||
| 			intel_hdmi->color_range_auto = true; | 			intel_hdmi->color_range_auto = true; | ||||||
|  | @ -916,11 +933,16 @@ intel_hdmi_set_property(struct drm_connector *connector, | ||||||
| 			break; | 			break; | ||||||
| 		case INTEL_BROADCAST_RGB_LIMITED: | 		case INTEL_BROADCAST_RGB_LIMITED: | ||||||
| 			intel_hdmi->color_range_auto = false; | 			intel_hdmi->color_range_auto = false; | ||||||
| 			intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; | 			intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (old_auto == intel_hdmi->color_range_auto && | ||||||
|  | 		    old_range == intel_hdmi->color_range) | ||||||
|  | 			return 0; | ||||||
|  | 
 | ||||||
| 		goto done; | 		goto done; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -941,7 +963,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { | static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { | ||||||
| 	.mode_fixup = intel_hdmi_mode_fixup, |  | ||||||
| 	.mode_set = intel_hdmi_mode_set, | 	.mode_set = intel_hdmi_mode_set, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -985,36 +1006,36 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, | ||||||
| 			   DRM_MODE_CONNECTOR_HDMIA); | 			   DRM_MODE_CONNECTOR_HDMIA); | ||||||
| 	drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); | 	drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); | ||||||
| 
 | 
 | ||||||
| 	connector->polled = DRM_CONNECTOR_POLL_HPD; |  | ||||||
| 	connector->interlace_allowed = 1; | 	connector->interlace_allowed = 1; | ||||||
| 	connector->doublescan_allowed = 0; | 	connector->doublescan_allowed = 0; | ||||||
| 
 | 
 | ||||||
| 	switch (port) { | 	switch (port) { | ||||||
| 	case PORT_B: | 	case PORT_B: | ||||||
| 		intel_hdmi->ddc_bus = GMBUS_PORT_DPB; | 		intel_hdmi->ddc_bus = GMBUS_PORT_DPB; | ||||||
| 		dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; | 		intel_encoder->hpd_pin = HPD_PORT_B; | ||||||
| 		break; | 		break; | ||||||
| 	case PORT_C: | 	case PORT_C: | ||||||
| 		intel_hdmi->ddc_bus = GMBUS_PORT_DPC; | 		intel_hdmi->ddc_bus = GMBUS_PORT_DPC; | ||||||
| 		dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; | 		intel_encoder->hpd_pin = HPD_PORT_C; | ||||||
| 		break; | 		break; | ||||||
| 	case PORT_D: | 	case PORT_D: | ||||||
| 		intel_hdmi->ddc_bus = GMBUS_PORT_DPD; | 		intel_hdmi->ddc_bus = GMBUS_PORT_DPD; | ||||||
| 		dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; | 		intel_encoder->hpd_pin = HPD_PORT_D; | ||||||
| 		break; | 		break; | ||||||
| 	case PORT_A: | 	case PORT_A: | ||||||
|  | 		intel_encoder->hpd_pin = HPD_PORT_A; | ||||||
| 		/* Internal port only for eDP. */ | 		/* Internal port only for eDP. */ | ||||||
| 	default: | 	default: | ||||||
| 		BUG(); | 		BUG(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!HAS_PCH_SPLIT(dev)) { | 	if (IS_VALLEYVIEW(dev)) { | ||||||
| 		intel_hdmi->write_infoframe = g4x_write_infoframe; |  | ||||||
| 		intel_hdmi->set_infoframes = g4x_set_infoframes; |  | ||||||
| 	} else if (IS_VALLEYVIEW(dev)) { |  | ||||||
| 		intel_hdmi->write_infoframe = vlv_write_infoframe; | 		intel_hdmi->write_infoframe = vlv_write_infoframe; | ||||||
| 		intel_hdmi->set_infoframes = vlv_set_infoframes; | 		intel_hdmi->set_infoframes = vlv_set_infoframes; | ||||||
| 	} else if (IS_HASWELL(dev)) { | 	} else if (!HAS_PCH_SPLIT(dev)) { | ||||||
|  | 		intel_hdmi->write_infoframe = g4x_write_infoframe; | ||||||
|  | 		intel_hdmi->set_infoframes = g4x_set_infoframes; | ||||||
|  | 	} else if (HAS_DDI(dev)) { | ||||||
| 		intel_hdmi->write_infoframe = hsw_write_infoframe; | 		intel_hdmi->write_infoframe = hsw_write_infoframe; | ||||||
| 		intel_hdmi->set_infoframes = hsw_set_infoframes; | 		intel_hdmi->set_infoframes = hsw_set_infoframes; | ||||||
| 	} else if (HAS_PCH_IBX(dev)) { | 	} else if (HAS_PCH_IBX(dev)) { | ||||||
|  | @ -1045,7 +1066,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) | void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) | ||||||
| { | { | ||||||
| 	struct intel_digital_port *intel_dig_port; | 	struct intel_digital_port *intel_dig_port; | ||||||
| 	struct intel_encoder *intel_encoder; | 	struct intel_encoder *intel_encoder; | ||||||
|  | @ -1069,6 +1090,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) | ||||||
| 			 DRM_MODE_ENCODER_TMDS); | 			 DRM_MODE_ENCODER_TMDS); | ||||||
| 	drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); | 	drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); | ||||||
| 
 | 
 | ||||||
|  | 	intel_encoder->compute_config = intel_hdmi_compute_config; | ||||||
| 	intel_encoder->enable = intel_enable_hdmi; | 	intel_encoder->enable = intel_enable_hdmi; | ||||||
| 	intel_encoder->disable = intel_disable_hdmi; | 	intel_encoder->disable = intel_disable_hdmi; | ||||||
| 	intel_encoder->get_hw_state = intel_hdmi_get_hw_state; | 	intel_encoder->get_hw_state = intel_hdmi_get_hw_state; | ||||||
|  | @ -1078,7 +1100,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) | ||||||
| 	intel_encoder->cloneable = false; | 	intel_encoder->cloneable = false; | ||||||
| 
 | 
 | ||||||
| 	intel_dig_port->port = port; | 	intel_dig_port->port = port; | ||||||
| 	intel_dig_port->hdmi.sdvox_reg = sdvox_reg; | 	intel_dig_port->hdmi.hdmi_reg = hdmi_reg; | ||||||
| 	intel_dig_port->dp.output_reg = 0; | 	intel_dig_port->dp.output_reg = 0; | ||||||
| 
 | 
 | ||||||
| 	intel_hdmi_init_connector(intel_dig_port, intel_connector); | 	intel_hdmi_init_connector(intel_dig_port, intel_connector); | ||||||
|  |  | ||||||
|  | @ -522,7 +522,9 @@ int intel_setup_gmbus(struct drm_device *dev) | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	int ret, i; | 	int ret, i; | ||||||
| 
 | 
 | ||||||
| 	if (HAS_PCH_SPLIT(dev)) | 	if (HAS_PCH_NOP(dev)) | ||||||
|  | 		return 0; | ||||||
|  | 	else if (HAS_PCH_SPLIT(dev)) | ||||||
| 		dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; | 		dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; | ||||||
| 	else if (IS_VALLEYVIEW(dev)) | 	else if (IS_VALLEYVIEW(dev)) | ||||||
| 		dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; | 		dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; | ||||||
|  |  | ||||||
|  | @ -261,8 +261,6 @@ centre_horizontally(struct drm_display_mode *mode, | ||||||
| 
 | 
 | ||||||
| 	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; | 	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; | ||||||
| 	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; | 	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; | ||||||
| 
 |  | ||||||
| 	mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
|  | @ -284,8 +282,6 @@ centre_vertically(struct drm_display_mode *mode, | ||||||
| 
 | 
 | ||||||
| 	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; | 	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; | ||||||
| 	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; | 	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; | ||||||
| 
 |  | ||||||
| 	mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline u32 panel_fitter_scaling(u32 source, u32 target) | static inline u32 panel_fitter_scaling(u32 source, u32 target) | ||||||
|  | @ -301,17 +297,20 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target) | ||||||
| 	return (FACTOR * ratio + FACTOR/2) / FACTOR; | 	return (FACTOR * ratio + FACTOR/2) / FACTOR; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, | ||||||
| 				  const struct drm_display_mode *mode, | 				      struct intel_crtc_config *pipe_config) | ||||||
| 				  struct drm_display_mode *adjusted_mode) |  | ||||||
| { | { | ||||||
| 	struct drm_device *dev = encoder->dev; | 	struct drm_device *dev = intel_encoder->base.dev; | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); | 	struct intel_lvds_encoder *lvds_encoder = | ||||||
|  | 		to_lvds_encoder(&intel_encoder->base); | ||||||
| 	struct intel_connector *intel_connector = | 	struct intel_connector *intel_connector = | ||||||
| 		&lvds_encoder->attached_connector->base; | 		&lvds_encoder->attached_connector->base; | ||||||
|  | 	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | ||||||
|  | 	struct drm_display_mode *mode = &pipe_config->requested_mode; | ||||||
| 	struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; | 	struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; | ||||||
| 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; | 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; | ||||||
|  | 	unsigned int lvds_bpp; | ||||||
| 	int pipe; | 	int pipe; | ||||||
| 
 | 
 | ||||||
| 	/* Should never happen!! */ | 	/* Should never happen!! */ | ||||||
|  | @ -323,6 +322,17 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||||||
| 	if (intel_encoder_check_is_cloned(&lvds_encoder->base)) | 	if (intel_encoder_check_is_cloned(&lvds_encoder->base)) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
|  | 	if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) == | ||||||
|  | 	    LVDS_A3_POWER_UP) | ||||||
|  | 		lvds_bpp = 8*3; | ||||||
|  | 	else | ||||||
|  | 		lvds_bpp = 6*3; | ||||||
|  | 
 | ||||||
|  | 	if (lvds_bpp != pipe_config->pipe_bpp) { | ||||||
|  | 		DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", | ||||||
|  | 			      pipe_config->pipe_bpp, lvds_bpp); | ||||||
|  | 		pipe_config->pipe_bpp = lvds_bpp; | ||||||
|  | 	} | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * We have timings from the BIOS for the panel, put them in | 	 * We have timings from the BIOS for the panel, put them in | ||||||
| 	 * to the adjusted mode.  The CRTC will be set up for this mode, | 	 * to the adjusted mode.  The CRTC will be set up for this mode, | ||||||
|  | @ -333,6 +343,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||||||
| 			       adjusted_mode); | 			       adjusted_mode); | ||||||
| 
 | 
 | ||||||
| 	if (HAS_PCH_SPLIT(dev)) { | 	if (HAS_PCH_SPLIT(dev)) { | ||||||
|  | 		pipe_config->has_pch_encoder = true; | ||||||
|  | 
 | ||||||
| 		intel_pch_panel_fitting(dev, | 		intel_pch_panel_fitting(dev, | ||||||
| 					intel_connector->panel.fitting_mode, | 					intel_connector->panel.fitting_mode, | ||||||
| 					mode, adjusted_mode); | 					mode, adjusted_mode); | ||||||
|  | @ -359,6 +371,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||||||
| 		I915_WRITE(BCLRPAT(pipe), 0); | 		I915_WRITE(BCLRPAT(pipe), 0); | ||||||
| 
 | 
 | ||||||
| 	drm_mode_set_crtcinfo(adjusted_mode, 0); | 	drm_mode_set_crtcinfo(adjusted_mode, 0); | ||||||
|  | 	pipe_config->timings_set = true; | ||||||
| 
 | 
 | ||||||
| 	switch (intel_connector->panel.fitting_mode) { | 	switch (intel_connector->panel.fitting_mode) { | ||||||
| 	case DRM_MODE_SCALE_CENTER: | 	case DRM_MODE_SCALE_CENTER: | ||||||
|  | @ -618,7 +631,6 @@ static void intel_lvds_destroy(struct drm_connector *connector) | ||||||
| 	if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) | 	if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) | ||||||
| 		kfree(lvds_connector->base.edid); | 		kfree(lvds_connector->base.edid); | ||||||
| 
 | 
 | ||||||
| 	intel_panel_destroy_backlight(connector->dev); |  | ||||||
| 	intel_panel_fini(&lvds_connector->base.panel); | 	intel_panel_fini(&lvds_connector->base.panel); | ||||||
| 
 | 
 | ||||||
| 	drm_sysfs_connector_remove(connector); | 	drm_sysfs_connector_remove(connector); | ||||||
|  | @ -661,7 +673,6 @@ static int intel_lvds_set_property(struct drm_connector *connector, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { | static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { | ||||||
| 	.mode_fixup = intel_lvds_mode_fixup, |  | ||||||
| 	.mode_set = intel_lvds_mode_set, | 	.mode_set = intel_lvds_mode_set, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -850,6 +861,14 @@ static const struct dmi_system_id intel_no_lvds[] = { | ||||||
| 			DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"), | 			DMI_MATCH(DMI_PRODUCT_NAME, "X7SPA-H"), | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		.callback = intel_no_lvds_dmi_callback, | ||||||
|  | 		.ident = "Fujitsu Esprimo Q900", | ||||||
|  | 		.matches = { | ||||||
|  | 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||||||
|  | 			DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"), | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
| 
 | 
 | ||||||
| 	{ }	/* terminating entry */ | 	{ }	/* terminating entry */ | ||||||
| }; | }; | ||||||
|  | @ -1019,12 +1038,15 @@ static bool intel_lvds_supported(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	/* With the introduction of the PCH we gained a dedicated
 | 	/* With the introduction of the PCH we gained a dedicated
 | ||||||
| 	 * LVDS presence pin, use it. */ | 	 * LVDS presence pin, use it. */ | ||||||
| 	if (HAS_PCH_SPLIT(dev)) | 	if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) | ||||||
| 		return true; | 		return true; | ||||||
| 
 | 
 | ||||||
| 	/* Otherwise LVDS was only attached to mobile products,
 | 	/* Otherwise LVDS was only attached to mobile products,
 | ||||||
| 	 * except for the inglorious 830gm */ | 	 * except for the inglorious 830gm */ | ||||||
| 	return IS_MOBILE(dev) && !IS_I830(dev); | 	if (INTEL_INFO(dev)->gen <= 4 && IS_MOBILE(dev) && !IS_I830(dev)) | ||||||
|  | 		return true; | ||||||
|  | 
 | ||||||
|  | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -1102,6 +1124,7 @@ bool intel_lvds_init(struct drm_device *dev) | ||||||
| 	intel_encoder->enable = intel_enable_lvds; | 	intel_encoder->enable = intel_enable_lvds; | ||||||
| 	intel_encoder->pre_enable = intel_pre_enable_lvds; | 	intel_encoder->pre_enable = intel_pre_enable_lvds; | ||||||
| 	intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; | 	intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; | ||||||
|  | 	intel_encoder->compute_config = intel_lvds_compute_config; | ||||||
| 	intel_encoder->disable = intel_disable_lvds; | 	intel_encoder->disable = intel_disable_lvds; | ||||||
| 	intel_encoder->get_hw_state = intel_lvds_get_hw_state; | 	intel_encoder->get_hw_state = intel_lvds_get_hw_state; | ||||||
| 	intel_connector->get_hw_state = intel_connector_get_hw_state; | 	intel_connector->get_hw_state = intel_connector_get_hw_state; | ||||||
|  |  | ||||||
|  | @ -286,8 +286,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 
 | 
 | ||||||
| 	dev_priv->backlight_level = level; | 	dev_priv->backlight.level = level; | ||||||
| 	if (dev_priv->backlight_enabled) | 	if (dev_priv->backlight.device) | ||||||
|  | 		dev_priv->backlight.device->props.brightness = level; | ||||||
|  | 
 | ||||||
|  | 	if (dev_priv->backlight.enabled) | ||||||
| 		intel_panel_actually_set_backlight(dev, level); | 		intel_panel_actually_set_backlight(dev, level); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -295,7 +298,7 @@ void intel_panel_disable_backlight(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 
 | 
 | ||||||
| 	dev_priv->backlight_enabled = false; | 	dev_priv->backlight.enabled = false; | ||||||
| 	intel_panel_actually_set_backlight(dev, 0); | 	intel_panel_actually_set_backlight(dev, 0); | ||||||
| 
 | 
 | ||||||
| 	if (INTEL_INFO(dev)->gen >= 4) { | 	if (INTEL_INFO(dev)->gen >= 4) { | ||||||
|  | @ -318,8 +321,12 @@ void intel_panel_enable_backlight(struct drm_device *dev, | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 
 | 
 | ||||||
| 	if (dev_priv->backlight_level == 0) | 	if (dev_priv->backlight.level == 0) { | ||||||
| 		dev_priv->backlight_level = intel_panel_get_max_backlight(dev); | 		dev_priv->backlight.level = intel_panel_get_max_backlight(dev); | ||||||
|  | 		if (dev_priv->backlight.device) | ||||||
|  | 			dev_priv->backlight.device->props.brightness = | ||||||
|  | 				dev_priv->backlight.level; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (INTEL_INFO(dev)->gen >= 4) { | 	if (INTEL_INFO(dev)->gen >= 4) { | ||||||
| 		uint32_t reg, tmp; | 		uint32_t reg, tmp; | ||||||
|  | @ -335,7 +342,7 @@ void intel_panel_enable_backlight(struct drm_device *dev, | ||||||
| 		if (tmp & BLM_PWM_ENABLE) | 		if (tmp & BLM_PWM_ENABLE) | ||||||
| 			goto set_level; | 			goto set_level; | ||||||
| 
 | 
 | ||||||
| 		if (dev_priv->num_pipe == 3) | 		if (INTEL_INFO(dev)->num_pipes == 3) | ||||||
| 			tmp &= ~BLM_PIPE_SELECT_IVB; | 			tmp &= ~BLM_PIPE_SELECT_IVB; | ||||||
| 		else | 		else | ||||||
| 			tmp &= ~BLM_PIPE_SELECT; | 			tmp &= ~BLM_PIPE_SELECT; | ||||||
|  | @ -360,16 +367,16 @@ set_level: | ||||||
| 	 * BLC_PWM_CPU_CTL may be cleared to zero automatically when these | 	 * BLC_PWM_CPU_CTL may be cleared to zero automatically when these | ||||||
| 	 * registers are set. | 	 * registers are set. | ||||||
| 	 */ | 	 */ | ||||||
| 	dev_priv->backlight_enabled = true; | 	dev_priv->backlight.enabled = true; | ||||||
| 	intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); | 	intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void intel_panel_init_backlight(struct drm_device *dev) | static void intel_panel_init_backlight(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 
 | 
 | ||||||
| 	dev_priv->backlight_level = intel_panel_get_backlight(dev); | 	dev_priv->backlight.level = intel_panel_get_backlight(dev); | ||||||
| 	dev_priv->backlight_enabled = dev_priv->backlight_level != 0; | 	dev_priv->backlight.enabled = dev_priv->backlight.level != 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| enum drm_connector_status | enum drm_connector_status | ||||||
|  | @ -405,8 +412,7 @@ static int intel_panel_update_status(struct backlight_device *bd) | ||||||
| static int intel_panel_get_brightness(struct backlight_device *bd) | static int intel_panel_get_brightness(struct backlight_device *bd) | ||||||
| { | { | ||||||
| 	struct drm_device *dev = bl_get_data(bd); | 	struct drm_device *dev = bl_get_data(bd); | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	return intel_panel_get_backlight(dev); | ||||||
| 	return dev_priv->backlight_level; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct backlight_ops intel_panel_bl_ops = { | static const struct backlight_ops intel_panel_bl_ops = { | ||||||
|  | @ -422,33 +428,38 @@ int intel_panel_setup_backlight(struct drm_connector *connector) | ||||||
| 
 | 
 | ||||||
| 	intel_panel_init_backlight(dev); | 	intel_panel_init_backlight(dev); | ||||||
| 
 | 
 | ||||||
|  | 	if (WARN_ON(dev_priv->backlight.device)) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
| 	memset(&props, 0, sizeof(props)); | 	memset(&props, 0, sizeof(props)); | ||||||
| 	props.type = BACKLIGHT_RAW; | 	props.type = BACKLIGHT_RAW; | ||||||
|  | 	props.brightness = dev_priv->backlight.level; | ||||||
| 	props.max_brightness = _intel_panel_get_max_backlight(dev); | 	props.max_brightness = _intel_panel_get_max_backlight(dev); | ||||||
| 	if (props.max_brightness == 0) { | 	if (props.max_brightness == 0) { | ||||||
| 		DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); | 		DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
| 	dev_priv->backlight = | 	dev_priv->backlight.device = | ||||||
| 		backlight_device_register("intel_backlight", | 		backlight_device_register("intel_backlight", | ||||||
| 					  &connector->kdev, dev, | 					  &connector->kdev, dev, | ||||||
| 					  &intel_panel_bl_ops, &props); | 					  &intel_panel_bl_ops, &props); | ||||||
| 
 | 
 | ||||||
| 	if (IS_ERR(dev_priv->backlight)) { | 	if (IS_ERR(dev_priv->backlight.device)) { | ||||||
| 		DRM_ERROR("Failed to register backlight: %ld\n", | 		DRM_ERROR("Failed to register backlight: %ld\n", | ||||||
| 			  PTR_ERR(dev_priv->backlight)); | 			  PTR_ERR(dev_priv->backlight.device)); | ||||||
| 		dev_priv->backlight = NULL; | 		dev_priv->backlight.device = NULL; | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} | 	} | ||||||
| 	dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev); |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void intel_panel_destroy_backlight(struct drm_device *dev) | void intel_panel_destroy_backlight(struct drm_device *dev) | ||||||
| { | { | ||||||
| 	struct drm_i915_private *dev_priv = dev->dev_private; | 	struct drm_i915_private *dev_priv = dev->dev_private; | ||||||
| 	if (dev_priv->backlight) | 	if (dev_priv->backlight.device) { | ||||||
| 		backlight_device_unregister(dev_priv->backlight); | 		backlight_device_unregister(dev_priv->backlight.device); | ||||||
|  | 		dev_priv->backlight.device = NULL; | ||||||
|  | 	} | ||||||
| } | } | ||||||
| #else | #else | ||||||
| int intel_panel_setup_backlight(struct drm_connector *connector) | int intel_panel_setup_backlight(struct drm_connector *connector) | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus Torvalds
				Linus Torvalds