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:
Linus Torvalds 2013-05-02 19:40:34 -07:00
commit 20a2078ce7
404 changed files with 29319 additions and 7341 deletions

View File

@ -0,0 +1,44 @@
/*
1600x1200.S: EDID data set for standard 1600x1200 60 Hz monitor
Copyright (C) 2013 Carsten Emde <C.Emde@osadl.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* EDID */
#define VERSION 1
#define REVISION 3
/* Display */
#define CLOCK 162000 /* kHz */
#define XPIX 1600
#define YPIX 1200
#define XY_RATIO XY_RATIO_4_3
#define XBLANK 560
#define YBLANK 50
#define XOFFSET 64
#define XPULSE 192
#define YOFFSET (63+1)
#define YPULSE (63+3)
#define DPI 72
#define VFREQ 60 /* Hz */
#define TIMING_NAME "Linux UXGA"
#define ESTABLISHED_TIMINGS_BITS 0x00 /* none */
#define HSYNC_POL 1
#define VSYNC_POL 1
#define CRC 0x9d
#include "edid.S"

View File

@ -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".

View File

@ -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>;
};

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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>

View File

@ -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"

View File

@ -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"

View File

@ -1 +1,2 @@
obj-y += drm/ vga/
obj-$(CONFIG_TEGRA_HOST1X) += host1x/

View File

@ -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"

View File

@ -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/

View File

@ -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)

View File

@ -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) {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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];

View File

@ -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

View File

@ -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,

View File

@ -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++) {

View File

@ -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);
}
}

View File

@ -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

View File

@ -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))

View File

@ -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);

View File

@ -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)
{

View File

@ -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.

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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__);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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,

View File

@ -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;
/*

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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_ */

View File

@ -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. */

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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(&reg->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;

View File

@ -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.

View File

@ -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);
}

View File

@ -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) {

View File

@ -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),
&gtt_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), &gtt_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);

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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[] = {

View File

@ -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? */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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__ */

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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