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
|
@ -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
|
||||
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
|
||||
commonly used screen resolutions (1024x768, 1280x1024, 1680x1050,
|
||||
1920x1080) as binary blobs, but the kernel source tree does not contain
|
||||
code to create these data. In order to elucidate the origin of the
|
||||
built-in binary EDID blobs and to facilitate the creation of individual
|
||||
data for a specific misbehaving monitor, commented sources and a
|
||||
Makefile environment are given here.
|
||||
commonly used screen resolutions (1024x768, 1280x1024, 1600x1200,
|
||||
1680x1050, 1920x1080) as binary blobs, but the kernel source tree does
|
||||
not contain code to create these data. In order to elucidate the origin
|
||||
of the built-in binary EDID blobs and to facilitate the creation of
|
||||
individual data for a specific misbehaving monitor, commented sources
|
||||
and a Makefile environment are given here.
|
||||
|
||||
To create binary EDID and C source code files from the existing data
|
||||
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 <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "mux.h"
|
||||
#include "hsmmc.h"
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "common.h"
|
||||
#include <linux/omap-dma.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "gpmc.h"
|
||||
#include "gpmc-smc91x.h"
|
||||
|
|
|
@ -35,8 +35,7 @@
|
|||
|
||||
#include "common.h"
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "am35xx-emac.h"
|
||||
#include "mux.h"
|
||||
|
|
|
@ -41,8 +41,7 @@
|
|||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
#include <linux/platform_data/spi-omap2-mcspi.h>
|
||||
|
||||
#include "common.h"
|
||||
|
|
|
@ -43,8 +43,7 @@
|
|||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include <linux/platform_data/spi-omap2-mcspi.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include <asm/mach/map.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mux.h"
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <asm/mach/arch.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 "common.h"
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "gpmc-smsc911x.h"
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "board-flash.h"
|
||||
#include "mux.h"
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#include <asm/mach/flash.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 "common.h"
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
#include "common.h"
|
||||
#include <linux/platform_data/spi-omap2-mcspi.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "mux.h"
|
||||
|
|
|
@ -44,8 +44,7 @@
|
|||
#include "gpmc.h"
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include <linux/platform_data/spi-omap2-mcspi.h>
|
||||
|
||||
|
|
|
@ -47,8 +47,7 @@
|
|||
#include <asm/mach/map.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-generic-dpi.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mux.h"
|
||||
|
|
|
@ -27,9 +27,7 @@
|
|||
#include <linux/gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <video/omap-panel-tfp410.h>
|
||||
#include <video/omap-panel-nokia-dsi.h>
|
||||
#include <video/omap-panel-picodlp.h>
|
||||
#include <video/omap-panel-data.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "dss-common.h"
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
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/tegra/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/omapdrm/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_AST) += ast/
|
||||
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
|
||||
obj-$(CONFIG_DRM_TEGRA) += tegra/
|
||||
obj-$(CONFIG_DRM_OMAP) += omapdrm/
|
||||
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
|
||||
obj-$(CONFIG_DRM_QXL) += qxl/
|
||||
obj-y += i2c/
|
||||
|
|
|
@ -241,6 +241,8 @@ struct ast_fbdev {
|
|||
void *sysram;
|
||||
int size;
|
||||
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)
|
||||
|
|
|
@ -53,16 +53,52 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
|
|||
int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8;
|
||||
int ret;
|
||||
bool unmap = false;
|
||||
bool store_for_later = false;
|
||||
int x2, y2;
|
||||
unsigned long flags;
|
||||
|
||||
obj = afbdev->afb.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);
|
||||
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;
|
||||
}
|
||||
|
||||
afbdev->x1 = afbdev->y1 = INT_MAX;
|
||||
afbdev->x2 = afbdev->y2 = 0;
|
||||
spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
|
||||
|
||||
if (!bo->kmap.virtual) {
|
||||
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
|
||||
if (ret) {
|
||||
|
@ -72,10 +108,10 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
|
|||
}
|
||||
unmap = true;
|
||||
}
|
||||
for (i = y; i < y + height; i++) {
|
||||
for (i = y; i <= y2; i++) {
|
||||
/* assume equal stride for now */
|
||||
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)
|
||||
|
@ -292,6 +328,7 @@ int ast_fbdev_init(struct drm_device *dev)
|
|||
|
||||
ast->fbdev = afbdev;
|
||||
afbdev->helper.funcs = &ast_fb_helper_funcs;
|
||||
spin_lock_init(&afbdev->dirty_lock);
|
||||
ret = drm_fb_helper_init(dev, &afbdev->helper,
|
||||
1, 1);
|
||||
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);
|
||||
if (ret) {
|
||||
if (ret != -ERESTARTSYS)
|
||||
if (ret != -ERESTARTSYS && ret != -EBUSY)
|
||||
DRM_ERROR("reserve failed %p\n", bo);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -154,6 +154,8 @@ struct cirrus_fbdev {
|
|||
struct list_head fbdev_list;
|
||||
void *sysram;
|
||||
int size;
|
||||
int x1, y1, x2, y2; /* dirty rect */
|
||||
spinlock_t dirty_lock;
|
||||
};
|
||||
|
||||
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 ret;
|
||||
bool unmap = false;
|
||||
bool store_for_later = false;
|
||||
int x2, y2;
|
||||
unsigned long flags;
|
||||
|
||||
obj = afbdev->gfb.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);
|
||||
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;
|
||||
}
|
||||
|
||||
afbdev->x1 = afbdev->y1 = INT_MAX;
|
||||
afbdev->x2 = afbdev->y2 = 0;
|
||||
spin_unlock_irqrestore(&afbdev->dirty_lock, flags);
|
||||
|
||||
if (!bo->kmap.virtual) {
|
||||
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
|
||||
if (ret) {
|
||||
|
@ -268,6 +303,7 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
|
|||
|
||||
cdev->mode_info.gfbdev = gfbdev;
|
||||
gfbdev->helper.funcs = &cirrus_fb_helper_funcs;
|
||||
spin_lock_init(&gfbdev->dirty_lock);
|
||||
|
||||
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
|
||||
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);
|
||||
if (ret) {
|
||||
if (ret != -ERESTARTSYS)
|
||||
if (ret != -ERESTARTSYS && ret != -EBUSY)
|
||||
DRM_ERROR("reserve failed %p\n", bo);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -105,12 +105,11 @@ drm_clflush_sg(struct sg_table *st)
|
|||
{
|
||||
#if defined(CONFIG_X86)
|
||||
if (cpu_has_clflush) {
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
struct sg_page_iter sg_iter;
|
||||
|
||||
mb();
|
||||
for_each_sg(st->sgl, sg, st->nents, i)
|
||||
drm_clflush_page(sg_page(sg));
|
||||
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0)
|
||||
drm_clflush_page(sg_page_iter_page(&sg_iter));
|
||||
mb();
|
||||
|
||||
return;
|
||||
|
|
|
@ -178,9 +178,6 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
|
|||
{ 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 {
|
||||
int type;
|
||||
char *name;
|
||||
|
@ -412,7 +409,7 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
|
|||
mutex_lock(&dev->mode_config.fb_lock);
|
||||
fb = __drm_framebuffer_lookup(dev, id);
|
||||
if (fb)
|
||||
kref_get(&fb->refcount);
|
||||
drm_framebuffer_reference(fb);
|
||||
mutex_unlock(&dev->mode_config.fb_lock);
|
||||
|
||||
return fb;
|
||||
|
@ -706,7 +703,6 @@ int drm_connector_init(struct drm_device *dev,
|
|||
connector->connector_type = connector_type;
|
||||
connector->connector_type_id =
|
||||
++drm_connector_enum_list[connector_type].count; /* TODO */
|
||||
INIT_LIST_HEAD(&connector->user_modes);
|
||||
INIT_LIST_HEAD(&connector->probed_modes);
|
||||
INIT_LIST_HEAD(&connector->modes);
|
||||
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)
|
||||
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);
|
||||
list_del(&connector->head);
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
|
||||
{
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
const char *name, int num_values)
|
||||
{
|
||||
|
@ -3739,6 +3445,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|||
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) {
|
||||
ret = -ENOMEM;
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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 !=
|
||||
set->crtc->fb->bits_per_pixel) {
|
||||
mode_changed = true;
|
||||
} else if (set->fb->pixel_format !=
|
||||
set->crtc->fb->pixel_format) {
|
||||
mode_changed = true;
|
||||
} else
|
||||
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}
|
||||
|
||||
/** 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_GET_UNIQUE, drm_getunique, 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_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_ATTACHMODE, drm_mode_attachmode_ioctl, 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_ATTACHMODE, drm_noop, 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_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),
|
||||
|
@ -375,7 +375,7 @@ long drm_ioctl(struct file *filp,
|
|||
{
|
||||
struct drm_file *file_priv = filp->private_data;
|
||||
struct drm_device *dev;
|
||||
struct drm_ioctl_desc *ioctl;
|
||||
const struct drm_ioctl_desc *ioctl;
|
||||
drm_ioctl_t *func;
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
int retcode = -EINVAL;
|
||||
|
@ -408,6 +408,7 @@ long drm_ioctl(struct file *filp,
|
|||
usize = asize = _IOC_SIZE(cmd);
|
||||
if (drv_size > asize)
|
||||
asize = drv_size;
|
||||
cmd = ioctl->cmd_drv;
|
||||
}
|
||||
else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
|
||||
ioctl = &drm_ioctls[nr];
|
||||
|
|
|
@ -587,284 +587,348 @@ static const struct drm_display_mode edid_cea_modes[] = {
|
|||
/* 1 - 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
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 */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
|
||||
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 */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
|
||||
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 */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 60, },
|
||||
/* 6 - 1440x480i@60Hz */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
DRM_MODE_FLAG_DBLCLK),
|
||||
.vrefresh = 60, },
|
||||
/* 9 - 1440x240@60Hz */
|
||||
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
|
||||
1602, 1716, 0, 240, 244, 247, 262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
DRM_MODE_FLAG_DBLCLK),
|
||||
.vrefresh = 60, },
|
||||
/* 10 - 2880x480i@60Hz */
|
||||
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 60, },
|
||||
/* 11 - 2880x480i@60Hz */
|
||||
{ DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
3204, 3432, 0, 480, 488, 494, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 60, },
|
||||
/* 12 - 2880x240@60Hz */
|
||||
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
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 */
|
||||
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
|
||||
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 */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
|
||||
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 */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
|
||||
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 */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 50, },
|
||||
/* 21 - 1440x576i@50Hz */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
DRM_MODE_FLAG_DBLCLK),
|
||||
.vrefresh = 50, },
|
||||
/* 24 - 1440x288@50Hz */
|
||||
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
|
||||
1590, 1728, 0, 288, 290, 293, 312, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
DRM_MODE_FLAG_DBLCLK),
|
||||
.vrefresh = 50, },
|
||||
/* 25 - 2880x576i@50Hz */
|
||||
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 50, },
|
||||
/* 26 - 2880x576i@50Hz */
|
||||
{ DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
3180, 3456, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 50, },
|
||||
/* 27 - 2880x288@50Hz */
|
||||
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
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 */
|
||||
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
|
||||
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 */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
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 */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
|
||||
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 */
|
||||
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
|
||||
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 */
|
||||
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
|
||||
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 */
|
||||
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
|
||||
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 */
|
||||
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
|
||||
2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 50, },
|
||||
/* 40 - 1920x1080i@100Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
|
||||
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 100, },
|
||||
/* 41 - 1280x720@100Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
|
||||
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 */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
|
||||
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 */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
|
||||
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 */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
DRM_MODE_FLAG_DBLCLK),
|
||||
.vrefresh = 100, },
|
||||
/* 45 - 1440x576i@100Hz */
|
||||
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
|
||||
DRM_MODE_FLAG_DBLCLK) },
|
||||
DRM_MODE_FLAG_DBLCLK),
|
||||
.vrefresh = 100, },
|
||||
/* 46 - 1920x1080i@120Hz */
|
||||
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
|
||||
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
DRM_MODE_FLAG_INTERLACE),
|
||||
.vrefresh = 120, },
|
||||
/* 47 - 1280x720@120Hz */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
|
||||
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 */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
|
||||
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 */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
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 */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
|
||||
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 */
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
|
||||
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 */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
|
||||
1590, 1728, 0, 576, 580, 586, 625, 0,
|
||||
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 */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
|
||||
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 */
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
|
||||
1602, 1716, 0, 480, 488, 494, 525, 0,
|
||||
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 */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
|
||||
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 */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
|
||||
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 */
|
||||
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
|
||||
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 */
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
|
||||
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 ***/
|
||||
|
@ -2266,13 +2330,34 @@ EXPORT_SYMBOL(drm_find_cea_extension);
|
|||
*/
|
||||
u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
|
||||
{
|
||||
struct drm_display_mode *cea_mode;
|
||||
u8 mode;
|
||||
|
||||
for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) {
|
||||
cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode];
|
||||
if (!to_match->clock)
|
||||
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 0;
|
||||
|
@ -2294,6 +2379,7 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
|
|||
newmode = drm_mode_duplicate(dev,
|
||||
&edid_cea_modes[cea_mode]);
|
||||
if (newmode) {
|
||||
newmode->vrefresh = 0;
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
modes++;
|
||||
}
|
||||
|
@ -2510,6 +2596,65 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
|
|||
}
|
||||
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
|
||||
* @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 "
|
||||
"from built-in data or /lib/firmware instead. ");
|
||||
|
||||
#define GENERIC_EDIDS 4
|
||||
#define GENERIC_EDIDS 5
|
||||
static char *generic_edid_name[GENERIC_EDIDS] = {
|
||||
"edid/1024x768.bin",
|
||||
"edid/1280x1024.bin",
|
||||
"edid/1600x1200.bin",
|
||||
"edid/1680x1050.bin",
|
||||
"edid/1920x1080.bin",
|
||||
};
|
||||
|
@ -79,6 +80,24 @@ static u8 generic_edid[GENERIC_EDIDS][128] = {
|
|||
{
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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,
|
||||
0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
|
||||
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;
|
||||
bool *enabled;
|
||||
int width, height;
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
|
@ -1419,17 +1419,24 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
|
||||
drm_enable_connectors(fb_helper, enabled);
|
||||
|
||||
ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
|
||||
if (!ret) {
|
||||
ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
|
||||
if (!ret)
|
||||
if (!(fb_helper->funcs->initial_config &&
|
||||
fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
|
||||
enabled, width, height))) {
|
||||
memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
|
||||
memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
|
||||
|
||||
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_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
|
||||
|
||||
drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
|
||||
|
||||
/* need to set the modesets up here for use later */
|
||||
/* fill out the connector<->crtc mappings into the modesets */
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
|
|
|
@ -205,11 +205,11 @@ static void
|
|||
drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
|
||||
{
|
||||
if (obj->import_attach) {
|
||||
drm_prime_remove_imported_buf_handle(&filp->prime,
|
||||
drm_prime_remove_buf_handle(&filp->prime,
|
||||
obj->import_attach->dmabuf);
|
||||
}
|
||||
if (obj->export_dma_buf) {
|
||||
drm_prime_remove_imported_buf_handle(&filp->prime,
|
||||
drm_prime_remove_buf_handle(&filp->prime,
|
||||
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)
|
||||
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 &&
|
||||
mode1->hsync_start == mode2->hsync_start &&
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_equal);
|
||||
EXPORT_SYMBOL(drm_mode_equal_no_clocks);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
struct pci_driver *pdriver = dev->driver->kdriver.pci;
|
||||
|
@ -194,9 +194,9 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int drm_pci_set_unique(struct drm_device *dev,
|
||||
struct drm_master *master,
|
||||
struct drm_unique *u)
|
||||
static int drm_pci_set_unique(struct drm_device *dev,
|
||||
struct drm_master *master,
|
||||
struct drm_unique *u)
|
||||
{
|
||||
int domain, bus, slot, func, ret;
|
||||
const char *bus_name;
|
||||
|
@ -266,7 +266,7 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
|
|||
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_pci_device_is_agp(dev))
|
||||
|
|
|
@ -62,6 +62,7 @@ struct drm_prime_member {
|
|||
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);
|
||||
|
||||
static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
|
||||
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;
|
||||
void *buf;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct dma_buf *dmabuf;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, handle);
|
||||
if (!obj)
|
||||
|
@ -209,43 +211,44 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
|
|||
mutex_lock(&file_priv->prime.lock);
|
||||
/* re-export the original imported object */
|
||||
if (obj->import_attach) {
|
||||
get_dma_buf(obj->import_attach->dmabuf);
|
||||
*prime_fd = dma_buf_fd(obj->import_attach->dmabuf, flags);
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
return 0;
|
||||
dmabuf = obj->import_attach->dmabuf;
|
||||
goto out_have_obj;
|
||||
}
|
||||
|
||||
if (obj->export_dma_buf) {
|
||||
get_dma_buf(obj->export_dma_buf);
|
||||
*prime_fd = dma_buf_fd(obj->export_dma_buf, flags);
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
} else {
|
||||
buf = dev->driver->gem_prime_export(dev, obj, flags);
|
||||
if (IS_ERR(buf)) {
|
||||
/* normally the created dma-buf takes ownership of the ref,
|
||||
* but if that fails then drop the ref
|
||||
*/
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
obj->export_dma_buf = buf;
|
||||
*prime_fd = dma_buf_fd(buf, flags);
|
||||
dmabuf = obj->export_dma_buf;
|
||||
goto out_have_obj;
|
||||
}
|
||||
|
||||
buf = dev->driver->gem_prime_export(dev, obj, flags);
|
||||
if (IS_ERR(buf)) {
|
||||
/* normally the created dma-buf takes ownership of the ref,
|
||||
* but if that fails then drop the ref
|
||||
*/
|
||||
ret = PTR_ERR(buf);
|
||||
goto out;
|
||||
}
|
||||
obj->export_dma_buf = buf;
|
||||
|
||||
/* if we've exported this buffer the cheat and add it to the import list
|
||||
* so we get the correct handle back
|
||||
*/
|
||||
ret = drm_prime_add_imported_buf_handle(&file_priv->prime,
|
||||
obj->export_dma_buf, handle);
|
||||
if (ret) {
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
return ret;
|
||||
}
|
||||
ret = drm_prime_add_buf_handle(&file_priv->prime,
|
||||
obj->export_dma_buf, handle);
|
||||
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);
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
return ret;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
dma_buf_put(dma_buf);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +279,8 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
|
|||
if (IS_ERR(attach))
|
||||
return ERR_PTR(PTR_ERR(attach));
|
||||
|
||||
get_dma_buf(dma_buf);
|
||||
|
||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR_OR_NULL(sgt)) {
|
||||
ret = PTR_ERR(sgt);
|
||||
|
@ -297,6 +301,8 @@ fail_unmap:
|
|||
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
|
||||
fail_detach:
|
||||
dma_buf_detach(dma_buf, attach);
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
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);
|
||||
|
||||
ret = drm_prime_lookup_imported_buf_handle(&file_priv->prime,
|
||||
ret = drm_prime_lookup_buf_handle(&file_priv->prime,
|
||||
dma_buf, handle);
|
||||
if (!ret) {
|
||||
ret = 0;
|
||||
|
@ -333,12 +339,15 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
|
|||
if (ret)
|
||||
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);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
mutex_unlock(&file_priv->prime.lock);
|
||||
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
return 0;
|
||||
|
||||
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 *sg = NULL;
|
||||
struct scatterlist *iter;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!sg)
|
||||
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)
|
||||
goto out;
|
||||
|
||||
for_each_sg(sg->sgl, iter, nr_pages, i)
|
||||
sg_set_page(iter, pages[i], PAGE_SIZE, 0);
|
||||
|
||||
return sg;
|
||||
out:
|
||||
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)
|
||||
{
|
||||
struct drm_prime_member *member, *safe;
|
||||
list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
|
||||
list_del(&member->entry);
|
||||
kfree(member);
|
||||
}
|
||||
/* by now drm_gem_release should've made sure the list is empty */
|
||||
WARN_ON(!list_empty(&prime_fpriv->head));
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -499,14 +501,14 @@ int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv
|
|||
if (!member)
|
||||
return -ENOMEM;
|
||||
|
||||
get_dma_buf(dma_buf);
|
||||
member->dma_buf = dma_buf;
|
||||
member->handle = handle;
|
||||
list_add(&member->entry, &prime_fpriv->head);
|
||||
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;
|
||||
|
||||
|
@ -518,19 +520,20 @@ int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fp
|
|||
}
|
||||
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;
|
||||
|
||||
mutex_lock(&prime_fpriv->lock);
|
||||
list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
|
||||
if (member->dma_buf == dma_buf) {
|
||||
dma_buf_put(dma_buf);
|
||||
list_del(&member->entry);
|
||||
kfree(member);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_vm_open_locked);
|
||||
|
||||
static void drm_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,9 @@ config DRM_EXYNOS_DMABUF
|
|||
|
||||
config DRM_EXYNOS_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
|
||||
Choose this option if you want to use Exynos FIMD for DRM.
|
||||
|
||||
|
@ -54,7 +56,7 @@ config DRM_EXYNOS_IPP
|
|||
|
||||
config DRM_EXYNOS_FIMC
|
||||
bool "Exynos DRM FIMC"
|
||||
depends on DRM_EXYNOS_IPP
|
||||
depends on DRM_EXYNOS_IPP && MFD_SYSCON && OF
|
||||
help
|
||||
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);
|
||||
if (count < 0) {
|
||||
if (!count) {
|
||||
DRM_ERROR("Add edid modes failed %d\n", count);
|
||||
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.
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
dma_buf_put(dma_buf);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
@ -244,6 +243,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
|
|||
if (IS_ERR(attach))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
get_dma_buf(dma_buf);
|
||||
|
||||
sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
|
||||
if (IS_ERR_OR_NULL(sgt)) {
|
||||
|
@ -298,6 +298,8 @@ err_unmap_attach:
|
|||
dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
|
||||
err_buf_detach:
|
||||
dma_buf_detach(dma_buf, attach);
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -380,6 +380,10 @@ static int __init exynos_drm_init(void)
|
|||
ret = platform_driver_register(&ipp_driver);
|
||||
if (ret < 0)
|
||||
goto out_ipp;
|
||||
|
||||
ret = exynos_platform_device_ipp_register();
|
||||
if (ret < 0)
|
||||
goto out_ipp_dev;
|
||||
#endif
|
||||
|
||||
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,
|
||||
NULL, 0);
|
||||
if (IS_ERR_OR_NULL(exynos_drm_pdev)) {
|
||||
if (IS_ERR(exynos_drm_pdev)) {
|
||||
ret = PTR_ERR(exynos_drm_pdev);
|
||||
goto out;
|
||||
}
|
||||
|
@ -400,6 +404,8 @@ out:
|
|||
|
||||
out_drm:
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
exynos_platform_device_ipp_unregister();
|
||||
out_ipp_dev:
|
||||
platform_driver_unregister(&ipp_driver);
|
||||
out_ipp:
|
||||
#endif
|
||||
|
@ -456,6 +462,7 @@ static void __exit exynos_drm_exit(void)
|
|||
platform_driver_unregister(&exynos_drm_platform_driver);
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IPP
|
||||
exynos_platform_device_ipp_unregister();
|
||||
platform_driver_unregister(&ipp_driver);
|
||||
#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
|
||||
* 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.
|
||||
*/
|
||||
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 hdmi_driver;
|
||||
extern struct platform_driver mixer_driver;
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <plat/map-base.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/exynos_drm.h>
|
||||
|
@ -76,6 +77,27 @@ enum fimc_wb {
|
|||
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.
|
||||
*
|
||||
|
@ -118,15 +140,6 @@ struct fimc_capability {
|
|||
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.
|
||||
*
|
||||
|
@ -134,13 +147,10 @@ struct fimc_driverdata {
|
|||
* @regs_res: register resources.
|
||||
* @regs: memory mapped io registers.
|
||||
* @lock: locking of operations.
|
||||
* @sclk_fimc_clk: fimc source clock.
|
||||
* @fimc_clk: fimc clock.
|
||||
* @wb_clk: writeback a clock.
|
||||
* @wb_b_clk: writeback b clock.
|
||||
* @clocks: fimc clocks.
|
||||
* @clk_frequency: LCLK clock frequency.
|
||||
* @sysreg: handle to SYSREG block regmap.
|
||||
* @sc: scaler infomations.
|
||||
* @odr: ordering of YUV.
|
||||
* @ver: fimc version.
|
||||
* @pol: porarity of writeback.
|
||||
* @id: fimc id.
|
||||
* @irq: irq number.
|
||||
|
@ -151,12 +161,10 @@ struct fimc_context {
|
|||
struct resource *regs_res;
|
||||
void __iomem *regs;
|
||||
struct mutex lock;
|
||||
struct clk *sclk_fimc_clk;
|
||||
struct clk *fimc_clk;
|
||||
struct clk *wb_clk;
|
||||
struct clk *wb_b_clk;
|
||||
struct clk *clocks[FIMC_CLKS_MAX];
|
||||
u32 clk_frequency;
|
||||
struct regmap *sysreg;
|
||||
struct fimc_scaler sc;
|
||||
struct fimc_driverdata *ddata;
|
||||
struct exynos_drm_ipp_pol pol;
|
||||
int id;
|
||||
int irq;
|
||||
|
@ -200,17 +208,13 @@ static void fimc_sw_reset(struct fimc_context *ctx)
|
|||
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__);
|
||||
|
||||
camblk_cfg = readl(SYSREG_CAMERA_BLK);
|
||||
camblk_cfg &= ~(SYSREG_FIMD0WB_DEST_MASK);
|
||||
camblk_cfg |= ctx->id << (SYSREG_FIMD0WB_DEST_SHIFT);
|
||||
|
||||
writel(camblk_cfg, SYSREG_CAMERA_BLK);
|
||||
return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK,
|
||||
SYSREG_FIMD0WB_DEST_MASK,
|
||||
ctx->id << SYSREG_FIMD0WB_DEST_SHIFT);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (enable) {
|
||||
clk_enable(ctx->sclk_fimc_clk);
|
||||
clk_enable(ctx->fimc_clk);
|
||||
clk_enable(ctx->wb_clk);
|
||||
clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
|
||||
clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]);
|
||||
ctx->suspended = false;
|
||||
} else {
|
||||
clk_disable(ctx->sclk_fimc_clk);
|
||||
clk_disable(ctx->fimc_clk);
|
||||
clk_disable(ctx->wb_clk);
|
||||
clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);
|
||||
clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]);
|
||||
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);
|
||||
|
||||
/* 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.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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct fimc_context *ctx;
|
||||
struct clk *parent_clk;
|
||||
struct resource *res;
|
||||
struct exynos_drm_ippdrv *ippdrv;
|
||||
struct exynos_drm_fimc_pdata *pdata;
|
||||
struct fimc_driverdata *ddata;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(dev, "no platform data specified.\n");
|
||||
return -EINVAL;
|
||||
if (!dev->of_node) {
|
||||
dev_err(dev, "device tree node not found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ddata = (struct fimc_driverdata *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
ctx->ippdrv.dev = dev;
|
||||
|
||||
/* clock control */
|
||||
ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc");
|
||||
if (IS_ERR(ctx->sclk_fimc_clk)) {
|
||||
dev_err(dev, "failed to get src fimc clock.\n");
|
||||
return PTR_ERR(ctx->sclk_fimc_clk);
|
||||
ret = fimc_parse_dt(ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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 */
|
||||
ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
@ -1804,13 +1852,11 @@ static int fimc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* context initailization */
|
||||
ctx->id = pdev->id;
|
||||
ctx->pol = pdata->pol;
|
||||
ctx->ddata = ddata;
|
||||
ret = fimc_setup_clocks(ctx);
|
||||
if (ret < 0)
|
||||
goto err_free_irq;
|
||||
|
||||
ippdrv = &ctx->ippdrv;
|
||||
ippdrv->dev = dev;
|
||||
ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
|
||||
ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops;
|
||||
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);
|
||||
if (ret < 0) {
|
||||
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,
|
||||
|
@ -1835,17 +1881,18 @@ static int fimc_probe(struct platform_device *pdev)
|
|||
ret = exynos_drm_ippdrv_register(ippdrv);
|
||||
if (ret < 0) {
|
||||
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");
|
||||
|
||||
return 0;
|
||||
|
||||
err_ippdrv_register:
|
||||
devm_kfree(dev, ippdrv->prop_list);
|
||||
err_pm_dis:
|
||||
pm_runtime_disable(dev);
|
||||
err_get_irq:
|
||||
err_put_clk:
|
||||
fimc_put_clocks(ctx);
|
||||
err_free_irq:
|
||||
free_irq(ctx->irq, ctx);
|
||||
|
||||
return ret;
|
||||
|
@ -1857,10 +1904,10 @@ static int fimc_remove(struct platform_device *pdev)
|
|||
struct fimc_context *ctx = get_fimc_context(dev);
|
||||
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
|
||||
|
||||
devm_kfree(dev, ippdrv->prop_list);
|
||||
exynos_drm_ippdrv_unregister(ippdrv);
|
||||
mutex_destroy(&ctx->lock);
|
||||
|
||||
fimc_put_clocks(ctx);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
|
@ -1915,36 +1962,22 @@ static int fimc_runtime_resume(struct device *dev)
|
|||
}
|
||||
#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 = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
|
||||
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 = {
|
||||
.probe = fimc_probe,
|
||||
.remove = fimc_remove,
|
||||
.id_table = fimc_driver_ids,
|
||||
.driver = {
|
||||
.of_match_table = fimc_of_match,
|
||||
.name = "exynos-drm-fimc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &fimc_pm_ops,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/samsung_fimd.h>
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
|
@ -800,18 +801,18 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
|
|||
if (enable) {
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(ctx->bus_clk);
|
||||
ret = clk_prepare_enable(ctx->bus_clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(ctx->lcd_clk);
|
||||
ret = clk_prepare_enable(ctx->lcd_clk);
|
||||
if (ret < 0) {
|
||||
clk_disable(ctx->bus_clk);
|
||||
clk_disable_unprepare(ctx->bus_clk);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
clk_disable(ctx->lcd_clk);
|
||||
clk_disable(ctx->bus_clk);
|
||||
clk_disable_unprepare(ctx->lcd_clk);
|
||||
clk_disable_unprepare(ctx->bus_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -884,10 +885,25 @@ static int fimd_probe(struct platform_device *pdev)
|
|||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(dev, "no platform data specified\n");
|
||||
return -EINVAL;
|
||||
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;
|
||||
if (!pdata) {
|
||||
DRM_ERROR("no platform data specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
panel = &pdata->panel;
|
||||
|
@ -918,7 +934,7 @@ static int fimd_probe(struct platform_device *pdev)
|
|||
if (IS_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) {
|
||||
dev_err(dev, "irq request failed.\n");
|
||||
return -ENXIO;
|
||||
|
@ -980,9 +996,6 @@ static int fimd_remove(struct platform_device *pdev)
|
|||
if (ctx->suspended)
|
||||
goto out;
|
||||
|
||||
clk_disable(ctx->lcd_clk);
|
||||
clk_disable(ctx->bus_clk);
|
||||
|
||||
pm_runtime_set_suspended(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->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))
|
||||
return PTR_ERR(exynos_gem_obj);
|
||||
|
||||
|
|
|
@ -51,21 +51,27 @@ struct drm_hdmi_context {
|
|||
|
||||
int exynos_platform_device_hdmi_register(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
||||
if (exynos_drm_hdmi_pdev)
|
||||
return -EEXIST;
|
||||
|
||||
exynos_drm_hdmi_pdev = platform_device_register_simple(
|
||||
pdev = platform_device_register_simple(
|
||||
"exynos-drm-hdmi", -1, NULL, 0);
|
||||
if (IS_ERR_OR_NULL(exynos_drm_hdmi_pdev))
|
||||
return PTR_ERR(exynos_drm_hdmi_pdev);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
exynos_drm_hdmi_pdev = pdev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_platform_device_hdmi_unregister(void)
|
||||
{
|
||||
if (exynos_drm_hdmi_pdev)
|
||||
if (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)
|
||||
|
@ -205,13 +211,45 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
|
|||
const struct drm_display_mode *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__);
|
||||
|
||||
if (hdmi_ops && hdmi_ops->mode_fixup)
|
||||
hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode,
|
||||
adjusted_mode);
|
||||
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||
|
||||
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)
|
||||
|
|
|
@ -36,9 +36,6 @@ struct exynos_hdmi_ops {
|
|||
int (*power_on)(void *ctx, int mode);
|
||||
|
||||
/* 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 (*get_max_resol)(void *ctx, unsigned int *width,
|
||||
unsigned int *height);
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
#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.
|
||||
*
|
||||
|
@ -102,6 +105,30 @@ static LIST_HEAD(exynos_drm_ippdrv_list);
|
|||
static DEFINE_MUTEX(exynos_drm_ippdrv_lock);
|
||||
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)
|
||||
{
|
||||
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");
|
||||
if (IS_ERR_OR_NULL(rot->clock)) {
|
||||
if (IS_ERR(rot->clock)) {
|
||||
dev_err(dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(rot->clock);
|
||||
goto err_clk_get;
|
||||
|
|
|
@ -108,7 +108,20 @@ struct hdmi_tg_regs {
|
|||
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 v2_blank[2];
|
||||
u8 v1_blank[2];
|
||||
|
@ -147,11 +160,23 @@ struct hdmi_core_regs {
|
|||
u8 vact_space_6[2];
|
||||
};
|
||||
|
||||
struct hdmi_v14_conf {
|
||||
int pixel_clock;
|
||||
struct hdmi_core_regs core;
|
||||
struct hdmi_v13_conf {
|
||||
struct hdmi_v13_core_regs core;
|
||||
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;
|
||||
union {
|
||||
struct hdmi_v13_conf v13_conf;
|
||||
struct hdmi_v14_conf v14_conf;
|
||||
} conf;
|
||||
};
|
||||
|
||||
struct hdmi_context {
|
||||
|
@ -169,9 +194,8 @@ struct hdmi_context {
|
|||
struct i2c_client *ddc_port;
|
||||
struct i2c_client *hdmiphy_port;
|
||||
|
||||
/* current hdmiphy conf index */
|
||||
int cur_conf;
|
||||
struct hdmi_v14_conf mode_conf;
|
||||
/* current hdmiphy conf regs */
|
||||
struct hdmi_conf_regs mode_conf;
|
||||
|
||||
struct hdmi_resources res;
|
||||
|
||||
|
@ -180,292 +204,60 @@ struct hdmi_context {
|
|||
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 {
|
||||
int pixel_clock;
|
||||
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[] = {
|
||||
{
|
||||
.pixel_clock = 25200000,
|
||||
|
@ -873,22 +665,6 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *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,
|
||||
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 |
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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",
|
||||
check_timing->xres, check_timing->yres,
|
||||
check_timing->refresh, (check_timing->vmode &
|
||||
FB_VMODE_INTERLACED) ? true : false);
|
||||
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
/* TODO */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int hdmi_v14_find_phy_conf(int pixel_clock)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) {
|
||||
if (hdmiphy_v14_configs[i].pixel_clock == pixel_clock)
|
||||
for (i = 0; i < count; i++)
|
||||
if (confs[i].pixel_clock == pixel_clock)
|
||||
return i;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
|
||||
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)
|
||||
{
|
||||
struct hdmi_context *hdata = ctx;
|
||||
int ret;
|
||||
|
||||
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->vmode);
|
||||
|
||||
if (hdata->type == HDMI_TYPE13)
|
||||
return hdmi_v13_check_timing(timing);
|
||||
else
|
||||
return hdmi_v14_check_timing(timing);
|
||||
ret = hdmi_find_phy_conf(hdata, timing->pixclock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const struct hdmi_v13_preset_conf *conf =
|
||||
hdmi_v13_confs[hdata->cur_conf].conf;
|
||||
const struct hdmi_v13_core_regs *core = &conf->core;
|
||||
const struct hdmi_v13_tg_regs *tg = &conf->tg;
|
||||
const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
|
||||
const struct hdmi_v13_core_regs *core =
|
||||
&hdata->mode_conf.conf.v13_conf.core;
|
||||
int tries;
|
||||
|
||||
/* 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_2, core->v_sync_gen3[2]);
|
||||
/* Timing generator registers */
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
|
||||
hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
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[1]);
|
||||
|
||||
/* waiting for HDMIPHY's PLL to get to steady state */
|
||||
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)
|
||||
{
|
||||
struct hdmi_core_regs *core = &hdata->mode_conf.core;
|
||||
struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
|
||||
const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
|
||||
const struct hdmi_v14_core_regs *core =
|
||||
&hdata->mode_conf.conf.v14_conf.core;
|
||||
int tries;
|
||||
|
||||
/* setting core registers */
|
||||
|
@ -1624,18 +1367,17 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
|
|||
}
|
||||
|
||||
/* pixel clock */
|
||||
if (hdata->type == HDMI_TYPE13) {
|
||||
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) {
|
||||
DRM_ERROR("failed to find hdmiphy conf\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdmiphy_data = hdmiphy_v14_configs[i].conf;
|
||||
i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
|
||||
if (i < 0) {
|
||||
DRM_ERROR("failed to find hdmiphy conf\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hdata->type == HDMI_TYPE13)
|
||||
hdmiphy_data = hdmiphy_v13_configs[i].conf;
|
||||
else
|
||||
hdmiphy_data = hdmiphy_v14_configs[i].conf;
|
||||
|
||||
memcpy(buffer, hdmiphy_data, 32);
|
||||
ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
|
||||
if (ret != 32) {
|
||||
|
@ -1687,58 +1429,6 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
|
|||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
struct drm_display_mode *m)
|
||||
{
|
||||
struct hdmi_core_regs *core = &hdata->mode_conf.core;
|
||||
struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
|
||||
|
||||
hdata->mode_conf.cea_video_id = drm_match_cea_mode(m);
|
||||
struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_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((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->v_line, 2, m->vtotal);
|
||||
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_bot_hdmi, 2, 0x233); /* Reset value */
|
||||
hdmi_set_reg(tg->tg_3d, 1, 0x0);
|
||||
|
||||
}
|
||||
|
||||
static void hdmi_mode_set(void *ctx, void *mode)
|
||||
{
|
||||
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) {
|
||||
conf_idx = hdmi_v13_conf_index(mode);
|
||||
if (conf_idx >= 0)
|
||||
hdata->cur_conf = conf_idx;
|
||||
else
|
||||
DRM_DEBUG_KMS("not supported mode\n");
|
||||
} else {
|
||||
if (hdata->type == HDMI_TYPE13)
|
||||
hdmi_v13_mode_set(hdata, mode);
|
||||
else
|
||||
hdmi_v14_mode_set(hdata, mode);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
/* manager */
|
||||
.mode_fixup = hdmi_mode_fixup,
|
||||
.mode_set = hdmi_mode_set,
|
||||
.get_max_resol = hdmi_get_max_resol,
|
||||
.commit = hdmi_commit,
|
||||
|
@ -2023,27 +1807,27 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
|
|||
|
||||
/* get clocks, power */
|
||||
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");
|
||||
goto fail;
|
||||
}
|
||||
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");
|
||||
goto fail;
|
||||
}
|
||||
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");
|
||||
goto fail;
|
||||
}
|
||||
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");
|
||||
goto fail;
|
||||
}
|
||||
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");
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -643,12 +643,14 @@ static void mixer_win_reset(struct mixer_context *ctx)
|
|||
/* setting graphical layers */
|
||||
val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
|
||||
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 */
|
||||
|
||||
/* the same configuration for both layers */
|
||||
/* Don't blend layer 0 onto the mixer background */
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct mixer_context *mixer_ctx = ctx;
|
||||
u32 w, h;
|
||||
|
||||
w = timing->xres;
|
||||
|
@ -831,9 +832,6 @@ static int mixer_check_timing(void *ctx, struct fb_videomode *timing)
|
|||
timing->refresh, (timing->vmode &
|
||||
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) ||
|
||||
(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
|
||||
(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);
|
||||
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -1096,17 +1094,17 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
|
|||
struct resource *res;
|
||||
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -661,9 +661,8 @@
|
|||
#define EXYNOS_CLKSRC_SCLK (1 << 1)
|
||||
|
||||
/* SYSREG for FIMC writeback */
|
||||
#define SYSREG_CAMERA_BLK (S3C_VA_SYS + 0x0218)
|
||||
#define SYSREG_ISP_BLK (S3C_VA_SYS + 0x020c)
|
||||
#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
|
||||
#define SYSREG_FIMD0WB_DEST_SHIFT 23
|
||||
#define SYSREG_CAMERA_BLK (0x0218)
|
||||
#define SYSREG_FIMD0WB_DEST_MASK (0x3 << 23)
|
||||
#define SYSREG_FIMD0WB_DEST_SHIFT 23
|
||||
|
||||
#endif /* EXYNOS_REGS_FIMC_H */
|
||||
|
|
|
@ -2,10 +2,15 @@ config DRM_GMA500
|
|||
tristate "Intel GMA5/600 KMS Framebuffer"
|
||||
depends on DRM && PCI && X86
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_TTM
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select DRM_KMS_HELPER
|
||||
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
|
||||
Say yes for an experimental 2D KMS framebuffer driver for the
|
||||
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;
|
||||
|
||||
connector = &psb_intel_connector->base;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
drm_connector_init(dev, connector,
|
||||
&cdv_intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
|
||||
|
||||
|
|
|
@ -319,6 +319,7 @@ void cdv_hdmi_init(struct drm_device *dev,
|
|||
goto err_priv;
|
||||
|
||||
connector = &psb_intel_connector->base;
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
encoder = &psb_intel_encoder->base;
|
||||
drm_connector_init(dev, connector,
|
||||
&cdv_hdmi_connector_funcs,
|
||||
|
|
|
@ -431,7 +431,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|||
fbdev->psb_fb_helper.fbdev = info;
|
||||
|
||||
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;
|
||||
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++)
|
||||
psb_intel_crtc_init(dev, i, mode_dev);
|
||||
|
||||
dev->mode_config.max_width = 2048;
|
||||
dev->mode_config.max_height = 2048;
|
||||
dev->mode_config.max_width = 4096;
|
||||
dev->mode_config.max_height = 4096;
|
||||
|
||||
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
|
||||
* 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 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);
|
||||
pages = r->pages;
|
||||
|
||||
/* Make sure changes are visible to the GPU */
|
||||
set_pages_array_wc(pages, r->npage);
|
||||
if (!resume) {
|
||||
/* Make sure changes are visible to the GPU */
|
||||
set_pages_array_wc(pages, r->npage);
|
||||
}
|
||||
|
||||
/* Write our page entries into the GTT itself */
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = psb_gtt_insert(dev, gt);
|
||||
ret = psb_gtt_insert(dev, gt, 0);
|
||||
if (ret < 0) {
|
||||
psb_gtt_detach_pages(gt);
|
||||
goto out;
|
||||
|
@ -421,9 +424,11 @@ int psb_gtt_init(struct drm_device *dev, int resume)
|
|||
int ret = 0;
|
||||
uint32_t pte;
|
||||
|
||||
mutex_init(&dev_priv->gtt_mutex);
|
||||
if (!resume) {
|
||||
mutex_init(&dev_priv->gtt_mutex);
|
||||
psb_gtt_alloc(dev);
|
||||
}
|
||||
|
||||
psb_gtt_alloc(dev);
|
||||
pg = &dev_priv->gtt;
|
||||
|
||||
/* Enable the GTT */
|
||||
|
@ -505,7 +510,8 @@ int psb_gtt_init(struct drm_device *dev, int resume)
|
|||
/*
|
||||
* Map the GTT and the stolen memory area
|
||||
*/
|
||||
dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start,
|
||||
if (!resume)
|
||||
dev_priv->gtt_map = ioremap_nocache(pg->gtt_phys_start,
|
||||
gtt_pages << PAGE_SHIFT);
|
||||
if (!dev_priv->gtt_map) {
|
||||
dev_err(dev->dev, "Failure to map gtt.\n");
|
||||
|
@ -513,7 +519,9 @@ int psb_gtt_init(struct drm_device *dev, int resume)
|
|||
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) {
|
||||
dev_err(dev->dev, "Failure to map stolen base.\n");
|
||||
ret = -ENOMEM;
|
||||
|
@ -549,3 +557,31 @@ out_err:
|
|||
psb_gtt_takedown(dev);
|
||||
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_roll(struct drm_device *dev,
|
||||
struct gtt_range *gt, int roll);
|
||||
|
||||
extern int psb_gtt_restore(struct drm_device *dev);
|
||||
#endif
|
||||
|
|
|
@ -218,12 +218,11 @@ static void parse_backlight_data(struct drm_psb_private *dev_priv,
|
|||
bl_start = find_section(bdb, BDB_LVDS_BACKLIGHT);
|
||||
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) {
|
||||
dev_err(dev_priv->dev->dev, "out of memory for backlight data\n");
|
||||
return;
|
||||
}
|
||||
memcpy(lvds_bl, vbt_lvds_bl, sizeof(*vbt_lvds_bl));
|
||||
dev_priv->lvds_bl = lvds_bl;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef _I830_BIOS_H_
|
||||
#define _I830_BIOS_H_
|
||||
#ifndef _INTEL_BIOS_H_
|
||||
#define _INTEL_BIOS_H_
|
||||
|
||||
#include <drm/drmP.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_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 =
|
||||
mdfld_dsi_get_pkg_sender(dsi_config);
|
||||
struct drm_device *dev = sender->dev;
|
||||
struct drm_psb_private *dev_priv = dev->dev_private;
|
||||
struct drm_device *dev;
|
||||
struct drm_psb_private *dev_priv;
|
||||
u32 gen_ctrl_val;
|
||||
|
||||
if (!sender) {
|
||||
|
@ -101,6 +101,9 @@ void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe)
|
|||
return;
|
||||
}
|
||||
|
||||
dev = sender->dev;
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
/* Set default display backlight value to 85% (0xd8)*/
|
||||
mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1,
|
||||
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);
|
||||
pci_write_config_word(pdev, PSB_GMCH_CTRL,
|
||||
dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
|
||||
|
||||
psb_gtt_restore(dev); /* Rebuild our GTT mappings */
|
||||
dev_priv->ops->restore_regs(dev);
|
||||
}
|
||||
|
||||
|
@ -313,3 +315,18 @@ int psb_runtime_idle(struct device *dev)
|
|||
else
|
||||
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_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
|
||||
|
|
|
@ -601,6 +601,9 @@ static void psb_remove(struct pci_dev *pdev)
|
|||
static const struct dev_pm_ops psb_pm_ops = {
|
||||
.resume = gma_power_resume,
|
||||
.suspend = gma_power_suspend,
|
||||
.thaw = gma_power_thaw,
|
||||
.freeze = gma_power_freeze,
|
||||
.restore = gma_power_restore,
|
||||
.runtime_suspend = psb_runtime_suspend,
|
||||
.runtime_resume = psb_runtime_resume,
|
||||
.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_TOPAZ (1 << 10)
|
||||
|
||||
extern int drm_psb_no_fb;
|
||||
extern int drm_idle_check_interval;
|
||||
|
||||
/*
|
||||
|
|
|
@ -50,119 +50,41 @@ struct psb_intel_p2_t {
|
|||
int p2_slow, p2_fast;
|
||||
};
|
||||
|
||||
#define INTEL_P2_NUM 2
|
||||
|
||||
struct psb_intel_limit_t {
|
||||
struct psb_intel_range_t dot, vco, n, m, m1, m2, p, p1;
|
||||
struct psb_intel_p2_t p2;
|
||||
};
|
||||
|
||||
#define I8XX_DOT_MIN 25000
|
||||
#define I8XX_DOT_MAX 350000
|
||||
#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
|
||||
#define INTEL_LIMIT_I9XX_SDVO_DAC 0
|
||||
#define INTEL_LIMIT_I9XX_LVDS 1
|
||||
|
||||
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 */
|
||||
.dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
|
||||
.vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX},
|
||||
.n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX},
|
||||
.m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX},
|
||||
.m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX},
|
||||
.m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX},
|
||||
.p = {.min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX},
|
||||
.p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX},
|
||||
.p2 = {.dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
|
||||
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast =
|
||||
I9XX_P2_SDVO_DAC_FAST},
|
||||
.dot = {.min = 20000, .max = 400000},
|
||||
.vco = {.min = 1400000, .max = 2800000},
|
||||
.n = {.min = 1, .max = 6},
|
||||
.m = {.min = 70, .max = 120},
|
||||
.m1 = {.min = 8, .max = 18},
|
||||
.m2 = {.min = 3, .max = 7},
|
||||
.p = {.min = 5, .max = 80},
|
||||
.p1 = {.min = 1, .max = 8},
|
||||
.p2 = {.dot_limit = 200000,
|
||||
.p2_slow = 10, .p2_fast = 5},
|
||||
},
|
||||
{ /* INTEL_LIMIT_I9XX_LVDS */
|
||||
.dot = {.min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
|
||||
.vco = {.min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX},
|
||||
.n = {.min = I9XX_N_MIN, .max = I9XX_N_MAX},
|
||||
.m = {.min = I9XX_M_MIN, .max = I9XX_M_MAX},
|
||||
.m1 = {.min = I9XX_M1_MIN, .max = I9XX_M1_MAX},
|
||||
.m2 = {.min = I9XX_M2_MIN, .max = I9XX_M2_MAX},
|
||||
.p = {.min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX},
|
||||
.p1 = {.min = I9XX_P1_MIN, .max = I9XX_P1_MAX},
|
||||
.dot = {.min = 20000, .max = 400000},
|
||||
.vco = {.min = 1400000, .max = 2800000},
|
||||
.n = {.min = 1, .max = 6},
|
||||
.m = {.min = 70, .max = 120},
|
||||
.m1 = {.min = 8, .max = 18},
|
||||
.m2 = {.min = 3, .max = 7},
|
||||
.p = {.min = 7, .max = 98},
|
||||
.p1 = {.min = 1, .max = 8},
|
||||
/* The single-channel range is 25-112Mhz, and dual-channel
|
||||
* is 80-224Mhz. Prefer single channel as much as possible.
|
||||
*/
|
||||
.p2 = {.dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
|
||||
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST},
|
||||
.p2 = {.dot_limit = 112000,
|
||||
.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;
|
||||
}
|
||||
|
||||
/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
|
||||
|
||||
static void i8xx_clock(int refclk, struct psb_intel_clock_t *clock)
|
||||
static void psb_intel_clock(int refclk, struct psb_intel_clock_t *clock)
|
||||
{
|
||||
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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
|
||||
*/
|
||||
|
@ -308,7 +212,7 @@ static bool psb_intel_find_best_PLL(struct drm_crtc *crtc, int target,
|
|||
clock.p1++) {
|
||||
int this_err;
|
||||
|
||||
psb_intel_clock(dev, refclk, &clock);
|
||||
psb_intel_clock(refclk, &clock);
|
||||
|
||||
if (!psb_intel_PLL_is_valid
|
||||
(crtc, &clock))
|
||||
|
@ -1068,7 +972,7 @@ static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
|
|||
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)
|
||||
{
|
||||
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) ==
|
||||
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
|
||||
/* XXX: might not be 66MHz */
|
||||
i8xx_clock(66000, &clock);
|
||||
psb_intel_clock(66000, &clock);
|
||||
} else
|
||||
i8xx_clock(48000, &clock);
|
||||
psb_intel_clock(48000, &clock);
|
||||
} else {
|
||||
if (dpll & PLL_P1_DIVIDE_BY_TWO)
|
||||
clock.p1 = 2;
|
||||
|
@ -1166,7 +1070,7 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
|
|||
else
|
||||
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
|
||||
|
@ -1225,7 +1129,7 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
|
|||
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 gtt_range *gt;
|
||||
|
|
|
@ -21,8 +21,5 @@
|
|||
#define _INTEL_DISPLAY_H_
|
||||
|
||||
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
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
/* maximum connectors per crtcs in the mode set */
|
||||
#define INTELFB_CONN_LIMIT 4
|
||||
|
||||
#define INTEL_I2C_BUS_DVO 1
|
||||
#define INTEL_I2C_BUS_SDVO 2
|
||||
|
||||
/* Intel Pipe Clone Bit */
|
||||
#define INTEL_HDMIB_CLONE_BIT 1
|
||||
#define INTEL_HDMIC_CLONE_BIT 2
|
||||
|
@ -68,11 +65,6 @@
|
|||
#define INTEL_OUTPUT_DISPLAYPORT 9
|
||||
#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_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
|
||||
|
||||
|
|
|
@ -493,7 +493,6 @@
|
|||
#define PIPEACONF_DISABLE 0
|
||||
#define PIPEACONF_DOUBLE_WIDE (1 << 30)
|
||||
#define PIPECONF_ACTIVE (1 << 30)
|
||||
#define I965_PIPECONF_ACTIVE (1 << 30)
|
||||
#define PIPECONF_DSIPLL_LOCK (1 << 29)
|
||||
#define PIPEACONF_SINGLE_WIDE 0
|
||||
#define PIPEACONF_PIPE_UNLOCKED 0
|
||||
|
|
|
@ -134,6 +134,9 @@ struct psb_intel_sdvo {
|
|||
|
||||
/* Input timings for adjusted_mode */
|
||||
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 {
|
||||
|
@ -1830,6 +1833,34 @@ done:
|
|||
#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 = {
|
||||
.dpms = psb_intel_sdvo_dpms,
|
||||
.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 = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.save = psb_intel_sdvo_save,
|
||||
.restore = psb_intel_sdvo_restore,
|
||||
.detect = psb_intel_sdvo_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.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);
|
||||
|
||||
if (vdc_stat & _PSB_PIPE_EVENT_FLAG)
|
||||
if (vdc_stat & (_PSB_PIPE_EVENT_FLAG|_PSB_IRQ_ASLE))
|
||||
dsp_int = 1;
|
||||
|
||||
/* FIXME: Handle Medfield
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef _SYSIRQ_H_
|
||||
#define _SYSIRQ_H_
|
||||
#ifndef _PSB_IRQ_H_
|
||||
#define _PSB_IRQ_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);
|
||||
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)
|
||||
|
@ -849,76 +866,42 @@ static const struct file_operations i915_error_state_fops = {
|
|||
.release = i915_error_state_release,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
i915_next_seqno_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_next_seqno_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[80];
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"next_seqno : 0x%x\n",
|
||||
dev_priv->next_seqno);
|
||||
|
||||
*val = dev_priv->next_seqno;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_next_seqno_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_next_seqno_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
char buf[20];
|
||||
u32 val = 1;
|
||||
struct drm_device *dev = data;
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_gem_set_seqno(dev, val);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return ret ?: cnt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_next_seqno_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_next_seqno_read,
|
||||
.write = i915_next_seqno_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops,
|
||||
i915_next_seqno_get, i915_next_seqno_set,
|
||||
"0x%llx\n");
|
||||
|
||||
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;
|
||||
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
|
||||
max_freq * GT_FREQUENCY_MULTIPLIER);
|
||||
|
||||
seq_printf(m, "Max overclocked frequency: %dMHz\n",
|
||||
dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
|
||||
} else {
|
||||
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)
|
||||
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;
|
||||
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,
|
||||
GEN6_PCODE_READ_MIN_FREQ_TABLE,
|
||||
&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);
|
||||
|
@ -1680,105 +1669,51 @@ static int i915_dpio_info(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_wedged_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_wedged_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[80];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"wedged : %d\n",
|
||||
atomic_read(&dev_priv->gpu_error.reset_counter));
|
||||
*val = atomic_read(&dev_priv->gpu_error.reset_counter);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_wedged_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_wedged_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
char buf[20];
|
||||
int val = 1;
|
||||
struct drm_device *dev = data;
|
||||
|
||||
if (cnt > 0) {
|
||||
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);
|
||||
DRM_INFO("Manually setting wedged to %llu\n", val);
|
||||
i915_handle_error(dev, val);
|
||||
|
||||
return cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_wedged_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_wedged_read,
|
||||
.write = i915_wedged_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops,
|
||||
i915_wedged_get, i915_wedged_set,
|
||||
"%llu\n");
|
||||
|
||||
static ssize_t
|
||||
i915_ring_stop_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_ring_stop_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[20];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"0x%08x\n", dev_priv->gpu_error.stop_rings);
|
||||
*val = dev_priv->gpu_error.stop_rings;
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_ring_stop_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_ring_stop_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
char buf[20];
|
||||
int val = 0, 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;
|
||||
|
||||
val = simple_strtoul(buf, NULL, 0);
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
|
||||
DRM_DEBUG_DRIVER("Stopping rings 0x%08llx\n", val);
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
|
@ -1787,16 +1722,12 @@ i915_ring_stop_write(struct file *filp,
|
|||
dev_priv->gpu_error.stop_rings = val;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_ring_stop_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_ring_stop_read,
|
||||
.write = i915_ring_stop_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_ring_stop_fops,
|
||||
i915_ring_stop_get, i915_ring_stop_set,
|
||||
"0x%08llx\n");
|
||||
|
||||
#define DROP_UNBOUND 0x1
|
||||
#define DROP_BOUND 0x2
|
||||
|
@ -1806,46 +1737,23 @@ static const struct file_operations i915_ring_stop_fops = {
|
|||
DROP_BOUND | \
|
||||
DROP_RETIRE | \
|
||||
DROP_ACTIVE)
|
||||
static ssize_t
|
||||
i915_drop_caches_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_drop_caches_get(void *data, u64 *val)
|
||||
{
|
||||
char buf[20];
|
||||
int len;
|
||||
*val = DROP_ALL;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL);
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_drop_caches_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_drop_caches_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj, *next;
|
||||
char buf[20];
|
||||
int val = 0, 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;
|
||||
|
||||
val = simple_strtoul(buf, NULL, 0);
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val);
|
||||
DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val);
|
||||
|
||||
/* No need to check and wait for gpu resets, only libdrm auto-restarts
|
||||
* on ioctls on -EAGAIN. */
|
||||
|
@ -1883,27 +1791,19 @@ i915_drop_caches_write(struct file *filp,
|
|||
unlock:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return ret ?: cnt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_drop_caches_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_drop_caches_read,
|
||||
.write = i915_drop_caches_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_drop_caches_fops,
|
||||
i915_drop_caches_get, i915_drop_caches_set,
|
||||
"0x%08llx\n");
|
||||
|
||||
static ssize_t
|
||||
i915_max_freq_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_max_freq_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[80];
|
||||
int len, ret;
|
||||
int ret;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
@ -1912,42 +1812,23 @@ i915_max_freq_read(struct file *filp,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"max freq: %d\n", dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER);
|
||||
*val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_max_freq_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_max_freq_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
char buf[20];
|
||||
int val = 1, ret;
|
||||
int ret;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
||||
if (cnt > 0) {
|
||||
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);
|
||||
DRM_DEBUG_DRIVER("Manually setting max freq to %llu\n", val);
|
||||
|
||||
ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
|
||||
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.
|
||||
*/
|
||||
dev_priv->rps.max_delay = val / GT_FREQUENCY_MULTIPLIER;
|
||||
|
||||
gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
|
||||
do_div(val, GT_FREQUENCY_MULTIPLIER);
|
||||
dev_priv->rps.max_delay = val;
|
||||
gen6_set_rps(dev, val);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
return cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_max_freq_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_max_freq_read,
|
||||
.write = i915_max_freq_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops,
|
||||
i915_max_freq_get, i915_max_freq_set,
|
||||
"%llu\n");
|
||||
|
||||
static ssize_t
|
||||
i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_min_freq_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[80];
|
||||
int len, ret;
|
||||
int ret;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
@ -1988,40 +1863,23 @@ i915_min_freq_read(struct file *filp, char __user *ubuf, size_t max,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"min freq: %d\n", dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER);
|
||||
*val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_min_freq_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_min_freq_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
char buf[20];
|
||||
int val = 1, ret;
|
||||
int ret;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
||||
if (cnt > 0) {
|
||||
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);
|
||||
DRM_DEBUG_DRIVER("Manually setting min freq to %llu\n", val);
|
||||
|
||||
ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
|
||||
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.
|
||||
*/
|
||||
dev_priv->rps.min_delay = val / GT_FREQUENCY_MULTIPLIER;
|
||||
|
||||
gen6_set_rps(dev, val / GT_FREQUENCY_MULTIPLIER);
|
||||
do_div(val, GT_FREQUENCY_MULTIPLIER);
|
||||
dev_priv->rps.min_delay = val;
|
||||
gen6_set_rps(dev, val);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
return cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_min_freq_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_min_freq_read,
|
||||
.write = i915_min_freq_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops,
|
||||
i915_min_freq_get, i915_min_freq_set,
|
||||
"%llu\n");
|
||||
|
||||
static ssize_t
|
||||
i915_cache_sharing_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t max,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_cache_sharing_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
char buf[80];
|
||||
u32 snpcr;
|
||||
int len, ret;
|
||||
int ret;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
@ -2068,46 +1918,25 @@ i915_cache_sharing_read(struct file *filp,
|
|||
snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
|
||||
mutex_unlock(&dev_priv->dev->struct_mutex);
|
||||
|
||||
len = snprintf(buf, sizeof(buf),
|
||||
"%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >>
|
||||
GEN6_MBC_SNPCR_SHIFT);
|
||||
*val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT;
|
||||
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
|
||||
return simple_read_from_buffer(ubuf, max, ppos, buf, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
i915_cache_sharing_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt,
|
||||
loff_t *ppos)
|
||||
static int
|
||||
i915_cache_sharing_set(void *data, u64 val)
|
||||
{
|
||||
struct drm_device *dev = filp->private_data;
|
||||
struct drm_device *dev = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
char buf[20];
|
||||
u32 snpcr;
|
||||
int val = 1;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
||||
if (cnt > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (val < 0 || val > 3)
|
||||
if (val > 3)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val);
|
||||
DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val);
|
||||
|
||||
/* Update the cache sharing policy here as well */
|
||||
snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
|
||||
|
@ -2115,16 +1944,12 @@ i915_cache_sharing_write(struct file *filp,
|
|||
snpcr |= (val << GEN6_MBC_SNPCR_SHIFT);
|
||||
I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
|
||||
|
||||
return cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations i915_cache_sharing_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = simple_open,
|
||||
.read = i915_cache_sharing_read,
|
||||
.write = i915_cache_sharing_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
|
||||
i915_cache_sharing_get, i915_cache_sharing_set,
|
||||
"%llu\n");
|
||||
|
||||
/* As the drm_debugfs_init() routines are called before dev->dev_private is
|
||||
* 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. */
|
||||
/* FIXME: do pre/post-mode set stuff in core KMS code */
|
||||
dev->vblank_disable_allowed = 1;
|
||||
if (INTEL_INFO(dev)->num_pipes == 0) {
|
||||
dev_priv->mm.suspended = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = intel_fbdev_init(dev);
|
||||
if (ret)
|
||||
|
@ -1452,6 +1456,22 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
|
|||
#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
|
||||
* @dev: DRM device
|
||||
|
@ -1498,6 +1518,28 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
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);
|
||||
if (ret)
|
||||
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))
|
||||
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;
|
||||
|
||||
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->modeset_restore_lock);
|
||||
|
||||
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
|
||||
dev_priv->num_pipe = 3;
|
||||
else if (IS_MOBILE(dev) || !IS_GEN2(dev))
|
||||
dev_priv->num_pipe = 2;
|
||||
else
|
||||
dev_priv->num_pipe = 1;
|
||||
dev_priv->num_plane = 1;
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
dev_priv->num_plane = 2;
|
||||
|
||||
ret = drm_vblank_init(dev, dev_priv->num_pipe);
|
||||
if (ret)
|
||||
goto out_gem_unload;
|
||||
if (INTEL_INFO(dev)->num_pipes) {
|
||||
ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
|
||||
if (ret)
|
||||
goto out_gem_unload;
|
||||
}
|
||||
|
||||
/* Start out suspended */
|
||||
dev_priv->mm.suspended = 1;
|
||||
|
@ -1636,9 +1657,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
i915_setup_sysfs(dev);
|
||||
|
||||
/* Must be done after probing outputs */
|
||||
intel_opregion_init(dev);
|
||||
acpi_video_register();
|
||||
if (INTEL_INFO(dev)->num_pipes) {
|
||||
/* Must be done after probing outputs */
|
||||
intel_opregion_init(dev);
|
||||
acpi_video_register();
|
||||
}
|
||||
|
||||
if (IS_GEN5(dev))
|
||||
intel_gpu_ips_init(dev_priv);
|
||||
|
@ -1663,10 +1686,9 @@ out_mtrrfree:
|
|||
dev_priv->mm.gtt_mtrr = -1;
|
||||
}
|
||||
io_mapping_free(dev_priv->gtt.mappable);
|
||||
dev_priv->gtt.gtt_remove(dev);
|
||||
out_rmmap:
|
||||
pci_iounmap(dev->pdev, dev_priv->regs);
|
||||
put_gmch:
|
||||
dev_priv->gtt.gtt_remove(dev);
|
||||
put_bridge:
|
||||
pci_dev_put(dev_priv->bridge_dev);
|
||||
free_priv:
|
||||
|
|
|
@ -121,9 +121,7 @@ MODULE_PARM_DESC(i915_enable_ppgtt,
|
|||
unsigned int i915_preliminary_hw_support __read_mostly = 0;
|
||||
module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
|
||||
MODULE_PARM_DESC(preliminary_hw_support,
|
||||
"Enable preliminary hardware support. "
|
||||
"Enable Haswell and ValleyView Support. "
|
||||
"(default: false)");
|
||||
"Enable preliminary hardware support. (default: false)");
|
||||
|
||||
int i915_disable_power_well __read_mostly = 0;
|
||||
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, \
|
||||
.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 = {
|
||||
.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,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_845g_info = {
|
||||
.gen = 2,
|
||||
.gen = 2, .num_pipes = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
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,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i865g_info = {
|
||||
.gen = 2,
|
||||
.gen = 2, .num_pipes = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
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,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.supports_tv = 1,
|
||||
};
|
||||
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,
|
||||
};
|
||||
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_overlay = 1, .overlay_needs_physical = 1,
|
||||
.supports_tv = 1,
|
||||
};
|
||||
|
||||
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_overlay = 1,
|
||||
};
|
||||
|
||||
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,
|
||||
.has_overlay = 1,
|
||||
.supports_tv = 1,
|
||||
};
|
||||
|
||||
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,
|
||||
.has_overlay = 1,
|
||||
};
|
||||
|
||||
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_bsd_ring = 1,
|
||||
};
|
||||
|
||||
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,
|
||||
.has_pipe_cxsr = 1, .has_hotplug = 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 = {
|
||||
.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,
|
||||
.has_overlay = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ironlake_d_info = {
|
||||
.gen = 5,
|
||||
.gen = 5, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
};
|
||||
|
||||
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,
|
||||
.has_fbc = 1,
|
||||
.has_bsd_ring = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_d_info = {
|
||||
.gen = 6,
|
||||
.gen = 6, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_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 = {
|
||||
.gen = 6, .is_mobile = 1,
|
||||
.gen = 6, .is_mobile = 1, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 1,
|
||||
.has_bsd_ring = 1,
|
||||
|
@ -255,61 +263,57 @@ static const struct intel_device_info intel_sandybridge_m_info = {
|
|||
.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 = {
|
||||
.is_ivybridge = 1, .gen = 7,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
.has_force_wake = 1,
|
||||
GEN7_FEATURES,
|
||||
.is_ivybridge = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_m_info = {
|
||||
.is_ivybridge = 1, .gen = 7, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
.has_force_wake = 1,
|
||||
GEN7_FEATURES,
|
||||
.is_ivybridge = 1,
|
||||
.is_mobile = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_q_info = {
|
||||
GEN7_FEATURES,
|
||||
.is_ivybridge = 1,
|
||||
.num_pipes = 0, /* legal, last one wins */
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_valleyview_m_info = {
|
||||
.gen = 7, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 0,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
GEN7_FEATURES,
|
||||
.is_mobile = 1,
|
||||
.num_pipes = 2,
|
||||
.is_valleyview = 1,
|
||||
.display_mmio_offset = VLV_DISPLAY_BASE,
|
||||
.has_llc = 0, /* legal, last one wins */
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_valleyview_d_info = {
|
||||
.gen = 7,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 0,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
GEN7_FEATURES,
|
||||
.num_pipes = 2,
|
||||
.is_valleyview = 1,
|
||||
.display_mmio_offset = VLV_DISPLAY_BASE,
|
||||
.has_llc = 0, /* legal, last one wins */
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_d_info = {
|
||||
.is_haswell = 1, .gen = 7,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
.has_force_wake = 1,
|
||||
GEN7_FEATURES,
|
||||
.is_haswell = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_m_info = {
|
||||
.is_haswell = 1, .gen = 7, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
.has_force_wake = 1,
|
||||
GEN7_FEATURES,
|
||||
.is_haswell = 1,
|
||||
.is_mobile = 1,
|
||||
};
|
||||
|
||||
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(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
|
||||
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(0x0402, &intel_haswell_d_info), /* GT1 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(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */
|
||||
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(0x0155, &intel_valleyview_d_info),
|
||||
{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 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
|
||||
* 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;
|
||||
DRM_DEBUG_KMS("Found LynxPoint PCH\n");
|
||||
WARN_ON(!IS_HASWELL(dev));
|
||||
WARN_ON(IS_ULT(dev));
|
||||
} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
|
||||
dev_priv->pch_type = PCH_LPT;
|
||||
dev_priv->num_pch_pll = 0;
|
||||
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
|
||||
WARN_ON(!IS_HASWELL(dev));
|
||||
WARN_ON(!IS_ULT(dev));
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
/* ignore lid events during suspend */
|
||||
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);
|
||||
|
||||
intel_modeset_disable(dev);
|
||||
|
||||
drm_irq_uninstall(dev);
|
||||
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);
|
||||
|
@ -556,6 +580,24 @@ void intel_console_resume(struct work_struct *work)
|
|||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -588,6 +633,8 @@ static int __i915_drm_thaw(struct drm_device *dev)
|
|||
* */
|
||||
intel_hpd_init(dev);
|
||||
dev_priv->enable_hotplug_processing = true;
|
||||
/* Config may have changed between suspend and resume */
|
||||
intel_resume_hotplug(dev);
|
||||
}
|
||||
|
||||
intel_opregion_init(dev);
|
||||
|
@ -732,6 +779,7 @@ static int ironlake_do_reset(struct drm_device *dev)
|
|||
int ret;
|
||||
|
||||
gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
|
||||
gdrst &= ~GRDOM_MASK;
|
||||
I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
|
||||
gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
|
||||
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 ... */
|
||||
gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
|
||||
gdrst &= ~GRDOM_MASK;
|
||||
I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
|
||||
gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
|
||||
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. */
|
||||
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;
|
||||
if (ret == -ENODEV) {
|
||||
DRM_ERROR("Reset not implemented, but ignoring "
|
||||
|
@ -882,7 +931,11 @@ int i915_reset(struct drm_device *dev)
|
|||
ring->init(ring);
|
||||
|
||||
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
|
||||
|
@ -1147,6 +1200,27 @@ ilk_dummy_write(struct drm_i915_private *dev_priv)
|
|||
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) \
|
||||
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
|
||||
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)) \
|
||||
ilk_dummy_write(dev_priv); \
|
||||
if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
|
||||
DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \
|
||||
I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \
|
||||
} \
|
||||
hsw_unclaimed_reg_clear(dev_priv, reg); \
|
||||
write##y(val, dev_priv->regs + reg); \
|
||||
if (unlikely(__fifo_ret)) { \
|
||||
gen6_gt_check_fifodbg(dev_priv); \
|
||||
} \
|
||||
if (IS_HASWELL(dev_priv->dev) && (I915_READ_NOTRACE(GEN7_ERR_INT) & ERR_INT_MMIO_UNCLAIMED)) { \
|
||||
DRM_ERROR("Unclaimed write to %x\n", reg); \
|
||||
writel(ERR_INT_MMIO_UNCLAIMED, dev_priv->regs + GEN7_ERR_INT); \
|
||||
} \
|
||||
hsw_unclaimed_reg_check(dev_priv, reg); \
|
||||
}
|
||||
__i915_write(8, b)
|
||||
__i915_write(16, w)
|
||||
|
|
|
@ -86,6 +86,19 @@ enum port {
|
|||
};
|
||||
#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 \
|
||||
(I915_GEM_DOMAIN_RENDER | \
|
||||
I915_GEM_DOMAIN_SAMPLER | \
|
||||
|
@ -93,7 +106,7 @@ enum port {
|
|||
I915_GEM_DOMAIN_INSTRUCTION | \
|
||||
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) \
|
||||
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;
|
||||
};
|
||||
#define I915_FENCE_REG_NONE -1
|
||||
#define I915_MAX_NUM_FENCES 16
|
||||
/* 16 fences + sign bit for FENCE_REG_NONE */
|
||||
#define I915_MAX_NUM_FENCE_BITS 5
|
||||
#define I915_MAX_NUM_FENCES 32
|
||||
/* 32 fences + sign bit for FENCE_REG_NONE */
|
||||
#define I915_MAX_NUM_FENCE_BITS 6
|
||||
|
||||
struct drm_i915_fence_reg {
|
||||
struct list_head lru_list;
|
||||
|
@ -243,7 +256,7 @@ struct drm_i915_error_state {
|
|||
int page_count;
|
||||
u32 gtt_offset;
|
||||
u32 *pages[0];
|
||||
} *ringbuffer, *batchbuffer;
|
||||
} *ringbuffer, *batchbuffer, *ctx;
|
||||
struct drm_i915_error_request {
|
||||
long jiffies;
|
||||
u32 seqno;
|
||||
|
@ -271,6 +284,9 @@ struct drm_i915_error_state {
|
|||
struct intel_display_error_state *display;
|
||||
};
|
||||
|
||||
struct intel_crtc_config;
|
||||
struct intel_crtc;
|
||||
|
||||
struct drm_i915_display_funcs {
|
||||
bool (*fbc_enabled)(struct drm_device *dev);
|
||||
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,
|
||||
struct drm_display_mode *mode);
|
||||
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,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
void (*crtc_enable)(struct drm_crtc *crtc);
|
||||
|
@ -341,6 +359,7 @@ struct drm_i915_gt_funcs {
|
|||
|
||||
struct intel_device_info {
|
||||
u32 display_mmio_offset;
|
||||
u8 num_pipes:3;
|
||||
u8 gen;
|
||||
u8 is_mobile:1;
|
||||
u8 is_i85x:1;
|
||||
|
@ -430,6 +449,7 @@ struct i915_hw_ppgtt {
|
|||
struct sg_table *st,
|
||||
unsigned int pg_start,
|
||||
enum i915_cache_level cache_level);
|
||||
int (*enable)(struct drm_device *dev);
|
||||
void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
|
||||
};
|
||||
|
||||
|
@ -460,6 +480,7 @@ enum intel_pch {
|
|||
PCH_IBX, /* Ibexpeak PCH */
|
||||
PCH_CPT, /* Cougarpoint PCH */
|
||||
PCH_LPT, /* Lynxpoint PCH */
|
||||
PCH_NOP,
|
||||
};
|
||||
|
||||
enum intel_sbi_destination {
|
||||
|
@ -647,6 +668,7 @@ struct intel_gen6_power_mgmt {
|
|||
u8 cur_delay;
|
||||
u8 min_delay;
|
||||
u8 max_delay;
|
||||
u8 hw_max;
|
||||
|
||||
struct delayed_work delayed_resume_work;
|
||||
|
||||
|
@ -905,16 +927,24 @@ typedef struct drm_i915_private {
|
|||
struct mutex dpio_lock;
|
||||
|
||||
/** Cached value of IMR to avoid reads in updating the bitfield */
|
||||
u32 pipestat[2];
|
||||
u32 irq_mask;
|
||||
u32 gt_irq_mask;
|
||||
|
||||
u32 hotplug_supported_mask;
|
||||
struct work_struct hotplug_work;
|
||||
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_plane;
|
||||
|
||||
unsigned long cfb_size;
|
||||
unsigned int cfb_fb;
|
||||
|
@ -928,9 +958,14 @@ typedef struct drm_i915_private {
|
|||
struct intel_overlay *overlay;
|
||||
unsigned int sprite_scaling_enabled;
|
||||
|
||||
/* backlight */
|
||||
struct {
|
||||
int level;
|
||||
bool enabled;
|
||||
struct backlight_device *device;
|
||||
} backlight;
|
||||
|
||||
/* 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 *sdvo_lvds_vbt_mode; /* if any */
|
||||
|
||||
|
@ -941,6 +976,7 @@ typedef struct drm_i915_private {
|
|||
unsigned int int_crt_support:1;
|
||||
unsigned int lvds_use_ssc:1;
|
||||
unsigned int display_clock_mode:1;
|
||||
unsigned int fdi_rx_polarity_inverted:1;
|
||||
int lvds_ssc_freq;
|
||||
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
|
||||
struct {
|
||||
|
@ -1032,8 +1068,6 @@ typedef struct drm_i915_private {
|
|||
*/
|
||||
struct work_struct console_resume_work;
|
||||
|
||||
struct backlight_device *backlight;
|
||||
|
||||
struct drm_property *broadcast_rgb_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_DDI(dev) (IS_HASWELL(dev))
|
||||
#define HAS_POWER_WELL(dev) (IS_HASWELL(dev))
|
||||
|
||||
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
|
||||
#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_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
|
||||
#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_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);
|
||||
static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
|
||||
{
|
||||
struct scatterlist *sg = obj->pages->sgl;
|
||||
int nents = obj->pages->nents;
|
||||
while (nents > SG_MAX_SINGLE_ALLOC) {
|
||||
if (n < SG_MAX_SINGLE_ALLOC - 1)
|
||||
break;
|
||||
struct sg_page_iter sg_iter;
|
||||
|
||||
sg = sg_chain_ptr(sg + SG_MAX_SINGLE_ALLOC - 1);
|
||||
n -= SG_MAX_SINGLE_ALLOC - 1;
|
||||
nents -= SG_MAX_SINGLE_ALLOC - 1;
|
||||
}
|
||||
return sg_page(sg+n);
|
||||
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n)
|
||||
return sg_page_iter_page(&sg_iter);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
void i915_gem_l3_remap(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);
|
||||
int __must_check i915_gpu_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);
|
||||
struct drm_i915_gem_object *
|
||||
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);
|
||||
|
||||
/* 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_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) \
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void __user *to_user_ptr(u64 address)
|
||||
{
|
||||
return (void __user *)(uintptr_t)address;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -411,10 +411,9 @@ i915_gem_shmem_pread(struct drm_device *dev,
|
|||
int obj_do_bit17_swizzling, page_do_bit17_swizzling;
|
||||
int prefaulted = 0;
|
||||
int needs_clflush = 0;
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
struct sg_page_iter sg_iter;
|
||||
|
||||
user_data = (char __user *) (uintptr_t) args->data_ptr;
|
||||
user_data = to_user_ptr(args->data_ptr);
|
||||
remain = args->size;
|
||||
|
||||
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;
|
||||
|
||||
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
|
||||
struct page *page;
|
||||
|
||||
if (i < offset >> PAGE_SHIFT)
|
||||
continue;
|
||||
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
|
||||
offset >> PAGE_SHIFT) {
|
||||
struct page *page = sg_page_iter_page(&sg_iter);
|
||||
|
||||
if (remain <= 0)
|
||||
break;
|
||||
|
@ -460,7 +457,6 @@ i915_gem_shmem_pread(struct drm_device *dev,
|
|||
if ((shmem_page_offset + page_length) > PAGE_SIZE)
|
||||
page_length = PAGE_SIZE - shmem_page_offset;
|
||||
|
||||
page = sg_page(sg);
|
||||
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
|
||||
(page_to_phys(page) & (1 << 17)) != 0;
|
||||
|
||||
|
@ -522,7 +518,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
|
|||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE,
|
||||
(char __user *)(uintptr_t)args->data_ptr,
|
||||
to_user_ptr(args->data_ptr),
|
||||
args->size))
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -613,7 +609,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
|
|||
if (ret)
|
||||
goto out_unpin;
|
||||
|
||||
user_data = (char __user *) (uintptr_t) args->data_ptr;
|
||||
user_data = to_user_ptr(args->data_ptr);
|
||||
remain = args->size;
|
||||
|
||||
offset = obj->gtt_offset + args->offset;
|
||||
|
@ -732,10 +728,9 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
|
|||
int hit_slowpath = 0;
|
||||
int needs_clflush_after = 0;
|
||||
int needs_clflush_before = 0;
|
||||
int i;
|
||||
struct scatterlist *sg;
|
||||
struct sg_page_iter sg_iter;
|
||||
|
||||
user_data = (char __user *) (uintptr_t) args->data_ptr;
|
||||
user_data = to_user_ptr(args->data_ptr);
|
||||
remain = args->size;
|
||||
|
||||
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;
|
||||
obj->dirty = 1;
|
||||
|
||||
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i) {
|
||||
struct page *page;
|
||||
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
|
||||
offset >> PAGE_SHIFT) {
|
||||
struct page *page = sg_page_iter_page(&sg_iter);
|
||||
int partial_cacheline_write;
|
||||
|
||||
if (i < offset >> PAGE_SHIFT)
|
||||
continue;
|
||||
|
||||
if (remain <= 0)
|
||||
break;
|
||||
|
||||
|
@ -796,7 +789,6 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
|
|||
((shmem_page_offset | page_length)
|
||||
& (boot_cpu_data.x86_clflush_size - 1));
|
||||
|
||||
page = sg_page(sg);
|
||||
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
|
||||
(page_to_phys(page) & (1 << 17)) != 0;
|
||||
|
||||
|
@ -867,11 +859,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
|
|||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_READ,
|
||||
(char __user *)(uintptr_t)args->data_ptr,
|
||||
to_user_ptr(args->data_ptr),
|
||||
args->size))
|
||||
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);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
@ -1633,9 +1625,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
|
|||
static void
|
||||
i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
int page_count = obj->base.size / PAGE_SIZE;
|
||||
struct scatterlist *sg;
|
||||
int ret, i;
|
||||
struct sg_page_iter sg_iter;
|
||||
int ret;
|
||||
|
||||
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)
|
||||
obj->dirty = 0;
|
||||
|
||||
for_each_sg(obj->pages->sgl, sg, page_count, i) {
|
||||
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);
|
||||
|
||||
if (obj->dirty)
|
||||
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 sg_table *st;
|
||||
struct scatterlist *sg;
|
||||
struct sg_page_iter sg_iter;
|
||||
struct page *page;
|
||||
unsigned long last_pfn = 0; /* suppress gcc warning */
|
||||
gfp_t gfp;
|
||||
|
||||
/* 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 |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
|
||||
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);
|
||||
if (IS_ERR(page)) {
|
||||
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);
|
||||
}
|
||||
|
||||
sg_set_page(sg, page, PAGE_SIZE, 0);
|
||||
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);
|
||||
} else {
|
||||
sg->length += PAGE_SIZE;
|
||||
}
|
||||
last_pfn = page_to_pfn(page);
|
||||
}
|
||||
|
||||
sg_mark_end(sg);
|
||||
obj->pages = st;
|
||||
|
||||
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;
|
||||
|
||||
err_pages:
|
||||
for_each_sg(st->sgl, sg, i, page_count)
|
||||
page_cache_release(sg_page(sg));
|
||||
sg_mark_end(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);
|
||||
kfree(st);
|
||||
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++) {
|
||||
struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
|
||||
|
||||
i915_gem_write_fence(dev, i, NULL);
|
||||
|
||||
if (reg->obj)
|
||||
i915_gem_object_fence_lost(reg->obj);
|
||||
|
||||
i915_gem_write_fence(dev, i, NULL);
|
||||
|
||||
reg->pin_count = 0;
|
||||
reg->obj = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
static void i915_gem_write_fence__ipi(void *data)
|
||||
{
|
||||
wbinvd();
|
||||
}
|
||||
|
||||
static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
|
||||
struct drm_i915_fence_reg *fence,
|
||||
bool enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
|
||||
int reg = fence_number(dev_priv, fence);
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
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) {
|
||||
obj->fence_reg = reg;
|
||||
obj->fence_reg = fence_reg;
|
||||
fence->obj = obj;
|
||||
list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
|
||||
} else {
|
||||
|
@ -2717,6 +2740,7 @@ int
|
|||
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_fence_reg *fence;
|
||||
int ret;
|
||||
|
||||
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)
|
||||
return 0;
|
||||
|
||||
i915_gem_object_update_fence(obj,
|
||||
&dev_priv->fence_regs[obj->fence_reg],
|
||||
false);
|
||||
fence = &dev_priv->fence_regs[obj->fence_reg];
|
||||
|
||||
i915_gem_object_fence_lost(obj);
|
||||
i915_gem_object_update_fence(obj, fence, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3986,6 +4010,12 @@ i915_gem_init_hw(struct drm_device *dev)
|
|||
if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1))
|
||||
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_init_swizzling(dev);
|
||||
|
@ -3999,7 +4029,13 @@ i915_gem_init_hw(struct drm_device *dev)
|
|||
* contexts before PPGTT.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
@ -4010,7 +4046,16 @@ int i915_gem_init(struct drm_device *dev)
|
|||
int ret;
|
||||
|
||||
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);
|
||||
|
||||
ret = i915_gem_init_hw(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (ret) {
|
||||
|
@ -4145,7 +4190,9 @@ i915_gem_load(struct drm_device *dev)
|
|||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
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;
|
||||
else
|
||||
dev_priv->num_fence_regs = 8;
|
||||
|
@ -4327,7 +4374,7 @@ i915_gem_phys_pwrite(struct drm_device *dev,
|
|||
struct drm_file *file_priv)
|
||||
{
|
||||
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)) {
|
||||
unsigned long unwritten;
|
||||
|
|
|
@ -152,6 +152,13 @@ create_hw_context(struct drm_device *dev,
|
|||
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
|
||||
* object tracking code. We give an initial ring value simple to pass an
|
||||
* 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;
|
||||
dst = st->sgl;
|
||||
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);
|
||||
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_device *dev = obj->base.dev;
|
||||
struct scatterlist *sg;
|
||||
struct sg_page_iter sg_iter;
|
||||
struct page **pages;
|
||||
int ret, i;
|
||||
|
||||
|
@ -124,14 +124,15 @@ static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf)
|
|||
|
||||
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)
|
||||
goto error;
|
||||
|
||||
for_each_sg(obj->pages->sgl, sg, obj->pages->nents, i)
|
||||
pages[i] = sg_page(sg);
|
||||
i = 0;
|
||||
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);
|
||||
|
||||
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.
|
||||
*/
|
||||
drm_gem_object_reference(&obj->base);
|
||||
dma_buf_put(dma_buf);
|
||||
return &obj->base;
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +281,8 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
|
|||
if (IS_ERR(attach))
|
||||
return ERR_CAST(attach);
|
||||
|
||||
get_dma_buf(dma_buf);
|
||||
|
||||
obj = i915_gem_object_alloc(dev);
|
||||
if (obj == NULL) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -300,5 +302,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
|
|||
|
||||
fail_detach:
|
||||
dma_buf_detach(dma_buf, attach);
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
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;
|
||||
int remain, ret;
|
||||
|
||||
user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
|
||||
user_relocs = to_user_ptr(entry->relocs_ptr);
|
||||
|
||||
remain = entry->relocation_count;
|
||||
while (remain) {
|
||||
|
@ -359,8 +359,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
|
|||
}
|
||||
|
||||
static int
|
||||
i915_gem_execbuffer_relocate(struct drm_device *dev,
|
||||
struct eb_objects *eb)
|
||||
i915_gem_execbuffer_relocate(struct eb_objects *eb)
|
||||
{
|
||||
struct drm_i915_gem_object *obj;
|
||||
int ret = 0;
|
||||
|
@ -475,7 +474,6 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj)
|
|||
|
||||
static int
|
||||
i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
|
||||
struct drm_file *file,
|
||||
struct list_head *objects,
|
||||
bool *need_relocs)
|
||||
{
|
||||
|
@ -618,7 +616,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
|
|||
u64 invalid_offset = (u64)-1;
|
||||
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,
|
||||
exec[i].relocation_count * sizeof(*reloc))) {
|
||||
|
@ -663,7 +661,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
|
|||
goto err;
|
||||
|
||||
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)
|
||||
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);
|
||||
|
||||
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() */
|
||||
|
||||
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 *
|
||||
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))
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -949,9 +951,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
|
|||
}
|
||||
|
||||
if (copy_from_user(cliprects,
|
||||
(struct drm_clip_rect __user *)(uintptr_t)
|
||||
args->cliprects_ptr,
|
||||
sizeof(*cliprects)*args->num_cliprects)) {
|
||||
to_user_ptr(args->cliprects_ptr),
|
||||
sizeof(*cliprects)*args->num_cliprects)) {
|
||||
ret = -EFAULT;
|
||||
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. */
|
||||
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)
|
||||
goto err;
|
||||
|
||||
/* The objects are in their final locations, apply the relocations. */
|
||||
if (need_relocs)
|
||||
ret = i915_gem_execbuffer_relocate(dev, eb);
|
||||
ret = i915_gem_execbuffer_relocate(eb);
|
||||
if (ret) {
|
||||
if (ret == -EFAULT) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (ret != 0) {
|
||||
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++)
|
||||
exec_list[i].offset = exec2_list[i].offset;
|
||||
/* ... 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,
|
||||
sizeof(*exec_list) * args->buffer_count);
|
||||
if (ret) {
|
||||
|
@ -1195,8 +1196,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
|
|||
return -ENOMEM;
|
||||
}
|
||||
ret = copy_from_user(exec2_list,
|
||||
(struct drm_i915_relocation_entry __user *)
|
||||
(uintptr_t) args->buffers_ptr,
|
||||
to_user_ptr(args->buffers_ptr),
|
||||
sizeof(*exec2_list) * args->buffer_count);
|
||||
if (ret != 0) {
|
||||
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);
|
||||
if (!ret) {
|
||||
/* 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,
|
||||
sizeof(*exec2_list) * args->buffer_count);
|
||||
if (ret) {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "i915_trace.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
typedef uint32_t gtt_pte_t;
|
||||
typedef uint32_t gen6_gtt_pte_t;
|
||||
|
||||
/* PPGTT stuff */
|
||||
#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_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
|
||||
|
||||
static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
|
||||
dma_addr_t addr,
|
||||
enum i915_cache_level level)
|
||||
static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
|
||||
dma_addr_t addr,
|
||||
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);
|
||||
|
||||
switch (level) {
|
||||
|
@ -72,18 +72,85 @@ static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev,
|
|||
BUG();
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
unsigned first_entry,
|
||||
unsigned num_entries)
|
||||
{
|
||||
gtt_pte_t *pt_vaddr;
|
||||
gtt_pte_t scratch_pte;
|
||||
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
gen6_gtt_pte_t *pt_vaddr, scratch_pte;
|
||||
unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
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)
|
||||
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++)
|
||||
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;
|
||||
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,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
gtt_pte_t *pt_vaddr;
|
||||
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
unsigned i, j, m, segment_len;
|
||||
dma_addr_t page_addr;
|
||||
struct scatterlist *sg;
|
||||
gen6_gtt_pte_t *pt_vaddr;
|
||||
unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
struct sg_page_iter sg_iter;
|
||||
|
||||
/* init sg walking */
|
||||
sg = pages->sgl;
|
||||
i = 0;
|
||||
segment_len = sg_dma_len(sg) >> PAGE_SHIFT;
|
||||
m = 0;
|
||||
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;
|
||||
|
||||
while (i < pages->nents) {
|
||||
pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]);
|
||||
page_addr = sg_page_iter_dma_address(&sg_iter);
|
||||
pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr,
|
||||
cache_level);
|
||||
if (++act_pte == I915_PPGTT_PT_ENTRIES) {
|
||||
kunmap_atomic(pt_vaddr);
|
||||
act_pt++;
|
||||
pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
|
||||
act_pte = 0;
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
first_pte = 0;
|
||||
act_pd++;
|
||||
}
|
||||
kunmap_atomic(pt_vaddr);
|
||||
}
|
||||
|
||||
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
|
||||
* entries. For aliasing ppgtt support we just steal them at the end for
|
||||
* now. */
|
||||
first_pd_entry_in_global_pt =
|
||||
gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES;
|
||||
first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
|
||||
|
||||
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
|
||||
ppgtt->enable = gen6_ppgtt_enable;
|
||||
ppgtt->clear_range = gen6_ppgtt_clear_range;
|
||||
ppgtt->insert_entries = gen6_ppgtt_insert_entries;
|
||||
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->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma;
|
||||
|
||||
ppgtt->clear_range(ppgtt, 0,
|
||||
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;
|
||||
|
||||
|
@ -256,8 +305,13 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
|
|||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
else
|
||||
BUG();
|
||||
|
||||
ret = gen6_ppgtt_init(ppgtt);
|
||||
if (ret)
|
||||
kfree(ppgtt);
|
||||
else
|
||||
|
@ -275,6 +329,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
|
|||
return;
|
||||
|
||||
ppgtt->cleanup(ppgtt);
|
||||
dev_priv->mm.aliasing_ppgtt = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
/* Certain Gen5 chipsets require require idling the GPU before
|
||||
* unmapping anything from the GTT when VT-d is enabled.
|
||||
|
@ -432,21 +429,16 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
|
|||
enum i915_cache_level level)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct scatterlist *sg = st->sgl;
|
||||
gtt_pte_t __iomem *gtt_entries =
|
||||
(gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
|
||||
int unused, i = 0;
|
||||
unsigned int len, m = 0;
|
||||
gen6_gtt_pte_t __iomem *gtt_entries =
|
||||
(gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
|
||||
int i = 0;
|
||||
struct sg_page_iter sg_iter;
|
||||
dma_addr_t addr;
|
||||
|
||||
for_each_sg(st->sgl, sg, st->nents, unused) {
|
||||
len = sg_dma_len(sg) >> PAGE_SHIFT;
|
||||
for (m = 0; m < len; m++) {
|
||||
addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
|
||||
iowrite32(gen6_pte_encode(dev, addr, level),
|
||||
>t_entries[i]);
|
||||
i++;
|
||||
}
|
||||
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
|
||||
addr = sg_page_iter_dma_address(&sg_iter);
|
||||
iowrite32(gen6_pte_encode(dev, addr, level), >t_entries[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* XXX: This serves as a posting read to make sure that the PTE has
|
||||
|
@ -472,8 +464,8 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
|
|||
unsigned int num_entries)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
gtt_pte_t scratch_pte;
|
||||
gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
|
||||
gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
|
||||
(gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
|
||||
const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
|
||||
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)) {
|
||||
int ret;
|
||||
/* PPGTT pdes are stolen from global gtt ptes, so shrink the
|
||||
* aperture accordingly when using aliasing ppgtt. */
|
||||
gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
|
||||
|
||||
if (INTEL_INFO(dev)->gen <= 7) {
|
||||
/* PPGTT pdes are stolen from global gtt ptes, so shrink the
|
||||
* aperture accordingly when using aliasing ppgtt. */
|
||||
gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_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);
|
||||
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);
|
||||
else
|
||||
*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);
|
||||
if (!dev_priv->gtt.gsm) {
|
||||
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 i915_gtt *gtt = &dev_priv->gtt;
|
||||
unsigned long gtt_size;
|
||||
int ret;
|
||||
|
||||
if (INTEL_INFO(dev)->gen <= 5) {
|
||||
|
@ -835,8 +831,6 @@ int i915_gem_gtt_init(struct drm_device *dev)
|
|||
if (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. */
|
||||
DRM_INFO("Memory usable by graphics device = %zdM\n",
|
||||
dev_priv->gtt.total >> 20);
|
||||
|
|
|
@ -312,6 +312,71 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
|
|||
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
|
||||
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;
|
||||
|
||||
/* check maximum stride & object size */
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
/* i965 stores the end address of the gtt mapping in the fence
|
||||
* reg, so dont bother to check the size */
|
||||
/* i965+ stores the end address of the gtt mapping in the fence
|
||||
* 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)
|
||||
return false;
|
||||
} 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 */
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
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 */
|
||||
if (stride < tile_width)
|
||||
return false;
|
||||
|
||||
if (stride & (stride - 1))
|
||||
return false;
|
||||
|
||||
|
@ -473,28 +476,29 @@ i915_gem_swizzle_page(struct page *page)
|
|||
void
|
||||
i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
int page_count = obj->base.size >> PAGE_SHIFT;
|
||||
struct sg_page_iter sg_iter;
|
||||
int i;
|
||||
|
||||
if (obj->bit_17 == NULL)
|
||||
return;
|
||||
|
||||
for_each_sg(obj->pages->sgl, sg, page_count, i) {
|
||||
struct page *page = sg_page(sg);
|
||||
i = 0;
|
||||
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;
|
||||
if ((new_bit_17 & 0x1) !=
|
||||
(test_bit(i, obj->bit_17) != 0)) {
|
||||
i915_gem_swizzle_page(page);
|
||||
set_page_dirty(page);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
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 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) {
|
||||
struct page *page = sg_page(sg);
|
||||
if (page_to_phys(page) & (1 << 17))
|
||||
i = 0;
|
||||
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
|
||||
if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17))
|
||||
__set_bit(i, obj->bit_17);
|
||||
else
|
||||
__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_RENDER (1<<2)
|
||||
#define GRDOM_MEDIA (3<<2)
|
||||
#define GRDOM_MASK (3<<2)
|
||||
#define GRDOM_RESET_ENABLE (1<<0)
|
||||
|
||||
#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */
|
||||
|
@ -121,10 +122,17 @@
|
|||
|
||||
#define GAM_ECOCHK 0x4090
|
||||
#define ECOCHK_SNB_BIT (1<<10)
|
||||
#define HSW_ECOCHK_ARB_PRIO_SOL (1<<6)
|
||||
#define ECOCHK_PPGTT_CACHE64B (0x3<<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 ECOBITS_SNB_BIT (1<<13)
|
||||
#define ECOBITS_PPGTT_CACHE64B (3<<8)
|
||||
#define ECOBITS_PPGTT_CACHE4B (0<<8)
|
||||
|
||||
|
@ -422,6 +430,7 @@
|
|||
|
||||
#define FENCE_REG_SANDYBRIDGE_0 0x100000
|
||||
#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32
|
||||
#define GEN7_FENCE_MAX_PITCH_VAL 0x0800
|
||||
|
||||
/* control register for cpu gtt access */
|
||||
#define TILECTL 0x101000
|
||||
|
@ -522,6 +531,9 @@
|
|||
#define GEN7_ERR_INT 0x44040
|
||||
#define ERR_INT_MMIO_UNCLAIMED (1<<13)
|
||||
|
||||
#define FPGA_DBG 0x42300
|
||||
#define FPGA_DBG_RM_NOCLAIM (1<<31)
|
||||
|
||||
#define DERRMR 0x44050
|
||||
|
||||
/* GM45+ chicken bits -- debug workaround bits that may be required
|
||||
|
@ -591,6 +603,7 @@
|
|||
#define I915_USER_INTERRUPT (1<<1)
|
||||
#define I915_ASLE_INTERRUPT (1<<0)
|
||||
#define I915_BSD_USER_INTERRUPT (1<<25)
|
||||
#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
|
||||
#define EIR 0x020b0
|
||||
#define EMR 0x020b4
|
||||
#define ESR 0x020b8
|
||||
|
@ -1197,6 +1210,9 @@
|
|||
|
||||
#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 */
|
||||
#define DCC 0x10200
|
||||
#define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0)
|
||||
|
@ -1637,6 +1653,12 @@
|
|||
#define SDVOC_HOTPLUG_INT_EN (1 << 25)
|
||||
#define TV_HOTPLUG_INT_EN (1 << 18)
|
||||
#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_ACTIVATION_PERIOD_32 (0 << 8)
|
||||
/* must use period 64 on GM45 according to docs */
|
||||
|
@ -1675,43 +1697,84 @@
|
|||
#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2)
|
||||
#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7)
|
||||
#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 SDVOB 0x61140
|
||||
#define SDVOC 0x61160
|
||||
#define SDVO_ENABLE (1 << 31)
|
||||
#define SDVO_PIPE_B_SELECT (1 << 30)
|
||||
#define SDVO_STALL_SELECT (1 << 29)
|
||||
#define SDVO_INTERRUPT_ENABLE (1 << 26)
|
||||
#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \
|
||||
SDVOB_HOTPLUG_INT_STATUS_I965 | \
|
||||
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_PIPE_SEL(pipe) ((pipe) << 30)
|
||||
#define SDVO_PIPE_SEL_MASK (1 << 30)
|
||||
#define SDVO_PIPE_B_SELECT (1 << 30)
|
||||
#define SDVO_STALL_SELECT (1 << 29)
|
||||
#define SDVO_INTERRUPT_ENABLE (1 << 26)
|
||||
/**
|
||||
* 915G/GM SDVO pixel multiplier.
|
||||
*
|
||||
* Programmed value is multiplier - 1, up to 5x.
|
||||
*
|
||||
* \sa DPLL_MD_UDI_MULTIPLIER_MASK
|
||||
*/
|
||||
#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
|
||||
#define SDVO_PORT_MULTIPLY_MASK (7 << 23)
|
||||
#define SDVO_PORT_MULTIPLY_SHIFT 23
|
||||
#define SDVO_PHASE_SELECT_MASK (15 << 19)
|
||||
#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
|
||||
#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
|
||||
#define SDVOC_GANG_MODE (1 << 16)
|
||||
#define SDVO_ENCODING_SDVO (0x0 << 10)
|
||||
#define SDVO_ENCODING_HDMI (0x2 << 10)
|
||||
/** 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_PHASE_SELECT_MASK (15 << 19)
|
||||
#define SDVO_PHASE_SELECT_DEFAULT (6 << 19)
|
||||
#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18)
|
||||
#define SDVOC_GANG_MODE (1 << 16) /* Port C only */
|
||||
#define SDVO_BORDER_ENABLE (1 << 7) /* SDVO only */
|
||||
#define SDVOB_PCIE_CONCURRENCY (1 << 3) /* Port B only */
|
||||
#define SDVO_DETECTED (1 << 2)
|
||||
/* Bits to be preserved when writing */
|
||||
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26))
|
||||
#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26))
|
||||
#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | \
|
||||
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 */
|
||||
#define DVOA 0x61120
|
||||
|
@ -1898,7 +1961,7 @@
|
|||
#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238)
|
||||
|
||||
/* 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_COMBINATION_MODE (1 << 30) /* gen4 only */
|
||||
#define BLM_PIPE_SELECT (1 << 29)
|
||||
|
@ -1917,7 +1980,7 @@
|
|||
#define BLM_PHASE_IN_COUNT_MASK (0xff << 8)
|
||||
#define BLM_PHASE_IN_INCR_SHIFT (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
|
||||
* complete cycle of the modulated backlight control.
|
||||
|
@ -1939,7 +2002,7 @@
|
|||
#define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe)
|
||||
#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
|
||||
* register layout machtes with gen4 BLC_PWM_CTL[12]. */
|
||||
|
@ -2589,14 +2652,14 @@
|
|||
#define _PIPEB_GMCH_DATA_M 0x71050
|
||||
|
||||
/* 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 PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25
|
||||
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
|
||||
#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 _PIPEB_GMCH_DATA_N 0x71054
|
||||
#define PIPE_GMCH_DATA_N_MASK (0xffffff)
|
||||
|
||||
/*
|
||||
* Computing Link M and N values for the Display Port link
|
||||
|
@ -2611,11 +2674,9 @@
|
|||
|
||||
#define _PIPEA_DP_LINK_M 0x70060
|
||||
#define _PIPEB_DP_LINK_M 0x71060
|
||||
#define PIPEA_DP_LINK_M_MASK (0xffffff)
|
||||
|
||||
#define _PIPEA_DP_LINK_N 0x70064
|
||||
#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_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_MASK (0x3f<<16)
|
||||
#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*/
|
||||
#define DRAIN_LATENCY_PRECISION_32 32
|
||||
|
@ -3233,6 +3296,63 @@
|
|||
#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
|
||||
#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 */
|
||||
#define VGACNTRL 0x71400
|
||||
# define VGA_DISP_DISABLE (1 << 31)
|
||||
|
@ -3282,8 +3402,6 @@
|
|||
|
||||
|
||||
#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 _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034)
|
||||
#define PIPE_DATA_N1_OFFSET 0
|
||||
|
@ -3456,6 +3574,9 @@
|
|||
#define DISP_ARB_CTL 0x45000
|
||||
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
|
||||
#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 */
|
||||
#define GEN7_COMMON_SLICE_CHICKEN1 0x7010
|
||||
|
@ -3508,7 +3629,11 @@
|
|||
#define SDE_PORTC_HOTPLUG (1 << 9)
|
||||
#define SDE_PORTB_HOTPLUG (1 << 8)
|
||||
#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_ERR (1 << 4)
|
||||
#define SDE_TRANSB_FIFO_UNDER (1 << 3)
|
||||
|
@ -3531,7 +3656,9 @@
|
|||
#define SDE_PORTC_HOTPLUG_CPT (1 << 22)
|
||||
#define SDE_PORTB_HOTPLUG_CPT (1 << 21)
|
||||
#define SDE_CRT_HOTPLUG_CPT (1 << 19)
|
||||
#define SDE_SDVOB_HOTPLUG_CPT (1 << 18)
|
||||
#define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \
|
||||
SDE_SDVOB_HOTPLUG_CPT | \
|
||||
SDE_PORTD_HOTPLUG_CPT | \
|
||||
SDE_PORTC_HOTPLUG_CPT | \
|
||||
SDE_PORTB_HOTPLUG_CPT)
|
||||
|
@ -3754,14 +3881,16 @@
|
|||
#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344
|
||||
#define HSW_VIDEO_DIP_GCP_B 0x61210
|
||||
|
||||
#define HSW_TVIDEO_DIP_CTL(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
|
||||
#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
|
||||
#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
|
||||
#define HSW_TVIDEO_DIP_GCP(pipe) \
|
||||
_PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
|
||||
#define HSW_TVIDEO_DIP_CTL(trans) \
|
||||
_TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
|
||||
#define HSW_TVIDEO_DIP_AVI_DATA(trans) \
|
||||
_TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
|
||||
#define HSW_TVIDEO_DIP_SPD_DATA(trans) \
|
||||
_TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
|
||||
#define HSW_TVIDEO_DIP_GCP(trans) \
|
||||
_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_HBLANK_B 0xe1004
|
||||
|
@ -3826,8 +3955,11 @@
|
|||
#define _TRANSA_CHICKEN2 0xf0064
|
||||
#define _TRANSB_CHICKEN2 0xf1064
|
||||
#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 FDIA_PHASE_SYNC_SHIFT_OVR 19
|
||||
|
@ -3976,34 +4108,6 @@
|
|||
#define FDI_PLL_CTL_1 0xfe000
|
||||
#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 LVDS_DETECTED (1 << 1)
|
||||
|
||||
|
@ -4020,6 +4124,15 @@
|
|||
#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c)
|
||||
#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_CONTROL 0xc7204
|
||||
#define PANEL_UNLOCK_REGS (0xabcd << 16)
|
||||
|
@ -4149,8 +4262,12 @@
|
|||
#define FORCEWAKE 0xA18C
|
||||
#define FORCEWAKE_VLV 0x1300b0
|
||||
#define FORCEWAKE_ACK_VLV 0x1300b4
|
||||
#define FORCEWAKE_MEDIA_VLV 0x1300b8
|
||||
#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc
|
||||
#define FORCEWAKE_ACK_HSW 0x130044
|
||||
#define FORCEWAKE_ACK 0x130090
|
||||
#define VLV_GTLC_WAKE_CTRL 0x130090
|
||||
#define VLV_GTLC_PW_STATUS 0x130094
|
||||
#define FORCEWAKE_MT 0xa188 /* multi-threaded */
|
||||
#define FORCEWAKE_KERNEL 0x1
|
||||
#define FORCEWAKE_USER 0x2
|
||||
|
@ -4184,6 +4301,7 @@
|
|||
#define GEN6_RPNSWREQ 0xA008
|
||||
#define GEN6_TURBO_DISABLE (1<<31)
|
||||
#define GEN6_FREQUENCY(x) ((x)<<25)
|
||||
#define HSW_FREQUENCY(x) ((x)<<24)
|
||||
#define GEN6_OFFSET(x) ((x)<<19)
|
||||
#define GEN6_AGGRESSIVE_TURBO (0<<15)
|
||||
#define GEN6_RC_VIDEO_FREQ 0xA00C
|
||||
|
@ -4274,6 +4392,21 @@
|
|||
#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245)
|
||||
#define GEN6_PCODE_DATA 0x138128
|
||||
#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_CORE_CPD_STATE_MASK (7<<4)
|
||||
|
|
|
@ -209,7 +209,8 @@ 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_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.saveLVDS = I915_READ(PCH_LVDS);
|
||||
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
|
||||
dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
|
||||
} else {
|
||||
dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
|
||||
dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
|
||||
|
@ -255,6 +256,7 @@ static void i915_save_display(struct drm_device *dev)
|
|||
static void i915_restore_display(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 mask = 0xffffffff;
|
||||
|
||||
/* Display arbitration */
|
||||
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))
|
||||
I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS);
|
||||
} else if (IS_MOBILE(dev) && !IS_I830(dev))
|
||||
I915_WRITE(LVDS, dev_priv->regfile.saveLVDS);
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
mask = ~LVDS_PORT_EN;
|
||||
|
||||
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))
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
@ -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);
|
||||
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
|
||||
|
@ -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);
|
||||
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
|
||||
|
@ -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);
|
||||
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);
|
||||
|
@ -215,7 +215,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
|
|||
ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
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)
|
||||
|
@ -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;
|
||||
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,
|
||||
|
@ -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_device *dev = minor->dev;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (val > non_oc_max)
|
||||
DRM_DEBUG("User requested overclocking to %d\n",
|
||||
val * GT_FREQUENCY_MULTIPLIER);
|
||||
|
||||
if (dev_priv->rps.cur_delay > 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;
|
||||
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,
|
||||
|
@ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
|
|||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
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);
|
||||
|
||||
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 {
|
||||
BUG();
|
||||
}
|
||||
return snprintf(buf, PAGE_SIZE, "%d", val);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||
}
|
||||
|
||||
static const struct attribute *gen6_attrs[] = {
|
||||
|
|
|
@ -351,12 +351,14 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
|||
dev_priv->lvds_ssc_freq =
|
||||
intel_bios_ssc_frequency(dev, general->ssc_freq);
|
||||
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_crt_support,
|
||||
dev_priv->lvds_use_ssc,
|
||||
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;
|
||||
u8 __iomem *bios = NULL;
|
||||
|
||||
if (HAS_PCH_NOP(dev))
|
||||
return -ENODEV;
|
||||
|
||||
init_vbt_defaults(dev_priv);
|
||||
|
||||
/* XXX Should this validation be moved to intel_opregion.c? */
|
||||
|
|
|
@ -127,7 +127,9 @@ struct bdb_general_features {
|
|||
/* bits 3 */
|
||||
u8 disable_smooth_vision: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 */
|
||||
u8 legacy_monitor_detect;
|
||||
|
|
|
@ -199,10 +199,14 @@ static int intel_crt_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool intel_crt_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static bool intel_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
pipe_config->has_pch_encoder = 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 = {
|
||||
.mode_fixup = intel_crt_mode_fixup,
|
||||
.mode_set = intel_crt_mode_set,
|
||||
};
|
||||
|
||||
|
@ -768,8 +771,11 @@ void intel_crt_init(struct drm_device *dev)
|
|||
else
|
||||
crt->adpa_reg = ADPA;
|
||||
|
||||
crt->base.compute_config = intel_crt_compute_config;
|
||||
crt->base.disable = intel_disable_crt;
|
||||
crt->base.enable = intel_enable_crt;
|
||||
if (I915_HAS_HOTPLUG(dev))
|
||||
crt->base.hpd_pin = HPD_CRT;
|
||||
if (HAS_DDI(dev))
|
||||
crt->base.get_hw_state = intel_ddi_get_hw_state;
|
||||
else
|
||||
|
@ -781,18 +787,14 @@ void intel_crt_init(struct drm_device *dev)
|
|||
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev))
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
else
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
if (!I915_HAS_HOTPLUG(dev))
|
||||
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
|
||||
/*
|
||||
* Configure the automatic hotplug detection stuff
|
||||
*/
|
||||
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
|
||||
* 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++;
|
||||
reg = SPLL_CTL;
|
||||
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,
|
||||
|
@ -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 intel_crtc *intel_crtc = to_intel_crtc(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;
|
||||
uint32_t temp;
|
||||
|
||||
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
|
||||
|
||||
temp = TRANS_MSA_SYNC_CLK;
|
||||
switch (intel_crtc->bpp) {
|
||||
switch (intel_crtc->config.pipe_bpp) {
|
||||
case 18:
|
||||
temp |= TRANS_MSA_6_BPC;
|
||||
break;
|
||||
|
@ -942,22 +945,20 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
|
|||
temp |= TRANS_MSA_12_BPC;
|
||||
break;
|
||||
default:
|
||||
temp |= TRANS_MSA_8_BPC;
|
||||
WARN(1, "%d bpp unsupported by DDI function\n",
|
||||
intel_crtc->bpp);
|
||||
BUG();
|
||||
}
|
||||
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_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
|
||||
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);
|
||||
int type = intel_encoder->type;
|
||||
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_SELECT_PORT(port);
|
||||
|
||||
switch (intel_crtc->bpp) {
|
||||
switch (intel_crtc->config.pipe_bpp) {
|
||||
case 18:
|
||||
temp |= TRANS_DDI_BPC_6;
|
||||
break;
|
||||
|
@ -980,8 +981,7 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
|
|||
temp |= TRANS_DDI_BPC_12;
|
||||
break;
|
||||
default:
|
||||
WARN(1, "%d bpp unsupported by transcoder DDI function\n",
|
||||
intel_crtc->bpp);
|
||||
BUG();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe)
|
||||
{
|
||||
uint32_t temp, ret;
|
||||
enum port port;
|
||||
enum port port = I915_MAX_PORTS;
|
||||
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
||||
pipe);
|
||||
int i;
|
||||
|
@ -1173,10 +1173,16 @@ static uint32_t intel_ddi_get_crtc_pll(struct drm_i915_private *dev_priv,
|
|||
port = i;
|
||||
}
|
||||
|
||||
ret = I915_READ(PORT_CLK_SEL(port));
|
||||
|
||||
DRM_DEBUG_KMS("Pipe %c connected to port %c using clock 0x%08x\n",
|
||||
pipe_name(pipe), port_name(port), ret);
|
||||
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));
|
||||
DRM_DEBUG_KMS("Pipe %c connected to port %c using clock "
|
||||
"0x%08x\n", pipe_name(pipe), port_name(port),
|
||||
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 intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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;
|
||||
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) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
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)
|
||||
|
@ -1467,19 +1473,17 @@ static void intel_ddi_destroy(struct drm_encoder *encoder)
|
|||
intel_dp_encoder_destroy(encoder);
|
||||
}
|
||||
|
||||
static bool intel_ddi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static bool intel_ddi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
||||
int type = intel_encoder->type;
|
||||
int type = 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)
|
||||
return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode);
|
||||
return intel_hdmi_compute_config(encoder, pipe_config);
|
||||
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 = {
|
||||
|
@ -1487,7 +1491,6 @@ static const struct drm_encoder_funcs intel_ddi_funcs = {
|
|||
};
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = {
|
||||
.mode_fixup = intel_ddi_mode_fixup,
|
||||
.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_encoder_helper_add(encoder, &intel_ddi_helper_funcs);
|
||||
|
||||
intel_encoder->compute_config = intel_ddi_compute_config;
|
||||
intel_encoder->enable = intel_enable_ddi;
|
||||
intel_encoder->pre_enable = intel_ddi_pre_enable;
|
||||
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)) &
|
||||
DDI_BUF_PORT_REVERSAL;
|
||||
if (hdmi_connector)
|
||||
intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port);
|
||||
else
|
||||
intel_dig_port->hdmi.sdvox_reg = 0;
|
||||
intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
|
||||
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
intel_dp_mode_valid(struct drm_connector *connector,
|
||||
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_connector *intel_connector = to_intel_connector(connector);
|
||||
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 (mode->hdisplay > fixed_mode->hdisplay)
|
||||
|
@ -219,9 +170,17 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
|||
|
||||
if (mode->vdisplay > fixed_mode->vdisplay)
|
||||
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;
|
||||
|
||||
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_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)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
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
|
||||
|
@ -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_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp_stat_reg, pp_ctrl_reg;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
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)) {
|
||||
WARN(1, "eDP powered off while attempting aux channel communication.\n");
|
||||
DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
|
||||
I915_READ(PCH_PP_STATUS),
|
||||
I915_READ(PCH_PP_CONTROL));
|
||||
I915_READ(pp_stat_reg),
|
||||
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 drm_device *dev = intel_dig_port->base.base.dev;
|
||||
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;
|
||||
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)
|
||||
if (has_aux_irq)
|
||||
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 *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 drm_device *dev = intel_dig_port->base.base.dev;
|
||||
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;
|
||||
int i, ret, recv_bytes;
|
||||
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);
|
||||
|
||||
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);
|
||||
/* The clock divider is based off the hrawclk,
|
||||
* 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 */
|
||||
else
|
||||
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);
|
||||
else
|
||||
} else {
|
||||
aux_clock_divider = intel_hrawclk(dev) / 2;
|
||||
}
|
||||
|
||||
if (IS_GEN6(dev))
|
||||
precharge = 3;
|
||||
|
@ -732,18 +661,26 @@ intel_dp_i2c_init(struct intel_dp *intel_dp,
|
|||
}
|
||||
|
||||
bool
|
||||
intel_dp_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
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;
|
||||
int lane_count, clock;
|
||||
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 bpp, mode_rate;
|
||||
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) {
|
||||
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,
|
||||
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)
|
||||
return false;
|
||||
|
@ -760,11 +699,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
|
|||
"max bw %02x pixel clock %iKHz\n",
|
||||
max_lane_count, bws[max_clock], adjusted_mode->clock);
|
||||
|
||||
if (!intel_dp_adjust_dithering(intel_dp, adjusted_mode, true))
|
||||
return false;
|
||||
/* 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);
|
||||
|
||||
bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24;
|
||||
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;
|
||||
|
||||
found:
|
||||
if (intel_dp->color_range_auto) {
|
||||
/*
|
||||
* See:
|
||||
|
@ -778,104 +734,38 @@ intel_dp_mode_fixup(struct drm_encoder *encoder,
|
|||
}
|
||||
|
||||
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);
|
||||
intel_dp->link_bw = bws[clock];
|
||||
intel_dp->lane_count = lane_count;
|
||||
adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
|
||||
pipe_config->pixel_target_clock = target_clock;
|
||||
|
||||
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);
|
||||
DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
|
||||
intel_dp->link_bw, intel_dp->lane_count,
|
||||
adjusted_mode->clock, bpp);
|
||||
DRM_DEBUG_KMS("DP link bw required %i available %i\n",
|
||||
mode_rate, link_avail);
|
||||
|
||||
if (mode_rate <= link_avail) {
|
||||
intel_dp->link_bw = bws[clock];
|
||||
intel_dp->lane_count = lane_count;
|
||||
adjusted_mode->clock = link_bw_clock;
|
||||
DRM_DEBUG_KMS("DP link bw %02x lane "
|
||||
"count %d clock %d bpp %d\n",
|
||||
intel_dp->link_bw, intel_dp->lane_count,
|
||||
adjusted_mode->clock, bpp);
|
||||
DRM_DEBUG_KMS("DP link bw required %i available %i\n",
|
||||
mode_rate, link_avail);
|
||||
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;
|
||||
intel_link_compute_m_n(bpp, lane_count,
|
||||
target_clock, adjusted_mode->clock,
|
||||
&pipe_config->dp_m_n);
|
||||
|
||||
/*
|
||||
* Find the lane count in the intel_encoder private
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
intel_dp->DP |= DP_PLL_FREQ_270MHZ;
|
||||
} 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;
|
||||
|
||||
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)
|
||||
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 */
|
||||
if (adjusted_mode->clock < 200000)
|
||||
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;
|
||||
}
|
||||
|
||||
if (is_cpu_edp(intel_dp))
|
||||
if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
|
||||
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_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",
|
||||
mask, value,
|
||||
I915_READ(PCH_PP_STATUS),
|
||||
I915_READ(PCH_PP_CONTROL));
|
||||
mask, value,
|
||||
I915_READ(pp_stat_reg),
|
||||
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",
|
||||
I915_READ(PCH_PP_STATUS),
|
||||
I915_READ(PCH_PP_CONTROL));
|
||||
I915_READ(pp_stat_reg),
|
||||
I915_READ(pp_ctrl_reg));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1075,9 +969,15 @@ static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp)
|
|||
* 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_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_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
u32 pp_stat_reg, pp_ctrl_reg;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
return;
|
||||
|
@ -1107,13 +1008,16 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
|
|||
if (!ironlake_edp_have_panel_power(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;
|
||||
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
|
||||
*/
|
||||
|
@ -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_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
u32 pp_stat_reg, pp_ctrl_reg;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
|
||||
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;
|
||||
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 */
|
||||
DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n",
|
||||
I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL));
|
||||
|
||||
DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n",
|
||||
I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
|
||||
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_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
u32 pp_ctrl_reg;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
return;
|
||||
|
@ -1197,7 +1106,7 @@ void ironlake_edp_panel_on(struct intel_dp *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)) {
|
||||
/* ILK workaround: disable reset around power sequence */
|
||||
pp &= ~PANEL_POWER_RESET;
|
||||
|
@ -1209,8 +1118,10 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
|
|||
if (!IS_GEN5(dev))
|
||||
pp |= PANEL_POWER_RESET;
|
||||
|
||||
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);
|
||||
|
||||
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_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
u32 pp_ctrl_reg;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
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");
|
||||
|
||||
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
|
||||
* panels get very unhappy and cease to work. */
|
||||
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;
|
||||
|
||||
|
@ -1253,6 +1168,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipe = to_intel_crtc(intel_dig_port->base.base.crtc)->pipe;
|
||||
u32 pp;
|
||||
u32 pp_ctrl_reg;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
return;
|
||||
|
@ -1265,10 +1181,13 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
|
|||
* allowing it to appear.
|
||||
*/
|
||||
msleep(intel_dp->backlight_on_delay);
|
||||
pp = ironlake_get_pp_control(dev_priv);
|
||||
pp = ironlake_get_pp_control(intel_dp);
|
||||
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);
|
||||
}
|
||||
|
@ -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_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
u32 pp_ctrl_reg;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
return;
|
||||
|
@ -1285,10 +1205,13 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
|
|||
intel_panel_disable_backlight(dev);
|
||||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
pp = ironlake_get_pp_control(dev_priv);
|
||||
pp = ironlake_get_pp_control(intel_dp);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1384,7 +1307,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
|
|||
if (!(tmp & DP_PORT_EN))
|
||||
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);
|
||||
} else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
|
||||
*pipe = PORT_TO_PIPE(tmp);
|
||||
|
@ -1441,10 +1364,12 @@ static void intel_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 drm_device *dev = encoder->base.dev;
|
||||
|
||||
if (is_cpu_edp(intel_dp)) {
|
||||
intel_dp_link_down(intel_dp);
|
||||
ironlake_edp_pll_off(intel_dp);
|
||||
if (!IS_VALLEYVIEW(dev))
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
if (HAS_DDI(dev)) {
|
||||
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
|
||||
case DP_TRAIN_VOLTAGE_SWING_400:
|
||||
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;
|
||||
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);
|
||||
mask = DDI_BUF_EMP_MASK;
|
||||
} 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;
|
||||
uint32_t temp;
|
||||
|
||||
if (IS_HASWELL(dev)) {
|
||||
if (HAS_DDI(dev)) {
|
||||
temp = I915_READ(DP_TP_CTL(port));
|
||||
|
||||
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);
|
||||
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) {
|
||||
case PORT_B:
|
||||
bit = PORTB_HOTPLUG_LIVE_STATUS;
|
||||
|
@ -2492,6 +2428,9 @@ intel_dp_set_property(struct drm_connector *connector,
|
|||
}
|
||||
|
||||
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) {
|
||||
case INTEL_BROADCAST_RGB_AUTO:
|
||||
intel_dp->color_range_auto = true;
|
||||
|
@ -2507,6 +2446,11 @@ intel_dp_set_property(struct drm_connector *connector,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (old_auto == intel_dp->color_range_auto &&
|
||||
old_range == intel_dp->color_range)
|
||||
return 0;
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -2538,17 +2482,14 @@ done:
|
|||
static void
|
||||
intel_dp_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||
struct intel_connector *intel_connector = to_intel_connector(connector);
|
||||
|
||||
if (!IS_ERR_OR_NULL(intel_connector->edid))
|
||||
kfree(intel_connector->edid);
|
||||
|
||||
if (is_edp(intel_dp)) {
|
||||
intel_panel_destroy_backlight(dev);
|
||||
if (is_edp(intel_dp))
|
||||
intel_panel_fini(&intel_connector->panel);
|
||||
}
|
||||
|
||||
drm_sysfs_connector_remove(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 = {
|
||||
.mode_fixup = intel_dp_mode_fixup,
|
||||
.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 edp_power_seq cur, vbt, spec, final;
|
||||
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
|
||||
* the very first thing. */
|
||||
pp = ironlake_get_pp_control(dev_priv);
|
||||
I915_WRITE(PCH_PP_CONTROL, pp);
|
||||
pp = ironlake_get_pp_control(intel_dp);
|
||||
I915_WRITE(pp_control_reg, pp);
|
||||
|
||||
pp_on = I915_READ(PCH_PP_ON_DELAYS);
|
||||
pp_off = I915_READ(PCH_PP_OFF_DELAYS);
|
||||
pp_div = I915_READ(PCH_PP_DIVISOR);
|
||||
pp_on = I915_READ(pp_on_reg);
|
||||
pp_off = I915_READ(pp_off_reg);
|
||||
pp_div = I915_READ(pp_div_reg);
|
||||
|
||||
/* Pull timing values out of registers */
|
||||
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 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. */
|
||||
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);
|
||||
/* Compute the divisor for the pp clock, simply match the Bspec
|
||||
* formula. */
|
||||
pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1)
|
||||
<< PP_REFERENCE_DIVIDER_SHIFT;
|
||||
pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT;
|
||||
pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000)
|
||||
<< PANEL_POWER_CYCLE_DELAY_SHIFT);
|
||||
|
||||
|
@ -2770,19 +2737,21 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
|
|||
* power sequencer any more. */
|
||||
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
|
||||
if (is_cpu_edp(intel_dp))
|
||||
pp_on |= PANEL_POWER_PORT_DP_A;
|
||||
port_sel = PANEL_POWER_PORT_DP_A;
|
||||
else
|
||||
pp_on |= PANEL_POWER_PORT_DP_D;
|
||||
port_sel = PANEL_POWER_PORT_DP_D;
|
||||
}
|
||||
|
||||
I915_WRITE(PCH_PP_ON_DELAYS, pp_on);
|
||||
I915_WRITE(PCH_PP_OFF_DELAYS, pp_off);
|
||||
I915_WRITE(PCH_PP_DIVISOR, pp_div);
|
||||
pp_on |= port_sel;
|
||||
|
||||
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",
|
||||
I915_READ(PCH_PP_ON_DELAYS),
|
||||
I915_READ(PCH_PP_OFF_DELAYS),
|
||||
I915_READ(PCH_PP_DIVISOR));
|
||||
I915_READ(pp_on_reg),
|
||||
I915_READ(pp_off_reg),
|
||||
I915_READ(pp_div_reg));
|
||||
}
|
||||
|
||||
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_helper_add(connector, &intel_dp_connector_helper_funcs);
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
|
@ -2844,27 +2812,46 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
|||
else
|
||||
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. */
|
||||
switch (port) {
|
||||
case PORT_A:
|
||||
intel_encoder->hpd_pin = HPD_PORT_A;
|
||||
name = "DPDDC-A";
|
||||
break;
|
||||
case PORT_B:
|
||||
dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS;
|
||||
intel_encoder->hpd_pin = HPD_PORT_B;
|
||||
name = "DPDDC-B";
|
||||
break;
|
||||
case PORT_C:
|
||||
dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS;
|
||||
intel_encoder->hpd_pin = HPD_PORT_C;
|
||||
name = "DPDDC-C";
|
||||
break;
|
||||
case PORT_D:
|
||||
dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS;
|
||||
intel_encoder->hpd_pin = HPD_PORT_D;
|
||||
name = "DPDDC-D";
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Invalid port %c\n", port_name(port));
|
||||
break;
|
||||
BUG();
|
||||
}
|
||||
|
||||
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_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->pre_enable = intel_pre_enable_dp;
|
||||
intel_encoder->disable = intel_disable_dp;
|
||||
|
|
|
@ -33,12 +33,21 @@
|
|||
#include <drm/drm_fb_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) ({ \
|
||||
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
|
||||
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \
|
||||
int ret__ = 0; \
|
||||
while (!(COND)) { \
|
||||
if (time_after(jiffies, timeout__)) { \
|
||||
ret__ = -ETIMEDOUT; \
|
||||
if (!(COND)) \
|
||||
ret__ = -ETIMEDOUT; \
|
||||
break; \
|
||||
} \
|
||||
if (W && drm_can_sleep()) { \
|
||||
|
@ -50,21 +59,10 @@
|
|||
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_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 MHz(x) KHz(1000*x)
|
||||
|
@ -101,34 +99,6 @@
|
|||
#define INTEL_DVO_CHIP_TMDS 2
|
||||
#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 drm_framebuffer base;
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
@ -158,9 +128,12 @@ struct intel_encoder {
|
|||
bool cloneable;
|
||||
bool connectors_active;
|
||||
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_enable)(struct intel_encoder *);
|
||||
void (*enable)(struct intel_encoder *);
|
||||
void (*mode_set)(struct intel_encoder *intel_encoder);
|
||||
void (*disable)(struct intel_encoder *);
|
||||
void (*post_disable)(struct intel_encoder *);
|
||||
/* 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. */
|
||||
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
|
||||
int crtc_mask;
|
||||
enum hpd_pin hpd_pin;
|
||||
};
|
||||
|
||||
struct intel_panel {
|
||||
|
@ -197,13 +171,65 @@ struct intel_connector {
|
|||
|
||||
/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid 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 drm_crtc base;
|
||||
enum pipe pipe;
|
||||
enum plane plane;
|
||||
enum transcoder cpu_transcoder;
|
||||
u8 lut_r[256], lut_g[256], lut_b[256];
|
||||
/*
|
||||
* 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_width, cursor_height;
|
||||
bool cursor_visible;
|
||||
unsigned int bpp;
|
||||
|
||||
struct intel_crtc_config config;
|
||||
|
||||
/* We can share PLLs across outputs if the timings match */
|
||||
struct intel_pch_pll *pch_pll;
|
||||
|
@ -242,11 +269,16 @@ struct intel_crtc {
|
|||
|
||||
struct intel_plane {
|
||||
struct drm_plane base;
|
||||
int plane;
|
||||
enum pipe pipe;
|
||||
struct drm_i915_gem_object *obj;
|
||||
bool can_scale;
|
||||
int max_downscale;
|
||||
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,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_i915_gem_object *obj,
|
||||
|
@ -347,7 +379,7 @@ struct dip_infoframe {
|
|||
} __attribute__((packed));
|
||||
|
||||
struct intel_hdmi {
|
||||
u32 sdvox_reg;
|
||||
u32 hdmi_reg;
|
||||
int ddc_bus;
|
||||
uint32_t color_range;
|
||||
bool color_range_auto;
|
||||
|
@ -366,6 +398,7 @@ struct intel_hdmi {
|
|||
|
||||
struct intel_dp {
|
||||
uint32_t output_reg;
|
||||
uint32_t aux_ch_ctl_reg;
|
||||
uint32_t DP;
|
||||
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
|
||||
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_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,
|
||||
struct intel_connector *intel_connector);
|
||||
extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
|
||||
extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config);
|
||||
extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
||||
extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
|
||||
bool is_sdvob);
|
||||
|
@ -464,18 +496,14 @@ extern void intel_dp_init(struct drm_device *dev, int output_reg,
|
|||
enum port port);
|
||||
extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
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_start_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_encoder_destroy(struct drm_encoder *encoder);
|
||||
extern void intel_dp_check_link_status(struct intel_dp *intel_dp);
|
||||
extern bool intel_dp_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern bool intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config);
|
||||
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_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_vdd_on(struct intel_dp *intel_dp);
|
||||
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 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,
|
||||
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 bool intel_connector_get_hw_state(struct intel_connector *connector);
|
||||
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)
|
||||
|
@ -636,6 +662,10 @@ extern void intel_init_clock_gating(struct drm_device *dev);
|
|||
extern void intel_write_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode);
|
||||
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 hsw_fdi_link_train(struct drm_crtc *crtc);
|
||||
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_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_set_power_well(struct drm_device *dev, bool enable);
|
||||
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);
|
||||
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_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,
|
||||
enum transcoder cpu_transcoder);
|
||||
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);
|
||||
extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
|
||||
|
||||
extern void intel_display_handle_reset(struct drm_device *dev);
|
||||
|
||||
#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];
|
||||
struct i2c_adapter *i2c;
|
||||
int gpio;
|
||||
bool dvoinit;
|
||||
|
||||
/* Allow the I2C driver info to specify the GPIO to be used in
|
||||
* 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);
|
||||
|
||||
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;
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_DVO;
|
||||
|
|
|
@ -150,7 +150,8 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
|||
}
|
||||
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_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;
|
||||
|
||||
ret = drm_fb_helper_init(dev, &ifbdev->helper,
|
||||
dev_priv->num_pipe,
|
||||
INTEL_INFO(dev)->num_pipes,
|
||||
INTELFB_CONN_LIMIT);
|
||||
if (ret) {
|
||||
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_plane *plane;
|
||||
|
||||
if (INTEL_INFO(dev)->num_pipes == 0)
|
||||
return;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
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;
|
||||
|
||||
WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits,
|
||||
WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
|
||||
"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) {
|
||||
case DIP_TYPE_AVI:
|
||||
return HSW_TVIDEO_DIP_AVI_DATA(pipe);
|
||||
return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder);
|
||||
case DIP_TYPE_SPD:
|
||||
return HSW_TVIDEO_DIP_SPD_DATA(pipe);
|
||||
return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder);
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
|
||||
return 0;
|
||||
|
@ -293,8 +294,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
|
|||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
u32 data_reg = hsw_infoframe_data_reg(frame, 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->config.cpu_transcoder);
|
||||
unsigned int i, len = DIP_HEADER_SIZE + frame->len;
|
||||
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 intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct dip_infoframe avi_if = {
|
||||
.type = DIP_TYPE_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;
|
||||
|
||||
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;
|
||||
else
|
||||
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 intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
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);
|
||||
|
||||
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 intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 sdvox;
|
||||
u32 hdmi_val;
|
||||
|
||||
sdvox = SDVO_ENCODING_HDMI;
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
sdvox |= intel_hdmi->color_range;
|
||||
hdmi_val = SDVO_ENCODING_HDMI;
|
||||
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
|
||||
hdmi_val |= intel_hdmi->color_range;
|
||||
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)
|
||||
sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
|
||||
hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
|
||||
|
||||
if (intel_crtc->bpp > 24)
|
||||
sdvox |= COLOR_FORMAT_12bpc;
|
||||
if (intel_crtc->config.pipe_bpp > 24)
|
||||
hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
|
||||
else
|
||||
sdvox |= COLOR_FORMAT_8bpc;
|
||||
hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
|
||||
|
||||
/* Required on CPT */
|
||||
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) {
|
||||
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
sdvox |= SDVO_AUDIO_ENABLE;
|
||||
sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
|
||||
hdmi_val |= SDVO_AUDIO_ENABLE;
|
||||
hdmi_val |= HDMI_MODE_SELECT_HDMI;
|
||||
intel_write_eld(encoder, adjusted_mode);
|
||||
}
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
|
||||
else if (intel_crtc->pipe == PIPE_B)
|
||||
sdvox |= SDVO_PIPE_B_SELECT;
|
||||
hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe);
|
||||
else
|
||||
hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe);
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
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);
|
||||
u32 tmp;
|
||||
|
||||
tmp = I915_READ(intel_hdmi->sdvox_reg);
|
||||
tmp = I915_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
if (!(tmp & SDVO_ENABLE))
|
||||
return false;
|
||||
|
@ -660,6 +662,7 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
|
|||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
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);
|
||||
u32 temp;
|
||||
u32 enable_bits = SDVO_ENABLE;
|
||||
|
@ -667,38 +670,32 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
|
|||
if (intel_hdmi->has_audio)
|
||||
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
|
||||
* before disabling it. */
|
||||
if (HAS_PCH_IBX(dev)) {
|
||||
struct drm_crtc *crtc = encoder->base.crtc;
|
||||
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
|
||||
|
||||
/* Restore the transcoder select bit. */
|
||||
if (pipe == PIPE_B)
|
||||
enable_bits |= SDVO_PIPE_B_SELECT;
|
||||
}
|
||||
* before disabling it, so restore the transcoder select bit here. */
|
||||
if (HAS_PCH_IBX(dev))
|
||||
enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe);
|
||||
|
||||
/* HW workaround, need to toggle enable bit off and on for 12bpc, but
|
||||
* we do this anyway which shows more stable in testing.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
}
|
||||
|
||||
temp |= enable_bits;
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* HW workaround, need to write this twice for issue that may result
|
||||
* in first write getting masked.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,7 +707,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
|
|||
u32 temp;
|
||||
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
|
||||
* before disabling it. */
|
||||
|
@ -720,12 +717,12 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
|
|||
|
||||
if (temp & SDVO_PIPE_B_SELECT) {
|
||||
temp &= ~SDVO_PIPE_B_SELECT;
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* Again we need to write this twice. */
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* Transcoder selection bits only update
|
||||
* 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.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
}
|
||||
|
||||
temp &= ~enable_bits;
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
|
||||
/* HW workaround, need to write this twice for issue that may result
|
||||
* in first write getting masked.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
I915_WRITE(intel_hdmi->hdmi_reg, temp);
|
||||
POSTING_READ(intel_hdmi->hdmi_reg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,23 +769,40 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
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) {
|
||||
/* See CEA-861-E - 5.1 Default Encoding Parameters */
|
||||
if (intel_hdmi->has_hdmi_sink &&
|
||||
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
|
||||
intel_hdmi->color_range = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -906,6 +920,9 @@ intel_hdmi_set_property(struct drm_connector *connector,
|
|||
}
|
||||
|
||||
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) {
|
||||
case INTEL_BROADCAST_RGB_AUTO:
|
||||
intel_hdmi->color_range_auto = true;
|
||||
|
@ -916,11 +933,16 @@ intel_hdmi_set_property(struct drm_connector *connector,
|
|||
break;
|
||||
case INTEL_BROADCAST_RGB_LIMITED:
|
||||
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;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (old_auto == intel_hdmi->color_range_auto &&
|
||||
old_range == intel_hdmi->color_range)
|
||||
return 0;
|
||||
|
||||
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 = {
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
.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_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
switch (port) {
|
||||
case PORT_B:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS;
|
||||
intel_encoder->hpd_pin = HPD_PORT_B;
|
||||
break;
|
||||
case PORT_C:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS;
|
||||
intel_encoder->hpd_pin = HPD_PORT_C;
|
||||
break;
|
||||
case PORT_D:
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS;
|
||||
intel_encoder->hpd_pin = HPD_PORT_D;
|
||||
break;
|
||||
case PORT_A:
|
||||
intel_encoder->hpd_pin = HPD_PORT_A;
|
||||
/* Internal port only for eDP. */
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev)) {
|
||||
intel_hdmi->write_infoframe = g4x_write_infoframe;
|
||||
intel_hdmi->set_infoframes = g4x_set_infoframes;
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
intel_hdmi->write_infoframe = vlv_write_infoframe;
|
||||
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->set_infoframes = hsw_set_infoframes;
|
||||
} 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_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_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->disable = intel_disable_hdmi;
|
||||
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_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_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;
|
||||
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;
|
||||
else if (IS_VALLEYVIEW(dev))
|
||||
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_end = mode->crtc_hsync_start + sync_width;
|
||||
|
||||
mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET;
|
||||
}
|
||||
|
||||
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_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)
|
||||
|
@ -301,17 +297,20 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target)
|
|||
return (FACTOR * ratio + FACTOR/2) / FACTOR;
|
||||
}
|
||||
|
||||
static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_device *dev = intel_encoder->base.dev;
|
||||
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 =
|
||||
&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;
|
||||
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
|
||||
unsigned int lvds_bpp;
|
||||
int pipe;
|
||||
|
||||
/* 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))
|
||||
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
|
||||
* 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);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
||||
intel_pch_panel_fitting(dev,
|
||||
intel_connector->panel.fitting_mode,
|
||||
mode, adjusted_mode);
|
||||
|
@ -359,6 +371,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
|||
I915_WRITE(BCLRPAT(pipe), 0);
|
||||
|
||||
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||
pipe_config->timings_set = true;
|
||||
|
||||
switch (intel_connector->panel.fitting_mode) {
|
||||
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))
|
||||
kfree(lvds_connector->base.edid);
|
||||
|
||||
intel_panel_destroy_backlight(connector->dev);
|
||||
intel_panel_fini(&lvds_connector->base.panel);
|
||||
|
||||
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 = {
|
||||
.mode_fixup = intel_lvds_mode_fixup,
|
||||
.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"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.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 */
|
||||
};
|
||||
|
@ -1019,12 +1038,15 @@ static bool intel_lvds_supported(struct drm_device *dev)
|
|||
{
|
||||
/* With the introduction of the PCH we gained a dedicated
|
||||
* LVDS presence pin, use it. */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
|
||||
return true;
|
||||
|
||||
/* Otherwise LVDS was only attached to mobile products,
|
||||
* 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->pre_enable = intel_pre_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->get_hw_state = intel_lvds_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;
|
||||
|
||||
dev_priv->backlight_level = level;
|
||||
if (dev_priv->backlight_enabled)
|
||||
dev_priv->backlight.level = level;
|
||||
if (dev_priv->backlight.device)
|
||||
dev_priv->backlight.device->props.brightness = level;
|
||||
|
||||
if (dev_priv->backlight.enabled)
|
||||
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;
|
||||
|
||||
dev_priv->backlight_enabled = false;
|
||||
dev_priv->backlight.enabled = false;
|
||||
intel_panel_actually_set_backlight(dev, 0);
|
||||
|
||||
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;
|
||||
|
||||
if (dev_priv->backlight_level == 0)
|
||||
dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
|
||||
if (dev_priv->backlight.level == 0) {
|
||||
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) {
|
||||
uint32_t reg, tmp;
|
||||
|
@ -335,7 +342,7 @@ void intel_panel_enable_backlight(struct drm_device *dev,
|
|||
if (tmp & BLM_PWM_ENABLE)
|
||||
goto set_level;
|
||||
|
||||
if (dev_priv->num_pipe == 3)
|
||||
if (INTEL_INFO(dev)->num_pipes == 3)
|
||||
tmp &= ~BLM_PIPE_SELECT_IVB;
|
||||
else
|
||||
tmp &= ~BLM_PIPE_SELECT;
|
||||
|
@ -360,16 +367,16 @@ set_level:
|
|||
* BLC_PWM_CPU_CTL may be cleared to zero automatically when these
|
||||
* registers are set.
|
||||
*/
|
||||
dev_priv->backlight_enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
|
||||
dev_priv->backlight.enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
|
||||
}
|
||||
|
||||
static void intel_panel_init_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->backlight_level = intel_panel_get_backlight(dev);
|
||||
dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
|
||||
dev_priv->backlight.level = intel_panel_get_backlight(dev);
|
||||
dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct drm_device *dev = bl_get_data(bd);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->backlight_level;
|
||||
return intel_panel_get_backlight(dev);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (WARN_ON(dev_priv->backlight.device))
|
||||
return -ENODEV;
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.brightness = dev_priv->backlight.level;
|
||||
props.max_brightness = _intel_panel_get_max_backlight(dev);
|
||||
if (props.max_brightness == 0) {
|
||||
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_priv->backlight =
|
||||
dev_priv->backlight.device =
|
||||
backlight_device_register("intel_backlight",
|
||||
&connector->kdev, dev,
|
||||
&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",
|
||||
PTR_ERR(dev_priv->backlight));
|
||||
dev_priv->backlight = NULL;
|
||||
PTR_ERR(dev_priv->backlight.device));
|
||||
dev_priv->backlight.device = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_panel_destroy_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
if (dev_priv->backlight)
|
||||
backlight_device_unregister(dev_priv->backlight);
|
||||
if (dev_priv->backlight.device) {
|
||||
backlight_device_unregister(dev_priv->backlight.device);
|
||||
dev_priv->backlight.device = NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
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…
Reference in New Issue